Complete folder share
parent
fd4105e913
commit
b84b4e6de1
|
@ -490,10 +490,7 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
|
|||
|
||||
// Folder
|
||||
if (this.$route.name === "folders") {
|
||||
let path: any = this.$route.params.path || "/";
|
||||
path = typeof path === "string" ? path : path.join("/");
|
||||
path = this.config_foldersPath + "/" + path;
|
||||
query.set("folder", path);
|
||||
query.set("folder", utils.getFolderRoutePath(this.config_foldersPath));
|
||||
}
|
||||
|
||||
// Archive
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
<template>
|
||||
<Modal
|
||||
@close="close"
|
||||
size="normal"
|
||||
v-if="show"
|
||||
:sidebar="!isRoot ? this.folderPath : null"
|
||||
>
|
||||
<template #title>
|
||||
{{ t("memories", "Share Folder") }}
|
||||
</template>
|
||||
|
||||
<div v-if="isRoot">
|
||||
{{ t("memories", "You cannot share the root folder") }}
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ t("memories", "Use the sidebar to share this folder.") }} <br />
|
||||
{{
|
||||
t(
|
||||
"memories",
|
||||
"If you create a public link share, click on refresh and a corresponding link to Memories will be shown below."
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
|
||||
<div class="links">
|
||||
<a
|
||||
v-for="link of links"
|
||||
:key="link.url"
|
||||
:href="link.url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{{ link.url }}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<template #buttons>
|
||||
<NcButton class="primary" @click="refreshUrls">
|
||||
{{ t("memories", "Refresh") }}
|
||||
</NcButton>
|
||||
</template>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Emit, Mixins } from "vue-property-decorator";
|
||||
|
||||
import axios from "@nextcloud/axios";
|
||||
import { generateOcsUrl, generateUrl } from "@nextcloud/router";
|
||||
import { NcButton } from "@nextcloud/vue";
|
||||
|
||||
import * as utils from "../../services/Utils";
|
||||
import Modal from "./Modal.vue";
|
||||
import GlobalMixin from "../../mixins/GlobalMixin";
|
||||
import UserConfig from "../../mixins/UserConfig";
|
||||
import { Type } from "@nextcloud/sharing";
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
Modal,
|
||||
NcButton,
|
||||
},
|
||||
})
|
||||
export default class FolderShareModal extends Mixins(GlobalMixin, UserConfig) {
|
||||
private show = false;
|
||||
private folderPath = "";
|
||||
private links: { url: string }[] = [];
|
||||
|
||||
get isRoot() {
|
||||
return this.folderPath === "/" || this.folderPath === "";
|
||||
}
|
||||
|
||||
@Emit("close")
|
||||
public close() {
|
||||
this.show = false;
|
||||
}
|
||||
|
||||
public open() {
|
||||
this.folderPath = utils.getFolderRoutePath(this.config_foldersPath);
|
||||
this.show = true;
|
||||
globalThis.OCA.Files.Sidebar.setActiveTab("sharing");
|
||||
this.refreshUrls();
|
||||
}
|
||||
|
||||
private async refreshUrls() {
|
||||
const query = `format=json&path=${encodeURIComponent(
|
||||
this.folderPath
|
||||
)}&reshares=true`;
|
||||
const url = generateOcsUrl(`/apps/files_sharing/api/v1/shares?${query}`);
|
||||
const response = await axios.get(url);
|
||||
const data = response.data?.ocs?.data;
|
||||
if (data) {
|
||||
this.links = data
|
||||
.filter((s) => s.share_type === Type.SHARE_TYPE_LINK && s.token)
|
||||
.map((share: any) => ({
|
||||
url:
|
||||
window.location.origin +
|
||||
generateUrl(`/apps/memories/s/${share.token}`),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.links {
|
||||
margin-top: 1em;
|
||||
a {
|
||||
display: block;
|
||||
margin-bottom: 0.2em;
|
||||
color: var(--color-primary-element);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,11 @@
|
|||
<template>
|
||||
<NcModal :size="size" @close="close" :outTransition="true">
|
||||
<NcModal
|
||||
:size="size"
|
||||
@close="close"
|
||||
:outTransition="true"
|
||||
:style="{ width: isSidebarShown ? `calc(100% - ${sidebarWidth}px)` : null }"
|
||||
:additionalTrapElements="trapElements"
|
||||
>
|
||||
<div class="container">
|
||||
<div class="head">
|
||||
<span> <slot name="title"></slot> </span>
|
||||
|
@ -17,6 +23,7 @@
|
|||
<script lang="ts">
|
||||
import { Component, Emit, Prop, Vue } from "vue-property-decorator";
|
||||
import { NcModal } from "@nextcloud/vue";
|
||||
import { subscribe, unsubscribe } from "@nextcloud/event-bus";
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
|
@ -25,9 +32,66 @@ import { NcModal } from "@nextcloud/vue";
|
|||
})
|
||||
export default class Modal extends Vue {
|
||||
@Prop({ default: "small" }) private size?: string;
|
||||
@Prop({ default: null }) private sidebar?: string;
|
||||
|
||||
private isSidebarShown = false;
|
||||
private sidebarWidth = 400;
|
||||
private trapElements: any = [];
|
||||
|
||||
@Emit("close")
|
||||
public close() {}
|
||||
|
||||
beforeMount() {
|
||||
if (this.sidebar) {
|
||||
subscribe("files:sidebar:opened", this.handleAppSidebarOpen);
|
||||
subscribe("files:sidebar:closed", this.handleAppSidebarClose);
|
||||
window.addEventListener("DOMNodeInserted", this.handlePopover);
|
||||
globalThis.OCA?.Files?.Sidebar?.setFullScreenMode?.(true);
|
||||
}
|
||||
}
|
||||
|
||||
beforeDestroy() {
|
||||
if (this.sidebar) {
|
||||
unsubscribe("files:sidebar:opened", this.handleAppSidebarOpen);
|
||||
unsubscribe("files:sidebar:closed", this.handleAppSidebarClose);
|
||||
window.removeEventListener("DOMNodeInserted", this.handlePopover);
|
||||
globalThis.OCA?.Files?.Sidebar?.setFullScreenMode?.(false);
|
||||
globalThis.OCA?.Files?.Sidebar?.close();
|
||||
}
|
||||
}
|
||||
|
||||
mounted() {
|
||||
if (this.sidebar) {
|
||||
globalThis.OCA.Files.Sidebar.open(this.sidebar);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch out for Popover inject in document root
|
||||
* That way we can adjust the focusTrap
|
||||
*/
|
||||
handlePopover(event) {
|
||||
if (
|
||||
event.target?.classList &&
|
||||
event.target.classList.contains("v-popper__popper")
|
||||
) {
|
||||
this.trapElements.push(event.target);
|
||||
}
|
||||
}
|
||||
|
||||
handleAppSidebarOpen() {
|
||||
this.isSidebarShown = true;
|
||||
const sidebar: HTMLElement = document.querySelector("aside.app-sidebar");
|
||||
if (sidebar) {
|
||||
this.sidebarWidth = sidebar.offsetWidth;
|
||||
this.trapElements = [sidebar];
|
||||
}
|
||||
}
|
||||
|
||||
handleAppSidebarClose() {
|
||||
this.isSidebarShown = false;
|
||||
this.trapElements = [];
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="album-top-matter">
|
||||
<div class="top-matter">
|
||||
<NcActions v-if="!isAlbumList">
|
||||
<NcActionButton :aria-label="t('memories', 'Back')" @click="back()">
|
||||
{{ t("memories", "Back") }}
|
||||
|
@ -124,7 +124,7 @@ export default class AlbumTopMatter extends Mixins(GlobalMixin, UserConfig) {
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.album-top-matter {
|
||||
.top-matter {
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
|
||||
|
|
|
@ -1,31 +1,61 @@
|
|||
<template>
|
||||
<NcBreadcrumbs v-if="topMatter">
|
||||
<NcBreadcrumb title="Home" :to="{ name: 'folders' }">
|
||||
<template #icon>
|
||||
<HomeIcon :size="20" />
|
||||
</template>
|
||||
</NcBreadcrumb>
|
||||
<NcBreadcrumb
|
||||
v-for="folder in topMatter.list"
|
||||
:key="folder.path"
|
||||
:title="folder.text"
|
||||
:to="{ name: 'folders', params: { path: folder.path } }"
|
||||
/>
|
||||
</NcBreadcrumbs>
|
||||
<div class="top-matter">
|
||||
<NcBreadcrumbs v-if="topMatter">
|
||||
<NcBreadcrumb title="Home" :to="{ name: 'folders' }">
|
||||
<template #icon>
|
||||
<HomeIcon :size="20" />
|
||||
</template>
|
||||
</NcBreadcrumb>
|
||||
<NcBreadcrumb
|
||||
v-for="folder in topMatter.list"
|
||||
:key="folder.path"
|
||||
:title="folder.text"
|
||||
:to="{ name: 'folders', params: { path: folder.path } }"
|
||||
/>
|
||||
</NcBreadcrumbs>
|
||||
|
||||
<div class="right-actions">
|
||||
<NcActions :inline="1">
|
||||
<NcActionButton
|
||||
:aria-label="t('memories', 'Share folder')"
|
||||
@click="$refs.shareModal.open(false)"
|
||||
close-after-click
|
||||
>
|
||||
{{ t("memories", "Share folder") }}
|
||||
<template #icon> <ShareIcon :size="20" /> </template>
|
||||
</NcActionButton>
|
||||
</NcActions>
|
||||
</div>
|
||||
|
||||
<FolderShareModal ref="shareModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Mixins, Watch } from "vue-property-decorator";
|
||||
import { TopMatterFolder, TopMatterType } from "../../types";
|
||||
import { NcBreadcrumbs, NcBreadcrumb } from "@nextcloud/vue";
|
||||
import {
|
||||
NcBreadcrumbs,
|
||||
NcBreadcrumb,
|
||||
NcActions,
|
||||
NcActionButton,
|
||||
} from "@nextcloud/vue";
|
||||
import GlobalMixin from "../../mixins/GlobalMixin";
|
||||
|
||||
import FolderShareModal from "../modal/FolderShareModal.vue";
|
||||
|
||||
import HomeIcon from "vue-material-design-icons/Home.vue";
|
||||
import ShareIcon from "vue-material-design-icons/ShareVariant.vue";
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
NcBreadcrumbs,
|
||||
NcBreadcrumb,
|
||||
NcActions,
|
||||
NcActionButton,
|
||||
FolderShareModal,
|
||||
HomeIcon,
|
||||
ShareIcon,
|
||||
},
|
||||
})
|
||||
export default class FolderTopMatter extends Mixins(GlobalMixin) {
|
||||
|
@ -64,3 +94,18 @@ export default class FolderTopMatter extends Mixins(GlobalMixin) {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.top-matter {
|
||||
display: flex;
|
||||
vertical-align: middle;
|
||||
|
||||
.right-actions {
|
||||
margin-right: 40px;
|
||||
z-index: 50;
|
||||
@media (max-width: 768px) {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -186,6 +186,18 @@ export function convertFlags(photo: IPhoto) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path of the folder on folders route
|
||||
* This function does not check if this is the folder route
|
||||
*/
|
||||
export function getFolderRoutePath(basePath: string) {
|
||||
let path: any = vuerouter.currentRoute.params.path || "/";
|
||||
path = typeof path === "string" ? path : path.join("/");
|
||||
path = basePath + "/" + path;
|
||||
path = path.replace(/\/\/+/, "/"); // Remove double slashes
|
||||
return path;
|
||||
}
|
||||
|
||||
// Outside for set
|
||||
const TagDayID = {
|
||||
START: -(1 << 30),
|
||||
|
|
Loading…
Reference in New Issue