Merge pull request #49261 from nextcloud/fix/file-list-filters-reset

fix(files): Properly reset all file list filters on view change
This commit is contained in:
Ferdinand Thiessen 2025-01-21 17:02:17 +01:00 committed by GitHub
commit 465fe42af1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 141 additions and 75 deletions

View file

@ -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()

View file

@ -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()

View file

@ -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

View file

@ -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,
}),
/**
* 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
}
getters: {
/**
* Currently active filter chips
* @param state Internal state
*/
activeChips(state): IFileListFilterChip[] {
return Object.values(state.chips).flat()
},
export const useFiltersStore = defineStore('filters', () => {
const chips = ref<Record<string, IFileListFilterChip[]>>({})
const filters = ref<IFileListFilter[]>([])
const filtersChanged = ref(false)
/**
* Filters sorted by order
* @param state Internal state
*/
sortedFilters(state): IFileListFilter[] {
return state.filters.sort((a, b) => a.order - b.order)
},
/**
* Currently active filter chips
*/
const activeChips = computed<IFileListFilterChip[]>(
() => Object.values(chips.value).flat(),
)
/**
* 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>[]
},
},
/**
* Filters sorted by order
*/
const sortedFilters = computed<IFileListFilter[]>(
() => filters.value.sort((a, b) => a.order - b.order),
)
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 })
},
/**
* All filters that provide a UI for visual controlling the filter state
*/
const filtersWithUI = computed<Required<IFileListFilter>[]>(
() => sortedFilters.value.filter(isFileListFilterWithUi)
)
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 })
/**
* 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)
filters.value.push(filter)
logger.debug('New file list filter registered', { id: filter.id })
}
/**
* 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 })
}
}
/**
* Event handler for filter update events
* @private
*/
function onFilterUpdate() {
filtersChanged.value = true
}
/**
* 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()
}
},
}
}
onFilterUpdate() {
this.filtersChanged = true
},
// 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)
}
onFilterUpdateChips(event: FilterUpdateChipsEvent) {
const id = (event.target as IFileListFilter).id
this.chips = { ...this.chips, [id]: [...event.detail] }
return {
// state
chips,
filters,
filtersWithUI,
filtersChanged,
logger.debug('File list filter chips updated', { filter: id, chips: event.detail })
},
// getters / computed
activeChips,
sortedFilters,
init() {
subscribe('files:filter:added', this.addFilter)
subscribe('files:filter:removed', this.removeFilter)
for (const filter of getFileListFilters()) {
this.addFilter(filter)
}
},
},
// actions / methods
addFilter,
removeFilter,
}
})

View file

@ -526,7 +526,6 @@ export default defineComponent({
},
mounted() {
this.filtersStore.init()
this.fetchContent()
subscribe('files:node:deleted', this.onNodeDeleted)

View file

@ -66,6 +66,10 @@ class AccountFilter extends FileListFilter {
})
}
public reset(): void {
this.currentInstance?.resetFilter()
}
public setAccounts(accounts?: IAccountData[]) {
this.filterAccounts = accounts
let chips: IFileListFilterChip[] = []

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
{"version":3,"sourceRoot":"","sources":["settings.scss","../../../core/css/variables.scss","../../../core/css/functions.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA,GCEA;AAAA;AAAA;AAAA,GCFA;AAAA;AAAA;AAAA,GFUC,0BACC,WAKF,OACC,WAID,4BE2BC,2CFvBD,mBEuBC,kDFnBD,qBEmBC,yCFfD,0BEeC,wCFXD,oEEWC,2CFPD,oCACC,oBACA,0BACA,+BACA,mBAGD,4BACC,oBACA,kCAGD,yBACC,WAIA,wCACC,kBACA,yDACC,gBAIA,mOACC,WAKH,uCACC,aAGD,sCACC,WAED,uDACC,WAKD,gBACC,WAIF,mBACC,aACA,aACA,iBACA,uEACA,qBAEA,4BACC,kBACA,SAEA,+BACC,mBAIA,qCACC,iBAKH,kCACC,sBACA,mBACA,gBAGD,mGACC,4BACA,0BACA,WAMF,oBACC,kBACA,wCACC,0BAIF,aACC,oBACA,4CACA,kFACA,8CACA,wCACA,2CACA,8CACA,6CACA,mBACA,yCAEA,sCAEC,oDAGD,+CAEC,6DACA,oDAGD,6BACC,qCACA,WACA,YAIF,6BACC,oBACA,kCAEA,mCACC,WAIA,oCACC,kBACA,oBACA,iBACA,2BACA,WACA,mBACA,QAEA,0CACC,mBACA,uBACA,gBAKD,gIACC,kBACA,qBACA,UACA,oBACA,YAKH,qCACC,kBACA,wBACA,MACA,SAEA,yCACC,qBAIF,4CACC,eAGD,4CACC,sBACA,WACA,YACA,YAMF,qBACC,aACA,sBACA,SACA,YAEA,uBACC,aAGD,uCACC,sBACA,cACA,yBAIF,iBACC,kBACA,eACA,oCACA,qCACA,6CACA,SACA,gBACA,YAEA,8CAEC,+CACA,2CAEA,0FACC,WAIF,uCACC,0BACA,qBACA,gCACA,WACA,eAEA,wDACC,qBACA,sBACA,eAIF,sCACC,kCAGC,4DAEC,iBACA,kBAEA,kFACC,YAGD,mEACC,oDAEA,kFACC,iBAIF,qEACC,WAEA,eAEA,uEACC,eAQN,gBACC,YAIA,2BACC,kCAGD,mBACC,YAIF,sCAEC,aAGD,eACC,WAGD,YACC,qBAIA,aACC,WACA,yBACA,YAGD,WACC,WACA,yBACA,YAMD,oBACC,sBAGD,iBACC,eAKD,iCACC,aACA,eACA,sBACA,SACA,gDACC,aACA,eACA,sBACA,sDACC,oBAIF,kGACC,cACA,YACA,gBAKA,iEACC,kBACA,UAED,+EACC,oBACA,oBACA,wBACA,qBAIF,wCACC,WAGD,iDACC,qBAGD,sDACC,kBACA,qBACA,WACA,0BACA,eACA,gBACA,WAQF,oBACC,gBAGD,wBACC,yBAGD,oDACC,WACA,YACA,wCAOD,oBACC,UACA,cACA,gBACA,uBAGD,2BACC,UAKD,oCAEC,cAKD,wEAEC,aAIF,gBACC,kBACA,QACA,mBAEA,sBACC,YAGD,sBACC,iBAKF,WACC,WAEA,cACC,WACA,UACA,uBACA,4CACA,iBACA,mBAGD,cACC,4CACA,UACA,uBACA,iBACA,mBAKD,gBACC,0BACA,cACA,eACA,uBACA,gBAGD,wBACC,0BAEA,gCACC,kBAIF,sCACC,kBAGD,sDAEC,cACA,eACA,eAEA,0EACC,UACA,qBACA,uBACA,gBAIF,8BACC,eAGD,kCACC,wBACA,cAIF,2BACC,mBAMA,oBACC,mBACA,sBACA,WAGD,gCACC,0BAIA,gGACC,cAOH,SACC,gBAEA,0BACC,4CAID,YACC,oBACA,mBACA,uBACA,eACA,iBACA,gBACA,aAEA,uBACC,aACA,mBACA,uBACA,oCACA,qCACA,yDACA,sBACA,oCAKF,WACC,kBACA,kBACA,oCACA,gBAKF,KACC,mBACA,mBAGD,SACC,aAGD,mBACC,mBAGD,eACC,gBAOA,+IACC,sBAEA,+KACC,aAGD,mKACC,WACA,YACA,kCACA,qBACA,kBAGD,mOACC,sCAGD,mNACC,sCAGD,mNACC,oCAMF,sBACC,aAGD,YACC,oBAGD,kBACC,0BAGD,yBACC,0BAGD,sBACC,0BAGD,oCACC,uBAIF,yCACC,uBAGD,wBACC,qBAGD,2BACC,wBAEA,gBACA,aACA,yBACA,sBAKD,WACC,kBACA,2BACA,WAGD,2DAGC,qBAIA,mCACC,qBACA,YACA,eAGD,+EAEC,YAIF,yBACC,mCACC,YACA,iBACA,cACA,iDAIF,eACC,WAGD,SACC,yBAGD,QACC,qBACA,YACA,WACA,2BAEA,gBACC,kBAIF,qBACC,sBACA,qBACA,YACA,iBAGD,kBACC,qBACA,gBAIA,aACC,sCACA,mCAGD,WACC,oCAGD,mBACC,sCACA,oBAMF,8CACC,yBACA,YAGD,wBACC,WACA,YACA,mBACA,kBACA,+DAIA,oBACC,yBACA,gBAEA,uBACC,cAGD,uBACC,kBAIF,0BACC,YACA,gCAGD,oDACC,yBAGD,wDACC,2BAGD,uBACC,cAKD,oBACC,0BAGD,oCACC,gBAIF,2BACC,aACA,eACA,mDAEA,8BACC,kBAGD,6BACC,WAIF,eACC,mBAEA,iBACC,qBACA,cAIF,SACC,UAGD,eACC,iBACA,mBACA,WAGD,UACI,+CAGJ,2BACE,GACE,YAGJ,mCACE,GACE","file":"settings.css"}
{"version":3,"sourceRoot":"","sources":["settings.scss","../../../core/css/variables.scss","../../../core/css/functions.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAAA,GCEA;AAAA;AAAA;AAAA,GCFA;AAAA;AAAA;AAAA,GFUC,0BACC,WAKF,OACC,WAID,4BE2BC,2CFvBD,mBEuBC,kDFnBD,qBEmBC,yCFfD,0BEeC,wCFXD,oEEWC,2CFPD,oCACC,oBACA,0BACA,+BACA,mBAGD,4BACC,oBACA,kCAGD,yBACC,WAIA,wCACC,kBACA,yDACC,gBAIA,mOACC,WAKH,uCACC,aAGD,sCACC,WAED,uDACC,WAKD,gBACC,WAIF,mBACC,aACA,aACA,iBACA,uEACA,qBAEA,4BACC,kBACA,SAEA,+BACC,mBAIA,qCACC,iBAKH,kCACC,sBACA,mBACA,gBAGD,mGACC,4BACA,0BACA,WAMF,oBACC,kBACA,wCACC,0BAIF,aACC,oBACA,4CACA,kFACA,8CACA,wCACA,2CACA,8CACA,6CACA,mBACA,yCAEA,sCAEC,oDAGD,+CAEC,6DACA,oDAGD,6BACC,qCACA,WACA,YAIF,6BACC,oBACA,kCAEA,mCACC,WAIA,oCACC,kBACA,oBACA,iBACA,2BACA,WACA,mBACA,QAEA,0CACC,mBACA,uBACA,gBAKD,gIACC,kBACA,qBACA,UACA,oBACA,YAKH,qCACC,kBACA,wBACA,MACA,SAEA,yCACC,qBAIF,4CACC,eAGD,4CACC,sBACA,WACA,YACA,YAMF,qBACC,aACA,sBACA,SACA,YAEA,uBACC,aAGD,uCACC,sBACA,cACA,yBAIF,iBACC,kBACA,eACA,oCACA,qCACA,6CACA,SACA,gBACA,YAEA,8CAEC,+CACA,2CAEA,0FACC,WAIF,uCACC,0BACA,qBACA,gCACA,WACA,eAEA,wDACC,qBACA,sBACA,eAIF,sCACC,kCAGC,4DAEC,iBACA,kBAEA,kFACC,YAGD,mEACC,oDAEA,kFACC,iBAIF,qEACC,WAEA,eAEA,uEACC,eAQN,gBACC,YAIA,2BACC,kCAGD,mBACC,YAIF,sCAEC,aAGD,eACC,WAGD,YACC,qBAIA,aACC,WACA,yBACA,YAGD,WACC,WACA,yBACA,YAMD,oBACC,sBAGD,iBACC,eAKD,iCACC,aACA,eACA,sBACA,SACA,gDACC,aACA,eACA,sBACA,sDACC,oBAIF,kGACC,cACA,YACA,gBAKA,iEACC,kBACA,UAED,+EACC,oBACA,oBACA,wBACA,qBAIF,wCACC,WAGD,iDACC,qBAGD,sDACC,kBACA,qBACA,WACA,0BACA,eACA,gBACA,WAQF,oBACC,gBAGD,wBACC,yBAGD,oDACC,WACA,YACA,wCAOD,oBACC,UACA,cACA,gBACA,uBAGD,2BACC,UAKD,oCAEC,cAKD,wEAEC,aAIF,gBACC,kBACA,QACA,mBAEA,sBACC,YAGD,sBACC,iBAKF,WACC,WAEA,cACC,WACA,UACA,uBACA,4CACA,iBACA,mBAGD,cACC,4CACA,UACA,uBACA,iBACA,mBAKD,gBACC,0BACA,cACA,eACA,uBACA,gBAGD,wBACC,0BAEA,gCACC,kBAIF,sCACC,kBAGD,sDAEC,cACA,eACA,eAEA,0EACC,UACA,qBACA,uBACA,gBAIF,8BACC,eAGD,kCACC,wBACA,cAIF,2BACC,mBAMA,oBACC,mBACA,sBACA,WAGD,gCACC,0BAIA,gGACC,cAOH,SACC,gBAEA,0BACC,4CAID,YACC,oBACA,mBACA,uBACA,eACA,iBACA,gBACA,aAEA,uBACC,aACA,mBACA,uBACA,oCACA,qCACA,yDACA,sBACA,oCAKF,WACC,kBACA,kBACA,oCACA,gBAKF,KACC,mBACA,mBAGD,SACC,aAGD,mBACC,mBAGD,eACC,gBAOA,+IACC,sBAEA,+KACC,aAGD,mKACC,WACA,YACA,kCACA,qBACA,kBAGD,mOACC,sCAGD,mNACC,sCAGD,mNACC,oCAMF,sBACC,aAGD,YACC,oBAGD,kBACC,0BAGD,yBACC,0BAGD,sBACC,0BAGD,oCACC,uBAIF,yCACC,uBAGD,wBACC,qBAGD,2BACC,wBAEA,gBACA,aACA,yBACA,sBAKD,WACC,kBACA,2BACA,WAGD,2DAGC,qBAIA,mCACC,qBACA,YACA,eAGD,+EAEC,YAIF,yBACC,mCACC,YACA,iBACA,cACA,iDAIF,eACC,WAGD,SACC,yBAGD,QACC,qBACA,YACA,WACA,2BAEA,gBACC,kBAIF,qBACC,sBACA,qBACA,YACA,iBAGD,kBACC,qBACA,gBAIA,aACC,sCACA,mCAGD,WACC,oCAGD,mBACC,sCACA,oBAMF,8CACC,yBACA,YAGD,wBACC,WACA,YACA,mBACA,kBACA,+DAIA,oBACC,yBACA,gBAEA,uBACC,cAGD,uBACC,kBAIF,0BACC,YACA,gCAGD,oDACC,yBAGD,wDACC,2BAGD,uBACC,cAKD,oBACC,0BAGD,oCACC,gBAIF,2BACC,aACA,eACA,mDAEA,8BACC,SACA,eACA,iBAGD,6BACC,WAIF,eACC,mBAEA,iBACC,qBACA,cAIF,SACC,UAGD,eACC,iBACA,mBACA,WAGD,UACI,+CAGJ,2BACE,GACE,YAGJ,mCACE,GACE","file":"settings.css"}

4
dist/files-init.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
dist/files-main.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long