diff --git a/awx/ui_next/src/components/ContentError/ContentError.jsx b/awx/ui_next/src/components/ContentError/ContentError.jsx
index f6fb2d825c..7f766f7e91 100644
--- a/awx/ui_next/src/components/ContentError/ContentError.jsx
+++ b/awx/ui_next/src/components/ContentError/ContentError.jsx
@@ -25,7 +25,6 @@ function ContentError({ error, children, isNotFound, i18n }) {
return null;
}
}
- console.error(error);
const is404 =
isNotFound || (error && error.response && error.response.status === 404);
const is401 = error && error.response && error.response.status === 401;
diff --git a/awx/ui_next/src/components/LaunchPrompt/CredentialsStep.test.jsx b/awx/ui_next/src/components/LaunchPrompt/CredentialsStep.test.jsx
new file mode 100644
index 0000000000..5038482125
--- /dev/null
+++ b/awx/ui_next/src/components/LaunchPrompt/CredentialsStep.test.jsx
@@ -0,0 +1,79 @@
+import React from 'react';
+import { act } from 'react-dom/test-utils';
+import { Formik } from 'formik';
+import { mountWithContexts } from '@testUtils/enzymeHelpers';
+import CredentialsStep from './CredentialsStep';
+import { CredentialsAPI, CredentialTypesAPI } from '@api';
+
+jest.mock('@api/models/CredentialTypes');
+jest.mock('@api/models/Credentials');
+
+const types = [
+ { id: 1, kind: 'ssh', name: 'SSH' },
+ { id: 2, kind: 'cloud', name: 'Ansible Tower' },
+ { id: 3, kind: 'vault', name: 'Vault' },
+];
+
+const credentials = [
+ { id: 1, kind: 'cloud', name: 'Cred 1', url: 'www.google.com' },
+ { id: 2, kind: 'ssh', name: 'Cred 2', url: 'www.google.com' },
+ { id: 3, kind: 'Ansible', name: 'Cred 3', url: 'www.google.com' },
+ { id: 4, kind: 'Machine', name: 'Cred 4', url: 'www.google.com' },
+ { id: 5, kind: 'Machine', name: 'Cred 5', url: 'www.google.com' },
+];
+
+describe('CredentialsStep', () => {
+ beforeEach(() => {
+ CredentialTypesAPI.loadAllTypes.mockResolvedValue(types);
+ CredentialsAPI.read.mockResolvedValue({
+ data: {
+ results: credentials,
+ count: 5,
+ },
+ });
+ });
+
+ test('should load credentials', async () => {
+ let wrapper;
+ await act(async () => {
+ wrapper = mountWithContexts(
+
+
+
+ );
+ });
+ wrapper.update();
+
+ expect(CredentialsAPI.read).toHaveBeenCalled();
+ expect(wrapper.find('OptionsList').prop('options')).toEqual(credentials);
+ });
+
+ test('should load credentials for selected type', async () => {
+ let wrapper;
+ await act(async () => {
+ wrapper = mountWithContexts(
+
+
+
+ );
+ });
+ wrapper.update();
+
+ expect(CredentialsAPI.read).toHaveBeenCalledWith({
+ credential_type: 1,
+ order_by: 'name',
+ page: 1,
+ page_size: 5,
+ });
+
+ await act(async () => {
+ wrapper.find('AnsibleSelect').invoke('onChange')({}, 2);
+ });
+ expect(CredentialsAPI.read).toHaveBeenCalledWith({
+ credential_type: 2,
+ order_by: 'name',
+ page: 1,
+ page_size: 5,
+ });
+ });
+});
diff --git a/awx/ui_next/src/components/LaunchPrompt/LaunchPrompt.jsx b/awx/ui_next/src/components/LaunchPrompt/LaunchPrompt.jsx
index 4a5a256ad7..ecf6c760c5 100644
--- a/awx/ui_next/src/components/LaunchPrompt/LaunchPrompt.jsx
+++ b/awx/ui_next/src/components/LaunchPrompt/LaunchPrompt.jsx
@@ -22,7 +22,7 @@ function LaunchPrompt({ config, resource, onLaunch, onCancel, i18n }) {
if (config.ask_credential_on_launch) {
initialValues.credentials = resource?.summary_fields?.credentials || [];
steps.push({
- name: i18n._(t`Credential`),
+ name: i18n._(t`Credentials`),
component: ,
});
}
diff --git a/awx/ui_next/src/components/LaunchPrompt/LaunchPrompt.test.jsx b/awx/ui_next/src/components/LaunchPrompt/LaunchPrompt.test.jsx
index edbb0cd7dc..3a490db6bc 100644
--- a/awx/ui_next/src/components/LaunchPrompt/LaunchPrompt.test.jsx
+++ b/awx/ui_next/src/components/LaunchPrompt/LaunchPrompt.test.jsx
@@ -3,6 +3,8 @@ import { act, isElementOfType } from 'react-dom/test-utils';
import { mountWithContexts } from '@testUtils/enzymeHelpers';
import LaunchPrompt from './LaunchPrompt';
import InventoryStep from './InventoryStep';
+import CredentialsStep from './CredentialsStep';
+import OtherPromptsStep from './OtherPromptsStep';
import PreviewStep from './PreviewStep';
import { InventoriesAPI } from '@api';
@@ -69,7 +71,7 @@ describe('LaunchPrompt', () => {
expect(steps).toHaveLength(5);
expect(steps[0].name).toEqual('Inventory');
- expect(steps[1].name).toEqual('Credential');
+ expect(steps[1].name).toEqual('Credentials');
expect(steps[2].name).toEqual('Other Prompts');
expect(steps[3].name).toEqual('Survey');
expect(steps[4].name).toEqual('Preview');
@@ -97,4 +99,50 @@ describe('LaunchPrompt', () => {
expect(isElementOfType(steps[0].component, InventoryStep)).toEqual(true);
expect(isElementOfType(steps[1].component, PreviewStep)).toEqual(true);
});
+
+ test('should add credentials step', async () => {
+ let wrapper;
+ await act(async () => {
+ wrapper = mountWithContexts(
+
+ );
+ });
+ const steps = wrapper.find('Wizard').prop('steps');
+
+ expect(steps).toHaveLength(2);
+ expect(steps[0].name).toEqual('Credentials');
+ expect(isElementOfType(steps[0].component, CredentialsStep)).toEqual(true);
+ expect(isElementOfType(steps[1].component, PreviewStep)).toEqual(true);
+ });
+
+ test('should add other prompts step', async () => {
+ let wrapper;
+ await act(async () => {
+ wrapper = mountWithContexts(
+
+ );
+ });
+ const steps = wrapper.find('Wizard').prop('steps');
+
+ expect(steps).toHaveLength(2);
+ expect(steps[0].name).toEqual('Other Prompts');
+ expect(isElementOfType(steps[0].component, OtherPromptsStep)).toEqual(true);
+ expect(isElementOfType(steps[1].component, PreviewStep)).toEqual(true);
+ });
});
diff --git a/awx/ui_next/src/components/LaunchPrompt/OtherPromptsStep.jsx b/awx/ui_next/src/components/LaunchPrompt/OtherPromptsStep.jsx
index 09445e63e9..0989368652 100644
--- a/awx/ui_next/src/components/LaunchPrompt/OtherPromptsStep.jsx
+++ b/awx/ui_next/src/components/LaunchPrompt/OtherPromptsStep.jsx
@@ -7,6 +7,17 @@ import FormField, { FieldTooltip } from '@components/FormField';
import { TagMultiSelect } from '@components/MultiSelect';
import AnsibleSelect from '@components/AnsibleSelect';
import { VariablesField } from '@components/CodeMirrorInput';
+import styled from 'styled-components';
+
+const FieldHeader = styled.div`
+ display: flex;
+ justify-content: space-between;
+ padding-bottom: var(--pf-c-form__label--PaddingBottom);
+
+ label {
+ --pf-c-form__label--PaddingBottom: 0px;
+ }
+`;
function OtherPromptsStep({ config, i18n }) {
return (
@@ -131,12 +142,28 @@ function VerbosityField({ i18n }) {
function ShowChangesToggle({ i18n }) {
const [field, , helpers] = useField('diff_mode');
return (
-
+
+
+ {' '}
+
+
+
+
);
}
@@ -150,23 +177,4 @@ function TagField({ id, name, label, tooltip }) {
);
}
-/*
- tooltips:
- verbosity: Control the level of output ansible will produce as the playbook executes.
- job tags: Tags are useful when you have a large playbook, and you want to run a specific part of a play or task. Use commas to separate multiple tags. Refer to Ansible Tower documentation for details on the usage of tags.
- skip tags: Skip tags are useful when you have a large playbook, and you want to skip specific parts of a play or task. Use commas to separate multiple tags. Refer to Ansible Tower documentation for details on the usage of tags.
- show changes: If enabled, show the changes made by Ansible tasks, where supported. This is equivalent to Ansible’s --diff mode.
- extra variables: Pass extra command line variables to the playbook. This is the -e or --extra-vars command line parameter for ansible-playbook. Provide key/value pairs using either YAML or JSON.
-
- JSON:
- {
- "somevar": "somevalue",
- "password": "magic"
- }
- YAML:
- ---
- somevar: somevalue
- password: magic
-*/
-
export default withI18n()(OtherPromptsStep);
diff --git a/awx/ui_next/src/components/LaunchPrompt/OtherPromptsStep.test.jsx b/awx/ui_next/src/components/LaunchPrompt/OtherPromptsStep.test.jsx
new file mode 100644
index 0000000000..58f0856131
--- /dev/null
+++ b/awx/ui_next/src/components/LaunchPrompt/OtherPromptsStep.test.jsx
@@ -0,0 +1,90 @@
+import React from 'react';
+import { act } from 'react-dom/test-utils';
+import { Formik } from 'formik';
+import { mountWithContexts } from '@testUtils/enzymeHelpers';
+import OtherPromptsStep from './OtherPromptsStep';
+
+describe('OtherPromptsStep', () => {
+ test('should render job type field', async () => {
+ let wrapper;
+ await act(async () => {
+ wrapper = mountWithContexts(
+
+
+
+ );
+ });
+
+ expect(wrapper.find('JobTypeField')).toHaveLength(1);
+ expect(
+ wrapper.find('JobTypeField AnsibleSelect').prop('data')
+ ).toHaveLength(3);
+ expect(wrapper.find('JobTypeField AnsibleSelect').prop('value')).toEqual(
+ 'run'
+ );
+ });
+
+ test('should render limit field', async () => {
+ let wrapper;
+ await act(async () => {
+ wrapper = mountWithContexts(
+
+
+
+ );
+ });
+
+ expect(wrapper.find('FormField#prompt-limit')).toHaveLength(1);
+ expect(wrapper.find('FormField#prompt-limit input').prop('name')).toEqual(
+ 'limit'
+ );
+ });
+
+ test('should render verbosity field', async () => {
+ let wrapper;
+ await act(async () => {
+ wrapper = mountWithContexts(
+
+
+
+ );
+ });
+
+ expect(wrapper.find('VerbosityField')).toHaveLength(1);
+ expect(
+ wrapper.find('VerbosityField AnsibleSelect').prop('data')
+ ).toHaveLength(5);
+ });
+
+ test('should render show changes toggle', async () => {
+ let wrapper;
+ await act(async () => {
+ wrapper = mountWithContexts(
+
+
+
+ );
+ });
+
+ expect(wrapper.find('ShowChangesToggle')).toHaveLength(1);
+ expect(wrapper.find('ShowChangesToggle Switch').prop('isChecked')).toEqual(
+ true
+ );
+ });
+});