Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Warn users when trying to delete a container #1062

Merged
merged 1 commit into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/ui-tests/cypress/support/next-commands/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,11 @@ Cypress.Commands.add('deleteRoute', (index: number) => {
cy.get('button[data-testid^="delete-btn-route"]').then((buttons) => {
cy.wrap(buttons[index]).click();
});
cy.get('body').then(($body) => {
if ($body.find('.pf-m-danger').length) {
// Delete Confirmation Modal appeared, click on the confirm button
cy.get('.pf-m-danger').click();
}
});
cy.closeFlowsListIfVisible();
});
6 changes: 6 additions & 0 deletions packages/ui-tests/cypress/support/next-commands/design.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ Cypress.Commands.add('checkConfigInputObject', (inputName: string, value: string

Cypress.Commands.add('removeNodeByName', (nodeName: string, nodeIndex?: number) => {
cy.performNodeAction(nodeName, 'delete', nodeIndex);
cy.get('body').then(($body) => {
if ($body.find('.pf-m-danger').length) {
// Delete Confirmation Modal appeared, click on the confirm button
cy.get('.pf-m-danger').click();
}
});
cy.get(nodeName).should('not.exist');
// wait for the canvas rerender
cy.wait(1000);
Expand Down
33 changes: 27 additions & 6 deletions packages/ui/src/components/Visualization/Canvas/Canvas.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { TestProvidersWrapper } from '../../../stubs';
import { camelRouteJson } from '../../../stubs/camel-route';
import { kameletJson } from '../../../stubs/kamelet-route';
import { Canvas } from './Canvas';
import { DeleteModalContextProvider } from '../../../providers';

describe('Canvas', () => {
const entity = new CamelRouteVisualEntity(camelRouteJson);
Expand Down Expand Up @@ -56,9 +57,11 @@ describe('Canvas', () => {
} as unknown as VisibleFLowsContextResult,
});
const wrapper = render(
<Provider>
<Canvas entities={routeEntities} />
</Provider>,
<DeleteModalContextProvider>
<Provider>
<Canvas entities={routeEntities} />
</Provider>
</DeleteModalContextProvider>,
);

// Right click anywhere on the container label
Expand All @@ -75,6 +78,14 @@ describe('Canvas', () => {
fireEvent.click(deleteRoute);
});

// Deal with the Confirmation modal
const deleteConfirmation = screen.getByRole('button', { name: 'Confirm' });
expect(deleteConfirmation).toBeInTheDocument();

await act(async () => {
fireEvent.click(deleteConfirmation);
});

// Check if the remove function is called
expect(removeSpy).toHaveBeenCalled();
expect(removeSpy).toHaveBeenCalledWith('route-8888');
Expand All @@ -93,9 +104,11 @@ describe('Canvas', () => {
});

const wrapper = render(
<Provider>
<Canvas entities={kameletEntities} />
</Provider>,
<DeleteModalContextProvider>
<Provider>
<Canvas entities={kameletEntities} />
</Provider>
</DeleteModalContextProvider>,
);

// Right click anywhere on the container label
Expand All @@ -113,6 +126,14 @@ describe('Canvas', () => {
fireEvent.click(deleteKamelet);
});

// Deal with the Confirmation modal
const deleteConfirmation = screen.getByRole('button', { name: 'Confirm' });
expect(deleteConfirmation).toBeInTheDocument();

await act(async () => {
fireEvent.click(deleteConfirmation);
});

// Check if the remove function is called
expect(removeSpy).toHaveBeenCalled();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Table, Tbody, Td, Th, Thead, Tr } from '@patternfly/react-table';
import { FunctionComponent, useCallback, useContext, useRef } from 'react';
import { BaseVisualCamelEntity } from '../../../../models/visualization/base-visual-entity';
import { EntitiesContext } from '../../../../providers/entities.provider';
import { DeleteModalContext } from '../../../../providers/delete-modal.provider';
import { VisibleFlowsContext } from '../../../../providers/visible-flows.provider';
import { InlineEdit } from '../../../InlineEdit';
import './FlowsList.scss';
Expand All @@ -18,6 +19,7 @@ interface IFlowsList {
export const FlowsList: FunctionComponent<IFlowsList> = (props) => {
const { visualEntities, camelResource, updateEntitiesFromCamelResource } = useContext(EntitiesContext)!;
const { visibleFlows, visualFlowsApi } = useContext(VisibleFlowsContext)!;
const deleteModalContext = useContext(DeleteModalContext);

const isListEmpty = visualEntities.length === 0;

Expand Down Expand Up @@ -102,7 +104,14 @@ export const FlowsList: FunctionComponent<IFlowsList> = (props) => {
data-testid={`delete-btn-${flow.id}`}
icon={<TrashIcon />}
variant="plain"
onClick={(event) => {
onClick={async (event) => {
const isDeleteConfirmed = await deleteModalContext?.deleteConfirmation({
title: 'Permanently delete flow?',
text: 'All steps will be lost.',
});

if (!isDeleteConfirmed) return;

camelResource.removeEntity(flow.id);
updateEntitiesFromCamelResource();
/** Required to avoid closing the Dropdown after clicking in the icon */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,15 @@ export const CustomNodeWithSelection: typeof DefaultNode = withSelection()(
}

if (nodeInteractions.canRemoveStep) {
const childrenNodes = vizNode.getChildren();
const shouldConfirmBeforeDeletion = childrenNodes !== undefined && childrenNodes.length > 0;
items.push(
<ItemDeleteStep key="context-menu-item-delete" data-testid="context-menu-item-delete" vizNode={vizNode} />,
<ItemDeleteStep
key="context-menu-item-delete"
data-testid="context-menu-item-delete"
vizNode={vizNode}
loadModal={shouldConfirmBeforeDeletion}
/>,
);
}
if (nodeInteractions.canRemoveFlow) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ContextMenuItem } from '@patternfly/react-topology';
import { FunctionComponent, PropsWithChildren, useCallback, useContext } from 'react';
import { IDataTestID } from '../../../models';
import { IVisualizationNode } from '../../../models/visualization/base-visual-entity';
import { DeleteModalContext } from '../../../providers/delete-modal.provider';
import { EntitiesContext } from '../../../providers/entities.provider';

interface ItemDeleteGroupProps extends PropsWithChildren<IDataTestID> {
Expand All @@ -11,12 +12,21 @@ interface ItemDeleteGroupProps extends PropsWithChildren<IDataTestID> {

export const ItemDeleteGroup: FunctionComponent<ItemDeleteGroupProps> = (props) => {
const entitiesContext = useContext(EntitiesContext);
const deleteModalContext = useContext(DeleteModalContext);
const flowId = props.vizNode?.getBaseEntity()?.getId();

const onRemoveGroup = useCallback(() => {
const onRemoveGroup = useCallback(async () => {
/** Open delete confirm modal, get the confirmation */
const isDeleteConfirmed = await deleteModalContext?.deleteConfirmation({
title: 'Permanently delete flow?',
text: 'All steps will be lost.',
});

if (!isDeleteConfirmed) return;

entitiesContext?.camelResource.removeEntity(flowId);
entitiesContext?.updateEntitiesFromCamelResource();
}, [entitiesContext, flowId]);
}, [deleteModalContext, entitiesContext, flowId]);

return (
<ContextMenuItem onClick={onRemoveGroup} data-testid={props['data-testid']}>
Expand Down
17 changes: 15 additions & 2 deletions packages/ui/src/components/Visualization/Custom/ItemDeleteStep.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,31 @@ import { FunctionComponent, PropsWithChildren, useCallback, useContext } from 'r
import { IDataTestID } from '../../../models';
import { IVisualizationNode } from '../../../models/visualization/base-visual-entity';
import { EntitiesContext } from '../../../providers/entities.provider';
import { DeleteModalContext } from '../../../providers/delete-modal.provider';

interface ItemDeleteStepProps extends PropsWithChildren<IDataTestID> {
vizNode: IVisualizationNode;
loadModal: boolean;
}

export const ItemDeleteStep: FunctionComponent<ItemDeleteStepProps> = (props) => {
const entitiesContext = useContext(EntitiesContext);
const deleteModalContext = useContext(DeleteModalContext);

const onRemoveNode = useCallback(async () => {
if (props.loadModal) {
/** Open delete confirm modal, get the confirmation */
const isDeleteConfirmed = await deleteModalContext?.deleteConfirmation({
title: 'Permanently delete step?',
text: 'Step and its children will be lost.',
});

if (!isDeleteConfirmed) return;
}

const onRemoveNode = useCallback(() => {
props.vizNode?.removeChild();
entitiesContext?.updateEntitiesFromCamelResource();
}, [entitiesContext, props.vizNode]);
}, [deleteModalContext, entitiesContext, props.loadModal, props.vizNode]);

return (
<ContextMenuItem onClick={onRemoveNode} data-testid={props['data-testid']}>
Expand Down
5 changes: 4 additions & 1 deletion packages/ui/src/multiplying-architecture/KaotoBridge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { CatalogLoaderProvider } from '../providers/catalog.provider';
import { SchemasLoaderProvider } from '../providers/schemas.provider';
import { SourceCodeApiContext } from '../providers/source-code.provider';
import { VisibleFlowsProvider } from '../providers/visible-flows.provider';
import { DeleteModalContextProvider } from '../providers/delete-modal.provider';
import { EventNotifier } from '../utils';

interface KaotoBridgeProps {
Expand Down Expand Up @@ -144,7 +145,9 @@ export const KaotoBridge = forwardRef<EditorApi, PropsWithChildren<KaotoBridgePr
<CatalogLoaderProvider catalogUrl={props.catalogUrl}>
<CatalogTilesProvider>
<VisibleFlowsProvider>
<CatalogModalProvider>{props.children}</CatalogModalProvider>
<CatalogModalProvider>
<DeleteModalContextProvider>{props.children}</DeleteModalContextProvider>
</CatalogModalProvider>
</VisibleFlowsProvider>
</CatalogTilesProvider>
</CatalogLoaderProvider>
Expand Down
13 changes: 8 additions & 5 deletions packages/ui/src/pages/Design/DesignPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CatalogModalProvider } from '../../providers/catalog-modal.provider';
import { EntitiesContext } from '../../providers/entities.provider';
import './DesignPage.scss';
import { ReturnToSourceCodeFallback } from './ReturnToSourceCodeFallback';
import { DeleteModalContextProvider } from '../../providers/delete-modal.provider';

export const DesignPage: FunctionComponent = () => {
const entitiesContext = useContext(EntitiesContext);
Expand All @@ -12,11 +13,13 @@ export const DesignPage: FunctionComponent = () => {
return (
<div className="canvas-page">
<CatalogModalProvider>
<Visualization
className="canvas-page__canvas"
entities={visualEntities}
fallback={<ReturnToSourceCodeFallback />}
/>
<DeleteModalContextProvider>
<Visualization
className="canvas-page__canvas"
entities={visualEntities}
fallback={<ReturnToSourceCodeFallback />}
/>
</DeleteModalContextProvider>
</CatalogModalProvider>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`DeleteModalProvider should allow consumers to update the modal title and text 1`] = `
<div
aria-describedby="pf-modal-part-4"
aria-labelledby="pf-modal-part-3"
aria-modal="true"
class="pf-v5-c-modal-box pf-m-warning pf-m-sm"
data-ouia-component-id="DeleteConfirmModal"
data-ouia-component-type="PF5/ModalContent"
data-ouia-safe="true"
id="pf-modal-part-2"
role="dialog"
>
<div
class="pf-v5-c-modal-box__close"
>
<button
aria-disabled="false"
aria-label="Close"
class="pf-v5-c-button pf-m-plain"
data-ouia-component-id="DeleteConfirmModal-ModalBoxCloseButton"
data-ouia-component-type="PF5/Button"
data-ouia-safe="true"
type="button"
>
<svg
aria-hidden="true"
class="pf-v5-svg"
fill="currentColor"
height="1em"
role="img"
viewBox="0 0 352 512"
width="1em"
>
<path
d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
/>
</svg>
</button>
</div>
<header
class="pf-v5-c-modal-box__header"
>
<h1
class="pf-v5-c-modal-box__title pf-m-icon"
id="pf-modal-part-3"
>
<span
class="pf-v5-c-modal-box__title-icon"
>
<svg
aria-hidden="true"
class="pf-v5-svg"
fill="currentColor"
height="1em"
role="img"
viewBox="0 0 576 512"
width="1em"
>
<path
d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
/>
</svg>
</span>
<span
class="pf-v5-screen-reader"
>
Warning alert:
</span>
<span
class="pf-v5-c-modal-box__title-text"
>
Custom title
</span>
</h1>
</header>
<div
class="pf-v5-c-modal-box__body"
id="pf-modal-part-4"
>
Custom text
</div>
<footer
class="pf-v5-c-modal-box__footer"
>
<button
aria-disabled="false"
class="pf-v5-c-button pf-m-danger"
data-ouia-component-id="OUIA-Generated-Button-danger-3"
data-ouia-component-type="PF5/Button"
data-ouia-safe="true"
type="button"
>
Confirm
</button>
<button
aria-disabled="false"
class="pf-v5-c-button pf-m-link"
data-ouia-component-id="OUIA-Generated-Button-link-3"
data-ouia-component-type="PF5/Button"
data-ouia-safe="true"
type="button"
>
Cancel
</button>
</footer>
</div>
`;
Loading
Loading