From ea1aa2fecd1d19b115bf369cd37693f14795c0d9 Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Wed, 24 Jun 2026 17:25:52 +0800 Subject: [PATCH] chore(web): remove unused frontend code (#37866) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- eslint-suppressions.json | 69 +- .../dsl-export-import-flow.test.ts | 188 ----- web/__tests__/xss-prevention.test.tsx | 60 -- .../app-info/__tests__/index.spec.tsx | 168 ----- .../components/app-sidebar/app-info/index.tsx | 14 - .../var-highlight/__tests__/index.spec.tsx | 30 +- .../base/var-highlight/index.tsx | 19 - .../config-modal/__tests__/utils.spec.ts | 5 +- .../config-var/config-modal/utils.ts | 4 - .../dataset-config/__tests__/index.spec.tsx | 54 +- .../app/log/__tests__/list-utils.spec.ts | 10 +- web/app/components/app/log/list-utils.ts | 20 - web/app/components/app/overview/app-chart.tsx | 1 - .../__tests__/AmplitudeProvider.spec.tsx | 9 +- .../base/amplitude/__tests__/init.spec.ts | 8 +- web/app/components/base/amplitude/init.ts | 5 - .../base/badge/__tests__/index.spec.tsx | 26 +- web/app/components/base/badge/index.tsx | 2 +- .../base/block-input/__tests__/index.spec.tsx | 233 +----- .../base/block-input/index.stories.tsx | 191 ----- web/app/components/base/block-input/index.tsx | 139 ---- .../utils/__tests__/dayjs-extended.spec.ts | 41 - .../utils/__tests__/dayjs.spec.ts | 37 - .../base/date-and-time-picker/utils/dayjs.ts | 26 - .../error-boundary/__tests__/index.spec.tsx | 71 +- .../components/base/error-boundary/index.tsx | 49 +- .../file-uploader/__tests__/utils.spec.ts | 13 - .../components/base/file-uploader/utils.ts | 6 - .../image-gallery/__tests__/index.spec.tsx | 12 +- .../components/base/image-gallery/index.tsx | 21 - .../image-uploader/__tests__/hooks.spec.ts | 297 +------- .../components/base/image-uploader/hooks.ts | 75 +- .../__tests__/constants.spec.tsx | 7 - .../prompt-editor/__tests__/utils.spec.ts | 76 -- .../base/prompt-editor/constants.tsx | 7 - .../current-block/__tests__/node.spec.tsx | 17 - .../plugins/current-block/node.tsx | 8 +- .../__tests__/node.spec.tsx | 13 +- .../plugins/error-message-block/node.tsx | 8 +- .../hitl-input-block/__tests__/node.spec.tsx | 7 +- .../plugins/hitl-input-block/node.tsx | 8 +- .../last-run-block/__tests__/node.spec.tsx | 9 - .../plugins/last-run-block/node.tsx | 8 +- .../request-url-block/__tests__/node.spec.tsx | 9 - .../plugins/request-url-block/node.tsx | 8 +- .../__tests__/node.spec.tsx | 7 +- .../plugins/roster-reference-block/node.tsx | 7 - .../__tests__/node.spec.tsx | 7 +- .../plugins/variable-value-block/node.tsx | 7 - .../__tests__/node.spec.tsx | 7 +- .../plugins/workflow-variable-block/node.tsx | 8 +- .../components/base/prompt-editor/utils.ts | 20 - .../base/zendesk/__tests__/utils.spec.ts | 58 -- web/app/components/base/zendesk/utils.ts | 10 - .../billing/__tests__/config.spec.ts | 10 +- web/app/components/billing/config.ts | 3 - .../__tests__/check-rerank-model.spec.ts | 175 +---- .../datasets/common/check-rerank-model.ts | 28 - .../__tests__/index.spec.tsx | 94 +-- .../common/retrieval-method-info/index.tsx | 51 -- .../__tests__/file-list-item.spec.tsx | 11 +- .../data-source/local-file/constants.ts | 1 - .../__tests__/use-local-file-upload.spec.tsx | 27 +- .../__tests__/use-embedding-status.spec.tsx | 74 -- .../embedding/hooks/use-embedding-status.ts | 16 - .../detail/metadata/__tests__/index.spec.tsx | 708 ------------------ .../__tests__/doc-type-selector.spec.tsx | 144 ---- .../__tests__/metadata-field-list.spec.tsx | 149 ---- .../metadata/components/doc-type-selector.tsx | 166 ---- .../components/metadata-field-list.tsx | 88 --- .../__tests__/use-metadata-state.spec.ts | 175 ----- .../metadata/hooks/use-metadata-state.ts | 156 ---- .../documents/detail/metadata/index.tsx | 126 ---- .../__tests__/index.spec.tsx | 224 ------ .../workplace-selector/index.tsx | 55 -- .../__tests__/constants.spec.ts | 37 - .../header/account-setting/constants.ts | 7 - .../header/account-setting/destinations.ts | 22 +- .../key-validator/ValidateStatus.tsx | 23 - .../__tests__/ValidateStatus.spec.tsx | 19 - .../__tests__/declarations.spec.ts | 12 - .../key-validator/declarations.ts | 7 - .../__tests__/hooks.spec.ts | 331 +------- .../__tests__/utils.spec.ts | 226 ------ .../model-provider-page/hooks.ts | 90 +-- .../model-provider-page/utils.ts | 135 +--- .../integrations/__tests__/routes.spec.ts | 20 - web/app/components/integrations/routes.ts | 24 - .../plugins/__tests__/utils.spec.ts | 48 +- .../marketplace/__tests__/atoms.spec.tsx | 15 - .../marketplace/__tests__/utils.spec.ts | 16 - .../components/plugins/marketplace/atoms.ts | 4 - .../components/plugins/marketplace/utils.ts | 7 - .../reasoning-config-form.helpers.spec.ts | 18 +- .../reasoning-config-form.helpers.ts | 23 +- web/app/components/plugins/utils.ts | 15 - .../hooks/__tests__/index.spec.ts | 22 - .../hooks/__tests__/use-DSL.spec.ts | 26 +- .../hooks/__tests__/use-pipeline-run.spec.ts | 78 +- .../__tests__/use-pipeline-start-run.spec.ts | 22 +- .../components/rag-pipeline/hooks/use-DSL.ts | 10 +- .../rag-pipeline/hooks/use-pipeline-run.ts | 10 +- .../hooks/use-pipeline-start-run.tsx | 10 +- .../hooks/__tests__/index.spec.ts | 2 - .../hooks/__tests__/use-DSL.spec.ts | 20 +- .../__tests__/use-workflow-start-run.spec.tsx | 52 +- .../components/workflow-app/hooks/use-DSL.ts | 10 +- .../hooks/use-workflow-start-run.tsx | 13 +- .../__tests__/form-input-item.helpers.spec.ts | 2 - .../components/form-input-item.helpers.ts | 3 - .../layout/__tests__/index.spec.tsx | 19 +- .../_base/components/layout/group-field.tsx | 29 - .../nodes/_base/components/layout/index.tsx | 1 - .../hooks/__tests__/use-config.spec.ts | 2 +- .../workflow/nodes/data-source/types.ts | 2 - .../knowledge-base/__tests__/utils.spec.ts | 12 - .../workflow/nodes/knowledge-base/utils.ts | 16 - .../trigger-webhook/__tests__/panel.spec.tsx | 1 - .../__tests__/use-config.spec.tsx | 7 +- .../nodes/trigger-webhook/use-config.ts | 2 - .../__tests__/plugin-install-check.spec.ts | 13 - .../workflow/utils/__tests__/tool.spec.ts | 12 +- .../workflow/utils/__tests__/workflow.spec.ts | 32 - .../workflow/utils/plugin-install-check.ts | 10 - web/app/components/workflow/utils/tool.ts | 7 - web/app/components/workflow/utils/workflow.ts | 27 - web/config/index.ts | 15 - web/hooks/use-metadata.ts | 80 +- web/hooks/use-query-params.spec.tsx | 67 -- web/hooks/use-query-params.ts | 24 - web/models/app.ts | 2 - web/models/common.ts | 43 +- web/models/datasets.ts | 19 +- .../__tests__/use-snippet-workflows.spec.tsx | 78 -- web/service/common.ts | 155 +--- web/service/datasets.ts | 6 +- web/service/use-snippet-workflows.ts | 23 - web/utils/index.spec.ts | 54 -- web/utils/index.ts | 8 - web/utils/permission.spec.ts | 90 --- web/utils/permission.ts | 18 - 141 files changed, 193 insertions(+), 6760 deletions(-) delete mode 100644 web/__tests__/rag-pipeline/dsl-export-import-flow.test.ts delete mode 100644 web/__tests__/xss-prevention.test.tsx delete mode 100644 web/app/components/app-sidebar/app-info/__tests__/index.spec.tsx delete mode 100644 web/app/components/base/block-input/index.stories.tsx delete mode 100644 web/app/components/datasets/documents/detail/metadata/__tests__/index.spec.tsx delete mode 100644 web/app/components/datasets/documents/detail/metadata/components/__tests__/doc-type-selector.spec.tsx delete mode 100644 web/app/components/datasets/documents/detail/metadata/components/__tests__/metadata-field-list.spec.tsx delete mode 100644 web/app/components/datasets/documents/detail/metadata/components/doc-type-selector.tsx delete mode 100644 web/app/components/datasets/documents/detail/metadata/components/metadata-field-list.tsx delete mode 100644 web/app/components/datasets/documents/detail/metadata/hooks/__tests__/use-metadata-state.spec.ts delete mode 100644 web/app/components/datasets/documents/detail/metadata/hooks/use-metadata-state.ts delete mode 100644 web/app/components/header/account-dropdown/workplace-selector/__tests__/index.spec.tsx delete mode 100644 web/app/components/header/account-setting/key-validator/__tests__/declarations.spec.ts delete mode 100644 web/app/components/header/account-setting/key-validator/declarations.ts delete mode 100644 web/app/components/workflow/nodes/_base/components/layout/group-field.tsx delete mode 100644 web/service/__tests__/use-snippet-workflows.spec.tsx diff --git a/eslint-suppressions.json b/eslint-suppressions.json index ba5b7366185..796b8166c73 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -474,11 +474,6 @@ "count": 1 } }, - "web/app/components/app/configuration/base/var-highlight/index.tsx": { - "react-refresh/only-export-components": { - "count": 1 - } - }, "web/app/components/app/configuration/config-prompt/__tests__/index.spec.tsx": { "jsx-a11y/click-events-have-key-events": { "count": 1 @@ -1068,34 +1063,6 @@ "count": 1 } }, - "web/app/components/base/block-input/index.stories.tsx": { - "no-console": { - "count": 2 - }, - "ts/no-explicit-any": { - "count": 1 - } - }, - "web/app/components/base/block-input/index.tsx": { - "jsx-a11y/click-events-have-key-events": { - "count": 1 - }, - "jsx-a11y/no-static-element-interactions": { - "count": 1 - }, - "react-refresh/only-export-components": { - "count": 1 - }, - "react/no-nested-component-definitions": { - "count": 1 - }, - "react/set-state-in-effect": { - "count": 1 - }, - "react/static-components": { - "count": 2 - } - }, "web/app/components/base/carousel/index.tsx": { "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 @@ -1387,7 +1354,7 @@ }, "web/app/components/base/error-boundary/index.tsx": { "react-refresh/only-export-components": { - "count": 3 + "count": 1 }, "react/jsx-no-key-after-spread": { "count": 1 @@ -2610,11 +2577,6 @@ "count": 3 } }, - "web/app/components/datasets/common/retrieval-method-info/index.tsx": { - "react-refresh/only-export-components": { - "count": 1 - } - }, "web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/header.tsx": { "jsx-a11y/click-events-have-key-events": { "count": 1 @@ -3089,19 +3051,6 @@ "count": 1 } }, - "web/app/components/datasets/documents/detail/metadata/components/metadata-field-list.tsx": { - "ts/no-non-null-asserted-optional-chain": { - "count": 1 - } - }, - "web/app/components/datasets/documents/detail/metadata/hooks/use-metadata-state.ts": { - "react-hooks-extra/no-direct-set-state-in-use-effect": { - "count": 6 - }, - "react/set-state-in-effect": { - "count": 6 - } - }, "web/app/components/datasets/documents/detail/metadata/index.tsx": { "no-barrel-files/no-barrel-files": { "count": 1 @@ -5121,10 +5070,10 @@ }, "web/app/components/workflow/nodes/_base/components/layout/index.tsx": { "no-barrel-files/no-barrel-files": { - "count": 7 + "count": 6 }, "react-refresh/only-export-components": { - "count": 7 + "count": 6 } }, "web/app/components/workflow/nodes/_base/components/mcp-tool-availability.tsx": { @@ -5486,9 +5435,6 @@ "erasable-syntax-only/enums": { "count": 1 }, - "no-barrel-files/no-barrel-files": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } @@ -7177,11 +7123,6 @@ "count": 1 } }, - "web/service/__tests__/use-snippet-workflows.spec.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/service/__tests__/use-tools.spec.tsx": { "no-restricted-imports": { "count": 1 @@ -7286,7 +7227,7 @@ "count": 1 }, "ts/no-explicit-any": { - "count": 26 + "count": 13 } }, "web/service/datasets.ts": { @@ -7294,7 +7235,7 @@ "count": 1 }, "ts/no-explicit-any": { - "count": 6 + "count": 5 } }, "web/service/debug.ts": { diff --git a/web/__tests__/rag-pipeline/dsl-export-import-flow.test.ts b/web/__tests__/rag-pipeline/dsl-export-import-flow.test.ts deleted file mode 100644 index cc97065d8f8..00000000000 --- a/web/__tests__/rag-pipeline/dsl-export-import-flow.test.ts +++ /dev/null @@ -1,188 +0,0 @@ -/** - * Integration test: DSL export/import flow - * - * Validates DSL export logic (sync draft → check secrets → download) - * and DSL import modal state management. - */ -import { act, renderHook } from '@testing-library/react' -import { describe, expect, it, vi } from 'vitest' - -const mockDoSyncWorkflowDraft = vi.fn().mockResolvedValue(undefined) -const mockExportPipelineConfig = vi.fn().mockResolvedValue({ data: 'yaml-content' }) -const mockNotify = vi.fn() -const mockToast = { - success: (message: string, options?: Record) => mockNotify({ type: 'success', message, ...options }), - error: (message: string, options?: Record) => mockNotify({ type: 'error', message, ...options }), - warning: (message: string, options?: Record) => mockNotify({ type: 'warning', message, ...options }), - info: (message: string, options?: Record) => mockNotify({ type: 'info', message, ...options }), - dismiss: vi.fn(), - update: vi.fn(), - promise: vi.fn(), -} - -vi.mock('@langgenius/dify-ui/toast', () => ({ - toast: mockToast, -})) -const mockEventEmitter = { emit: vi.fn() } -const mockDownloadBlob = vi.fn() - -vi.mock('react-i18next', () => ({ - useTranslation: () => ({ - t: (key: string) => key, - }), -})) - -vi.mock('@/app/components/workflow/constants', () => ({ - DSL_EXPORT_CHECK: 'DSL_EXPORT_CHECK', -})) - -vi.mock('@/app/components/workflow/store', () => ({ - useWorkflowStore: () => ({ - getState: () => ({ - pipelineId: 'pipeline-abc', - knowledgeName: 'My Pipeline', - }), - }), -})) - -vi.mock('@/context/event-emitter', () => ({ - useEventEmitterContextContext: () => ({ - eventEmitter: mockEventEmitter, - }), -})) - -vi.mock('@/service/use-pipeline', () => ({ - useExportPipelineDSL: () => ({ - mutateAsync: mockExportPipelineConfig, - }), -})) - -vi.mock('@/service/workflow', () => ({ - fetchWorkflowDraft: vi.fn(), -})) - -vi.mock('@/utils/download', () => ({ - downloadBlob: (...args: unknown[]) => mockDownloadBlob(...args), -})) - -vi.mock('@/app/components/rag-pipeline/hooks/use-nodes-sync-draft', () => ({ - useNodesSyncDraft: () => ({ - doSyncWorkflowDraft: mockDoSyncWorkflowDraft, - }), -})) - -describe('DSL Export/Import Flow', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - - describe('Export Flow', () => { - it('should sync draft then export then download', async () => { - const { useDSL } = await import('@/app/components/rag-pipeline/hooks/use-DSL') - const { result } = renderHook(() => useDSL()) - - await act(async () => { - await result.current.handleExportDSL() - }) - - expect(mockDoSyncWorkflowDraft).toHaveBeenCalled() - expect(mockExportPipelineConfig).toHaveBeenCalledWith({ - pipelineId: 'pipeline-abc', - include: false, - }) - expect(mockDownloadBlob).toHaveBeenCalledWith(expect.objectContaining({ - fileName: 'My Pipeline.pipeline', - })) - }) - - it('should export with include flag when specified', async () => { - const { useDSL } = await import('@/app/components/rag-pipeline/hooks/use-DSL') - const { result } = renderHook(() => useDSL()) - - await act(async () => { - await result.current.handleExportDSL(true) - }) - - expect(mockExportPipelineConfig).toHaveBeenCalledWith({ - pipelineId: 'pipeline-abc', - include: true, - }) - }) - - it('should notify on export error', async () => { - mockDoSyncWorkflowDraft.mockRejectedValueOnce(new Error('sync failed')) - const { useDSL } = await import('@/app/components/rag-pipeline/hooks/use-DSL') - const { result } = renderHook(() => useDSL()) - - await act(async () => { - await result.current.handleExportDSL() - }) - - expect(mockNotify).toHaveBeenCalledWith(expect.objectContaining({ - type: 'error', - })) - }) - }) - - describe('Export Check Flow', () => { - it('should export directly when no secret environment variables', async () => { - const { fetchWorkflowDraft } = await import('@/service/workflow') - vi.mocked(fetchWorkflowDraft).mockResolvedValueOnce({ - environment_variables: [ - { value_type: 'string', key: 'API_URL', value: 'https://api.example.com' }, - ], - } as unknown as Awaited>) - - const { useDSL } = await import('@/app/components/rag-pipeline/hooks/use-DSL') - const { result } = renderHook(() => useDSL()) - - await act(async () => { - await result.current.exportCheck() - }) - - // Should proceed to export directly (no secret vars) - expect(mockDoSyncWorkflowDraft).toHaveBeenCalled() - }) - - it('should emit DSL_EXPORT_CHECK event when secret variables exist', async () => { - const { fetchWorkflowDraft } = await import('@/service/workflow') - vi.mocked(fetchWorkflowDraft).mockResolvedValueOnce({ - environment_variables: [ - { value_type: 'secret', key: 'API_KEY', value: '***' }, - ], - } as unknown as Awaited>) - - const { useDSL } = await import('@/app/components/rag-pipeline/hooks/use-DSL') - const { result } = renderHook(() => useDSL()) - - await act(async () => { - await result.current.exportCheck() - }) - - expect(mockEventEmitter.emit).toHaveBeenCalledWith(expect.objectContaining({ - type: 'DSL_EXPORT_CHECK', - payload: expect.objectContaining({ - data: expect.arrayContaining([ - expect.objectContaining({ value_type: 'secret' }), - ]), - }), - })) - }) - - it('should notify on export check error', async () => { - const { fetchWorkflowDraft } = await import('@/service/workflow') - vi.mocked(fetchWorkflowDraft).mockRejectedValueOnce(new Error('fetch failed')) - - const { useDSL } = await import('@/app/components/rag-pipeline/hooks/use-DSL') - const { result } = renderHook(() => useDSL()) - - await act(async () => { - await result.current.exportCheck() - }) - - expect(mockNotify).toHaveBeenCalledWith(expect.objectContaining({ - type: 'error', - })) - }) - }) -}) diff --git a/web/__tests__/xss-prevention.test.tsx b/web/__tests__/xss-prevention.test.tsx deleted file mode 100644 index 233cbebf0ee..00000000000 --- a/web/__tests__/xss-prevention.test.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/** - * XSS Prevention Test Suite - * - * This test verifies that the XSS vulnerability in block-input has been properly - * fixed by replacing dangerouslySetInnerHTML with safe React rendering. - */ - -import { cleanup, render } from '@testing-library/react' -import * as React from 'react' -import BlockInput from '../app/components/base/block-input' - -// Mock styles -vi.mock('../app/components/app/configuration/base/var-highlight/style.module.css', () => ({ - default: { - item: 'mock-item-class', - }, -})) - -describe('XSS Prevention - Block Input Security', () => { - afterEach(() => { - cleanup() - }) - - describe('BlockInput Component Security', () => { - it('should safely render malicious variable names without executing scripts', () => { - const testInput = 'user@test.com{{}}' - const { container } = render() - - const scriptElements = container.querySelectorAll('script') - expect(scriptElements).toHaveLength(0) - - const textContent = container.textContent - expect(textContent).toContain(''} - const { container } = render() - - const spanElement = container.querySelector('span') - const scriptElements = container.querySelectorAll('script') - - expect(spanElement?.textContent).toBe('') - expect(scriptElements).toHaveLength(0) - }) - }) -}) - -export {} diff --git a/web/app/components/app-sidebar/app-info/__tests__/index.spec.tsx b/web/app/components/app-sidebar/app-info/__tests__/index.spec.tsx deleted file mode 100644 index 573cdf02334..00000000000 --- a/web/app/components/app-sidebar/app-info/__tests__/index.spec.tsx +++ /dev/null @@ -1,168 +0,0 @@ -import type { App, AppSSO } from '@/types/app' -import { render, screen } from '@testing-library/react' -import userEvent from '@testing-library/user-event' -import * as React from 'react' -import { AppModeEnum } from '@/types/app' -import AppInfo from '..' - -const mockDetailPanel = vi.hoisted(() => vi.fn()) -const mockModals = vi.hoisted(() => vi.fn()) - -let mockAppPermissionKeys = ['app.acl.view_layout'] -const mockSetPanelOpen = vi.fn() - -vi.mock('@/context/app-context', () => ({ - useAppContext: () => ({ - workspacePermissionKeys: ['app.create_and_management'], - }), - useSelector: (selector: (state: { userProfile: { id: string }, workspacePermissionKeys: string[] }) => unknown) => selector({ - userProfile: { id: 'user-1' }, - workspacePermissionKeys: ['app.create_and_management'], - }), -})) - -vi.mock('../app-info-trigger', () => ({ - default: React.memo(({ appDetail, expand, onClick }: { - appDetail: App & Partial - expand: boolean - onClick: () => void - }) => ( - - )), -})) - -vi.mock('../app-info-detail-panel', () => ({ - default: React.memo((props: { show: boolean, onClose: () => void }) => { - mockDetailPanel(props) - return props.show ?
: null - }), -})) - -vi.mock('../app-info-modals', () => ({ - default: React.memo((props: { activeModal: string | null }) => { - mockModals(props) - return props.activeModal ?
: null - }), -})) - -const mockAppDetail: App & Partial = { - id: 'app-1', - name: 'Test App', - mode: AppModeEnum.CHAT, - icon: '🤖', - icon_type: 'emoji', - icon_background: '#FFEAD5', - icon_url: '', - description: '', - use_icon_as_answer_icon: false, - permission_keys: mockAppPermissionKeys, -} as App & Partial - -const mockUseAppInfoActions = { - appDetail: mockAppDetail, - panelOpen: false, - setPanelOpen: mockSetPanelOpen, - closePanel: vi.fn(), - activeModal: null as string | null, - openModal: vi.fn(), - closeModal: vi.fn(), - secretEnvList: [], - setSecretEnvList: vi.fn(), - onEdit: vi.fn(), - onCopy: vi.fn(), - onExport: vi.fn(), - exportCheck: vi.fn(), - handleConfirmExport: vi.fn(), - onConfirmDelete: vi.fn(), -} - -vi.mock('../use-app-info-actions', () => ({ - useAppInfoActions: () => mockUseAppInfoActions, -})) - -describe('AppInfo', () => { - beforeEach(() => { - vi.clearAllMocks() - mockAppPermissionKeys = ['app.acl.view_layout'] - mockUseAppInfoActions.appDetail = mockAppDetail - mockUseAppInfoActions.appDetail.permission_keys = mockAppPermissionKeys - mockUseAppInfoActions.panelOpen = false - mockUseAppInfoActions.activeModal = null - }) - - it('should return null when appDetail is not available', () => { - mockUseAppInfoActions.appDetail = undefined as unknown as App & Partial - const { container } = render() - expect(container.innerHTML).toBe('') - }) - - it('should render trigger when not onlyShowDetail', () => { - render() - expect(screen.getByTestId('trigger'))!.toBeInTheDocument() - }) - - it('should not mount detail layer while the app info panel is closed', () => { - render() - expect(mockDetailPanel).not.toHaveBeenCalled() - expect(mockModals).not.toHaveBeenCalled() - }) - - it('should not render trigger when onlyShowDetail is true', () => { - render() - expect(screen.queryByTestId('trigger')).not.toBeInTheDocument() - }) - - it('should pass expand prop to trigger', () => { - render() - expect(screen.getByTestId('trigger'))!.toHaveAttribute('data-expand', 'true') - - const { unmount } = render() - const triggers = screen.getAllByTestId('trigger') - expect(triggers[triggers.length - 1])!.toHaveAttribute('data-expand', 'false') - unmount() - }) - - it('should toggle panel when trigger is clicked and user is editor', async () => { - const user = userEvent.setup() - render() - - await user.click(screen.getByTestId('trigger')) - - expect(mockSetPanelOpen).toHaveBeenCalled() - const updater = mockSetPanelOpen.mock.calls[0]![0] as (v: boolean) => boolean - expect(updater(false)).toBe(true) - expect(updater(true)).toBe(false) - }) - - it('should not toggle panel when app ACL does not allow layout access', async () => { - const user = userEvent.setup() - mockAppPermissionKeys = [] - mockUseAppInfoActions.appDetail.permission_keys = mockAppPermissionKeys - render() - - await user.click(screen.getByTestId('trigger')) - - expect(mockSetPanelOpen).not.toHaveBeenCalled() - }) - - it('should show detail panel based on panelOpen when not onlyShowDetail', () => { - mockUseAppInfoActions.panelOpen = true - render() - expect(screen.getByTestId('detail-panel'))!.toBeInTheDocument() - expect(mockDetailPanel).toHaveBeenCalled() - }) - - it('should show detail panel based on openState when onlyShowDetail', () => { - render() - expect(screen.getByTestId('detail-panel'))!.toBeInTheDocument() - }) - - it('should hide detail panel when openState is false and onlyShowDetail', () => { - render() - expect(screen.queryByTestId('detail-panel')).not.toBeInTheDocument() - expect(mockDetailPanel).not.toHaveBeenCalled() - expect(mockModals).not.toHaveBeenCalled() - }) -}) diff --git a/web/app/components/app-sidebar/app-info/index.tsx b/web/app/components/app-sidebar/app-info/index.tsx index f08c1f12ed8..ea1665d0dbd 100644 --- a/web/app/components/app-sidebar/app-info/index.tsx +++ b/web/app/components/app-sidebar/app-info/index.tsx @@ -5,7 +5,6 @@ import { getAppACLCapabilities } from '@/utils/permission' import AppInfoDetailPanel from './app-info-detail-panel' import AppInfoModals from './app-info-modals' import AppInfoTrigger from './app-info-trigger' -import { useAppInfoActions } from './use-app-info-actions' type IAppInfoProps = { expand: boolean @@ -122,16 +121,3 @@ export const AppInfoView = ({
) } - -const AppInfo = ({ onDetailExpand, ...props }: IAppInfoProps) => { - const actions = useAppInfoActions({ onDetailExpand }) - - return ( - - ) -} - -export default React.memo(AppInfo) diff --git a/web/app/components/app/configuration/base/var-highlight/__tests__/index.spec.tsx b/web/app/components/app/configuration/base/var-highlight/__tests__/index.spec.tsx index 1add8601c40..e60576004b3 100644 --- a/web/app/components/app/configuration/base/var-highlight/__tests__/index.spec.tsx +++ b/web/app/components/app/configuration/base/var-highlight/__tests__/index.spec.tsx @@ -1,5 +1,5 @@ import { render, screen } from '@testing-library/react' -import VarHighlight, { varHighlightHTML } from '../index' +import VarHighlight from '../index' describe('VarHighlight', () => { beforeEach(() => { @@ -35,32 +35,4 @@ describe('VarHighlight', () => { expect(container.firstChild).toHaveClass('mt-2') }) }) - - // Escaping HTML via helper - describe('varHighlightHTML', () => { - it('should escape dangerous characters before returning HTML string', () => { - // Arrange - const props = { name: '' } - - // Act - const html = varHighlightHTML(props) - - // Assert - expect(html).toContain('<script>alert('xss')</script>') - expect(html).not.toContain('')).not.toContain('