updates tooltip component, fixes formik configuration on ad hoc qizard

This commit is contained in:
Alex Corey
2020-09-02 11:09:25 -04:00
parent 0e3fbb74d4
commit 678dcad437
9 changed files with 98 additions and 75 deletions

View File

@@ -65,7 +65,7 @@ function AdHocCommands({ children, apiModule, adHocItems, itemId, i18n }) {
useCallback(
async values => {
const { data } = await apiModule.launchAdHocCommands(itemId, values);
history.push(`/jobs/${data.module_name}/${data.id}/output`);
history.push(`/jobs/command/${data.id}/output`);
},
[apiModule, itemId, history]

View File

@@ -157,12 +157,12 @@ describe('<AdHocCommands />', () => {
).toBe(true);
await act(async () => {
wrapper.find('AnsibleSelect[name="module_args"]').prop('onChange')(
wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')(
{},
'command'
);
wrapper.find('input#arguments').simulate('change', {
target: { value: 'foo', name: 'arguments' },
wrapper.find('input#module_args').simulate('change', {
target: { value: 'foo', name: 'module_args' },
});
wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1);
});
@@ -194,14 +194,15 @@ describe('<AdHocCommands />', () => {
);
expect(InventoriesAPI.launchAdHocCommands).toBeCalledWith(1, {
arguments: 'foo',
changes: false,
module_args: 'foo',
diff_mode: false,
credential: 4,
escalation: false,
job_type: 'run',
become_enabled: '',
extra_vars: '---',
forks: 0,
limit: 'Inventory 1 Org 0, Inventory 2 Org 0',
module_args: 'command',
module_name: 'command',
verbosity: 1,
});
@@ -271,12 +272,12 @@ describe('<AdHocCommands />', () => {
).toBe(true);
await act(async () => {
wrapper.find('AnsibleSelect[name="module_args"]').prop('onChange')(
wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')(
{},
'command'
);
wrapper.find('input#arguments').simulate('change', {
target: { value: 'foo', name: 'arguments' },
wrapper.find('input#module_args').simulate('change', {
target: { value: 'foo', name: 'module_args' },
});
wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1);
});

View File

@@ -22,12 +22,12 @@ function AdHocCommandsWizard({
const { values } = useFormikContext();
const enabledNextOnDetailsStep = () => {
if (!values.module_args) {
if (!values.module_name) {
return false;
}
if (values.module_args === 'shell' || values.module_args === 'command') {
if (values.arguments) {
if (values.module_name === 'shell' || values.module_name === 'command') {
if (values.module_args) {
return true;
// eslint-disable-next-line no-else-return
} else {
@@ -90,15 +90,16 @@ const FormikApp = withFormik({
mapPropsToValues({ adHocItems, verbosityOptions }) {
const adHocItemStrings = adHocItems.map(item => item.name).join(', ');
return {
limit: adHocItemStrings || [],
limit: adHocItemStrings || 'all',
credential: [],
module_args: '',
arguments: '',
verbosity: verbosityOptions[0].value,
forks: 0,
changes: false,
escalation: false,
diff_mode: false,
become_enabled: '',
module_name: '',
extra_vars: '---',
job_type: 'run',
};
},
})(AdHocCommandsWizard);

View File

@@ -73,12 +73,12 @@ describe('<AdHocCommandsWizard/>', () => {
await waitForElement(wrapper, 'WizardNavItem', el => el.length > 0);
await act(async () => {
wrapper.find('AnsibleSelect[name="module_args"]').prop('onChange')(
wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')(
{},
'command'
);
wrapper.find('input#arguments').simulate('change', {
target: { value: 'foo', name: 'arguments' },
wrapper.find('input#module_args').simulate('change', {
target: { value: 'foo', name: 'module_args' },
});
wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1);
});
@@ -105,12 +105,12 @@ describe('<AdHocCommandsWizard/>', () => {
await waitForElement(wrapper, 'WizardNavItem', el => el.length > 0);
await act(async () => {
wrapper.find('AnsibleSelect[name="module_args"]').prop('onChange')(
wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')(
{},
'command'
);
wrapper.find('input#arguments').simulate('change', {
target: { value: 'foo', name: 'arguments' },
wrapper.find('input#module_args').simulate('change', {
target: { value: 'foo', name: 'module_args' },
});
wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1);
});
@@ -165,12 +165,12 @@ describe('<AdHocCommandsWizard/>', () => {
await waitForElement(wrapper, 'WizardNavItem', el => el.length > 0);
await act(async () => {
wrapper.find('AnsibleSelect[name="module_args"]').prop('onChange')(
wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')(
{},
'command'
);
wrapper.find('input#arguments').simulate('change', {
target: { value: 'foo', name: 'arguments' },
wrapper.find('input#module_args').simulate('change', {
target: { value: 'foo', name: 'module_args' },
});
wrapper.find('AnsibleSelect[name="verbosity"]').prop('onChange')({}, 1);
});

View File

@@ -28,29 +28,36 @@ const TooltipWrapper = styled.div`
const brandName = BrandName;
function CredentialStep({ i18n, verbosityOptions, moduleOptions }) {
const [moduleField, moduleMeta, moduleHelpers] = useField({
const [module_nameField, module_nameMeta, module_nameHelpers] = useField({
name: 'module_name',
validate: required(null, i18n),
});
const [module_argsField] = useField({
name: 'module_args',
validate: required(null, i18n),
});
const [variablesField] = useField('extra_vars');
const [changesField, , changesHelpers] = useField('changes');
const [escalationField, , escalationHelpers] = useField('escalation');
const [diff_modeField, , diff_modeHelpers] = useField('diff_mode');
const [become_enabledField, , become_enabledHelpers] = useField(
'become_enabled'
);
const [verbosityField, verbosityMeta, verbosityHelpers] = useField({
name: 'verbosity',
validate: required(null, i18n),
});
return (
<Form>
<FormColumnLayout>
<FormFullWidthLayout>
<FormGroup
fieldId="module"
fieldId="module_name"
label={i18n._(t`Module`)}
isRequired
helperTextInvalid={moduleMeta.error}
helperTextInvalid={module_nameMeta.error}
validated={
!moduleMeta.touched || !moduleMeta.error ? 'default' : 'error'
!module_nameMeta.touched || !module_nameMeta.error
? 'default'
: 'error'
}
labelIcon={
<FieldTooltip
@@ -61,26 +68,43 @@ function CredentialStep({ i18n, verbosityOptions, moduleOptions }) {
}
>
<AnsibleSelect
{...moduleField}
isValid={!moduleMeta.touched || !moduleMeta.error}
id="module"
{...module_nameField}
isValid={!module_nameMeta.touched || !module_nameMeta.error}
id="module_name"
data={moduleOptions || []}
onChange={(event, value) => {
moduleHelpers.setValue(value);
module_nameHelpers.setValue(value);
}}
/>
</FormGroup>
<FormField
id="arguments"
name="arguments"
id="module_args"
name="module_args"
type="text"
label={i18n._(t`Arguments`)}
isRequired={
moduleField.value === 'command' || moduleField.value === 'shell'
module_nameField.value === 'command' ||
module_nameField.value === 'shell'
}
tooltip={
module_nameField.value ? (
<>
{i18n._(
t`These arguments are used with the specified module. You can find information about the ${module_argsField.value} by clicking `
)}
<a
href={`https://docs.ansible.com/ansible/latest/modules/${module_argsField.value}_module.html`}
target="_blank"
rel="noopener noreferrer"
>
{' '}
{i18n._(t`here.`)}
</a>
</>
) : (
i18n._(t`These arguments are used with the specified module.`)
)
}
tooltip={i18n._(
t`These arguments are used with the specified module.`
)}
/>
<FormGroup
fieldId="verbosity"
@@ -106,7 +130,7 @@ function CredentialStep({ i18n, verbosityOptions, moduleOptions }) {
id="verbosity"
data={verbosityOptions || []}
onChange={(event, value) => {
verbosityHelpers.setValue(value);
verbosityHelpers.setValue(parseInt(value, 10));
}}
/>
</FormGroup>
@@ -164,20 +188,17 @@ function CredentialStep({ i18n, verbosityOptions, moduleOptions }) {
>
<Switch
css="display: inline-flex;"
id="changes"
id="diff_mode"
label={i18n._(t`On`)}
labelOff={i18n._(t`Off`)}
isChecked={changesField.value}
isChecked={diff_modeField.value}
onChange={() => {
changesHelpers.setValue(!changesField.value);
diff_modeHelpers.setValue(!diff_modeField.value);
}}
aria-label={i18n._(t`toggle changes`)}
/>
</FormGroup>
<FormGroup
name={i18n._(t`enable privilege escalation`)}
fieldId="escalation"
>
<FormGroup name="become_enabled" fieldId="become_enabled">
<FormCheckboxLayout>
<Checkbox
aria-label={i18n._(t`Enable privilege escalation`)}
@@ -202,10 +223,10 @@ function CredentialStep({ i18n, verbosityOptions, moduleOptions }) {
/>
</span>
}
id="escalation"
isChecked={escalationField.value}
id="become_enabled"
isChecked={become_enabledField.value}
onChange={checked => {
escalationHelpers.setValue(checked);
become_enabledHelpers.setValue(checked);
}}
/>
</FormCheckboxLayout>

View File

@@ -29,7 +29,7 @@ const initialValues = {
extra_vars: '---',
};
describe('<DetailsStep />', () => {
describe('<AdHocDetailsStep />', () => {
let wrapper;
afterEach(() => {
@@ -64,14 +64,12 @@ describe('<DetailsStep />', () => {
);
});
expect(wrapper.find('FormGroup[label="Module"]').length).toBe(1);
expect(wrapper.find('FormField[name="arguments"]').length).toBe(1);
expect(wrapper.find('FormField[label="Arguments"]').length).toBe(1);
expect(wrapper.find('FormGroup[label="Verbosity"]').length).toBe(1);
expect(wrapper.find('FormField[label="Limit"]').length).toBe(1);
expect(wrapper.find('FormField[name="forks"]').length).toBe(1);
expect(wrapper.find('FormGroup[label="Show changes"]').length).toBe(1);
expect(
wrapper.find('FormGroup[name="enable privilege escalation"]').length
).toBe(1);
expect(wrapper.find('FormGroup[name="become_enabled"]').length).toBe(1);
expect(wrapper.find('VariablesField').length).toBe(1);
});
@@ -89,12 +87,12 @@ describe('<DetailsStep />', () => {
});
await act(async () => {
wrapper.find('AnsibleSelect[name="module_args"]').prop('onChange')(
wrapper.find('AnsibleSelect[name="module_name"]').prop('onChange')(
{},
'command'
);
wrapper.find('input#arguments').simulate('change', {
target: { value: 'foo', name: 'arguments' },
wrapper.find('input#module_args').simulate('change', {
target: { value: 'foo', name: 'module_args' },
});
wrapper.find('input#limit').simulate('change', {
target: {
@@ -116,9 +114,9 @@ describe('<DetailsStep />', () => {
});
wrapper.update();
expect(
wrapper.find('AnsibleSelect[name="module_args"]').prop('value')
wrapper.find('AnsibleSelect[name="module_name"]').prop('value')
).toBe('command');
expect(wrapper.find('input#arguments').prop('value')).toBe('foo');
expect(wrapper.find('input#module_args').prop('value')).toBe('foo');
expect(wrapper.find('AnsibleSelect[name="verbosity"]').prop('value')).toBe(
1
);

View File

@@ -83,7 +83,7 @@ describe('VariablesField', () => {
)}
</Formik>
);
expect(wrapper.find('Tooltip').length).toBe(1);
expect(wrapper.find('Popover').length).toBe(1);
});
it('should submit value through Formik', async () => {

View File

@@ -61,6 +61,6 @@ describe('FieldWithPrompt', () => {
</Formik>
);
expect(wrapper.find('.pf-c-form__label-required')).toHaveLength(1);
expect(wrapper.find('Tooltip')).toHaveLength(1);
expect(wrapper.find('Popover')).toHaveLength(1);
});
});

View File

@@ -1,6 +1,6 @@
import React from 'react';
import React, { useState } from 'react';
import { node } from 'prop-types';
import { Tooltip } from '@patternfly/react-core';
import { Popover } from '@patternfly/react-core';
import { QuestionCircleIcon as PFQuestionCircleIcon } from '@patternfly/react-icons';
import styled from 'styled-components';
@@ -9,18 +9,20 @@ const QuestionCircleIcon = styled(PFQuestionCircleIcon)`
`;
function FieldTooltip({ content, ...rest }) {
const [showTooltip, setShowTooltip] = useState(false);
if (!content) {
return null;
}
return (
<Tooltip
position="right"
content={content}
trigger="click mouseenter focus"
<Popover
bodyContent={content}
isVisible={showTooltip}
hideOnOutsideClick
shouldClose={() => setShowTooltip(false)}
{...rest}
>
<QuestionCircleIcon />
</Tooltip>
<QuestionCircleIcon onClick={() => setShowTooltip(!showTooltip)} />
</Popover>
);
}
FieldTooltip.propTypes = {