fixes erroneous validation warning, template Jobs tab, job detail job type

This commit is contained in:
Alex Corey
2021-03-17 11:09:06 -04:00
parent e0d9100dc4
commit 40f0f5ddf7
15 changed files with 100 additions and 40 deletions

View File

@@ -94,4 +94,56 @@ describe('<ProjectLookup />', () => {
expect(wrapper.find('ProjectLookup')).toHaveLength(1); expect(wrapper.find('ProjectLookup')).toHaveLength(1);
expect(wrapper.find('Lookup').prop('isDisabled')).toBe(true); expect(wrapper.find('Lookup').prop('isDisabled')).toBe(true);
}); });
test('should not show helper text', async () => {
let wrapper;
ProjectsAPI.readOptions.mockReturnValue({
data: {
actions: {
GET: {},
},
related_search_fields: [],
},
});
await act(async () => {
wrapper = mountWithContexts(
<ProjectLookup
isValid
helperTextInvalid="select value"
onChange={() => {}}
/>
);
});
wrapper.update();
expect(wrapper.find('div#project-helper').length).toBe(0);
});
test('should not show helper text', async () => {
let wrapper;
ProjectsAPI.readOptions.mockReturnValue({
data: {
actions: {
GET: {},
},
related_search_fields: [],
},
});
await act(async () => {
wrapper = mountWithContexts(
<ProjectLookup
isValid={false}
helperTextInvalid="select value"
onChange={() => {}}
/>
);
});
wrapper.update();
expect(wrapper.find('div#project-helper').text('helperTextInvalid')).toBe(
'select value'
);
});
}); });

View File

@@ -64,8 +64,8 @@ function Host({ i18n, setBreadcrumb }) {
id: 2, id: 2,
}, },
{ {
name: i18n._(t`Completed Jobs`), name: i18n._(t`Jobs`),
link: `${match.url}/completed_jobs`, link: `${match.url}/jobs`,
id: 3, id: 3,
}, },
]; ];
@@ -122,7 +122,7 @@ function Host({ i18n, setBreadcrumb }) {
<Route path="/hosts/:id/groups" key="groups"> <Route path="/hosts/:id/groups" key="groups">
<HostGroups host={host} /> <HostGroups host={host} />
</Route>, </Route>,
<Route path="/hosts/:id/completed_jobs" key="completed-jobs"> <Route path="/hosts/:id/jobs" key="jobs">
<JobList defaultParams={{ job__hosts: host.id }} /> <JobList defaultParams={{ job__hosts: host.id }} />
</Route>, </Route>,
]} ]}

View File

@@ -29,7 +29,7 @@ function Hosts({ i18n }) {
[`/hosts/${host.id}/details`]: i18n._(t`Details`), [`/hosts/${host.id}/details`]: i18n._(t`Details`),
[`/hosts/${host.id}/facts`]: i18n._(t`Facts`), [`/hosts/${host.id}/facts`]: i18n._(t`Facts`),
[`/hosts/${host.id}/groups`]: i18n._(t`Groups`), [`/hosts/${host.id}/groups`]: i18n._(t`Groups`),
[`/hosts/${host.id}/completed_jobs`]: i18n._(t`Completed Jobs`), [`/hosts/${host.id}/jobs`]: i18n._(t`Jobs`),
}); });
}, },
[i18n] [i18n]

View File

