Merge pull request #6570 from marshmalien/6530-wf-node-inv-src-details

Add Inventory Source workflow node prompt details

Reviewed-by: https://github.com/apps/softwarefactory-project-zuul
This commit is contained in:
softwarefactory-project-zuul[bot] 2020-04-06 16:10:33 +00:00 committed by GitHub
commit 646e403fbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 546 additions and 0 deletions

View File

@ -10,6 +10,9 @@ import { VariablesDetail } from '@components/CodeMirrorInput';
import { DetailList, Detail, UserDateDetail } from '@components/DetailList';
import PromptProjectDetail from './PromptProjectDetail';
import PromptInventorySourceDetail from './PromptInventorySourceDetail';
import PromptJobTemplateDetail from './PromptJobTemplateDetail';
import PromptWFJobTemplateDetail from './PromptWFJobTemplateDetail';
const PromptHeader = styled.h2`
font-weight: bold;
@ -84,6 +87,15 @@ function PromptDetail({ i18n, resource, launchConfig = {} }) {
{resource?.type === 'project' && (
<PromptProjectDetail resource={resource} />
)}
{resource?.type === 'inventory_source' && (
<PromptInventorySourceDetail resource={resource} />
)}
{resource?.type === 'job_template' && (
<PromptJobTemplateDetail resource={resource} />
)}
{resource?.type === 'workflow_job_template' && (
<PromptWFJobTemplateDetail resource={resource} />
)}
<UserDateDetail
label={i18n._(t`Created`)}

View File

@ -0,0 +1,161 @@
import React from 'react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { Link } from 'react-router-dom';
import { Chip, ChipGroup, List, ListItem } from '@patternfly/react-core';
import { Detail } from '@components/DetailList';
import { VariablesDetail } from '@components/CodeMirrorInput';
import CredentialChip from '@components/CredentialChip';
function PromptInventorySourceDetail({ i18n, resource }) {
const {
custom_virtualenv,
group_by,
instance_filters,
overwrite,
overwrite_vars,
source,
source_regions,
source_vars,
source_path,
summary_fields,
update_cache_timeout,
update_on_launch,
update_on_project_update,
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 (
overwrite ||
overwrite_vars ||
update_on_launch ||
update_on_project_update
) {
optionsList = (
<List>
{overwrite && <ListItem>{i18n._(t`Overwrite`)}</ListItem>}
{overwrite_vars && (
<ListItem>{i18n._(t`Overwrite Variables`)}</ListItem>
)}
{update_on_launch && <ListItem>{i18n._(t`Update on Launch`)}</ListItem>}
{update_on_project_update && (
<ListItem>{i18n._(t`Update on Project Update`)}</ListItem>
)}
</List>
);
}
return (
<>
{summary_fields?.inventory && (
<Detail
label={i18n._(t`Inventory`)}
value={
<Link to={`/inventories/${summary_fields.inventory?.id}/details`}>
{summary_fields?.inventory?.name}
</Link>
}
/>
)}
<Detail label={i18n._(t`Source`)} value={source} />
<Detail
label={i18n._(t`Ansible Environment`)}
value={custom_virtualenv}
/>
{summary_fields?.source_project && (
<Detail
label={i18n._(t`Project`)}
value={
<Link to={`/projects/${summary_fields.source_project?.id}/details`}>
{summary_fields.source_project?.name}
</Link>
}
/>
)}
<Detail label={i18n._(t`Inventory File`)} value={source_path} />
<Detail
label={i18n._(t`Custom Inventory Script`)}
value={summary_fields?.source_script?.name}
/>
<Detail label={i18n._(t`Verbosity`)} value={VERBOSITY[verbosity]} />
<Detail
label={i18n._(t`Cache Timeout`)}
value={`${update_cache_timeout} ${i18n._(t`Seconds`)}`}
/>
{summary_fields?.credentials?.length > 0 && (
<Detail
fullWidth
label={i18n._(t`Credential`)}
value={summary_fields.credentials.map(cred => (
<CredentialChip key={cred?.id} credential={cred} isReadOnly />
))}
/>
)}
{source_regions && (
<Detail
fullWidth
label={i18n._(t`Regions`)}
value={
<ChipGroup numChips={5}>
{source_regions.split(',').map(region => (
<Chip key={region} isReadOnly>
{region}
</Chip>
))}
</ChipGroup>
}
/>
)}
{instance_filters && (
<Detail
fullWidth
label={i18n._(t`Instance Filters`)}
value={
<ChipGroup numChips={5}>
{instance_filters.split(',').map(filter => (
<Chip key={filter} isReadOnly>
{filter}
</Chip>
))}
</ChipGroup>
}
/>
)}
{group_by && (
<Detail
fullWidth
label={i18n._(t`Only Group By`)}
value={
<ChipGroup numChips={5}>
{group_by.split(',').map(group => (
<Chip key={group} isReadOnly>
{group}
</Chip>
))}
</ChipGroup>
}
/>
)}
{optionsList && <Detail label={i18n._(t`Options`)} value={optionsList} />}
{source_vars && (
<VariablesDetail
label={i18n._(t`Source Variables`)}
rows={4}
value={source_vars}
/>
)}
</>
);
}
export default withI18n()(PromptInventorySourceDetail);

View File

@ -0,0 +1,77 @@
import React from 'react';
import { mountWithContexts } from '@testUtils/enzymeHelpers';
import PromptInventorySourceDetail from './PromptInventorySourceDetail';
import mockInvSource from './data.inventory_source.json';
describe('PromptInventorySourceDetail', () => {
let wrapper;
beforeAll(() => {
wrapper = mountWithContexts(
<PromptInventorySourceDetail resource={mockInvSource} />
);
});
afterAll(() => {
wrapper.unmount();
});
test('should render successfully', () => {
expect(wrapper.find('PromptInventorySourceDetail')).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('Inventory', 'Demo Inventory');
assertDetail('Source', 'scm');
assertDetail('Project', 'Mock Project');
assertDetail('Inventory File', 'foo');
assertDetail('Custom Inventory Script', 'Mock Script');
assertDetail('Verbosity', '2 (More Verbose)');
assertDetail('Cache Timeout', '2 Seconds');
expect(
wrapper
.find('Detail[label="Regions"]')
.containsAllMatchingElements([
<span>us-east-1</span>,
<span>us-east-2</span>,
])
).toEqual(true);
expect(
wrapper
.find('Detail[label="Instance Filters"]')
.containsAllMatchingElements([
<span>filter1</span>,
<span>filter2</span>,
<span>filter3</span>,
])
).toEqual(true);
expect(
wrapper
.find('Detail[label="Only Group By"]')
.containsAllMatchingElements([
<span>group1</span>,
<span>group2</span>,
<span>group3</span>,
])
).toEqual(true);
expect(wrapper.find('CredentialChip').text()).toBe('Cloud: mock cred');
expect(wrapper.find('VariablesDetail').prop('value')).toEqual(
'---\nfoo: bar'
);
expect(
wrapper
.find('Detail[label="Options"]')
.containsAllMatchingElements([
<li>Overwrite</li>,
<li>Overwrite Variables</li>,
<li>Update on Launch</li>,
<li>Update on Project Update</li>,
])
).toEqual(true);
});
});

View File

@ -0,0 +1,8 @@
import React from 'react';
import { CardBody } from '@components/Card';
function PromptJobTemplateDetail() {
return <CardBody>Coming soon :)</CardBody>;
}
export default PromptJobTemplateDetail;

View File

@ -0,0 +1,55 @@
import React from 'react';
import { mountWithContexts } from '@testUtils/enzymeHelpers';
import PromptProjectDetail from './PromptProjectDetail';
import mockProject from './data.project.json';
describe('PromptProjectDetail', () => {
let wrapper;
beforeAll(() => {
const config = {
project_base_dir: 'dir/foo/bar',
};
wrapper = mountWithContexts(
<PromptProjectDetail resource={mockProject} />,
{
context: { config },
}
);
});
afterAll(() => {
wrapper.unmount();
});
test('should render successfully', () => {
expect(wrapper.find('PromptProjectDetail')).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('SCM Type', 'Git');
assertDetail('SCM URL', 'https://github.com/ansible/ansible-tower-samples');
assertDetail('SCM Branch', 'foo');
assertDetail('SCM Refspec', 'refs/');
assertDetail('Cache Timeout', '3 Seconds');
assertDetail('Ansible Environment', 'mock virtual env');
assertDetail('Project Base Path', 'dir/foo/bar');
assertDetail('Playbook Directory', '_6__demo_project');
assertDetail('SCM Credential', 'Scm: mock scm');
expect(
wrapper
.find('Detail[label="Options"]')
.containsAllMatchingElements([
<li>Clean</li>,
<li>Delete on Update</li>,
<li>Update Revision on Launch</li>,
<li>Allow Branch Override</li>,
])
).toEqual(true);
});
});

View File

@ -0,0 +1,8 @@
import React from 'react';
import { CardBody } from '@components/Card';
function PromptWFJobTemplateDetail() {
return <CardBody>Coming soon :)</CardBody>;
}
export default PromptWFJobTemplateDetail;

View File

@ -0,0 +1,118 @@
{
"id":53,
"type":"inventory_source",
"url":"/api/v2/inventory_sources/53/",
"related":{
"named_url":"/api/v2/inventory_sources/src++Demo Inventory++Default/",
"created_by":"/api/v2/users/1/",
"modified_by":"/api/v2/users/1/",
"update":"/api/v2/inventory_sources/53/update/",
"inventory_updates":"/api/v2/inventory_sources/53/inventory_updates/",
"schedules":"/api/v2/inventory_sources/53/schedules/",
"activity_stream":"/api/v2/inventory_sources/53/activity_stream/",
"hosts":"/api/v2/inventory_sources/53/hosts/",
"groups":"/api/v2/inventory_sources/53/groups/",
"notification_templates_started":"/api/v2/inventory_sources/53/notification_templates_started/",
"notification_templates_success":"/api/v2/inventory_sources/53/notification_templates_success/",
"notification_templates_error":"/api/v2/inventory_sources/53/notification_templates_error/",
"inventory":"/api/v2/inventories/1/",
"source_project":"/api/v2/projects/8/",
"credentials":"/api/v2/inventory_sources/53/credentials/"
},
"summary_fields":{
"organization":{
"id":1,
"name":"Default",
"description":""
},
"inventory":{
"id":1,
"name":"Demo Inventory",
"description":"",
"has_active_failures":false,
"total_hosts":1,
"hosts_with_active_failures":0,
"total_groups":2,
"has_inventory_sources":true,
"total_inventory_sources":5,
"inventory_sources_with_failures":0,
"organization_id":1,
"kind":""
},
"source_project":{
"id":8,
"name":"Mock Project",
"description":"",
"status":"never updated",
"scm_type":"git"
},
"source_script": {
"name": "Mock Script",
"description": ""
},
"created_by":{
"id":1,
"username":"admin",
"first_name":"",
"last_name":""
},
"modified_by":{
"id":1,
"username":"admin",
"first_name":"",
"last_name":""
},
"user_capabilities":{
"edit":true,
"delete":true,
"start":true,
"schedule":true
},
"credential": {
"id": 8,
"name": "mock cred",
"description": "",
"kind": "vmware",
"cloud": true,
"credential_type_id": 7
},
"credentials":[
{
"id": 8,
"name": "mock cred",
"description": "",
"kind": "vmware",
"cloud": true,
"credential_type_id": 7
}
]
},
"created":"2020-04-02T18:59:08.474167Z",
"modified":"2020-04-02T19:52:23.924252Z",
"name":"mock inv source",
"description":"mock description",
"source":"scm",
"source_path": "foo",
"source_script": "Mock Script",
"source_vars":"---\nfoo: bar",
"credential": 8,
"source_regions": "us-east-1,us-east-2",
"instance_filters": "filter1,filter2,filter3",
"group_by": "group1,group2,group3",
"overwrite":true,
"overwrite_vars":true,
"custom_virtualenv":null,
"timeout":0,
"verbosity":2,
"last_job_run":null,
"last_job_failed":false,
"next_job_run":null,
"status":"never updated",
"inventory":1,
"update_on_launch":true,
"update_cache_timeout":2,
"source_project":8,
"update_on_project_update":true,
"last_update_failed": true,
"last_updated":null
}

View File

@ -0,0 +1,107 @@
{
"id":6,
"type":"project",
"url":"/api/v2/projects/6/",
"related":{
"named_url":"/api/v2/projects/Demo Project++Default/",
"created_by":"/api/v2/users/1/",
"modified_by":"/api/v2/users/1/",
"teams":"/api/v2/projects/6/teams/",
"playbooks":"/api/v2/projects/6/playbooks/",
"inventory_files":"/api/v2/projects/6/inventories/",
"update":"/api/v2/projects/6/update/",
"project_updates":"/api/v2/projects/6/project_updates/",
"scm_inventory_sources":"/api/v2/projects/6/scm_inventory_sources/",
"schedules":"/api/v2/projects/6/schedules/",
"activity_stream":"/api/v2/projects/6/activity_stream/",
"notification_templates_started":"/api/v2/projects/6/notification_templates_started/",
"notification_templates_success":"/api/v2/projects/6/notification_templates_success/",
"notification_templates_error":"/api/v2/projects/6/notification_templates_error/",
"access_list":"/api/v2/projects/6/access_list/",
"object_roles":"/api/v2/projects/6/object_roles/",
"copy":"/api/v2/projects/6/copy/",
"organization":"/api/v2/organizations/1/"
},
"summary_fields":{
"organization":{
"id":1,
"name":"Default",
"description":""
},
"credential": {
"id": 9,
"name": "mock scm",
"description": "",
"kind": "scm",
"cloud": false,
"kubernetes": false,
"credential_type_id": 2
},
"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 project",
"name":"Admin",
"id":15
},
"use_role":{
"description":"Can use the project in a job template",
"name":"Use",
"id":16
},
"update_role":{
"description":"May update the project",
"name":"Update",
"id":17
},
"read_role":{
"description":"May view settings for the project",
"name":"Read",
"id":18
}
},
"user_capabilities":{
"edit":true,
"delete":true,
"start":true,
"schedule":true,
"copy":true
}
},
"created":"2020-04-02T18:16:15.862724Z",
"modified":"2020-04-02T18:16:15.862738Z",
"name":"Demo Project",
"description":"",
"local_path":"_6__demo_project",
"scm_type":"git",
"scm_url":"https://github.com/ansible/ansible-tower-samples",
"scm_branch":"foo",
"scm_refspec":"refs/",
"scm_clean":true,
"scm_delete_on_update":true,
"credential":9,
"timeout":0,
"scm_revision":"",
"last_job_run":"2020-03-11T20:18:14Z",
"last_job_failed":false,
"next_job_run":null,
"status":"never updated",
"organization":1,
"scm_update_on_launch":true,
"scm_update_cache_timeout":3,
"allow_override":true,
"custom_virtualenv": "mock virtual env",
"last_update_failed":false,
"last_updated":"2020-03-11T20:18:14Z"
}