mirror of
https://github.com/ansible/awx.git
synced 2026-05-17 14:27:42 -02:30
final fixes to tests and linting for pf v4 react upgrade
This commit is contained in:
@@ -1,103 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { withI18n } from '@lingui/react';
|
|
||||||
import { t } from '@lingui/macro';
|
|
||||||
import { useField } from 'formik';
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
ButtonVariant,
|
|
||||||
FormGroup,
|
|
||||||
InputGroup,
|
|
||||||
Tooltip,
|
|
||||||
} from '@patternfly/react-core';
|
|
||||||
import { KeyIcon } from '@patternfly/react-icons';
|
|
||||||
import { CredentialPluginPrompt } from './CredentialPluginPrompt';
|
|
||||||
import CredentialPluginSelected from './CredentialPluginSelected';
|
|
||||||
|
|
||||||
function CredentialPluginField(props) {
|
|
||||||
const {
|
|
||||||
children,
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
label,
|
|
||||||
validate,
|
|
||||||
isRequired,
|
|
||||||
isDisabled,
|
|
||||||
i18n,
|
|
||||||
} = props;
|
|
||||||
const [showPluginWizard, setShowPluginWizard] = useState(false);
|
|
||||||
const [field, meta, helpers] = useField({ name, validate });
|
|
||||||
const isValid = !(meta.touched && meta.error);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormGroup
|
|
||||||
fieldId={id}
|
|
||||||
helperTextInvalid={meta.error}
|
|
||||||
isRequired={isRequired}
|
|
||||||
validated={isValid ? 'default' : 'error'}
|
|
||||||
label={label}
|
|
||||||
>
|
|
||||||
{field?.value?.credential ? (
|
|
||||||
<CredentialPluginSelected
|
|
||||||
credential={field?.value?.credential}
|
|
||||||
onClearPlugin={() => helpers.setValue('')}
|
|
||||||
onEditPlugin={() => setShowPluginWizard(true)}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<InputGroup>
|
|
||||||
{React.cloneElement(children, {
|
|
||||||
...field,
|
|
||||||
isRequired,
|
|
||||||
onChange: (_, event) => {
|
|
||||||
field.onChange(event);
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
<Tooltip
|
|
||||||
content={i18n._(
|
|
||||||
t`Populate field from an external secret management system`
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
variant={ButtonVariant.control}
|
|
||||||
aria-label={i18n._(
|
|
||||||
t`Populate field from an external secret management system`
|
|
||||||
)}
|
|
||||||
onClick={() => setShowPluginWizard(true)}
|
|
||||||
isDisabled={isDisabled}
|
|
||||||
>
|
|
||||||
<KeyIcon />
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
</InputGroup>
|
|
||||||
)}
|
|
||||||
{showPluginWizard && (
|
|
||||||
<CredentialPluginPrompt
|
|
||||||
initialValues={typeof field.value === 'object' ? field.value : {}}
|
|
||||||
onClose={() => setShowPluginWizard(false)}
|
|
||||||
onSubmit={val => {
|
|
||||||
val.touched = true;
|
|
||||||
helpers.setValue(val);
|
|
||||||
setShowPluginWizard(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</FormGroup>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
CredentialPluginField.propTypes = {
|
|
||||||
id: PropTypes.string.isRequired,
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
label: PropTypes.string.isRequired,
|
|
||||||
validate: PropTypes.func,
|
|
||||||
isRequired: PropTypes.bool,
|
|
||||||
isDisabled: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
CredentialPluginField.defaultProps = {
|
|
||||||
validate: () => {},
|
|
||||||
isRequired: false,
|
|
||||||
isDisabled: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default withI18n()(CredentialPluginField);
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { withI18n } from '@lingui/react';
|
|
||||||
import { t } from '@lingui/macro';
|
|
||||||
import { useField } from 'formik';
|
|
||||||
import {
|
|
||||||
FileUpload,
|
|
||||||
FormGroup,
|
|
||||||
TextArea,
|
|
||||||
TextInput,
|
|
||||||
} from '@patternfly/react-core';
|
|
||||||
import {
|
|
||||||
FormColumnLayout,
|
|
||||||
FormFullWidthLayout,
|
|
||||||
} from '../../../../components/FormLayout';
|
|
||||||
import { required } from '../../../../util/validators';
|
|
||||||
import { CredentialPluginField } from '../CredentialPlugins';
|
|
||||||
|
|
||||||
const GoogleComputeEngineSubForm = ({ i18n }) => {
|
|
||||||
const [fileError, setFileError] = useState(null);
|
|
||||||
const [filename, setFilename] = useState('');
|
|
||||||
const [file, setFile] = useState('');
|
|
||||||
const inputsUsernameHelpers = useField({
|
|
||||||
name: 'inputs.username',
|
|
||||||
})[2];
|
|
||||||
const inputsProjectHelpers = useField({
|
|
||||||
name: 'inputs.project',
|
|
||||||
})[2];
|
|
||||||
const inputsSSHKeyDataHelpers = useField({
|
|
||||||
name: 'inputs.ssh_key_data',
|
|
||||||
})[2];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<FormColumnLayout>
|
|
||||||
<FormGroup
|
|
||||||
fieldId="credential-gce-file"
|
|
||||||
validated={!fileError ? 'default' : 'error'}
|
|
||||||
label={i18n._(t`Service account JSON file`)}
|
|
||||||
helperText={i18n._(
|
|
||||||
t`Select a JSON formatted service account key to autopopulate the following fields.`
|
|
||||||
)}
|
|
||||||
helperTextInvalid={fileError}
|
|
||||||
>
|
|
||||||
<FileUpload
|
|
||||||
id="credential-gce-file"
|
|
||||||
value={file}
|
|
||||||
filename={filename}
|
|
||||||
filenamePlaceholder={i18n._(t`Choose a .json file`)}
|
|
||||||
onChange={async value => {
|
|
||||||
if (value) {
|
|
||||||
try {
|
|
||||||
setFile(value);
|
|
||||||
setFilename(value.name);
|
|
||||||
const fileText = await value.text();
|
|
||||||
const fileJSON = JSON.parse(fileText);
|
|
||||||
if (
|
|
||||||
!fileJSON.client_email &&
|
|
||||||
!fileJSON.project_id &&
|
|
||||||
!fileJSON.private_key
|
|
||||||
) {
|
|
||||||
setFileError(
|
|
||||||
i18n._(
|
|
||||||
t`Expected at least one of client_email, project_id or private_key to be present in the file.`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
inputsUsernameHelpers.setValue(fileJSON.client_email || '');
|
|
||||||
inputsProjectHelpers.setValue(fileJSON.project_id || '');
|
|
||||||
inputsSSHKeyDataHelpers.setValue(fileJSON.private_key || '');
|
|
||||||
setFileError(null);
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
setFileError(
|
|
||||||
i18n._(
|
|
||||||
t`There was an error parsing the file. Please check the file formatting and try again.`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setFile('');
|
|
||||||
setFilename('');
|
|
||||||
inputsUsernameHelpers.setValue('');
|
|
||||||
inputsProjectHelpers.setValue('');
|
|
||||||
inputsSSHKeyDataHelpers.setValue('');
|
|
||||||
setFileError(null);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
dropzoneProps={{
|
|
||||||
accept: '.json',
|
|
||||||
onDropRejected: () => {
|
|
||||||
setFileError(
|
|
||||||
i18n._(
|
|
||||||
t`File upload rejected. Please select a single .json file.`
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
<CredentialPluginField
|
|
||||||
id="credential-username"
|
|
||||||
label={i18n._(t`Service account email address`)}
|
|
||||||
name="inputs.username"
|
|
||||||
type="email"
|
|
||||||
validate={required(null, i18n)}
|
|
||||||
isRequired
|
|
||||||
>
|
|
||||||
<TextInput id="credential-username" />
|
|
||||||
</CredentialPluginField>
|
|
||||||
<CredentialPluginField
|
|
||||||
id="credential-project"
|
|
||||||
label={i18n._(t`Project`)}
|
|
||||||
name="inputs.project"
|
|
||||||
>
|
|
||||||
<TextInput id="credential-project" />
|
|
||||||
</CredentialPluginField>
|
|
||||||
<FormFullWidthLayout>
|
|
||||||
<CredentialPluginField
|
|
||||||
id="credential-sshKeyData"
|
|
||||||
label={i18n._(t`RSA private key`)}
|
|
||||||
name="inputs.ssh_key_data"
|
|
||||||
type="textarea"
|
|
||||||
validate={required(null, i18n)}
|
|
||||||
isRequired
|
|
||||||
>
|
|
||||||
<TextArea
|
|
||||||
id="credential-sshKeyData"
|
|
||||||
rows={6}
|
|
||||||
resizeOrientation="vertical"
|
|
||||||
/>
|
|
||||||
</CredentialPluginField>
|
|
||||||
</FormFullWidthLayout>
|
|
||||||
</FormColumnLayout>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default withI18n()(GoogleComputeEngineSubForm);
|
|
||||||
@@ -178,7 +178,7 @@ describe('<InventoryGroupsList />', () => {
|
|||||||
await waitForElement(wrapper, 'ContentError', el => el.length === 1);
|
await waitForElement(wrapper, 'ContentError', el => el.length === 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.skip('should show error modal when group is not successfully deleted from api', async () => {
|
test('should show error modal when group is not successfully deleted from api', async () => {
|
||||||
GroupsAPI.destroy.mockRejectedValue(
|
GroupsAPI.destroy.mockRejectedValue(
|
||||||
new Error({
|
new Error({
|
||||||
response: {
|
response: {
|
||||||
@@ -199,8 +199,8 @@ describe('<InventoryGroupsList />', () => {
|
|||||||
});
|
});
|
||||||
await waitForElement(
|
await waitForElement(
|
||||||
wrapper,
|
wrapper,
|
||||||
'InventoryGroupsDeleteModal',
|
'AlertModal[title="Delete Group?"]',
|
||||||
el => el.props().isModalOpen === true
|
el => el.props().isOpen === true
|
||||||
);
|
);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('Radio[id="radio-delete"]').invoke('onChange')();
|
wrapper.find('Radio[id="radio-delete"]').invoke('onChange')();
|
||||||
@@ -211,7 +211,11 @@ describe('<InventoryGroupsList />', () => {
|
|||||||
.find('ModalBoxFooter Button[aria-label="Delete"]')
|
.find('ModalBoxFooter Button[aria-label="Delete"]')
|
||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
await waitForElement(wrapper, { title: 'Error!', variant: 'error' });
|
await waitForElement(
|
||||||
|
wrapper,
|
||||||
|
'AlertModal[title="Error!"] Modal',
|
||||||
|
el => el.props().isOpen === true && el.props().title === 'Error!'
|
||||||
|
);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('ModalBoxCloseButton').invoke('onClose')();
|
wrapper.find('ModalBoxCloseButton').invoke('onClose')();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ function HostEventModal({ onClose, hostEvent = {}, isOpen = false, i18n }) {
|
|||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
title={i18n._(t`Host Details`)}
|
title={i18n._(t`Host Details`)}
|
||||||
aria-label={i18n._(t`Host details modal`)}
|
aria-label={i18n._(t`Host details modal`)}
|
||||||
width={'75%'}
|
width="75%"
|
||||||
>
|
>
|
||||||
<Tabs
|
<Tabs
|
||||||
aria-label={i18n._(t`Tabs`)}
|
aria-label={i18n._(t`Tabs`)}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { t } from '@lingui/macro';
|
|||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { CaretLeftIcon } from '@patternfly/react-icons';
|
import { CaretLeftIcon } from '@patternfly/react-icons';
|
||||||
import { Card, PageSection } from '@patternfly/react-core';
|
import { Card, PageSection } from '@patternfly/react-core';
|
||||||
import RoutedTabs from '../../components/RoutedTabs';
|
|
||||||
import {
|
import {
|
||||||
Switch,
|
Switch,
|
||||||
Route,
|
Route,
|
||||||
@@ -13,6 +12,7 @@ import {
|
|||||||
useParams,
|
useParams,
|
||||||
useRouteMatch,
|
useRouteMatch,
|
||||||
} from 'react-router-dom';
|
} from 'react-router-dom';
|
||||||
|
import RoutedTabs from '../../components/RoutedTabs';
|
||||||
import useRequest from '../../util/useRequest';
|
import useRequest from '../../util/useRequest';
|
||||||
import ContentError from '../../components/ContentError';
|
import ContentError from '../../components/ContentError';
|
||||||
import JobList from '../../components/JobList';
|
import JobList from '../../components/JobList';
|
||||||
|
|||||||
Reference in New Issue
Block a user