diff --git a/designer/client/cypress/e2e/testCases.cy.ts b/designer/client/cypress/e2e/testCases.cy.ts index 8376f0d0173..eb908635e7c 100644 --- a/designer/client/cypress/e2e/testCases.cy.ts +++ b/designer/client/cypress/e2e/testCases.cy.ts @@ -262,6 +262,22 @@ const openEditNameInput = () => { cy.get('[data-testid="edit-test-case-name"]').click(); }; +const openEditNameInput = () => { + cy.get('[data-testid="edit-test-case-name"]').click(); +}; + +const clickDeleteTestCase = () => { + cy.get('[data-testid="delete-test-case"]').click(); +}; + +const confirmDeleteTestCase = () => { + cy.get('[data-testid="confirm-delete-test-case"]').click(); +}; + +const cancelDeleteTestCase = () => { + cy.get('[data-testid="cancel-delete-test-case"]').click(); +}; + const expandAssertionItem = (nodeId: string) => { cy.get(`[id="${nodeId}-header"]`).find('[data-testid="ExpandMoreIcon"]').click(); }; diff --git a/designer/client/src/actions/nk/testCasesActions.ts b/designer/client/src/actions/nk/testCasesActions.ts index e0f9896e87b..49699e1834f 100644 --- a/designer/client/src/actions/nk/testCasesActions.ts +++ b/designer/client/src/actions/nk/testCasesActions.ts @@ -2,7 +2,13 @@ import type { WithUuid } from "../../components/graph/node-modal/appendUuid"; import type { ExpressionObj } from "../../components/graph/node-modal/editors/expression/types"; import type { TestingDataRecords } from "../../components/modals/TestingDataRecords/Table"; import type { TestCase } from "../../reducers/graph/testCase"; -import { getTestCaseAssertions, getTestCaseAssertionsForNode, getTestData, getTestCaseMocks } from "../../reducers/selectors/testCases"; +import { + getTestCaseAssertions, + getTestCaseAssertionsForNode, + getTestCases, + getTestData, + getTestCaseMocks, +} from "../../reducers/selectors/testCases"; import { getActiveTestCaseId } from "../../reducers/selectors/testing"; import type { ThunkAction } from "../reduxTypes"; import { changeActiveTestCase } from "./testingActions"; @@ -25,7 +31,8 @@ export type Mocks = Record; export type TestCasesActions = | { type: "UPDATE_TEST_CASE"; testCaseId: string; updates: Omit, "id"> } - | { type: "ADD_TEST_CASE"; testCase: TestCase }; + | { type: "ADD_TEST_CASE"; testCase: TestCase } + | { type: "REMOVE_TEST_CASE"; testCaseId: string }; export function setTestCaseAssertions(nodeId: string, updater: (prev: WithUuid[]) => WithUuid[]): ThunkAction { return (dispatch, getState) => { @@ -101,3 +108,18 @@ export function addTestCase(testCase: TestCase): ThunkAction { dispatch(changeActiveTestCase(testCase.id)); }; } + +export function removeTestCase(testCaseId: string): ThunkAction { + return (dispatch, getState) => { + const testCases = getTestCases(getState()); + const deletedIndex = testCases.findIndex((tc) => tc.id === testCaseId); + const remaining = testCases.filter((tc) => tc.id !== testCaseId); + const nextActive = remaining[deletedIndex] ?? remaining[deletedIndex - 1]; + + dispatch({ type: "REMOVE_TEST_CASE", testCaseId }); + + if (nextActive) { + dispatch(changeActiveTestCase(nextActive.id)); + } + }; +} diff --git a/designer/client/src/components/graph/node-modal/node/NodeContent/TestingContentElements/TestCaseSelect.tsx b/designer/client/src/components/graph/node-modal/node/NodeContent/TestingContentElements/TestCaseSelect.tsx index 814de8fb732..7e3b3545fc8 100644 --- a/designer/client/src/components/graph/node-modal/node/NodeContent/TestingContentElements/TestCaseSelect.tsx +++ b/designer/client/src/components/graph/node-modal/node/NodeContent/TestingContentElements/TestCaseSelect.tsx @@ -1,5 +1,5 @@ -import { EditOutlined } from "@mui/icons-material"; -import { Box, FormHelperText, InputBase, styled, Typography } from "@mui/material"; +import { CheckOutlined, CloseOutlined, DeleteOutlined, EditOutlined } from "@mui/icons-material"; +import { Box, Divider, FormHelperText, InputBase, styled, Typography } from "@mui/material"; import React, { useCallback } from "react"; import { useTranslation } from "react-i18next"; @@ -13,6 +13,7 @@ import { WindowKind } from "../../../../../../windowManager/WindowKind"; import { StyledButton } from "../../../../styledButton"; import { InfoTooltip } from "../../../editors/InfoTooltip/InfoTooltip"; import { TypeSelect } from "../../../fragment-input-definition/TypeSelect"; +import { useTestCaseDelete } from "./useTestCaseDelete"; import { useTestCaseNameEdit } from "./useTestCaseNameEdit"; export const TestCaseSelect = () => { @@ -27,6 +28,15 @@ export const TestCaseSelect = () => { activeTestCaseOption?.label, ); + const { + isConfirming, + isDisabled: isDeleteDisabled, + disabledTooltip, + startDeleting, + cancelDelete, + confirmDelete, + } = useTestCaseDelete(activeTestCaseOption?.value, testCaseOptions.length, isEditing); + const { open } = useWindows(); const onDisplayEnterpriseInfo = useCallback(() => { open({ kind: WindowKind.enterpriseFeatureInfo, layoutData: { width: 500 } }); @@ -58,16 +68,45 @@ export const TestCaseSelect = () => { /> {loggedUser.isWriter() && ( <> - - - - - + {isConfirming ? ( + <> + + + + + + + + + + + + ) : ( + <> + + + + + + + + + + + + + + )} + { + const { t } = useTranslation(); + const dispatch = useAppDispatch(); + + const [isConfirming, setIsConfirming] = useState(false); + + const isOnlyOne = testCasesCount <= 1; + const isDisabled = isOnlyOne || isEditing; + + const disabledTooltip = isEditing + ? t("testCaseDelete.disabledEditing", "Finish editing before deleting") + : isOnlyOne + ? t("testCaseDelete.disabledOnlyOne", "Cannot delete the only test case") + : undefined; + + const startDeleting = useCallback(() => setIsConfirming(true), []); + + const cancelDelete = useCallback(() => setIsConfirming(false), []); + + const confirmDelete = useCallback(() => { + if (!activeTestCaseId) return; + dispatch(removeTestCase(activeTestCaseId)); + setIsConfirming(false); + }, [dispatch, activeTestCaseId]); + + return { isConfirming, isDisabled, disabledTooltip, startDeleting, cancelDelete, confirmDelete }; +}; diff --git a/designer/client/src/components/graph/styledButton.ts b/designer/client/src/components/graph/styledButton.ts index b6e82b7da94..909e8b3c186 100644 --- a/designer/client/src/components/graph/styledButton.ts +++ b/designer/client/src/components/graph/styledButton.ts @@ -29,6 +29,9 @@ export const StyledButton = styled(Button)(({ theme }) => height: 35, fontWeight: "bold", fontSize: 20, + display: "flex", + justifyContent: "center", + alignItems: "center", }, ]), ); diff --git a/designer/client/src/reducers/graph/testCase.ts b/designer/client/src/reducers/graph/testCase.ts index 3556a79974e..d9490076490 100644 --- a/designer/client/src/reducers/graph/testCase.ts +++ b/designer/client/src/reducers/graph/testCase.ts @@ -43,6 +43,11 @@ export const testCaseReducer: Reducer = produce((dra break; } + case "REMOVE_TEST_CASE": { + draft.list = draft.list.filter((tc) => tc.id !== action.testCaseId); + break; + } + case "DELETE_NODES": draft.list = cleanTestCaseState(draft, action.ids); break;