Skip to content

Commit 8d2c83e

Browse files
committed
perf(files_sharing): do not require second propfind for account filter
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
1 parent 9c64099 commit 8d2c83e

File tree

2 files changed

+81
-69
lines changed

2 files changed

+81
-69
lines changed

apps/files_sharing/src/components/FileListFilterAccount.vue

Lines changed: 15 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,11 @@
3636
</template>
3737

3838
<script setup lang="ts">
39-
import type { IAccountData } from '../filters/AccountFilter.ts'
39+
import type { IAccountData } from '../files_filters/AccountFilter.ts'
4040
4141
import { translate as t } from '@nextcloud/l10n'
42-
import { ShareType } from '@nextcloud/sharing'
4342
import { mdiAccountMultiple } from '@mdi/js'
44-
import { useBrowserLocation } from '@vueuse/core'
4543
import { computed, ref, watch } from 'vue'
46-
import { useNavigation } from '../../../files/src/composables/useNavigation.ts'
4744
4845
import FileListFilter from '../../../files/src/components/FileListFilter/FileListFilter.vue'
4946
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
@@ -61,8 +58,6 @@ const emit = defineEmits<{
6158
(event: 'update:accounts', value: IAccountData[]): void
6259
}>()
6360
64-
const { currentView } = useNavigation()
65-
const currentLocation = useBrowserLocation()
6661
const accountFilter = ref('')
6762
const availableAccounts = ref<IUserSelectData[]>([])
6863
const selectedAccounts = ref<IUserSelectData[]>([])
@@ -105,72 +100,28 @@ watch(selectedAccounts, () => {
105100
emit('update:accounts', accounts)
106101
})
107102
108-
/**
109-
* Update the accounts owning nodes or have nodes shared to them
110-
* @param path The path inside the current view to load for accounts
111-
*/
112-
async function updateAvailableAccounts(path: string = '/') {
113-
availableAccounts.value = []
114-
if (!currentView.value) {
115-
return
116-
}
117-
118-
const { contents } = await currentView.value.getContents(path)
119-
const available = new Map<string, IUserSelectData>()
120-
for (const node of contents) {
121-
const owner = node.owner
122-
if (owner && !available.has(owner)) {
123-
available.set(owner, {
124-
id: owner,
125-
user: owner,
126-
displayName: node.attributes['owner-display-name'] ?? node.owner,
127-
})
128-
}
129-
130-
const sharees = node.attributes.sharees?.sharee
131-
if (sharees) {
132-
// ensure sharees is an array (if only one share then it is just an object)
133-
for (const sharee of [sharees].flat()) {
134-
// Skip link shares and other without user
135-
if (sharee.id === '') {
136-
continue
137-
}
138-
if (sharee.type !== ShareType.User && sharee.type !== ShareType.Remote) {
139-
continue
140-
}
141-
// Add if not already added
142-
if (!available.has(sharee.id)) {
143-
available.set(sharee.id, {
144-
id: sharee.id,
145-
user: sharee.id,
146-
displayName: sharee['display-name'],
147-
})
148-
}
149-
}
150-
}
151-
}
152-
availableAccounts.value = [...available.values()]
153-
}
154-
155103
/**
156104
* Reset this filter
157105
*/
158106
function resetFilter() {
159107
selectedAccounts.value = []
160108
accountFilter.value = ''
161109
}
162-
defineExpose({ resetFilter, toggleAccount })
163110
164-
// When the current view changes or the current directory,
165-
// then we need to rebuild the available accounts
166-
watch([currentView, currentLocation], () => {
167-
if (currentView.value) {
168-
// we have no access to the files router here...
169-
const path = (currentLocation.value.search ?? '?dir=/').match(/(?<=&|\?)dir=([^&#]+)/)?.[1]
170-
resetFilter()
171-
updateAvailableAccounts(decodeURIComponent(path ?? '/'))
172-
}
173-
}, { immediate: true })
111+
/**
112+
* Update list of available accounts in current view.
113+
*
114+
* @param accounts - Accounts to use
115+
*/
116+
function setAvailableAccounts(accounts: IAccountData[]): void {
117+
availableAccounts.value = accounts.map(({ uid, displayName }) => ({ displayName, id: uid, user: uid }))
118+
}
119+
120+
defineExpose({
121+
resetFilter,
122+
setAvailableAccounts,
123+
toggleAccount,
124+
})
174125
</script>
175126

176127
<style scoped lang="scss">

apps/files_sharing/src/filters/AccountFilter.ts

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,27 +4,40 @@
44
*/
55
import type { IFileListFilterChip, INode } from '@nextcloud/files'
66

7+
import { subscribe } from '@nextcloud/event-bus'
78
import { FileListFilter, registerFileListFilter } from '@nextcloud/files'
9+
import { ShareType } from '@nextcloud/sharing'
810
import Vue from 'vue'
11+
912
import FileListFilterAccount from '../components/FileListFilterAccount.vue'
1013

1114
export interface IAccountData {
1215
uid: string
1316
displayName: string
1417
}
1518

16-
type CurrentInstance = Vue & { resetFilter: () => void, toggleAccount: (account: string) => void }
19+
type CurrentInstance = Vue & {
20+
resetFilter: () => void
21+
setAvailableAccounts: (accounts: IAccountData[]) => void
22+
toggleAccount: (account: string) => void
23+
}
1724

1825
/**
1926
* File list filter to filter by owner / sharee
2027
*/
2128
class AccountFilter extends FileListFilter {
2229

30+
private availableAccounts: IAccountData[]
2331
private currentInstance?: CurrentInstance
2432
private filterAccounts?: IAccountData[]
2533

2634
constructor() {
2735
super('files_sharing:account', 100)
36+
this.availableAccounts = []
37+
38+
subscribe('files:list:updated', ({ contents }) => {
39+
this.updateAvailableAccounts(contents)
40+
})
2841
}
2942

3043
public mount(el: HTMLElement) {
@@ -33,11 +46,11 @@ class AccountFilter extends FileListFilter {
3346
}
3447

3548
const View = Vue.extend(FileListFilterAccount as never)
36-
this.currentInstance = new View({
37-
el,
38-
})
39-
.$on('update:accounts', this.setAccounts.bind(this))
49+
this.currentInstance = new View({ el })
50+
.$on('update:accounts', (accounts?: IAccountData[]) => this.setAccounts(accounts))
4051
.$mount() as CurrentInstance
52+
this.currentInstance
53+
.setAvailableAccounts(this.availableAccounts)
4154
}
4255

4356
public filter(nodes: INode[]): INode[] {
@@ -70,6 +83,11 @@ class AccountFilter extends FileListFilter {
7083
this.currentInstance?.resetFilter()
7184
}
7285

86+
/**
87+
* Set accounts that should be filtered.
88+
*
89+
* @param accounts - Account to filter or undefined if inactive.
90+
*/
7391
public setAccounts(accounts?: IAccountData[]) {
7492
this.filterAccounts = accounts
7593
let chips: IFileListFilterChip[] = []
@@ -85,6 +103,49 @@ class AccountFilter extends FileListFilter {
85103
this.filterUpdated()
86104
}
87105

106+
/**
107+
* Update the accounts owning nodes or have nodes shared to them.
108+
*
109+
* @param nodes - The current content of the file list.
110+
*/
111+
protected updateAvailableAccounts(nodes: INode[]): void {
112+
const available = new Map<string, IAccountData>()
113+
114+
for (const node of nodes) {
115+
const owner = node.owner
116+
if (owner && !available.has(owner)) {
117+
available.set(owner, {
118+
uid: owner,
119+
displayName: node.attributes['owner-display-name'] ?? node.owner,
120+
})
121+
}
122+
123+
// ensure sharees is an array (if only one share then it is just an object)
124+
const sharees: { id: string, 'display-name': string, type: ShareType }[] = [node.attributes.sharees?.sharee].flat().filter(Boolean)
125+
for (const sharee of [sharees].flat()) {
126+
// Skip link shares and other without user
127+
if (sharee.id === '') {
128+
continue
129+
}
130+
if (sharee.type !== ShareType.User && sharee.type !== ShareType.Remote) {
131+
continue
132+
}
133+
// Add if not already added
134+
if (!available.has(sharee.id)) {
135+
available.set(sharee.id, {
136+
uid: sharee.id,
137+
displayName: sharee['display-name'],
138+
})
139+
}
140+
}
141+
}
142+
143+
this.availableAccounts = [...available.values()]
144+
if (this.currentInstance) {
145+
this.currentInstance.setAvailableAccounts(this.availableAccounts)
146+
}
147+
}
148+
88149
}
89150

90151
/**

0 commit comments

Comments
 (0)