Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 0 additions & 82 deletions core/src/components/UnifiedSearch/SearchFilterChip.vue

This file was deleted.

26 changes: 19 additions & 7 deletions core/src/components/UnifiedSearch/UnifiedSearchModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,12 @@
</NcCheckboxRadioSwitch>
</div>
<div class="unified-search-modal__filters-applied">
<FilterChip
<NcChip
v-for="filter in filters"
:key="filter.id"
:text="filter.name ?? filter.text"
pretext=""
@delete="removeFilter(filter)">
:aria-label-close="t('core', 'Remove filter: {text}', { text: filter.name ?? filter.text })"
@close="removeFilter(filter)">
<template #icon>
<NcAvatar
v-if="filter.type === 'person'"
Expand All @@ -128,9 +128,13 @@
hideUserStatus
:hideFavorite="false" />
<IconCalendarRange v-else-if="filter.type === 'date'" />
<img v-else :src="filter.icon" alt="">
<img
v-else
:src="filter.icon"
class="unified-search-modal__filter-icon"
alt="">
</template>
</FilterChip>
</NcChip>
</div>
</div>

Expand Down Expand Up @@ -233,6 +237,7 @@ import NcActions from '@nextcloud/vue/components/NcActions'
import NcAvatar from '@nextcloud/vue/components/NcAvatar'
import NcButton from '@nextcloud/vue/components/NcButton'
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
import NcChip from '@nextcloud/vue/components/NcChip'
import NcEmptyContent from '@nextcloud/vue/components/NcEmptyContent'
import NcTextField from '@nextcloud/vue/components/NcTextField'
import IconAccountGroup from 'vue-material-design-icons/AccountGroupOutline.vue'
Expand All @@ -245,7 +250,6 @@ import IconListBox from 'vue-material-design-icons/ListBox.vue'
import IconMagnify from 'vue-material-design-icons/Magnify.vue'
import CustomDateRangeModal from './CustomDateRangeModal.vue'
import SearchableList from './SearchableList.vue'
import FilterChip from './SearchFilterChip.vue'
import SearchResult from './SearchResult.vue'
import { useUnifiedSearch } from '../../composables/useUnifiedSearch.ts'
import { unifiedSearchLogger } from '../../logger.js'
Expand All @@ -271,11 +275,11 @@ export default defineComponent({
IconMagnify,

CustomDateRangeModal,
FilterChip,
NcActions,
NcActionButton,
NcAvatar,
NcButton,
NcChip,
NcEmptyContent,
NcCheckboxRadioSwitch,
NcTextField,
Expand Down Expand Up @@ -1299,6 +1303,14 @@ export default defineComponent({
padding-top: 4px;
display: flex;
flex-wrap: wrap;
gap: var(--default-grid-baseline);
}

&__filter-icon {
width: 20px;
height: 20px;
object-fit: contain;
filter: var(--background-invert-if-bright);
}

&__no-content {
Expand Down
2 changes: 0 additions & 2 deletions dist/1598-1598.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/1598-1598.js.map

This file was deleted.

1 change: 0 additions & 1 deletion dist/1598-1598.js.map.license

This file was deleted.

2 changes: 2 additions & 0 deletions dist/6692-6692.js

Large diffs are not rendered by default.

File renamed without changes.
1 change: 1 addition & 0 deletions dist/6692-6692.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/6692-6692.js.map.license
4 changes: 2 additions & 2 deletions dist/core-common.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/core-common.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/core-unified-search.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/core-unified-search.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/files-main.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/files-main.js.map

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/files_sharing-init.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/files_sharing-init.js.map

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions tests/playwright/e2e/core/unified-search-filter-chips.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { expect } from '@playwright/test'
import { test } from '../../support/fixtures/random-user-session.ts'
import { UnifiedSearchPage } from '../../support/sections/UnifiedSearchPage.ts'

test.describe('Header: unified search filter chips', () => {
test.beforeEach(async ({ page }) => {
await page.goto('apps/files')
})

test('shows an accessible remove button on applied date filter chips', async ({ page }) => {
const search = new UnifiedSearchPage(page)
await search.openWithQuery()
await search.applyDateFilter('Today')

await expect(search.filterChip('Today')).toBeVisible()
await expect(search.filterChip('Today').getByRole('button', { name: 'Remove filter: Today' })).toBeVisible()
})

test('removes a date filter when clicking the chip remove button', async ({ page }) => {
const search = new UnifiedSearchPage(page)
await search.openWithQuery()
await search.applyDateFilter('Last 7 days')

await expect(search.filterChip('Last 7 days')).toBeVisible()

await search.removeFilterChip('Last 7 days')

await expect(search.filterChip('Last 7 days')).toHaveCount(0)
})

test('removes a date filter when activating the remove button with Space', async ({ page }) => {
const search = new UnifiedSearchPage(page)
await search.openWithQuery()
await search.applyDateFilter('Today')

const removeButton = search.filterChip('Today').getByRole('button', { name: 'Remove filter: Today' })
await removeButton.press('Space')

await expect(search.filterChip('Today')).toHaveCount(0)
})
})
44 changes: 44 additions & 0 deletions tests/playwright/support/sections/UnifiedSearchPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,48 @@ export class UnifiedSearchPage {
option(id: string): Locator {
return this.page.locator(`[id="${id}"]`)
}

/** Filter controls (Places, Date, People, …) in the open search panel. */
filtersBar(): Locator {
return this.panel().locator('[data-cy-unified-search-filters]')
}

/** Applied filter chips rendered below the filter controls. */
appliedFilters(): Locator {
return this.panel().locator('.unified-search-modal__filters-applied')
}

/** A single applied filter chip matching the given label text. */
filterChip(text: string | RegExp): Locator {
return this.appliedFilters().filter({ hasText: text })
}

/**
* Focus the header search and open the results panel.
* A non-empty query is required on desktop for the panel (and its filters) to render.
*/
async openWithQuery(query = 'test'): Promise<void> {
await this.input().click()
await this.input().fill(query)
await this.panel().waitFor({ state: 'visible' })
}

/** Apply a quick date filter from the Date menu. */
async applyDateFilter(label: 'Today' | 'Last 7 days' | 'Last 30 days' | 'This year' | 'Last year'): Promise<void> {
await this.filtersBar()
.locator('[data-cy-unified-search-filter="date"]')
.getByRole('button', { name: 'Date' })
.click()
await this.page.getByRole('menuitem', { name: label }).click()
}

/**
* Remove an applied filter via its chip close control.
* NcChip exposes the close action as a button named "Remove filter: {text}".
*/
async removeFilterChip(filterText: string): Promise<void> {
await this.filterChip(filterText)
.getByRole('button', { name: `Remove filter: ${filterText}` })
.click({ force: true })
}
}
Loading