mirror of
https://github.com/ansible/awx.git
synced 2026-01-16 12:20:45 -03:30
Changes settings revert all to send DELETE on individual endpoint rather than PATCHing
This commit is contained in:
parent
d3b20e6585
commit
12504c9bc3
@ -29,6 +29,10 @@ class Settings extends Base {
|
||||
createTest(category, data) {
|
||||
return this.http.post(`${this.baseUrl}${category}/test/`, data);
|
||||
}
|
||||
|
||||
revertCategory(category) {
|
||||
return this.http.delete(`${this.baseUrl}${category}/`);
|
||||
}
|
||||
}
|
||||
|
||||
export default Settings;
|
||||
|
||||
@ -1,88 +0,0 @@
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import {
|
||||
mountWithContexts,
|
||||
waitForElement,
|
||||
} from '../../../../../testUtils/enzymeHelpers';
|
||||
import { SettingsProvider } from '../../../../contexts/Settings';
|
||||
import { SettingsAPI } from '../../../../api';
|
||||
import { assertDetail } from '../../shared/settingTestUtils';
|
||||
import mockAllOptions from '../../shared/data.allSettingOptions.json';
|
||||
import ActivityStreamDetail from './ActivityStreamDetail';
|
||||
|
||||
jest.mock('../../../../api');
|
||||
|
||||
describe('<ActivityStreamDetail />', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeAll(async () => {
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
ACTIVITY_STREAM_ENABLED: true,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: false,
|
||||
},
|
||||
});
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<SettingsProvider value={mockAllOptions.actions}>
|
||||
<ActivityStreamDetail />
|
||||
</SettingsProvider>
|
||||
);
|
||||
});
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
wrapper.unmount();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(wrapper.find('ActivityStreamDetail').length).toBe(1);
|
||||
});
|
||||
|
||||
test('should render expected tabs', () => {
|
||||
const expectedTabs = ['Back to Settings', 'Details'];
|
||||
wrapper.find('RoutedTabs li').forEach((tab, index) => {
|
||||
expect(tab.text()).toEqual(expectedTabs[index]);
|
||||
});
|
||||
});
|
||||
|
||||
test('should render expected details', () => {
|
||||
assertDetail(wrapper, 'Enable Activity Stream', 'On');
|
||||
assertDetail(wrapper, 'Enable Activity Stream for Inventory Sync', 'Off');
|
||||
});
|
||||
|
||||
test('should hide edit button from non-superusers', async () => {
|
||||
const config = {
|
||||
me: {
|
||||
is_superuser: false,
|
||||
},
|
||||
};
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<SettingsProvider value={mockAllOptions.actions}>
|
||||
<ActivityStreamDetail />
|
||||
</SettingsProvider>,
|
||||
{
|
||||
context: { config },
|
||||
}
|
||||
);
|
||||
});
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
expect(wrapper.find('Button[aria-label="Edit"]').exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should display content error when api throws error on initial render', async () => {
|
||||
SettingsAPI.readCategory.mockRejectedValue(new Error());
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<SettingsProvider value={mockAllOptions.actions}>
|
||||
<ActivityStreamDetail />
|
||||
</SettingsProvider>
|
||||
);
|
||||
});
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
expect(wrapper.find('ContentError').length).toBe(1);
|
||||
});
|
||||
});
|
||||
@ -1 +0,0 @@
|
||||
export { default } from './ActivityStreamDetail';
|
||||
@ -1,130 +0,0 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { Formik } from 'formik';
|
||||
import { Form } from '@patternfly/react-core';
|
||||
import { CardBody } from '../../../../components/Card';
|
||||
import ContentError from '../../../../components/ContentError';
|
||||
import ContentLoading from '../../../../components/ContentLoading';
|
||||
import { FormSubmitError } from '../../../../components/FormField';
|
||||
import { FormColumnLayout } from '../../../../components/FormLayout';
|
||||
import { useSettings } from '../../../../contexts/Settings';
|
||||
import {
|
||||
BooleanField,
|
||||
RevertAllAlert,
|
||||
RevertFormActionGroup,
|
||||
} from '../../shared';
|
||||
import useModal from '../../../../util/useModal';
|
||||
import useRequest from '../../../../util/useRequest';
|
||||
import { SettingsAPI } from '../../../../api';
|
||||
|
||||
function ActivityStreamEdit() {
|
||||
const history = useHistory();
|
||||
const { isModalOpen, toggleModal, closeModal } = useModal();
|
||||
const { PUT: options } = useSettings();
|
||||
|
||||
const {
|
||||
isLoading,
|
||||
error,
|
||||
request,
|
||||
result: {
|
||||
ACTIVITY_STREAM_ENABLED,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC,
|
||||
},
|
||||
} = useRequest(
|
||||
useCallback(async () => {
|
||||
const { data } = await SettingsAPI.readCategory('system');
|
||||
return {
|
||||
ACTIVITY_STREAM_ENABLED: {
|
||||
...options.ACTIVITY_STREAM_ENABLED,
|
||||
value: data.ACTIVITY_STREAM_ENABLED,
|
||||
},
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: {
|
||||
...options.ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC,
|
||||
value: data.ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC,
|
||||
},
|
||||
};
|
||||
}, [options]),
|
||||
{}
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
request();
|
||||
}, [request]);
|
||||
|
||||
const { error: submitError, request: submitForm } = useRequest(
|
||||
useCallback(
|
||||
async values => {
|
||||
await SettingsAPI.updateAll(values);
|
||||
history.push('/settings/activity_stream/details');
|
||||
},
|
||||
[history]
|
||||
),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm(form);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
history.push('/settings/activity_stream/details');
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = {
|
||||
ACTIVITY_STREAM_ENABLED: ACTIVITY_STREAM_ENABLED.default,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC:
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC.default,
|
||||
};
|
||||
await submitForm(defaultValues);
|
||||
closeModal();
|
||||
};
|
||||
|
||||
return (
|
||||
<CardBody>
|
||||
{isLoading && <ContentLoading />}
|
||||
{!isLoading && error && <ContentError error={error} />}
|
||||
{!isLoading && ACTIVITY_STREAM_ENABLED && (
|
||||
<Formik
|
||||
initialValues={{
|
||||
ACTIVITY_STREAM_ENABLED: ACTIVITY_STREAM_ENABLED.value,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC:
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC.value,
|
||||
}}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{formik => {
|
||||
return (
|
||||
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
|
||||
<FormColumnLayout>
|
||||
<BooleanField
|
||||
name="ACTIVITY_STREAM_ENABLED"
|
||||
config={ACTIVITY_STREAM_ENABLED}
|
||||
/>
|
||||
<BooleanField
|
||||
name="ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC"
|
||||
config={ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
onSubmit={formik.handleSubmit}
|
||||
onRevert={toggleModal}
|
||||
/>
|
||||
{isModalOpen && (
|
||||
<RevertAllAlert
|
||||
onClose={closeModal}
|
||||
onRevertAll={handleRevertAll}
|
||||
/>
|
||||
)}
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
</Formik>
|
||||
)}
|
||||
</CardBody>
|
||||
);
|
||||
}
|
||||
|
||||
export default ActivityStreamEdit;
|
||||
@ -1 +0,0 @@
|
||||
export { default } from './ActivityStreamEdit';
|
||||
@ -1 +0,0 @@
|
||||
export { default } from './ActivityStream';
|
||||
@ -55,6 +55,13 @@ function AzureADEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('azuread-oauth2');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm({
|
||||
...form,
|
||||
@ -68,13 +75,11 @@ function AzureADEdit() {
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(azure).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/azure/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -120,6 +125,7 @@ function AzureADEdit() {
|
||||
config={azure.SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<AzureADEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -60,7 +61,7 @@ describe('<AzureADEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -75,13 +76,8 @@ describe('<AzureADEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
SOCIAL_AUTH_AZUREAD_OAUTH2_KEY: '',
|
||||
SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET: '',
|
||||
SOCIAL_AUTH_AZUREAD_OAUTH2_ORGANIZATION_MAP: null,
|
||||
SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP: null,
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('azuread-oauth2');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -55,6 +55,13 @@ function GitHubEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('github');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm({
|
||||
...form,
|
||||
@ -66,13 +73,11 @@ function GitHubEdit() {
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(github).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/github/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -118,6 +123,7 @@ function GitHubEdit() {
|
||||
config={github.SOCIAL_AUTH_GITHUB_TEAM_MAP}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<GitHubEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -72,7 +73,7 @@ describe('<GitHubEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -87,13 +88,8 @@ describe('<GitHubEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
SOCIAL_AUTH_GITHUB_KEY: '',
|
||||
SOCIAL_AUTH_GITHUB_SECRET: '',
|
||||
SOCIAL_AUTH_GITHUB_ORGANIZATION_MAP: null,
|
||||
SOCIAL_AUTH_GITHUB_TEAM_MAP: null,
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('github');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -55,6 +55,13 @@ function GitHubEnterpriseEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('github-enterprise');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm({
|
||||
...form,
|
||||
@ -68,13 +75,11 @@ function GitHubEnterpriseEdit() {
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(github).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/github/enterprise/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -128,6 +133,7 @@ function GitHubEnterpriseEdit() {
|
||||
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<GitHubEnterpriseEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -82,7 +83,7 @@ describe('<GitHubEnterpriseEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -97,15 +98,10 @@ describe('<GitHubEnterpriseEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_URL: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP: null,
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP: null,
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith(
|
||||
'github-enterprise'
|
||||
);
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -55,6 +55,13 @@ function GitHubEnterpriseOrgEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('github-enterprise-org');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm({
|
||||
...form,
|
||||
@ -68,13 +75,11 @@ function GitHubEnterpriseOrgEdit() {
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(github).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/github/enterprise_organization/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -134,6 +139,7 @@ function GitHubEnterpriseOrgEdit() {
|
||||
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<GitHubEnterpriseOrgEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -94,7 +95,7 @@ describe('<GitHubEnterpriseOrgEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -109,16 +110,10 @@ describe('<GitHubEnterpriseOrgEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_API_URL: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_KEY: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_SECRET: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_NAME: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_ORGANIZATION_MAP: null,
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP: null,
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith(
|
||||
'github-enterprise-org'
|
||||
);
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -55,6 +55,13 @@ function GitHubEnterpriseTeamEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('github-enterprise-team');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm({
|
||||
...form,
|
||||
@ -68,13 +75,11 @@ function GitHubEnterpriseTeamEdit() {
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(github).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/github/enterprise_team/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -134,6 +139,7 @@ function GitHubEnterpriseTeamEdit() {
|
||||
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<GitHubEnterpriseTeamEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -88,7 +89,7 @@ describe('<GitHubEnterpriseTeamEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -103,16 +104,10 @@ describe('<GitHubEnterpriseTeamEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_API_URL: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_KEY: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_SECRET: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ID: '',
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_ORGANIZATION_MAP: null,
|
||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP: null,
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith(
|
||||
'github-enterprise-team'
|
||||
);
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -55,6 +55,13 @@ function GitHubOrgEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('github-org');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm({
|
||||
...form,
|
||||
@ -68,13 +75,11 @@ function GitHubOrgEdit() {
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(github).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/github/organization/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -124,6 +129,7 @@ function GitHubOrgEdit() {
|
||||
config={github.SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<GitHubOrgEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -79,7 +80,7 @@ describe('<GitHubOrgEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -94,14 +95,8 @@ describe('<GitHubOrgEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
SOCIAL_AUTH_GITHUB_ORG_KEY: '',
|
||||
SOCIAL_AUTH_GITHUB_ORG_SECRET: '',
|
||||
SOCIAL_AUTH_GITHUB_ORG_NAME: '',
|
||||
SOCIAL_AUTH_GITHUB_ORG_ORGANIZATION_MAP: null,
|
||||
SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP: null,
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('github-org');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -55,6 +55,13 @@ function GitHubTeamEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('github-team');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm({
|
||||
...form,
|
||||
@ -68,13 +75,11 @@ function GitHubTeamEdit() {
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(github).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/github/team/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -124,6 +129,7 @@ function GitHubTeamEdit() {
|
||||
config={github.SOCIAL_AUTH_GITHUB_TEAM_TEAM_MAP}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<GitHubTeamEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -74,7 +75,7 @@ describe('<GitHubTeamEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -89,14 +90,8 @@ describe('<GitHubTeamEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
SOCIAL_AUTH_GITHUB_TEAM_KEY: '',
|
||||
SOCIAL_AUTH_GITHUB_TEAM_SECRET: '',
|
||||
SOCIAL_AUTH_GITHUB_TEAM_ID: '',
|
||||
SOCIAL_AUTH_GITHUB_TEAM_ORGANIZATION_MAP: null,
|
||||
SOCIAL_AUTH_GITHUB_TEAM_TEAM_MAP: null,
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('github-team');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -60,6 +60,13 @@ function GoogleOAuth2Edit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('google-oauth2');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm({
|
||||
...form,
|
||||
@ -79,13 +86,11 @@ function GoogleOAuth2Edit() {
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(googleOAuth2).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/google_oauth2/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -148,6 +153,7 @@ function GoogleOAuth2Edit() {
|
||||
config={googleOAuth2.SOCIAL_AUTH_GOOGLE_OAUTH2_TEAM_MAP}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<GoogleOAuth2Edit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -82,7 +83,7 @@ describe('<GoogleOAuth2Edit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -97,15 +98,8 @@ describe('<GoogleOAuth2Edit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY: '',
|
||||
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET: '',
|
||||
SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS: [],
|
||||
SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS: {},
|
||||
SOCIAL_AUTH_GOOGLE_OAUTH2_ORGANIZATION_MAP: null,
|
||||
SOCIAL_AUTH_GOOGLE_OAUTH2_TEAM_MAP: null,
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('google-oauth2');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -63,6 +63,13 @@ function JobsEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('jobs');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm({
|
||||
...form,
|
||||
@ -76,12 +83,11 @@ function JobsEdit() {
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = {};
|
||||
Object.entries(jobs).forEach(([key, value]) => {
|
||||
defaultValues[key] = value.default;
|
||||
});
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/jobs/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -181,6 +187,7 @@ function JobsEdit() {
|
||||
/>
|
||||
<ObjectField name="AWX_TASK_ENV" config={jobs.AWX_TASK_ENV} />
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -7,7 +7,6 @@ import {
|
||||
} from '../../../../../testUtils/enzymeHelpers';
|
||||
import mockAllOptions from '../../shared/data.allSettingOptions.json';
|
||||
import mockJobSettings from '../../shared/data.jobSettings.json';
|
||||
import mockDefaultJobSettings from './data.defaultJobSettings.json';
|
||||
import { SettingsProvider } from '../../../../contexts/Settings';
|
||||
import { SettingsAPI } from '../../../../api';
|
||||
import JobsEdit from './JobsEdit';
|
||||
@ -19,6 +18,7 @@ describe('<JobsEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: mockJobSettings,
|
||||
@ -51,7 +51,7 @@ describe('<JobsEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -66,8 +66,8 @@ describe('<JobsEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith(mockDefaultJobSettings);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('jobs');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -75,14 +75,19 @@ function LoggingEdit() {
|
||||
});
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = {};
|
||||
Object.entries(logging).forEach(([key, value]) => {
|
||||
defaultValues[key] = value.default;
|
||||
});
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('logging');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
await revertAll();
|
||||
|
||||
await submitForm(defaultValues);
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/logging/details');
|
||||
};
|
||||
|
||||
const {
|
||||
@ -221,6 +226,7 @@ function LoggingEdit() {
|
||||
config={logging.LOG_AGGREGATOR_LOGGERS}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
onSubmit={formik.handleSubmit}
|
||||
|
||||
@ -35,29 +35,6 @@ const mockSettings = {
|
||||
LOG_AGGREGATOR_MAX_DISK_USAGE_PATH: '/var/lib/awx',
|
||||
LOG_AGGREGATOR_RSYSLOGD_DEBUG: false,
|
||||
};
|
||||
const mockDefaultSettings = {
|
||||
LOG_AGGREGATOR_HOST: null,
|
||||
LOG_AGGREGATOR_PORT: null,
|
||||
LOG_AGGREGATOR_TYPE: null,
|
||||
LOG_AGGREGATOR_USERNAME: '',
|
||||
LOG_AGGREGATOR_PASSWORD: '',
|
||||
LOG_AGGREGATOR_LOGGERS: [
|
||||
'awx',
|
||||
'activity_stream',
|
||||
'job_events',
|
||||
'system_tracking',
|
||||
],
|
||||
LOG_AGGREGATOR_INDIVIDUAL_FACTS: false,
|
||||
LOG_AGGREGATOR_ENABLED: false,
|
||||
LOG_AGGREGATOR_TOWER_UUID: '',
|
||||
LOG_AGGREGATOR_PROTOCOL: 'https',
|
||||
LOG_AGGREGATOR_TCP_TIMEOUT: 5,
|
||||
LOG_AGGREGATOR_VERIFY_CERT: true,
|
||||
LOG_AGGREGATOR_LEVEL: 'INFO',
|
||||
LOG_AGGREGATOR_MAX_DISK_USAGE_GB: 1,
|
||||
LOG_AGGREGATOR_MAX_DISK_USAGE_PATH: '/var/lib/awx',
|
||||
LOG_AGGREGATOR_RSYSLOGD_DEBUG: false,
|
||||
};
|
||||
|
||||
describe('<LoggingEdit />', () => {
|
||||
let wrapper;
|
||||
@ -68,6 +45,7 @@ describe('<LoggingEdit />', () => {
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: mockSettings,
|
||||
@ -227,7 +205,7 @@ describe('<LoggingEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -242,8 +220,8 @@ describe('<LoggingEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith(mockDefaultSettings);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('logging');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -1,15 +1,14 @@
|
||||
import React from 'react';
|
||||
import { Link, Redirect, Route, Switch } from 'react-router-dom';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
import { PageSection, Card } from '@patternfly/react-core';
|
||||
import ContentError from '../../../components/ContentError';
|
||||
import { useConfig } from '../../../contexts/Config';
|
||||
import ActivityStreamDetail from './ActivityStreamDetail';
|
||||
import ActivityStreamEdit from './ActivityStreamEdit';
|
||||
import MiscAuthenticationDetail from './MiscAuthenticationDetail';
|
||||
import MiscAuthenticationEdit from './MiscAuthenticationEdit';
|
||||
|
||||
function ActivityStream() {
|
||||
const baseURL = '/settings/activity_stream';
|
||||
function MiscAuthentication() {
|
||||
const baseURL = '/settings/miscellaneous_authentication';
|
||||
const { me } = useConfig();
|
||||
|
||||
return (
|
||||
@ -18,11 +17,11 @@ function ActivityStream() {
|
||||
<Switch>
|
||||
<Redirect from={baseURL} to={`${baseURL}/details`} exact />
|
||||
<Route path={`${baseURL}/details`}>
|
||||
<ActivityStreamDetail />
|
||||
<MiscAuthenticationDetail />
|
||||
</Route>
|
||||
<Route path={`${baseURL}/edit`}>
|
||||
{me?.is_superuser ? (
|
||||
<ActivityStreamEdit />
|
||||
<MiscAuthenticationEdit />
|
||||
) : (
|
||||
<Redirect to={`${baseURL}/details`} />
|
||||
)}
|
||||
@ -30,7 +29,7 @@ function ActivityStream() {
|
||||
<Route key="not-found" path={`${baseURL}/*`}>
|
||||
<ContentError isNotFound>
|
||||
<Link to={`${baseURL}/details`}>
|
||||
{t`View Activity Stream settings`}
|
||||
{t`View Miscellaneous Authentication settings`}
|
||||
</Link>
|
||||
</ContentError>
|
||||
</Route>
|
||||
@ -40,4 +39,4 @@ function ActivityStream() {
|
||||
);
|
||||
}
|
||||
|
||||
export default ActivityStream;
|
||||
export default MiscAuthentication;
|
||||
@ -5,55 +5,57 @@ import {
|
||||
mountWithContexts,
|
||||
waitForElement,
|
||||
} from '../../../../testUtils/enzymeHelpers';
|
||||
import ActivityStream from './ActivityStream';
|
||||
import { SettingsAPI } from '../../../api';
|
||||
import MiscAuthentication from './MiscAuthentication';
|
||||
|
||||
jest.mock('../../../api/models/Settings');
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
ACTIVITY_STREAM_ENABLED: true,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: false,
|
||||
},
|
||||
});
|
||||
jest.mock('../../../api');
|
||||
|
||||
describe('<ActivityStream />', () => {
|
||||
describe('<MiscAuthentication />', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {},
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.unmount();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('should render activity stream details', async () => {
|
||||
test('should render miscellaneous authentication details', async () => {
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/settings/activity_stream/details'],
|
||||
initialEntries: ['/settings/miscellaneous_authentication/details'],
|
||||
});
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(<ActivityStream />, {
|
||||
wrapper = mountWithContexts(<MiscAuthentication />, {
|
||||
context: { router: { history } },
|
||||
});
|
||||
});
|
||||
expect(wrapper.find('ActivityStreamDetail').length).toBe(1);
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
expect(wrapper.find('MiscAuthenticationDetail').length).toBe(1);
|
||||
});
|
||||
|
||||
test('should render activity stream edit', async () => {
|
||||
test('should render miscellaneous authentication edit', async () => {
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/settings/activity_stream/edit'],
|
||||
initialEntries: ['/settings/miscellaneous_authentication/edit'],
|
||||
});
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(<ActivityStream />, {
|
||||
wrapper = mountWithContexts(<MiscAuthentication />, {
|
||||
context: { router: { history } },
|
||||
});
|
||||
});
|
||||
expect(wrapper.find('ActivityStreamEdit').length).toBe(1);
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
expect(wrapper.find('MiscAuthenticationEdit').length).toBe(1);
|
||||
});
|
||||
|
||||
test('should show content error when user navigates to erroneous route', async () => {
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/settings/activity_stream/foo'],
|
||||
initialEntries: ['/settings/miscellaneous_authentication/foo'],
|
||||
});
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(<ActivityStream />, {
|
||||
wrapper = mountWithContexts(<MiscAuthentication />, {
|
||||
context: { router: { history } },
|
||||
});
|
||||
});
|
||||
@ -62,10 +64,10 @@ describe('<ActivityStream />', () => {
|
||||
|
||||
test('should redirect to details for users without system admin permissions', async () => {
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/settings/activity_stream/edit'],
|
||||
initialEntries: ['/settings/miscellaneous_authentication/edit'],
|
||||
});
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(<ActivityStream />, {
|
||||
wrapper = mountWithContexts(<MiscAuthentication />, {
|
||||
context: {
|
||||
router: {
|
||||
history,
|
||||
@ -79,7 +81,7 @@ describe('<ActivityStream />', () => {
|
||||
});
|
||||
});
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
expect(wrapper.find('ActivityStreamDetail').length).toBe(1);
|
||||
expect(wrapper.find('ActivityStreamEdit').length).toBe(0);
|
||||
expect(wrapper.find('MiscAuthenticationDetail').length).toBe(1);
|
||||
expect(wrapper.find('MiscAuthenticationEdit').length).toBe(0);
|
||||
});
|
||||
});
|
||||
@ -1,36 +1,27 @@
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
import { CaretLeftIcon } from '@patternfly/react-icons';
|
||||
import { Button } from '@patternfly/react-core';
|
||||
import { CaretLeftIcon } from '@patternfly/react-icons';
|
||||
import { CardBody, CardActionsRow } from '../../../../components/Card';
|
||||
import ContentLoading from '../../../../components/ContentLoading';
|
||||
import ContentError from '../../../../components/ContentError';
|
||||
import { DetailList } from '../../../../components/DetailList';
|
||||
import RoutedTabs from '../../../../components/RoutedTabs';
|
||||
import useRequest from '../../../../util/useRequest';
|
||||
import { useConfig } from '../../../../contexts/Config';
|
||||
import { useSettings } from '../../../../contexts/Settings';
|
||||
import useRequest from '../../../../util/useRequest';
|
||||
import { SettingsAPI } from '../../../../api';
|
||||
import { SettingDetail } from '../../shared';
|
||||
|
||||
function ActivityStreamDetail() {
|
||||
function MiscAuthenticationDetail() {
|
||||
const { me } = useConfig();
|
||||
const { GET: options } = useSettings();
|
||||
|
||||
const { isLoading, error, request, result: activityStream } = useRequest(
|
||||
const { isLoading, error, request, result: authentication } = useRequest(
|
||||
useCallback(async () => {
|
||||
const {
|
||||
data: {
|
||||
ACTIVITY_STREAM_ENABLED,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC,
|
||||
},
|
||||
} = await SettingsAPI.readCategory('system');
|
||||
return {
|
||||
ACTIVITY_STREAM_ENABLED,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC,
|
||||
};
|
||||
const { data } = await SettingsAPI.readCategory('authentication');
|
||||
return data;
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
@ -52,7 +43,7 @@ function ActivityStreamDetail() {
|
||||
},
|
||||
{
|
||||
name: t`Details`,
|
||||
link: `/settings/activity_stream/details`,
|
||||
link: `/settings/miscellaneous_authentication/details`,
|
||||
id: 0,
|
||||
},
|
||||
];
|
||||
@ -63,9 +54,9 @@ function ActivityStreamDetail() {
|
||||
<CardBody>
|
||||
{isLoading && <ContentLoading />}
|
||||
{!isLoading && error && <ContentError error={error} />}
|
||||
{!isLoading && activityStream && (
|
||||
{!isLoading && authentication && (
|
||||
<DetailList>
|
||||
{Object.keys(activityStream).map(key => {
|
||||
{Object.keys(authentication).map(key => {
|
||||
const record = options?.[key];
|
||||
return (
|
||||
<SettingDetail
|
||||
@ -75,7 +66,7 @@ function ActivityStreamDetail() {
|
||||
label={record?.label}
|
||||
type={record?.type}
|
||||
unit={record?.unit}
|
||||
value={activityStream?.[key]}
|
||||
value={authentication?.[key]}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@ -84,10 +75,10 @@ function ActivityStreamDetail() {
|
||||
{me?.is_superuser && (
|
||||
<CardActionsRow>
|
||||
<Button
|
||||
ouiaId="activity-stream-detail-edit-button"
|
||||
ouiaId="authentication-detail-edit-button"
|
||||
aria-label={t`Edit`}
|
||||
component={Link}
|
||||
to="/settings/activity_stream/edit"
|
||||
to="/settings/miscellaneous_authentication/edit"
|
||||
>
|
||||
{t`Edit`}
|
||||
</Button>
|
||||
@ -98,4 +89,4 @@ function ActivityStreamDetail() {
|
||||
);
|
||||
}
|
||||
|
||||
export default ActivityStreamDetail;
|
||||
export default MiscAuthenticationDetail;
|
||||
@ -0,0 +1,128 @@
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import {
|
||||
mountWithContexts,
|
||||
waitForElement,
|
||||
} from '../../../../../testUtils/enzymeHelpers';
|
||||
import { SettingsProvider } from '../../../../contexts/Settings';
|
||||
import { SettingsAPI } from '../../../../api';
|
||||
import {
|
||||
assertDetail,
|
||||
assertVariableDetail,
|
||||
} from '../../shared/settingTestUtils';
|
||||
import mockAllOptions from '../../shared/data.allSettingOptions.json';
|
||||
import MiscAuthenticationDetail from './MiscAuthenticationDetail';
|
||||
|
||||
jest.mock('../../../../api');
|
||||
|
||||
describe('<MiscAuthenticationDetail />', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeEach(async () => {
|
||||
SettingsAPI.readCategory = jest.fn();
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
SESSION_COOKIE_AGE: 1800,
|
||||
SESSIONS_PER_USER: -1,
|
||||
DISABLE_LOCAL_AUTH: false,
|
||||
AUTH_BASIC_ENABLED: true,
|
||||
OAUTH2_PROVIDER: {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS: 31536000000,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS: 2628000,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS: 600,
|
||||
},
|
||||
ALLOW_OAUTH2_FOR_EXTERNAL_USERS: false,
|
||||
LOGIN_REDIRECT_OVERRIDE: 'https://foohost',
|
||||
AUTHENTICATION_BACKENDS: [
|
||||
'awx.sso.backends.TACACSPlusBackend',
|
||||
'awx.main.backends.AWXModelBackend',
|
||||
],
|
||||
SOCIAL_AUTH_ORGANIZATION_MAP: {},
|
||||
SOCIAL_AUTH_TEAM_MAP: {},
|
||||
SOCIAL_AUTH_USER_FIELDS: [],
|
||||
},
|
||||
});
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<SettingsProvider value={mockAllOptions.actions}>
|
||||
<MiscAuthenticationDetail />
|
||||
</SettingsProvider>
|
||||
);
|
||||
});
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(wrapper.find('MiscAuthenticationDetail').length).toBe(1);
|
||||
});
|
||||
|
||||
test('should render expected tabs', () => {
|
||||
const expectedTabs = ['Back to Settings', 'Details'];
|
||||
wrapper.find('RoutedTabs li').forEach((tab, index) => {
|
||||
expect(tab.text()).toEqual(expectedTabs[index]);
|
||||
});
|
||||
});
|
||||
|
||||
test('should render expected details', () => {
|
||||
assertDetail(wrapper, 'Disable the built-in authentication system', 'Off');
|
||||
assertVariableDetail(
|
||||
wrapper,
|
||||
'OAuth 2 Timeout Settings',
|
||||
'{\n "ACCESS_TOKEN_EXPIRE_SECONDS": 31536000000,\n "REFRESH_TOKEN_EXPIRE_SECONDS": 2628000,\n "AUTHORIZATION_CODE_EXPIRE_SECONDS": 600\n}'
|
||||
);
|
||||
assertDetail(wrapper, 'Login redirect override URL', 'https://foohost');
|
||||
assertVariableDetail(
|
||||
wrapper,
|
||||
'Authentication Backends',
|
||||
'[\n "awx.sso.backends.TACACSPlusBackend",\n "awx.main.backends.AWXModelBackend"\n]'
|
||||
);
|
||||
assertVariableDetail(wrapper, 'Social Auth Organization Map', '{}');
|
||||
assertVariableDetail(wrapper, 'Social Auth Team Map', '{}');
|
||||
assertVariableDetail(wrapper, 'Social Auth User Fields', '[]');
|
||||
assertDetail(
|
||||
wrapper,
|
||||
'Allow External Users to Create OAuth2 Tokens',
|
||||
'Off'
|
||||
);
|
||||
assertDetail(wrapper, 'Enable HTTP Basic Auth', 'On');
|
||||
assertDetail(wrapper, 'Idle Time Force Log Out', '1800 seconds');
|
||||
assertDetail(
|
||||
wrapper,
|
||||
'Maximum number of simultaneous logged in sessions',
|
||||
'-1'
|
||||
);
|
||||
});
|
||||
|
||||
test('should hide edit button from non-superusers', async () => {
|
||||
const config = {
|
||||
me: {
|
||||
is_superuser: false,
|
||||
},
|
||||
};
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<SettingsProvider value={mockAllOptions.actions}>
|
||||
<MiscAuthenticationDetail />
|
||||
</SettingsProvider>,
|
||||
{
|
||||
context: { config },
|
||||
}
|
||||
);
|
||||
});
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
expect(wrapper.find('Button[aria-label="Edit"]').exists()).toBeFalsy();
|
||||
});
|
||||
|
||||
test('should display content error when api throws error on initial render', async () => {
|
||||
SettingsAPI.readCategory.mockRejectedValue(new Error());
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<SettingsProvider value={mockAllOptions.actions}>
|
||||
<MiscAuthenticationDetail />
|
||||
</SettingsProvider>
|
||||
);
|
||||
});
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
expect(wrapper.find('ContentError').length).toBe(1);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1 @@
|
||||
export { default } from './MiscAuthenticationDetail';
|
||||
@ -0,0 +1,270 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import { t } from '@lingui/macro';
|
||||
import { Formik } from 'formik';
|
||||
import { Form } from '@patternfly/react-core';
|
||||
import { CardBody } from '../../../../components/Card';
|
||||
import ContentError from '../../../../components/ContentError';
|
||||
import ContentLoading from '../../../../components/ContentLoading';
|
||||
import { FormSubmitError } from '../../../../components/FormField';
|
||||
import { FormColumnLayout } from '../../../../components/FormLayout';
|
||||
import { useSettings } from '../../../../contexts/Settings';
|
||||
import { RevertAllAlert, RevertFormActionGroup } from '../../shared';
|
||||
import {
|
||||
BooleanField,
|
||||
InputField,
|
||||
ObjectField,
|
||||
} from '../../shared/SharedFields';
|
||||
import useModal from '../../../../util/useModal';
|
||||
import useRequest from '../../../../util/useRequest';
|
||||
import { SettingsAPI } from '../../../../api';
|
||||
import { formatJson, pluck } from '../../shared/settingUtils';
|
||||
|
||||
function MiscAuthenticationEdit() {
|
||||
const history = useHistory();
|
||||
const { isModalOpen, toggleModal, closeModal } = useModal();
|
||||
const { PUT: options } = useSettings();
|
||||
|
||||
const {
|
||||
isLoading,
|
||||
error,
|
||||
request: fetchAuthentication,
|
||||
result: authentication,
|
||||
} = useRequest(
|
||||
useCallback(async () => {
|
||||
const { data } = await SettingsAPI.readCategory('authentication');
|
||||
|
||||
const {
|
||||
OAUTH2_PROVIDER: {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
},
|
||||
...pluckedAuthenticationData
|
||||
} = pluck(
|
||||
data,
|
||||
'ALLOW_OAUTH2_FOR_EXTERNAL_USERS',
|
||||
'AUTH_BASIC_ENABLED',
|
||||
'LOGIN_REDIRECT_OVERRIDE',
|
||||
'DISABLE_LOCAL_AUTH',
|
||||
'OAUTH2_PROVIDER',
|
||||
'SESSIONS_PER_USER',
|
||||
'SESSION_COOKIE_AGE',
|
||||
'SOCIAL_AUTH_ORGANIZATION_MAP',
|
||||
'SOCIAL_AUTH_TEAM_MAP',
|
||||
'SOCIAL_AUTH_USER_FIELDS'
|
||||
);
|
||||
|
||||
const authenticationData = {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
...pluckedAuthenticationData,
|
||||
};
|
||||
|
||||
const {
|
||||
OAUTH2_PROVIDER: OAUTH2_PROVIDER_OPTIONS,
|
||||
...restOptions
|
||||
} = options;
|
||||
|
||||
const authenticationOptions = {
|
||||
...restOptions,
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS: {
|
||||
...OAUTH2_PROVIDER_OPTIONS,
|
||||
default: OAUTH2_PROVIDER_OPTIONS.default.ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
type: OAUTH2_PROVIDER_OPTIONS.child.type,
|
||||
label: t`Access Token Expiration`,
|
||||
},
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS: {
|
||||
...OAUTH2_PROVIDER_OPTIONS,
|
||||
default: OAUTH2_PROVIDER_OPTIONS.default.REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
type: OAUTH2_PROVIDER_OPTIONS.child.type,
|
||||
label: t`Refresh Token Expiration`,
|
||||
},
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS: {
|
||||
...OAUTH2_PROVIDER_OPTIONS,
|
||||
default:
|
||||
OAUTH2_PROVIDER_OPTIONS.default.AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
type: OAUTH2_PROVIDER_OPTIONS.child.type,
|
||||
label: t`Authorization Code Expiration`,
|
||||
},
|
||||
};
|
||||
|
||||
const mergedData = {};
|
||||
|
||||
Object.keys(authenticationData).forEach(key => {
|
||||
if (!authenticationOptions[key]) {
|
||||
return;
|
||||
}
|
||||
mergedData[key] = authenticationOptions[key];
|
||||
mergedData[key].value = authenticationData[key];
|
||||
});
|
||||
|
||||
return mergedData;
|
||||
}, [options]),
|
||||
null
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
fetchAuthentication();
|
||||
}, [fetchAuthentication]);
|
||||
|
||||
const { error: submitError, request: submitForm } = useRequest(
|
||||
useCallback(
|
||||
async values => {
|
||||
await SettingsAPI.updateAll(values);
|
||||
history.push('/settings/miscellaneous_authentication/details');
|
||||
},
|
||||
[history]
|
||||
),
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('authentication');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
const {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
...formData
|
||||
} = form;
|
||||
|
||||
await submitForm({
|
||||
...formData,
|
||||
OAUTH2_PROVIDER: {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
},
|
||||
SOCIAL_AUTH_ORGANIZATION_MAP: formatJson(
|
||||
formData.SOCIAL_AUTH_ORGANIZATION_MAP
|
||||
),
|
||||
SOCIAL_AUTH_TEAM_MAP: formatJson(formData.SOCIAL_AUTH_TEAM_MAP),
|
||||
SOCIAL_AUTH_USER_FIELDS: formatJson(formData.SOCIAL_AUTH_USER_FIELDS),
|
||||
});
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/miscellaneous_authentication/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
history.push('/settings/miscellaneous_authentication/details');
|
||||
};
|
||||
|
||||
const initialValues = fields =>
|
||||
Object.keys(fields).reduce((acc, key) => {
|
||||
if (fields[key].type === 'list' || fields[key].type === 'nested object') {
|
||||
const emptyDefault = fields[key].type === 'list' ? '[]' : '{}';
|
||||
acc[key] = fields[key].value
|
||||
? JSON.stringify(fields[key].value, null, 2)
|
||||
: emptyDefault;
|
||||
} else {
|
||||
acc[key] = fields[key].value ?? '';
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return (
|
||||
<CardBody>
|
||||
{isLoading && <ContentLoading />}
|
||||
{!isLoading && error && <ContentError error={error} />}
|
||||
{!isLoading && authentication && (
|
||||
<Formik
|
||||
initialValues={initialValues(authentication)}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{formik => (
|
||||
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
|
||||
<FormColumnLayout>
|
||||
<BooleanField
|
||||
name="DISABLE_LOCAL_AUTH"
|
||||
needsConfirmationModal
|
||||
modalTitle={t`Confirm Disable Local Authorization`}
|
||||
config={authentication.DISABLE_LOCAL_AUTH}
|
||||
/>
|
||||
<InputField
|
||||
name="SESSION_COOKIE_AGE"
|
||||
config={authentication.SESSION_COOKIE_AGE}
|
||||
type="number"
|
||||
isRequired
|
||||
/>
|
||||
<InputField
|
||||
name="SESSIONS_PER_USER"
|
||||
config={authentication.SESSIONS_PER_USER}
|
||||
type="number"
|
||||
isRequired
|
||||
/>
|
||||
<BooleanField
|
||||
name="AUTH_BASIC_ENABLED"
|
||||
config={authentication.AUTH_BASIC_ENABLED}
|
||||
/>
|
||||
<BooleanField
|
||||
name="ALLOW_OAUTH2_FOR_EXTERNAL_USERS"
|
||||
config={authentication.ALLOW_OAUTH2_FOR_EXTERNAL_USERS}
|
||||
/>
|
||||
<InputField
|
||||
name="LOGIN_REDIRECT_OVERRIDE"
|
||||
config={authentication.LOGIN_REDIRECT_OVERRIDE}
|
||||
type="url"
|
||||
/>
|
||||
<InputField
|
||||
name="ACCESS_TOKEN_EXPIRE_SECONDS"
|
||||
config={authentication.ACCESS_TOKEN_EXPIRE_SECONDS}
|
||||
type="number"
|
||||
/>
|
||||
<InputField
|
||||
name="REFRESH_TOKEN_EXPIRE_SECONDS"
|
||||
config={authentication.REFRESH_TOKEN_EXPIRE_SECONDS}
|
||||
type="number"
|
||||
/>
|
||||
<InputField
|
||||
name="AUTHORIZATION_CODE_EXPIRE_SECONDS"
|
||||
config={authentication.AUTHORIZATION_CODE_EXPIRE_SECONDS}
|
||||
type="number"
|
||||
/>
|
||||
<ObjectField
|
||||
name="SOCIAL_AUTH_ORGANIZATION_MAP"
|
||||
config={authentication.SOCIAL_AUTH_ORGANIZATION_MAP}
|
||||
/>
|
||||
<ObjectField
|
||||
name="SOCIAL_AUTH_TEAM_MAP"
|
||||
config={authentication.SOCIAL_AUTH_TEAM_MAP}
|
||||
/>
|
||||
<ObjectField
|
||||
name="SOCIAL_AUTH_USER_FIELDS"
|
||||
config={authentication.SOCIAL_AUTH_USER_FIELDS}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
onSubmit={formik.handleSubmit}
|
||||
onRevert={toggleModal}
|
||||
/>
|
||||
{isModalOpen && (
|
||||
<RevertAllAlert
|
||||
onClose={closeModal}
|
||||
onRevertAll={handleRevertAll}
|
||||
/>
|
||||
)}
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
)}
|
||||
</CardBody>
|
||||
);
|
||||
}
|
||||
|
||||
export default MiscAuthenticationEdit;
|
||||
@ -6,36 +6,55 @@ import {
|
||||
waitForElement,
|
||||
} from '../../../../../testUtils/enzymeHelpers';
|
||||
import mockAllOptions from '../../shared/data.allSettingOptions.json';
|
||||
import mockAllSettings from '../../shared/data.allSettings.json';
|
||||
import { SettingsProvider } from '../../../../contexts/Settings';
|
||||
import { SettingsAPI } from '../../../../api';
|
||||
import ActivityStreamEdit from './ActivityStreamEdit';
|
||||
import MiscAuthenticationEdit from './MiscAuthenticationEdit';
|
||||
|
||||
jest.mock('../../../../api');
|
||||
|
||||
describe('<ActivityStreamEdit />', () => {
|
||||
const authenticationData = {
|
||||
SESSION_COOKIE_AGE: 1800,
|
||||
SESSIONS_PER_USER: -1,
|
||||
DISABLE_LOCAL_AUTH: false,
|
||||
AUTH_BASIC_ENABLED: true,
|
||||
OAUTH2_PROVIDER: {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS: 31536000000,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS: 2628000,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS: 600,
|
||||
},
|
||||
ALLOW_OAUTH2_FOR_EXTERNAL_USERS: false,
|
||||
LOGIN_REDIRECT_OVERRIDE: '',
|
||||
AUTHENTICATION_BACKENDS: [
|
||||
'awx.sso.backends.TACACSPlusBackend',
|
||||
'awx.main.backends.AWXModelBackend',
|
||||
],
|
||||
SOCIAL_AUTH_ORGANIZATION_MAP: {},
|
||||
SOCIAL_AUTH_TEAM_MAP: {},
|
||||
SOCIAL_AUTH_USER_FIELDS: [],
|
||||
};
|
||||
|
||||
describe('<MiscAuthenticationEdit />', () => {
|
||||
let wrapper;
|
||||
let history;
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.unmount();
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
history = createMemoryHistory({
|
||||
initialEntries: ['/settings/activity_stream/edit'],
|
||||
});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
ACTIVITY_STREAM_ENABLED: false,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: true,
|
||||
},
|
||||
});
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: mockAllSettings,
|
||||
});
|
||||
history = createMemoryHistory({
|
||||
initialEntries: ['/settings/miscellaneous_authentication/edit'],
|
||||
});
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<SettingsProvider value={mockAllOptions.actions}>
|
||||
<ActivityStreamEdit />
|
||||
<MiscAuthenticationEdit />
|
||||
</SettingsProvider>,
|
||||
{
|
||||
context: { router: { history } },
|
||||
@ -45,54 +64,23 @@ describe('<ActivityStreamEdit />', () => {
|
||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(wrapper.find('ActivityStreamEdit').length).toBe(1);
|
||||
test('initially renders without crashing', async () => {
|
||||
expect(wrapper.find('MiscAuthenticationEdit').length).toBe(1);
|
||||
});
|
||||
|
||||
test('should navigate to activity stream detail when cancel is clicked', async () => {
|
||||
test('save button should call updateAll', async () => {
|
||||
expect(wrapper.find('MiscAuthenticationEdit').length).toBe(1);
|
||||
wrapper.update();
|
||||
await act(async () => {
|
||||
wrapper.find('button[aria-label="Cancel"]').invoke('onClick')();
|
||||
});
|
||||
expect(history.location.pathname).toEqual(
|
||||
'/settings/activity_stream/details'
|
||||
);
|
||||
});
|
||||
|
||||
test('should navigate to activity stream detail on successful submission', async () => {
|
||||
await act(async () => {
|
||||
wrapper.find('Form').invoke('onSubmit')();
|
||||
});
|
||||
expect(history.location.pathname).toEqual(
|
||||
'/settings/activity_stream/details'
|
||||
);
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(
|
||||
wrapper.find('Switch#ACTIVITY_STREAM_ENABLED').prop('isChecked')
|
||||
).toEqual(false);
|
||||
|
||||
await act(async () => {
|
||||
wrapper.find('Switch#ACTIVITY_STREAM_ENABLED').invoke('onChange')(true);
|
||||
wrapper.find('button[aria-label="Save"]').simulate('click');
|
||||
});
|
||||
wrapper.update();
|
||||
expect(
|
||||
wrapper.find('Switch#ACTIVITY_STREAM_ENABLED').prop('isChecked')
|
||||
).toEqual(true);
|
||||
|
||||
await act(async () => {
|
||||
wrapper.find('Form').invoke('onSubmit')();
|
||||
});
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
ACTIVITY_STREAM_ENABLED: true,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: true,
|
||||
});
|
||||
const { AUTHENTICATION_BACKENDS, ...rest } = authenticationData;
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith(rest);
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -107,11 +95,33 @@ describe('<ActivityStreamEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
ACTIVITY_STREAM_ENABLED: true,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: false,
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('authentication');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
await act(async () => {
|
||||
wrapper.find('Form').invoke('onSubmit')();
|
||||
});
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should navigate to miscellaneous detail on successful submission', async () => {
|
||||
await act(async () => {
|
||||
wrapper.find('Form').invoke('onSubmit')();
|
||||
});
|
||||
expect(history.location.pathname).toEqual(
|
||||
'/settings/miscellaneous_authentication/details'
|
||||
);
|
||||
});
|
||||
|
||||
test('should navigate to miscellaneous detail when cancel is clicked', async () => {
|
||||
await act(async () => {
|
||||
wrapper.find('button[aria-label="Cancel"]').invoke('onClick')();
|
||||
});
|
||||
expect(history.location.pathname).toEqual(
|
||||
'/settings/miscellaneous_authentication/details'
|
||||
);
|
||||
});
|
||||
|
||||
test('should display error message on unsuccessful submission', async () => {
|
||||
@ -138,7 +148,7 @@ describe('<ActivityStreamEdit />', () => {
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<SettingsProvider value={mockAllOptions.actions}>
|
||||
<ActivityStreamEdit />
|
||||
<MiscAuthenticationEdit />
|
||||
</SettingsProvider>
|
||||
);
|
||||
});
|
||||
@ -0,0 +1 @@
|
||||
export { default } from './MiscAuthenticationEdit';
|
||||
@ -0,0 +1 @@
|
||||
export { default } from './MiscAuthentication';
|
||||
@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Link, Redirect, Route, Switch } from 'react-router-dom';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
import { PageSection, Card } from '@patternfly/react-core';
|
||||
import ContentError from '../../../components/ContentError';
|
||||
|
||||
@ -18,84 +18,49 @@ import { sortNestedDetails, pluck } from '../../shared/settingUtils';
|
||||
|
||||
function MiscSystemDetail() {
|
||||
const { me } = useConfig();
|
||||
const { GET: allOptions } = useSettings();
|
||||
const { GET: options } = useSettings();
|
||||
|
||||
const { isLoading, error, request, result: system } = useRequest(
|
||||
useCallback(async () => {
|
||||
const { data } = await SettingsAPI.readCategory('all');
|
||||
let DEFAULT_EXECUTION_ENVIRONMENT = '';
|
||||
const { data } = await SettingsAPI.readCategory('system');
|
||||
if (data.DEFAULT_EXECUTION_ENVIRONMENT) {
|
||||
const {
|
||||
data: { name },
|
||||
} = await ExecutionEnvironmentsAPI.readDetail(
|
||||
data.DEFAULT_EXECUTION_ENVIRONMENT
|
||||
);
|
||||
DEFAULT_EXECUTION_ENVIRONMENT = name;
|
||||
data.DEFAULT_EXECUTION_ENVIRONMENT = name;
|
||||
}
|
||||
const {
|
||||
OAUTH2_PROVIDER: {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
},
|
||||
...pluckedSystemData
|
||||
} = pluck(
|
||||
|
||||
const systemData = pluck(
|
||||
data,
|
||||
'ALLOW_OAUTH2_FOR_EXTERNAL_USERS',
|
||||
'AUTH_BASIC_ENABLED',
|
||||
'ACTIVITY_STREAM_ENABLED',
|
||||
'ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC',
|
||||
'AUTOMATION_ANALYTICS_GATHER_INTERVAL',
|
||||
'AUTOMATION_ANALYTICS_URL',
|
||||
'INSIGHTS_TRACKING_STATE',
|
||||
'LOGIN_REDIRECT_OVERRIDE',
|
||||
'MANAGE_ORGANIZATION_AUTH',
|
||||
'DISABLE_LOCAL_AUTH',
|
||||
'OAUTH2_PROVIDER',
|
||||
'ORG_ADMINS_CAN_SEE_ALL_USERS',
|
||||
'REDHAT_PASSWORD',
|
||||
'REDHAT_USERNAME',
|
||||
'REMOTE_HOST_HEADERS',
|
||||
'SESSIONS_PER_USER',
|
||||
'SESSION_COOKIE_AGE',
|
||||
'REDHAT_PASSWORD',
|
||||
'SUBSCRIPTIONS_USERNAME',
|
||||
'SUBSCRIPTIONS_PASSWORD',
|
||||
'TOWER_URL_BASE'
|
||||
'INSTALL_UUID',
|
||||
'REMOTE_HOST_HEADERS',
|
||||
'TOWER_URL_BASE',
|
||||
'DEFAULT_EXECUTION_ENVIRONMENT',
|
||||
'PROXY_IP_ALLOWED_LIST',
|
||||
'AUTOMATION_ANALYTICS_LAST_GATHER',
|
||||
'AUTOMATION_ANALYTICS_LAST_ENTRIES'
|
||||
);
|
||||
const systemData = {
|
||||
...pluckedSystemData,
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
DEFAULT_EXECUTION_ENVIRONMENT,
|
||||
};
|
||||
const {
|
||||
OAUTH2_PROVIDER: OAUTH2_PROVIDER_OPTIONS,
|
||||
...options
|
||||
} = allOptions;
|
||||
const systemOptions = {
|
||||
...options,
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS: {
|
||||
...OAUTH2_PROVIDER_OPTIONS,
|
||||
type: OAUTH2_PROVIDER_OPTIONS.child.type,
|
||||
label: t`Access Token Expiration`,
|
||||
},
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS: {
|
||||
...OAUTH2_PROVIDER_OPTIONS,
|
||||
type: OAUTH2_PROVIDER_OPTIONS.child.type,
|
||||
label: t`Refresh Token Expiration`,
|
||||
},
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS: {
|
||||
...OAUTH2_PROVIDER_OPTIONS,
|
||||
type: OAUTH2_PROVIDER_OPTIONS.child.type,
|
||||
label: t`Authorization Code Expiration`,
|
||||
},
|
||||
};
|
||||
|
||||
const mergedData = {};
|
||||
Object.keys(systemData).forEach(key => {
|
||||
mergedData[key] = systemOptions[key];
|
||||
mergedData[key] = options[key];
|
||||
mergedData[key].value = systemData[key];
|
||||
});
|
||||
return sortNestedDetails(mergedData);
|
||||
}, [allOptions]),
|
||||
}, [options]),
|
||||
null
|
||||
);
|
||||
|
||||
|
||||
@ -22,28 +22,26 @@ describe('<MiscSystemDetail />', () => {
|
||||
SettingsAPI.readCategory = jest.fn();
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
ALLOW_OAUTH2_FOR_EXTERNAL_USERS: false,
|
||||
AUTH_BASIC_ENABLED: true,
|
||||
AUTOMATION_ANALYTICS_GATHER_INTERVAL: 14400,
|
||||
ACTIVITY_STREAM_ENABLED: true,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: false,
|
||||
ORG_ADMINS_CAN_SEE_ALL_USERS: true,
|
||||
MANAGE_ORGANIZATION_AUTH: true,
|
||||
TOWER_URL_BASE: 'https://towerhost',
|
||||
REMOTE_HOST_HEADERS: [],
|
||||
PROXY_IP_ALLOWED_LIST: [],
|
||||
LICENSE: null,
|
||||
REDHAT_USERNAME: 'name1',
|
||||
REDHAT_PASSWORD: '$encrypted$',
|
||||
SUBSCRIPTIONS_USERNAME: 'name2',
|
||||
SUBSCRIPTIONS_PASSWORD: '$encrypted$',
|
||||
AUTOMATION_ANALYTICS_URL: 'https://example.com',
|
||||
INSTALL_UUID: 'db39b9ec-0c6e-4554-987d-42aw9c732ed8',
|
||||
DEFAULT_EXECUTION_ENVIRONMENT: 1,
|
||||
CUSTOM_VENV_PATHS: [],
|
||||
INSIGHTS_TRACKING_STATE: false,
|
||||
LOGIN_REDIRECT_OVERRIDE: 'https://redirect.com',
|
||||
MANAGE_ORGANIZATION_AUTH: true,
|
||||
DISABLE_LOCAL_AUTH: false,
|
||||
OAUTH2_PROVIDER: {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS: 1,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS: 2,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS: 3,
|
||||
},
|
||||
ORG_ADMINS_CAN_SEE_ALL_USERS: true,
|
||||
REDHAT_PASSWORD: '$encrypted$',
|
||||
REDHAT_USERNAME: 'mock name',
|
||||
REMOTE_HOST_HEADERS: [],
|
||||
SESSIONS_PER_USER: -1,
|
||||
SESSION_COOKIE_AGE: 30000000000,
|
||||
TOWER_URL_BASE: 'https://towerhost',
|
||||
DEFAULT_EXECUTION_ENVIRONMENT: 1,
|
||||
AUTOMATION_ANALYTICS_LAST_GATHER: null,
|
||||
AUTOMATION_ANALYTICS_LAST_ENTRIES: 'foo',
|
||||
AUTOMATION_ANALYTICS_GATHER_INTERVAL: 14400,
|
||||
},
|
||||
});
|
||||
ExecutionEnvironmentsAPI.readDetail = jest.fn();
|
||||
@ -77,14 +75,17 @@ describe('<MiscSystemDetail />', () => {
|
||||
});
|
||||
|
||||
test('should render expected details', () => {
|
||||
assertDetail(wrapper, 'Access Token Expiration', '1 seconds');
|
||||
assertDetail(wrapper, 'All Users Visible to Organization Admins', 'On');
|
||||
assertDetail(
|
||||
wrapper,
|
||||
'Allow External Users to Create OAuth2 Tokens',
|
||||
'Off'
|
||||
'Unique identifier for an installation',
|
||||
'db39b9ec-0c6e-4554-987d-42aw9c732ed8'
|
||||
);
|
||||
assertDetail(wrapper, 'Authorization Code Expiration', '2 seconds');
|
||||
assertDetail(
|
||||
wrapper,
|
||||
'Last gathered entries for expensive collectors for Insights for Ansible Automation Platform.',
|
||||
'foo'
|
||||
);
|
||||
assertDetail(wrapper, 'All Users Visible to Organization Admins', 'On');
|
||||
assertDetail(
|
||||
wrapper,
|
||||
'Insights for Ansible Automation Platform Gather Interval',
|
||||
@ -96,32 +97,24 @@ describe('<MiscSystemDetail />', () => {
|
||||
'https://example.com'
|
||||
);
|
||||
assertDetail(wrapper, 'Base URL of the service', 'https://towerhost');
|
||||
assertDetail(wrapper, 'Enable HTTP Basic Auth', 'On');
|
||||
assertDetail(
|
||||
wrapper,
|
||||
'Gather data for Insights for Ansible Automation Platform',
|
||||
'Off'
|
||||
);
|
||||
assertDetail(wrapper, 'Idle Time Force Log Out', '30000000000 seconds');
|
||||
assertDetail(
|
||||
wrapper,
|
||||
'Login redirect override URL',
|
||||
'https://redirect.com'
|
||||
);
|
||||
assertDetail(
|
||||
wrapper,
|
||||
'Maximum number of simultaneous logged in sessions',
|
||||
'-1'
|
||||
);
|
||||
assertDetail(
|
||||
wrapper,
|
||||
'Organization Admins Can Manage Users and Teams',
|
||||
'On'
|
||||
);
|
||||
assertDetail(wrapper, 'Enable Activity Stream', 'On');
|
||||
assertDetail(wrapper, 'Enable Activity Stream for Inventory Sync', 'Off');
|
||||
assertDetail(wrapper, 'Red Hat customer password', 'Encrypted');
|
||||
assertDetail(wrapper, 'Red Hat customer username', 'mock name');
|
||||
assertDetail(wrapper, 'Refresh Token Expiration', '3 seconds');
|
||||
assertDetail(wrapper, 'Red Hat customer username', 'name1');
|
||||
assertDetail(wrapper, 'Red Hat or Satellite password', 'Encrypted');
|
||||
assertDetail(wrapper, 'Red Hat or Satellite username', 'name2');
|
||||
assertVariableDetail(wrapper, 'Remote Host Headers', '[]');
|
||||
assertVariableDetail(wrapper, 'Proxy IP Allowed List', '[]');
|
||||
assertDetail(wrapper, 'Global default execution environment', 'Foo');
|
||||
});
|
||||
|
||||
|
||||
@ -30,76 +30,33 @@ function MiscSystemEdit() {
|
||||
|
||||
const { isLoading, error, request: fetchSystem, result: system } = useRequest(
|
||||
useCallback(async () => {
|
||||
const { data } = await SettingsAPI.readCategory('all');
|
||||
const {
|
||||
OAUTH2_PROVIDER: {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
},
|
||||
...pluckedSystemData
|
||||
} = pluck(
|
||||
const { data } = await SettingsAPI.readCategory('system');
|
||||
const systemData = pluck(
|
||||
data,
|
||||
'ALLOW_OAUTH2_FOR_EXTERNAL_USERS',
|
||||
'AUTH_BASIC_ENABLED',
|
||||
'ACTIVITY_STREAM_ENABLED',
|
||||
'ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC',
|
||||
'AUTOMATION_ANALYTICS_GATHER_INTERVAL',
|
||||
'AUTOMATION_ANALYTICS_URL',
|
||||
'AUTOMATION_ANALYTICS_LAST_ENTRIES',
|
||||
'INSIGHTS_TRACKING_STATE',
|
||||
'LOGIN_REDIRECT_OVERRIDE',
|
||||
'MANAGE_ORGANIZATION_AUTH',
|
||||
'DISABLE_LOCAL_AUTH',
|
||||
'OAUTH2_PROVIDER',
|
||||
'ORG_ADMINS_CAN_SEE_ALL_USERS',
|
||||
'REDHAT_PASSWORD',
|
||||
'REDHAT_USERNAME',
|
||||
'REDHAT_PASSWORD',
|
||||
'SUBSCRIPTIONS_USERNAME',
|
||||
'SUBSCRIPTIONS_PASSWORD',
|
||||
'REMOTE_HOST_HEADERS',
|
||||
'SESSIONS_PER_USER',
|
||||
'SESSION_COOKIE_AGE',
|
||||
'TOWER_URL_BASE',
|
||||
'DEFAULT_EXECUTION_ENVIRONMENT'
|
||||
'DEFAULT_EXECUTION_ENVIRONMENT',
|
||||
'PROXY_IP_ALLOWED_LIST'
|
||||
);
|
||||
|
||||
const systemData = {
|
||||
...pluckedSystemData,
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
};
|
||||
|
||||
const {
|
||||
OAUTH2_PROVIDER: OAUTH2_PROVIDER_OPTIONS,
|
||||
...restOptions
|
||||
} = options;
|
||||
|
||||
const systemOptions = {
|
||||
...restOptions,
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS: {
|
||||
...OAUTH2_PROVIDER_OPTIONS,
|
||||
default: OAUTH2_PROVIDER_OPTIONS.default.ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
type: OAUTH2_PROVIDER_OPTIONS.child.type,
|
||||
label: t`Access Token Expiration`,
|
||||
},
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS: {
|
||||
...OAUTH2_PROVIDER_OPTIONS,
|
||||
default: OAUTH2_PROVIDER_OPTIONS.default.REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
type: OAUTH2_PROVIDER_OPTIONS.child.type,
|
||||
label: t`Refresh Token Expiration`,
|
||||
},
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS: {
|
||||
...OAUTH2_PROVIDER_OPTIONS,
|
||||
default:
|
||||
OAUTH2_PROVIDER_OPTIONS.default.AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
type: OAUTH2_PROVIDER_OPTIONS.child.type,
|
||||
label: t`Authorization Code Expiration`,
|
||||
},
|
||||
};
|
||||
|
||||
const mergedData = {};
|
||||
Object.keys(systemData).forEach(key => {
|
||||
if (!systemOptions[key]) {
|
||||
if (!options[key]) {
|
||||
return;
|
||||
}
|
||||
mergedData[key] = systemOptions[key];
|
||||
mergedData[key] = options[key];
|
||||
mergedData[key].value = systemData[key];
|
||||
});
|
||||
return mergedData;
|
||||
@ -122,50 +79,29 @@ function MiscSystemEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
const {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
...formData
|
||||
} = form;
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('system');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm({
|
||||
...formData,
|
||||
REMOTE_HOST_HEADERS: formatJson(formData.REMOTE_HOST_HEADERS),
|
||||
OAUTH2_PROVIDER: {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
},
|
||||
...form,
|
||||
PROXY_IP_ALLOWED_LIST: formatJson(form.PROXY_IP_ALLOWED_LIST),
|
||||
REMOTE_HOST_HEADERS: formatJson(form.REMOTE_HOST_HEADERS),
|
||||
DEFAULT_EXECUTION_ENVIRONMENT:
|
||||
formData.DEFAULT_EXECUTION_ENVIRONMENT?.id || null,
|
||||
form.DEFAULT_EXECUTION_ENVIRONMENT?.id || null,
|
||||
});
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
||||
...systemData
|
||||
} = system;
|
||||
await revertAll();
|
||||
|
||||
const defaultValues = {};
|
||||
Object.entries(systemData).forEach(([key, value]) => {
|
||||
defaultValues[key] = value.default;
|
||||
});
|
||||
|
||||
await submitForm({
|
||||
...defaultValues,
|
||||
OAUTH2_PROVIDER: {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS: ACCESS_TOKEN_EXPIRE_SECONDS.default,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS: REFRESH_TOKEN_EXPIRE_SECONDS.default,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS:
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS.default,
|
||||
},
|
||||
});
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/miscellaneous_system/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -226,6 +162,14 @@ function MiscSystemEdit() {
|
||||
return (
|
||||
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
|
||||
<FormColumnLayout>
|
||||
<BooleanField
|
||||
name="ACTIVITY_STREAM_ENABLED"
|
||||
config={system.ACTIVITY_STREAM_ENABLED}
|
||||
/>
|
||||
<BooleanField
|
||||
name="ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC"
|
||||
config={system.ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC}
|
||||
/>
|
||||
<ExecutionEnvironmentLookup
|
||||
helperTextInvalid={
|
||||
formik.errors.DEFAULT_EXECUTION_ENVIRONMENT
|
||||
@ -267,52 +211,6 @@ function MiscSystemEdit() {
|
||||
name="MANAGE_ORGANIZATION_AUTH"
|
||||
config={system.MANAGE_ORGANIZATION_AUTH}
|
||||
/>
|
||||
<BooleanField
|
||||
name="DISABLE_LOCAL_AUTH"
|
||||
needsConfirmationModal
|
||||
modalTitle={t`Confirm Disable Local Authorization`}
|
||||
config={system.DISABLE_LOCAL_AUTH}
|
||||
/>
|
||||
<InputField
|
||||
name="SESSION_COOKIE_AGE"
|
||||
config={system.SESSION_COOKIE_AGE}
|
||||
type="number"
|
||||
isRequired
|
||||
/>
|
||||
<InputField
|
||||
name="SESSIONS_PER_USER"
|
||||
config={system.SESSIONS_PER_USER}
|
||||
type="number"
|
||||
isRequired
|
||||
/>
|
||||
<BooleanField
|
||||
name="AUTH_BASIC_ENABLED"
|
||||
config={system.AUTH_BASIC_ENABLED}
|
||||
/>
|
||||
<BooleanField
|
||||
name="ALLOW_OAUTH2_FOR_EXTERNAL_USERS"
|
||||
config={system.ALLOW_OAUTH2_FOR_EXTERNAL_USERS}
|
||||
/>
|
||||
<InputField
|
||||
name="LOGIN_REDIRECT_OVERRIDE"
|
||||
config={system.LOGIN_REDIRECT_OVERRIDE}
|
||||
type="url"
|
||||
/>
|
||||
<InputField
|
||||
name="ACCESS_TOKEN_EXPIRE_SECONDS"
|
||||
config={system.ACCESS_TOKEN_EXPIRE_SECONDS}
|
||||
type="number"
|
||||
/>
|
||||
<InputField
|
||||
name="REFRESH_TOKEN_EXPIRE_SECONDS"
|
||||
config={system.REFRESH_TOKEN_EXPIRE_SECONDS}
|
||||
type="number"
|
||||
/>
|
||||
<InputField
|
||||
name="AUTHORIZATION_CODE_EXPIRE_SECONDS"
|
||||
config={system.AUTHORIZATION_CODE_EXPIRE_SECONDS}
|
||||
type="number"
|
||||
/>
|
||||
<BooleanField
|
||||
name="INSIGHTS_TRACKING_STATE"
|
||||
config={system.INSIGHTS_TRACKING_STATE}
|
||||
@ -325,6 +223,14 @@ function MiscSystemEdit() {
|
||||
name="REDHAT_PASSWORD"
|
||||
config={system.REDHAT_PASSWORD}
|
||||
/>
|
||||
<InputField
|
||||
name="SUBSCRIPTIONS_USERNAME"
|
||||
config={system.SUBSCRIPTIONS_USERNAME}
|
||||
/>
|
||||
<EncryptedField
|
||||
name="SUBSCRIPTIONS_PASSWORD"
|
||||
config={system.SUBSCRIPTIONS_PASSWORD}
|
||||
/>
|
||||
<InputField
|
||||
name="AUTOMATION_ANALYTICS_URL"
|
||||
config={system.AUTOMATION_ANALYTICS_URL}
|
||||
@ -336,12 +242,22 @@ function MiscSystemEdit() {
|
||||
type="number"
|
||||
isRequired
|
||||
/>
|
||||
<InputField
|
||||
name="AUTOMATION_ANALYTICS_LAST_ENTRIES"
|
||||
config={system.AUTOMATION_ANALYTICS_LAST_ENTRIES}
|
||||
/>
|
||||
<ObjectField
|
||||
name="REMOTE_HOST_HEADERS"
|
||||
config={system.REMOTE_HOST_HEADERS}
|
||||
isRequired
|
||||
/>
|
||||
<ObjectField
|
||||
name="PROXY_IP_ALLOWED_LIST"
|
||||
config={system.PROXY_IP_ALLOWED_LIST}
|
||||
isRequired
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -23,27 +23,22 @@ const mockExecutionEnvironment = [
|
||||
];
|
||||
|
||||
const systemData = {
|
||||
ALLOW_OAUTH2_FOR_EXTERNAL_USERS: false,
|
||||
AUTH_BASIC_ENABLED: true,
|
||||
ACTIVITY_STREAM_ENABLED: true,
|
||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: false,
|
||||
AUTOMATION_ANALYTICS_GATHER_INTERVAL: 14400,
|
||||
AUTOMATION_ANALYTICS_LAST_ENTRIES: '',
|
||||
AUTOMATION_ANALYTICS_URL: 'https://example.com',
|
||||
DEFAULT_EXECUTION_ENVIRONMENT: 1,
|
||||
INSIGHTS_TRACKING_STATE: false,
|
||||
LOGIN_REDIRECT_OVERRIDE: '',
|
||||
MANAGE_ORGANIZATION_AUTH: true,
|
||||
DISABLE_LOCAL_AUTH: false,
|
||||
OAUTH2_PROVIDER: {
|
||||
ACCESS_TOKEN_EXPIRE_SECONDS: 31536000000,
|
||||
AUTHORIZATION_CODE_EXPIRE_SECONDS: 600,
|
||||
REFRESH_TOKEN_EXPIRE_SECONDS: 2628000,
|
||||
},
|
||||
ORG_ADMINS_CAN_SEE_ALL_USERS: true,
|
||||
REDHAT_PASSWORD: '',
|
||||
REDHAT_USERNAME: '',
|
||||
REDHAT_PASSWORD: '',
|
||||
SUBSCRIPTIONS_USERNAME: '',
|
||||
SUBSCRIPTIONS_PASSWORD: '',
|
||||
REMOTE_HOST_HEADERS: ['REMOTE_ADDR', 'REMOTE_HOST'],
|
||||
SESSIONS_PER_USER: -1,
|
||||
SESSION_COOKIE_AGE: 1800,
|
||||
TOWER_URL_BASE: 'https://localhost:3000',
|
||||
PROXY_IP_ALLOWED_LIST: [],
|
||||
};
|
||||
|
||||
describe('<MiscSystemEdit />', () => {
|
||||
@ -55,6 +50,7 @@ describe('<MiscSystemEdit />', () => {
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: mockAllSettings,
|
||||
@ -116,7 +112,7 @@ describe('<MiscSystemEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -131,7 +127,8 @@ describe('<MiscSystemEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('system');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -47,18 +47,23 @@ function RADIUSEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('radius');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm(form);
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(radius).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/radius/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -90,6 +95,7 @@ function RADIUSEdit() {
|
||||
config={radius.RADIUS_SECRET}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<RADIUSEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -60,7 +61,7 @@ describe('<RADIUSEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -75,12 +76,8 @@ describe('<RADIUSEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
RADIUS_SERVER: '',
|
||||
RADIUS_PORT: 1812,
|
||||
RADIUS_SECRET: '',
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('radius');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -56,6 +56,13 @@ function SAMLEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('saml');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm({
|
||||
...form,
|
||||
@ -86,13 +93,11 @@ function SAMLEdit() {
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(saml).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/saml/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -185,6 +190,7 @@ function SAMLEdit() {
|
||||
config={saml.SOCIAL_AUTH_SAML_EXTRA_DATA}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<SAMLEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -131,7 +132,7 @@ describe('<SAMLEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -146,26 +147,8 @@ describe('<SAMLEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
SAML_AUTO_CREATE_OBJECTS: true,
|
||||
SOCIAL_AUTH_SAML_ENABLED_IDPS: {},
|
||||
SOCIAL_AUTH_SAML_EXTRA_DATA: null,
|
||||
SOCIAL_AUTH_SAML_ORGANIZATION_ATTR: {},
|
||||
SOCIAL_AUTH_SAML_ORGANIZATION_MAP: null,
|
||||
SOCIAL_AUTH_SAML_ORG_INFO: {},
|
||||
SOCIAL_AUTH_SAML_SP_ENTITY_ID: '',
|
||||
SOCIAL_AUTH_SAML_SP_EXTRA: null,
|
||||
SOCIAL_AUTH_SAML_SP_PRIVATE_KEY: '',
|
||||
SOCIAL_AUTH_SAML_SP_PUBLIC_CERT: '',
|
||||
SOCIAL_AUTH_SAML_SUPPORT_CONTACT: {},
|
||||
SOCIAL_AUTH_SAML_TEAM_ATTR: {},
|
||||
SOCIAL_AUTH_SAML_TEAM_MAP: null,
|
||||
SOCIAL_AUTH_SAML_TECHNICAL_CONTACT: {},
|
||||
SOCIAL_AUTH_SAML_SECURITY_CONFIG: {
|
||||
requestedAuthnContext: false,
|
||||
},
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('saml');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -107,8 +107,8 @@ function SettingList() {
|
||||
path: '/settings/miscellaneous_system',
|
||||
},
|
||||
{
|
||||
title: t`Activity Stream settings`,
|
||||
path: '/settings/activity_stream',
|
||||
title: t`Miscellaneous Authentication settings`,
|
||||
path: '/settings/miscellaneous_authentication',
|
||||
},
|
||||
{
|
||||
title: t`Logging settings`,
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { Link, Route, Switch, Redirect } from 'react-router-dom';
|
||||
|
||||
import { t } from '@lingui/macro';
|
||||
import { PageSection, Card } from '@patternfly/react-core';
|
||||
import ContentError from '../../components/ContentError';
|
||||
import ContentLoading from '../../components/ContentLoading';
|
||||
import ScreenHeader from '../../components/ScreenHeader';
|
||||
import ActivityStream from './ActivityStream';
|
||||
import AzureAD from './AzureAD';
|
||||
import GitHub from './GitHub';
|
||||
import GoogleOAuth2 from './GoogleOAuth2';
|
||||
@ -14,6 +12,7 @@ import Jobs from './Jobs';
|
||||
import LDAP from './LDAP';
|
||||
import Subscription from './Subscription';
|
||||
import Logging from './Logging';
|
||||
import MiscAuthentication from './MiscAuthentication';
|
||||
import MiscSystem from './MiscSystem';
|
||||
import RADIUS from './RADIUS';
|
||||
import SAML from './SAML';
|
||||
@ -94,6 +93,9 @@ function Settings() {
|
||||
'/settings/logging': t`Logging`,
|
||||
'/settings/logging/details': t`Details`,
|
||||
'/settings/logging/edit': t`Edit Details`,
|
||||
'/settings/miscellaneous_authentication': t`Miscellaneous Authentication`,
|
||||
'/settings/miscellaneous_authentication/details': t`Details`,
|
||||
'/settings/miscellaneous_authentication/edit': t`Edit Details`,
|
||||
'/settings/miscellaneous_system': t`Miscellaneous System`,
|
||||
'/settings/miscellaneous_system/details': t`Details`,
|
||||
'/settings/miscellaneous_system/edit': t`Edit Details`,
|
||||
@ -142,9 +144,6 @@ function Settings() {
|
||||
<SettingsProvider value={result}>
|
||||
<ScreenHeader streamType="setting" breadcrumbConfig={breadcrumbConfig} />
|
||||
<Switch>
|
||||
<Route path="/settings/activity_stream">
|
||||
<ActivityStream />
|
||||
</Route>
|
||||
<Route path="/settings/azure">
|
||||
<AzureAD />
|
||||
</Route>
|
||||
@ -170,6 +169,9 @@ function Settings() {
|
||||
<Route path="/settings/logging">
|
||||
<Logging />
|
||||
</Route>
|
||||
<Route path="/settings/miscellaneous_authentication">
|
||||
<MiscAuthentication />
|
||||
</Route>
|
||||
<Route path="/settings/miscellaneous_system">
|
||||
<MiscSystem />
|
||||
</Route>
|
||||
|
||||
@ -51,18 +51,23 @@ function TACACSEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('tacacsplus');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm(form);
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(tacacs).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push('/settings/tacacs/details');
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -107,6 +112,7 @@ function TACACSEdit() {
|
||||
config={tacacs.TACACSPLUS_AUTH_PROTOCOL}
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<TACACSEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -68,7 +69,7 @@ describe('<TACACSEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -83,14 +84,8 @@ describe('<TACACSEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
TACACSPLUS_HOST: '',
|
||||
TACACSPLUS_PORT: 49,
|
||||
TACACSPLUS_SECRET: '',
|
||||
TACACSPLUS_SESSION_TIMEOUT: 5,
|
||||
TACACSPLUS_AUTH_PROTOCOL: 'ascii',
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('tacacsplus');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
@ -65,18 +65,26 @@ function UIEdit() {
|
||||
null
|
||||
);
|
||||
|
||||
const { error: revertError, request: revertAll } = useRequest(
|
||||
useCallback(async () => {
|
||||
await SettingsAPI.revertCategory('ui');
|
||||
}, []),
|
||||
null
|
||||
);
|
||||
|
||||
const handleSubmit = async form => {
|
||||
await submitForm(form);
|
||||
};
|
||||
|
||||
const handleRevertAll = async () => {
|
||||
const defaultValues = Object.assign(
|
||||
...Object.entries(uiData).map(([key, value]) => ({
|
||||
[key]: value.default,
|
||||
}))
|
||||
);
|
||||
await submitForm(defaultValues);
|
||||
await revertAll();
|
||||
|
||||
closeModal();
|
||||
|
||||
history.push({
|
||||
pathname: '/settings/ui/details',
|
||||
hardReload: true,
|
||||
});
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
@ -115,6 +123,7 @@ function UIEdit() {
|
||||
type="dataURL"
|
||||
/>
|
||||
{submitError && <FormSubmitError error={submitError} />}
|
||||
{revertError && <FormSubmitError error={revertError} />}
|
||||
</FormColumnLayout>
|
||||
<RevertFormActionGroup
|
||||
onCancel={handleCancel}
|
||||
|
||||
@ -17,6 +17,7 @@ describe('<UIEdit />', () => {
|
||||
let history;
|
||||
|
||||
beforeEach(() => {
|
||||
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||
SettingsAPI.updateAll.mockResolvedValue({});
|
||||
SettingsAPI.readCategory.mockResolvedValue({
|
||||
data: {
|
||||
@ -62,7 +63,7 @@ describe('<UIEdit />', () => {
|
||||
});
|
||||
|
||||
test('should successfully send default values to api on form revert all', async () => {
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(0);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(0);
|
||||
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||
await act(async () => {
|
||||
wrapper
|
||||
@ -77,12 +78,8 @@ describe('<UIEdit />', () => {
|
||||
.invoke('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
||||
CUSTOM_LOGIN_INFO: '',
|
||||
CUSTOM_LOGO: '',
|
||||
PENDO_TRACKING_STATE: 'off',
|
||||
});
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('ui');
|
||||
});
|
||||
|
||||
test('should successfully send request to api on form submission', async () => {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user