From f22428c83d36b966654a78cf51d16dcf3401f37f Mon Sep 17 00:00:00 2001 From: Diogo Castro Date: Wed, 19 Oct 2022 14:12:39 +0200 Subject: [PATCH] Search on current folder While api not implemented on our Reva banckend --- packages/web-app-files/src/index.ts | 4 +- .../src/mixins/filesListFilter.js | 48 +++++++++++++++++ .../web-app-files/src/search/filter/index.ts | 53 +++++++++++++++++++ .../src/search/filter/preview.ts | 46 ++++++++++++++++ packages/web-app-files/src/search/index.ts | 1 + .../web-app-files/src/services/registry.ts | 3 +- .../src/views/spaces/GenericSpace.vue | 4 +- .../web-app-search/src/portals/SearchBar.vue | 16 ++---- 8 files changed, 161 insertions(+), 14 deletions(-) create mode 100644 packages/web-app-files/src/mixins/filesListFilter.js create mode 100644 packages/web-app-files/src/search/filter/index.ts create mode 100644 packages/web-app-files/src/search/filter/preview.ts diff --git a/packages/web-app-files/src/index.ts b/packages/web-app-files/src/index.ts index 45248de7bc4..60aeca63c5e 100644 --- a/packages/web-app-files/src/index.ts +++ b/packages/web-app-files/src/index.ts @@ -9,7 +9,7 @@ import SpaceProjects from './views/spaces/Projects.vue' import translations from '../l10n/translations.json' import quickActions from './quickActions' import store from './store' -import { SDKSearch } from './search' +import { FilterSearch, SDKSearch } from './search' import { eventBus } from 'web-pkg/src/services/eventBus' import { archiverService, thumbnailService, Registry } from './services' import fileSideBars from './fileSideBars' @@ -129,10 +129,12 @@ export default { quickActions, translations, ready({ router, store }) { + Registry.filterSearch = new FilterSearch(store, router) Registry.sdkSearch = new SDKSearch(store, router) // when discussing the boot process of applications we need to implement a // registry that does not rely on call order, aka first register "on" and only after emit. + eventBus.publish('app.search.register.provider', Registry.filterSearch) eventBus.publish('app.search.register.provider', Registry.sdkSearch) archiverService.initialize( diff --git a/packages/web-app-files/src/mixins/filesListFilter.js b/packages/web-app-files/src/mixins/filesListFilter.js new file mode 100644 index 00000000000..c18f022fc65 --- /dev/null +++ b/packages/web-app-files/src/mixins/filesListFilter.js @@ -0,0 +1,48 @@ +import { Registry } from '../services' +import { mapMutations } from 'vuex' +import { onBeforeUnmount } from 'vue' + +export default { + mounted() { + const { filterSearch } = Registry + + if (!filterSearch || !filterSearch.available) { + return + } + + const resetEventToken = filterSearch.subscribe('reset', () => { + this.CLEAR_FILES_SEARCHED() + }) + + const updateTermEventToken = filterSearch.subscribe('updateTerm', (term) => { + if (!term) { + this.CLEAR_FILES_SEARCHED() + } + }) + + const activateEventToken = filterSearch.subscribe('activate', ({ resources }) => { + this.LOAD_FILES_SEARCHED(resources) + }) + + onBeforeUnmount(() => { + filterSearch.unsubscribe('reset', resetEventToken) + filterSearch.unsubscribe('updateTerm', updateTermEventToken) + filterSearch.unsubscribe('activate', activateEventToken) + }) + }, + watch: { + $route: { + handler: function (to, from) { + if (to.name === from?.name && to.params?.item === from?.params?.item) { + return + } + + this.CLEAR_FILES_SEARCHED() + }, + immediate: true + } + }, + methods: { + ...mapMutations('Files', ['CLEAR_FILES_SEARCHED', 'LOAD_FILES_SEARCHED']) + } +} diff --git a/packages/web-app-files/src/search/filter/index.ts b/packages/web-app-files/src/search/filter/index.ts new file mode 100644 index 00000000000..93e45964375 --- /dev/null +++ b/packages/web-app-files/src/search/filter/index.ts @@ -0,0 +1,53 @@ +import { SearchProvider, SearchList, SearchPreview } from 'web-app-search/src/types' +import Preview from './preview' +import { EventBus } from 'web-pkg/src/services/eventBus' +import { filterResources } from '../../helpers/resource' +import { Store } from 'vuex' +import { Router } from 'vue-router' +import { isLocationSpacesActive } from '../../router' + +function $gettext(msg) { + return msg +} +export default class Provider extends EventBus implements SearchProvider { + public readonly id: string + public readonly displayName: string + public readonly previewSearch: SearchPreview + public readonly listSearch: SearchList + private readonly store: Store + private readonly router: Router + + constructor(store: Store, router: Router) { + super() + + this.id = 'files.filter' + this.displayName = $gettext('In this folder') + this.store = store + this.router = router + this.previewSearch = new Preview(store, router) + } + + public activate(term: string): void { + if (!term) { + return + } + + const resources = filterResources(this.store.getters['Files/files'], term) + this.publish('activate', { term, resources }) + } + + public reset(): void { + this.publish('reset') + } + + public updateTerm(term: string): void { + this.publish('updateTerm', term) + } + + public get available(): boolean { + return ( + isLocationSpacesActive(this.router, 'files-spaces-generic') && + !isLocationSpacesActive(this.router, 'files-spaces-projects') + ) + } +} diff --git a/packages/web-app-files/src/search/filter/preview.ts b/packages/web-app-files/src/search/filter/preview.ts new file mode 100644 index 00000000000..7248125927f --- /dev/null +++ b/packages/web-app-files/src/search/filter/preview.ts @@ -0,0 +1,46 @@ +import { SearchPreview, SearchResult } from 'web-app-search/src/types' +import PreviewComponent from '../../components/Search/Preview.vue' +import { filterResources } from '../../helpers/resource' +import { Store } from 'vuex' +import { Component, unref } from 'vue' +import { Router } from 'vue-router' + +export default class Preview implements SearchPreview { + public readonly component: Component + private readonly router: Router + private readonly store: Store + + constructor(store: Store, router: Router) { + this.component = PreviewComponent + this.router = router + this.store = store + } + + public search(term: string): Promise { + if (!term) { + return Promise.resolve({ + totalResults: null, + values: [] + }) + } + // no cache required, the filtering is client only and fast enough to recalculate the set + // of results every time on the fly + const resources: any[] = filterResources(this.store.getters['Files/files'], term, 5) + const areHiddenFilesShown = this.store.state.Files?.areHiddenFilesShown + + const searchResult = resources.reduce((acc, resource) => { + // filter results if hidden files shouldn't be shown due to settings + if (!resource.name.startsWith('.') || areHiddenFilesShown) { + acc.push({ id: resource.id, data: { ...resource, storageId: 'eos' } }) + } + + return acc + }, []) + + return Promise.resolve({ totalResults: searchResult.length, values: searchResult }) + } + + public get available(): boolean { + return unref(this.router.currentRoute).name !== 'search-provider-list' + } +} diff --git a/packages/web-app-files/src/search/index.ts b/packages/web-app-files/src/search/index.ts index 514195a3906..a348a27b7f6 100644 --- a/packages/web-app-files/src/search/index.ts +++ b/packages/web-app-files/src/search/index.ts @@ -1 +1,2 @@ export { default as SDKSearch } from './sdk' +export { default as FilterSearch } from './filter' diff --git a/packages/web-app-files/src/services/registry.ts b/packages/web-app-files/src/services/registry.ts index 7ccea22453d..689030ab2d4 100644 --- a/packages/web-app-files/src/services/registry.ts +++ b/packages/web-app-files/src/services/registry.ts @@ -1,5 +1,6 @@ -import { SDKSearch } from '../search' +import { FilterSearch, SDKSearch } from '../search' export default class Registry { + static filterSearch: FilterSearch static sdkSearch: SDKSearch } diff --git a/packages/web-app-files/src/views/spaces/GenericSpace.vue b/packages/web-app-files/src/views/spaces/GenericSpace.vue index 5ea2d6364e3..ef0d602a90c 100644 --- a/packages/web-app-files/src/views/spaces/GenericSpace.vue +++ b/packages/web-app-files/src/views/spaces/GenericSpace.vue @@ -189,6 +189,8 @@ import { CreateTargetRouteOptions } from 'web-app-files/src/helpers/folderLink/t import SingleSharedFile from './SingleSharedFile.vue' import Home from './Home.vue' +import MixinFilesListFilter from '../../mixins/filesListFilter' + const visibilityObserver = new VisibilityObserver() export default defineComponent({ @@ -214,7 +216,7 @@ export default defineComponent({ Home }, - mixins: [MixinAccessibleBreadcrumb, MixinFileActions], + mixins: [MixinAccessibleBreadcrumb, MixinFileActions, MixinFilesListFilter], props: { space: { diff --git a/packages/web-app-search/src/portals/SearchBar.vue b/packages/web-app-search/src/portals/SearchBar.vue index d4de552233a..a14cafcbca2 100644 --- a/packages/web-app-search/src/portals/SearchBar.vue +++ b/packages/web-app-search/src/portals/SearchBar.vue @@ -56,15 +56,7 @@
  • {{ provider.displayName }} - - - {{ getMoreResultsDetailsTextForProvider(provider) }} - - + {{ getMoreResultsDetailsTextForProvider(provider) }}