From d7afe854b786e51853b4a221c4ade48ec7918306 Mon Sep 17 00:00:00 2001 From: lizhensheng Date: Thu, 22 Feb 2024 06:34:19 +0000 Subject: [PATCH 1/4] [feature]: Refactor filtering and sorting based on a specific key with weight prioritization --- .../ProjectSelector/MockSelectItemOptions.tsx | 10 +++-- .../Nav/SideMenu/ProjectSelector/index.tsx | 11 ++--- .../Nav/SideMenu/ProjectSelector/style.ts | 8 ++++ packages/shared/lib/utils/Tool.ts | 45 ++++++++++++++++--- .../shared/lib/utils/__tests__/Tool.test.ts | 7 +++ 5 files changed, 67 insertions(+), 14 deletions(-) create mode 100644 packages/shared/lib/utils/__tests__/Tool.test.ts diff --git a/packages/base/src/page/Nav/SideMenu/ProjectSelector/MockSelectItemOptions.tsx b/packages/base/src/page/Nav/SideMenu/ProjectSelector/MockSelectItemOptions.tsx index 384c869ef..0cbda87d7 100644 --- a/packages/base/src/page/Nav/SideMenu/ProjectSelector/MockSelectItemOptions.tsx +++ b/packages/base/src/page/Nav/SideMenu/ProjectSelector/MockSelectItemOptions.tsx @@ -1,12 +1,14 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; import classNames from 'classnames'; -import { ProjectSelectorLabelStyleWrapper } from './style'; +import { + MockSelectItemOptionsStyleWrapper, + ProjectSelectorLabelStyleWrapper +} from './style'; import { IconProjectArchived, IconProjectFlag } from '@actiontech/shared/lib/Icon/common'; -import { CustomSelectPopupMenuStyleWrapper } from '@actiontech/shared/lib/components/CustomSelect/style'; import { IBindProject } from './index.type'; const MockSelectItemOptions: React.FC<{ @@ -16,7 +18,7 @@ const MockSelectItemOptions: React.FC<{ const navigate = useNavigate(); const [activeId, setActiveId] = useState(''); return ( - + {list.map((v) => { return (
); })} - + ); }; diff --git a/packages/base/src/page/Nav/SideMenu/ProjectSelector/index.tsx b/packages/base/src/page/Nav/SideMenu/ProjectSelector/index.tsx index 6f6d60f05..4ed8a8ae6 100644 --- a/packages/base/src/page/Nav/SideMenu/ProjectSelector/index.tsx +++ b/packages/base/src/page/Nav/SideMenu/ProjectSelector/index.tsx @@ -13,6 +13,7 @@ import { import { CustomSelectPopupMenuStyleWrapper } from '@actiontech/shared/lib/components/CustomSelect/style'; import MockSelectItemOptions from './MockSelectItemOptions'; import { ProjectSelectorProps } from './index.type'; +import { fuzzySearchAndSortByWeight } from '@actiontech/shared/lib/utils/Tool'; const ProjectSelector: React.FC = ({ value, @@ -31,10 +32,10 @@ const ProjectSelector: React.FC = ({ >(); const renderDropdown: SelectProps['dropdownRender'] = (menu) => { - const filterBindProjects = (bindProjects ?? []).filter((v) => - v.project_name - ?.toLocaleLowerCase() - .includes(searchValue.toLocaleLowerCase()) + const filterBindProjects = fuzzySearchAndSortByWeight( + searchValue, + bindProjects ?? [], + 'project_name' ); return ( @@ -83,7 +84,7 @@ const ProjectSelector: React.FC = ({ setOpen(false); setSearchValue(''); }} - list={filterBindProjects?.slice(0, 3) ?? []} + list={filterBindProjects ?? []} /> )} diff --git a/packages/base/src/page/Nav/SideMenu/ProjectSelector/style.ts b/packages/base/src/page/Nav/SideMenu/ProjectSelector/style.ts index 413c38e1e..f6272770e 100644 --- a/packages/base/src/page/Nav/SideMenu/ProjectSelector/style.ts +++ b/packages/base/src/page/Nav/SideMenu/ProjectSelector/style.ts @@ -1,4 +1,5 @@ import { CustomSelect } from '@actiontech/shared/lib/components/CustomSelect'; +import { CustomSelectPopupMenuStyleWrapper } from '@actiontech/shared/lib/components/CustomSelect/style'; import { styled } from '@mui/material/styles'; @@ -99,3 +100,10 @@ export const ProjectSelectorPopupMenuStyleWrapper = styled('div')` } } `; + +export const MockSelectItemOptionsStyleWrapper = styled( + CustomSelectPopupMenuStyleWrapper +)` + max-height: 120px; + overflow-y: auto; +`; diff --git a/packages/shared/lib/utils/Tool.ts b/packages/shared/lib/utils/Tool.ts index 82ddbf8ea..32b57bf8d 100644 --- a/packages/shared/lib/utils/Tool.ts +++ b/packages/shared/lib/utils/Tool.ts @@ -1,9 +1,9 @@ export function formatParamsBySeparator(formatParams: string | number) { - const val = ( - typeof formatParams === 'number' && !Number.isNaN(formatParams) - ? formatParams + '' - : formatParams - ) as string; + if (Number.isNaN(formatParams)) { + return formatParams; + } + const val = + typeof formatParams === 'number' ? formatParams + '' : formatParams; const result = []; let group = ''; const [integerStr, floatStr] = val.split('.'); @@ -16,3 +16,38 @@ export function formatParamsBySeparator(formatParams: string | number) { } return `${result.join(',')}${floatStr ? '.' + floatStr : ''}`; } + +export function fuzzySearchAndSortByWeight>( + query: string, + data: Array, + key: keyof T +): Array { + if (!query) { + return data; + } + const filterRegex = new RegExp(query, 'i'); + + const results: Array<{ item: T } & { weight: number }> = []; + + data.forEach((item) => { + const value = item[key]; + if (!value || typeof value !== 'string') { + return item; + } + + if (filterRegex.test(value)) { + if (value.toLowerCase() === query.toLowerCase()) { + results.unshift({ item, weight: 1000 }); + } else { + const matchLen = query.length; + const totalLen = value.length; + const ratio = matchLen / totalLen; + const weight = ratio * 1000; + + results.push({ item, weight }); + } + } + }); + + return results.sort((a, b) => b.weight - a.weight).map((res) => res.item); +} diff --git a/packages/shared/lib/utils/__tests__/Tool.test.ts b/packages/shared/lib/utils/__tests__/Tool.test.ts new file mode 100644 index 000000000..b4143f3e8 --- /dev/null +++ b/packages/shared/lib/utils/__tests__/Tool.test.ts @@ -0,0 +1,7 @@ +import { formatParamsBySeparator } from '../Tool'; + +describe('test utils/Tool', () => { + it('test formatParamsBySeparator', () => { + expect(formatParamsBySeparator(NaN)).toBe(NaN); + }); +}); From 8b708e3229d94cf9659c1d18ae24eac8776e1568 Mon Sep 17 00:00:00 2001 From: lizhensheng Date: Thu, 22 Feb 2024 14:50:39 +0800 Subject: [PATCH 2/4] [test]:(shard/utils/Tool) Supplementary unit tests --- .../MockSelectItemOptions.test.tsx.snap | 8 ++-- .../test/__snapshots__/index.test.tsx.snap | 2 +- .../shared/lib/utils/__tests__/Tool.test.ts | 41 ++++++++++++++++++- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/packages/base/src/page/Nav/SideMenu/ProjectSelector/test/__snapshots__/MockSelectItemOptions.test.tsx.snap b/packages/base/src/page/Nav/SideMenu/ProjectSelector/test/__snapshots__/MockSelectItemOptions.test.tsx.snap index 362938492..037021c99 100644 --- a/packages/base/src/page/Nav/SideMenu/ProjectSelector/test/__snapshots__/MockSelectItemOptions.test.tsx.snap +++ b/packages/base/src/page/Nav/SideMenu/ProjectSelector/test/__snapshots__/MockSelectItemOptions.test.tsx.snap @@ -4,7 +4,7 @@ exports[`base/page/Nav/SideMenu/MockSelectItemOptions should render snap when ha
diff --git a/packages/base/src/page/Nav/SideMenu/ProjectSelector/test/__snapshots__/index.test.tsx.snap b/packages/base/src/page/Nav/SideMenu/ProjectSelector/test/__snapshots__/index.test.tsx.snap index 7ecb9e44c..467f327f4 100644 --- a/packages/base/src/page/Nav/SideMenu/ProjectSelector/test/__snapshots__/index.test.tsx.snap +++ b/packages/base/src/page/Nav/SideMenu/ProjectSelector/test/__snapshots__/index.test.tsx.snap @@ -515,7 +515,7 @@ exports[`base/page/Nav/SideMenu/ProjectSelector render snap when has data 5`] = 您所属的项目
{ it('test formatParamsBySeparator', () => { expect(formatParamsBySeparator(NaN)).toBe(NaN); + + expect(formatParamsBySeparator(0)).toBe('0'); + expect(formatParamsBySeparator(33)).toBe('33'); + expect(formatParamsBySeparator(333)).toBe('333'); + expect(formatParamsBySeparator(333.22)).toBe('333.22'); + expect(formatParamsBySeparator(3334.22)).toBe('3,334.22'); + expect(formatParamsBySeparator(3332334.224343)).toBe('3,332,334.224343'); + + expect(formatParamsBySeparator('0')).toBe('0'); + expect(formatParamsBySeparator('33')).toBe('33'); + expect(formatParamsBySeparator('333')).toBe('333'); + expect(formatParamsBySeparator('333.22')).toBe('333.22'); + expect(formatParamsBySeparator('3334.228')).toBe('3,334.228'); + expect(formatParamsBySeparator('3332334.224343')).toBe('3,332,334.224343'); + }); + + it('test fuzzySearchAndSortByWeight', () => { + expect(fuzzySearchAndSortByWeight('', [], '')).toEqual([]); + expect(fuzzySearchAndSortByWeight('', [{ foo: 'bar' }], 'foo')).toEqual([ + { foo: 'bar' } + ]); + + const data = [ + { a: 'bar' }, + { a: 'foo' }, + { a: 'test-1' }, + { a: 'tes' }, + { a: 'test1' } + ]; + expect(fuzzySearchAndSortByWeight('b', data, 'a')).toEqual([{ a: 'bar' }]); + expect(fuzzySearchAndSortByWeight('te', data, 'a')).toEqual([ + { a: 'tes' }, + { a: 'test1' }, + { a: 'test-1' } + ]); + expect(fuzzySearchAndSortByWeight('test', data, 'a')).toEqual([ + { a: 'test1' }, + { a: 'test-1' } + ]); }); }); From 7ac0db464ab90d4522234ce2af0ba754f33c7888 Mon Sep 17 00:00:00 2001 From: lizhensheng Date: Thu, 22 Feb 2024 15:08:27 +0800 Subject: [PATCH 3/4] [chore]: fix lint error --- packages/shared/lib/utils/Tool.ts | 4 ++-- packages/shared/lib/utils/__tests__/Tool.test.ts | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/shared/lib/utils/Tool.ts b/packages/shared/lib/utils/Tool.ts index 32b57bf8d..c73e8236a 100644 --- a/packages/shared/lib/utils/Tool.ts +++ b/packages/shared/lib/utils/Tool.ts @@ -1,6 +1,6 @@ -export function formatParamsBySeparator(formatParams: string | number) { +export function formatParamsBySeparator(formatParams: string | number): string { if (Number.isNaN(formatParams)) { - return formatParams; + return 'NaN'; } const val = typeof formatParams === 'number' ? formatParams + '' : formatParams; diff --git a/packages/shared/lib/utils/__tests__/Tool.test.ts b/packages/shared/lib/utils/__tests__/Tool.test.ts index 41f9a08bb..afd2b9e9a 100644 --- a/packages/shared/lib/utils/__tests__/Tool.test.ts +++ b/packages/shared/lib/utils/__tests__/Tool.test.ts @@ -2,7 +2,7 @@ import { formatParamsBySeparator, fuzzySearchAndSortByWeight } from '../Tool'; describe('test utils/Tool', () => { it('test formatParamsBySeparator', () => { - expect(formatParamsBySeparator(NaN)).toBe(NaN); + expect(formatParamsBySeparator(NaN)).toBe('NaN'); expect(formatParamsBySeparator(0)).toBe('0'); expect(formatParamsBySeparator(33)).toBe('33'); @@ -38,9 +38,15 @@ describe('test utils/Tool', () => { { a: 'test1' }, { a: 'test-1' } ]); + expect(fuzzySearchAndSortByWeight('tes', data, 'a')).toEqual([ + { a: 'tes' }, + { a: 'test1' }, + { a: 'test-1' } + ]); expect(fuzzySearchAndSortByWeight('test', data, 'a')).toEqual([ { a: 'test1' }, { a: 'test-1' } ]); + expect(fuzzySearchAndSortByWeight('test', data, 'a1' as any)).toEqual([]); }); }); From e932cd02cb2f3a4df27324b4e5d03ded0a1d9876 Mon Sep 17 00:00:00 2001 From: lizhensheng Date: Fri, 23 Feb 2024 17:31:56 +0800 Subject: [PATCH 4/4] [test]:(utils/Tool) update test case --- packages/shared/lib/utils/__tests__/Tool.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/shared/lib/utils/__tests__/Tool.test.ts b/packages/shared/lib/utils/__tests__/Tool.test.ts index afd2b9e9a..52984740d 100644 --- a/packages/shared/lib/utils/__tests__/Tool.test.ts +++ b/packages/shared/lib/utils/__tests__/Tool.test.ts @@ -38,6 +38,10 @@ describe('test utils/Tool', () => { { a: 'test1' }, { a: 'test-1' } ]); + expect(fuzzySearchAndSortByWeight('est', data, 'a')).toEqual([ + { a: 'test1' }, + { a: 'test-1' } + ]); expect(fuzzySearchAndSortByWeight('tes', data, 'a')).toEqual([ { a: 'tes' }, { a: 'test1' },