diff --git a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx
index 69a55550f1..5863abe8ea 100644
--- a/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx
+++ b/awx/ui_next/src/screens/Template/JobTemplateAdd/JobTemplateAdd.jsx
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';
-import { Card } from '@patternfly/react-core';
+import { Card, PageSection } from '@patternfly/react-core';
import { CardBody } from '@components/Card';
import JobTemplateForm from '../shared/JobTemplateForm';
import { JobTemplatesAPI } from '@api';
@@ -61,15 +61,17 @@ function JobTemplateAdd() {
}
return (
-
-
-
-
-
+
+
+
+
+
+
+
);
}
diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.jsx
index 40c874328c..921aa7486b 100644
--- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.jsx
+++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.jsx
@@ -8,8 +8,9 @@ import { WorkflowJobTemplatesAPI } from '@api';
import WorkflowJobTemplateForm from '../shared/WorkflowJobTemplateForm';
function WorkflowJobTemplateAdd() {
- const [formSubmitError, setFormSubmitError] = useState();
const history = useHistory();
+ const [formSubmitError, setFormSubmitError] = useState();
+
const handleSubmit = async values => {
const { labels, organizationId, ...remainingValues } = values;
try {
diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.test.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.test.jsx
index 1424c689e0..fd063ac73b 100644
--- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.test.jsx
+++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateAdd/WorkflowJobTemplateAdd.test.jsx
@@ -39,9 +39,11 @@ describe('', () => {
afterEach(async () => {
wrapper.unmount();
});
+
test('initially renders successfully', async () => {
expect(wrapper.length).toBe(1);
});
+
test('calls workflowJobTemplatesAPI with correct information on submit', async () => {
await act(async () => {
await wrapper.find('WorkflowJobTemplateForm').invoke('handleSubmit')({
@@ -55,12 +57,14 @@ describe('', () => {
});
expect(WorkflowJobTemplatesAPI.associateLabel).toHaveBeenCalledTimes(2);
});
+
test('handleCancel navigates the user to the /templates', async () => {
await act(async () => {
await wrapper.find('WorkflowJobTemplateForm').invoke('handleCancel')();
});
expect(history.location.pathname).toBe('/templates');
});
+
test('throwing error renders FormSubmitError component', async () => {
const error = new Error('oops');
WorkflowJobTemplatesAPI.create.mockImplementation(() =>
diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.jsx
index fcfea46b82..f39035286a 100644
--- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.jsx
+++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.jsx
@@ -39,12 +39,15 @@ function WorkflowJobTemplateDetail({ template, i18n, webhook_key }) {
related,
webhook_credential,
} = template;
+
const urlOrigin = window.location.origin;
const history = useHistory();
+
const [deletionError, setDeletionError] = useState(null);
const [hasContentLoading, setHasContentLoading] = useState(false);
+
const renderOptionsField =
- template.allow_simultaneous || template.webhook_servicee;
+ template.allow_simultaneous || template.webhook_service;
const renderOptions = (
@@ -75,6 +78,7 @@ function WorkflowJobTemplateDetail({ template, i18n, webhook_key }) {
}
setHasContentLoading(false);
};
+
const inventoryValue = (kind, inventoryId) => {
const inventorykind = kind === 'smart' ? 'smart_inventory' : 'inventory';
@@ -91,6 +95,7 @@ function WorkflowJobTemplateDetail({ template, i18n, webhook_key }) {
);
};
+
const canLaunch = summary_fields?.user_capabilities?.start;
const recentPlaybookJobs = summary_fields.recent_jobs.map(job => ({
...job,
diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.test.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.test.jsx
index d979a2713a..90f1ab08e1 100644
--- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.test.jsx
+++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.test.jsx
@@ -40,6 +40,7 @@ describe('', () => {
},
webhook_service: 'Github',
};
+
beforeEach(async () => {
history = createMemoryHistory({
initialEntries: ['/templates/workflow_job_template/1/details'],
@@ -75,12 +76,15 @@ describe('', () => {
);
});
});
+
afterEach(() => {
wrapper.unmount();
});
+
test('renders successfully', () => {
expect(wrapper.find(WorkflowJobTemplateDetail).length).toBe(1);
});
+
test('expect detail fields to render properly', () => {
const renderedValues = [
{
@@ -147,6 +151,7 @@ describe('', () => {
renderedValues.map(value => assertValue(value));
});
+
test('link out resource have the correct url', () => {
const inventory = wrapper.find('Detail[label="Inventory"]').find('Link');
const organization = wrapper
diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.jsx
index 2a83c18033..53dd2ba442 100644
--- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.jsx
+++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.jsx
@@ -7,8 +7,8 @@ import { WorkflowJobTemplatesAPI, OrganizationsAPI } from '@api';
import { WorkflowJobTemplateForm } from '../shared';
function WorkflowJobTemplateEdit({ template, webhook_key }) {
- const [formSubmitError, setFormSubmitError] = useState();
const history = useHistory();
+ const [formSubmitError, setFormSubmitError] = useState();
const handleSubmit = async values => {
const { labels, ...remainingValues } = values;
diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.test.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.test.jsx
index e73b29ae4e..ebb3155abc 100644
--- a/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.test.jsx
+++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateEdit/WorkflowJobTemplateEdit.test.jsx
@@ -25,6 +25,7 @@ const mockTemplate = {
describe('', () => {
let wrapper;
let history;
+
beforeEach(async () => {
await act(async () => {
history = createMemoryHistory({
@@ -49,12 +50,15 @@ describe('', () => {
);
});
});
+
afterEach(async () => {
wrapper.unmount();
});
+
test('renders successfully', () => {
expect(wrapper.find('WorkflowJobTemplateEdit').length).toBe(1);
});
+
test('api is called to properly to save the updated template.', async () => {
await act(async () => {
await wrapper.find('WorkflowJobTemplateForm').invoke('handleSubmit')({
@@ -69,6 +73,7 @@ describe('', () => {
variables: '---',
});
});
+
expect(WorkflowJobTemplatesAPI.update).toHaveBeenCalledWith(6, {
id: 6,
name: 'Alex',
@@ -88,12 +93,14 @@ describe('', () => {
await expect(WorkflowJobTemplatesAPI.associateLabel).toBeCalledTimes(1);
});
+
test('handleCancel navigates the user to the /templates', async () => {
await act(async () => {
await wrapper.find('WorkflowJobTemplateForm').invoke('handleCancel')();
});
expect(history.location.pathname).toBe('/templates');
});
+
test('throwing error renders FormSubmitError component', async () => {
const error = new Error('oops');
WorkflowJobTemplatesAPI.update.mockImplementation(() =>
diff --git a/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.jsx b/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.jsx
index afa68ea97a..db36f925f3 100644
--- a/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.jsx
+++ b/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.jsx
@@ -46,14 +46,24 @@ function WorkflowJobTemplateForm({
webhook_key,
submitError,
}) {
+ const urlOrigin = window.location.origin;
+
const { id } = useParams();
const wfjtAddMatch = useRouteMatch('/templates/workflow_job_template/add');
- const urlOrigin = window.location.origin;
-
const [contentError, setContentError] = useState(null);
- const [webhookKey, setWebHookKey] = useState(webhook_key);
const [credTypeId, setCredentialTypeId] = useState();
+
+ const [inventory, setInventory] = useState(
+ template?.summary_fields?.inventory || null
+ );
+ const [organization, setOrganization] = useState(
+ template?.summary_fields?.organization || null
+ );
+ const [webhookCredential, setWebhookCredential] = useState(
+ template?.summary_fields?.webhook_credential || null
+ );
+ const [webhookKey, setWebHookKey] = useState(webhook_key);
const [webhookService, setWebHookService] = useState(
template.webhook_service || ''
);
@@ -159,16 +169,16 @@ function WorkflowJobTemplateForm({
return (
{
- values.webhook_credential = values?.webhook_credential?.id;
- values.organization = values?.organization?.id;
- values.inventory = values?.inventory?.id;
+ if (values.webhook_service === '') {
+ values.webhook_credential = '';
+ }
return handleSubmit(values);
}}
initialValues={{
name: template.name || '',
description: template.description || '',
- inventory: template?.summary_fields?.inventory || null,
- organization: template?.summary_fields?.organization || null,
+ inventory: template?.summary_fields?.inventory?.id || null,
+ organization: template?.summary_fields?.organization?.id || null,
labels: template.summary_fields?.labels?.results || [],
extra_vars: template.variables || '---',
limit: template.limit || '',
@@ -178,7 +188,7 @@ function WorkflowJobTemplateForm({
template?.related?.webhook_receiver &&
`${urlOrigin}${template?.related?.webhook_receiver}`,
webhook_credential:
- template?.summary_fields?.webhook_credential || null,
+ template?.summary_fields?.webhook_credential?.id || null,
webhook_service: template.webhook_service || '',
ask_limit_on_launch: template.ask_limit_on_launch || false,
ask_inventory_on_launch: template.ask_inventory_on_launch || false,
@@ -208,7 +218,7 @@ function WorkflowJobTemplateForm({
label={i18n._(t`Organization`)}
name="organization"
>
- {({ form, field }) => (
+ {({ form }) => (
form.setFieldTouched('organization')}
onChange={value => {
- form.setFieldValue('organization', value);
+ form.setFieldValue('organization', value.id);
+ setOrganization(value);
}}
- value={field.value}
+ value={organization}
touched={form.touched.organization}
error={form.errors.organization}
/>
)}
- {({ form, field }) => (
+ {({ form }) => (
{
- form.setFieldValue('inventory', value);
+ form.setFieldValue('inventory', value.id);
+ setInventory(value);
form.setFieldValue('organizationId', value.organization);
}}
error={form.errors.inventory}
@@ -426,7 +438,7 @@ function WorkflowJobTemplateForm({
)}
{credTypeId && (
- {({ form, field }) => (
+ {({ form }) => (
{
- form.setFieldValue('webhook_credential', value);
+ form.setFieldValue('webhook_credential', value.id);
+ setWebhookCredential(value);
}}
- value={field.value}
+ value={webhookCredential}
/>
)}
diff --git a/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.test.jsx b/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.test.jsx
index c7fa586c06..328ba5de85 100644
--- a/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.test.jsx
+++ b/awx/ui_next/src/screens/Template/shared/WorkflowJobTemplateForm.test.jsx
@@ -9,9 +9,11 @@ import WorkflowJobTemplateForm from './WorkflowJobTemplateForm';
import { WorkflowJobTemplatesAPI } from '../../../api';
jest.mock('@api/models/WorkflowJobTemplates');
+
WorkflowJobTemplatesAPI.updateWebhookKey.mockResolvedValue({
data: { webhook_key: 'sdafdghjkl2345678ionbvcxz' },
});
+
describe('', () => {
let wrapper;
let history;
@@ -35,6 +37,7 @@ describe('', () => {
webhook_receiver: '/api/v2/workflow_job_templates/57/gitlab/',
},
};
+
beforeEach(() => {
history = createMemoryHistory({
initialEntries: ['/templates/workflow_job_template/6/edit'],
@@ -66,13 +69,16 @@ describe('', () => {
);
});
});
+
afterEach(() => {
wrapper.unmount();
jest.clearAllMocks();
});
+
test('renders successfully', () => {
expect(wrapper.length).toBe(1);
});
+
test('all the fields render successfully', () => {
const fields = [
'FormField[name="name"]',
@@ -89,6 +95,7 @@ describe('', () => {
};
fields.map((field, index) => assertField(field, index));
});
+
test('changing inputs should update values', async () => {
const inputsToChange = [
{
@@ -193,6 +200,7 @@ describe('', () => {
expect(wrapper.find('AnsibleSelect').prop('value')).toBe('gitlab');
});
+
test('handleSubmit is called on submit button click', async () => {
act(() => {
wrapper.find('Formik').prop('onSubmit')({});
@@ -201,6 +209,7 @@ describe('', () => {
sleep(0);
expect(handleSubmit).toBeCalled();
});
+
test('handleCancel is called on cancel button click', async () => {
act(() => {
wrapper.find('button[aria-label="Cancel"]').simulate('click');