aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_sharing/src
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2025-04-18 16:24:04 +0200
committerGitHub <noreply@github.com>2025-04-18 16:24:04 +0200
commit0e3eef3edd85ad4bd653515f45f969f02d0effb9 (patch)
tree52f5f9a378f05d4a7d3f0a31e7d857854192dcc1 /apps/files_sharing/src
parent3a699c637355e375de9a101b3575ab81a4804a4b (diff)
parentccd26448218982cb01158b455431893862e1fb62 (diff)
downloadnextcloud-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.vue79
-rw-r--r--apps/files_sharing/src/filters/AccountFilter.ts71
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)
+ }
+ }
+
}
/**