Merge pull request #10635 from nixocio/ui_issue_10613

Add extra step to confirm edition of login redirect URL
This commit is contained in:
Sarah Akus 2021-07-28 14:29:21 -04:00 committed by GitHub
commit 5d345c22b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 188 additions and 2 deletions

View File

@ -16,6 +16,7 @@ import {
BooleanField,
InputField,
ObjectField,
InputAlertField,
} from '../../shared/SharedFields';
import { RevertAllAlert, RevertFormActionGroup } from '../../shared';
import { formatJson, pluck } from '../../shared/settingUtils';
@ -211,7 +212,7 @@ function MiscAuthenticationEdit() {
name="ALLOW_OAUTH2_FOR_EXTERNAL_USERS"
config={authentication.ALLOW_OAUTH2_FOR_EXTERNAL_USERS}
/>
<InputField
<InputAlertField
name="LOGIN_REDIRECT_OVERRIDE"
config={authentication.LOGIN_REDIRECT_OVERRIDE}
/>

View File

@ -64,6 +64,46 @@ describe('<MiscAuthenticationEdit />', () => {
await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0);
});
test('should enable edit login redirect once alert is confirmed', async () => {
expect(
wrapper.find('TextInput#LOGIN_REDIRECT_OVERRIDE').prop('isDisabled')
).toBe(true);
await act(async () =>
wrapper
.find('Button[ouiaId="confirm-edit-login-redirect"]')
.simulate('click')
);
wrapper.update();
const modal = wrapper.find('AlertModal');
expect(modal).toHaveLength(1);
expect(modal.prop('isOpen')).toEqual(true);
await act(async () =>
modal
.find('Button[aria-label="confirm edit login redirect"]')
.simulate('click')
);
wrapper.update();
expect(
wrapper.find('TextInput#LOGIN_REDIRECT_OVERRIDE').prop('isDisabled')
).toBe(false);
await act(async () => {
wrapper.find('TextInput#LOGIN_REDIRECT_OVERRIDE').invoke('onChange')(
null,
{
target: {
name: 'LOGIN_REDIRECT_OVERRIDE',
value: 'bar',
},
}
);
});
wrapper.update();
expect(
wrapper.find('TextInput#LOGIN_REDIRECT_OVERRIDE').prop('value')
).toEqual('bar');
});
test('initially renders without crashing', async () => {
expect(wrapper.find('MiscAuthenticationEdit').length).toBe(1);
});

View File

