Complete folder share
parent
fd4105e913
commit
b84b4e6de1
|
@ -490,10 +490,7 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
|
||||||
|
|
||||||
// Folder
|
// Folder
|
||||||
if (this.$route.name === "folders") {
|
if (this.$route.name === "folders") {
|
||||||
let path: any = this.$route.params.path || "/";
|
query.set("folder", utils.getFolderRoutePath(this.config_foldersPath));
|
||||||
path = typeof path === "string" ? path : path.join("/");
|
|
||||||
path = this.config_foldersPath + "/" + path;
|
|
||||||
query.set("folder", path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Archive
|
// 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>
|
<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="container">
|
||||||
<div class="head">
|
<div class="head">
|
||||||
<span> <slot name="title"></slot> </span>
|
<span> <slot name="title"></slot> </span>
|
||||||
|
@ -17,6 +23,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Emit, Prop, Vue } from "vue-property-decorator";
|
import { Component, Emit, Prop, Vue } from "vue-property-decorator";
|
||||||
import { NcModal } from "@nextcloud/vue";
|
import { NcModal } from "@nextcloud/vue";
|
||||||
|
import { subscribe, unsubscribe } from "@nextcloud/event-bus";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
|
@ -25,9 +32,66 @@ import { NcModal } from "@nextcloud/vue";
|
||||||
})
|
})
|
||||||
export default class Modal extends Vue {
|
export default class Modal extends Vue {
|
||||||
@Prop({ default: "small" }) private size?: string;
|
@Prop({ default: "small" }) private size?: string;
|
||||||
|
@Prop({ default: null }) private sidebar?: string;
|
||||||
|
|
||||||
|
private isSidebarShown = false;
|
||||||
|
private sidebarWidth = 400;
|
||||||
|
private trapElements: any = [];
|
||||||
|
|
||||||
@Emit("close")
|
@Emit("close")
|
||||||
public 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>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="album-top-matter">
|
<div class="top-matter">
|
||||||
<NcActions v-if="!isAlbumList">
|
<NcActions v-if="!isAlbumList">
|
||||||
<NcActionButton :aria-label="t('memories', 'Back')" @click="back()">
|
<NcActionButton :aria-label="t('memories', 'Back')" @click="back()">
|
||||||
{{ t("memories", "Back") }}
|
{{ t("memories", "Back") }}
|
||||||
|
@ -124,7 +124,7 @@ export default class AlbumTopMatter extends Mixins(GlobalMixin, UserConfig) {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.album-top-matter {
|
.top-matter {
|
||||||
display: flex;
|
display: flex;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
|
|
||||||
|
|
|
@ -1,31 +1,61 @@
|
||||||
<template>
|
<template>
|
||||||
<NcBreadcrumbs v-if="topMatter">
|
<div class="top-matter">
|
||||||
<NcBreadcrumb title="Home" :to="{ name: 'folders' }">
|
<NcBreadcrumbs v-if="topMatter">
|
||||||
<template #icon>
|
<NcBreadcrumb title="Home" :to="{ name: 'folders' }">
|
||||||
<HomeIcon :size="20" />
|
<template #icon>
|
||||||
</template>
|
<HomeIcon :size="20" />
|
||||||
</NcBreadcrumb>
|
</template>
|
||||||
<NcBreadcrumb
|
</NcBreadcrumb>
|
||||||
v-for="folder in topMatter.list"
|
<NcBreadcrumb
|
||||||
:key="folder.path"
|
v-for="folder in topMatter.list"
|
||||||
:title="folder.text"
|
:key="folder.path"
|
||||||
:to="{ name: 'folders', params: { path: folder.path } }"
|
:title="folder.text"
|
||||||
/>
|
:to="{ name: 'folders', params: { path: folder.path } }"
|
||||||
</NcBreadcrumbs>
|
/>
|
||||||
|
</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>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Component, Mixins, Watch } from "vue-property-decorator";
|
import { Component, Mixins, Watch } from "vue-property-decorator";
|
||||||
import { TopMatterFolder, TopMatterType } from "../../types";
|
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 GlobalMixin from "../../mixins/GlobalMixin";
|
||||||
|
|
||||||
|
import FolderShareModal from "../modal/FolderShareModal.vue";
|
||||||
|
|
||||||
import HomeIcon from "vue-material-design-icons/Home.vue";
|
import HomeIcon from "vue-material-design-icons/Home.vue";
|
||||||
|
import ShareIcon from "vue-material-design-icons/ShareVariant.vue";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
components: {
|
components: {
|
||||||
NcBreadcrumbs,
|
NcBreadcrumbs,
|
||||||
NcBreadcrumb,
|
NcBreadcrumb,
|
||||||
|
NcActions,
|
||||||
|
NcActionButton,
|
||||||
|
FolderShareModal,
|
||||||
HomeIcon,
|
HomeIcon,
|
||||||
|
ShareIcon,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
export default class FolderTopMatter extends Mixins(GlobalMixin) {
|
export default class FolderTopMatter extends Mixins(GlobalMixin) {
|
||||||
|
@ -63,4 +93,19 @@ export default class FolderTopMatter extends Mixins(GlobalMixin) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</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
|
// Outside for set
|
||||||
const TagDayID = {
|
const TagDayID = {
|
||||||
START: -(1 << 30),
|
START: -(1 << 30),
|
||||||
|
|
Loading…
Reference in New Issue