Skip to content

Commit

Permalink
feat(HMS-2994): add delete confirmation modal
Browse files Browse the repository at this point in the history
This change introduce the delete confirmation modal
dialog.

This dialog will show up when we click on the kebab
menu of the list domains view to delete the item, or
when we click on the kebab menu from the detail view
of the domain to delete the domain that is being
displayed.

In both cases, the deletion confirmation modal is
showed up, and when we press Delete button the
item is eventually deleted from the database.

Making click on the modal cross icon or cancel link
will dismiss the deletion confirmation modal with
no effect on the data stored.

Signed-off-by: Alejandro Visiedo <[email protected]>
  • Loading branch information
avisiedo committed Apr 26, 2024
1 parent 9d4ea10 commit c478299
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import '~@redhat-cloud-services/frontend-components-utilities/styles/variables';
50 changes: 50 additions & 0 deletions src/Components/ConfirmDeleteDomain/ConfirmDeleteDomain.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import ConfirmDeleteDomain from './ConfirmDeleteDomain';
import '@testing-library/jest-dom';
import { Domain } from '../../Api';

const domain: Domain = {
domain_name: 'mydomain.test',
} as unknown as Domain;

test('expect empty when isOpen is false', () => {
const root = render(<ConfirmDeleteDomain domain={domain} isOpen={false} />);
expect(root.container).toBeEmptyDOMElement();
});

test('expect modal displayed', () => {
render(<ConfirmDeleteDomain domain={domain} isOpen={true} />);
expect(screen.getByRole('heading')).toHaveTextContent(/^Warning alert:Delete identity domain registration\?$/);
expect(screen.getByRole('button', { name: 'Close' })).toHaveTextContent(/^$/);
expect(screen.getByRole('button', { name: 'Delete' })).toHaveTextContent(/^Delete$/);
expect(screen.getByRole('button', { name: 'Cancel' })).toHaveTextContent(/^Cancel$/);
});

test('expect handler onDelete to be called', () => {
// given
const confirmHandler = jest.fn();
const cancelHandler = jest.fn();
render(<ConfirmDeleteDomain domain={domain} isOpen={true} onDelete={confirmHandler} onCancel={cancelHandler} />);

// when the OK button is clicked
screen.getByRole('button', { name: 'Delete' }).click();

// then the confirmHandler should be called with the domain as argument and cancelHandler should not
expect(confirmHandler).toBeCalledWith(domain);
expect(cancelHandler).toBeCalledTimes(0);
});

test('expect handler onCancel to be called', () => {
// given
const confirmHandler = jest.fn();
const cancelHandler = jest.fn();
render(<ConfirmDeleteDomain domain={domain} isOpen={true} onDelete={confirmHandler} onCancel={cancelHandler} />);

// when the OK button is clicked
screen.getByRole('button', { name: 'Cancel' }).click();

// then the confirmHandler should be called with the domain as argument and cancelHandler should not
expect(cancelHandler).toBeCalledTimes(1);
expect(confirmHandler).toBeCalledTimes(0);
});
44 changes: 44 additions & 0 deletions src/Components/ConfirmDeleteDomain/ConfirmDeleteDomain.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Button, Modal } from '@patternfly/react-core';
import './ConfirmDeleteDomain.scss';
import React from 'react';
import { Domain } from '../../Api/api';

interface ConfirmDeleteDomainProps {
domain?: Domain;
isOpen?: boolean;
onDelete?: (domain?: Domain) => void;
onCancel?: () => void;
}

/**
* Modal dialog to confirm a domain deletion.
*
* @param props the props given by the smart component.
*/
const ConfirmDeleteDomain: React.FC<ConfirmDeleteDomainProps> = (props) => {
const onDeleteWrapper = () => {
props.onDelete && props.onDelete(props.domain);
};
return (
<Modal
isOpen={props.isOpen}
titleIconVariant={'warning'}
variant="small"
title="Delete identity domain registration?"
ouiaId="ModalConfirmDeletion"
onClose={props.onCancel}
actions={[
<Button key="delete" variant="danger" onClick={onDeleteWrapper} ouiaId="ButtonModalConfirmDeletionDelete">
Delete
</Button>,
<Button key="cancel" variant="link" onClick={props.onCancel} ouiaId="ButtonModalConfirmDeletionCancel">
Cancel
</Button>,
]}
>
No new host enrollment from HCC will be allowed on <b>{props.domain?.title || ''}</b> domain after registration deletion.
</Modal>
);
};

export default ConfirmDeleteDomain;
20 changes: 17 additions & 3 deletions src/Components/DomainList/DomainList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useNavigate } from 'react-router-dom';
import { AppContext, AppContextType } from '../../AppContext';
import { Button } from '@patternfly/react-core';
import AutoJoinChangeConfirmDialog from '../AutoJoinChangeConfirmDialog/AutoJoinChangeConfirmDialog';
import ConfirmDeleteDomain from '../ConfirmDeleteDomain/ConfirmDeleteDomain';

