Addresses PR issues

Adds Delete Modal for deleting from Details view
Adds test for delete modal
Addresses styling for Variables label
Removes X close button from form
This commit is contained in:
Alex Corey 2019-12-03 15:49:36 -05:00
parent c997fcfc2c
commit 3ea37e1c79
4 changed files with 95 additions and 32 deletions

View File

@ -51,14 +51,24 @@ function InventoryGroups({ i18n, match, setBreadcrumb, inventory }) {
key="edit"
path="/inventories/inventory/:id/groups/:groupId/edit"
render={() => {
return <InventoryGroupEdit inventoryGroup={inventoryGroup} />;
return (
<InventoryGroupEdit
inventory={inventory}
inventoryGroup={inventoryGroup}
/>
);
}}
/>,
<Route
key="details"
path="/inventories/inventory/:id/groups/:groupId/details"
render={() => {
return <InventoryGroupDetail inventoryGroup={inventoryGroup} />;
return (
<InventoryGroupDetail
inventory={inventory}
inventoryGroup={inventoryGroup}
/>
);
}}
/>,
<Route

View File

@ -3,10 +3,12 @@ import { t } from '@lingui/macro';
import { CardBody, Button } from '@patternfly/react-core';
import { withI18n } from '@lingui/react';
import { withRouter } from 'react-router-dom';
import { withRouter, Link } from 'react-router-dom';
import styled from 'styled-components';
import { VariablesInput } from '@components/CodeMirrorInput';
import ContentError from '@components/ContentError';
import AlertModal from '@components/AlertModal';
import { formatDateString } from '@util/dates';
import { GroupsAPI } from '@api';
import { DetailList, Detail } from '@components/DetailList';
@ -21,6 +23,8 @@ const ActionButtonWrapper = styled.div`
`;
function InventoryGroupDetail({ i18n, history, match, inventoryGroup }) {
const [error, setError] = useState(false);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const handleDelete = async () => {
try {
await GroupsAPI.destroy(inventoryGroup.id);
@ -29,10 +33,42 @@ function InventoryGroupDetail({ i18n, history, match, inventoryGroup }) {
setError(err);
}
};
if (error) {
return <ContentError />;
}
if (isDeleteModalOpen) {
return (
<AlertModal
variant="danger"
title={i18n._(t`Delete Inventory Group`)}
isOpen={isDeleteModalOpen}
onClose={() => setIsDeleteModalOpen(false)}
actions={[
<Button
key="delete"
variant="danger"
aria-label={i18n._(t`confirm delete`)}
onClick={handleDelete}
>
{i18n._(t`Delete`)}
</Button>,
<Button
key="cancel"
variant="secondary"
aria-label={i18n._(t`cancel delete`)}
onClick={() => setIsDeleteModalOpen(false)}
>
{i18n._(t`Cancel`)}
</Button>,
]}
>
{i18n._(t`Are you sure you want to delete:`)}
<br />
<strong>{inventoryGroup.name}</strong>
<br />
</AlertModal>
);
}
return (
<CardBody style={{ paddingTop: '20px' }}>
<DetailList gutter="sm">
@ -41,23 +77,47 @@ function InventoryGroupDetail({ i18n, history, match, inventoryGroup }) {
label={i18n._(t`Description`)}
value={inventoryGroup.description}
/>
<Detail
fullWidth
label={i18n._(t`Variables`)}
value={
<VariablesInput
css="margin: 20px 0"
id="inventoryGroup-variables"
readOnly
value={inventoryGroup.variables}
rows={4}
label=""
/>
}
/>
</DetailList>
<VariablesInput
css="margin: 20px 0"
id="inventoryGroup-variables"
readOnly
value={inventoryGroup.variables}
rows={4}
label={i18n._(t`Variables`)}
/>
<DetailList>
<Detail
label={i18n._(t`Created`)}
value={`${inventoryGroup.created} by ${inventoryGroup.summary_fields.created_by.username}`}
value={
<span>
{i18n._(t`${formatDateString(inventoryGroup.created)} by`)}{' '}
<Link
to={`/users/${inventoryGroup.summary_fields.created_by.id}`}
>
{inventoryGroup.summary_fields.created_by.username}
</Link>
</span>
}
/>
<Detail
label={i18n._(t`Modified`)}
value={`${inventoryGroup.modified} by ${inventoryGroup.summary_fields.modified_by.username}`}
value={
<span>
{i18n._(t`${formatDateString(inventoryGroup.modified)} by`)}{' '}
<Link
to={`/users/${inventoryGroup.summary_fields.modified_by.id}`}
>
{inventoryGroup.summary_fields.modified_by.username}
</Link>
</span>
}
/>
</DetailList>
<ActionButtonWrapper>
@ -75,7 +135,7 @@ function InventoryGroupDetail({ i18n, history, match, inventoryGroup }) {
<Button
variant="danger"
aria-label={i18n._(t`Delete`)}
onClick={handleDelete}
onClick={() => setIsDeleteModalOpen(true)}
>
{i18n._(t`Delete`)}
</Button>

View File

@ -13,14 +13,16 @@ const inventoryGroup = {
description: 'Bar',
variables: 'bizz: buzz',
id: 1,
created: '10:00',
modified: '12:00',
created: '2019-12-02T15:58:16.276813Z',
modified: '2019-12-03T20:33:46.207654Z',
summary_fields: {
created_by: {
username: 'James',
id: 13,
},
modified_by: {
username: 'Bond',
id: 14,
},
},
};
@ -49,8 +51,10 @@ describe('<InventoryGroupDetail />', () => {
test('InventoryGroupDetail renders successfully', () => {
expect(wrapper.length).toBe(1);
});
test('should call api to delete the group', () => {
test('should open delete modal and then call api to delete the group', () => {
wrapper.find('button[aria-label="Delete"]').simulate('click');
expect(wrapper.find('Modal').length).toBe(1);
wrapper.find('button[aria-label="confirm delete"]').simulate('click');
expect(GroupsAPI.destroy).toBeCalledWith(1);
});
test('should navigate user to edit form on edit button click', async () => {
@ -67,12 +71,8 @@ describe('<InventoryGroupDetail />', () => {
expect(wrapper.find('Detail[label="Description"]').prop('value')).toBe(
'Bar'
);
expect(wrapper.find('Detail[label="Created"]').prop('value')).toBe(
'10:00 by James'
);
expect(wrapper.find('Detail[label="Modified"]').prop('value')).toBe(
'12:00 by Bond'
);
expect(wrapper.find('Detail[label="Created"]').length).toBe(1);
expect(wrapper.find('Detail[label="Modified"]').length).toBe(1);
expect(wrapper.find('VariablesInput').prop('value')).toBe('bizz: buzz');
});
});

View File

@ -2,10 +2,9 @@ import React from 'react';
import { withRouter } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { Formik } from 'formik';
import { Form, Card, CardBody, CardHeader } from '@patternfly/react-core';
import { Form, Card, CardBody } from '@patternfly/react-core';
import { t } from '@lingui/macro';
import CardCloseButton from '@components/CardCloseButton';
import FormRow from '@components/FormRow';
import FormField from '@components/FormField';
import FormActionGroup from '@components/FormActionGroup/FormActionGroup';
@ -18,7 +17,6 @@ function InventoryGroupForm({
group = {},
handleSubmit,
handleCancel,
match,
}) {
const initialValues = {
name: group.name || '',
@ -28,11 +26,6 @@ function InventoryGroupForm({
return (
<Card className="awx-c-card">
<CardHeader>
<CardCloseButton
linkTo={`/inventories/inventory/${match.params.id}/groups`}
/>
</CardHeader>
<CardBody>
<Formik
initialValues={initialValues}