Skip to content

Commit

Permalink
Merge pull request #7338 from mabashian/cred-plugin-test-button
Browse files Browse the repository at this point in the history
Hook up Test button on Metadata step in credential plugin wizard

Reviewed-by: John Hill <johill@redhat.com>
             https://github.com/unlikelyzero
  • Loading branch information
softwarefactory-project-zuul[bot] authored Sep 25, 2020
2 parents b4d6270 + ad1c4b1 commit 24e9484
Show file tree
Hide file tree
Showing 17 changed files with 297 additions and 125 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { FieldTooltip, PasswordInput } from '../../../../components/FormField';
import AnsibleSelect from '../../../../components/AnsibleSelect';
import { CredentialType } from '../../../../types';
import { required } from '../../../../util/validators';
import { CredentialPluginField } from './CredentialPlugins';
import { CredentialPluginField } from '../CredentialPlugins';
import BecomeMethodField from './BecomeMethodField';

const FileUpload = styled(PFFileUpload)`
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
Tooltip,
} from '@patternfly/react-core';
import { KeyIcon } from '@patternfly/react-icons';
import { FieldTooltip } from '../../../../../components/FormField';
import FieldWithPrompt from '../../../../../components/FieldWithPrompt';
import { FieldTooltip } from '../../../../components/FormField';
import FieldWithPrompt from '../../../../components/FieldWithPrompt';
import { CredentialPluginPrompt } from './CredentialPluginPrompt';
import CredentialPluginSelected from './CredentialPluginSelected';

Expand Down Expand Up @@ -55,6 +55,7 @@ function CredentialPluginInput(props) {
)}
>
<Button
id={`credential-${fieldOptions.id}-external-button`}
variant={ButtonVariant.control}
aria-label={i18n._(
t`Populate field from an external secret management system`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import { Formik } from 'formik';
import { TextInput } from '@patternfly/react-core';
import { mountWithContexts } from '../../../../../../testUtils/enzymeHelpers';
import { mountWithContexts } from '../../../../../testUtils/enzymeHelpers';
import CredentialPluginField from './CredentialPluginField';

const fieldOptions = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import React, { useCallback } from 'react';
import { func, shape } from 'prop-types';
import { Formik, useField } from 'formik';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import {
Button,
Tooltip,
Wizard,
WizardContextConsumer,
WizardFooter,
} from '@patternfly/react-core';
import CredentialsStep from './CredentialsStep';
import MetadataStep from './MetadataStep';
import { CredentialsAPI } from '../../../../../api';
import useRequest from '../../../../../util/useRequest';
import { CredentialPluginTestAlert } from '..';

function CredentialPluginWizard({ i18n, handleSubmit, onClose }) {
const [selectedCredential] = useField('credential');
const [inputValues] = useField('inputs');

const {
result: testPluginSuccess,
error: testPluginError,
request: testPluginMetadata,
} = useRequest(
useCallback(
async () =>
CredentialsAPI.test(selectedCredential.value.id, {
metadata: inputValues.value,
}),
[selectedCredential, inputValues]
),
null
);

const steps = [
{
id: 1,
name: i18n._(t`Credential`),
key: 'credential',
component: <CredentialsStep />,
enableNext: !!selectedCredential.value,
},
{
id: 2,
name: i18n._(t`Metadata`),
key: 'metadata',
component: <MetadataStep />,
canJumpTo: !!selectedCredential.value,
},
];

const CustomFooter = (
<WizardFooter>
<WizardContextConsumer>
{({ activeStep, onNext, onBack }) => (
<>
<Button
id="credential-plugin-prompt-next"
variant="primary"
onClick={onNext}
isDisabled={!selectedCredential.value}
>
{activeStep.key === 'metadata' ? i18n._(t`OK`) : i18n._(t`Next`)}
</Button>
{activeStep && activeStep.key === 'metadata' && (
<>
<Tooltip
content={i18n._(
t`Click this button to verify connection to the secret management system using the selected credential and specified inputs.`
)}
position="right"
>
<Button
id="credential-plugin-prompt-test"
variant="secondary"
onClick={() => testPluginMetadata()}
>
{i18n._(t`Test`)}
</Button>
</Tooltip>

<Button
id="credential-plugin-prompt-back"
variant="secondary"
onClick={onBack}
>
{i18n._(t`Back`)}
</Button>
</>
)}
<Button
id="credential-plugin-prompt-cancel"
variant="link"
onClick={onClose}
>
{i18n._(t`Cancel`)}
</Button>
</>
)}
</WizardContextConsumer>
</WizardFooter>
);

return (
<>
<Wizard
isOpen
onClose={onClose}
title={i18n._(t`External Secret Management System`)}
steps={steps}
onSave={handleSubmit}
footer={CustomFooter}
/>
{selectedCredential.value && (
<CredentialPluginTestAlert
credentialName={selectedCredential.value.name}
successResponse={testPluginSuccess}
errorResponse={testPluginError}
/>
)}
</>
);
}

function CredentialPluginPrompt({ i18n, onClose, onSubmit, initialValues }) {
return (
<Formik
initialValues={{
credential: initialValues?.credential || null,
inputs: initialValues?.inputs || {},
}}
onSubmit={onSubmit}
>
{({ handleSubmit }) => (
<CredentialPluginWizard
handleSubmit={handleSubmit}
i18n={i18n}
onClose={onClose}
/>
)}
</Formik>
);
}

CredentialPluginPrompt.propTypes = {
onClose: func.isRequired,
onSubmit: func.isRequired,
initialValues: shape({}),
};

CredentialPluginPrompt.defaultProps = {
initialValues: {},
};

export default withI18n()(CredentialPluginPrompt);
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ import { act } from 'react-dom/test-utils';
import {
mountWithContexts,
waitForElement,
} from '../../../../../../../testUtils/enzymeHelpers';
import { CredentialsAPI, CredentialTypesAPI } from '../../../../../../api';
import selectedCredential from '../../../data.cyberArkCredential.json';
import azureVaultCredential from '../../../data.azureVaultCredential.json';
import hashiCorpCredential from '../../../data.hashiCorpCredential.json';
} from '../../../../../../testUtils/enzymeHelpers';
import { CredentialsAPI, CredentialTypesAPI } from '../../../../../api';
import selectedCredential from '../../data.cyberArkCredential.json';
import azureVaultCredential from '../../data.azureVaultCredential.json';
import hashiCorpCredential from '../../data.hashiCorpCredential.json';
import CredentialPluginPrompt from './CredentialPluginPrompt';

jest.mock('../../../../../../api/models/Credentials');
jest.mock('../../../../../../api/models/CredentialTypes');
jest.mock('../../../../../api/models/Credentials');
jest.mock('../../../../../api/models/CredentialTypes');

CredentialsAPI.test.mockResolvedValue({});

CredentialsAPI.read.mockResolvedValue({
data: {
Expand Down Expand Up @@ -234,5 +236,13 @@ describe('<CredentialPluginPrompt />', () => {
wrapper.find('input#credential-secret_version').prop('value')
).toBe('9000');
});
test('clicking Test button makes correct call', async () => {
await act(async () => {
wrapper.find('Button[children="Test"]').simulate('click');
});
expect(CredentialsAPI.test).toHaveBeenCalledWith(1, {
metadata: { secret_path: '/foo/bar', secret_version: '9000' },
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { useHistory } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { useField } from 'formik';
import { CredentialsAPI } from '../../../../../../api';
import CheckboxListItem from '../../../../../../components/CheckboxListItem';
import ContentError from '../../../../../../components/ContentError';
import DataListToolbar from '../../../../../../components/DataListToolbar';
import PaginatedDataList from '../../../../../../components/PaginatedDataList';
import { getQSConfig, parseQueryString } from '../../../../../../util/qs';
import useRequest from '../../../../../../util/useRequest';
import { CredentialsAPI } from '../../../../../api';
import CheckboxListItem from '../../../../../components/CheckboxListItem';
import ContentError from '../../../../../components/ContentError';
import DataListToolbar from '../../../../../components/DataListToolbar';
import PaginatedDataList from '../../../../../components/PaginatedDataList';
import { getQSConfig, parseQueryString } from '../../../../../util/qs';
import useRequest from '../../../../../util/useRequest';

const QS_CONFIG = getQSConfig('credential', {
page: 1,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
import React, { useCallback, useEffect } from 'react';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { useField, useFormikContext } from 'formik';
import styled from 'styled-components';
import { Button, Form, FormGroup, Tooltip } from '@patternfly/react-core';
import { Form, FormGroup, Tooltip } from '@patternfly/react-core';
import { QuestionCircleIcon as PFQuestionCircleIcon } from '@patternfly/react-icons';
import { CredentialTypesAPI } from '../../../../../../api';
import AnsibleSelect from '../../../../../../components/AnsibleSelect';
import ContentError from '../../../../../../components/ContentError';
import ContentLoading from '../../../../../../components/ContentLoading';
import FormField from '../../../../../../components/FormField';
import { FormFullWidthLayout } from '../../../../../../components/FormLayout';
import useRequest from '../../../../../../util/useRequest';
import { required } from '../../../../../../util/validators';
import { CredentialTypesAPI } from '../../../../../api';
import AnsibleSelect from '../../../../../components/AnsibleSelect';
import ContentError from '../../../../../components/ContentError';
import ContentLoading from '../../../../../components/ContentLoading';
import FormField from '../../../../../components/FormField';
import { FormFullWidthLayout } from '../../../../../components/FormLayout';
import useRequest from '../../../../../util/useRequest';
import { required } from '../../../../../util/validators';

const QuestionCircleIcon = styled(PFQuestionCircleIcon)`
margin-left: 10px;
`;

const TestButton = styled(Button)`
margin-top: 20px;
`;

function MetadataStep({ i18n }) {
const form = useFormikContext();
const [selectedCredential] = useField('credential');
Expand Down Expand Up @@ -65,10 +60,6 @@ function MetadataStep({ i18n }) {
fetchMetadataOptions();
}, [fetchMetadataOptions]);

const testMetadata = () => {
// https://github.com/ansible/awx/issues/7126
};

if (isLoading) {
return <ContentLoading />;
}
Expand Down Expand Up @@ -136,20 +127,6 @@ function MetadataStep({ i18n }) {
</FormFullWidthLayout>
</Form>
)}
<Tooltip
content={i18n._(
t`Click this button to verify connection to the secret management system using the selected credential and specified inputs.`
)}
position="right"
>
<TestButton
variant="primary"
type="submit"
onClick={() => testMetadata()}
>
{i18n._(t`Test`)}
</TestButton>
</Tooltip>
</>
);
}
Expand Down
Loading

0 comments on commit 24e9484

Please sign in to comment.