Skip to content

Commit 8462564

Browse files
committed
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 65ef696 commit 8462564

File tree

1 file changed

+97
-3
lines changed

1 file changed

+97
-3
lines changed

core/src/components/UnifiedSearch/UnifiedSearchModal.vue

Lines changed: 97 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,36 @@
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 v-for="(result, index) in providerResult.results"
166+
:key="index"
167+
v-bind="result" />
168+
</ul>
169+
<div class="result-footer">
170+
<NcButton v-if="providerResult.results.length === providerResult.limit" variant="tertiary-no-background" @click="loadMoreResultsForProvider(providerResult)">
171+
{{ t('core', 'Load more results') }}
172+
<template #icon>
173+
<IconDotsHorizontal :size="20" />
174+
</template>
175+
</NcButton>
176+
<NcButton v-if="providerResult.inAppSearch" alignment="end-reverse" variant="tertiary-no-background">
177+
{{ t('core', 'Search in') }} {{ providerResult.name }}
178+
<template #icon>
179+
<IconArrowRight :size="20" />
180+
</template>
181+
</NcButton>
182+
</div>
183+
</div>
184+
</template>
154185
</div>
155186
</NcDialog>
156187
</template>
@@ -335,6 +366,50 @@ export default defineComponent({
335366
hasExternalResources() {
336367
return this.providers.some(provider => provider.isExternalProvider)
337368
},
369+
370+
hasContentFilters() {
371+
return this.filters.some((filter) => filter.type === 'date' || filter.type === 'person')
372+
},
373+
374+
filteredResults() {
375+
const isInFolderAtRoot = (result) => {
376+
if (result.id !== 'in-folder') {
377+
return false
378+
}
379+
const path = result.extraParams?.path
380+
return !path || path === '/' || path === ''
381+
}
382+
383+
if (!this.hasContentFilters) {
384+
return this.results.filter((result) => !isInFolderAtRoot(result))
385+
}
386+
return this.results.filter((result) => result.supportsActiveFilters === true && !isInFolderAtRoot(result))
387+
},
388+
389+
filteredResultUrls() {
390+
const urls = new Set()
391+
this.filteredResults.forEach((provider) => {
392+
provider.results.forEach((entry) => {
393+
if (entry.resourceUrl) {
394+
urls.add(entry.resourceUrl)
395+
}
396+
})
397+
})
398+
return urls
399+
},
400+
401+
unfilteredResults() {
402+
if (!this.hasContentFilters) {
403+
return []
404+
}
405+
return this.results
406+
.filter((result) => result.supportsActiveFilters === false)
407+
.map((provider) => ({
408+
...provider,
409+
results: provider.results.filter((entry) => !this.filteredResultUrls.has(entry.resourceUrl)),
410+
}))
411+
.filter((provider) => provider.results.length > 0)
412+
},
338413
},
339414
340415
watch: {
@@ -473,6 +548,7 @@ export default defineComponent({
473548
...provider,
474549
results: response.data.ocs.data.entries,
475550
limit: params.limit ?? 5,
551+
supportsActiveFilters,
476552
})
477553
478554
unifiedSearchLogger.debug('Unified search results:', { results: this.results, newResults })
@@ -836,9 +912,27 @@ export default defineComponent({
836912
align-items: center;
837913
display: flex;
838914
}
915+
916+
&--unfiltered {
917+
opacity: 0.7;
918+
}
839919
}
840920
841921
}
922+
923+
&__unfiltered-header {
924+
display: flex;
925+
flex-direction: column;
926+
gap: 2px;
927+
margin-block: 16px 8px;
928+
padding-block: 12px 0;
929+
border-top: 1px solid var(--color-border);
930+
}
931+
932+
&__unfiltered-label {
933+
font-weight: bold;
934+
color: var(--color-text-maxcontrast);
935+
}
842936
}
843937
844938
.filter-button__icon {

0 commit comments

Comments
 (0)