From f601d2b1c4b8fecf7b3da86d78ec7f340fb4bc46 Mon Sep 17 00:00:00 2001 From: Jannik Stehle Date: Wed, 19 Apr 2023 11:50:02 +0200 Subject: [PATCH 1/2] Fix fuzzy fuse filter results --- .../unreleased/bugfix-remove-fuzzy-search-results | 4 +++- .../src/components/OcSelect/OcSelect.vue | 4 ++-- .../src/components/Groups/GroupsList.vue | 9 ++------- .../src/components/Groups/SideBar/MembersPanel.vue | 9 ++------- .../src/components/Spaces/SideBar/MembersPanel.vue | 9 ++------- .../src/components/Spaces/SpacesList.vue | 11 +++-------- .../src/components/Users/UsersList.vue | 6 ++---- .../src/components/SideBar/Shares/SpaceMembers.vue | 6 ++---- packages/web-app-files/src/helpers/resource/filter.ts | 5 ++--- packages/web-app-files/src/views/trash/Overview.vue | 10 ++-------- packages/web-pkg/src/components/ItemFilter.vue | 6 ++---- packages/web-pkg/src/helpers/fuse.ts | 5 +++++ packages/web-pkg/src/helpers/index.ts | 1 + 13 files changed, 30 insertions(+), 55 deletions(-) create mode 100644 packages/web-pkg/src/helpers/fuse.ts diff --git a/changelog/unreleased/bugfix-remove-fuzzy-search-results b/changelog/unreleased/bugfix-remove-fuzzy-search-results index e7ae4a4219d..1046f7b26d3 100644 --- a/changelog/unreleased/bugfix-remove-fuzzy-search-results +++ b/changelog/unreleased/bugfix-remove-fuzzy-search-results @@ -3,4 +3,6 @@ Bugfix: Remove fuzzy search results We've had a bug that caused some search results to show up that didn't align with the search term. https://github.com/owncloud/web/pull/8508 -https://github.com/owncloud/web/issues/8493 \ No newline at end of file +https://github.com/owncloud/web/pull/8863 +https://github.com/owncloud/web/issues/8493 +https://github.com/owncloud/web/issues/8860 \ No newline at end of file diff --git a/packages/design-system/src/components/OcSelect/OcSelect.vue b/packages/design-system/src/components/OcSelect/OcSelect.vue index fd3b8fbf2c5..90363aa3cbb 100644 --- a/packages/design-system/src/components/OcSelect/OcSelect.vue +++ b/packages/design-system/src/components/OcSelect/OcSelect.vue @@ -119,8 +119,8 @@ export default defineComponent({ const fuse = new Fuse(items, { ...(props.label && { keys: [props.label] }), shouldSort: true, - threshold: 0.1, - location: 0, + threshold: 0, + ignoreLocation: true, distance: 100, minMatchCharLength: 1 }) diff --git a/packages/web-app-admin-settings/src/components/Groups/GroupsList.vue b/packages/web-app-admin-settings/src/components/Groups/GroupsList.vue index a0ef5e1f893..e5197103b27 100644 --- a/packages/web-app-admin-settings/src/components/Groups/GroupsList.vue +++ b/packages/web-app-admin-settings/src/components/Groups/GroupsList.vue @@ -111,6 +111,7 @@ import { SideBarEventTopics } from 'web-pkg/src/composables/sideBar' import { Group } from 'web-client/src/generated' import ContextMenuQuickAction from 'web-pkg/src/components/ContextActions/ContextMenuQuickAction.vue' import { useGettext } from 'vue3-gettext' +import { defaultFuseOptions } from 'web-pkg/src/helpers' export default defineComponent({ name: 'GroupsList', @@ -287,13 +288,7 @@ export default defineComponent({ if (!(filterTerm || '').trim()) { return groups } - const groupsSearchEngine = new Fuse(groups, { - includeScore: false, - useExtendedSearch: true, - threshold: 0.1, - keys: ['displayName'] - }) - + const groupsSearchEngine = new Fuse(groups, { ...defaultFuseOptions, keys: ['displayName'] }) return groupsSearchEngine.search(filterTerm).map((r) => r.item) }, orderBy(list, prop, desc) { diff --git a/packages/web-app-admin-settings/src/components/Groups/SideBar/MembersPanel.vue b/packages/web-app-admin-settings/src/components/Groups/SideBar/MembersPanel.vue index 0ea5b6e7f1c..054a8a3b8f8 100644 --- a/packages/web-app-admin-settings/src/components/Groups/SideBar/MembersPanel.vue +++ b/packages/web-app-admin-settings/src/components/Groups/SideBar/MembersPanel.vue @@ -22,6 +22,7 @@ import MembersRoleSection from '../../Groups/SideBar/MembersRoleSection.vue' import Fuse from 'fuse.js' import Mark from 'mark.js' import { Group } from 'web-client/src/generated' +import { defaultFuseOptions } from 'web-pkg/src/helpers' export default defineComponent({ name: 'GroupsMembersPanel', @@ -37,13 +38,7 @@ export default defineComponent({ return collection } - const searchEngine = new Fuse(collection, { - includeScore: false, - useExtendedSearch: true, - threshold: 0.1, - keys: ['displayName'] - }) - + const searchEngine = new Fuse(collection, { ...defaultFuseOptions, keys: ['displayName'] }) return searchEngine.search(term).map((r) => r.item) } diff --git a/packages/web-app-admin-settings/src/components/Spaces/SideBar/MembersPanel.vue b/packages/web-app-admin-settings/src/components/Spaces/SideBar/MembersPanel.vue index bfd5245b50d..460df725e7d 100644 --- a/packages/web-app-admin-settings/src/components/Spaces/SideBar/MembersPanel.vue +++ b/packages/web-app-admin-settings/src/components/Spaces/SideBar/MembersPanel.vue @@ -43,6 +43,7 @@ import MembersRoleSection from './MembersRoleSection.vue' import Fuse from 'fuse.js' import Mark from 'mark.js' import { spaceRoleEditor, spaceRoleManager, spaceRoleViewer } from 'web-client/src/helpers/share' +import { defaultFuseOptions } from 'web-pkg/src/helpers' export default defineComponent({ name: 'MembersPanel', @@ -57,13 +58,7 @@ export default defineComponent({ return collection } - const searchEngine = new Fuse(collection, { - includeScore: false, - useExtendedSearch: true, - threshold: 0.1, - keys: ['displayName'] - }) - + const searchEngine = new Fuse(collection, { ...defaultFuseOptions, keys: ['displayName'] }) return searchEngine.search(term).map((r) => r.item) } diff --git a/packages/web-app-admin-settings/src/components/Spaces/SpacesList.vue b/packages/web-app-admin-settings/src/components/Spaces/SpacesList.vue index 79106a9ed76..5cce7acea29 100644 --- a/packages/web-app-admin-settings/src/components/Spaces/SpacesList.vue +++ b/packages/web-app-admin-settings/src/components/Spaces/SpacesList.vue @@ -119,7 +119,8 @@ import { formatDateFromJSDate, formatRelativeDateFromJSDate, displayPositionedDropdown, - formatFileSize + formatFileSize, + defaultFuseOptions } from 'web-pkg/src/helpers' import { computed, defineComponent, nextTick, onMounted, PropType, ref, unref, watch } from 'vue' import { SpaceResource } from 'web-client/src/helpers' @@ -218,13 +219,7 @@ export default defineComponent({ if (!(filterTerm || '').trim()) { return spaces } - const searchEngine = new Fuse(spaces, { - includeScore: false, - useExtendedSearch: true, - threshold: 0.1, - keys: ['name'] - }) - + const searchEngine = new Fuse(spaces, { ...defaultFuseOptions, keys: ['name'] }) return searchEngine.search(filterTerm).map((r) => r.item) } const isSpaceSelected = (space: SpaceResource) => { diff --git a/packages/web-app-admin-settings/src/components/Users/UsersList.vue b/packages/web-app-admin-settings/src/components/Users/UsersList.vue index 658b50c543a..cdf583e18b9 100644 --- a/packages/web-app-admin-settings/src/components/Users/UsersList.vue +++ b/packages/web-app-admin-settings/src/components/Users/UsersList.vue @@ -110,7 +110,7 @@ import { defineComponent, PropType, ref, unref, ComponentPublicInstance } from 'vue' import Fuse from 'fuse.js' import Mark from 'mark.js' -import { displayPositionedDropdown, eventBus } from 'web-pkg' +import { defaultFuseOptions, displayPositionedDropdown, eventBus } from 'web-pkg' import { SideBarEventTopics } from 'web-pkg/src/composables/sideBar' import { AppRole, User } from 'web-client/src/generated' import ContextMenuQuickAction from 'web-pkg/src/components/ContextActions/ContextMenuQuickAction.vue' @@ -311,9 +311,7 @@ export default defineComponent({ return users } const usersSearchEngine = new Fuse(users, { - includeScore: false, - useExtendedSearch: true, - threshold: 0.1, + ...defaultFuseOptions, keys: ['displayName', 'mail', 'onPremisesSamAccountName', 'role.displayName'] }) diff --git a/packages/web-app-files/src/components/SideBar/Shares/SpaceMembers.vue b/packages/web-app-files/src/components/SideBar/Shares/SpaceMembers.vue index 0274e6686f6..2a3bec2e946 100644 --- a/packages/web-app-files/src/components/SideBar/Shares/SpaceMembers.vue +++ b/packages/web-app-files/src/components/SideBar/Shares/SpaceMembers.vue @@ -73,7 +73,7 @@ import { ProjectSpaceResource } from 'web-client/src/helpers' import { useClientService } from 'web-pkg/src/composables' import Fuse from 'fuse.js' import Mark from 'mark.js' -import { configurationManager } from 'web-pkg' +import { configurationManager, defaultFuseOptions } from 'web-pkg' export default defineComponent({ name: 'SpaceMembers', @@ -148,9 +148,7 @@ export default defineComponent({ return collection } const searchEngine = new Fuse(collection, { - includeScore: false, - useExtendedSearch: true, - threshold: 0.1, + ...defaultFuseOptions, keys: ['collaborator.displayName', 'collaborator.name'] }) diff --git a/packages/web-app-files/src/helpers/resource/filter.ts b/packages/web-app-files/src/helpers/resource/filter.ts index d3788385a9d..c0da9ec6cc5 100644 --- a/packages/web-app-files/src/helpers/resource/filter.ts +++ b/packages/web-app-files/src/helpers/resource/filter.ts @@ -1,10 +1,9 @@ import Fuse from 'fuse.js' +import { defaultFuseOptions } from 'web-pkg/src/helpers' export const filterResources = (resources: unknown[], term: string, limit?: number): unknown[] => { const engine = new Fuse(resources, { - includeScore: false, - useExtendedSearch: true, - threshold: 0.1, + ...defaultFuseOptions, keys: ['name', 'type', 'icon', 'extension', 'tags'] }) diff --git a/packages/web-app-files/src/views/trash/Overview.vue b/packages/web-app-files/src/views/trash/Overview.vue index 71485a1c23c..db2f711ac5b 100644 --- a/packages/web-app-files/src/views/trash/Overview.vue +++ b/packages/web-app-files/src/views/trash/Overview.vue @@ -67,7 +67,7 @@ import Mark from 'mark.js' import Fuse from 'fuse.js' import { useGettext } from 'vue3-gettext' import { useTask } from 'vue-concurrency' -import { useClientService, useRouter, useStore } from 'web-pkg' +import { defaultFuseOptions, useClientService, useRouter, useStore } from 'web-pkg' import { createLocationTrash } from 'web-app-files/src/router' import { createFileRouteOptions } from 'web-pkg/src/helpers/router' import AppBar from 'web-app-files/src/components/AppBar/AppBar.vue' @@ -155,13 +155,7 @@ export default defineComponent({ if (!(filterTerm || '').trim()) { return spaces } - const searchEngine = new Fuse(spaces, { - includeScore: true, - useExtendedSearch: true, - threshold: 0.1, - keys: ['name'] - }) - + const searchEngine = new Fuse(spaces, { ...defaultFuseOptions, keys: ['name'] }) return searchEngine.search(filterTerm).map((r) => r.item) } diff --git a/packages/web-pkg/src/components/ItemFilter.vue b/packages/web-pkg/src/components/ItemFilter.vue index 472cd2531da..93cbccb5073 100644 --- a/packages/web-pkg/src/components/ItemFilter.vue +++ b/packages/web-pkg/src/components/ItemFilter.vue @@ -58,7 +58,7 @@ import { defineComponent, nextTick, onMounted, ref, unref, watch } from 'vue' import Fuse from 'fuse.js' import Mark from 'mark.js' import omit from 'lodash-es/omit' -import { useRoute, useRouteQuery, useRouter } from 'web-pkg' +import { defaultFuseOptions, useRoute, useRouteQuery, useRouter } from 'web-pkg' import { queryItemAsString } from 'web-pkg/src/composables/appDefaults' export default defineComponent({ @@ -164,9 +164,7 @@ export default defineComponent({ return items } const usersSearchEngine = new Fuse(items, { - includeScore: false, - useExtendedSearch: true, - threshold: 0.1, + ...defaultFuseOptions, keys: props.filterableAttributes as any }) diff --git a/packages/web-pkg/src/helpers/fuse.ts b/packages/web-pkg/src/helpers/fuse.ts new file mode 100644 index 00000000000..b3eb4c54ebb --- /dev/null +++ b/packages/web-pkg/src/helpers/fuse.ts @@ -0,0 +1,5 @@ +export const defaultFuseOptions = { + ignoreLocation: true, + threshold: 0, + useExtendedSearch: true +} diff --git a/packages/web-pkg/src/helpers/index.ts b/packages/web-pkg/src/helpers/index.ts index 16059196abd..9fc802b8dea 100644 --- a/packages/web-pkg/src/helpers/index.ts +++ b/packages/web-pkg/src/helpers/index.ts @@ -3,4 +3,5 @@ export * from './contextMenuDropdown' export * from './download' export * from './datetime' export * from './filesize' +export * from './fuse' export * from './locale' From f13bb288f4feab23ab9b9364fe687f48216d4cd2 Mon Sep 17 00:00:00 2001 From: Jannik Stehle Date: Wed, 19 Apr 2023 14:24:00 +0200 Subject: [PATCH 2/2] Fix snapshot tests --- .../Groups/SideBar/__snapshots__/MembersPanel.spec.ts.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/__snapshots__/MembersPanel.spec.ts.snap b/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/__snapshots__/MembersPanel.spec.ts.snap index 2d09187d029..13190e9a05c 100644 --- a/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/__snapshots__/MembersPanel.spec.ts.snap +++ b/packages/web-app-admin-settings/tests/unit/components/Groups/SideBar/__snapshots__/MembersPanel.spec.ts.snap @@ -2,7 +2,7 @@ exports[`MembersPanel should display an empty result if no matching members found 1`] = `
- +

No members found

@@ -14,7 +14,7 @@ exports[`MembersPanel should display an empty result if no matching members foun exports[`MembersPanel should render all members accordingly to their role assignments 1`] = `
- +