From 23cd129802beb6017fd82be2c95e6efb0e9fbce3 Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Fri, 5 Jun 2026 16:15:28 +0800 Subject: [PATCH] refactor(web): align search input with dify ui (#37101) --- eslint-suppressions.json | 6 - .../components/apps/__tests__/list.spec.tsx | 17 +-- web/app/components/apps/list.tsx | 18 +-- .../checkbox-list/__tests__/index.spec.tsx | 13 +- .../components/base/checkbox-list/index.tsx | 4 +- .../search-input/__tests__/index.spec.tsx | 140 ++++++++++++------ .../base/search-input/index.stories.tsx | 63 +++----- .../components/base/search-input/index.tsx | 104 +++++++------ .../account-setting/__tests__/index.spec.tsx | 2 +- .../header/account-setting/index.tsx | 6 +- .../agent-strategy-selector.spec.tsx | 16 +- .../components/agent-strategy-selector.tsx | 9 +- 12 files changed, 216 insertions(+), 182 deletions(-) diff --git a/eslint-suppressions.json b/eslint-suppressions.json index e1a54ec37c..fde5850496 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -660,9 +660,6 @@ "web/app/components/apps/list.tsx": { "no-restricted-globals": { "count": 2 - }, - "no-restricted-imports": { - "count": 1 } }, "web/app/components/apps/new-app-card.tsx": { @@ -1744,9 +1741,6 @@ "web/app/components/base/search-input/index.stories.tsx": { "no-console": { "count": 3 - }, - "ts/no-explicit-any": { - "count": 1 } }, "web/app/components/base/svg-gallery/index.tsx": { diff --git a/web/app/components/apps/__tests__/list.spec.tsx b/web/app/components/apps/__tests__/list.spec.tsx index b09b0d0051..d23982655a 100644 --- a/web/app/components/apps/__tests__/list.spec.tsx +++ b/web/app/components/apps/__tests__/list.spec.tsx @@ -203,9 +203,9 @@ vi.mock('../app-card', () => ({ })) vi.mock('../new-app-card', () => ({ - default: React.forwardRef((_props: unknown, _ref: React.ForwardedRef) => { + default: (_props: { ref?: React.Ref }) => { return React.createElement('div', { 'data-testid': 'new-app-card', 'role': 'button' }, 'New App Card') - }), + }, })) vi.mock('../empty', () => ({ @@ -293,7 +293,7 @@ describe('List', () => { it('should render search input', () => { renderList() - expect(screen.getByRole('textbox'))!.toBeInTheDocument() + expect(screen.getByRole('searchbox', { name: 'app.gotoAnything.actions.searchApplications' }))!.toBeInTheDocument() }) it('should render tag filter', () => { @@ -360,13 +360,13 @@ describe('List', () => { describe('Search Functionality', () => { it('should render search input field', () => { renderList() - expect(screen.getByRole('textbox'))!.toBeInTheDocument() + expect(screen.getByRole('searchbox', { name: 'app.gotoAnything.actions.searchApplications' }))!.toBeInTheDocument() }) it('should handle search input change', () => { renderList() - const input = screen.getByRole('textbox') + const input = screen.getByRole('searchbox', { name: 'app.gotoAnything.actions.searchApplications' }) fireEvent.change(input, { target: { value: 'test search' } }) expect(mockSetKeywords).toHaveBeenCalledWith('test search') @@ -377,10 +377,7 @@ describe('List', () => { renderList() - const clearButton = document.querySelector('.group') - expect(clearButton)!.toBeInTheDocument() - if (clearButton) - fireEvent.click(clearButton) + fireEvent.click(screen.getByRole('button', { name: 'common.operation.clear' })) expect(mockSetKeywords).toHaveBeenCalledWith('') }) @@ -505,7 +502,7 @@ describe('List', () => { it('should render with all filter options visible', () => { renderList() - expect(screen.getByRole('textbox'))!.toBeInTheDocument() + expect(screen.getByRole('searchbox', { name: 'app.gotoAnything.actions.searchApplications' }))!.toBeInTheDocument() expect(screen.getByText('common.tag.placeholder'))!.toBeInTheDocument() expect(screen.getByText('app.showMyCreatedAppsOnly'))!.toBeInTheDocument() }) diff --git a/web/app/components/apps/list.tsx b/web/app/components/apps/list.tsx index 33469f0ef8..2b72857eab 100644 --- a/web/app/components/apps/list.tsx +++ b/web/app/components/apps/list.tsx @@ -1,6 +1,5 @@ 'use client' -import type { FC } from 'react' import type { AppListQuery } from '@/contract/console/apps' import { Checkbox } from '@langgenius/dify-ui/checkbox' import { cn } from '@langgenius/dify-ui/cn' @@ -8,7 +7,7 @@ import { keepPreviousData, useInfiniteQuery, useSuspenseQuery } from '@tanstack/ import { useDebounce } from 'ahooks' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import Input from '@/app/components/base/input' +import { SearchInput } from '@/app/components/base/search-input' import TabSliderNew from '@/app/components/base/tab-slider-new' import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import { useAppContext } from '@/context/app-context' @@ -39,9 +38,9 @@ const CreateFromDSLModal = dynamic(() => import('@/app/components/app/create-fro type Props = { controlRefreshList?: number } -const List: FC = ({ +function List({ controlRefreshList = 0, -}) => { +}: Props) { const { t } = useTranslation() const { data: systemFeatures } = useSuspenseQuery(systemFeaturesQueryOptions()) const { isCurrentWorkspaceEditor, isCurrentWorkspaceDatasetOperator, isLoadingCurrentWorkspace } = useAppContext() @@ -224,13 +223,12 @@ const List: FC = ({ setShowTagManagementModal(true)} /> - setKeywords(e.target.value)} - onClear={() => setKeywords('')} + onValueChange={setKeywords} + placeholder={t('operation.search', { ns: 'common' })} + aria-label={t('gotoAnything.actions.searchApplications', { ns: 'app' })} /> diff --git a/web/app/components/base/checkbox-list/__tests__/index.spec.tsx b/web/app/components/base/checkbox-list/__tests__/index.spec.tsx index feccbd0b38..06dea9225e 100644 --- a/web/app/components/base/checkbox-list/__tests__/index.spec.tsx +++ b/web/app/components/base/checkbox-list/__tests__/index.spec.tsx @@ -4,6 +4,7 @@ import { CheckboxList } from '..' describe('checkbox list component', () => { const selectAllName = 'common.operation.selectAll' + const getSearchInput = () => screen.getByRole('searchbox', { name: 'common.operation.search' }) const options = [ { label: 'Option 1', value: 'option1' }, { label: 'Option 2', value: 'option2' }, @@ -30,7 +31,7 @@ describe('checkbox list component', () => { it('filters options by label', async () => { render() - const input = screen.getByRole('textbox') + const input = getSearchInput() await userEvent.type(input, 'app') expect(screen.getByText('Apple'))!.toBeInTheDocument() @@ -116,7 +117,7 @@ describe('checkbox list component', () => { it('hides select-all checkbox when searching', async () => { render() - await userEvent.type(screen.getByRole('textbox'), 'app') + await userEvent.type(getSearchInput(), 'app') expect(screen.queryByRole('checkbox', { name: selectAllName })).not.toBeInTheDocument() }) @@ -182,7 +183,7 @@ describe('checkbox list component', () => { />, ) - const input = screen.getByRole('textbox') + const input = getSearchInput() await userEvent.type(input, 'ban') await userEvent.click(screen.getByText('common.operation.resetKeywords')) expect(input)!.toHaveValue('') @@ -293,7 +294,7 @@ describe('checkbox list component', () => { it('filters options correctly when searching', async () => { render() - const input = screen.getByRole('textbox') + const input = getSearchInput() await userEvent.type(input, 'option') expect(screen.getByText('Option 1'))!.toBeInTheDocument() @@ -305,7 +306,7 @@ describe('checkbox list component', () => { it('shows no data message when no options match search', async () => { render() - const input = screen.getByRole('textbox') + const input = getSearchInput() await userEvent.type(input, 'xyz') expect(screen.getByText(/common.operation.noSearchResults/i))!.toBeInTheDocument() @@ -372,7 +373,7 @@ describe('checkbox list component', () => { />, ) - const input = screen.getByRole('textbox') + const input = getSearchInput() await userEvent.type(input, 'opt') expect(screen.getByText(/operation.searchCount/i))!.toBeInTheDocument() diff --git a/web/app/components/base/checkbox-list/index.tsx b/web/app/components/base/checkbox-list/index.tsx index 0b809e3792..fb3fd58fab 100644 --- a/web/app/components/base/checkbox-list/index.tsx +++ b/web/app/components/base/checkbox-list/index.tsx @@ -8,7 +8,7 @@ import { FieldsetLegend, FieldsetRoot } from '@langgenius/dify-ui/fieldset' import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import Badge from '@/app/components/base/badge' -import SearchInput from '@/app/components/base/search-input' +import { SearchInput } from '@/app/components/base/search-input' import SearchMenu from '@/assets/search-menu.svg' type CheckboxListOption = { @@ -134,7 +134,7 @@ export const CheckboxList = ({ {showSearch && ( diff --git a/web/app/components/base/search-input/__tests__/index.spec.tsx b/web/app/components/base/search-input/__tests__/index.spec.tsx index 1189c107b4..6656b1fb43 100644 --- a/web/app/components/base/search-input/__tests__/index.spec.tsx +++ b/web/app/components/base/search-input/__tests__/index.spec.tsx @@ -1,23 +1,31 @@ import { fireEvent, render, screen } from '@testing-library/react' -import SearchInput from '..' +import { useState } from 'react' +import { SearchInput } from '..' describe('SearchInput', () => { describe('Render', () => { it('renders correctly with default props', () => { - render( {}} />) - const input = screen.getByPlaceholderText('common.operation.search') + render( {}} />) + const input = screen.getByRole('searchbox', { name: 'common.operation.search' }) expect(input).toBeInTheDocument() expect(input).toHaveValue('') + expect(input).toHaveAttribute('name', 'query') + expect(input).toHaveAttribute('autocomplete', 'off') }) it('renders custom placeholder', () => { - render( {}} placeholder="Custom Placeholder" />) - expect(screen.getByPlaceholderText('Custom Placeholder')).toBeInTheDocument() + render( {}} placeholder="Custom Placeholder" />) + expect(screen.getByRole('searchbox', { name: 'common.operation.search' })).toHaveAttribute('placeholder', 'Custom Placeholder') + }) + + it('uses custom aria label', () => { + render( {}} aria-label="Search providers" />) + expect(screen.getByRole('searchbox', { name: 'Search providers' })).toBeInTheDocument() }) it('shows clear button when value is present', () => { - const onChange = vi.fn() - render() + const onValueChange = vi.fn() + render() const clearButton = screen.getByLabelText('common.operation.clear') expect(clearButton).toBeInTheDocument() @@ -25,65 +33,113 @@ describe('SearchInput', () => { }) describe('Interaction', () => { - it('calls onChange when typing', () => { - const onChange = vi.fn() - render() - const input = screen.getByPlaceholderText('common.operation.search') + it('calls onValueChange when typing', () => { + const onValueChange = vi.fn() + render() + const input = screen.getByRole('searchbox', { name: 'common.operation.search' }) fireEvent.change(input, { target: { value: 'test' } }) - expect(onChange).toHaveBeenCalledWith('test') + expect(onValueChange).toHaveBeenCalledWith('test') }) it('handles composition events', () => { - const onChange = vi.fn() - render() - const input = screen.getByPlaceholderText('common.operation.search') + const onValueChange = vi.fn() + render() + const input = screen.getByRole('searchbox', { name: 'common.operation.search' }) - // Start composition fireEvent.compositionStart(input) fireEvent.change(input, { target: { value: 'final' } }) - // While composing, onChange should NOT be called - expect(onChange).not.toHaveBeenCalled() + expect(onValueChange).not.toHaveBeenCalled() expect(input).toHaveValue('final') - // End composition fireEvent.compositionEnd(input) - expect(onChange).toHaveBeenCalledTimes(1) - expect(onChange).toHaveBeenCalledWith('final') + expect(onValueChange).toHaveBeenCalledTimes(1) + expect(onValueChange).toHaveBeenCalledWith('final') }) - it('calls onChange with empty string when clear button is clicked', () => { - const onChange = vi.fn() - render() + it('does not keep stale composition commits after the next distinct change', () => { + const onValueChange = vi.fn() + + function ControlledSearchInput() { + const [value, setValue] = useState('initial') + + return ( + { + onValueChange(nextValue) + setValue(nextValue) + }} + /> + ) + } + + render() + const input = screen.getByRole('searchbox', { name: 'common.operation.search' }) + + fireEvent.compositionStart(input) + fireEvent.change(input, { target: { value: 'final' } }) + fireEvent.compositionEnd(input) + fireEvent.change(input, { target: { value: 'finalx' } }) + fireEvent.change(input, { target: { value: 'final' } }) + + expect(onValueChange).toHaveBeenCalledTimes(3) + expect(onValueChange).toHaveBeenNthCalledWith(1, 'final') + expect(onValueChange).toHaveBeenNthCalledWith(2, 'finalx') + expect(onValueChange).toHaveBeenNthCalledWith(3, 'final') + }) + + it('clears composition value without committing stale text', () => { + const onValueChange = vi.fn() + + function ControlledSearchInput() { + const [value, setValue] = useState('initial') + + return ( + { + onValueChange(nextValue) + setValue(nextValue) + }} + /> + ) + } + + render() + const input = screen.getByRole('searchbox', { name: 'common.operation.search' }) + + fireEvent.compositionStart(input) + fireEvent.change(input, { target: { value: 'final' } }) + fireEvent.click(screen.getByRole('button', { name: 'common.operation.clear' })) + fireEvent.compositionEnd(input) + + expect(input).toHaveValue('') + expect(onValueChange).toHaveBeenCalledTimes(1) + expect(onValueChange).toHaveBeenCalledWith('') + }) + + it('calls onValueChange with empty string when clear button is clicked', () => { + const onValueChange = vi.fn() + render() const clearButton = screen.getByLabelText('common.operation.clear') fireEvent.click(clearButton) - expect(onChange).toHaveBeenCalledWith('') + expect(onValueChange).toHaveBeenCalledWith('') }) - it('updates focus state on focus/blur', () => { - const { container } = render( {}} />) - const wrapper = container.firstChild as HTMLElement - const input = screen.getByPlaceholderText('common.operation.search') - - fireEvent.focus(input) - expect(wrapper).toHaveClass(/bg-components-input-bg-active/) - - fireEvent.blur(input) - expect(wrapper).not.toHaveClass(/bg-components-input-bg-active/) + it('uses dify-ui input spacing for the search adornment', () => { + render( {}} />) + const input = screen.getByRole('searchbox', { name: 'common.operation.search' }) + expect(input).toHaveClass('ps-7') + expect(input).not.toHaveClass('h-[18px]') }) }) describe('Style', () => { - it('applies white style', () => { - const { container } = render( {}} white />) - const wrapper = container.firstChild as HTMLElement - expect(wrapper).toHaveClass('bg-white!') - }) - it('applies custom className', () => { - const { container } = render( {}} className="custom-test" />) + const { container } = render( {}} className="custom-test" />) const wrapper = container.firstChild as HTMLElement expect(wrapper).toHaveClass('custom-test') }) diff --git a/web/app/components/base/search-input/index.stories.tsx b/web/app/components/base/search-input/index.stories.tsx index bf8881c7c8..eec9eae510 100644 --- a/web/app/components/base/search-input/index.stories.tsx +++ b/web/app/components/base/search-input/index.stories.tsx @@ -1,7 +1,8 @@ import type { Meta, StoryObj } from '@storybook/nextjs-vite' +import type { ComponentProps } from 'react' import { Kbd } from '@langgenius/dify-ui/kbd' import { useState } from 'react' -import SearchInput from '.' +import { SearchInput } from '.' const meta = { title: 'Base/Data Entry/SearchInput', @@ -20,25 +21,21 @@ const meta = { control: 'text', description: 'Search input value', }, - onChange: { - action: 'changed', - description: 'Change handler', + onValueChange: { + action: 'value changed', + description: 'Value change handler', }, placeholder: { control: 'text', description: 'Placeholder text', }, - white: { - control: 'boolean', - description: 'White background variant', - }, className: { control: 'text', description: 'Additional CSS classes', }, }, args: { - onChange: (v) => { + onValueChange: (v: string) => { console.log('Search value changed:', v) }, }, @@ -47,8 +44,7 @@ const meta = { export default meta type Story = StoryObj -// Interactive demo wrapper -const SearchInputDemo = (args: any) => { +const SearchInputDemo = (args: ComponentProps) => { const [value, setValue] = useState(args.value || '') return ( @@ -56,7 +52,7 @@ const SearchInputDemo = (args: any) => { { + onValueChange={(v: string) => { setValue(v) console.log('Search value changed:', v) }} @@ -77,31 +73,19 @@ export const Default: Story = { render: args => , args: { placeholder: 'Search...', - white: false, value: '', - onChange: (v) => { + onValueChange: (v: string) => { console.log('Search value changed:', v) }, }, } -// White variant -export const WhiteBackground: Story = { - render: args => , - args: { - placeholder: 'Search...', - white: true, - value: '', - }, -} - // With initial value export const WithInitialValue: Story = { render: args => , args: { value: 'Initial search query', placeholder: 'Search...', - white: false, }, } @@ -110,7 +94,6 @@ export const CustomPlaceholder: Story = { render: args => , args: { placeholder: 'Search documents, files, and more...', - white: false, value: '', }, } @@ -138,7 +121,7 @@ const UserListSearchDemo = () => {

Team Members

@@ -212,9 +195,8 @@ const ProductSearchDemo = () => {

Product Catalog

{filteredProducts.length > 0 @@ -272,10 +254,8 @@ const DocumentationSearchDemo = () => {

Search our comprehensive guides and API references

{filteredDocs.length > 0 @@ -338,10 +318,8 @@ const CommandPaletteDemo = () => {
@@ -413,13 +391,13 @@ const LiveSearchWithCountDemo = () => {
- {filteredItems.map((item, index) => ( + {filteredItems.map(item => (
{item}
@@ -445,24 +423,22 @@ const SizeVariationsDemo = () => {
- +
@@ -480,6 +456,5 @@ export const Playground: Story = { args: { value: '', placeholder: 'Search...', - white: false, }, } diff --git a/web/app/components/base/search-input/index.tsx b/web/app/components/base/search-input/index.tsx index dc29c4d510..eccb8377a8 100644 --- a/web/app/components/base/search-input/index.tsx +++ b/web/app/components/base/search-input/index.tsx @@ -1,86 +1,100 @@ -import type { FC } from 'react' +import type { ComponentProps } from 'react' import { cn } from '@langgenius/dify-ui/cn' -import { RiCloseCircleFill, RiSearchLine } from '@remixicon/react' +import { Input } from '@langgenius/dify-ui/input' import { useRef, useState } from 'react' import { useTranslation } from 'react-i18next' type SearchInputProps = { + value: string + onValueChange: (value: string) => void placeholder?: string className?: string - value: string - onChange: (v: string) => void - white?: boolean -} +} & Pick, 'aria-label'> -const SearchInput: FC = ({ +export function SearchInput({ placeholder, className, value, - onChange, - white, -}) => { + onValueChange, + 'aria-label': ariaLabel, +}: SearchInputProps) { const { t } = useTranslation() const inputRef = useRef(null) - const [focus, setFocus] = useState(false) - const isComposing = useRef(false) - const [compositionValue, setCompositionValue] = useState('') + const isComposingRef = useRef(false) + const compositionCommitRef = useRef(null) + const [compositionValue, setCompositionValue] = useState('') + const inputValue = isComposingRef.current ? compositionValue : value + + const handleClear = () => { + isComposingRef.current = false + compositionCommitRef.current = null + setCompositionValue('') + onValueChange('') + inputRef.current?.focus() + } return (
-
-
- + { - const newValue = e.target.value - if (isComposing.current) - setCompositionValue(newValue) - else - onChange(newValue) + placeholder={placeholder ?? t('operation.search', { ns: 'common' })} + value={inputValue} + onValueChange={(nextValue) => { + if (isComposingRef.current) { + setCompositionValue(nextValue) + return + } + if (compositionCommitRef.current !== null) { + if (compositionCommitRef.current !== nextValue) { + compositionCommitRef.current = null + onValueChange(nextValue) + return + } + compositionCommitRef.current = null + return + } + onValueChange(nextValue) }} onCompositionStart={() => { - isComposing.current = true + isComposingRef.current = true + compositionCommitRef.current = null setCompositionValue(value) }} onCompositionEnd={(e) => { - isComposing.current = false + if (!isComposingRef.current) + return + + isComposingRef.current = false setCompositionValue('') - onChange(e.currentTarget.value) + compositionCommitRef.current = e.currentTarget.value + onValueChange(e.currentTarget.value) }} - onFocus={() => setFocus(true)} - onBlur={() => setFocus(false)} autoComplete="off" + enterKeyHint="search" /> - {value && ( + {!!inputValue && ( )}
) } - -export default SearchInput diff --git a/web/app/components/header/account-setting/__tests__/index.spec.tsx b/web/app/components/header/account-setting/__tests__/index.spec.tsx index a4c9d79b5d..e5767dfdc6 100644 --- a/web/app/components/header/account-setting/__tests__/index.spec.tsx +++ b/web/app/components/header/account-setting/__tests__/index.spec.tsx @@ -461,7 +461,7 @@ describe('AccountSetting', () => { renderAccountSetting({ initialTab: ACCOUNT_SETTING_TAB.PROVIDER }) // Act - const input = screen.getByRole('textbox') + const input = screen.getByRole('searchbox', { name: 'common.operation.search' }) fireEvent.change(input, { target: { value: 'test-search' } }) // Assert diff --git a/web/app/components/header/account-setting/index.tsx b/web/app/components/header/account-setting/index.tsx index 19dee39709..1e712d7eab 100644 --- a/web/app/components/header/account-setting/index.tsx +++ b/web/app/components/header/account-setting/index.tsx @@ -5,7 +5,7 @@ import { cn } from '@langgenius/dify-ui/cn' import { ScrollArea } from '@langgenius/dify-ui/scroll-area' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' -import SearchInput from '@/app/components/base/search-input' +import { SearchInput } from '@/app/components/base/search-input' import BillingPage from '@/app/components/billing/billing-page' import CustomPage from '@/app/components/custom/custom-page' import { @@ -218,8 +218,8 @@ export default function AccountSetting({ {activeItem?.key === ACCOUNT_SETTING_TAB.PROVIDER && (
diff --git a/web/app/components/workflow/nodes/_base/components/__tests__/agent-strategy-selector.spec.tsx b/web/app/components/workflow/nodes/_base/components/__tests__/agent-strategy-selector.spec.tsx index 58296f5af5..acdef3c943 100644 --- a/web/app/components/workflow/nodes/_base/components/__tests__/agent-strategy-selector.spec.tsx +++ b/web/app/components/workflow/nodes/_base/components/__tests__/agent-strategy-selector.spec.tsx @@ -42,20 +42,20 @@ vi.mock('@/app/components/plugins/install-plugin/base/use-get-icon', () => ({ })) vi.mock('@/app/components/base/search-input', () => ({ - default: ({ + SearchInput: ({ value, - onChange, + onValueChange, placeholder, }: { value: string - onChange: (value: string) => void + onValueChange: (value: string) => void placeholder?: string className?: string }) => ( onChange(e.target.value)} + onChange={e => onValueChange(e.target.value)} /> ), })) @@ -220,14 +220,14 @@ vi.mock('@langgenius/dify-ui/popover', async () => { } return ( - + {children} - + ) } const PopoverTrigger = ({ render }: { render: React.ReactNode }) => { - const { open, setOpen } = React.useContext(PopoverContext) + const { open, setOpen } = React.use(PopoverContext) return (
setOpen(!open)}> {render} @@ -236,7 +236,7 @@ vi.mock('@langgenius/dify-ui/popover', async () => { } const PopoverContent = ({ children }: { children: React.ReactNode }) => { - const { open } = React.useContext(PopoverContext) + const { open } = React.use(PopoverContext) return open ?
{children}
: null } diff --git a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx index f3cd453e67..9d1d8eec0a 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx @@ -14,11 +14,10 @@ import { TooltipContent, TooltipTrigger, } from '@langgenius/dify-ui/tooltip' -import { RiArrowDownSLine, RiErrorWarningFill } from '@remixicon/react' import { useSuspenseQuery } from '@tanstack/react-query' import { memo, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import SearchInput from '@/app/components/base/search-input' +import { SearchInput } from '@/app/components/base/search-input' import useGetIcon from '@/app/components/plugins/install-plugin/base/use-get-icon' import { useMarketplacePlugins } from '@/app/components/plugins/marketplace/hooks' import { PluginCategoryEnum } from '@/app/components/plugins/types' @@ -45,7 +44,7 @@ const NotFoundWarn = (props: { return (
} + render={
} />
@@ -204,7 +203,7 @@ export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) => description={t('nodes.agent.strategyNotFoundDesc', { ns: 'workflow' })} /> ) - : } + :