mirror of
https://github.com/ansible/awx.git
synced 2026-05-24 00:57:48 -02:30
Merge pull request #6664 from marshmalien/6530-wf-node-jt
Add JT wf node modal prompt details Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
@@ -4,6 +4,7 @@ import { withI18n } from '@lingui/react';
|
|||||||
import { t, Trans } from '@lingui/macro';
|
import { t, Trans } from '@lingui/macro';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import { toTitleCase } from '@util/strings';
|
||||||
|
|
||||||
import { Chip, ChipGroup } from '@patternfly/react-core';
|
import { Chip, ChipGroup } from '@patternfly/react-core';
|
||||||
import { VariablesDetail } from '@components/CodeMirrorInput';
|
import { VariablesDetail } from '@components/CodeMirrorInput';
|
||||||
@@ -19,6 +20,19 @@ const PromptHeader = styled.h2`
|
|||||||
margin: var(--pf-global--spacer--lg) 0;
|
margin: var(--pf-global--spacer--lg) 0;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
function formatTimeout(timeout) {
|
||||||
|
if (typeof timeout === 'undefined' || timeout === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const minutes = Math.floor(timeout / 60);
|
||||||
|
const seconds = timeout - Math.floor(timeout / 60) * 60;
|
||||||
|
return (
|
||||||
|
<Trans>
|
||||||
|
{minutes} min {seconds} sec
|
||||||
|
</Trans>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function hasPromptData(launchData) {
|
function hasPromptData(launchData) {
|
||||||
return (
|
return (
|
||||||
launchData.ask_credential_on_launch ||
|
launchData.ask_credential_on_launch ||
|
||||||
@@ -34,21 +48,93 @@ function hasPromptData(launchData) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatTimeout(timeout) {
|
function omitOverrides(resource, overrides) {
|
||||||
if (typeof timeout === 'undefined' || timeout === null) {
|
const clonedResource = {
|
||||||
return null;
|
...resource,
|
||||||
|
summary_fields: { ...resource.summary_fields },
|
||||||
|
};
|
||||||
|
Object.keys(overrides).forEach(keyToOmit => {
|
||||||
|
delete clonedResource[keyToOmit];
|
||||||
|
delete clonedResource.summary_fields[keyToOmit];
|
||||||
|
});
|
||||||
|
return clonedResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: When prompting is hooked up, update function
|
||||||
|
// to filter based on prompt overrides
|
||||||
|
function partitionPromptDetails(resource, launchConfig) {
|
||||||
|
const { defaults = {} } = launchConfig;
|
||||||
|
const overrides = {};
|
||||||
|
|
||||||
|
if (launchConfig.ask_credential_on_launch) {
|
||||||
|
let isEqual;
|
||||||
|
const defaultCreds = defaults.credentials;
|
||||||
|
const currentCreds = resource?.summary_fields?.credentials;
|
||||||
|
|
||||||
|
if (defaultCreds?.length === currentCreds?.length) {
|
||||||
|
isEqual = currentCreds.every(cred => {
|
||||||
|
return defaultCreds.some(item => item.id === cred.id);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
isEqual = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEqual) {
|
||||||
|
overrides.credentials = resource?.summary_fields?.credentials;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const minutes = Math.floor(timeout / 60);
|
if (launchConfig.ask_diff_mode_on_launch) {
|
||||||
const seconds = timeout - Math.floor(timeout / 60) * 60;
|
if (defaults.diff_mode !== resource.diff_mode) {
|
||||||
return (
|
overrides.diff_mode = resource.diff_mode;
|
||||||
<>
|
}
|
||||||
{minutes} <Trans>min</Trans> {seconds} <Trans>sec</Trans>
|
}
|
||||||
</>
|
if (launchConfig.ask_inventory_on_launch) {
|
||||||
);
|
if (defaults.inventory.id !== resource.inventory) {
|
||||||
|
overrides.inventory = resource?.summary_fields?.inventory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (launchConfig.ask_job_type_on_launch) {
|
||||||
|
if (defaults.job_type !== resource.job_type) {
|
||||||
|
overrides.job_type = resource.job_type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (launchConfig.ask_limit_on_launch) {
|
||||||
|
if (defaults.limit !== resource.limit) {
|
||||||
|
overrides.limit = resource.limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (launchConfig.ask_scm_branch_on_launch) {
|
||||||
|
if (defaults.scm_branch !== resource.scm_branch) {
|
||||||
|
overrides.scm_branch = resource.scm_branch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (launchConfig.ask_skip_tags_on_launch) {
|
||||||
|
if (defaults.skip_tags !== resource.skip_tags) {
|
||||||
|
overrides.skip_tags = resource.skip_tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (launchConfig.ask_tags_on_launch) {
|
||||||
|
if (defaults.job_tags !== resource.job_tags) {
|
||||||
|
overrides.job_tags = resource.job_tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (launchConfig.ask_variables_on_launch) {
|
||||||
|
if (defaults.extra_vars !== resource.extra_vars) {
|
||||||
|
overrides.extra_vars = resource.extra_vars;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (launchConfig.ask_verbosity_on_launch) {
|
||||||
|
if (defaults.verbosity !== resource.verbosity) {
|
||||||
|
overrides.verbosity = resource.verbosity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const withoutOverrides = omitOverrides(resource, overrides);
|
||||||
|
|
||||||
|
return [withoutOverrides, overrides];
|
||||||
}
|
}
|
||||||
|
|
||||||
function PromptDetail({ i18n, resource, launchConfig = {} }) {
|
function PromptDetail({ i18n, resource, launchConfig = {} }) {
|
||||||
const { defaults = {} } = launchConfig;
|
|
||||||
const VERBOSITY = {
|
const VERBOSITY = {
|
||||||
0: i18n._(t`0 (Normal)`),
|
0: i18n._(t`0 (Normal)`),
|
||||||
1: i18n._(t`1 (Verbose)`),
|
1: i18n._(t`1 (Verbose)`),
|
||||||
@@ -57,73 +143,79 @@ function PromptDetail({ i18n, resource, launchConfig = {} }) {
|
|||||||
4: i18n._(t`4 (Connection Debug)`),
|
4: i18n._(t`4 (Connection Debug)`),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [details, overrides] = partitionPromptDetails(resource, launchConfig);
|
||||||
|
const hasOverrides = Object.keys(overrides).length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DetailList gutter="sm">
|
<DetailList gutter="sm">
|
||||||
<Detail label={i18n._(t`Name`)} value={resource.name} />
|
<Detail label={i18n._(t`Name`)} value={details.name} />
|
||||||
<Detail label={i18n._(t`Description`)} value={resource.description} />
|
<Detail label={i18n._(t`Description`)} value={details.description} />
|
||||||
<Detail
|
<Detail
|
||||||
label={i18n._(t`Type`)}
|
label={i18n._(t`Type`)}
|
||||||
value={resource.unified_job_type || resource.type}
|
value={toTitleCase(details.unified_job_type || details.type)}
|
||||||
/>
|
/>
|
||||||
<Detail
|
<Detail
|
||||||
label={i18n._(t`Timeout`)}
|
label={i18n._(t`Timeout`)}
|
||||||
value={formatTimeout(resource?.timeout)}
|
value={formatTimeout(details?.timeout)}
|
||||||
/>
|
/>
|
||||||
{resource?.summary_fields?.organization && (
|
{details?.summary_fields?.organization && (
|
||||||
<Detail
|
<Detail
|
||||||
label={i18n._(t`Organization`)}
|
label={i18n._(t`Organization`)}
|
||||||
value={
|
value={
|
||||||
<Link
|
<Link
|
||||||
to={`/organizations/${resource?.summary_fields.organization.id}/details`}
|
to={`/organizations/${details?.summary_fields.organization.id}/details`}
|
||||||
>
|
>
|
||||||
{resource?.summary_fields?.organization.name}
|
{details?.summary_fields?.organization.name}
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* TODO: Add JT, WFJT, Inventory Source Details */}
|
{/* TODO: Add JT, WFJT, Inventory Source Details */}
|
||||||
{resource?.type === 'project' && (
|
{details?.type === 'project' && (
|
||||||
<PromptProjectDetail resource={resource} />
|
<PromptProjectDetail resource={details} />
|
||||||
)}
|
)}
|
||||||
{resource?.type === 'inventory_source' && (
|
{details?.type === 'inventory_source' && (
|
||||||
<PromptInventorySourceDetail resource={resource} />
|
<PromptInventorySourceDetail resource={details} />
|
||||||
)}
|
)}
|
||||||
{resource?.type === 'job_template' && (
|
{details?.type === 'job_template' && (
|
||||||
<PromptJobTemplateDetail resource={resource} />
|
<PromptJobTemplateDetail resource={details} />
|
||||||
)}
|
)}
|
||||||
{resource?.type === 'workflow_job_template' && (
|
{details?.type === 'workflow_job_template' && (
|
||||||
<PromptWFJobTemplateDetail resource={resource} />
|
<PromptWFJobTemplateDetail resource={details} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<UserDateDetail
|
<UserDateDetail
|
||||||
label={i18n._(t`Created`)}
|
label={i18n._(t`Created`)}
|
||||||
date={resource?.created}
|
date={details?.created}
|
||||||
user={resource?.summary_fields?.created_by}
|
user={details?.summary_fields?.created_by}
|
||||||
/>
|
/>
|
||||||
<UserDateDetail
|
<UserDateDetail
|
||||||
label={i18n._(t`Last Modified`)}
|
label={i18n._(t`Last Modified`)}
|
||||||
date={resource?.modified}
|
date={details?.modified}
|
||||||
user={resource?.summary_fields?.modified_by}
|
user={details?.summary_fields?.modified_by}
|
||||||
/>
|
/>
|
||||||
</DetailList>
|
</DetailList>
|
||||||
|
|
||||||
{hasPromptData(launchConfig) && (
|
{hasPromptData(launchConfig) && hasOverrides && (
|
||||||
<>
|
<>
|
||||||
<PromptHeader>{i18n._(t`Prompted Values`)}</PromptHeader>
|
<PromptHeader>{i18n._(t`Prompted Values`)}</PromptHeader>
|
||||||
<DetailList>
|
<DetailList aria-label="Prompt Overrides">
|
||||||
{launchConfig.ask_job_type_on_launch && (
|
{overrides?.job_type && (
|
||||||
<Detail label={i18n._(t`Job Type`)} value={defaults?.job_type} />
|
<Detail
|
||||||
|
label={i18n._(t`Job Type`)}
|
||||||
|
value={toTitleCase(overrides.job_type)}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
{launchConfig.ask_credential_on_launch && (
|
{overrides?.credentials && (
|
||||||
<Detail
|
<Detail
|
||||||
fullWidth
|
fullWidth
|
||||||
label={i18n._(t`Credential`)}
|
label={i18n._(t`Credential`)}
|
||||||
rows={4}
|
rows={4}
|
||||||
value={
|
value={
|
||||||
<ChipGroup numChips={5}>
|
<ChipGroup numChips={5}>
|
||||||
{defaults?.credentials.map(cred => (
|
{overrides.credentials.map(cred => (
|
||||||
<Chip key={cred.id} isReadOnly>
|
<Chip key={cred.id} isReadOnly>
|
||||||
{cred.name}
|
{cred.name}
|
||||||
</Chip>
|
</Chip>
|
||||||
@@ -132,34 +224,34 @@ function PromptDetail({ i18n, resource, launchConfig = {} }) {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{launchConfig.ask_inventory_on_launch && (
|
{overrides?.inventory && (
|
||||||
<Detail
|
<Detail
|
||||||
label={i18n._(t`Inventory`)}
|
label={i18n._(t`Inventory`)}
|
||||||
value={defaults?.inventory?.name}
|
value={overrides.inventory?.name}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{launchConfig.ask_scm_branch_on_launch && (
|
{overrides?.scm_branch && (
|
||||||
<Detail
|
<Detail
|
||||||
label={i18n._(t`Source Control Branch`)}
|
label={i18n._(t`Source Control Branch`)}
|
||||||
value={defaults?.scm_branch}
|
value={overrides.scm_branch}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{launchConfig.ask_limit_on_launch && (
|
{overrides?.limit && (
|
||||||
<Detail label={i18n._(t`Limit`)} value={defaults?.limit} />
|
<Detail label={i18n._(t`Limit`)} value={overrides.limit} />
|
||||||
)}
|
)}
|
||||||
{launchConfig.ask_verbosity_on_launch && (
|
{overrides?.verbosity && (
|
||||||
<Detail
|
<Detail
|
||||||
label={i18n._(t`Verbosity`)}
|
label={i18n._(t`Verbosity`)}
|
||||||
value={VERBOSITY[(defaults?.verbosity)]}
|
value={VERBOSITY[overrides.verbosity]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{launchConfig.ask_tags_on_launch && (
|
{overrides?.job_tags && (
|
||||||
<Detail
|
<Detail
|
||||||
fullWidth
|
fullWidth
|
||||||
label={i18n._(t`Job Tags`)}
|
label={i18n._(t`Job Tags`)}
|
||||||
value={
|
value={
|
||||||
<ChipGroup numChips={5}>
|
<ChipGroup numChips={5}>
|
||||||
{defaults?.job_tags.split(',').map(jobTag => (
|
{overrides.job_tags.split(',').map(jobTag => (
|
||||||
<Chip key={jobTag} isReadOnly>
|
<Chip key={jobTag} isReadOnly>
|
||||||
{jobTag}
|
{jobTag}
|
||||||
</Chip>
|
</Chip>
|
||||||
@@ -168,13 +260,13 @@ function PromptDetail({ i18n, resource, launchConfig = {} }) {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{launchConfig.ask_skip_tags_on_launch && (
|
{overrides?.skip_tags && (
|
||||||
<Detail
|
<Detail
|
||||||
fullWidth
|
fullWidth
|
||||||
label={i18n._(t`Skip Tags`)}
|
label={i18n._(t`Skip Tags`)}
|
||||||
value={
|
value={
|
||||||
<ChipGroup numChips={5}>
|
<ChipGroup numChips={5}>
|
||||||
{defaults?.skip_tags.split(',').map(skipTag => (
|
{overrides.skip_tags.split(',').map(skipTag => (
|
||||||
<Chip key={skipTag} isReadOnly>
|
<Chip key={skipTag} isReadOnly>
|
||||||
{skipTag}
|
{skipTag}
|
||||||
</Chip>
|
</Chip>
|
||||||
@@ -183,19 +275,19 @@ function PromptDetail({ i18n, resource, launchConfig = {} }) {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{launchConfig.ask_diff_mode_on_launch && (
|
{overrides?.diff_mode && (
|
||||||
<Detail
|
<Detail
|
||||||
label={i18n._(t`Diff Mode`)}
|
label={i18n._(t`Show Changes`)}
|
||||||
value={
|
value={
|
||||||
defaults?.diff_mode === true ? i18n._(t`On`) : i18n._(t`Off`)
|
overrides.diff_mode === true ? i18n._(t`On`) : i18n._(t`Off`)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{launchConfig.ask_variables_on_launch && (
|
{overrides?.extra_vars && (
|
||||||
<VariablesDetail
|
<VariablesDetail
|
||||||
label={i18n._(t`Variables`)}
|
label={i18n._(t`Variables`)}
|
||||||
rows={4}
|
rows={4}
|
||||||
value={defaults?.extra_vars}
|
value={overrides.extra_vars}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</DetailList>
|
</DetailList>
|
||||||
|
|||||||
@@ -1,16 +1,9 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
||||||
|
import mockTemplate from './data.job_template.json';
|
||||||
|
|
||||||
import PromptDetail from './PromptDetail';
|
import PromptDetail from './PromptDetail';
|
||||||
|
|
||||||
const mockTemplate = {
|
|
||||||
name: 'Mock Template',
|
|
||||||
description: 'mock description',
|
|
||||||
unified_job_type: 'job',
|
|
||||||
created: '2019-08-08T19:24:05.344276Z',
|
|
||||||
modified: '2019-08-08T19:24:18.162949Z',
|
|
||||||
};
|
|
||||||
|
|
||||||
const mockPromptLaunch = {
|
const mockPromptLaunch = {
|
||||||
ask_credential_on_launch: true,
|
ask_credential_on_launch: true,
|
||||||
ask_diff_mode_on_launch: true,
|
ask_diff_mode_on_launch: true,
|
||||||
@@ -26,10 +19,10 @@ const mockPromptLaunch = {
|
|||||||
extra_vars: '---foo: bar',
|
extra_vars: '---foo: bar',
|
||||||
diff_mode: false,
|
diff_mode: false,
|
||||||
limit: 3,
|
limit: 3,
|
||||||
job_tags: 'one,two,three',
|
job_tags: 'T_100,T_200',
|
||||||
skip_tags: 'skip',
|
skip_tags: 'S_100,S_200',
|
||||||
job_type: 'run',
|
job_type: 'run',
|
||||||
verbosity: 1,
|
verbosity: 3,
|
||||||
inventory: {
|
inventory: {
|
||||||
name: 'Demo Inventory',
|
name: 'Demo Inventory',
|
||||||
id: 1,
|
id: 1,
|
||||||
@@ -37,12 +30,16 @@ const mockPromptLaunch = {
|
|||||||
credentials: [
|
credentials: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: 'Demo Credential',
|
kind: 'ssh',
|
||||||
credential_type: 1,
|
name: 'Credential 1',
|
||||||
passwords_needed: [],
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
kind: 'awx',
|
||||||
|
name: 'Credential 2',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
scm_branch: '123',
|
scm_branch: 'Foo branch',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,21 +68,40 @@ describe('PromptDetail', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expect(wrapper.find('PromptDetail h2').text()).toBe('Prompted Values');
|
expect(wrapper.find('PromptDetail h2').text()).toBe('Prompted Values');
|
||||||
assertDetail('Name', 'Mock Template');
|
assertDetail('Name', 'Mock JT');
|
||||||
assertDetail('Description', 'mock description');
|
assertDetail('Description', 'Mock JT Description');
|
||||||
assertDetail('Type', 'job');
|
assertDetail('Type', 'Job Template');
|
||||||
assertDetail('Job Type', 'run');
|
assertDetail('Job Type', 'Run');
|
||||||
assertDetail('Credential', 'Demo Credential');
|
|
||||||
assertDetail('Inventory', 'Demo Inventory');
|
assertDetail('Inventory', 'Demo Inventory');
|
||||||
assertDetail('Source Control Branch', '123');
|
assertDetail('Source Control Branch', 'Foo branch');
|
||||||
assertDetail('Limit', '3');
|
assertDetail('Limit', 'alpha:beta');
|
||||||
assertDetail('Verbosity', '1 (Verbose)');
|
assertDetail('Verbosity', '3 (Debug)');
|
||||||
assertDetail('Job Tags', 'onetwothree');
|
assertDetail('Show Changes', 'Off');
|
||||||
assertDetail('Skip Tags', 'skip');
|
|
||||||
assertDetail('Diff Mode', 'Off');
|
|
||||||
expect(wrapper.find('VariablesDetail').prop('value')).toEqual(
|
expect(wrapper.find('VariablesDetail').prop('value')).toEqual(
|
||||||
'---foo: bar'
|
'---foo: bar'
|
||||||
);
|
);
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('Detail[label="Credentials"]')
|
||||||
|
.containsAllMatchingElements([
|
||||||
|
<span>
|
||||||
|
<strong>SSH:</strong>Credential 1
|
||||||
|
</span>,
|
||||||
|
<span>
|
||||||
|
<strong>Awx:</strong>Credential 2
|
||||||
|
</span>,
|
||||||
|
])
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('Detail[label="Job Tags"]')
|
||||||
|
.containsAnyMatchingElements([<span>T_100</span>, <span>T_200</span>])
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('Detail[label="Skip Tags"]')
|
||||||
|
.containsAllMatchingElements([<span>S_100</span>, <span>S_200</span>])
|
||||||
|
).toEqual(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -106,8 +122,11 @@ describe('PromptDetail', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should not render promptable details', () => {
|
test('should not render promptable details', () => {
|
||||||
|
const overrideDetails = wrapper.find(
|
||||||
|
'DetailList[aria-label="Prompt Overrides"]'
|
||||||
|
);
|
||||||
function assertNoDetail(label) {
|
function assertNoDetail(label) {
|
||||||
expect(wrapper.find(`Detail[label="${label}"]`).length).toBe(0);
|
expect(overrideDetails.find(`Detail[label="${label}"]`).length).toBe(0);
|
||||||
}
|
}
|
||||||
[
|
[
|
||||||
'Job Type',
|
'Job Type',
|
||||||
@@ -120,8 +139,8 @@ describe('PromptDetail', () => {
|
|||||||
'Skip Tags',
|
'Skip Tags',
|
||||||
'Diff Mode',
|
'Diff Mode',
|
||||||
].forEach(label => assertNoDetail(label));
|
].forEach(label => assertNoDetail(label));
|
||||||
expect(wrapper.find('PromptDetail h2').length).toBe(0);
|
expect(overrideDetails.find('PromptDetail h2').length).toBe(0);
|
||||||
expect(wrapper.find('VariablesDetail').length).toBe(0);
|
expect(overrideDetails.find('VariablesDetail').length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,207 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { CardBody } from '@components/Card';
|
import { withI18n } from '@lingui/react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
function PromptJobTemplateDetail() {
|
import { Chip, ChipGroup, List, ListItem } from '@patternfly/react-core';
|
||||||
return <CardBody>Coming soon :)</CardBody>;
|
import { Detail } from '@components/DetailList';
|
||||||
|
import { VariablesDetail } from '@components/CodeMirrorInput';
|
||||||
|
import CredentialChip from '@components/CredentialChip';
|
||||||
|
import Sparkline from '@components/Sparkline';
|
||||||
|
import { toTitleCase } from '@util/strings';
|
||||||
|
|
||||||
|
function PromptJobTemplateDetail({ i18n, resource }) {
|
||||||
|
const {
|
||||||
|
allow_simultaneous,
|
||||||
|
become_enabled,
|
||||||
|
diff_mode,
|
||||||
|
extra_vars,
|
||||||
|
forks,
|
||||||
|
host_config_key,
|
||||||
|
instance_groups,
|
||||||
|
job_slice_count,
|
||||||
|
job_tags,
|
||||||
|
job_type,
|
||||||
|
limit,
|
||||||
|
playbook,
|
||||||
|
scm_branch,
|
||||||
|
skip_tags,
|
||||||
|
summary_fields,
|
||||||
|
url,
|
||||||
|
use_fact_cache,
|
||||||
|
verbosity,
|
||||||
|
} = resource;
|
||||||
|
|
||||||
|
const VERBOSITY = {
|
||||||
|
0: i18n._(t`0 (Normal)`),
|
||||||
|
1: i18n._(t`1 (Verbose)`),
|
||||||
|
2: i18n._(t`2 (More Verbose)`),
|
||||||
|
3: i18n._(t`3 (Debug)`),
|
||||||
|
4: i18n._(t`4 (Connection Debug)`),
|
||||||
|
};
|
||||||
|
|
||||||
|
let optionsList = '';
|
||||||
|
if (
|
||||||
|
become_enabled ||
|
||||||
|
host_config_key ||
|
||||||
|
allow_simultaneous ||
|
||||||
|
use_fact_cache
|
||||||
|
) {
|
||||||
|
optionsList = (
|
||||||
|
<List>
|
||||||
|
{become_enabled && (
|
||||||
|
<ListItem>{i18n._(t`Enable Privilege Escalation`)}</ListItem>
|
||||||
|
)}
|
||||||
|
{host_config_key && (
|
||||||
|
<ListItem>{i18n._(t`Allow Provisioning Callbacks`)}</ListItem>
|
||||||
|
)}
|
||||||
|
{allow_simultaneous && (
|
||||||
|
<ListItem>{i18n._(t`Enable Concurrent Jobs`)}</ListItem>
|
||||||
|
)}
|
||||||
|
{use_fact_cache && <ListItem>{i18n._(t`Use Fact Storage`)}</ListItem>}
|
||||||
|
</List>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const inventoryKind =
|
||||||
|
summary_fields?.inventory?.kind === 'smart'
|
||||||
|
? 'smart_inventory'
|
||||||
|
: 'inventory';
|
||||||
|
|
||||||
|
const recentJobs = summary_fields.recent_jobs.map(job => ({
|
||||||
|
...job,
|
||||||
|
type: 'job',
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{summary_fields.recent_jobs?.length > 0 && (
|
||||||
|
<Detail
|
||||||
|
value={<Sparkline jobs={recentJobs} />}
|
||||||
|
label={i18n._(t`Activity`)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Detail label={i18n._(t`Job Type`)} value={toTitleCase(job_type)} />
|
||||||
|
{summary_fields?.inventory && (
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Inventory`)}
|
||||||
|
value={
|
||||||
|
<Link
|
||||||
|
to={`/${inventoryKind}/${summary_fields.inventory?.id}/details`}
|
||||||
|
>
|
||||||
|
{summary_fields.inventory?.name}
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{summary_fields?.project && (
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Project`)}
|
||||||
|
value={
|
||||||
|
<Link to={`/projects/${summary_fields.project?.id}/details`}>
|
||||||
|
{summary_fields.project?.name}
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Detail label={i18n._(t`Source Control Branch`)} value={scm_branch} />
|
||||||
|
<Detail label={i18n._(t`Playbook`)} value={playbook} />
|
||||||
|
<Detail label={i18n._(t`Forks`)} value={forks || '0'} />
|
||||||
|
<Detail label={i18n._(t`Limit`)} value={limit} />
|
||||||
|
<Detail label={i18n._(t`Verbosity`)} value={VERBOSITY[verbosity]} />
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Show Changes`)}
|
||||||
|
value={diff_mode ? 'On' : 'Off'}
|
||||||
|
/>
|
||||||
|
<Detail label={i18n._(t` Job Slicing`)} value={job_slice_count} />
|
||||||
|
{host_config_key && (
|
||||||
|
<React.Fragment>
|
||||||
|
<Detail label={i18n._(t`Host Config Key`)} value={host_config_key} />
|
||||||
|
<Detail
|
||||||
|
label={i18n._(t`Provisioning Callback URL`)}
|
||||||
|
value={`${window.location.origin + url}callback/`}
|
||||||
|
/>
|
||||||
|
</React.Fragment>
|
||||||
|
)}
|
||||||
|
{optionsList && <Detail label={i18n._(t`Options`)} value={optionsList} />}
|
||||||
|
{summary_fields?.credentials?.length > 0 && (
|
||||||
|
<Detail
|
||||||
|
fullWidth
|
||||||
|
label={i18n._(t`Credentials`)}
|
||||||
|
value={summary_fields.credentials.map(chip => (
|
||||||
|
<CredentialChip key={chip.id} credential={chip} isReadOnly />
|
||||||
|
))}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{summary_fields?.labels?.results?.length > 0 && (
|
||||||
|
<Detail
|
||||||
|
fullWidth
|
||||||
|
label={i18n._(t`Labels`)}
|
||||||
|
value={
|
||||||
|
<ChipGroup numChips={5}>
|
||||||
|
{summary_fields.labels.results.map(label => (
|
||||||
|
<Chip key={label.id} isReadOnly>
|
||||||
|
{label.name}
|
||||||
|
</Chip>
|
||||||
|
))}
|
||||||
|
</ChipGroup>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{instance_groups?.length > 0 && (
|
||||||
|
<Detail
|
||||||
|
fullWidth
|
||||||
|
label={i18n._(t`Instance Groups`)}
|
||||||
|
value={
|
||||||
|
<ChipGroup numChips={5}>
|
||||||
|
{instance_groups.map(ig => (
|
||||||
|
<Chip key={ig.id} isReadOnly>
|
||||||
|
{ig.name}
|
||||||
|
</Chip>
|
||||||
|
))}
|
||||||
|
</ChipGroup>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{job_tags?.length > 0 && (
|
||||||
|
<Detail
|
||||||
|
fullWidth
|
||||||
|
label={i18n._(t`Job Tags`)}
|
||||||
|
value={
|
||||||
|
<ChipGroup numChips={5}>
|
||||||
|
{job_tags.split(',').map(jobTag => (
|
||||||
|
<Chip key={jobTag} isReadOnly>
|
||||||
|
{jobTag}
|
||||||
|
</Chip>
|
||||||
|
))}
|
||||||
|
</ChipGroup>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{skip_tags?.length > 0 && (
|
||||||
|
<Detail
|
||||||
|
fullWidth
|
||||||
|
label={i18n._(t`Skip Tags`)}
|
||||||
|
value={
|
||||||
|
<ChipGroup numChips={5}>
|
||||||
|
{skip_tags.split(',').map(skipTag => (
|
||||||
|
<Chip key={skipTag} isReadOnly>
|
||||||
|
{skipTag}
|
||||||
|
</Chip>
|
||||||
|
))}
|
||||||
|
</ChipGroup>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{extra_vars && (
|
||||||
|
<VariablesDetail
|
||||||
|
label={i18n._(t`Variables`)}
|
||||||
|
rows={4}
|
||||||
|
value={extra_vars}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PromptJobTemplateDetail;
|
export default withI18n()(PromptJobTemplateDetail);
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
||||||
|
import PromptJobTemplateDetail from './PromptJobTemplateDetail';
|
||||||
|
import mockData from './data.job_template.json';
|
||||||
|
|
||||||
|
const mockJT = {
|
||||||
|
...mockData,
|
||||||
|
instance_groups: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'ig1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'ig2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('PromptJobTemplateDetail', () => {
|
||||||
|
let wrapper;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
wrapper = mountWithContexts(<PromptJobTemplateDetail resource={mockJT} />);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render successfully', () => {
|
||||||
|
expect(wrapper.find('PromptJobTemplateDetail')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should render expected 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertDetail('Job Type', 'Run');
|
||||||
|
assertDetail('Inventory', 'Demo Inventory');
|
||||||
|
assertDetail('Project', 'Mock Project');
|
||||||
|
assertDetail('Source Control Branch', 'Foo branch');
|
||||||
|
assertDetail('Playbook', 'ping.yml');
|
||||||
|
assertDetail('Forks', '2');
|
||||||
|
assertDetail('Limit', 'alpha:beta');
|
||||||
|
assertDetail('Verbosity', '3 (Debug)');
|
||||||
|
assertDetail('Show Changes', 'Off');
|
||||||
|
assertDetail('Job Slicing', '1');
|
||||||
|
assertDetail('Host Config Key', 'a1b2c3');
|
||||||
|
expect(
|
||||||
|
wrapper.find('Detail[label="Provisioning Callback URL"] dd').text()
|
||||||
|
).toEqual(expect.stringContaining('/api/v2/job_templates/7/callback/'));
|
||||||
|
expect(
|
||||||
|
wrapper.find('Detail[label="Credentials"]').containsAllMatchingElements([
|
||||||
|
<span>
|
||||||
|
<strong>SSH:</strong>Credential 1
|
||||||
|
</span>,
|
||||||
|
<span>
|
||||||
|
<strong>Awx:</strong>Credential 2
|
||||||
|
</span>,
|
||||||
|
])
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('Detail[label="Labels"]')
|
||||||
|
.containsAllMatchingElements([<span>L_91o2</span>, <span>L_91o3</span>])
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('Detail[label="Instance Groups"]')
|
||||||
|
.containsAllMatchingElements([<span>ig1</span>, <span>ig2</span>])
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('Detail[label="Job Tags"]')
|
||||||
|
.containsAllMatchingElements([<span>T_100</span>, <span>T_200</span>])
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('Detail[label="Skip Tags"]')
|
||||||
|
.containsAllMatchingElements([<span>S_100</span>, <span>S_200</span>])
|
||||||
|
).toEqual(true);
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('Detail[label="Options"]')
|
||||||
|
.containsAllMatchingElements([
|
||||||
|
<li>Enable Privilege Escalation</li>,
|
||||||
|
<li>Allow Provisioning Callbacks</li>,
|
||||||
|
<li>Enable Concurrent Jobs</li>,
|
||||||
|
<li>Use Fact Storage</li>,
|
||||||
|
])
|
||||||
|
).toEqual(true);
|
||||||
|
expect(wrapper.find('VariablesDetail').prop('value')).toEqual(
|
||||||
|
'---foo: bar'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
178
awx/ui_next/src/components/PromptDetail/data.job_template.json
Normal file
178
awx/ui_next/src/components/PromptDetail/data.job_template.json
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"type": "job_template",
|
||||||
|
"url": "/api/v2/job_templates/7/",
|
||||||
|
"related": {
|
||||||
|
"named_url": "/api/v2/job_templates/MockJT/",
|
||||||
|
"created_by": "/api/v2/users/1/",
|
||||||
|
"modified_by": "/api/v2/users/1/",
|
||||||
|
"labels": "/api/v2/job_templates/7/labels/",
|
||||||
|
"inventory": "/api/v2/inventories/1/",
|
||||||
|
"project": "/api/v2/projects/6/",
|
||||||
|
"extra_credentials": "/api/v2/job_templates/7/extra_credentials/",
|
||||||
|
"credentials": "/api/v2/job_templates/7/credentials/",
|
||||||
|
"last_job": "/api/v2/jobs/12/",
|
||||||
|
"jobs": "/api/v2/job_templates/7/jobs/",
|
||||||
|
"schedules": "/api/v2/job_templates/7/schedules/",
|
||||||
|
"activity_stream": "/api/v2/job_templates/7/activity_stream/",
|
||||||
|
"launch": "/api/v2/job_templates/7/launch/",
|
||||||
|
"notification_templates_started": "/api/v2/job_templates/7/notification_templates_started/",
|
||||||
|
"notification_templates_success": "/api/v2/job_templates/7/notification_templates_success/",
|
||||||
|
"notification_templates_error": "/api/v2/job_templates/7/notification_templates_error/",
|
||||||
|
"access_list": "/api/v2/job_templates/7/access_list/",
|
||||||
|
"survey_spec": "/api/v2/job_templates/7/survey_spec/",
|
||||||
|
"object_roles": "/api/v2/job_templates/7/object_roles/",
|
||||||
|
"instance_groups": "/api/v2/job_templates/7/instance_groups/",
|
||||||
|
"slice_workflow_jobs": "/api/v2/job_templates/7/slice_workflow_jobs/",
|
||||||
|
"copy": "/api/v2/job_templates/7/copy/"
|
||||||
|
},
|
||||||
|
"summary_fields": {
|
||||||
|
"inventory": {
|
||||||
|
"id": 1,
|
||||||
|
"name": "Demo Inventory",
|
||||||
|
"description": "",
|
||||||
|
"has_active_failures": false,
|
||||||
|
"total_hosts": 1,
|
||||||
|
"hosts_with_active_failures": 0,
|
||||||
|
"total_groups": 0,
|
||||||
|
"groups_with_active_failures": 0,
|
||||||
|
"has_inventory_sources": false,
|
||||||
|
"total_inventory_sources": 0,
|
||||||
|
"inventory_sources_with_failures": 0,
|
||||||
|
"organization_id": 1,
|
||||||
|
"kind": ""
|
||||||
|
},
|
||||||
|
"project": {
|
||||||
|
"id": 6,
|
||||||
|
"name": "Mock Project",
|
||||||
|
"description": "",
|
||||||
|
"status": "successful",
|
||||||
|
"scm_type": "git"
|
||||||
|
},
|
||||||
|
"last_job": {
|
||||||
|
"id": 12,
|
||||||
|
"name": "Mock JT",
|
||||||
|
"description": "",
|
||||||
|
"finished": "2019-10-01T14:34:35.142483Z",
|
||||||
|
"status": "successful",
|
||||||
|
"failed": false
|
||||||
|
},
|
||||||
|
"last_update": {
|
||||||
|
"id": 12,
|
||||||
|
"name": "Mock JT",
|
||||||
|
"description": "",
|
||||||
|
"status": "successful",
|
||||||
|
"failed": false
|
||||||
|
},
|
||||||
|
"created_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"modified_by": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
"object_roles": {
|
||||||
|
"admin_role": {
|
||||||
|
"description": "Can manage all aspects of the job template",
|
||||||
|
"name": "Admin",
|
||||||
|
"id": 24
|
||||||
|
},
|
||||||
|
"execute_role": {
|
||||||
|
"description": "May run the job template",
|
||||||
|
"name": "Execute",
|
||||||
|
"id": 25
|
||||||
|
},
|
||||||
|
"read_role": {
|
||||||
|
"description": "May view settings for the job template",
|
||||||
|
"name": "Read",
|
||||||
|
"id": 26
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"user_capabilities": {
|
||||||
|
"edit": true,
|
||||||
|
"delete": true,
|
||||||
|
"start": true,
|
||||||
|
"schedule": true,
|
||||||
|
"copy": true
|
||||||
|
},
|
||||||
|
"labels": {
|
||||||
|
"count": 1,
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"id": 91,
|
||||||
|
"name": "L_91o2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 92,
|
||||||
|
"name": "L_91o3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"survey": {
|
||||||
|
"title": "",
|
||||||
|
"description": ""
|
||||||
|
},
|
||||||
|
"recent_jobs": [
|
||||||
|
{
|
||||||
|
"id": 12,
|
||||||
|
"status": "successful",
|
||||||
|
"finished": "2019-10-01T14:34:35.142483Z",
|
||||||
|
"type": "job"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extra_credentials": [],
|
||||||
|
"credentials": [
|
||||||
|
{
|
||||||
|
"id": 1, "kind": "ssh" , "name": "Credential 1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2, "kind": "awx" , "name": "Credential 2"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"created": "2019-09-30T16:18:34.564820Z",
|
||||||
|
"modified": "2019-10-01T14:47:31.818431Z",
|
||||||
|
"name": "Mock JT",
|
||||||
|
"description": "Mock JT Description",
|
||||||
|
"job_type": "run",
|
||||||
|
"inventory": 1,
|
||||||
|
"project": 6,
|
||||||
|
"playbook": "ping.yml",
|
||||||
|
"scm_branch": "Foo branch",
|
||||||
|
"forks": 2,
|
||||||
|
"limit": "alpha:beta",
|
||||||
|
"verbosity": 3,
|
||||||
|
"extra_vars": "---foo: bar",
|
||||||
|
"job_tags": "T_100,T_200",
|
||||||
|
"force_handlers": false,
|
||||||
|
"skip_tags": "S_100,S_200",
|
||||||
|
"start_at_task": "",
|
||||||
|
"timeout": 0,
|
||||||
|
"use_fact_cache": true,
|
||||||
|
"last_job_run": "2019-10-01T14:34:35.142483Z",
|
||||||
|
"last_job_failed": false,
|
||||||
|
"next_job_run": null,
|
||||||
|
"status": "successful",
|
||||||
|
"host_config_key": "a1b2c3",
|
||||||
|
"ask_scm_branch_on_launch": false,
|
||||||
|
"ask_diff_mode_on_launch": false,
|
||||||
|
"ask_variables_on_launch": false,
|
||||||
|
"ask_limit_on_launch": false,
|
||||||
|
"ask_tags_on_launch": false,
|
||||||
|
"ask_skip_tags_on_launch": false,
|
||||||
|
"ask_job_type_on_launch": false,
|
||||||
|
"ask_verbosity_on_launch": false,
|
||||||
|
"ask_inventory_on_launch": false,
|
||||||
|
"ask_credential_on_launch": false,
|
||||||
|
"survey_enabled": true,
|
||||||
|
"become_enabled": true,
|
||||||
|
"diff_mode": false,
|
||||||
|
"allow_simultaneous": true,
|
||||||
|
"custom_virtualenv": null,
|
||||||
|
"job_slice_count": 1
|
||||||
|
}
|
||||||
@@ -294,7 +294,7 @@ function JobTemplateDetail({ i18n, template }) {
|
|||||||
{job_tags && job_tags.length > 0 && (
|
{job_tags && job_tags.length > 0 && (
|
||||||
<Detail
|
<Detail
|
||||||
fullWidth
|
fullWidth
|
||||||
label={i18n._(t`Job tags`)}
|
label={i18n._(t`Job Tags`)}
|
||||||
value={
|
value={
|
||||||
<ChipGroup numChips={5}>
|
<ChipGroup numChips={5}>
|
||||||
{job_tags.split(',').map(jobTag => (
|
{job_tags.split(',').map(jobTag => (
|
||||||
@@ -309,7 +309,7 @@ function JobTemplateDetail({ i18n, template }) {
|
|||||||
{skip_tags && skip_tags.length > 0 && (
|
{skip_tags && skip_tags.length > 0 && (
|
||||||
<Detail
|
<Detail
|
||||||
fullWidth
|
fullWidth
|
||||||
label={i18n._(t`Skip tags`)}
|
label={i18n._(t`Skip Tags`)}
|
||||||
value={
|
value={
|
||||||
<ChipGroup numChips={5}>
|
<ChipGroup numChips={5}>
|
||||||
{skip_tags.split(',').map(skipTag => (
|
{skip_tags.split(',').map(skipTag => (
|
||||||
|
|||||||
@@ -71,7 +71,14 @@ function NodeViewModal({ i18n }) {
|
|||||||
request: fetchNodeDetail,
|
request: fetchNodeDetail,
|
||||||
} = useRequest(
|
} = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
const { data } = await nodeAPI?.readDetail(unifiedJobTemplate.id);
|
let { data } = await nodeAPI?.readDetail(unifiedJobTemplate.id);
|
||||||
|
if (data?.type === 'job_template') {
|
||||||
|
const {
|
||||||
|
data: { results = [] },
|
||||||
|
} = await JobTemplatesAPI.readInstanceGroups(data.id);
|
||||||
|
data = Object.assign(data, { instance_groups: results });
|
||||||
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}, [nodeAPI, unifiedJobTemplate.id]),
|
}, [nodeAPI, unifiedJobTemplate.id]),
|
||||||
null
|
null
|
||||||
|
|||||||
@@ -13,6 +13,13 @@ jest.mock('@api/models/WorkflowJobTemplates');
|
|||||||
WorkflowJobTemplatesAPI.readLaunch.mockResolvedValue({});
|
WorkflowJobTemplatesAPI.readLaunch.mockResolvedValue({});
|
||||||
WorkflowJobTemplatesAPI.readDetail.mockResolvedValue({});
|
WorkflowJobTemplatesAPI.readDetail.mockResolvedValue({});
|
||||||
JobTemplatesAPI.readLaunch.mockResolvedValue({});
|
JobTemplatesAPI.readLaunch.mockResolvedValue({});
|
||||||
|
JobTemplatesAPI.readInstanceGroups.mockResolvedValue({});
|
||||||
|
JobTemplatesAPI.readDetail.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
id: 1,
|
||||||
|
type: 'job_template',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const dispatch = jest.fn();
|
const dispatch = jest.fn();
|
||||||
|
|
||||||
@@ -64,6 +71,8 @@ describe('NodeViewModal', () => {
|
|||||||
|
|
||||||
test('should fetch workflow template launch data', () => {
|
test('should fetch workflow template launch data', () => {
|
||||||
expect(JobTemplatesAPI.readLaunch).not.toHaveBeenCalled();
|
expect(JobTemplatesAPI.readLaunch).not.toHaveBeenCalled();
|
||||||
|
expect(JobTemplatesAPI.readDetail).not.toHaveBeenCalled();
|
||||||
|
expect(JobTemplatesAPI.readInstanceGroups).not.toHaveBeenCalled();
|
||||||
expect(WorkflowJobTemplatesAPI.readLaunch).toHaveBeenCalledWith(1);
|
expect(WorkflowJobTemplatesAPI.readLaunch).toHaveBeenCalledWith(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -95,7 +104,7 @@ describe('NodeViewModal', () => {
|
|||||||
id: 1,
|
id: 1,
|
||||||
name: 'Mock Node',
|
name: 'Mock Node',
|
||||||
description: '',
|
description: '',
|
||||||
type: 'job_template',
|
unified_job_type: 'job',
|
||||||
created: '2019-08-08T19:24:05.344276Z',
|
created: '2019-08-08T19:24:05.344276Z',
|
||||||
modified: '2019-08-08T19:24:18.162949Z',
|
modified: '2019-08-08T19:24:18.162949Z',
|
||||||
},
|
},
|
||||||
@@ -104,6 +113,7 @@ describe('NodeViewModal', () => {
|
|||||||
|
|
||||||
test('should fetch job template launch data', async () => {
|
test('should fetch job template launch data', async () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<WorkflowDispatchContext.Provider value={dispatch}>
|
<WorkflowDispatchContext.Provider value={dispatch}>
|
||||||
@@ -116,6 +126,8 @@ describe('NodeViewModal', () => {
|
|||||||
waitForLoaded(wrapper);
|
waitForLoaded(wrapper);
|
||||||
expect(WorkflowJobTemplatesAPI.readLaunch).not.toHaveBeenCalled();
|
expect(WorkflowJobTemplatesAPI.readLaunch).not.toHaveBeenCalled();
|
||||||
expect(JobTemplatesAPI.readLaunch).toHaveBeenCalledWith(1);
|
expect(JobTemplatesAPI.readLaunch).toHaveBeenCalledWith(1);
|
||||||
|
expect(JobTemplatesAPI.readDetail).toHaveBeenCalledWith(1);
|
||||||
|
expect(JobTemplatesAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
@@ -167,6 +179,7 @@ describe('NodeViewModal', () => {
|
|||||||
waitForLoaded(wrapper);
|
waitForLoaded(wrapper);
|
||||||
expect(WorkflowJobTemplatesAPI.readLaunch).not.toHaveBeenCalled();
|
expect(WorkflowJobTemplatesAPI.readLaunch).not.toHaveBeenCalled();
|
||||||
expect(JobTemplatesAPI.readLaunch).not.toHaveBeenCalled();
|
expect(JobTemplatesAPI.readLaunch).not.toHaveBeenCalled();
|
||||||
|
expect(JobTemplatesAPI.readInstanceGroups).not.toHaveBeenCalled();
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user