From 03e227f8f1f1819ab209507d05d02fddfab66def Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Wed, 6 May 2026 14:20:28 +0800 Subject: [PATCH] fix(web): align Tailwind v4 CSS migration (#35829) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- eslint-suppressions.json | 10 - .../__tests__/app-info-modals.spec.tsx | 6 + .../__tests__/app-operations.spec.tsx | 15 ++ .../app-sidebar/app-info/app-info-modals.tsx | 91 ++++++--- .../app-sidebar/app-info/app-operations.tsx | 8 +- .../specific-groups-or-members.tsx | 2 +- .../config/agent/agent-setting/index.tsx | 2 +- .../app/configuration/configuration-view.tsx | 14 +- .../dataset-config/select-dataset/index.tsx | 183 +++++++++--------- .../base/app-icon-picker/ImageInput.tsx | 2 +- .../base/chat/chat/chat-input-area/index.tsx | 2 +- .../file-image-item.tsx | 2 +- web/app/components/base/tag-input/index.tsx | 2 +- .../components/base/tag-management/index.tsx | 2 +- .../base/tag-management/tag-item-editor.tsx | 2 +- web/app/components/base/tag/index.tsx | 2 +- .../billing/header-billing-btn/index.tsx | 2 +- .../datasets/documents/style.module.css | 2 +- .../create/ExternalApiSelect.tsx | 2 +- .../invited-modal/invitation-link.tsx | 2 +- .../header/nav/nav-selector/index.tsx | 2 +- .../workflow/comment/mention-input.tsx | 2 +- .../workflow/dsl-export-confirm-modal.tsx | 160 ++++++++------- .../object-child-tree-panel/picker/field.tsx | 2 +- .../variable/var-reference-vars.tsx | 2 +- .../components/add-dataset.tsx | 25 +-- .../workflow/run/status-container.tsx | 2 +- web/app/styles/tailwind-core.css | 15 +- 28 files changed, 310 insertions(+), 253 deletions(-) diff --git a/eslint-suppressions.json b/eslint-suppressions.json index 6ff584e4e9..79ae57e414 100644 --- a/eslint-suppressions.json +++ b/eslint-suppressions.json @@ -438,11 +438,6 @@ "count": 1 } }, - "web/app/components/app/configuration/dataset-config/select-dataset/index.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/app/configuration/dataset-config/settings-modal/index.tsx": { "react/set-state-in-effect": { "count": 2 @@ -3567,11 +3562,6 @@ "count": 1 } }, - "web/app/components/workflow/dsl-export-confirm-modal.tsx": { - "no-restricted-imports": { - "count": 1 - } - }, "web/app/components/workflow/header/run-mode.tsx": { "no-console": { "count": 1 diff --git a/web/app/components/app-sidebar/app-info/__tests__/app-info-modals.spec.tsx b/web/app/components/app-sidebar/app-info/__tests__/app-info-modals.spec.tsx index 2fdd35cc43..218d4b94e6 100644 --- a/web/app/components/app-sidebar/app-info/__tests__/app-info-modals.spec.tsx +++ b/web/app/components/app-sidebar/app-info/__tests__/app-info-modals.spec.tsx @@ -46,6 +46,12 @@ vi.mock('@/app/components/workflow/update-dsl-modal', () => ({ })) vi.mock('@/app/components/workflow/dsl-export-confirm-modal', () => ({ + DSLExportConfirmContent: ({ onConfirm, onClose }: { onConfirm: (include?: boolean) => void, onClose: () => void }) => ( +
+ + +
+ ), default: ({ onConfirm, onClose }: { onConfirm: (include?: boolean) => void, onClose: () => void }) => (
diff --git a/web/app/components/app-sidebar/app-info/__tests__/app-operations.spec.tsx b/web/app/components/app-sidebar/app-info/__tests__/app-operations.spec.tsx index ff6aed2c71..5daf0c7100 100644 --- a/web/app/components/app-sidebar/app-info/__tests__/app-operations.spec.tsx +++ b/web/app/components/app-sidebar/app-info/__tests__/app-operations.spec.tsx @@ -228,6 +228,21 @@ describe('AppOperations', () => { }) describe('Visible operations click', () => { + it('should keep focus ring inside visible operation buttons', () => { + const cleanup = setupDomMeasurements(500, 60, [80]) + const editOp = createOperation('edit', 'Edit') + + render() + + const visibleButton = screen.getAllByText('Edit') + .map(label => label.closest('button')) + .find(button => button?.tabIndex !== -1) + + expect(visibleButton).toHaveClass('focus-visible:ring-inset') + + cleanup() + }) + it('should call onClick when a visible operation is clicked', async () => { const cleanup = setupDomMeasurements(500, 60, [80, 80]) const user = userEvent.setup() diff --git a/web/app/components/app-sidebar/app-info/app-info-modals.tsx b/web/app/components/app-sidebar/app-info/app-info-modals.tsx index 9535725cd3..e1ed1d62ef 100644 --- a/web/app/components/app-sidebar/app-info/app-info-modals.tsx +++ b/web/app/components/app-sidebar/app-info/app-info-modals.tsx @@ -16,13 +16,13 @@ import * as React from 'react' import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import Input from '@/app/components/base/input' +import { DSLExportConfirmContent } from '@/app/components/workflow/dsl-export-confirm-modal' import dynamic from '@/next/dynamic' const SwitchAppModal = dynamic(() => import('@/app/components/app/switch-app-modal'), { ssr: false }) const CreateAppModal = dynamic(() => import('@/app/components/explore/create-app-modal'), { ssr: false }) const DuplicateAppModal = dynamic(() => import('@/app/components/app/duplicate-modal'), { ssr: false }) const UpdateDSLModal = dynamic(() => import('@/app/components/workflow/update-dsl-modal'), { ssr: false }) -const DSLExportConfirmModal = dynamic(() => import('@/app/components/workflow/dsl-export-confirm-modal'), { ssr: false }) type AppInfoModalsProps = { appDetail: App & Partial @@ -54,7 +54,14 @@ const AppInfoModals = ({ const { t } = useTranslation() const [confirmDeleteInput, setConfirmDeleteInput] = useState('') const [isConfirmingExport, setIsConfirmingExport] = useState(false) + const [isSecretExporting, setIsSecretExporting] = useState(false) const isDeleteConfirmDisabled = confirmDeleteInput !== appDetail.name + const exportDialogMode = secretEnvList.length > 0 + ? 'secret' + : activeModal === 'exportWarning' + ? 'warning' + : null + const isExportDialogOpen = exportDialogMode !== null const handleDeleteDialogClose = () => { setConfirmDeleteInput('') @@ -74,6 +81,22 @@ const AppInfoModals = ({ } }, [handleConfirmExport, isConfirmingExport]) + const handleExportDialogClose = useCallback(() => { + if (exportDialogMode === 'secret') { + setSecretEnvList([]) + return + } + + closeModal() + }, [closeModal, exportDialogMode, setSecretEnvList]) + + const handleExportDialogOpenChange = useCallback((open: boolean) => { + if (open || isConfirmingExport || isSecretExporting) + return + + handleExportDialogClose() + }, [handleExportDialogClose, isConfirmingExport, isSecretExporting]) + return ( <> {activeModal === 'switch' && ( @@ -163,38 +186,42 @@ const AppInfoModals = ({ onBackup={exportCheck} /> )} - !open && closeModal()}> - -
- - {t('sidebar.exportWarning', { ns: 'workflow' })} - - - {t('sidebar.exportWarningDesc', { ns: 'workflow' })} - -
- - {t('operation.cancel', { ns: 'common' })} - - {isConfirmingExport - ? t('operation.exporting', { ns: 'common' }) - : t('operation.confirm', { ns: 'common' })} - - -
+ + {exportDialogMode === 'secret' + ? ( + setSecretEnvList([])} + onExportingChange={setIsSecretExporting} + /> + ) + : exportDialogMode === 'warning' && ( + +
+ + {t('sidebar.exportWarning', { ns: 'workflow' })} + + + {t('sidebar.exportWarningDesc', { ns: 'workflow' })} + +
+ + {t('operation.cancel', { ns: 'common' })} + + {isConfirmingExport + ? t('operation.exporting', { ns: 'common' }) + : t('operation.confirm', { ns: 'common' })} + + +
+ )}
- {secretEnvList.length > 0 && ( - setSecretEnvList([])} - /> - )} ) } diff --git a/web/app/components/app-sidebar/app-info/app-operations.tsx b/web/app/components/app-sidebar/app-info/app-operations.tsx index cc6afd739c..2e3270a222 100644 --- a/web/app/components/app-sidebar/app-info/app-operations.tsx +++ b/web/app/components/app-sidebar/app-info/app-operations.tsx @@ -133,7 +133,7 @@ const AppOperations = ({ data-targetid={operation.id} size="small" variant="secondary" - className="gap-px" + className="gap-px focus-visible:ring-inset" tabIndex={-1} > {cloneElement(operation.icon, { className: 'h-3.5 w-3.5 text-components-button-secondary-text' })} @@ -146,7 +146,7 @@ const AppOperations = ({ id="more-measure" size="small" variant="secondary" - className="gap-px" + className="gap-px focus-visible:ring-inset" tabIndex={-1} > @@ -162,7 +162,7 @@ const AppOperations = ({ data-targetid={operation.id} size="small" variant="secondary" - className="gap-px" + className="gap-px focus-visible:ring-inset" onClick={operation.onClick} > {cloneElement(operation.icon, { className: 'h-3.5 w-3.5 text-components-button-secondary-text' })} @@ -178,7 +178,7 @@ const AppOperations = ({ + ))} + {isFetchingNextPage && } +
+ + )} + {!isLoading && ( +
+
+ {selected.length > 0 && `${selected.length} ${t('feature.dataSet.selected', { ns: 'appDebug' })}`} +
+
+ + +
- - )} - {!isLoading && ( -
-
- {selected.length > 0 && `${selected.length} ${t('feature.dataSet.selected', { ns: 'appDebug' })}`} -
-
- - -
-
- )} - + )} + + ) } export default React.memo(SelectDataSet) diff --git a/web/app/components/base/app-icon-picker/ImageInput.tsx b/web/app/components/base/app-icon-picker/ImageInput.tsx index 92a3f8a9f6..fddee6d58a 100644 --- a/web/app/components/base/app-icon-picker/ImageInput.tsx +++ b/web/app/components/base/app-icon-picker/ImageInput.tsx @@ -95,7 +95,7 @@ const ImageInput: FC = ({ return (
{query}
-