From 45e4d4720734d2b57c70aeff264a09d59a9c8767 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:49:49 +0000 Subject: [PATCH 1/9] [autofix.ci] apply automated fixes --- web/eslint-suppressions.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json index 96da7fa748..4714f517fc 100644 --- a/web/eslint-suppressions.json +++ b/web/eslint-suppressions.json @@ -4568,11 +4568,6 @@ "count": 5 } }, - "app/components/header/account-setting/model-provider-page/model-name/index.tsx": { - "tailwindcss/enforce-consistent-class-order": { - "count": 1 - } - }, "app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 From 5d07ccce5991508c475f961f089c715b00283f13 Mon Sep 17 00:00:00 2001 From: yyh Date: Wed, 11 Mar 2026 20:08:46 +0800 Subject: [PATCH 2/9] fix: tests --- .../model-selector/index.spec.tsx | 68 +++++++++++++------ .../model-selector/popup.spec.tsx | 36 +++------- 2 files changed, 59 insertions(+), 45 deletions(-) diff --git a/web/app/components/header/account-setting/model-provider-page/model-selector/index.spec.tsx b/web/app/components/header/account-setting/model-provider-page/model-selector/index.spec.tsx index 0491bb0849..e658150a2f 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-selector/index.spec.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-selector/index.spec.tsx @@ -1,4 +1,6 @@ -import type { Model, ModelItem } from '../declarations' +import type { ReactNode } from 'react' +import type { DefaultModel, Model, ModelItem } from '../declarations' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { fireEvent, render, screen } from '@testing-library/react' import { ConfigurationMethodEnum, @@ -7,16 +9,20 @@ import { } from '../declarations' import ModelSelector from './index' -vi.mock('./model-trigger', () => ({ - default: () =>
model-trigger
, -})) +vi.mock('./model-selector-trigger', () => ({ + default: ({ + currentProvider, + currentModel, + defaultModel, + }: { currentProvider?: Model, currentModel?: ModelItem, defaultModel?: DefaultModel }) => { + if (currentProvider && currentModel) + return
model-trigger
-vi.mock('./deprecated-model-trigger', () => ({ - default: ({ modelName }: { modelName: string }) =>
{`deprecated:${modelName}`}
, -})) + if (defaultModel) + return
{`deprecated:${defaultModel.model}`}
-vi.mock('./empty-trigger', () => ({ - default: () =>
empty-trigger
, + return
empty-trigger
+ }, })) vi.mock('./popup', () => ({ @@ -52,24 +58,43 @@ const makeModel = (overrides: Partial = {}): Model => ({ ...overrides, }) +const createTestQueryClient = () => new QueryClient({ + defaultOptions: { + queries: { retry: false }, + mutations: { retry: false }, + }, +}) + +const renderWithQueryClient = (node: ReactNode) => { + const queryClient = createTestQueryClient() + return render( + + {node} + , + ) +} + describe('ModelSelector', () => { beforeEach(() => { vi.clearAllMocks() }) it('should toggle popup and close it after selecting a model', () => { - render() + renderWithQueryClient() - fireEvent.click(screen.getByText('empty-trigger')) + const triggerButton = screen.getByRole('button', { name: 'empty-trigger' }) + + fireEvent.click(triggerButton) + expect(triggerButton).toHaveAttribute('aria-expanded', 'true') expect(screen.getByText('select')).toBeInTheDocument() fireEvent.click(screen.getByText('select')) - expect(screen.queryByText('select')).not.toBeInTheDocument() + expect(triggerButton).toHaveAttribute('aria-expanded', 'false') }) it('should call onSelect when provided', () => { const onSelect = vi.fn() - render() + renderWithQueryClient() fireEvent.click(screen.getByText('empty-trigger')) fireEvent.click(screen.getByText('select')) @@ -78,24 +103,26 @@ describe('ModelSelector', () => { }) it('should close popup when popup requests hide', () => { - render() + renderWithQueryClient() - fireEvent.click(screen.getByText('empty-trigger')) + const triggerButton = screen.getByRole('button', { name: 'empty-trigger' }) + fireEvent.click(triggerButton) + expect(triggerButton).toHaveAttribute('aria-expanded', 'true') expect(screen.getByText('hide')).toBeInTheDocument() fireEvent.click(screen.getByText('hide')) - expect(screen.queryByText('hide')).not.toBeInTheDocument() + expect(triggerButton).toHaveAttribute('aria-expanded', 'false') }) it('should not open popup when readonly', () => { - render() + renderWithQueryClient() fireEvent.click(screen.getByText('empty-trigger')) expect(screen.queryByText('select')).not.toBeInTheDocument() }) it('should render deprecated trigger when defaultModel is not in list', () => { - const { rerender } = render( + const { unmount } = renderWithQueryClient( { expect(screen.getByText('deprecated:missing-model')).toBeInTheDocument() - rerender( + unmount() + renderWithQueryClient( { }) it('should render model trigger when defaultModel matches', () => { - render( + renderWithQueryClient( ({ supportFunctionCall: mockSupportFunctionCall, })) -const mockCloseActiveTooltip = vi.hoisted(() => vi.fn()) -vi.mock('@/app/components/base/tooltip/TooltipManager', () => ({ - tooltipManager: { - closeActiveTooltip: mockCloseActiveTooltip, - register: vi.fn(), - clear: vi.fn(), - }, -})) - type MockMarketplacePlugin = { plugin_id: string latest_package_identifier: string @@ -231,12 +222,20 @@ describe('Popup', () => { expect(screen.getByText('No model found for \u201C\u201D')).toBeInTheDocument() }) - it('should match labels from other languages when current language key is missing', () => { + it('should match model labels from fallback languages when current language key is missing', () => { mockLanguage = 'fr_FR' render( , @@ -244,25 +243,12 @@ describe('Popup', () => { fireEvent.change( screen.getByPlaceholderText('datasetSettings.form.searchModel'), - { target: { value: 'gpt' } }, + { target: { value: 'openai' } }, ) expect(screen.getByText('openai')).toBeInTheDocument() }) - it('should close tooltip on scroll', () => { - const { container } = render( - , - ) - - fireEvent.scroll(container.firstElementChild as HTMLElement) - expect(mockCloseActiveTooltip).toHaveBeenCalled() - }) - it('should open provider settings when clicking footer link', () => { const onHide = vi.fn() render( From 715a0fabfcb7f2782ea1669ee5d90e3ccfa57e71 Mon Sep 17 00:00:00 2001 From: yyh Date: Wed, 11 Mar 2026 20:28:37 +0800 Subject: [PATCH 3/9] fix: tests --- .../__tests__/variable-block.spec.tsx | 2 +- .../settings/form/__tests__/index.spec.tsx | 8 + .../__tests__/indexing-section.spec.tsx | 15 ++ .../model-selector/__tests__/index.spec.tsx | 165 +++++++----------- 4 files changed, 90 insertions(+), 100 deletions(-) diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/variable-block.spec.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/variable-block.spec.tsx index f16951aed1..c8c6bd2d36 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/variable-block.spec.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/variable-block.spec.tsx @@ -33,7 +33,7 @@ const createWorkflowNodesMap = (title = 'Node One'): WorkflowNodesMap => ({ }) const hasErrorIcon = (container: HTMLElement) => { - return container.querySelector('svg.text-text-destructive') !== null + return container.querySelector('svg.text-text-warning') !== null } const renderVariableBlock = (props: { diff --git a/web/app/components/datasets/settings/form/__tests__/index.spec.tsx b/web/app/components/datasets/settings/form/__tests__/index.spec.tsx index b2a2e3c9d8..7048059736 100644 --- a/web/app/components/datasets/settings/form/__tests__/index.spec.tsx +++ b/web/app/components/datasets/settings/form/__tests__/index.spec.tsx @@ -127,6 +127,14 @@ vi.mock('@/service/use-common', () => ({ ], }, }), + useCurrentWorkspace: () => ({ + data: { + trial_credits: 1000, + trial_credits_used: 100, + next_credit_reset_date: undefined, + }, + isPending: false, + }), })) vi.mock('@/app/components/header/account-setting/model-provider-page/hooks', () => ({ diff --git a/web/app/components/datasets/settings/form/components/__tests__/indexing-section.spec.tsx b/web/app/components/datasets/settings/form/components/__tests__/indexing-section.spec.tsx index f49bdbc576..2f771d4c25 100644 --- a/web/app/components/datasets/settings/form/components/__tests__/indexing-section.spec.tsx +++ b/web/app/components/datasets/settings/form/components/__tests__/indexing-section.spec.tsx @@ -30,6 +30,21 @@ vi.mock('@/context/app-context', () => ({ }, })) +vi.mock('@/service/use-common', async () => { + const actual = await vi.importActual('@/service/use-common') + return { + ...actual, + useCurrentWorkspace: () => ({ + data: { + trial_credits: 1000, + trial_credits_used: 100, + next_credit_reset_date: undefined, + }, + isPending: false, + }), + } +}) + // Mock model-provider-page hooks vi.mock('@/app/components/header/account-setting/model-provider-page/hooks', () => ({ useModelList: () => ({ data: [], mutate: vi.fn(), isLoading: false }), diff --git a/web/app/components/plugins/plugin-detail-panel/model-selector/__tests__/index.spec.tsx b/web/app/components/plugins/plugin-detail-panel/model-selector/__tests__/index.spec.tsx index e5750d007b..9b04a710e0 100644 --- a/web/app/components/plugins/plugin-detail-panel/model-selector/__tests__/index.spec.tsx +++ b/web/app/components/plugins/plugin-detail-panel/model-selector/__tests__/index.spec.tsx @@ -9,40 +9,6 @@ import ModelParameterModal from '../index' // ==================== Mock Setup ==================== -// Mock shared state for portal -let mockPortalOpenState = false - -vi.mock('@/app/components/base/portal-to-follow-elem', () => ({ - PortalToFollowElem: ({ children, open }: { children: React.ReactNode, open: boolean }) => { - mockPortalOpenState = open || false - return ( -
- {children} -
- ) - }, - PortalToFollowElemTrigger: ({ children, onClick, className }: { children: React.ReactNode, onClick: () => void, className?: string }) => ( -
- {children} -
- ), - PortalToFollowElemContent: ({ children, className }: { children: React.ReactNode, className?: string }) => { - if (!mockPortalOpenState) - return null - return ( -
- {children} -
- ) - }, -})) - -vi.mock('@/app/components/base/toast', () => ({ - default: { - notify: vi.fn(), - }, -})) - // Mock provider context const mockProviderContextValue = { isAPIKeySet: true, @@ -87,6 +53,8 @@ vi.mock('@/utils/completion-params', () => ({ fetchAndMergeValidCompletionParams: (...args: unknown[]) => mockFetchAndMergeValidCompletionParams(...args), })) +const mockToastNotify = vi.spyOn(Toast, 'notify') + // Mock child components vi.mock('@/app/components/header/account-setting/model-provider-page/model-selector', () => ({ default: ({ defaultModel, modelList, scopeFeatures, onSelect }: { @@ -108,30 +76,33 @@ vi.mock('@/app/components/header/account-setting/model-provider-page/model-selec })) vi.mock('@/app/components/header/account-setting/model-provider-page/model-parameter-modal/trigger', () => ({ - default: ({ disabled, hasDeprecated, modelDisabled, currentProvider, currentModel, providerName, modelId, isInWorkflow }: { - disabled?: boolean - hasDeprecated?: boolean - modelDisabled?: boolean + default: ({ currentProvider, currentModel, providerName, modelId, isInWorkflow }: { currentProvider?: Model currentModel?: ModelItem providerName?: string modelId?: string isInWorkflow?: boolean - }) => ( -
- Trigger -
- ), + }) => { + const hasDeprecated = !currentProvider || !currentModel + const modelDisabled = currentModel?.status !== ModelStatusEnum.active + const disabled = !mockProviderContextValue.isAPIKeySet || hasDeprecated || modelDisabled + + return ( +
+ Trigger +
+ ) + }, })) vi.mock('@/app/components/header/account-setting/model-provider-page/model-parameter-modal/agent-model-trigger', () => ({ @@ -273,7 +244,7 @@ const setupModelLists = (config: { describe('ModelParameterModal', () => { beforeEach(() => { vi.clearAllMocks() - mockPortalOpenState = false + mockToastNotify.mockReturnValue({}) mockProviderContextValue.isAPIKeySet = true mockProviderContextValue.modelProviders = [] setupModelLists() @@ -356,7 +327,7 @@ describe('ModelParameterModal', () => { render() // Assert - expect(screen.queryByTestId('portal-content')).not.toBeInTheDocument() + expect(screen.queryByTestId('model-selector')).not.toBeInTheDocument() }) it('should render model selector inside portal content when open', async () => { @@ -365,13 +336,12 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { - expect(screen.getByTestId('portal-content')).toBeInTheDocument() + expect(screen.getByTestId('model-selector')).toBeInTheDocument() }) - expect(screen.getByTestId('model-selector')).toBeInTheDocument() }) }) @@ -405,12 +375,11 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { - const content = screen.getByTestId('portal-content') - expect(content.querySelector('.custom-popup-class')).toBeInTheDocument() + expect(document.querySelector('.custom-popup-class')).toBeInTheDocument() }) }) @@ -422,7 +391,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert const selector = screen.getByTestId('model-selector') @@ -438,13 +407,13 @@ describe('ModelParameterModal', () => { // Act render() - expect(screen.queryByTestId('portal-content')).not.toBeInTheDocument() + expect(screen.queryByTestId('model-selector')).not.toBeInTheDocument() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { - expect(screen.getByTestId('portal-content')).toBeInTheDocument() + expect(screen.getByTestId('model-selector')).toBeInTheDocument() }) }) @@ -454,15 +423,15 @@ describe('ModelParameterModal', () => { // Act const { rerender } = render() - expect(screen.getByTestId('portal-elem')).toHaveAttribute('data-open', 'false') + expect(screen.queryByTestId('model-selector')).not.toBeInTheDocument() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Force a re-render to ensure state is stable rerender() // Assert - open state should remain false due to readonly - expect(screen.getByTestId('portal-elem')).toHaveAttribute('data-open', 'false') + expect(screen.queryByTestId('model-selector')).not.toBeInTheDocument() }) }) @@ -474,7 +443,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -489,7 +458,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -512,7 +481,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -530,7 +499,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -547,7 +516,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -564,7 +533,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -581,7 +550,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -598,7 +567,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -615,7 +584,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -632,7 +601,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -831,7 +800,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) await waitFor(() => { fireEvent.click(screen.getByTestId('model-selector')) @@ -856,7 +825,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) await waitFor(() => { fireEvent.click(screen.getByTestId('model-selector')) @@ -888,7 +857,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) await waitFor(() => { fireEvent.click(screen.getByTestId('model-selector')) @@ -915,7 +884,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) await waitFor(() => { fireEvent.click(screen.getByTestId('model-selector')) @@ -951,7 +920,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) await waitFor(() => { const panel = screen.getByTestId('llm-params-panel') @@ -988,7 +957,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) await waitFor(() => { const panel = screen.getByTestId('tts-params-panel') @@ -1025,7 +994,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -1051,7 +1020,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -1077,7 +1046,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -1104,12 +1073,11 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { - const content = screen.getByTestId('portal-content') - expect(content.querySelector('.bg-divider-subtle')).toBeInTheDocument() + expect(document.querySelector('.bg-divider-subtle')).toBeInTheDocument() }) }) }) @@ -1146,7 +1114,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -1185,7 +1153,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -1264,7 +1232,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert await waitFor(() => { @@ -1280,7 +1248,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert - defaultModel is created with undefined provider await waitFor(() => { @@ -1297,7 +1265,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert - defaultModel is created with undefined model await waitFor(() => { @@ -1314,7 +1282,7 @@ describe('ModelParameterModal', () => { // Act render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) // Assert - when defaultModel is undefined, attribute is not set (returns null) await waitFor(() => { @@ -1350,14 +1318,13 @@ describe('ModelParameterModal', () => { // Act const { rerender } = render() - fireEvent.click(screen.getByTestId('portal-trigger')) + fireEvent.click(screen.getByTestId('trigger')) await waitFor(() => { expect(screen.getByTestId('model-selector')).toHaveAttribute('data-model-list-count', '1') }) // Rerender with different scope - mockPortalOpenState = true rerender() // Assert @@ -1398,7 +1365,7 @@ describe('ModelParameterModal', () => { render() // Assert - const trigger = screen.getByTestId('portal-trigger') + const trigger = screen.getByTestId('trigger') expect(trigger).toBeInTheDocument() }) }) From c08b9a289b1d988b7851cc48f52f10d48fab1627 Mon Sep 17 00:00:00 2001 From: yyh Date: Wed, 11 Mar 2026 20:42:40 +0800 Subject: [PATCH 4/9] fix: tests --- .../install-bundle/__tests__/index.spec.tsx | 10 +++++++--- .../plugins/update-plugin/from-market-place.tsx | 8 +++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/web/app/components/plugins/install-plugin/install-bundle/__tests__/index.spec.tsx b/web/app/components/plugins/install-plugin/install-bundle/__tests__/index.spec.tsx index 777a5174c6..fee88913b7 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/__tests__/index.spec.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/__tests__/index.spec.tsx @@ -170,9 +170,13 @@ vi.mock('@/service/use-plugins', () => ({ })) // Mock config -vi.mock('@/config', () => ({ - MARKETPLACE_API_PREFIX: 'https://marketplace.example.com', -})) +vi.mock('@/config', async () => { + const actual = await vi.importActual('@/config') + return { + ...actual, + MARKETPLACE_API_PREFIX: 'https://marketplace.example.com', + } +}) // Mock mitt context vi.mock('@/context/mitt-context', () => ({ diff --git a/web/app/components/plugins/update-plugin/from-market-place.tsx b/web/app/components/plugins/update-plugin/from-market-place.tsx index 8bfe3a0a59..7564eae638 100644 --- a/web/app/components/plugins/update-plugin/from-market-place.tsx +++ b/web/app/components/plugins/update-plugin/from-market-place.tsx @@ -99,6 +99,12 @@ const UpdatePluginModal: FC = ({ }) as Awaited> & FailedUpgradeResponse if (response.task?.status === TaskStatus.failed) { + const failedPlugin = response.task.plugins?.find(plugin => plugin.plugin_unique_identifier === targetPackageInfo.id) + ?? response.task.plugins?.[0] + Toast.notify({ + type: 'error', + message: failedPlugin?.message || t('error', { ns: 'common' }), + }) setUploadStep(UploadStep.notStarted) return } @@ -132,7 +138,7 @@ const UpdatePluginModal: FC = ({ } if (uploadStep === UploadStep.installed) onSave() - }, [onSave, uploadStep, check, originalPackageInfo.id, handleRefetch, targetPackageInfo.id]) + }, [onSave, uploadStep, check, originalPackageInfo.id, handleRefetch, t, targetPackageInfo.id]) const { mutateAsync } = useRemoveAutoUpgrade() const invalidateReferenceSettings = useInvalidateReferenceSettings() From bd2bb27faac986931b6f0528db13a87f6b1235bc Mon Sep 17 00:00:00 2001 From: yyh Date: Wed, 11 Mar 2026 20:47:48 +0800 Subject: [PATCH 5/9] fix --- .../plugins/plugin-detail-panel/model-selector/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 721d0dd534..761b7a12f4 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 @@ -191,7 +191,7 @@ const ModelParameterModal: FC = ({
+
+ )} /> Date: Wed, 11 Mar 2026 20:53:17 +0800 Subject: [PATCH 6/9] chore: try 6 shard web tests ci --- .github/workflows/web-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/web-tests.yml b/.github/workflows/web-tests.yml index 33e9170b02..2b4458963e 100644 --- a/.github/workflows/web-tests.yml +++ b/.github/workflows/web-tests.yml @@ -17,8 +17,8 @@ jobs: strategy: fail-fast: false matrix: - shardIndex: [1, 2, 3, 4] - shardTotal: [4] + shardIndex: [1, 2, 3, 4, 5, 6] + shardTotal: [6] defaults: run: shell: bash From e9d0c7bb2a0e56a81adc2fc2c8d523e663f3a30d Mon Sep 17 00:00:00 2001 From: yyh Date: Wed, 11 Mar 2026 21:00:55 +0800 Subject: [PATCH 7/9] fix --- .../install-from-marketplace.tsx | 16 +++++++++++++--- .../credits-exhausted-alert.tsx | 8 +++++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/web/app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx b/web/app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx index 09c1c4b9c6..ab712f27cc 100644 --- a/web/app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx +++ b/web/app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx @@ -43,13 +43,23 @@ const InstallFromMarketplace = ({
-
setCollapse(!collapse)}> +
+
{t('modelProvider.discoverMore', { ns: 'common' })} - + {t('marketplace.difyMarketplace', { ns: 'plugin' })} diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-auth-dropdown/credits-exhausted-alert.tsx b/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-auth-dropdown/credits-exhausted-alert.tsx index d7a414c8b2..802afd931b 100644 --- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-auth-dropdown/credits-exhausted-alert.tsx +++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-auth-dropdown/credits-exhausted-alert.tsx @@ -34,7 +34,13 @@ export default function CreditsExhaustedAlert({ hasApiKeyFallback }: CreditsExha i18nKey={descriptionKey} ns="common" components={{ - upgradeLink: , + upgradeLink: ( +
From ee2280851d9da6aaa0284b46f3dde836ceac670d Mon Sep 17 00:00:00 2001 From: yyh Date: Wed, 11 Mar 2026 21:07:33 +0800 Subject: [PATCH 8/9] fix: checklist popover --- .../header/checklist/plugin-group.spec.tsx | 23 +++++++++++++++---- .../header/checklist/plugin-group.tsx | 21 +++++++++-------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/web/app/components/workflow/header/checklist/plugin-group.spec.tsx b/web/app/components/workflow/header/checklist/plugin-group.spec.tsx index 14c4d980b8..a2f2962afe 100644 --- a/web/app/components/workflow/header/checklist/plugin-group.spec.tsx +++ b/web/app/components/workflow/header/checklist/plugin-group.spec.tsx @@ -1,6 +1,7 @@ import type { ChecklistItem } from '../../hooks/use-checklist' import { fireEvent, render, screen } from '@testing-library/react' import { beforeEach, describe, expect, it } from 'vitest' +import { Popover, PopoverContent } from '@/app/components/base/ui/popover' import { useStore as usePluginDependencyStore } from '../../plugin-dependency/store' import { BlockEnum } from '../../types' import { ChecklistPluginGroup } from './plugin-group' @@ -17,6 +18,20 @@ const createChecklistItem = (overrides: Partial = {}): ChecklistI }) describe('ChecklistPluginGroup', () => { + const getInstallButton = () => { + return screen.getByText('workflow.nodes.agent.pluginInstaller.install').closest('button') as HTMLButtonElement + } + + const renderInPopover = (items: ChecklistItem[]) => { + return render( + + + + + , + ) + } + beforeEach(() => { usePluginDependencyStore.setState({ dependencies: [] }) }) @@ -28,9 +43,9 @@ describe('ChecklistPluginGroup', () => { createChecklistItem({ id: 'node-3', pluginUniqueIdentifier: 'langgenius/another-plugin:2.0.0@sha256' }), ] - render() + renderInPopover(items) - fireEvent.click(screen.getByRole('button')) + fireEvent.click(getInstallButton()) expect(usePluginDependencyStore.getState().dependencies).toEqual([ { @@ -53,9 +68,9 @@ describe('ChecklistPluginGroup', () => { }) it('should keep install button disabled when no identifier is available', () => { - render() + renderInPopover([createChecklistItem({ pluginUniqueIdentifier: undefined })]) - const installButton = screen.getByRole('button') + const installButton = getInstallButton() expect(installButton).toBeDisabled() fireEvent.click(installButton) diff --git a/web/app/components/workflow/header/checklist/plugin-group.tsx b/web/app/components/workflow/header/checklist/plugin-group.tsx index a4863c1363..122cd560bc 100644 --- a/web/app/components/workflow/header/checklist/plugin-group.tsx +++ b/web/app/components/workflow/header/checklist/plugin-group.tsx @@ -1,10 +1,10 @@ -import type { MouseEventHandler } from 'react' import type { ChecklistItem } from '../../hooks/use-checklist' import type { BlockEnum } from '../../types' import type { Dependency } from '@/app/components/plugins/types' import { memo, useMemo } from 'react' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' +import { PopoverClose } from '@/app/components/base/ui/popover' import BlockIcon from '../../block-icon' import { useStore as usePluginDependencyStore } from '../../plugin-dependency/store' import { ItemIndicator } from './item-indicator' @@ -46,8 +46,7 @@ export const ChecklistPluginGroup = memo(({ }) }, [identifiers]) - const handleInstallAll: MouseEventHandler = (e) => { - e.stopPropagation() + const handleInstallAll = () => { if (dependencies.length === 0) return const { setDependencies } = usePluginDependencyStore.getState() @@ -63,14 +62,18 @@ export const ChecklistPluginGroup = memo(({ {t('nodes.common.pluginsNotInstalled', { ns: 'workflow', count: items.length })} - +
{items.map(item => ( From f0086888e39537f3ef83f8531806fe49ac9199d2 Mon Sep 17 00:00:00 2001 From: yyh Date: Wed, 11 Mar 2026 21:17:35 +0800 Subject: [PATCH 9/9] fix --- .../plugins/plugin-page/plugin-tasks/components/plugin-item.tsx | 1 + .../components/plugins/update-plugin/plugin-version-picker.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/web/app/components/plugins/plugin-page/plugin-tasks/components/plugin-item.tsx b/web/app/components/plugins/plugin-page/plugin-tasks/components/plugin-item.tsx index 5fa0f36203..9e8d6df230 100644 --- a/web/app/components/plugins/plugin-page/plugin-tasks/components/plugin-item.tsx +++ b/web/app/components/plugins/plugin-page/plugin-tasks/components/plugin-item.tsx @@ -46,6 +46,7 @@ const PluginItem: FC = ({
{onClear && (