Skip to content

Commit e8df690

Browse files
authored
Merge pull request #50264 from nextcloud/backport/49259/stable30
[stable30] fix(files): File type filter UI sync with filter state
2 parents 54a1a56 + 7e2fb5d commit e8df690

File tree

5 files changed

+86
-12
lines changed

5 files changed

+86
-12
lines changed

apps/files/src/components/FileListFilter/FileListFilterType.vue

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ export default defineComponent({
4545
},
4646
4747
props: {
48+
presets: {
49+
type: Array as PropType<ITypePreset[]>,
50+
default: () => [],
51+
},
4852
typePresets: {
4953
type: Array as PropType<ITypePreset[]>,
5054
required: true,
@@ -71,17 +75,25 @@ export default defineComponent({
7175
},
7276
7377
watch: {
78+
/** Reset selected options if property is changed */
79+
presets() {
80+
this.selectedOptions = this.presets ?? []
81+
},
7482
selectedOptions(newValue, oldValue) {
7583
if (this.selectedOptions.length === 0) {
7684
if (oldValue.length !== 0) {
77-
this.$emit('update:preset')
85+
this.$emit('update:presets')
7886
}
7987
} else {
80-
this.$emit('update:preset', this.selectedOptions)
88+
this.$emit('update:presets', this.selectedOptions)
8189
}
8290
},
8391
},
8492
93+
mounted() {
94+
this.selectedOptions = this.presets ?? []
95+
},
96+
8597
methods: {
8698
resetFilter() {
8799
this.selectedOptions = []

apps/files/src/filters/TypeFilter.ts

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

7-
import { subscribe } from '@nextcloud/event-bus'
87
import { FileListFilter, registerFileListFilter } from '@nextcloud/files'
98
import { t } from '@nextcloud/l10n'
109
import Vue from 'vue'
@@ -89,12 +88,12 @@ const getTypePresets = async () => [
8988
class TypeFilter extends FileListFilter {
9089

9190
private currentInstance?: Vue
92-
private currentPresets?: ITypePreset[]
91+
private currentPresets: ITypePreset[]
9392
private allPresets?: ITypePreset[]
9493

9594
constructor() {
9695
super('files:type', 10)
97-
subscribe('files:navigation:changed', () => this.setPreset())
96+
this.currentPresets = []
9897
}
9998

10099
public async mount(el: HTMLElement) {
@@ -103,18 +102,21 @@ class TypeFilter extends FileListFilter {
103102
this.allPresets = await getTypePresets()
104103
}
105104

105+
// Already mounted
106106
if (this.currentInstance) {
107107
this.currentInstance.$destroy()
108+
delete this.currentInstance
108109
}
109110

110111
const View = Vue.extend(FileListFilterType as never)
111112
this.currentInstance = new View({
112113
propsData: {
114+
presets: this.currentPresets,
113115
typePresets: this.allPresets!,
114116
},
115117
el,
116118
})
117-
.$on('update:preset', this.setPreset.bind(this))
119+
.$on('update:presets', this.setPresets.bind(this))
118120
.$mount()
119121
}
120122

@@ -141,8 +143,9 @@ class TypeFilter extends FileListFilter {
141143
})
142144
}
143145

144-
public setPreset(presets?: ITypePreset[]) {
145-
this.currentPresets = presets
146+
public setPresets(presets?: ITypePreset[]) {
147+
this.currentPresets = presets ?? []
148+
this.currentInstance!.$props.presets = presets
146149
this.filterUpdated()
147150

148151
const chips: IFileListFilterChip[] = []
@@ -151,7 +154,7 @@ class TypeFilter extends FileListFilter {
151154
chips.push({
152155
icon: preset.icon,
153156
text: preset.label,
154-
onclick: () => this.setPreset(presets.filter(({ id }) => id !== preset.id)),
157+
onclick: () => this.removeFilterPreset(preset.id),
155158
})
156159
}
157160
} else {
@@ -160,6 +163,16 @@ class TypeFilter extends FileListFilter {
160163
this.updateChips(chips)
161164
}
162165

166+
/**
167+
* Helper callback that removed a preset from selected.
168+
* This is used when clicking on "remove" on a filter-chip.
169+
* @param presetId Id of preset to remove
170+
*/
171+
private removeFilterPreset(presetId: string) {
172+
const filtered = this.currentPresets.filter(({ id }) => id !== presetId)
173+
this.setPresets(filtered)
174+
}
175+
163176
}
164177

165178
/**

cypress/e2e/files/files-filtering.cy.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,55 @@ describe('files: Filter in files list', { testIsolation: true }, () => {
201201
getRowForFile('text.txt').should('not.exist')
202202
})
203203

204+
/** Regression test of https://github.com/nextcloud/server/issues/47251 */
205+
it('keeps filter state when changing the directory', () => {
206+
// files are visible
207+
getRowForFile('folder').should('be.visible')
208+
getRowForFile('file.txt').should('be.visible')
209+
210+
// enable type filter for folders
211+
filesFilters.filterContainter()
212+
.findByRole('button', { name: 'Type' })
213+
.should('be.visible')
214+
.click()
215+
cy.findByRole('menuitemcheckbox', { name: 'Folders' })
216+
.should('be.visible')
217+
.click()
218+
// assert the button is checked
219+
cy.findByRole('menuitemcheckbox', { name: 'Folders' })
220+
.should('have.attr', 'aria-checked', 'true')
221+
// close the menu
222+
filesFilters.filterContainter()
223+
.findByRole('button', { name: 'Type' })
224+
.click()
225+
226+
// See the chips are active
227+
filesFilters.activeFilters()
228+
.should('have.length', 1)
229+
.contains(/Folder/).should('be.visible')
230+
231+
// See that folder is visible but file not
232+
getRowForFile('folder').should('be.visible')
233+
getRowForFile('file.txt').should('not.exist')
234+
235+
// Change the directory
236+
navigateToFolder('folder')
237+
getRowForFile('folder').should('not.exist')
238+
239+
// See that the chip is still
240+
filesFilters.activeFilters()
241+
.should('have.length', 1)
242+
.contains(/Folder/).should('be.visible')
243+
// And also the button should be active
244+
filesFilters.filterContainter()
245+
.findByRole('button', { name: 'Type' })
246+
.should('be.visible')
247+
.click()
248+
cy.findByRole('menuitemcheckbox', { name: 'Folders' })
249+
.should('be.visible')
250+
.and('have.attr', 'aria-checked', 'true')
251+
})
252+
204253
it('resets filter when changing the view', () => {
205254
// All are visible by default
206255
getRowForFile('folder').should('be.visible')

dist/files-init.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/files-init.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)