diff --git a/awx/ui_next/src/api/models/JobTemplates.js b/awx/ui_next/src/api/models/JobTemplates.js
index 4f631cec2a..23f2716dda 100644
--- a/awx/ui_next/src/api/models/JobTemplates.js
+++ b/awx/ui_next/src/api/models/JobTemplates.js
@@ -24,6 +24,10 @@ class JobTemplates extends SchedulesMixin(
return this.http.post(`${this.baseUrl}${id}/launch/`, data);
}
+ readTemplateOptions(id) {
+ return this.http.options(`${this.baseUrl}/${id}/`);
+ }
+
readLaunch(id) {
return this.http.get(`${this.baseUrl}${id}/launch/`);
}
diff --git a/awx/ui_next/src/api/models/WorkflowJobTemplates.js b/awx/ui_next/src/api/models/WorkflowJobTemplates.js
index 7c582cd57f..e52e050b1d 100644
--- a/awx/ui_next/src/api/models/WorkflowJobTemplates.js
+++ b/awx/ui_next/src/api/models/WorkflowJobTemplates.js
@@ -12,6 +12,10 @@ class WorkflowJobTemplates extends SchedulesMixin(NotificationsMixin(Base)) {
return this.http.get(`${this.baseUrl}${id}/webhook_key/`);
}
+ readWorkflowJobTemplateOptions(id) {
+ return this.http.options(`${this.baseUrl}/${id}/`);
+ }
+
updateWebhookKey(id) {
return this.http.post(`${this.baseUrl}${id}/webhook_key/`);
}
diff --git a/awx/ui_next/src/screens/Template/Template.jsx b/awx/ui_next/src/screens/Template/Template.jsx
index 2358fb109b..12629ebe51 100644
--- a/awx/ui_next/src/screens/Template/Template.jsx
+++ b/awx/ui_next/src/screens/Template/Template.jsx
@@ -36,18 +36,23 @@ function Template({ i18n, me, setBreadcrumb }) {
request: loadTemplateAndRoles,
} = useRequest(
useCallback(async () => {
- const [{ data }, notifAdminRes] = await Promise.all([
+ const [{ data }, actions, notifAdminRes] = await Promise.all([
JobTemplatesAPI.readDetail(templateId),
+ JobTemplatesAPI.readTemplateOptions(templateId),
OrganizationsAPI.read({
page_size: 1,
role_level: 'notification_admin_role',
}),
]);
- if (data.webhook_service && data?.related?.webhook_key) {
- const {
- data: { webhook_key },
- } = await JobTemplatesAPI.readWebhookKey(templateId);
- data.webhook_key = webhook_key;
+
+ if (actions.data.actions.PUT) {
+ if (data.webhook_service && data?.related?.webhook_key) {
+ const {
+ data: { webhook_key },
+ } = await JobTemplatesAPI.readWebhookKey(templateId);
+
+ data.webhook_key = webhook_key;
+ }
}
setBreadcrumb(data);
diff --git a/awx/ui_next/src/screens/Template/Template.test.jsx b/awx/ui_next/src/screens/Template/Template.test.jsx
index 8176e4486a..a38209db75 100644
--- a/awx/ui_next/src/screens/Template/Template.test.jsx
+++ b/awx/ui_next/src/screens/Template/Template.test.jsx
@@ -18,11 +18,16 @@ const mockMe = {
is_system_auditor: false,
};
describe('', () => {
+ let wrapper;
beforeEach(() => {
JobTemplatesAPI.readDetail.mockResolvedValue({
data: mockJobTemplateData,
});
-
+ JobTemplatesAPI.readTemplateOptions.mockResolvedValue({
+ data: {
+ actions: { PUT: true },
+ },
+ });
OrganizationsAPI.read.mockResolvedValue({
data: {
count: 1,
@@ -35,21 +40,33 @@ describe('', () => {
],
},
});
+ JobTemplatesAPI.readWebhookKey.mockResolvedValue({
+ data: {
+ webhook_key: 'key',
+ },
+ });
+ });
+ afterEach(() => {
+ jest.clearAllMocks();
+ wrapper.unmount();
});
test('initially renders succesfully', async () => {
await act(async () => {
- mountWithContexts( {}} me={mockMe} />);
+ wrapper = mountWithContexts(
+ {}} me={mockMe} />
+ );
});
});
test('When component mounts API is called and the response is put in state', async () => {
await act(async () => {
- mountWithContexts( {}} me={mockMe} />);
+ wrapper = mountWithContexts(
+ {}} me={mockMe} />
+ );
});
expect(JobTemplatesAPI.readDetail).toBeCalled();
expect(OrganizationsAPI.read).toBeCalled();
});
test('notifications tab shown for admins', async done => {
- let wrapper;
await act(async () => {
wrapper = mountWithContexts(
{}} me={mockMe} />
@@ -74,7 +91,6 @@ describe('', () => {
},
});
- let wrapper;
await act(async () => {
wrapper = mountWithContexts(
{}} me={mockMe} />
@@ -93,7 +109,7 @@ describe('', () => {
const history = createMemoryHistory({
initialEntries: ['/templates/job_template/1/foobar'],
});
- let wrapper;
+
await act(async () => {
wrapper = mountWithContexts(
{}} me={mockMe} />,
@@ -117,4 +133,62 @@ describe('', () => {
await waitForElement(wrapper, 'ContentError', el => el.length === 1);
});
+ test('should call to get webhook key', async () => {
+ const history = createMemoryHistory({
+ initialEntries: ['/templates/job_template/1/foobar'],
+ });
+ await act(async () => {
+ wrapper = mountWithContexts(
+ {}} me={mockMe} />,
+ {
+ context: {
+ router: {
+ history,
+ route: {
+ location: history.location,
+ match: {
+ params: { id: 1 },
+ url: '/templates/job_template/1/foobar',
+ path: '/templates/job_template/1/foobar',
+ },
+ },
+ },
+ },
+ }
+ );
+ });
+ expect(JobTemplatesAPI.readWebhookKey).toHaveBeenCalled();
+ });
+ test('should not call to get webhook key', async () => {
+ JobTemplatesAPI.readTemplateOptions.mockResolvedValueOnce({
+ data: {
+ actions: {},
+ },
+ });
+
+ const history = createMemoryHistory({
+ initialEntries: ['/templates/job_template/1/foobar'],
+ });
+ await act(async () => {
+ wrapper = mountWithContexts(
+ {}} me={mockMe} />,
+ {
+ context: {
+ router: {
+ history,
+ route: {
+ location: history.location,
+ match: {
+ params: { id: 1 },
+ url: '/templates/job_template/1/foobar',
+ path: '/templates/job_template/1/foobar',
+ },
+ },
+ },
+ },
+ }
+ );
+ });
+ expect(JobTemplatesAPI.readWebhookKey).not.toHaveBeenCalled();
+ });
});
diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx
index 51abaab73a..e16a35ce1c 100644
--- a/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx
+++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplate.jsx
@@ -56,10 +56,20 @@ class WorkflowJobTemplate extends Component {
this.setState({ contentError: null });
try {
- const { data } = await WorkflowJobTemplatesAPI.readDetail(id);
+ const [
+ { data },
+ {
+ data: { actions },
+ },
+ ] = await Promise.all([
+ WorkflowJobTemplatesAPI.readDetail(id),
+ WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions(id),
+ ]);
let webhookKey;
- if (data?.webhook_service && data?.related?.webhook_key) {
- webhookKey = await WorkflowJobTemplatesAPI.readWebhookKey(id);
+ if (actions.PUT) {
+ if (data?.webhook_service && data?.related?.webhook_key) {
+ webhookKey = await WorkflowJobTemplatesAPI.readWebhookKey(id);
+ }
}
if (data?.summary_fields?.webhook_credential) {
const {
diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplate.test.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplate.test.jsx
index a0400ca772..e3e66bf8c1 100644
--- a/awx/ui_next/src/screens/Template/WorkflowJobTemplate.test.jsx
+++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplate.test.jsx
@@ -59,6 +59,7 @@ describe('', () => {
},
},
});
+
WorkflowJobTemplatesAPI.readWebhookKey.mockResolvedValue({
data: { webhook_key: 'WebHook Key' },
});
@@ -74,6 +75,9 @@ describe('', () => {
});
});
beforeEach(() => {
+ WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions.mockResolvedValue({
+ data: { actions: { PUT: {} } },
+ });
history = createMemoryHistory({
initialEntries: ['/templates/workflow_job_template/1/details'],
});
@@ -95,13 +99,18 @@ describe('', () => {
);
});
});
-
+ afterEach(() => {
+ jest.clearAllMocks();
+ wrapper.unmount();
+ });
test('calls api to get workflow job template data', async () => {
expect(wrapper.find('WorkflowJobTemplate').length).toBe(1);
expect(WorkflowJobTemplatesAPI.readDetail).toBeCalledWith('1');
wrapper.update();
await sleep(0);
expect(WorkflowJobTemplatesAPI.readWebhookKey).toBeCalledWith('1');
+ expect(WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions).toBeCalled();
+
expect(CredentialsAPI.readDetail).toBeCalledWith(1234567);
expect(OrganizationsAPI.read).toBeCalledWith({
page_size: 1,
@@ -144,4 +153,12 @@ describe('', () => {
tabs.forEach(t => expect(tc.prop(`aria-label=[${t}]`)));
});
});
+ test('should not call for webhook key', async () => {
+ WorkflowJobTemplatesAPI.readWorkflowJobTemplateOptions.mockResolvedValueOnce(
+ {
+ data: { actions: {} },
+ }
+ );
+ expect(WorkflowJobTemplatesAPI.readWebhookKey).not.toBeCalled();
+ });
});
diff --git a/awx/ui_next/src/screens/Template/shared/data.job_template.json b/awx/ui_next/src/screens/Template/shared/data.job_template.json
index 4d0cdb6aae..804c3b72a2 100644
--- a/awx/ui_next/src/screens/Template/shared/data.job_template.json
+++ b/awx/ui_next/src/screens/Template/shared/data.job_template.json
@@ -24,7 +24,8 @@
"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/",
- "webhook_receiver": "/api/v2/job_templates/7/github/"
+ "webhook_receiver": "/api/v2/job_templates/7/github/",
+ "webhook_key": "/api/v2/job_templates/7/webhook_key/"
},
"summary_fields": {
"inventory": {