mirror of
https://github.com/ansible/awx.git
synced 2024-10-27 09:25:10 +03:00
Adds Deleted
text to missing resources in JT Detials View
The usecase of this change is if a user deletes an Inventory, or a Project that is used by a JT they need to know that those resources are missing. The only time that `Deleted` won't be shown for a missing resource is for Inventory if it has been marked Prompt on Launch then nothing is shown. in that field. Also adds icon to indicate that a JT is missing resources on the JT List.
This commit is contained in:
parent
b3d298269b
commit
e5b76c6427
@ -14,7 +14,7 @@ const DetailName = styled(({ fullWidth, ...props }) => (
|
||||
`}
|
||||
`;
|
||||
|
||||
const DetailValue = styled(({ fullWidth, ...props }) => (
|
||||
const DetailValue = styled(({ fullWidth, missingValue, ...props }) => (
|
||||
<TextListItem {...props} />
|
||||
))`
|
||||
word-break: break-all;
|
||||
@ -23,9 +23,14 @@ const DetailValue = styled(({ fullWidth, ...props }) => (
|
||||
`
|
||||
grid-column: 2 / -1;
|
||||
`}
|
||||
${props =>
|
||||
props.missingValue &&
|
||||
`
|
||||
color: #c9190b;
|
||||
`}
|
||||
`;
|
||||
|
||||
const Detail = ({ label, value, fullWidth }) => {
|
||||
const Detail = ({ label, value, fullWidth, missingValue }) => {
|
||||
if (!value && typeof value !== 'number') {
|
||||
return null;
|
||||
}
|
||||
@ -34,7 +39,11 @@ const Detail = ({ label, value, fullWidth }) => {
|
||||
<DetailName component={TextListItemVariants.dt} fullWidth={fullWidth}>
|
||||
{label}
|
||||
</DetailName>
|
||||
<DetailValue component={TextListItemVariants.dd} fullWidth={fullWidth}>
|
||||
<DetailValue
|
||||
missingValue={missingValue}
|
||||
component={TextListItemVariants.dd}
|
||||
fullWidth={fullWidth}
|
||||
>
|
||||
{value}
|
||||
</DetailValue>
|
||||
</Fragment>
|
||||
@ -44,10 +53,12 @@ Detail.propTypes = {
|
||||
label: node.isRequired,
|
||||
value: node,
|
||||
fullWidth: bool,
|
||||
missingValue: bool,
|
||||
};
|
||||
Detail.defaultProps = {
|
||||
value: null,
|
||||
fullWidth: false,
|
||||
missingValue: false,
|
||||
};
|
||||
|
||||
export default Detail;
|
||||
|
@ -72,6 +72,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Name"
|
||||
missingValue={false}
|
||||
value="jane brown"
|
||||
/>
|
||||
</ForwardRef>
|
||||
@ -83,6 +84,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Team Roles"
|
||||
missingValue={false}
|
||||
value={
|
||||
<ForwardRef>
|
||||
<ForwardRef
|
||||
@ -126,6 +128,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Name"
|
||||
missingValue={false}
|
||||
value="jane brown"
|
||||
/>
|
||||
</ForwardRef>
|
||||
@ -137,6 +140,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Team Roles"
|
||||
missingValue={false}
|
||||
value={
|
||||
<ForwardRef>
|
||||
<ForwardRef
|
||||
@ -203,6 +207,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Name"
|
||||
missingValue={false}
|
||||
value="jane brown"
|
||||
/>
|
||||
</ForwardRef>
|
||||
@ -214,6 +219,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Team Roles"
|
||||
missingValue={false}
|
||||
value={
|
||||
<ForwardRef>
|
||||
<ForwardRef
|
||||
@ -379,6 +385,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Name"
|
||||
missingValue={false}
|
||||
value="jane brown"
|
||||
>
|
||||
<Detail__DetailName
|
||||
@ -435,6 +442,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail__DetailValue
|
||||
component="dd"
|
||||
fullWidth={false}
|
||||
missingValue={false}
|
||||
>
|
||||
<StyledComponent
|
||||
component="dd"
|
||||
@ -445,10 +453,12 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "Detail__DetailValue-sc-16ypsyv-1",
|
||||
"isStatic": false,
|
||||
"lastClassName": "yHlYM",
|
||||
"lastClassName": "kCDjmZ",
|
||||
"rules": Array [
|
||||
"word-break:break-all;",
|
||||
[Function],
|
||||
" ",
|
||||
[Function],
|
||||
],
|
||||
},
|
||||
"displayName": "Detail__DetailValue",
|
||||
@ -463,18 +473,20 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
}
|
||||
forwardedRef={null}
|
||||
fullWidth={false}
|
||||
missingValue={false}
|
||||
>
|
||||
<Component
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 kCDjmZ"
|
||||
component="dd"
|
||||
fullWidth={false}
|
||||
missingValue={false}
|
||||
>
|
||||
<TextListItem
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 kCDjmZ"
|
||||
component="dd"
|
||||
>
|
||||
<dd
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 kCDjmZ"
|
||||
data-pf-content={true}
|
||||
>
|
||||
jane brown
|
||||
@ -542,6 +554,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Team Roles"
|
||||
missingValue={false}
|
||||
value={
|
||||
<ForwardRef>
|
||||
<ForwardRef
|
||||
@ -607,6 +620,7 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
<Detail__DetailValue
|
||||
component="dd"
|
||||
fullWidth={false}
|
||||
missingValue={false}
|
||||
>
|
||||
<StyledComponent
|
||||
component="dd"
|
||||
@ -617,10 +631,12 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "Detail__DetailValue-sc-16ypsyv-1",
|
||||
"isStatic": false,
|
||||
"lastClassName": "yHlYM",
|
||||
"lastClassName": "kCDjmZ",
|
||||
"rules": Array [
|
||||
"word-break:break-all;",
|
||||
[Function],
|
||||
" ",
|
||||
[Function],
|
||||
],
|
||||
},
|
||||
"displayName": "Detail__DetailValue",
|
||||
@ -635,18 +651,20 @@ exports[`<ResourceAccessListItem /> initially renders succesfully 1`] = `
|
||||
}
|
||||
forwardedRef={null}
|
||||
fullWidth={false}
|
||||
missingValue={false}
|
||||
>
|
||||
<Component
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 kCDjmZ"
|
||||
component="dd"
|
||||
fullWidth={false}
|
||||
missingValue={false}
|
||||
>
|
||||
<TextListItem
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 kCDjmZ"
|
||||
component="dd"
|
||||
>
|
||||
<dd
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 kCDjmZ"
|
||||
data-pf-content={true}
|
||||
>
|
||||
<ChipGroup>
|
||||
|
@ -9,13 +9,20 @@ import mockJobData from '../shared/data.job.json';
|
||||
jest.mock('@api');
|
||||
|
||||
describe('<JobDetail />', () => {
|
||||
let wrapper;
|
||||
beforeEach(() => {
|
||||
wrapper = mountWithContexts(<JobDetail job={mockJobData} />);
|
||||
});
|
||||
afterEach(() => {
|
||||
wrapper.unmount();
|
||||
});
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(<JobDetail job={mockJobData} />);
|
||||
wrapper = mountWithContexts(<JobDetail job={mockJobData} />);
|
||||
|
||||
expect(wrapper.length).toBe(1);
|
||||
});
|
||||
|
||||
test('should display details', () => {
|
||||
const wrapper = mountWithContexts(<JobDetail job={mockJobData} />);
|
||||
|
||||
function assertDetail(label, value) {
|
||||
expect(wrapper.find(`Detail[label="${label}"] dt`).text()).toBe(label);
|
||||
expect(wrapper.find(`Detail[label="${label}"] dd`).text()).toBe(value);
|
||||
@ -43,7 +50,6 @@ describe('<JobDetail />', () => {
|
||||
});
|
||||
|
||||
test('should display credentials', () => {
|
||||
const wrapper = mountWithContexts(<JobDetail job={mockJobData} />);
|
||||
const credentialChip = wrapper.find('CredentialChip');
|
||||
|
||||
expect(credentialChip.prop('credential')).toEqual(
|
||||
@ -52,21 +58,18 @@ describe('<JobDetail />', () => {
|
||||
});
|
||||
|
||||
test('should display successful job status icon', () => {
|
||||
const wrapper = mountWithContexts(<JobDetail job={mockJobData} />);
|
||||
const statusDetail = wrapper.find('Detail[label="Status"]');
|
||||
expect(statusDetail.find('StatusIcon__SuccessfulTop')).toHaveLength(1);
|
||||
expect(statusDetail.find('StatusIcon__SuccessfulBottom')).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should display successful project status icon', () => {
|
||||
const wrapper = mountWithContexts(<JobDetail job={mockJobData} />);
|
||||
const statusDetail = wrapper.find('Detail[label="Project"]');
|
||||
expect(statusDetail.find('StatusIcon__SuccessfulTop')).toHaveLength(1);
|
||||
expect(statusDetail.find('StatusIcon__SuccessfulBottom')).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should properly delete job', async () => {
|
||||
const wrapper = mountWithContexts(<JobDetail job={mockJobData} />);
|
||||
wrapper.find('button[aria-label="Delete"]').simulate('click');
|
||||
await sleep(1);
|
||||
wrapper.update();
|
||||
@ -89,8 +92,6 @@ describe('<JobDetail />', () => {
|
||||
},
|
||||
})
|
||||
);
|
||||
const wrapper = mountWithContexts(<JobDetail job={mockJobData} />);
|
||||
|
||||
wrapper.find('button[aria-label="Delete"]').simulate('click');
|
||||
const modal = wrapper.find('Modal');
|
||||
expect(modal.length).toBe(1);
|
||||
@ -102,4 +103,23 @@ describe('<JobDetail />', () => {
|
||||
const errorModal = wrapper.find('ErrorDetail');
|
||||
expect(errorModal.length).toBe(1);
|
||||
});
|
||||
|
||||
test('DELETED is shown for required Job resources that have been deleted', () => {
|
||||
const newMockJobData = { ...mockJobData };
|
||||
newMockJobData.summary_fields.inventory = null;
|
||||
newMockJobData.summary_fields.project = null;
|
||||
const newWrapper = mountWithContexts(
|
||||
<JobDetail job={newMockJobData} />
|
||||
).find('JobDetail');
|
||||
async function assertMissingDetail(label) {
|
||||
expect(newWrapper.length).toBe(1);
|
||||
await sleep(0);
|
||||
expect(newWrapper.find(`Detail[label="${label}"] dt`).text()).toBe(label);
|
||||
expect(newWrapper.find(`Detail[label="${label}"] dd`).text()).toBe(
|
||||
'DELETED'
|
||||
);
|
||||
}
|
||||
assertMissingDetail('Project');
|
||||
assertMissingDetail('Inventory');
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { Component } from 'react';
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import { Link, withRouter } from 'react-router-dom';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import {
|
||||
@ -60,6 +60,7 @@ class JobTemplateDetail extends Component {
|
||||
render() {
|
||||
const {
|
||||
template: {
|
||||
ask_inventory_on_launch,
|
||||
allow_simultaneous,
|
||||
become_enabled,
|
||||
created,
|
||||
@ -156,6 +157,28 @@ class JobTemplateDetail extends Component {
|
||||
</TextList>
|
||||
);
|
||||
|
||||
const renderMissingDataDetail = value => (
|
||||
<Detail missingValue label={value} value={i18n._(t`Deleted`)} />
|
||||
);
|
||||
|
||||
const inventoryValue = (kind, id) => {
|
||||
const inventorykind =
|
||||
kind === 'smart' ? (kind = 'smary_inventory') : (kind = 'inventory');
|
||||
|
||||
return ask_inventory_on_launch ? (
|
||||
<Fragment>
|
||||
<Link to={`/inventories/${inventorykind}/${id}/details`}>
|
||||
{summary_fields.inventory.name}
|
||||
</Link>
|
||||
<span> {i18n._(t`(Prompt on Launch)`)}</span>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Link to={`/inventories/${inventorykind}/${id}/details`}>
|
||||
{summary_fields.inventory.name}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
if (contentError) {
|
||||
return <ContentError error={contentError} />;
|
||||
}
|
||||
@ -171,31 +194,32 @@ class JobTemplateDetail extends Component {
|
||||
<Detail label={i18n._(t`Name`)} value={name} />
|
||||
<Detail label={i18n._(t`Description`)} value={description} />
|
||||
<Detail label={i18n._(t`Job Type`)} value={job_type} />
|
||||
{summary_fields.inventory && (
|
||||
|
||||
{summary_fields.inventory ? (
|
||||
<Detail
|
||||
label={i18n._(t`Inventory`)}
|
||||
value={
|
||||
<Link
|
||||
to={`/inventories/${
|
||||
summary_fields.inventory.kind === 'smart'
|
||||
? 'smart_inventory'
|
||||
: 'inventory'
|
||||
}/${summary_fields.inventory.id}/details`}
|
||||
>
|
||||
{summary_fields.inventory.name}
|
||||
</Link>
|
||||
}
|
||||
value={inventoryValue(
|
||||
summary_fields.inventory.kind,
|
||||
summary_fields.inventory.id
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
!ask_inventory_on_launch &&
|
||||
renderMissingDataDetail(i18n._(t`Inventory`))
|
||||
)}
|
||||
{summary_fields.project && (
|
||||
{summary_fields.project ? (
|
||||
<Detail
|
||||
label={i18n._(t`Project`)}
|
||||
value={
|
||||
<Link to={`/projects/${summary_fields.project.id}/details`}>
|
||||
{summary_fields.project.name}
|
||||
{summary_fields.project
|
||||
? summary_fields.project.name
|
||||
: i18n._(t`Deleted`)}
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
renderMissingDataDetail(i18n._(t`Project`))
|
||||
)}
|
||||
<Detail label={i18n._(t`Playbook`)} value={playbook} />
|
||||
<Detail label={i18n._(t`Forks`)} value={forks || '0'} />
|
||||
|
@ -9,6 +9,8 @@ import { JobTemplate } from '@types';
|
||||
import { getAddedAndRemoved } from '@util/lists';
|
||||
import JobTemplateForm from '../shared/JobTemplateForm';
|
||||
|
||||
const loadRelatedProjectPlaybooks = async project =>
|
||||
ProjectsAPI.readPlaybooks(project);
|
||||
class JobTemplateEdit extends Component {
|
||||
static propTypes = {
|
||||
template: JobTemplate.isRequired,
|
||||
@ -33,9 +35,6 @@ class JobTemplateEdit extends Component {
|
||||
this.handleCancel = this.handleCancel.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
this.loadRelatedCredentials = this.loadRelatedCredentials.bind(this);
|
||||
this.loadRelatedProjectPlaybooks = this.loadRelatedProjectPlaybooks.bind(
|
||||
this
|
||||
);
|
||||
this.submitLabels = this.submitLabels.bind(this);
|
||||
}
|
||||
|
||||
@ -44,15 +43,20 @@ class JobTemplateEdit extends Component {
|
||||
}
|
||||
|
||||
async loadRelated() {
|
||||
const {
|
||||
template: { project },
|
||||
} = this.props;
|
||||
this.setState({ contentError: null, hasContentLoading: true });
|
||||
try {
|
||||
const [relatedCredentials, relatedProjectPlaybooks] = await Promise.all([
|
||||
this.loadRelatedCredentials(),
|
||||
this.loadRelatedProjectPlaybooks(),
|
||||
]);
|
||||
if (project) {
|
||||
const { data: playbook = [] } = await loadRelatedProjectPlaybooks(
|
||||
project
|
||||
);
|
||||
this.setState({ relatedProjectPlaybooks: playbook });
|
||||
}
|
||||
const [relatedCredentials] = await this.loadRelatedCredentials();
|
||||
this.setState({
|
||||
relatedCredentials,
|
||||
relatedProjectPlaybooks,
|
||||
});
|
||||
} catch (contentError) {
|
||||
this.setState({ contentError });
|
||||
@ -89,19 +93,6 @@ class JobTemplateEdit extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
async loadRelatedProjectPlaybooks() {
|
||||
const {
|
||||
template: { project },
|
||||
} = this.props;
|
||||
try {
|
||||
const { data: playbooks = [] } = await ProjectsAPI.readPlaybooks(project);
|
||||
this.setState({ relatedProjectPlaybooks: playbooks });
|
||||
return playbooks;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async handleSubmit(values) {
|
||||
const { template, history } = this.props;
|
||||
const {
|
||||
|
@ -44,6 +44,10 @@ const mockJobTemplate = {
|
||||
{ id: 1, kind: 'cloud', name: 'Foo' },
|
||||
{ id: 2, kind: 'ssh', name: 'Bar' },
|
||||
],
|
||||
project: {
|
||||
id: 15,
|
||||
name: 'Boo',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -237,4 +241,50 @@ describe('<JobTemplateEdit />', () => {
|
||||
'/templates/job_template/1/details'
|
||||
);
|
||||
});
|
||||
test('should not call ProjectsAPI.readPlaybooks if there is no project', async () => {
|
||||
const history = createMemoryHistory({});
|
||||
const noProjectTemplate = {
|
||||
id: 1,
|
||||
name: 'Foo',
|
||||
description: 'Bar',
|
||||
job_type: 'run',
|
||||
inventory: 2,
|
||||
playbook: 'Baz',
|
||||
type: 'job_template',
|
||||
forks: 0,
|
||||
limit: '',
|
||||
verbosity: '0',
|
||||
job_slice_count: 1,
|
||||
timeout: 0,
|
||||
job_tags: '',
|
||||
skip_tags: '',
|
||||
diff_mode: false,
|
||||
allow_callbacks: false,
|
||||
allow_simultaneous: false,
|
||||
use_fact_cache: false,
|
||||
host_config_key: '',
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
edit: true,
|
||||
},
|
||||
labels: {
|
||||
results: [{ name: 'Sushi', id: 1 }, { name: 'Major', id: 2 }],
|
||||
},
|
||||
inventory: {
|
||||
id: 2,
|
||||
organization_id: 1,
|
||||
},
|
||||
credentials: [
|
||||
{ id: 1, kind: 'cloud', name: 'Foo' },
|
||||
{ id: 2, kind: 'ssh', name: 'Bar' },
|
||||
],
|
||||
},
|
||||
};
|
||||
await act(async () =>
|
||||
mountWithContexts(<JobTemplateEdit template={noProjectTemplate} />, {
|
||||
context: { router: { history } },
|
||||
})
|
||||
);
|
||||
expect(ProjectsAPI.readPlaybooks).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
@ -8,7 +8,11 @@ import {
|
||||
} from '@patternfly/react-core';
|
||||
import { t } from '@lingui/macro';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { PencilAltIcon, RocketIcon } from '@patternfly/react-icons';
|
||||
import {
|
||||
ExclamationTriangleIcon,
|
||||
PencilAltIcon,
|
||||
RocketIcon,
|
||||
} from '@patternfly/react-icons';
|
||||
|
||||
import ActionButtonCell from '@components/ActionButtonCell';
|
||||
import DataListCell from '@components/DataListCell';
|
||||
@ -58,7 +62,10 @@ class TemplateListItem extends Component {
|
||||
render() {
|
||||
const { i18n, template, isSelected, onSelect } = this.props;
|
||||
const canLaunch = template.summary_fields.user_capabilities.start;
|
||||
|
||||
const missingResourceIcon =
|
||||
(!template.summary_fields.inventory &&
|
||||
!template.ask_inventory_on_launch) ||
|
||||
!template.summary_fields.project;
|
||||
return (
|
||||
<DataListItem
|
||||
aria-labelledby={`check-action-${template.id}`}
|
||||
@ -80,6 +87,16 @@ class TemplateListItem extends Component {
|
||||
<b>{template.name}</b>
|
||||
</Link>
|
||||
</span>
|
||||
{missingResourceIcon && (
|
||||
<Tooltip
|
||||
content={i18n._(
|
||||
t`Resources are missing from this template.`
|
||||
)}
|
||||
position="right"
|
||||
>
|
||||
<ExclamationTriangleIcon css="color: #c9190b; margin-left: 20px;" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</LeftDataListCell>,
|
||||
<RightDataListCell
|
||||
css="padding-left: 40px;"
|
||||
|
@ -81,4 +81,65 @@ describe('<TemplatesListItem />', () => {
|
||||
);
|
||||
expect(wrapper.find('PencilAltIcon').exists()).toBeFalsy();
|
||||
});
|
||||
test('missing resource icon is shown.', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<TemplatesListItem
|
||||
isSelected={false}
|
||||
template={{
|
||||
id: 1,
|
||||
name: 'Template 1',
|
||||
url: '/templates/job_template/1',
|
||||
type: 'job_template',
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
edit: false,
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('ExclamationTriangleIcon').exists()).toBe(true);
|
||||
});
|
||||
test('missing resource icon is not shown when there is a project and an inventory.', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<TemplatesListItem
|
||||
isSelected={false}
|
||||
template={{
|
||||
id: 1,
|
||||
name: 'Template 1',
|
||||
url: '/templates/job_template/1',
|
||||
type: 'job_template',
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
edit: false,
|
||||
},
|
||||
project: { name: 'Foo', id: 2 },
|
||||
inventory: { name: 'Bar', id: 2 },
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('ExclamationTriangleIcon').exists()).toBe(false);
|
||||
});
|
||||
test('missing resource icon is not shown when inventory is prompt_on_launch, and a project', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<TemplatesListItem
|
||||
isSelected={false}
|
||||
template={{
|
||||
id: 1,
|
||||
name: 'Template 1',
|
||||
url: '/templates/job_template/1',
|
||||
type: 'job_template',
|
||||
ask_inventory_on_launch: true,
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
edit: false,
|
||||
},
|
||||
project: { name: 'Foo', id: 2 },
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('ExclamationTriangleIcon').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@ -572,7 +572,9 @@ const FormikApp = withFormik({
|
||||
inventory: { organization: null },
|
||||
},
|
||||
} = template;
|
||||
|
||||
const hasInventory = summary_fields.inventory
|
||||
? summary_fields.inventory.organization_id
|
||||
: null;
|
||||
return {
|
||||
name: template.name || '',
|
||||
description: template.description || '',
|
||||
@ -594,7 +596,7 @@ const FormikApp = withFormik({
|
||||
allow_simultaneous: template.allow_simultaneous || false,
|
||||
use_fact_cache: template.use_fact_cache || false,
|
||||
host_config_key: template.host_config_key || '',
|
||||
organizationId: summary_fields.inventory.organization_id || null,
|
||||
organizationId: hasInventory,
|
||||
initialInstanceGroups: [],
|
||||
instanceGroups: [],
|
||||
credentials: summary_fields.credentials || [],
|
||||
|
Loading…
Reference in New Issue
Block a user