diff --git a/changelog/unreleased/bugfix-loading-shares-in-deep-nested-folders b/changelog/unreleased/bugfix-loading-shares-in-deep-nested-folders new file mode 100644 index 00000000000..75004bd5daf --- /dev/null +++ b/changelog/unreleased/bugfix-loading-shares-in-deep-nested-folders @@ -0,0 +1,6 @@ +Bugfix: Loading shares in deep nested folders + +Loading shares and share indicators on page reloads in deep nested folders was not possible and has been fixed. + +https://github.com/owncloud/web/issues/7655 +https://github.com/owncloud/web/pull/8349 diff --git a/changelog/unreleased/enhancement-share-and-folder-loading-performance b/changelog/unreleased/enhancement-share-and-folder-loading-performance new file mode 100644 index 00000000000..a3d158d0841 --- /dev/null +++ b/changelog/unreleased/enhancement-share-and-folder-loading-performance @@ -0,0 +1,6 @@ +Enhancement: Improve performance when loading folders and share indicators + +The performance when loading folders and share indicators has been improved by optimizing the way how shares are being loaded. + +https://github.com/owncloud/web/issues/7721 +https://github.com/owncloud/web/pull/8349 diff --git a/packages/design-system/src/components/OcStatusIndicators/OcStatusIndicators.vue b/packages/design-system/src/components/OcStatusIndicators/OcStatusIndicators.vue index 259cb3ac35f..79dc9cec8dc 100644 --- a/packages/design-system/src/components/OcStatusIndicators/OcStatusIndicators.vue +++ b/packages/design-system/src/components/OcStatusIndicators/OcStatusIndicators.vue @@ -13,7 +13,7 @@ variation="inverse" :data-testid="indicator.id" :data-test-indicator-type="indicator.type" - @click="indicator.handler(resource, indicator.target)" + @click="indicator.handler(resource, indicator.target, $router)" > diff --git a/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue b/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue index 34c41af4e75..058bb09083c 100644 --- a/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue +++ b/packages/web-app-files/src/components/AppBar/CreateAndUpload.vue @@ -178,6 +178,7 @@ import { urlJoin } from 'web-client/src/utils' import { stringify } from 'qs' import { useService } from 'web-pkg/src/composables/service' import { UppyService } from 'web-runtime/src/services/uppyService' +import { getIndicators } from 'web-app-files/src/helpers/statusIndicators' export default defineComponent({ components: { @@ -252,7 +253,13 @@ export default defineComponent({ }), computed: { ...mapGetters(['capabilities', 'configuration', 'newFileHandlers', 'user']), - ...mapGetters('Files', ['files', 'currentFolder', 'selectedFiles', 'clipboardResources']), + ...mapGetters('Files', [ + 'ancestorMetaData', + 'files', + 'currentFolder', + 'selectedFiles', + 'clipboardResources' + ]), ...mapState('Files', ['areFileExtensionsShown']), ...mapGetters('runtime/spaces', ['spaces']), @@ -317,15 +324,14 @@ export default defineComponent({ return false } return this.currentFolder.canUpload({ user: this.user }) + }, + + loadIndicatorsForNewFile() { + return this.isSpacesGenericLocation && this.space.driveType !== 'share' } }, methods: { - ...mapActions('Files', [ - 'loadPreview', - 'loadIndicators', - 'clearClipboardFiles', - 'pasteSelectedFiles' - ]), + ...mapActions('Files', ['clearClipboardFiles', 'pasteSelectedFiles']), ...mapActions(['showMessage', 'createModal', 'setModalInputErrorMessage', 'hideModal']), ...mapMutations('Files', ['UPSERT_RESOURCE']), ...mapMutations('runtime/spaces', ['UPDATE_SPACE_FIELD']), @@ -453,16 +459,14 @@ export default defineComponent({ const resource = await (this.$clientService.webdav as WebDAV).createFolder(this.space, { path }) - this.UPSERT_RESOURCE(resource) - this.hideModal() - if (this.isSpacesGenericLocation && this.space.driveType !== 'share') { - this.loadIndicators({ - client: this.$client, - currentFolder: this.currentFolder.path - }) + if (this.loadIndicatorsForNewFile) { + resource.indicators = getIndicators({ resource, ancestorMetaData: this.ancestorMetaData }) } + this.UPSERT_RESOURCE(resource) + this.hideModal() + this.showMessage({ title: this.$gettextInterpolate( this.$gettext('"%{folderName}" was created successfully'), @@ -522,6 +526,10 @@ export default defineComponent({ path }) + if (this.loadIndicatorsForNewFile) { + resource.indicators = getIndicators({ resource, ancestorMetaData: this.ancestorMetaData }) + } + this.UPSERT_RESOURCE(resource) if (this.newFileAction) { @@ -538,14 +546,6 @@ export default defineComponent({ } this.hideModal() - - if (this.isSpacesGenericLocation && this.space.driveType !== 'share') { - this.loadIndicators({ - client: this.$client, - currentFolder: this.currentFolder.path - }) - } - this.showMessage({ title: this.$gettextInterpolate(this.$gettext('"%{fileName}" was created successfully'), { fileName @@ -584,16 +584,14 @@ export default defineComponent({ const resource = await (this.$clientService.webdav as WebDAV).getFileInfo(this.space, { path }) + + if (this.loadIndicatorsForNewFile) { + resource.indicators = getIndicators({ resource, ancestorMetaData: this.ancestorMetaData }) + } + this.$_fileActions_triggerDefaultAction({ space: this.space, resources: [resource] }) this.UPSERT_RESOURCE(resource) this.hideModal() - - if (this.isSpacesGenericLocation && this.space.driveType !== 'share') { - this.loadIndicators({ - client: this.$client, - currentFolder: this.currentFolder.path - }) - } this.showMessage({ title: this.$gettextInterpolate(this.$gettext('"%{fileName}" was created successfully'), { fileName diff --git a/packages/web-app-files/src/components/Shares/SharedWithMeSection.vue b/packages/web-app-files/src/components/Shares/SharedWithMeSection.vue index 5d29dc7addb..f7195a0bc4e 100644 --- a/packages/web-app-files/src/components/Shares/SharedWithMeSection.vue +++ b/packages/web-app-files/src/components/Shares/SharedWithMeSection.vue @@ -93,7 +93,7 @@ import { computed, defineComponent, unref } from 'vue' import { debounce } from 'lodash-es' import { ImageDimension, ImageType } from 'web-pkg/src/constants' import { VisibilityObserver } from 'web-pkg/src/observer' -import { mapActions, mapGetters, mapMutations } from 'vuex' +import { mapActions, mapGetters } from 'vuex' import FileActions from '../../mixins/fileActions' import MixinAcceptShare from '../../mixins/actions/acceptShare' import MixinDeclineShare from '../../mixins/actions/declineShare' @@ -258,8 +258,7 @@ export default defineComponent({ visibilityObserver.disconnect() }, methods: { - ...mapActions('Files', ['loadIndicators', 'loadPreview', 'loadAvatars']), - ...mapMutations('Files', ['LOAD_FILES', 'CLEAR_CURRENT_FILES_LIST']), + ...mapActions('Files', ['loadPreview', 'loadAvatars']), rowMounted(resource, component) { const debounced = debounce(({ unobserve }) => { diff --git a/packages/web-app-files/src/components/SideBar/Details/FileDetails.vue b/packages/web-app-files/src/components/SideBar/Details/FileDetails.vue index 2f51957ce89..713ea41ef44 100644 --- a/packages/web-app-files/src/components/SideBar/Details/FileDetails.vue +++ b/packages/web-app-files/src/components/SideBar/Details/FileDetails.vue @@ -284,7 +284,7 @@ export default defineComponent({ }, computed: { ...mapGetters('runtime/spaces', ['spaces']), - ...mapGetters('Files', ['versions', 'sharesTree', 'sharesTreeLoading']), + ...mapGetters('Files', ['ancestorMetaData', 'versions', 'sharesTree', 'sharesTreeLoading']), ...mapGetters(['user', 'configuration']), matchingSpace() { @@ -453,7 +453,7 @@ export default defineComponent({ ) }, shareIndicators() { - return getIndicators(this.resource, this.sharesTree) + return getIndicators({ resource: this.resource, ancestorMetaData: this.ancestorMetaData }) }, shares() { if (this.sharedParentDir === null) { diff --git a/packages/web-app-files/src/components/SideBar/Shares/FileLinks.vue b/packages/web-app-files/src/components/SideBar/Shares/FileLinks.vue index 72951f6881c..46b5bedc63b 100644 --- a/packages/web-app-files/src/components/SideBar/Shares/FileLinks.vue +++ b/packages/web-app-files/src/components/SideBar/Shares/FileLinks.vue @@ -538,13 +538,7 @@ export default defineComponent({ this.currentFileOutgoingLinks.length === 1 ? this.currentFileOutgoingLinks[0].id : undefined try { - await this.removeLink({ - client, - share, - path, - storageId: resource.fileId, - loadIndicators: !!lastLinkId - }) + await this.removeLink({ client, share, path, loadIndicators: !!lastLinkId }) this.showMessage({ title: this.$gettext('Link was deleted successfully') }) diff --git a/packages/web-app-files/src/components/SideBar/Shares/FileShares.vue b/packages/web-app-files/src/components/SideBar/Shares/FileShares.vue index e93843c91a7..27c8a2e418f 100644 --- a/packages/web-app-files/src/components/SideBar/Shares/FileShares.vue +++ b/packages/web-app-files/src/components/SideBar/Shares/FileShares.vue @@ -303,7 +303,6 @@ export default defineComponent({ client: this.$client, share: share, path, - storageId: this.resource.fileId, loadIndicators: !!lastShareId }) diff --git a/packages/web-app-files/src/components/SideBar/SideBar.vue b/packages/web-app-files/src/components/SideBar/SideBar.vue index 795380b3433..783e5fa1429 100644 --- a/packages/web-app-files/src/components/SideBar/SideBar.vue +++ b/packages/web-app-files/src/components/SideBar/SideBar.vue @@ -168,6 +168,9 @@ export default defineComponent({ const highlightedFileIsSpace = computed(() => { return isProjectSpaceResource(unref(highlightedFile) || {}) }) + const highlightedSpace = computed(() => { + return store.getters['runtime/spaces/spaces'].find((s) => s.id === unref(highlightedFile).id) + }) const sharesLoadingDisabledOnCurrentRoute = computed(() => { return unref(isPublicFilesLocation) || unref(isTrashLocation) }) @@ -204,9 +207,7 @@ export default defineComponent({ const getSelectedResource = () => { if (unref(highlightedFileIsSpace) && unref(selectedFiles).length) { - return store.getters['runtime/spaces/spaces'].find( - (s) => s.id === unref(highlightedFile).id - ) + return unref(highlightedSpace) } if (unref(selectedFiles).length === 1) { return unref(selectedFiles)[0] @@ -254,8 +255,11 @@ export default defineComponent({ } watch( - selectedFiles, - (newResource, oldResource) => { + () => [...unref(selectedFiles), props.open], + () => { + if (!props.open) { + return + } if ( unref(selectedFiles).length === 1 && unref(loadedResource)?.id === unref(selectedFiles)[0].id @@ -267,16 +271,14 @@ export default defineComponent({ loading.value = true let selectedResource = getSelectedResource() if (selectedResource) { - const shouldLoadShares = - !unref(sharesLoadingDisabledOnCurrentRoute) && (!!oldResource || !unref(currentFolder)) - if (shouldLoadShares) { + if (!unref(sharesLoadingDisabledOnCurrentRoute)) { loadShares() } if (unref(highlightedFileIsSpace)) { store.dispatch('runtime/spaces/loadSpaceMembers', { graphClient: unref(graphClient), - space: selectedResource + space: unref(highlightedSpace) }) } diff --git a/packages/web-app-files/src/helpers/statusIndicators.ts b/packages/web-app-files/src/helpers/statusIndicators.ts index 1d41d27b26f..aa9147d58f3 100644 --- a/packages/web-app-files/src/helpers/statusIndicators.ts +++ b/packages/web-app-files/src/helpers/statusIndicators.ts @@ -1,123 +1,80 @@ -import { getParentPaths } from './path' import { ShareTypes } from 'web-client/src/helpers/share' -import { eventBus } from 'web-pkg/src/services/eventBus' +import { eventBus } from 'web-pkg' import { SideBarEventTopics } from 'web-pkg/src/composables/sideBar' +import { createLocationShares } from 'web-app-files/src/router' // dummy to trick gettext string extraction into recognizing strings const $gettext = (str) => { return str } -const $shareTypes = (resource) => { - if (typeof resource.shareTypes !== 'undefined') { - return resource.shareTypes - } - - if (resource.shares) { - return Array.from(new Set(resource.shares.map((share) => parseInt(share.type)))) - } - - return [] -} - -const isDirectUserShare = (resource) => { - return ShareTypes.containsAnyValue(ShareTypes.authenticated, $shareTypes(resource)) -} - -const isIndirectUserShare = (resource, sharesTree, hasShareJail) => { - return ( - (resource.isReceivedShare() && !hasShareJail) || - ShareTypes.containsAnyValue( - ShareTypes.authenticated, - shareTypesIndirect(resource.path, sharesTree) - ) - ) -} - -const isDirectLinkShare = (resource) => { - return ShareTypes.containsAnyValue(ShareTypes.unauthenticated, $shareTypes(resource)) -} - -const isIndirectLinkShare = (resource, sharesTree) => { - return ShareTypes.containsAnyValue( - ShareTypes.unauthenticated, - shareTypesIndirect(resource.path, sharesTree) - ) -} - -const isUserShare = (resource, sharesTree, hasShareJail) => { - return isDirectUserShare(resource) || isIndirectUserShare(resource, sharesTree, hasShareJail) +const isUserShare = (shareTypes) => { + return ShareTypes.containsAnyValue(ShareTypes.authenticated, shareTypes ?? []) } -const isLinkShare = (resource, sharesTree) => { - return isDirectLinkShare(resource) || isIndirectLinkShare(resource, sharesTree) +const isLinkShare = (shareTypes) => { + return ShareTypes.containsAnyValue(ShareTypes.unauthenticated, shareTypes ?? []) } -const shareUserIconDescribedBy = (resource) => { - return isDirectUserShare(resource) +const shareUserIconDescribedBy = ({ isDirect }) => { + return isDirect ? $gettext('This item is directly shared with others.') : $gettext('This item is shared with others through one of the parent folders.') } -const shareLinkDescribedBy = (resource) => { - return isDirectLinkShare(resource) +const shareLinkDescribedBy = ({ isDirect }) => { + return isDirect ? $gettext('This item is directly shared via links.') : $gettext('This item is shared via links through one of the parent folders.') } -const shareTypesIndirect = (path, sharesTree) => { - const parentPaths = getParentPaths(path, true) - - if (parentPaths.length === 0) { - return [] - } - - const shareTypes = {} - - parentPaths.forEach((parentPath) => { - // TODO: optimize for performance by skipping once we got all known types - const shares = sharesTree[parentPath] - - if (shares) { - shares.forEach((share) => { - // note: no distinction between incoming and outgoing shares as we display the same - // indirect indicator for them - shareTypes[share.shareType] = true - }) +const getUserIndicator = ({ resource, isDirect, isIncoming = false }) => { + return { + id: `files-sharing-${resource.getDomSelector()}`, + accessibleDescription: shareUserIconDescribedBy({ isDirect }), + label: isIncoming ? $gettext('Shared with you') : $gettext('Show invited people'), + icon: 'group', + target: 'sharing', + type: isDirect ? 'user-direct' : 'user-indirect', + handler: (resource, panel, $router) => { + if (isIncoming) { + $router.push(createLocationShares('files-shares-with-me')) + return + } + eventBus.publish(SideBarEventTopics.openWithPanel, `${panel}#peopleShares`) } - }) - - return Object.keys(shareTypes).map((shareType) => parseInt(shareType, 10)) + } } -// TODO: Think of a different way how to access sharesTree -export const getIndicators = (resource, sharesTree, hasShareJail = false) => { - const indicators = [ - { - id: `files-sharing-${resource.getDomSelector()}`, - accessibleDescription: shareUserIconDescribedBy(resource), - label: $gettext('Show invited people'), - visible: isUserShare(resource, sharesTree, hasShareJail), - icon: 'group', - target: 'sharing', - type: isDirectUserShare(resource) ? 'user-direct' : 'user-indirect', - handler: (resource, panel) => { - eventBus.publish(SideBarEventTopics.openWithPanel, `${panel}#peopleShares`) - } - }, - { - id: `file-link-${resource.getDomSelector()}`, - accessibleDescription: shareLinkDescribedBy(resource), - label: $gettext('Show links'), - visible: isLinkShare(resource, sharesTree), - icon: 'link', - target: 'sharing', - type: isDirectLinkShare(resource) ? 'link-direct' : 'link-indirect', - handler: (resource, panel) => { - eventBus.publish(SideBarEventTopics.openWithPanel, `${panel}#linkShares`) - } +const getLinkIndicator = ({ resource, isDirect }) => { + return { + id: `file-link-${resource.getDomSelector()}`, + accessibleDescription: shareLinkDescribedBy({ isDirect }), + label: $gettext('Show links'), + icon: 'link', + target: 'sharing', + type: isDirect ? 'link-direct' : 'link-indirect', + handler: (resource, panel) => { + eventBus.publish(SideBarEventTopics.openWithPanel, `${panel}#linkShares`) } - ] + } +} - return indicators.filter((indicator) => indicator.visible) +export const getIndicators = ({ resource, ancestorMetaData }) => { + const indicators = [] + const parentShareTypes = Object.values(ancestorMetaData).reduce((acc: any, data: any) => { + acc.push(...(data.shareTypes || [])) + return acc + }, []) + const isDirectUserShare = isUserShare(resource.shareTypes) + if (isDirectUserShare || isUserShare(parentShareTypes)) { + indicators.push(getUserIndicator({ resource, isDirect: isDirectUserShare })) + } else if (resource.isReceivedShare()) { + indicators.push(getUserIndicator({ resource, isDirect: false, isIncoming: true })) + } + const isDirectLinkShare = isLinkShare(resource.shareTypes) + if (isDirectLinkShare || isLinkShare(parentShareTypes)) { + indicators.push(getLinkIndicator({ resource, isDirect: isDirectLinkShare })) + } + return indicators } diff --git a/packages/web-app-files/src/mixins/deleteResources.ts b/packages/web-app-files/src/mixins/deleteResources.ts index a5ea0c2d1ae..66b0f328bfd 100644 --- a/packages/web-app-files/src/mixins/deleteResources.ts +++ b/packages/web-app-files/src/mixins/deleteResources.ts @@ -95,7 +95,7 @@ export default { }, methods: { - ...mapActions('Files', ['pushResourcesToDeleteList', 'removeFilesFromTrashbin', 'deleteFiles']), + ...mapActions('Files', ['removeFilesFromTrashbin', 'deleteFiles']), ...mapActions(['showMessage', 'toggleModalConfirmButton', 'hideModal', 'createModal']), ...mapMutations('runtime/spaces', ['UPDATE_SPACE_FIELD']), ...mapMutations(['SET_QUOTA']), diff --git a/packages/web-app-files/src/services/folder/loaderSpace.ts b/packages/web-app-files/src/services/folder/loaderSpace.ts index 420c4beed16..42d88a664a3 100644 --- a/packages/web-app-files/src/services/folder/loaderSpace.ts +++ b/packages/web-app-files/src/services/folder/loaderSpace.ts @@ -2,18 +2,14 @@ import { FolderLoader, FolderLoaderTask, TaskContext } from '../folder' import { Router } from 'vue-router' import { useTask } from 'vue-concurrency' import { isLocationPublicActive, isLocationSpacesActive } from '../../router' -import { - useCapabilityFilesSharingResharing, - useCapabilityShareJailEnabled, - useCapabilitySpacesEnabled -} from 'web-pkg/src/composables' -import { getIndicators } from '../../helpers/statusIndicators' +import { useCapabilityFilesSharingResharing } from 'web-pkg/src/composables' import { SpaceResource } from 'web-client/src/helpers' import { unref } from 'vue' import { FolderLoaderOptions } from './types' import { authService } from 'web-runtime/src/services/auth' import { useFileRouteReplace } from 'web-pkg/src/composables/router/useFileRouteReplace' import { aggregateResourceShares } from '../../helpers/resources' +import { getIndicators } from 'web-app-files/src/helpers/statusIndicators' export class FolderLoaderSpace implements FolderLoader { public isEnabled(): boolean { @@ -32,15 +28,10 @@ export class FolderLoaderSpace implements FolderLoader { } public getTask(context: TaskContext): FolderLoaderTask { - const { - store, - router, - clientService: { owncloudSdk: client, webdav } - } = context + const { store, router, clientService } = context + const { owncloudSdk: client, webdav } = clientService const { replaceInvalidFileRoute } = useFileRouteReplace({ router }) - const hasShareJail = useCapabilityShareJailEnabled(store) const hasResharing = useCapabilityFilesSharingResharing(store) - const hasSpaces = useCapabilitySpacesEnabled(store) return useTask(function* ( signal1, @@ -75,25 +66,19 @@ export class FolderLoaderSpace implements FolderLoader { } } - if (options.loadShares) { - yield store.dispatch('Files/loadSharesTree', { - client, - path: currentFolder.path, - ...(unref(hasSpaces) && { storageId: currentFolder.fileId }), - includeRoot: currentFolder.path === '/' && space.driveType !== 'personal' - }) - - for (const file of resources) { - file.indicators = getIndicators(file, store.state.Files.sharesTree, unref(hasShareJail)) - } - } - yield store.dispatch('Files/loadAncestorMetaData', { folder: currentFolder, space, client: webdav }) + if (options.loadShares) { + const ancestorMetaData = store.getters['Files/ancestorMetaData'] + for (const file of resources) { + file.indicators = getIndicators({ resource: file, ancestorMetaData }) + } + } + store.commit('Files/LOAD_FILES', { currentFolder, files: resources diff --git a/packages/web-app-files/src/store/actions.ts b/packages/web-app-files/src/store/actions.ts index d627f6f8cad..814a82e3251 100644 --- a/packages/web-app-files/src/store/actions.ts +++ b/packages/web-app-files/src/store/actions.ts @@ -1,5 +1,4 @@ import PQueue from 'p-queue' -import { dirname } from 'path' import { getParentPaths } from '../helpers/path' import { buildShare, buildCollaboratorShare } from '../helpers/resources' @@ -269,16 +268,18 @@ export default { const shareMethod = isGroupShare ? 'shareFileWithGroup' : 'shareFileWithUser' return client.shares[shareMethod](path, shareWith, options) .then((share) => { - context.commit( - 'CURRENT_FILE_OUTGOING_SHARES_UPSERT', - buildCollaboratorShare( - share.shareInfo, - context.getters.highlightedFile, - allowSharePermissions(context.rootGetters) - ) + const builtShare = buildCollaboratorShare( + share.shareInfo, + context.getters.highlightedFile, + allowSharePermissions(context.rootGetters) ) + context.commit('CURRENT_FILE_OUTGOING_SHARES_UPSERT', builtShare) + context.commit('SHARESTREE_UPSERT', { + path, + share: { ...builtShare, indirect: false, outgoing: true } + }) context.dispatch('updateCurrentFileShareTypes') - context.dispatch('loadIndicators', { client, currentFolder: path, storageId }) + context.commit('LOAD_INDICATORS', path) }) .catch((e) => { context.dispatch( @@ -292,13 +293,13 @@ export default { ) }) }, - deleteShare(context, { client, share, path, storageId, loadIndicators = false }) { + deleteShare(context, { client, share, path, loadIndicators = false }) { return client.shares.deleteShare(share.id, {} as any).then(() => { context.commit('CURRENT_FILE_OUTGOING_SHARES_REMOVE', share) context.dispatch('updateCurrentFileShareTypes') - + context.commit('SHARESTREE_REMOVE', { path, id: share.id }) if (loadIndicators) { - context.dispatch('loadIndicators', { client, currentFolder: path, storageId }) + context.commit('LOAD_INDICATORS', path) } }) }, @@ -369,9 +370,9 @@ export default { } parentPaths.forEach((queryPath) => { + const ancestorMetaData = context.state.ancestorMetaData[queryPath] ?? null const indirect = path !== queryPath - // FIXME: We need the storageId of each parent resource here - const spaceRef = indirect ? null : storageId + const spaceRef = indirect ? ancestorMetaData?.id : storageId // no need to fetch cached paths again, only adjust the "indirect" state if (context.getters.sharesTree[queryPath] && useCached) { sharesTree[queryPath] = context.getters.sharesTree[queryPath].map((s) => { @@ -424,7 +425,11 @@ export default { const link = buildShare(data.shareInfo, null, allowSharePermissions(context.rootGetters)) context.commit('CURRENT_FILE_OUTGOING_SHARES_UPSERT', link) context.dispatch('updateCurrentFileShareTypes') - context.dispatch('loadIndicators', { client, currentFolder: path, storageId }) + context.commit('LOAD_INDICATORS', path) + context.commit('SHARESTREE_UPSERT', { + path, + share: { ...link, indirect: false, outgoing: true } + }) resolve(link) }) .catch((e) => { @@ -446,34 +451,17 @@ export default { }) }) }, - removeLink(context, { share, client, path, storageId, loadIndicators = false }) { + removeLink(context, { share, client, path, loadIndicators = false }) { return client.shares.deleteShare(share.id).then(() => { context.commit('CURRENT_FILE_OUTGOING_SHARES_REMOVE', share) context.dispatch('updateCurrentFileShareTypes') - + context.commit('SHARESTREE_REMOVE', { path, id: share.id }) if (loadIndicators) { - context.dispatch('loadIndicators', { client, currentFolder: path, storageId }) + context.commit('LOAD_INDICATORS', path) } }) }, - pushResourcesToDeleteList({ commit }, resources) { - commit('PUSH_RESOURCES_TO_DELETE_LIST', resources) - }, - - async loadIndicators({ dispatch, commit }, { client, currentFolder, storageId }) { - // kind of bruteforce for now: remove the shares for the current folder and children, reload shares tree for the current folder. - // TODO: when we refactor the shares tree we want to modify shares tree nodes incrementally during adding and removing shares, not loading everything new from the backend. - commit('SHARESTREE_PRUNE_OUTSIDE_PATH', dirname(currentFolder)) - await dispatch('loadSharesTree', { - client, - path: currentFolder, - storageId, - includeRoot: currentFolder === '/' - }) - commit('LOAD_INDICATORS', currentFolder) - }, - loadAvatars({ commit, rootGetters }, { resource }) { if (!rootGetters.capabilities.files_sharing.user.profile_picture) { return diff --git a/packages/web-app-files/src/store/mutations.ts b/packages/web-app-files/src/store/mutations.ts index 53288fd4dca..becefaf2e26 100644 --- a/packages/web-app-files/src/store/mutations.ts +++ b/packages/web-app-files/src/store/mutations.ts @@ -132,6 +132,18 @@ export default { SHARESTREE_ADD(state, sharesTree) { state.sharesTree = Object.assign({}, state.sharesTree, sharesTree) }, + SHARESTREE_UPSERT(state, { path, share }) { + if (!state.sharesTree[path]) { + state.sharesTree[path] = [] + } + state.sharesTree[path].push(share) + }, + SHARESTREE_REMOVE(state, { path, id }) { + if (!state.sharesTree[path]) { + return + } + state.sharesTree[path] = state.sharesTree[path].filter((s) => s.id !== id) + }, SHARESTREE_ERROR(state, error) { state.sharesTreeError = error }, @@ -158,8 +170,7 @@ export default { LOAD_INDICATORS(state, path) { const files = state.files.filter((f) => f.path.startsWith(path)) for (const resource of files) { - const indicators = getIndicators(resource, state.sharesTree) - + const indicators = getIndicators({ resource, ancestorMetaData: state.ancestorMetaData }) if (!indicators.length && !resource.indicators.length) { continue } diff --git a/packages/web-app-files/src/views/shares/SharedViaLink.vue b/packages/web-app-files/src/views/shares/SharedViaLink.vue index 724f2322f8d..47722271124 100644 --- a/packages/web-app-files/src/views/shares/SharedViaLink.vue +++ b/packages/web-app-files/src/views/shares/SharedViaLink.vue @@ -61,7 +61,7 @@