@@ -56,7 +56,7 @@ function Inventories({ i18n }) {
...initScreenHeader.current, ...initScreenHeader.current,
[inventoryPath]: `${inventory.name}`, [inventoryPath]: `${inventory.name}`,
[`${inventoryPath}/access`]: i18n._(t`Access`), [`${inventoryPath}/access`]: i18n._(t`Access`),
[`${inventoryPath}/completed_jobs`]: i18n._(t`Completed jobs`), [`${inventoryPath}/jobs`]: i18n._(t`Jobs`),
[`${inventoryPath}/details`]: i18n._(t`Details`), [`${inventoryPath}/details`]: i18n._(t`Details`),
[`${inventoryPath}/edit`]: i18n._(t`Edit details`), [`${inventoryPath}/edit`]: i18n._(t`Edit details`),
@@ -69,9 +69,7 @@ function Inventories({ i18n }) {
[`${inventoryHostsPath}/${nestedObject?.id}/details`]: i18n._( [`${inventoryHostsPath}/${nestedObject?.id}/details`]: i18n._(
t`Host details` t`Host details`
), ),
[`${inventoryHostsPath}/${nestedObject?.id}/completed_jobs`]: i18n._( [`${inventoryHostsPath}/${nestedObject?.id}/jobs`]: i18n._(t`Jobs`),
t`Completed jobs`
),
[`${inventoryHostsPath}/${nestedObject?.id}/facts`]: i18n._(t`Facts`), [`${inventoryHostsPath}/${nestedObject?.id}/facts`]: i18n._(t`Facts`),
[`${inventoryHostsPath}/${nestedObject?.id}/groups`]: i18n._(t`Groups`), [`${inventoryHostsPath}/${nestedObject?.id}/groups`]: i18n._(t`Groups`),

View File

@@ -65,8 +65,8 @@ function Inventory({ i18n, setBreadcrumb }) {
{ name: i18n._(t`Hosts`), link: `${match.url}/hosts`, id: 3 }, { name: i18n._(t`Hosts`), link: `${match.url}/hosts`, id: 3 },
{ name: i18n._(t`Sources`), link: `${match.url}/sources`, id: 4 }, { name: i18n._(t`Sources`), link: `${match.url}/sources`, id: 4 },
{ {
name: i18n._(t`Completed Jobs`), name: i18n._(t`Jobs`),
link: `${match.url}/completed_jobs`, link: `${match.url}/jobs`,
id: 5, id: 5,
}, },
]; ];
@@ -160,10 +160,7 @@ function Inventory({ i18n, setBreadcrumb }) {
setBreadcrumb={setBreadcrumb} setBreadcrumb={setBreadcrumb}
/> />
</Route>, </Route>,
<Route <Route path="/inventories/inventory/:id/jobs" key="jobs">
path="/inventories/inventory/:id/completed_jobs"
key="completed_jobs"
>
<JobList <JobList
defaultParams={{ defaultParams={{
or__job__inventory: inventory.id, or__job__inventory: inventory.id,

View File

@@ -85,8 +85,8 @@ function InventoryHost({ i18n, setBreadcrumb, inventory }) {
id: 3, id: 3,
}, },
{ {
name: i18n._(t`Completed Jobs`), name: i18n._(t`Jobs`),
link: `${match.url}/completed_jobs`, link: `${match.url}/jobs`,
id: 4, id: 4,
}, },
]; ];
@@ -151,8 +151,8 @@ function InventoryHost({ i18n, setBreadcrumb, inventory }) {
<InventoryHostGroups /> <InventoryHostGroups />
</Route> </Route>
<Route <Route
key="completed-jobs" key="jobs"
path="/inventories/inventory/:id/hosts/:hostId/completed_jobs" path="/inventories/inventory/:id/hosts/:hostId/jobs"
> >
<JobList defaultParams={{ job__hosts: host.id }} /> <JobList defaultParams={{ job__hosts: host.id }} />
</Route> </Route>

View File

@@ -49,7 +49,7 @@ describe('<InventoryHost />', () => {
'Details', 'Details',
'Facts', 'Facts',
'Groups', 'Groups',
'Completed Jobs', 'Jobs',
]; ];
wrapper.find('RoutedTabs li').forEach((tab, index) => { wrapper.find('RoutedTabs li').forEach((tab, index) => {
expect(tab.text()).toEqual(expectedTabs[index]); expect(tab.text()).toEqual(expectedTabs[index]);

View File

@@ -70,8 +70,8 @@ function SmartInventory({ i18n, setBreadcrumb }) {
{ name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 }, { name: i18n._(t`Access`), link: `${match.url}/access`, id: 1 },
{ name: i18n._(t`Hosts`), link: `${match.url}/hosts`, id: 2 }, { name: i18n._(t`Hosts`), link: `${match.url}/hosts`, id: 2 },
{ {
name: i18n._(t`Completed jobs`), name: i18n._(t`Jobs`),
link: `${match.url}/completed_jobs`, link: `${match.url}/jobs`,
id: 3, id: 3,
}, },
]; ];
@@ -150,10 +150,7 @@ function SmartInventory({ i18n, setBreadcrumb }) {
setBreadcrumb={setBreadcrumb} setBreadcrumb={setBreadcrumb}
/> />
</Route>, </Route>,
<Route <Route key="jobs" path="/inventories/smart_inventory/:id/jobs">
key="completed_jobs"
path="/inventories/smart_inventory/:id/completed_jobs"
>
<JobList <JobList
defaultParams={{ defaultParams={{
or__job__inventory: inventory.id, or__job__inventory: inventory.id,

View File

@@ -78,7 +78,10 @@ function JobDetail({ job, i18n }) {
const jobTypes = { const jobTypes = {
project_update: i18n._(t`Source Control Update`), project_update: i18n._(t`Source Control Update`),
inventory_update: i18n._(t`Inventory Sync`), inventory_update: i18n._(t`Inventory Sync`),
job: i18n._(t`Playbook Run`), job:
job.job_type === 'check'
? i18n._(t`Playbook Check`)
: i18n._(t`Playbook Run`),
ad_hoc_command: i18n._(t`Command`), ad_hoc_command: i18n._(t`Command`),
management_job: i18n._(t`Management Job`), management_job: i18n._(t`Management Job`),
workflow_job: i18n._(t`Workflow Job`), workflow_job: i18n._(t`Workflow Job`),

View File

@@ -10,16 +10,15 @@ jest.mock('../../../api');
describe('<JobDetail />', () => { describe('<JobDetail />', () => {
let wrapper; let wrapper;
function assertDetail(label, value) {
expect(wrapper.find(`Detail[label="${label}"] dt`).text()).toBe(label);
expect(wrapper.find(`Detail[label="${label}"] dd`).text()).toBe(value);
}
afterEach(() => { afterEach(() => {
wrapper.unmount(); wrapper.unmount();
}); });
test('should display details', () => { test('should display details', () => {
function assertDetail(label, value) {
expect(wrapper.find(`Detail[label="${label}"] dt`).text()).toBe(label);
expect(wrapper.find(`Detail[label="${label}"] dd`).text()).toBe(value);
}
wrapper = mountWithContexts( wrapper = mountWithContexts(
<JobDetail <JobDetail
job={{ job={{
@@ -162,4 +161,15 @@ describe('<JobDetail />', () => {
assertMissingDetail('Project'); assertMissingDetail('Project');
assertMissingDetail('Inventory'); assertMissingDetail('Inventory');
}); });
test('should display Playbook Check detail', () => {
wrapper = mountWithContexts(
<JobDetail
job={{
...mockJobData,
job_type: 'check',
}}
/>
);
assertDetail('Job Type', 'Playbook Check');
});
}); });

View File

@@ -148,8 +148,8 @@ function Template({ i18n, setBreadcrumb }) {
tabsArray.push( tabsArray.push(
{ {
name: i18n._(t`Completed Jobs`), name: i18n._(t`Jobs`),
link: `${match.url}/completed_jobs`, link: `${match.url}/jobs`,
}, },
{ {
name: canAddAndEditSurvey ? i18n._(t`Survey`) : i18n._(t`View Survey`), name: canAddAndEditSurvey ? i18n._(t`Survey`) : i18n._(t`View Survey`),
@@ -232,7 +232,7 @@ function Template({ i18n, setBreadcrumb }) {
/> />
</Route> </Route>
)} )}
<Route path="/templates/:templateType/:id/completed_jobs"> <Route path="/templates/:templateType/:id/jobs">
<JobList defaultParams={{ job__job_template: template.id }} /> <JobList defaultParams={{ job__job_template: template.id }} />
</Route> </Route>
<Route path="/templates/:templateType/:id/survey"> <Route path="/templates/:templateType/:id/survey">

View File

@@ -45,7 +45,7 @@ function Templates({ i18n }) {
[`${templatePath}/edit`]: i18n._(t`Edit Details`), [`${templatePath}/edit`]: i18n._(t`Edit Details`),
[`${templatePath}/access`]: i18n._(t`Access`), [`${templatePath}/access`]: i18n._(t`Access`),
[`${templatePath}/notifications`]: i18n._(t`Notifications`), [`${templatePath}/notifications`]: i18n._(t`Notifications`),
[`${templatePath}/completed_jobs`]: i18n._(t`Completed Jobs`), [`${templatePath}/jobs`]: i18n._(t`Jobs`),
[surveyPath]: i18n._(t`Survey`), [surveyPath]: i18n._(t`Survey`),
[`${surveyPath}/add`]: i18n._(t`Add Question`), [`${surveyPath}/add`]: i18n._(t`Add Question`),
[`${surveyPath}/edit`]: i18n._(t`Edit Question`), [`${surveyPath}/edit`]: i18n._(t`Edit Question`),

View File

@@ -142,8 +142,8 @@ function WorkflowJobTemplate({ i18n, setBreadcrumb }) {
link: `${match.url}/visualizer`, link: `${match.url}/visualizer`,
}, },
{ {
name: i18n._(t`Completed Jobs`), name: i18n._(t`Jobs`),
link: `${match.url}/completed_jobs`, link: `${match.url}/jobs`,
}, },
{ {
name: canAddAndEditSurvey ? i18n._(t`Survey`) : i18n._(t`View Survey`), name: canAddAndEditSurvey ? i18n._(t`Survey`) : i18n._(t`View Survey`),
@@ -253,7 +253,7 @@ function WorkflowJobTemplate({ i18n, setBreadcrumb }) {
</Route> </Route>
)} )}
{template?.id && ( {template?.id && (
<Route path="/templates/:templateType/:id/completed_jobs"> <Route path="/templates/:templateType/:id/jobs">
<JobList <JobList
defaultParams={{ defaultParams={{
workflow_job__workflow_job_template: template.id, workflow_job__workflow_job_template: template.id,

View File

@@ -154,7 +154,7 @@ function JobTemplateForm({
const handleProjectUpdate = useCallback( const handleProjectUpdate = useCallback(
value => { value => {
setFieldValue('playbook', 0); setFieldValue('playbook', '');
setFieldValue('scm_branch', ''); setFieldValue('scm_branch', '');
setFieldValue('project', value); setFieldValue('project', value);
}, },
@@ -271,7 +271,9 @@ function JobTemplateForm({
onBlur={() => projectHelpers.setTouched()} onBlur={() => projectHelpers.setTouched()}
tooltip={i18n._(t`Select the project containing the playbook tooltip={i18n._(t`Select the project containing the playbook
you want this job to execute.`)} you want this job to execute.`)}
isValid={!projectMeta.touched || !projectMeta.error} isValid={
!projectMeta.touched || !projectMeta.error || projectField.value
}
helperTextInvalid={projectMeta.error} helperTextInvalid={projectMeta.error}
onChange={handleProjectUpdate} onChange={handleProjectUpdate}
required required

View File

@@ -58,6 +58,7 @@ function PlaybookSelect({
placeholderText={i18n._(t`Select a playbook`)} placeholderText={i18n._(t`Select a playbook`)}
isCreateable={false} isCreateable={false}
onSelect={(event, value) => { onSelect={(event, value) => {
setIsOpen(false);
onChange(value); onChange(value);
}} }}
id="template-playbook" id="template-playbook"