@ -10,8 +10,11 @@ import {
Switch,
TextArea,
TextInput,
Tooltip,
ButtonVariant,
} from '@patternfly/react-core';
import FileUploadIcon from '@patternfly/react-icons/dist/js/icons/file-upload-icon';
import { ExclamationCircleIcon as PFExclamationCircleIcon } from '@patternfly/react-icons';
import styled from 'styled-components';
import AnsibleSelect from 'components/AnsibleSelect';
import CodeEditor from 'components/CodeEditor';
@ -22,6 +25,12 @@ import { combine, integer, minMaxValue, required, url } from 'util/validators';
import AlertModal from 'components/AlertModal';
import RevertButton from './RevertButton';
const ExclamationCircleIcon = styled(PFExclamationCircleIcon)`
&& {
color: var(--pf-global--danger-color--100);
}
`;
const FormGroup = styled(PFFormGroup)`
.pf-c-form__group-label {
display: inline-flex;
@ -30,6 +39,13 @@ const FormGroup = styled(PFFormGroup)`
}
`;
const Selected = styled.div`
display: flex;
justify-content: space-between;
background-color: white;
border-bottom-color: var(--pf-global--BorderColor--200);
`;
const SettingGroup = ({
children,
defaultValue,
@ -114,7 +130,9 @@ const BooleanField = ({
{t`Cancel`}
</Button>,
]}
>{t`Are you sure you want to disable local authentication? Doing so could impact users' ability to log in and the system administrator's ability to reverse this change.`}</AlertModal>
>
{t`Are you sure you want to disable local authentication? Doing so could impact users' ability to log in and the system administrator's ability to reverse this change.`}
</AlertModal>
);
}
@ -215,6 +233,106 @@ EncryptedField.propTypes = {
config: shape({}).isRequired,
};
const InputAlertField = ({ name, config }) => {
const [field, meta] = useField({ name });
const isValid = !(meta.touched && meta.error);
const [isModalOpen, setIsModalOpen] = useState(false);
const [isDisable, setIsDisable] = useState(true);
const handleSetIsOpen = () => {
setIsModalOpen(true);
};
const handleEnableTextInput = () => {
setIsDisable(false);
};
return config ? (
<>
<SettingGroup
defaultValue={config.default ?? ''}
fieldId={name}
helperTextInvalid={meta.error}
label={config.label}
popoverContent={config.help_text}
validated={isValid ? 'default' : 'error'}
isDisabled={isDisable}
>
<Selected>
{isDisable && (
<Tooltip
content={t`Edit Login redirect override URL`}
position="top"
>
<Button
onClick={() => {
handleSetIsOpen();
}}
ouiaId="confirm-edit-login-redirect"
variant={ButtonVariant.control}
>
<ExclamationCircleIcon />
</Button>
</Tooltip>
)}
<TextInput
id={name}
placeholder={config.placeholder}
validated={isValid ? 'default' : 'error'}
value={field.value}
onBlur={field.onBlur}
onChange={(value, event) => {
field.onChange(event);
}}
isDisabled={isDisable}
/>
</Selected>
</SettingGroup>
{isModalOpen && isDisable && (
<AlertModal
isOpen
title={t`Edit login redirect override URL`}
variant="danger"
aria-label={t`Edit login redirect override URL`}
onClose={() => {
setIsModalOpen(false);
}}
actions={[
<Button
key="confirm"
variant="danger"
aria-label={t`confirm edit login redirect`}
onClick={() => {
handleEnableTextInput();
setIsModalOpen(false);
}}
>
{t`Confirm`}
</Button>,
<Button
key="cancel"
variant="link"
aria-label={t`cancel edit login redirect`}
onClick={() => {
setIsModalOpen(false);
}}
>
{t`Cancel`}
</Button>,
]}
>
{t`Are you sure you want to edit login redirect override URL? Doing so could impact users' ability to log in to the system once local authentication is also disabled.`}
</AlertModal>
)}
</>
) : null;
};
InputAlertField.propTypes = {
name: string.isRequired,
config: shape({}).isRequired,
};
const InputField = ({ name, config, type = 'text', isRequired = false }) => {
const min_value = config?.min_value ?? Number.MIN_SAFE_INTEGER;
const max_value = config?.max_value ?? Number.MAX_SAFE_INTEGER;
@ -407,4 +525,5 @@ export {
InputField,
ObjectField,
TextAreaField,
InputAlertField,
};

View File

@ -9,6 +9,7 @@ import {
ChoiceField,
EncryptedField,
FileUploadField,
InputAlertField,
InputField,
ObjectField,
TextAreaField,
@ -158,6 +159,30 @@ describe('Setting form fields', () => {
expect(wrapper.find('TextInputBase').prop('value')).toEqual(0);
});
test('InputAlertField initially renders disable TextInput', async () => {
const wrapper = mountWithContexts(
<Formik
initialValues={{
text: '',
}}
>
{() => (
<InputAlertField
name="text"
config={{
label: 'test',
help_text: 'test',
default: '',
}}
/>
)}
</Formik>
);
expect(wrapper.find('TextInput')).toHaveLength(1);
expect(wrapper.find('TextInput').prop('value')).toEqual('');
expect(wrapper.find('TextInput').prop('isDisabled')).toBe(true);
});
test('TextAreaField renders the expected content', async () => {
const wrapper = mountWithContexts(
<Formik

View File

@ -7,4 +7,5 @@ export {
EncryptedField,
InputField,
ObjectField,
InputAlertField,
} from './SharedFields';