diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeEditModal.test.js b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeEditModal.test.js index 13f81db148..717a0be30c 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeEditModal.test.js +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeEditModal.test.js @@ -4,6 +4,7 @@ import { WorkflowDispatchContext, WorkflowStateContext, } from 'contexts/Workflow'; +import { useUserProfile } from 'contexts/Config'; import { mountWithContexts, waitForElement, @@ -41,6 +42,17 @@ const workflowContext = { }; describe('NodeEditModal', () => { + beforeEach(() => { + useUserProfile.mockImplementation(() => { + return { + isSuperUser: true, + isSystemAuditor: false, + isOrgAdmin: false, + isNotificationAdmin: false, + isExecEnvAdmin: false, + }; + }); + }); test('Node modal confirmation dispatches as expected', async () => { const wrapper = mountWithContexts( diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeModal.test.js b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeModal.test.js index bdb27196e7..4f786288cd 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeModal.test.js +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeModal.test.js @@ -4,6 +4,7 @@ import { WorkflowDispatchContext, WorkflowStateContext, } from 'contexts/Workflow'; +import { useUserProfile } from 'contexts/Config'; import { InventorySourcesAPI, JobTemplatesAPI, @@ -93,6 +94,15 @@ const mockJobTemplate = { describe('NodeModal', () => { beforeEach(async () => { + useUserProfile.mockImplementation(() => { + return { + isSuperUser: true, + isSystemAuditor: false, + isOrgAdmin: false, + isNotificationAdmin: false, + isExecEnvAdmin: false, + }; + }); JobTemplatesAPI.read = jest.fn(); JobTemplatesAPI.read.mockResolvedValue({ data: { @@ -523,6 +533,17 @@ describe('NodeModal', () => { }); }); describe('Edit existing node', () => { + beforeEach(() => { + useUserProfile.mockImplementation(() => { + return { + isSuperUser: true, + isSystemAuditor: false, + isOrgAdmin: false, + isNotificationAdmin: false, + isExecEnvAdmin: false, + }; + }); + }); let newWrapper; afterEach(() => { jest.clearAllMocks(); diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.js b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.js index caf6b95e5a..5c9ac30cbf 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.js +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.js @@ -19,7 +19,7 @@ import Popover from 'components/Popover'; import AnsibleSelect from 'components/AnsibleSelect'; import FormField from 'components/FormField'; import getDocsBaseUrl from 'util/getDocsBaseUrl'; -import { useConfig } from 'contexts/Config'; +import { useConfig, useUserProfile } from 'contexts/Config'; import InventorySourcesList from './InventorySourcesList'; import JobTemplatesList from './JobTemplatesList'; import ProjectsList from './ProjectsList'; @@ -44,6 +44,7 @@ const TimeoutLabel = styled.p` `; function NodeTypeStep({ isIdentifierRequired }) { + const { isSuperUser } = useUserProfile(); const [nodeTypeField, , nodeTypeHelpers] = useField('nodeType'); const [nodeResourceField, nodeResourceMeta, nodeResourceHelpers] = useField('nodeResource'); @@ -59,6 +60,51 @@ function NodeTypeStep({ isIdentifierRequired }) { const config = useConfig(); const isValid = !approvalNameMeta.touched || !approvalNameMeta.error; + const nodeTypeChoices = [ + { + key: 'workflow_approval_template', + value: 'workflow_approval_template', + label: t`Approval`, + isDisabled: false, + }, + { + key: 'inventory_source', + value: 'inventory_source', + label: t`Inventory Source Sync`, + isDisabled: false, + }, + { + key: 'job_template', + value: 'job_template', + label: t`Job Template`, + isDisabled: false, + }, + { + key: 'project', + value: 'project', + label: t`Project Sync`, + isDisabled: false, + }, + { + key: 'workflow_job_template', + value: 'workflow_job_template', + label: t`Workflow Job Template`, + isDisabled: false, + }, + ]; + + const modifiedNodeTypeChoices = isSuperUser + ? [ + ...nodeTypeChoices, + { + key: 'system_job_template', + value: 'system_job_template', + label: t`Management Job`, + isDisabled: false, + }, + ] + : nodeTypeChoices; + return ( <> {nodeResourceMeta.error && ( @@ -74,44 +120,7 @@ function NodeTypeStep({ isIdentifierRequired }) { { nodeTypeHelpers.setValue(val); diff --git a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.test.js b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.test.js index cfc73a3593..682fdf9d82 100644 --- a/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.test.js +++ b/awx/ui/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.test.js @@ -7,6 +7,7 @@ import { ProjectsAPI, WorkflowJobTemplatesAPI, } from 'api'; +import { useUserProfile } from 'contexts/Config'; import { mountWithContexts } from '../../../../../../../testUtils/enzymeHelpers'; import NodeTypeStep from './NodeTypeStep'; @@ -17,6 +18,17 @@ jest.mock('../../../../../../api/models/Projects'); jest.mock('../../../../../../api/models/WorkflowJobTemplates'); describe('NodeTypeStep', () => { + beforeEach(() => { + useUserProfile.mockImplementation(() => { + return { + isSuperUser: true, + isSystemAuditor: false, + isOrgAdmin: false, + isNotificationAdmin: false, + isExecEnvAdmin: false, + }; + }); + }); beforeAll(() => { JobTemplatesAPI.read.mockResolvedValue({ data: { @@ -222,4 +234,65 @@ describe('NodeTypeStep', () => { expect(wrapper.find('input[name="timeoutMinutes"]').prop('value')).toBe(5); expect(wrapper.find('input[name="timeoutSeconds"]').prop('value')).toBe(30); }); + + test('it does not show management job as a choice for non system admin', async () => { + useUserProfile.mockImplementation(() => { + return { + isSuperUser: false, + isSystemAuditor: false, + isOrgAdmin: true, + isNotificationAdmin: false, + isExecEnvAdmin: false, + }; + }); + + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + + + ); + }); + wrapper.update(); + expect(wrapper.find('AnsibleSelect').prop('data').length).toBe(5); + expect( + wrapper + .find('AnsibleSelect') + .prop('data') + .map((item) => item.key) + ).toEqual([ + 'workflow_approval_template', + 'inventory_source', + 'job_template', + 'project', + 'workflow_job_template', + ]); + }); + + test('it does show management job as a choice for system admin', async () => { + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + + + ); + }); + wrapper.update(); + expect(wrapper.find('AnsibleSelect').prop('data').length).toBe(6); + expect( + wrapper + .find('AnsibleSelect') + .prop('data') + .map((item) => item.key) + ).toEqual([ + 'workflow_approval_template', + 'inventory_source', + 'job_template', + 'project', + 'workflow_job_template', + 'system_job_template', + ]); + }); });