export interface IColumnType<T> {
key: string;
Expand Down Expand Up @@ -108,7 +109,9 @@ export const DomainList = () => {
const [activeSortDirection, setActiveSortDirection] = React.useState<'asc' | 'desc'>('asc');

const domains = context?.domains || ([] as Domain[]);

const [isOpenAutoJoinChangeConfirm, setIsOpenAutoJoinChangeConfirm] = useState(false);
const [isOpenConfirmDelete, setIsOpenConfirmDelete] = useState<boolean>(false);
const [currentDomain, setCurrentDomain] = useState<Domain>();

const enabledText = 'Enabled';
Expand Down Expand Up @@ -166,8 +169,18 @@ export const DomainList = () => {
}
};

const onDelete = (domain: Domain) => {
if (domain.domain_id !== undefined) {
const OnShowConfirmDelete = (domain: Domain) => {
setIsOpenConfirmDelete(true);
setCurrentDomain(domain);
};

const onDismissConfirmDelete = () => {
setIsOpenConfirmDelete(false);
};

const onDelete = (domain?: Domain) => {
setIsOpenConfirmDelete(false);
if (domain?.domain_id !== undefined) {
const domainId = domain.domain_id;
resources_api
.deleteDomain(domainId)
Expand Down Expand Up @@ -198,7 +211,7 @@ export const DomainList = () => {
},
{
title: 'Delete',
onClick: () => onDelete(domain),
onClick: () => OnShowConfirmDelete(domain),
ouiaId: 'ButtonActionDelete',
},
];
Expand Down Expand Up @@ -269,6 +282,7 @@ export const DomainList = () => {
onConfirm={onConfirmAutoJoinChange}
onCancel={() => setIsOpenAutoJoinChangeConfirm(false)}
/>
<ConfirmDeleteDomain domain={currentDomain} isOpen={isOpenConfirmDelete} onCancel={onDismissConfirmDelete} onDelete={onDelete} />
</>
);
};
Expand Down
50 changes: 33 additions & 17 deletions src/Routes/DetailPage/DetailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Domain, ResourcesApiFactory } from '../../Api/api';
import { AppContext, AppContextType } from '../../AppContext';
import { DetailGeneral } from './Components/DetailGeneral/DetailGeneral';
import { DetailServers } from './Components/DetailServers/DetailServers';
import ConfirmDeleteDomain from '../../Components/ConfirmDeleteDomain/ConfirmDeleteDomain';

/**
* It represents the detail page to show the information about a
Expand All @@ -40,6 +41,7 @@ const DetailPage = () => {

// States
const [domain, setDomain] = useState<Domain | undefined>(appContext?.getDomain(domain_id || ''));
const [isOpenConfirmDelete, setIsOpenConfirmDelete] = useState<boolean>(false);

console.log('INFO:DetailPage render:domain_id=' + domain_id);

Expand Down Expand Up @@ -82,26 +84,39 @@ const DetailPage = () => {
setIsKebabOpen(!isKebabOpen);
};

const OnShowConfirmDelete = () => {
setIsOpenConfirmDelete(true);
};

const onDismissConfirmDelete = () => {
setIsOpenConfirmDelete(false);
};

const onDelete = (domain?: Domain) => {
if (domain?.domain_id !== undefined) {
const domainId = domain.domain_id;
resources_api
.deleteDomain(domainId)
.then((response) => {
if (response.status == 204) {
appContext?.deleteDomain(domainId);
navigate('/domains', { replace: true });
} else {
// TODO show-up notification with error message
}
})
.catch((error) => {
// TODO show-up notification with error message
console.log('error onClose: ' + error);
});
}
};

const dropdownItems: JSX.Element[] = [
<DropdownItem
key="delete"
onClick={(value) => {
console.log('Deleting domain: ' + value);
if (domain_id !== undefined) {
resources_api
.deleteDomain(domain_id)
.then((res) => {
if (res.status === 204) {
console.info('Domain ' + value + ' was deleted');
appContext?.deleteDomain(domain_id);
navigate('/domains', { replace: true });
}
})
.catch((reason) => {
// TODO Send error notification to chrome
console.log(reason);
});
}
onClick={() => {
domain !== undefined && OnShowConfirmDelete();
}}
ouiaId="ButtonDetailsDelete"
>
Expand Down Expand Up @@ -168,6 +183,7 @@ const DetailPage = () => {
</Card>
</PageSection>
</Page>
<ConfirmDeleteDomain domain={domain} isOpen={isOpenConfirmDelete} onCancel={onDismissConfirmDelete} onDelete={onDelete} />
</>
);
};
Expand Down

0 comments on commit c478299

Please sign in to comment.