Merge pull request #5740 from AlexSCorey/5257-WFJTMissingResource

Fixes InvGroup Form submission error and TemplateList Missing Resource Bug

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot]
2020-01-23 18:43:44 +00:00
committed by GitHub
6 changed files with 127 additions and 129 deletions

View File

@@ -1,28 +1,28 @@
import React, { useState, useEffect } from 'react'; import React, { useState } from 'react';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { withRouter } from 'react-router-dom'; import { useHistory, useParams } from 'react-router-dom';
import { GroupsAPI } from '@api'; import { GroupsAPI } from '@api';
import { Card } from '@patternfly/react-core'; import { Card } from '@patternfly/react-core';
import InventoryGroupForm from '../shared/InventoryGroupForm'; import InventoryGroupForm from '../shared/InventoryGroupForm';
function InventoryGroupsAdd({ history, inventory, setBreadcrumb }) { function InventoryGroupsAdd() {
const [error, setError] = useState(null); const [error, setError] = useState(null);
const { id } = useParams();
useEffect(() => setBreadcrumb(inventory), [inventory, setBreadcrumb]); const history = useHistory();
const handleSubmit = async values => { const handleSubmit = async values => {
values.inventory = inventory.id; values.inventory = id;
try { try {
const { data } = await GroupsAPI.create(values); const { data } = await GroupsAPI.create(values);
history.push(`/inventories/inventory/${inventory.id}/groups/${data.id}`); history.push(`/inventories/inventory/${id}/groups/${data.id}`);
} catch (err) { } catch (err) {
setError(err); setError(err);
} }
}; };
const handleCancel = () => { const handleCancel = () => {
history.push(`/inventories/inventory/${inventory.id}/groups`); history.push(`/inventories/inventory/${id}/groups`);
}; };
return ( return (
@@ -35,5 +35,5 @@ function InventoryGroupsAdd({ history, inventory, setBreadcrumb }) {
</Card> </Card>
); );
} }
export default withI18n()(withRouter(InventoryGroupsAdd)); export default withI18n()(InventoryGroupsAdd);
export { InventoryGroupsAdd as _InventoryGroupsAdd }; export { InventoryGroupsAdd as _InventoryGroupsAdd };

View File

@@ -21,9 +21,7 @@ describe('<InventoryGroupAdd />', () => {
wrapper = mountWithContexts( wrapper = mountWithContexts(
<Route <Route
path="/inventories/inventory/:id/groups/add" path="/inventories/inventory/:id/groups/add"
component={() => ( component={() => <InventoryGroupAdd />}
<InventoryGroupAdd setBreadcrumb={() => {}} inventory={{ id: 1 }} />
)}
/>, />,
{ {
context: { context: {

View File

@@ -1,28 +1,26 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { withRouter } from 'react-router-dom'; import { useParams, useHistory } from 'react-router-dom';
import { GroupsAPI } from '@api'; import { GroupsAPI } from '@api';
import InventoryGroupForm from '../shared/InventoryGroupForm'; import InventoryGroupForm from '../shared/InventoryGroupForm';
function InventoryGroupEdit({ history, inventoryGroup, inventory, match }) { function InventoryGroupEdit({ inventoryGroup }) {
const [error, setError] = useState(null); const [error, setError] = useState(null);
const { id, groupId } = useParams();
const history = useHistory();
const handleSubmit = async values => { const handleSubmit = async values => {
try { try {
await GroupsAPI.update(match.params.groupId, values); await GroupsAPI.update(groupId, values);
history.push( history.push(`/inventories/inventory/${id}/groups/${groupId}`);
`/inventories/inventory/${inventory.id}/groups/${inventoryGroup.id}`
);
} catch (err) { } catch (err) {
setError(err); setError(err);
} }
}; };
const handleCancel = () => { const handleCancel = () => {
history.push( history.push(`/inventories/inventory/${id}/groups/${groupId}`);
`/inventories/inventory/${inventory.id}/groups/${inventoryGroup.id}`
);
}; };
return ( return (
@@ -34,5 +32,5 @@ function InventoryGroupEdit({ history, inventoryGroup, inventory, match }) {
/> />
); );
} }
export default withI18n()(withRouter(InventoryGroupEdit)); export default withI18n()(InventoryGroupEdit);
export { InventoryGroupEdit as _InventoryGroupEdit }; export { InventoryGroupEdit as _InventoryGroupEdit };

View File

@@ -26,24 +26,12 @@ describe('<InventoryGroupEdit />', () => {
wrapper = mountWithContexts( wrapper = mountWithContexts(
<Route <Route
path="/inventories/inventory/:id/groups/:groupId/edit" path="/inventories/inventory/:id/groups/:groupId/edit"
component={() => ( component={() => <InventoryGroupEdit inventoryGroup={{ id: 2 }} />}
<InventoryGroupEdit
setBreadcrumb={() => {}}
inventory={{ id: 1 }}
inventoryGroup={{ id: 2 }}
/>
)}
/>, />,
{ {
context: { context: {
router: { router: {
history, history,
route: {
match: {
params: { groupId: 13 },
},
location: history.location,
},
}, },
}, },
} }

View File

@@ -1,4 +1,4 @@
import React, { Component } from 'react'; import React from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { import {
DataListItem, DataListItem,
@@ -22,7 +22,6 @@ import ListActionButton from '@components/ListActionButton';
import VerticalSeparator from '@components/VerticalSeparator'; import VerticalSeparator from '@components/VerticalSeparator';
import { Sparkline } from '@components/Sparkline'; import { Sparkline } from '@components/Sparkline';
import { toTitleCase } from '@util/strings'; import { toTitleCase } from '@util/strings';
import styled from 'styled-components'; import styled from 'styled-components';
const rightStyle = ` const rightStyle = `
@@ -51,108 +50,104 @@ const LeftDataListCell = styled(DataListCell)`
} }
} }
`; `;
const RightDataListCell = styled(DataListCell)` const RightDataListCell = styled(DataListCell)`
${rightStyle} ${rightStyle}
`; `;
const RightActionButtonCell = styled(ActionButtonCell)` const RightActionButtonCell = styled(ActionButtonCell)`
${rightStyle} ${rightStyle}
`; `;
class TemplateListItem extends Component { function TemplateListItem({ i18n, template, isSelected, onSelect }) {
render() { const canLaunch = template.summary_fields.user_capabilities.start;
const { i18n, template, isSelected, onSelect } = this.props;
const canLaunch = template.summary_fields.user_capabilities.start; const missingResourceIcon =
const missingResourceIcon = template.type === 'job_template' &&
(!template.summary_fields.project ||
(!template.summary_fields.inventory && (!template.summary_fields.inventory &&
!template.ask_inventory_on_launch) || !template.ask_inventory_on_launch));
!template.summary_fields.project;
return ( return (
<DataListItem <DataListItem
aria-labelledby={`check-action-${template.id}`} aria-labelledby={`check-action-${template.id}`}
css="--pf-c-data-list__expandable-content--BoxShadow: none;" css="--pf-c-data-list__expandable-content--BoxShadow: none;"
id={`${template.id}`} id={`${template.id}`}
> >
<DataListItemRow> <DataListItemRow>
<DataListCheck <DataListCheck
id={`select-jobTemplate-${template.id}`} id={`select-jobTemplate-${template.id}`}
checked={isSelected} checked={isSelected}
onChange={onSelect} onChange={onSelect}
aria-labelledby={`check-action-${template.id}`} aria-labelledby={`check-action-${template.id}`}
/> />
<DataListItemCells <DataListItemCells
dataListCells={[ dataListCells={[
<LeftDataListCell key="divider"> <LeftDataListCell key="divider">
<VerticalSeparator /> <VerticalSeparator />
<span>
<Link to={`/templates/${template.type}/${template.id}`}>
<b>{template.name}</b>
</Link>
</span>
{missingResourceIcon && (
<span> <span>
<Link to={`/templates/${template.type}/${template.id}`}> <Tooltip
<b>{template.name}</b> content={i18n._(
</Link> t`Resources are missing from this template.`
)}
position="right"
>
<ExclamationTriangleIcon css="color: #c9190b; margin-left: 20px;" />
</Tooltip>
</span> </span>
{missingResourceIcon && ( )}
<span> </LeftDataListCell>,
<Tooltip <RightDataListCell
content={i18n._( css="padding-left: 40px;"
t`Resources are missing from this template.` righthalf="true"
)} key="type"
position="right" >
> {toTitleCase(template.type)}
<ExclamationTriangleIcon css="color: #c9190b; margin-left: 20px;" /> </RightDataListCell>,
</Tooltip> <RightDataListCell css="flex: 1;" righthalf="true" key="sparkline">
</span> <Sparkline jobs={template.summary_fields.recent_jobs} />
)} </RightDataListCell>,
</LeftDataListCell>, <RightActionButtonCell
<RightDataListCell css="max-width: 80px;"
css="padding-left: 40px;" righthalf="true"
righthalf="true" lastcolumn="true"
key="type" key="launch"
> >
{toTitleCase(template.type)} {canLaunch && template.type === 'job_template' && (
</RightDataListCell>, <Tooltip content={i18n._(t`Launch Template`)} position="top">
<RightDataListCell <LaunchButton resource={template}>
css="flex: 1;" {({ handleLaunch }) => (
righthalf="true" <ListActionButton variant="plain" onClick={handleLaunch}>
key="sparkline" <RocketIcon />
> </ListActionButton>
<Sparkline jobs={template.summary_fields.recent_jobs} /> )}
</RightDataListCell>, </LaunchButton>
<RightActionButtonCell </Tooltip>
css="max-width: 80px;" )}
righthalf="true" {template.summary_fields.user_capabilities.edit && (
lastcolumn="true" <Tooltip content={i18n._(t`Edit Template`)} position="top">
key="launch" <ListActionButton
> variant="plain"
{canLaunch && template.type === 'job_template' && ( component={Link}
<Tooltip content={i18n._(t`Launch Template`)} position="top"> to={`/templates/${template.type}/${template.id}/edit`}
<LaunchButton resource={template}> >
{({ handleLaunch }) => ( <PencilAltIcon />
<ListActionButton </ListActionButton>
variant="plain" </Tooltip>
onClick={handleLaunch} )}
> </RightActionButtonCell>,
<RocketIcon /> ]}
</ListActionButton> />
)} </DataListItemRow>
</LaunchButton> </DataListItem>
</Tooltip> );
)}
{template.summary_fields.user_capabilities.edit && (
<Tooltip content={i18n._(t`Edit Template`)} position="top">
<ListActionButton
variant="plain"
component={Link}
to={`/templates/${template.type}/${template.id}/edit`}
>
<PencilAltIcon />
</ListActionButton>
</Tooltip>
)}
</RightActionButtonCell>,
]}
/>
</DataListItemRow>
</DataListItem>
);
}
} }
export { TemplateListItem as _TemplateListItem }; export { TemplateListItem as _TemplateListItem };
export default withI18n()(TemplateListItem); export default withI18n()(TemplateListItem);

View File

@@ -142,4 +142,23 @@ describe('<TemplatesListItem />', () => {
); );
expect(wrapper.find('ExclamationTriangleIcon').exists()).toBe(false); expect(wrapper.find('ExclamationTriangleIcon').exists()).toBe(false);
}); });
test('missing resource icon is not shown type is workflow_job_template', () => {
const wrapper = mountWithContexts(
<TemplatesListItem
isSelected={false}
template={{
id: 1,
name: 'Template 1',
url: '/templates/job_template/1',
type: 'workflow_job_template',
summary_fields: {
user_capabilities: {
edit: false,
},
},
}}
/>
);
expect(wrapper.find('ExclamationTriangleIcon').exists()).toBe(false);
});
}); });