From a0135e9e38472e35cc348c7a2e34ffaa49791d14 Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:15:22 +0800 Subject: [PATCH] refactor: migrate tag filter overlay and remove dead z-index override prop (#33791) --- .../tag-management/__tests__/filter.spec.tsx | 25 +--- .../components/base/tag-management/filter.tsx | 112 ++++++++---------- .../model-selector/index.tsx | 3 - web/eslint.constants.mjs | 1 - 4 files changed, 54 insertions(+), 87 deletions(-) diff --git a/web/app/components/base/tag-management/__tests__/filter.spec.tsx b/web/app/components/base/tag-management/__tests__/filter.spec.tsx index 3cffac29b2..a455d1a791 100644 --- a/web/app/components/base/tag-management/__tests__/filter.spec.tsx +++ b/web/app/components/base/tag-management/__tests__/filter.spec.tsx @@ -14,23 +14,11 @@ vi.mock('@/service/tag', () => ({ fetchTagList, })) -// Mock ahooks to avoid timer-related issues in tests vi.mock('ahooks', () => { return { - useDebounceFn: (fn: (...args: unknown[]) => void) => { - const ref = React.useRef(fn) - ref.current = fn - const stableRun = React.useRef((...args: unknown[]) => { - // Schedule to run after current event handler finishes, - // allowing React to process pending state updates first - Promise.resolve().then(() => ref.current(...args)) - }) - return { run: stableRun.current } - }, useMount: (fn: () => void) => { React.useEffect(() => { fn() - // eslint-disable-next-line react-hooks/exhaustive-deps }, []) }, } @@ -228,7 +216,6 @@ describe('TagFilter', () => { const searchInput = screen.getByRole('textbox') await user.type(searchInput, 'Front') - // With debounce mocked to be synchronous, results should be immediate expect(screen.getByText('Frontend')).toBeInTheDocument() expect(screen.queryByText('Backend')).not.toBeInTheDocument() expect(screen.queryByText('API Design')).not.toBeInTheDocument() @@ -257,22 +244,14 @@ describe('TagFilter', () => { const searchInput = screen.getByRole('textbox') await user.type(searchInput, 'Front') - // Wait for the debounced search to filter - await waitFor(() => { - expect(screen.queryByText('Backend')).not.toBeInTheDocument() - }) + expect(screen.queryByText('Backend')).not.toBeInTheDocument() - // Clear the search using the Input's clear button const clearButton = screen.getByTestId('input-clear') await user.click(clearButton) - // The input value should be cleared expect(searchInput).toHaveValue('') - // After the clear + microtask re-render, all app tags should be visible again - await waitFor(() => { - expect(screen.getByText('Backend')).toBeInTheDocument() - }) + expect(screen.getByText('Backend')).toBeInTheDocument() expect(screen.getByText('Frontend')).toBeInTheDocument() expect(screen.getByText('API Design')).toBeInTheDocument() }) diff --git a/web/app/components/base/tag-management/filter.tsx b/web/app/components/base/tag-management/filter.tsx index ad71334ddb..fcd59bcf7d 100644 --- a/web/app/components/base/tag-management/filter.tsx +++ b/web/app/components/base/tag-management/filter.tsx @@ -1,15 +1,15 @@ import type { FC } from 'react' import type { Tag } from '@/app/components/base/tag-management/constant' -import { useDebounceFn, useMount } from 'ahooks' +import { useMount } from 'ahooks' import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import { Tag01, Tag03 } from '@/app/components/base/icons/src/vender/line/financeAndECommerce' import Input from '@/app/components/base/input' import { - PortalToFollowElem, - PortalToFollowElemContent, - PortalToFollowElemTrigger, -} from '@/app/components/base/portal-to-follow-elem' + Popover, + PopoverContent, + PopoverTrigger, +} from '@/app/components/base/ui/popover' import { fetchTagList } from '@/service/tag' import { cn } from '@/utils/classnames' @@ -33,18 +33,10 @@ const TagFilter: FC = ({ const setShowTagManagementModal = useTagStore(s => s.setShowTagManagementModal) const [keywords, setKeywords] = useState('') - const [searchKeywords, setSearchKeywords] = useState('') - const { run: handleSearch } = useDebounceFn(() => { - setSearchKeywords(keywords) - }, { wait: 500 }) - const handleKeywordsChange = (value: string) => { - setKeywords(value) - handleSearch() - } const filteredTagList = useMemo(() => { - return tagList.filter(tag => tag.type === type && tag.name.includes(searchKeywords)) - }, [type, tagList, searchKeywords]) + return tagList.filter(tag => tag.type === type && tag.name.includes(keywords)) + }, [type, tagList, keywords]) const currentTag = useMemo(() => { return tagList.find(tag => tag.id === value[0]) @@ -64,61 +56,61 @@ const TagFilter: FC = ({ }) return ( -
- setOpen(v => !v)} - className="block" - > -
-
- -
-
- {!value.length && t('tag.placeholder', { ns: 'common' })} - {!!value.length && currentTag?.name} -
- {value.length > 1 && ( -
{`+${value.length - 1}`}
- )} - {!value.length && ( +
- +
- )} - {!!value.length && ( -
{ - e.stopPropagation() - onChange([]) - }} - data-testid="tag-filter-clear-button" - > - +
+ {!value.length && t('tag.placeholder', { ns: 'common' })} + {!!value.length && currentTag?.name}
- )} -
- - -
+ {value.length > 1 && ( +
{`+${value.length - 1}`}
+ )} + {!value.length && ( +
+ +
+ )} + + )} + /> + {!!value.length && ( + + )} + +
handleKeywordsChange(e.target.value)} - onClear={() => handleKeywordsChange('')} + onChange={e => setKeywords(e.target.value)} + onClear={() => setKeywords('')} />
@@ -155,9 +147,9 @@ const TagFilter: FC = ({
-
+
- + ) } diff --git a/web/app/components/plugins/plugin-detail-panel/model-selector/index.tsx b/web/app/components/plugins/plugin-detail-panel/model-selector/index.tsx index 761b7a12f4..04b78f98b7 100644 --- a/web/app/components/plugins/plugin-detail-panel/model-selector/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/model-selector/index.tsx @@ -31,7 +31,6 @@ import TTSParamsPanel from './tts-params-panel' export type ModelParameterModalProps = { popupClassName?: string - portalToFollowElemContentClassName?: string isAdvancedMode: boolean value: any setModel: (model: any) => void @@ -44,7 +43,6 @@ export type ModelParameterModalProps = { const ModelParameterModal: FC = ({ popupClassName, - portalToFollowElemContentClassName, isAdvancedMode, value, setModel, @@ -230,7 +228,6 @@ const ModelParameterModal: FC = ({
diff --git a/web/eslint.constants.mjs b/web/eslint.constants.mjs index ce19b99c9b..9992d94f36 100644 --- a/web/eslint.constants.mjs +++ b/web/eslint.constants.mjs @@ -116,7 +116,6 @@ export const OVERLAY_MIGRATION_LEGACY_BASE_FILES = [ 'app/components/base/select/index.tsx', 'app/components/base/select/pure.tsx', 'app/components/base/sort/index.tsx', - 'app/components/base/tag-management/filter.tsx', 'app/components/base/theme-selector.tsx', 'app/components/base/tooltip/index.tsx', ]