Skip to content

Commit 068ab41

Browse files
committed
fix(files): Ensure search query is cleared when changing view or directory
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
1 parent 8c87769 commit 068ab41

File tree

4 files changed

+186
-3
lines changed

4 files changed

+186
-3
lines changed

apps/files/src/views/FilesList.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,13 +426,15 @@ export default defineComponent({
426426
427427
logger.debug('View changed', { newView, oldView })
428428
this.selectionStore.reset()
429+
this.resetSearch()
429430
this.fetchContent()
430431
},
431432
432433
dir(newDir, oldDir) {
433434
logger.debug('Directory changed', { newDir, oldDir })
434435
// TODO: preserve selection on browsing?
435436
this.selectionStore.reset()
437+
this.resetSearch()
436438
this.fetchContent()
437439
438440
// Scroll to top, force virtual scroller to re-render
@@ -600,6 +602,14 @@ export default defineComponent({
600602
console.debug('Files app handling search event from unified search...', searchEvent)
601603
this.filterText = searchEvent.query
602604
}, 500),
605+
606+
/**
607+
* Reset the search query
608+
*/
609+
resetSearch() {
610+
this.filterText = ''
611+
},
612+
603613
openSharingSidebar() {
604614
if (!this.currentFolder) {
605615
logger.debug('No current folder found for opening sharing sidebar')

core/src/views/UnifiedSearchModal.vue

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@
1313
<div class="unified-search-modal__header">
1414
<h2>{{ t('core', 'Unified search') }}</h2>
1515
<NcInputField ref="searchInput"
16+
data-cy-unified-search-input
1617
:value.sync="searchQuery"
1718
type="text"
1819
:label="t('core', 'Search apps, files, tags, messages') + '...'"
1920
@update:value="debouncedFind" />
20-
<div class="unified-search-modal__filters">
21+
<div class="unified-search-modal__filters" data-cy-unified-search-filters>
2122
<NcActions :menu-name="t('core', 'Apps and Settings')" :open.sync="providerActionMenuIsOpen">
2223
<template #icon>
2324
<ListBox :size="20" />
@@ -31,7 +32,7 @@
3132
{{ provider.name }}
3233
</NcActionButton>
3334
</NcActions>
34-
<NcActions :menu-name="t('core', 'Date')" :open.sync="dateActionMenuIsOpen">
35+
<NcActions :menu-name="t('core', 'Date')" :open.sync="dateActionMenuIsOpen" data-cy-unified-search-filter="date">
3536
<template #icon>
3637
<CalendarRangeIcon :size="20" />
3738
</template>
@@ -57,6 +58,7 @@
5758
<SearchableList :label-text="t('core', 'Search people')"
5859
:search-list="userContacts"
5960
:empty-content-text="t('core', 'Not found')"
61+
data-cy-unified-search-filter="people"
6062
@search-term-change="debouncedFilterContacts"
6163
@item-selected="applyPersonFilter">
6264
<template #trigger>
@@ -68,7 +70,7 @@
6870
</NcButton>
6971
</template>
7072
</SearchableList>
71-
<NcButton v-if="supportFiltering" @click="closeModal">
73+
<NcButton v-if="supportFiltering" data-cy-unified-search-filter="current-view" @click="closeModal">
7274
{{ t('core', 'Filter in current view') }}
7375
<template #icon>
7476
<FilterIcon :size="20" />

cypress/e2e/core-utils.ts

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @copyright Copyright (c) 2024 Ferdinand Thiessen <opensource@fthiessen.de>
3+
*
4+
* @author Ferdinand Thiessen <opensource@fthiessen.de>
5+
*
6+
* @license AGPL-3.0-or-later
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as
10+
* published by the Free Software Foundation, either version 3 of the
11+
* License, or (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
*
21+
*/
22+
23+
/**
24+
* Get the unified search modal (if open)
25+
*/
26+
export function getUnifiedSearchModal() {
27+
return cy.get('#unified-search')
28+
}
29+
30+
/**
31+
* Open the unified search modal
32+
*/
33+
export function openUnifiedSearch() {
34+
cy.get('button[aria-label="Unified search"]').click({ force: true })
35+
// wait for it to be open
36+
getUnifiedSearchModal().should('be.visible')
37+
}
38+
39+
/**
40+
* Close the unified search modal
41+
*/
42+
export function closeUnifiedSearch() {
43+
getUnifiedSearchModal().find('button[aria-label="Close"]').click({ force: true })
44+
getUnifiedSearchModal().should('not.be.visible')
45+
}
46+
47+
/**
48+
* Get the input field of the unified search
49+
*/
50+
export function getUnifiedSearchInput() {
51+
return getUnifiedSearchModal().find('[data-cy-unified-search-input]')
52+
}
53+
54+
export enum UnifiedSearchFilter {
55+
FilterCurrentView = 'current-view',
56+
People = 'people',
57+
Date = 'date',
58+
}
59+
60+
/**
61+
* Get a filter action from the unified search
62+
* @param filter The filter to get
63+
*/
64+
export function getUnifiedSearchFilter(filter: UnifiedSearchFilter) {
65+
return getUnifiedSearchModal().find(`[data-cy-unified-search-filters] [data-cy-unified-search-filter="${CSS.escape(filter)}"]`)
66+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
* @copyright Copyright (c) 2024 Ferdinand Thiessen <opensource@fthiessen.de>
3+
*
4+
* @author Ferdinand Thiessen <opensource@fthiessen.de>
5+
*
6+
* @license AGPL-3.0-or-later
7+
*
8+
* This program is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Affero General Public License as
10+
* published by the Free Software Foundation, either version 3 of the
11+
* License, or (at your option) any later version.
12+
*
13+
* This program is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Affero General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Affero General Public License
19+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
20+
*
21+
*/
22+
23+
import type { User } from '@nextcloud/cypress'
24+
import { getRowForFile, navigateToFolder } from './FilesUtils'
25+
import { UnifiedSearchFilter, getUnifiedSearchFilter, getUnifiedSearchInput, getUnifiedSearchModal, openUnifiedSearch } from '../core-utils.ts'
26+
27+
describe('files: Search and filter in files list', { testIsolation: true }, () => {
28+
let user: User
29+
30+
beforeEach(() => cy.createRandomUser().then(($user) => {
31+
user = $user
32+
33+
cy.mkdir(user, '/a folder')
34+
cy.uploadContent(user, new Blob([]), 'text/plain', '/b file')
35+
cy.uploadContent(user, new Blob([]), 'text/plain', '/a folder/c file')
36+
cy.login(user)
37+
cy.visit('/apps/files')
38+
}))
39+
40+
it('filters current view', () => {
41+
// All are visible by default
42+
getRowForFile('a folder').should('be.visible')
43+
getRowForFile('b file').should('be.visible')
44+
45+
// Set up a search query
46+
openUnifiedSearch()
47+
getUnifiedSearchInput().type('a folder')
48+
getUnifiedSearchFilter(UnifiedSearchFilter.FilterCurrentView).click({ force: true })
49+
// Wait for modal to close
50+
getUnifiedSearchModal().should('not.be.visible')
51+
52+
// See that only the folder is visible
53+
getRowForFile('a folder').should('be.visible')
54+
getRowForFile('b file').should('not.exist')
55+
})
56+
57+
it('resets filter when changeing the directory', () => {
58+
// All are visible by default
59+
getRowForFile('a folder').should('be.visible')
60+
getRowForFile('b file').should('be.visible')
61+
62+
// Set up a search query
63+
openUnifiedSearch()
64+
getUnifiedSearchInput().type('a folder')
65+
getUnifiedSearchFilter(UnifiedSearchFilter.FilterCurrentView).click({ force: true })
66+
// Wait for modal to close
67+
getUnifiedSearchModal().should('not.be.visible')
68+
69+
// See that only the folder is visible
70+
getRowForFile('a folder').should('be.visible')
71+
getRowForFile('b file').should('not.exist')
72+
73+
// go to that folder
74+
navigateToFolder('a folder')
75+
76+
// see that the folder is not filtered
77+
getRowForFile('c file').should('be.visible')
78+
})
79+
80+
it('resets filter when changeing the view', () => {
81+
// All are visible by default
82+
getRowForFile('a folder').should('be.visible')
83+
getRowForFile('b file').should('be.visible')
84+
85+
// Set up a search query
86+
openUnifiedSearch()
87+
getUnifiedSearchInput().type('a folder')
88+
getUnifiedSearchFilter(UnifiedSearchFilter.FilterCurrentView).click({ force: true })
89+
// Wait for modal to close
90+
getUnifiedSearchModal().should('not.be.visible')
91+
92+
// See that only the folder is visible
93+
getRowForFile('a folder').should('be.visible')
94+
getRowForFile('b file').should('not.exist')
95+
96+
// go to other view
97+
cy.get('[data-cy-files-navigation-item="recent"] a').click({ force: true })
98+
// wait for view changed
99+
cy.url().should('match', /apps\/files\/recent/)
100+
101+
// see that the folder is not filtered
102+
getRowForFile('a folder').should('be.visible')
103+
getRowForFile('b file').should('be.visible')
104+
})
105+
})

0 commit comments

Comments
 (0)