mirror of
https://github.com/ansible/awx.git
synced 2026-03-18 17:37:30 -02:30
Merge pull request #10635 from nixocio/ui_issue_10613
Add extra step to confirm edition of login redirect URL
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
|||||||
BooleanField,
|
BooleanField,
|
||||||
InputField,
|
InputField,
|
||||||
ObjectField,
|
ObjectField,
|
||||||
|
InputAlertField,
|
||||||
} from '../../shared/SharedFields';
|
} from '../../shared/SharedFields';
|
||||||
import { RevertAllAlert, RevertFormActionGroup } from '../../shared';
|
import { RevertAllAlert, RevertFormActionGroup } from '../../shared';
|
||||||
import { formatJson, pluck } from '../../shared/settingUtils';
|
import { formatJson, pluck } from '../../shared/settingUtils';
|
||||||
@@ -211,7 +212,7 @@ function MiscAuthenticationEdit() {
|
|||||||
name="ALLOW_OAUTH2_FOR_EXTERNAL_USERS"
|
name="ALLOW_OAUTH2_FOR_EXTERNAL_USERS"
|
||||||
config={authentication.ALLOW_OAUTH2_FOR_EXTERNAL_USERS}
|
config={authentication.ALLOW_OAUTH2_FOR_EXTERNAL_USERS}
|
||||||
/>
|
/>
|
||||||
<InputField
|
<InputAlertField
|
||||||
name="LOGIN_REDIRECT_OVERRIDE"
|
name="LOGIN_REDIRECT_OVERRIDE"
|
||||||
config={authentication.LOGIN_REDIRECT_OVERRIDE}
|
config={authentication.LOGIN_REDIRECT_OVERRIDE}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -64,6 +64,46 @@ describe('<MiscAuthenticationEdit />', () => {
|
|||||||
await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0);
|
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 () => {
|
test('initially renders without crashing', async () => {
|
||||||
expect(wrapper.find('MiscAuthenticationEdit').length).toBe(1);
|
expect(wrapper.find('MiscAuthenticationEdit').length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,8 +10,11 @@ import {
|
|||||||
Switch,
|
Switch,
|
||||||
TextArea,
|
TextArea,
|
||||||
TextInput,
|
TextInput,
|
||||||
|
Tooltip,
|
||||||
|
ButtonVariant,
|
||||||
} from '@patternfly/react-core';
|
} from '@patternfly/react-core';
|
||||||
import FileUploadIcon from '@patternfly/react-icons/dist/js/icons/file-upload-icon';
|
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 styled from 'styled-components';
|
||||||
import AnsibleSelect from 'components/AnsibleSelect';
|
import AnsibleSelect from 'components/AnsibleSelect';
|
||||||
import CodeEditor from 'components/CodeEditor';
|
import CodeEditor from 'components/CodeEditor';
|
||||||
@@ -22,6 +25,12 @@ import { combine, integer, minMaxValue, required, url } from 'util/validators';
|
|||||||
import AlertModal from 'components/AlertModal';
|
import AlertModal from 'components/AlertModal';
|
||||||
import RevertButton from './RevertButton';
|
import RevertButton from './RevertButton';
|
||||||
|
|
||||||
|
const ExclamationCircleIcon = styled(PFExclamationCircleIcon)`
|
||||||
|
&& {
|
||||||
|
color: var(--pf-global--danger-color--100);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
const FormGroup = styled(PFFormGroup)`
|
const FormGroup = styled(PFFormGroup)`
|
||||||
.pf-c-form__group-label {
|
.pf-c-form__group-label {
|
||||||
display: inline-flex;
|
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 = ({
|
const SettingGroup = ({
|
||||||
children,
|
children,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
@@ -114,7 +130,9 @@ const BooleanField = ({
|
|||||||
{t`Cancel`}
|
{t`Cancel`}
|
||||||
</Button>,
|
</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,
|
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 InputField = ({ name, config, type = 'text', isRequired = false }) => {
|
||||||
const min_value = config?.min_value ?? Number.MIN_SAFE_INTEGER;
|
const min_value = config?.min_value ?? Number.MIN_SAFE_INTEGER;
|
||||||
const max_value = config?.max_value ?? Number.MAX_SAFE_INTEGER;
|
const max_value = config?.max_value ?? Number.MAX_SAFE_INTEGER;
|
||||||
@@ -407,4 +525,5 @@ export {
|
|||||||
InputField,
|
InputField,
|
||||||
ObjectField,
|
ObjectField,
|
||||||
TextAreaField,
|
TextAreaField,
|
||||||
|
InputAlertField,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
ChoiceField,
|
ChoiceField,
|
||||||
EncryptedField,
|
EncryptedField,
|
||||||
FileUploadField,
|
FileUploadField,
|
||||||
|
InputAlertField,
|
||||||
InputField,
|
InputField,
|
||||||
ObjectField,
|
ObjectField,
|
||||||
TextAreaField,
|
TextAreaField,
|
||||||
@@ -158,6 +159,30 @@ describe('Setting form fields', () => {
|
|||||||
expect(wrapper.find('TextInputBase').prop('value')).toEqual(0);
|
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 () => {
|
test('TextAreaField renders the expected content', async () => {
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<Formik
|
<Formik
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ export {
|
|||||||
EncryptedField,
|
EncryptedField,
|
||||||
InputField,
|
InputField,
|
||||||
ObjectField,
|
ObjectField,
|
||||||
|
InputAlertField,
|
||||||
} from './SharedFields';
|
} from './SharedFields';
|
||||||
|
|||||||
Reference in New Issue
Block a user