Skip to content

Commit 1353905

Browse files
nfebebackportbot[bot]
authored andcommitted
fix(unified-search): Separate filtered and unfiltered results
Show results from providers that don't support active content filters (date/person) in a separate "Additional results" section with a note explaining that some filters may have been ignored. Changes: - Add computed properties to separate filtered/unfiltered results - Track filter compatibility using baseProvider for searchFrom providers - Deduplicate results by resourceUrl across sections - Skip in-folder results when at root to avoid duplicating Files results - Fix providerIsCompatibleWithFilters to check correct filter properties - Add styling for the unfiltered results section Signed-off-by: nfebe <[email protected]>
1 parent 0b20b93 commit 1353905

File tree

1 file changed

+98
-3
lines changed

1 file changed

+98
-3
lines changed

core/src/components/UnifiedSearch/UnifiedSearchModal.vue

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
:label="t('core', 'Search apps, files, tags, messages') + '...'"
2828
@update:value="debouncedFind" />
2929
<div class="unified-search-modal__filters" data-cy-unified-search-filters>
30-
<NcActions v-model:open="providerActionMenuIsOpen" :menu-name="t('core', 'Places')" data-cy-unified-search-filter="places">
30+
<NcActions :open.sync="providerActionMenuIsOpen" :menu-name="t('core', 'Places')" data-cy-unified-search-filter="places">
3131
<template #icon>
3232
<IconListBox :size="20" />
3333
</template>
@@ -43,7 +43,7 @@
4343
{{ provider.name }}
4444
</NcActionButton>
4545
</NcActions>
46-
<NcActions v-model:open="dateActionMenuIsOpen" :menu-name="t('core', 'Date')" data-cy-unified-search-filter="date">
46+
<NcActions :open.sync="dateActionMenuIsOpen" :menu-name="t('core', 'Date')" data-cy-unified-search-filter="date">
4747
<template #icon>
4848
<IconCalendarRange :size="20" />
4949
</template>
@@ -127,7 +127,8 @@
127127
<h3 class="hidden-visually">
128128
{{ t('core', 'Results') }}
129129
</h3>
130-
<div v-for="providerResult in results" :key="providerResult.id" class="result">
130+
<!-- Filtered results section -->
131+
<div v-for="providerResult in filteredResults" :key="providerResult.id" class="result">
131132
<h4 :id="`unified-search-result-${providerResult.id}`" class="result-title">
132133
{{ providerResult.name }}
133134
</h4>
@@ -151,6 +152,37 @@
151152
</NcButton>
152153
</div>
153154
</div>
155+
<!-- Unfiltered results section -->
156+
<template v-if="unfilteredResults.length > 0">
157+
<div class="unified-search-modal__unfiltered-header">
158+
<span class="unified-search-modal__unfiltered-label">{{ t('core', 'Partial matches') }}</span>
159+
</div>
160+
<div v-for="providerResult in unfilteredResults" :key="`unfiltered-${providerResult.id}`" class="result result--unfiltered">
161+
<h4 :id="`unified-search-result-unfiltered-${providerResult.id}`" class="result-title">
162+
{{ providerResult.name }}
163+
</h4>
164+
<ul class="result-items" :aria-labelledby="`unified-search-result-unfiltered-${providerResult.id}`">
165+
<SearchResult
166+
v-for="(result, index) in providerResult.results"
167+
:key="index"
168+
v-bind="result" />
169+
</ul>
170+
<div class="result-footer">
171+
<NcButton v-if="providerResult.results.length === providerResult.limit" variant="tertiary-no-background" @click="loadMoreResultsForProvider(providerResult)">
172+
{{ t('core', 'Load more results') }}
173+
<template #icon>
174+
<IconDotsHorizontal :size="20" />
175+
</template>
176+
</NcButton>
177+
<NcButton v-if="providerResult.inAppSearch" alignment="end-reverse" variant="tertiary-no-background">
178+
{{ t('core', 'Search in') }} {{ providerResult.name }}
179+
<template #icon>
180+
<IconArrowRight :size="20" />
181+
</template>
182+
</NcButton>
183+
</div>
184+
</div>
185+
</template>
154186
</div>
155187
</NcDialog>
156188
</template>
@@ -335,6 +367,50 @@ export default defineComponent({
335367
hasExternalResources() {
336368
return this.providers.some(provider => provider.isExternalProvider)
337369
},
370+
371+
hasContentFilters() {
372+
return this.filters.some((filter) => filter.type === 'date' || filter.type === 'person')
373+
},
374+
375+
filteredResults() {
376+
const isInFolderAtRoot = (result) => {
377+
if (result.id !== 'in-folder') {
378+
return false
379+
}
380+
const path = result.extraParams?.path
381+
return !path || path === '/' || path === ''
382+
}
383+
384+
if (!this.hasContentFilters) {
385+
return this.results.filter((result) => !isInFolderAtRoot(result))
386+
}
387+
return this.results.filter((result) => result.supportsActiveFilters === true && !isInFolderAtRoot(result))
388+
},
389+
390+
filteredResultUrls() {
391+
const urls = new Set()
392+
this.filteredResults.forEach((provider) => {
393+
provider.results.forEach((entry) => {
394+
if (entry.resourceUrl) {
395+
urls.add(entry.resourceUrl)
396+
}
397+
})
398+
})
399+
return urls
400+
},
401+
402+
unfilteredResults() {
403+
if (!this.hasContentFilters) {
404+
return []
405+
}
406+
return this.results
407+
.filter((result) => result.supportsActiveFilters === false)
408+
.map((provider) => ({
409+
...provider,
410+
results: provider.results.filter((entry) => !this.filteredResultUrls.has(entry.resourceUrl)),
411+
}))
412+
.filter((provider) => provider.results.length > 0)
413+
},
338414
},
339415
340416
watch: {
@@ -473,6 +549,7 @@ export default defineComponent({
473549
...provider,
474550
results: response.data.ocs.data.entries,
475551
limit: params.limit ?? 5,
552+
supportsActiveFilters,
476553
})
477554
478555
unifiedSearchLogger.debug('Unified search results:', { results: this.results, newResults })
@@ -836,9 +913,27 @@ export default defineComponent({
836913
align-items: center;
837914
display: flex;
838915
}
916+
917+
&--unfiltered {
918+
opacity: 0.7;
919+
}
839920
}
840921
841922
}
923+
924+
&__unfiltered-header {
925+
display: flex;
926+
flex-direction: column;
927+
gap: 2px;
928+
margin-block: 16px 8px;
929+
padding-block: 12px 0;
930+
border-top: 1px solid var(--color-border);
931+
}
932+
933+
&__unfiltered-label {
934+
font-weight: bold;
935+
color: var(--color-text-maxcontrast);
936+
}
842937
}
843938
844939
.filter-button__icon {

0 commit comments

Comments
 (0)