diff options
author | Ferdinand Thiessen <opensource@fthiessen.de> | 2025-04-18 16:24:04 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-04-18 16:24:04 +0200 |
commit | 0e3eef3edd85ad4bd653515f45f969f02d0effb9 (patch) | |
tree | 52f5f9a378f05d4a7d3f0a31e7d857854192dcc1 /apps/files_sharing/src | |
parent | 3a699c637355e375de9a101b3575ab81a4804a4b (diff) | |
parent | ccd26448218982cb01158b455431893862e1fb62 (diff) | |
download | nextcloud-server-0e3eef3edd85ad4bd653515f45f969f02d0effb9.tar.gz nextcloud-server-0e3eef3edd85ad4bd653515f45f969f02d0effb9.zip |
Merge pull request #52002 from nextcloud/backport/51937/stable30
[stable30] perf(files_sharing): do not emit second propfind for account filter
Diffstat (limited to 'apps/files_sharing/src')
-rw-r--r-- | apps/files_sharing/src/components/FileListFilterAccount.vue | 79 | ||||
-rw-r--r-- | apps/files_sharing/src/filters/AccountFilter.ts | 71 |
2 files changed, 81 insertions, 69 deletions
diff --git a/apps/files_sharing/src/components/FileListFilterAccount.vue b/apps/files_sharing/src/components/FileListFilterAccount.vue index 89cedbf1ed8..8d4178af454 100644 --- a/apps/files_sharing/src/components/FileListFilterAccount.vue +++ b/apps/files_sharing/src/components/FileListFilterAccount.vue @@ -36,14 +36,11 @@ </template> <script setup lang="ts"> -import type { IAccountData } from '../filters/AccountFilter.ts' +import type { IAccountData } from '../files_filters/AccountFilter.ts' import { translate as t } from '@nextcloud/l10n' -import { ShareType } from '@nextcloud/sharing' import { mdiAccountMultiple } from '@mdi/js' -import { useBrowserLocation } from '@vueuse/core' import { computed, ref, watch } from 'vue' -import { useNavigation } from '../../../files/src/composables/useNavigation.ts' import FileListFilter from '../../../files/src/components/FileListFilter/FileListFilter.vue' import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js' @@ -61,8 +58,6 @@ const emit = defineEmits<{ (event: 'update:accounts', value: IAccountData[]): void }>() -const { currentView } = useNavigation() -const currentLocation = useBrowserLocation() const accountFilter = ref('') const availableAccounts = ref<IUserSelectData[]>([]) const selectedAccounts = ref<IUserSelectData[]>([]) @@ -106,71 +101,27 @@ watch(selectedAccounts, () => { }) /** - * Update the accounts owning nodes or have nodes shared to them - * @param path The path inside the current view to load for accounts - */ -async function updateAvailableAccounts(path: string = '/') { - availableAccounts.value = [] - if (!currentView.value) { - return - } - - const { contents } = await currentView.value.getContents(path) - const available = new Map<string, IUserSelectData>() - for (const node of contents) { - const owner = node.owner - if (owner && !available.has(owner)) { - available.set(owner, { - id: owner, - user: owner, - displayName: node.attributes['owner-display-name'] ?? node.owner, - }) - } - - const sharees = node.attributes.sharees?.sharee - if (sharees) { - // ensure sharees is an array (if only one share then it is just an object) - for (const sharee of [sharees].flat()) { - // Skip link shares and other without user - if (sharee.id === '') { - continue - } - if (sharee.type !== ShareType.User && sharee.type !== ShareType.Remote) { - continue - } - // Add if not already added - if (!available.has(sharee.id)) { - available.set(sharee.id, { - id: sharee.id, - user: sharee.id, - displayName: sharee['display-name'], - }) - } - } - } - } - availableAccounts.value = [...available.values()] -} - -/** * Reset this filter */ function resetFilter() { selectedAccounts.value = [] accountFilter.value = '' } -defineExpose({ resetFilter, toggleAccount }) -// When the current view changes or the current directory, -// then we need to rebuild the available accounts -watch([currentView, currentLocation], () => { - if (currentView.value) { - // we have no access to the files router here... - const path = (currentLocation.value.search ?? '?dir=/').match(/(?<=&|\?)dir=([^&#]+)/)?.[1] - resetFilter() - updateAvailableAccounts(decodeURIComponent(path ?? '/')) - } -}, { immediate: true }) +/** + * Update list of available accounts in current view. + * + * @param accounts - Accounts to use + */ +function setAvailableAccounts(accounts: IAccountData[]): void { + availableAccounts.value = accounts.map(({ uid, displayName }) => ({ displayName, id: uid, user: uid })) +} + +defineExpose({ + resetFilter, + setAvailableAccounts, + toggleAccount, +}) </script> <style scoped lang="scss"> diff --git a/apps/files_sharing/src/filters/AccountFilter.ts b/apps/files_sharing/src/filters/AccountFilter.ts index 8da4d85d67c..56bcef07200 100644 --- a/apps/files_sharing/src/filters/AccountFilter.ts +++ b/apps/files_sharing/src/filters/AccountFilter.ts @@ -4,8 +4,11 @@ */ import type { IFileListFilterChip, INode } from '@nextcloud/files' +import { subscribe } from '@nextcloud/event-bus' import { FileListFilter, registerFileListFilter } from '@nextcloud/files' +import { ShareType } from '@nextcloud/sharing' import Vue from 'vue' + import FileListFilterAccount from '../components/FileListFilterAccount.vue' export interface IAccountData { @@ -13,18 +16,28 @@ export interface IAccountData { displayName: string } -type CurrentInstance = Vue & { resetFilter: () => void, toggleAccount: (account: string) => void } +type CurrentInstance = Vue & { + resetFilter: () => void + setAvailableAccounts: (accounts: IAccountData[]) => void + toggleAccount: (account: string) => void +} /** * File list filter to filter by owner / sharee */ class AccountFilter extends FileListFilter { + private availableAccounts: IAccountData[] private currentInstance?: CurrentInstance private filterAccounts?: IAccountData[] constructor() { super('files_sharing:account', 100) + this.availableAccounts = [] + + subscribe('files:list:updated', ({ contents }) => { + this.updateAvailableAccounts(contents) + }) } public mount(el: HTMLElement) { @@ -33,11 +46,11 @@ class AccountFilter extends FileListFilter { } const View = Vue.extend(FileListFilterAccount as never) - this.currentInstance = new View({ - el, - }) - .$on('update:accounts', this.setAccounts.bind(this)) + this.currentInstance = new View({ el }) + .$on('update:accounts', (accounts?: IAccountData[]) => this.setAccounts(accounts)) .$mount() as CurrentInstance + this.currentInstance + .setAvailableAccounts(this.availableAccounts) } public filter(nodes: INode[]): INode[] { @@ -70,6 +83,11 @@ class AccountFilter extends FileListFilter { this.currentInstance?.resetFilter() } + /** + * Set accounts that should be filtered. + * + * @param accounts - Account to filter or undefined if inactive. + */ public setAccounts(accounts?: IAccountData[]) { this.filterAccounts = accounts let chips: IFileListFilterChip[] = [] @@ -85,6 +103,49 @@ class AccountFilter extends FileListFilter { this.filterUpdated() } + /** + * Update the accounts owning nodes or have nodes shared to them. + * + * @param nodes - The current content of the file list. + */ + protected updateAvailableAccounts(nodes: INode[]): void { + const available = new Map<string, IAccountData>() + + for (const node of nodes) { + const owner = node.owner + if (owner && !available.has(owner)) { + available.set(owner, { + uid: owner, + displayName: node.attributes['owner-display-name'] ?? node.owner, + }) + } + + // ensure sharees is an array (if only one share then it is just an object) + const sharees: { id: string, 'display-name': string, type: ShareType }[] = [node.attributes.sharees?.sharee].flat().filter(Boolean) + for (const sharee of [sharees].flat()) { + // Skip link shares and other without user + if (sharee.id === '') { + continue + } + if (sharee.type !== ShareType.User && sharee.type !== ShareType.Remote) { + continue + } + // Add if not already added + if (!available.has(sharee.id)) { + available.set(sharee.id, { + uid: sharee.id, + displayName: sharee['display-name'], + }) + } + } + } + + this.availableAccounts = [...available.values()] + if (this.currentInstance) { + this.currentInstance.setAvailableAccounts(this.availableAccounts) + } + } + } /** |