4141 @keypress.enter.prevent.stop =" onInputEnter" >
4242 </div >
4343
44+ <!-- Search filters -->
45+ <div v-if =" availableFilters.length > 1" class =" unified-search__filters" >
46+ <ul >
47+ <SearchFilter v-for =" type in availableFilters"
48+ :key =" type"
49+ :type =" type"
50+ :name =" typesMap[type]"
51+ @click =" onClickFilter" />
52+ </ul >
53+ </div >
54+
4455 <template v-if =" ! hasResults " >
4556 <!-- Loading placeholders -->
4657 <ul v-if =" isLoading" >
97108</template >
98109
99110<script >
100- import { minSearchLength , getTypes , search , defaultLimit } from ' ../services/UnifiedSearchService'
111+ import { minSearchLength , getTypes , search , defaultLimit , regexFilterIn , regexFilterNot } from ' ../services/UnifiedSearchService'
101112import EmptyContent from ' @nextcloud/vue/dist/Components/EmptyContent'
102113import Magnify from ' vue-material-design-icons/Magnify'
103114import debounce from ' debounce'
104115
105116import HeaderMenu from ' ../components/HeaderMenu'
117+ import SearchFilter from ' ../components/UnifiedSearch/SearchFilter'
106118import SearchResult from ' ../components/UnifiedSearch/SearchResult'
107119import SearchResultPlaceholder from ' ../components/UnifiedSearch/SearchResultPlaceholder'
108120
@@ -113,6 +125,7 @@ export default {
113125 EmptyContent,
114126 HeaderMenu,
115127 Magnify,
128+ SearchFilter,
116129 SearchResult,
117130 SearchResultPlaceholder,
118131 },
@@ -161,17 +174,52 @@ export default {
161174
162175 /**
163176 * Return ordered results
164- * @returns {Object }
177+ * @returns {Array }
165178 */
166179 orderedResults () {
167- return Object . values ( this .typesIDs )
180+ return this .typesIDs
168181 .filter (type => type in this .results )
169182 .map (type => ({
170183 type,
171184 list: this .results [type],
172185 }))
173186 },
174187
188+ /**
189+ * Available filters
190+ * We only show filters that are available on the results
191+ * @returns {string[]}
192+ */
193+ availableFilters () {
194+ return Object .keys (this .results )
195+ },
196+
197+ /**
198+ * Applied filters
199+ * @returns {string[]}
200+ */
201+ usedFiltersIn () {
202+ let match
203+ const filters = []
204+ while ((match = regexFilterIn .exec (this .query )) !== null ) {
205+ filters .push (match[1 ])
206+ }
207+ return filters
208+ },
209+
210+ /**
211+ * Applied anti filters
212+ * @returns {string[]}
213+ */
214+ usedFiltersNot () {
215+ let match
216+ const filters = []
217+ while ((match = regexFilterNot .exec (this .query )) !== null ) {
218+ filters .push (match[1 ])
219+ }
220+ return filters
221+ },
222+
175223 /**
176224 * Is the current search too short
177225 * @returns {boolean}
@@ -286,12 +334,30 @@ export default {
286334 return
287335 }
288336
337+ let types = this .typesIDs
338+ let query = this .query
339+
340+ // Filter out types
341+ if (this .usedFiltersNot .length > 0 ) {
342+ types = this .typesIDs .filter (type => this .usedFiltersNot .indexOf (type) === - 1 )
343+ }
344+
345+ // Only use those filters if any and check if they are valid
346+ if (this .usedFiltersIn .length > 0 ) {
347+ types = this .typesIDs .filter (type => this .usedFiltersIn .indexOf (type) > - 1 )
348+ }
349+
350+ // remove any filters from the query
351+ query = query .replace (regexFilterIn, ' ' ).replace (regexFilterNot, ' ' )
352+
353+ console .debug (' Searching' , query, ' in' , types)
354+
289355 // reset search if the query changed
290356 this .resetState ()
291357
292- this . typesIDs .forEach (async type => {
358+ types .forEach (async type => {
293359 this .$set (this .loading , type, true )
294- const request = await search (type, this . query )
360+ const request = await search (type, query)
295361
296362 // Process results
297363 if (request .data .entries .length > 0 ) {
@@ -473,6 +539,13 @@ export default {
473539 this .focused = index
474540 }
475541 },
542+
543+ onClickFilter (filter ) {
544+ this .query = ` ${ this .query } ${ filter} `
545+ .replace (/ {2} / g , ' ' )
546+ .trim ()
547+ this .onInput ()
548+ },
476549 },
477550}
478551 </script >
@@ -495,6 +568,14 @@ $input-padding: 6px;
495568 background-color : var (--color-main-background );
496569 }
497570
571+ & __filters {
572+ margin : $margin / 2 $margin ;
573+ ul {
574+ display : inline-flex ;
575+ justify-content : space-between ;
576+ }
577+ }
578+
498579 & __input {
499580 // Minus margins
500581 width : calc (100% - 2 * #{$margin } );
@@ -505,10 +586,9 @@ $input-padding: 6px;
505586 & [placeholder ],
506587 & ::placeholder {
507588 overflow : hidden ;
508- text-overflow :ellipsis ;
509589 white-space : nowrap ;
590+ text-overflow : ellipsis ;
510591 }
511-
512592 }
513593
514594 & __results {
0 commit comments