aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2024-11-13 17:09:33 +0100
committerFerdinand Thiessen <opensource@fthiessen.de>2025-02-18 12:34:11 +0100
commitd693dc9a00fa1f7bbbe33cc7e68415dfa1a36efd (patch)
tree5210f9522705928c18646358e93b108a62b95314 /apps
parent6f30c32aca8a1db6a7465898f9573a8a923fa06c (diff)
downloadnextcloud-server-d693dc9a00fa1f7bbbe33cc7e68415dfa1a36efd.tar.gz
nextcloud-server-d693dc9a00fa1f7bbbe33cc7e68415dfa1a36efd.zip
fix(files): Properly reset all file list filters on view change
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps')
-rw-r--r--apps/files/src/filters/FilenameFilter.ts6
-rw-r--r--apps/files/src/filters/ModifiedFilter.ts6
-rw-r--r--apps/files/src/filters/TypeFilter.ts4
-rw-r--r--apps/files/src/store/filters.ts183
-rw-r--r--apps/files/src/views/FilesList.vue1
-rw-r--r--apps/files_sharing/src/filters/AccountFilter.ts4
6 files changed, 135 insertions, 69 deletions
diff --git a/apps/files/src/filters/FilenameFilter.ts b/apps/files/src/filters/FilenameFilter.ts
index 32df078a006..5019ca42d83 100644
--- a/apps/files/src/filters/FilenameFilter.ts
+++ b/apps/files/src/filters/FilenameFilter.ts
@@ -4,7 +4,6 @@
*/
import type { IFileListFilterChip, INode } from '@nextcloud/files'
-import { subscribe } from '@nextcloud/event-bus'
import { FileListFilter } from '@nextcloud/files'
/**
@@ -16,7 +15,6 @@ export class FilenameFilter extends FileListFilter {
constructor() {
super('files:filename', 5)
- subscribe('files:navigation:changed', () => this.updateQuery(''))
}
public filter(nodes: INode[]): INode[] {
@@ -27,6 +25,10 @@ export class FilenameFilter extends FileListFilter {
})
}
+ public reset(): void {
+ this.updateQuery('')
+ }
+
public updateQuery(query: string) {
query = (query || '').trim()
diff --git a/apps/files/src/filters/ModifiedFilter.ts b/apps/files/src/filters/ModifiedFilter.ts
index 63563f24510..e7d7c2f26a7 100644
--- a/apps/files/src/filters/ModifiedFilter.ts
+++ b/apps/files/src/filters/ModifiedFilter.ts
@@ -4,7 +4,6 @@
*/
import type { IFileListFilterChip, INode } from '@nextcloud/files'
-import { subscribe } from '@nextcloud/event-bus'
import { FileListFilter, registerFileListFilter } from '@nextcloud/files'
import { t } from '@nextcloud/l10n'
import Vue from 'vue'
@@ -58,7 +57,6 @@ class ModifiedFilter extends FileListFilter {
constructor() {
super('files:modified', 50)
- subscribe('files:navigation:changed', () => this.setPreset())
}
public mount(el: HTMLElement) {
@@ -85,6 +83,10 @@ class ModifiedFilter extends FileListFilter {
return nodes.filter((node) => node.mtime === undefined || this.currentPreset!.filter(node.mtime.getTime()))
}
+ public reset(): void {
+ this.setPreset()
+ }
+
public setPreset(preset?: ITimePreset) {
this.currentPreset = preset
this.filterUpdated()
diff --git a/apps/files/src/filters/TypeFilter.ts b/apps/files/src/filters/TypeFilter.ts
index d49249789da..3955805aa5e 100644
--- a/apps/files/src/filters/TypeFilter.ts
+++ b/apps/files/src/filters/TypeFilter.ts
@@ -143,6 +143,10 @@ class TypeFilter extends FileListFilter {
})
}
+ public reset(): void {
+ this.setPresets()
+ }
+
public setPresets(presets?: ITypePreset[]) {
this.currentPresets = presets ?? []
this.currentInstance!.$props.presets = presets
diff --git a/apps/files/src/store/filters.ts b/apps/files/src/store/filters.ts
index ea8ff736b99..bc57e25a1f8 100644
--- a/apps/files/src/store/filters.ts
+++ b/apps/files/src/store/filters.ts
@@ -6,75 +6,130 @@ import type { FilterUpdateChipsEvent, IFileListFilter, IFileListFilterChip } fro
import { subscribe } from '@nextcloud/event-bus'
import { getFileListFilters } from '@nextcloud/files'
import { defineStore } from 'pinia'
+import { computed, ref } from 'vue'
import logger from '../logger'
-export const useFiltersStore = defineStore('filters', {
- state: () => ({
- chips: {} as Record<string, IFileListFilterChip[]>,
- filters: [] as IFileListFilter[],
- filtersChanged: false,
- }),
-
- getters: {
- /**
- * Currently active filter chips
- * @param state Internal state
- */
- activeChips(state): IFileListFilterChip[] {
- return Object.values(state.chips).flat()
- },
-
- /**
- * Filters sorted by order
- * @param state Internal state
- */
- sortedFilters(state): IFileListFilter[] {
- return state.filters.sort((a, b) => a.order - b.order)
- },
-
- /**
- * All filters that provide a UI for visual controlling the filter state
- */
- filtersWithUI(): Required<IFileListFilter>[] {
- return this.sortedFilters.filter((filter) => 'mount' in filter) as Required<IFileListFilter>[]
- },
- },
-
- actions: {
- addFilter(filter: IFileListFilter) {
- filter.addEventListener('update:chips', this.onFilterUpdateChips)
- filter.addEventListener('update:filter', this.onFilterUpdate)
- this.filters.push(filter)
- logger.debug('New file list filter registered', { id: filter.id })
- },
-
- removeFilter(filterId: string) {
- const index = this.filters.findIndex(({ id }) => id === filterId)
- if (index > -1) {
- const [filter] = this.filters.splice(index, 1)
- filter.removeEventListener('update:chips', this.onFilterUpdateChips)
- filter.removeEventListener('update:filter', this.onFilterUpdate)
- logger.debug('Files list filter unregistered', { id: filterId })
- }
- },
+/**
+ * Check if the given value is an instance file list filter with mount function
+ * @param value The filter to check
+ */
+function isFileListFilterWithUi(value: IFileListFilter): value is Required<IFileListFilter> {
+ return 'mount' in value
+}
+
+export const useFiltersStore = defineStore('filters', () => {
+ const chips = ref<Record<string, IFileListFilterChip[]>>({})
+ const filters = ref<IFileListFilter[]>([])
+ const filtersChanged = ref(false)
+
+ /**
+ * Currently active filter chips
+ */
+ const activeChips = computed<IFileListFilterChip[]>(
+ () => Object.values(chips.value).flat(),
+ )
+
+ /**
+ * Filters sorted by order
+ */
+ const sortedFilters = computed<IFileListFilter[]>(
+ () => filters.value.sort((a, b) => a.order - b.order),
+ )
+
+ /**
+ * All filters that provide a UI for visual controlling the filter state
+ */
+ const filtersWithUI = computed<Required<IFileListFilter>[]>(
+ () => sortedFilters.value.filter(isFileListFilterWithUi)
+ )
+
+ /**
+ * Register a new filter on the store.
+ * This will subscribe the store to the filters events.
+ *
+ * @param filter The filter to add
+ */
+ function addFilter(filter: IFileListFilter) {
+ filter.addEventListener('update:chips', onFilterUpdateChips)
+ filter.addEventListener('update:filter', onFilterUpdate)
- onFilterUpdate() {
- this.filtersChanged = true
- },
+ filters.value.push(filter)
+ logger.debug('New file list filter registered', { id: filter.id })
+ }
- onFilterUpdateChips(event: FilterUpdateChipsEvent) {
- const id = (event.target as IFileListFilter).id
- this.chips = { ...this.chips, [id]: [...event.detail] }
+ /**
+ * Unregister a filter from the store.
+ * This will remove the filter from the store and unsubscribe the store from the filer events.
+ * @param filterId Id of the filter to remove
+ */
+ function removeFilter(filterId: string) {
+ const index = filters.value.findIndex(({ id }) => id === filterId)
+ if (index > -1) {
+ const [filter] = filters.value.splice(index, 1)
+ filter.removeEventListener('update:chips', onFilterUpdateChips)
+ filter.removeEventListener('update:filter', onFilterUpdate)
+ logger.debug('Files list filter unregistered', { id: filterId })
+ }
+ }
- logger.debug('File list filter chips updated', { filter: id, chips: event.detail })
- },
+ /**
+ * Event handler for filter update events
+ * @private
+ */
+ function onFilterUpdate() {
+ filtersChanged.value = true
+ }
- init() {
- subscribe('files:filter:added', this.addFilter)
- subscribe('files:filter:removed', this.removeFilter)
- for (const filter of getFileListFilters()) {
- this.addFilter(filter)
+ /**
+ * Event handler for filter chips updates
+ * @param event The update event
+ * @private
+ */
+ function onFilterUpdateChips(event: FilterUpdateChipsEvent) {
+ const id = (event.target as IFileListFilter).id
+ chips.value = {
+ ...chips.value,
+ [id]: [...event.detail],
+ }
+
+ logger.debug('File list filter chips updated', { filter: id, chips: event.detail })
+ }
+
+ /**
+ * Event handler that resets all filters if the file list view was changed.
+ * @private
+ */
+ function onViewChanged() {
+ logger.debug('Reset all file list filters - view changed')
+
+ for (const filter of filters.value) {
+ if (filter.reset !== undefined) {
+ filter.reset()
}
- },
- },
+ }
+ }
+
+ // Initialize the store
+ subscribe('files:navigation:changed', onViewChanged)
+ subscribe('files:filter:added', addFilter)
+ subscribe('files:filter:removed', removeFilter)
+ for (const filter of getFileListFilters()) {
+ addFilter(filter)
+ }
+
+ return {
+ // state
+ chips,
+ filters,
+ filtersWithUI,
+ filtersChanged,
+
+ // getters / computed
+ activeChips,
+ sortedFilters,
+
+ // actions / methods
+ addFilter,
+ removeFilter,
+ }
})
diff --git a/apps/files/src/views/FilesList.vue b/apps/files/src/views/FilesList.vue
index dab0ba3562d..6d333202914 100644
--- a/apps/files/src/views/FilesList.vue
+++ b/apps/files/src/views/FilesList.vue
@@ -494,7 +494,6 @@ export default defineComponent({
},
mounted() {
- this.filtersStore.init()
this.fetchContent()
subscribe('files:node:deleted', this.onNodeDeleted)
diff --git a/apps/files_sharing/src/filters/AccountFilter.ts b/apps/files_sharing/src/filters/AccountFilter.ts
index 29e8088dc23..8da4d85d67c 100644
--- a/apps/files_sharing/src/filters/AccountFilter.ts
+++ b/apps/files_sharing/src/filters/AccountFilter.ts
@@ -66,6 +66,10 @@ class AccountFilter extends FileListFilter {
})
}
+ public reset(): void {
+ this.currentInstance?.resetFilter()
+ }
+
public setAccounts(accounts?: IAccountData[]) {
this.filterAccounts = accounts
let chips: IFileListFilterChip[] = []