mirror of
https://github.com/ansible/awx.git
synced 2026-03-09 13:39:27 -02:30
Merge pull request #10376 from mabashian/3831-settings-changes
Changes settings revert all to send DELETE on individual endpoint rather than PATCHing SUMMARY Resolves #3831 #3831 (comment) is a good explanation of the state of the new UI as well as the old. The Misc System settings were the most problematic part of this since that form pulled fields from both /api/v2/settings/system and /api/v2/settings/authentication. In order to revert these fields with a DELETE request I needed to split this form up into Miscellaneous System and Miscellaneous Authentication. The Activity Stream Settings also needed to be absorbed by the Miscellaneous System Settings. All settings forms (except noted below) will now issue a DELETE request to revert all the fields for a particular settings subsection. There was one form that I did not change the Revert All functionality on and that was the LDAP Settings form(s). The UI splits these fields out into 5 different subforms and reverting one (issuing a DELETE on /api/v2/settings/ldap) would revert all the ldap settings which I think is undesirable. This fix has the added benefit of cleaning up future activity stream entries for reverting an entire settings category. I also consulted with @wenottingham and @gamuniz on some fields that were present in the api but missing in the ui and I added those. ISSUE TYPE Feature Pull Request COMPONENT NAME UI Reviewed-by: Alan Rominger <arominge@redhat.com> Reviewed-by: Jake McDermott <yo@jakemcdermott.me> Reviewed-by: Tiago Góes <tiago.goes2009@gmail.com>
This commit is contained in:
@@ -29,6 +29,10 @@ class Settings extends Base {
|
|||||||
createTest(category, data) {
|
createTest(category, data) {
|
||||||
return this.http.post(`${this.baseUrl}${category}/test/`, data);
|
return this.http.post(`${this.baseUrl}${category}/test/`, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
revertCategory(category) {
|
||||||
|
return this.http.delete(`${this.baseUrl}${category}/`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Settings;
|
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
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('azuread-oauth2');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm({
|
await submitForm({
|
||||||
...form,
|
...form,
|
||||||
@@ -68,13 +75,11 @@ function AzureADEdit() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(azure).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/azure/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -120,6 +125,7 @@ function AzureADEdit() {
|
|||||||
config={azure.SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP}
|
config={azure.SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<AzureADEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -60,7 +61,7 @@ describe('<AzureADEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -75,13 +76,8 @@ describe('<AzureADEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('azuread-oauth2');
|
||||||
SOCIAL_AUTH_AZUREAD_OAUTH2_KEY: '',
|
|
||||||
SOCIAL_AUTH_AZUREAD_OAUTH2_SECRET: '',
|
|
||||||
SOCIAL_AUTH_AZUREAD_OAUTH2_ORGANIZATION_MAP: null,
|
|
||||||
SOCIAL_AUTH_AZUREAD_OAUTH2_TEAM_MAP: null,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -55,6 +55,13 @@ function GitHubEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('github');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm({
|
await submitForm({
|
||||||
...form,
|
...form,
|
||||||
@@ -66,13 +73,11 @@ function GitHubEdit() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(github).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/github/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -118,6 +123,7 @@ function GitHubEdit() {
|
|||||||
config={github.SOCIAL_AUTH_GITHUB_TEAM_MAP}
|
config={github.SOCIAL_AUTH_GITHUB_TEAM_MAP}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<GitHubEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -72,7 +73,7 @@ describe('<GitHubEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -87,13 +88,8 @@ describe('<GitHubEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('github');
|
||||||
SOCIAL_AUTH_GITHUB_KEY: '',
|
|
||||||
SOCIAL_AUTH_GITHUB_SECRET: '',
|
|
||||||
SOCIAL_AUTH_GITHUB_ORGANIZATION_MAP: null,
|
|
||||||
SOCIAL_AUTH_GITHUB_TEAM_MAP: null,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -55,6 +55,13 @@ function GitHubEnterpriseEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('github-enterprise');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm({
|
await submitForm({
|
||||||
...form,
|
...form,
|
||||||
@@ -68,13 +75,11 @@ function GitHubEnterpriseEdit() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(github).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/github/enterprise/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -128,6 +133,7 @@ function GitHubEnterpriseEdit() {
|
|||||||
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP}
|
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<GitHubEnterpriseEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -82,7 +83,7 @@ describe('<GitHubEnterpriseEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -97,15 +98,10 @@ describe('<GitHubEnterpriseEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith(
|
||||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_URL: '',
|
'github-enterprise'
|
||||||
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,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -55,6 +55,13 @@ function GitHubEnterpriseOrgEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('github-enterprise-org');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm({
|
await submitForm({
|
||||||
...form,
|
...form,
|
||||||
@@ -68,13 +75,11 @@ function GitHubEnterpriseOrgEdit() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(github).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/github/enterprise_organization/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -134,6 +139,7 @@ function GitHubEnterpriseOrgEdit() {
|
|||||||
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP}
|
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_TEAM_MAP}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<GitHubEnterpriseOrgEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -94,7 +95,7 @@ describe('<GitHubEnterpriseOrgEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -109,16 +110,10 @@ describe('<GitHubEnterpriseOrgEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith(
|
||||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORG_URL: '',
|
'github-enterprise-org'
|
||||||
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,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -55,6 +55,13 @@ function GitHubEnterpriseTeamEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('github-enterprise-team');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm({
|
await submitForm({
|
||||||
...form,
|
...form,
|
||||||
@@ -68,13 +75,11 @@ function GitHubEnterpriseTeamEdit() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(github).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/github/enterprise_team/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -134,6 +139,7 @@ function GitHubEnterpriseTeamEdit() {
|
|||||||
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP}
|
config={github.SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_TEAM_MAP}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<GitHubEnterpriseTeamEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -88,7 +89,7 @@ describe('<GitHubEnterpriseTeamEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -103,16 +104,10 @@ describe('<GitHubEnterpriseTeamEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith(
|
||||||
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_URL: '',
|
'github-enterprise-team'
|
||||||
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,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -55,6 +55,13 @@ function GitHubOrgEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('github-org');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm({
|
await submitForm({
|
||||||
...form,
|
...form,
|
||||||
@@ -68,13 +75,11 @@ function GitHubOrgEdit() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(github).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/github/organization/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -124,6 +129,7 @@ function GitHubOrgEdit() {
|
|||||||
config={github.SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP}
|
config={github.SOCIAL_AUTH_GITHUB_ORG_TEAM_MAP}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<GitHubOrgEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -79,7 +80,7 @@ describe('<GitHubOrgEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -94,14 +95,8 @@ describe('<GitHubOrgEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('github-org');
|
||||||
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,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -55,6 +55,13 @@ function GitHubTeamEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('github-team');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm({
|
await submitForm({
|
||||||
...form,
|
...form,
|
||||||
@@ -68,13 +75,11 @@ function GitHubTeamEdit() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(github).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/github/team/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -124,6 +129,7 @@ function GitHubTeamEdit() {
|
|||||||
config={github.SOCIAL_AUTH_GITHUB_TEAM_TEAM_MAP}
|
config={github.SOCIAL_AUTH_GITHUB_TEAM_TEAM_MAP}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<GitHubTeamEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -74,7 +75,7 @@ describe('<GitHubTeamEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -89,14 +90,8 @@ describe('<GitHubTeamEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('github-team');
|
||||||
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,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -60,6 +60,13 @@ function GoogleOAuth2Edit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('google-oauth2');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm({
|
await submitForm({
|
||||||
...form,
|
...form,
|
||||||
@@ -79,13 +86,11 @@ function GoogleOAuth2Edit() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(googleOAuth2).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/google_oauth2/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -148,6 +153,7 @@ function GoogleOAuth2Edit() {
|
|||||||
config={googleOAuth2.SOCIAL_AUTH_GOOGLE_OAUTH2_TEAM_MAP}
|
config={googleOAuth2.SOCIAL_AUTH_GOOGLE_OAUTH2_TEAM_MAP}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<GoogleOAuth2Edit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -82,7 +83,7 @@ describe('<GoogleOAuth2Edit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -97,15 +98,8 @@ describe('<GoogleOAuth2Edit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('google-oauth2');
|
||||||
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,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -63,6 +63,13 @@ function JobsEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('jobs');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm({
|
await submitForm({
|
||||||
...form,
|
...form,
|
||||||
@@ -76,12 +83,11 @@ function JobsEdit() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = {};
|
await revertAll();
|
||||||
Object.entries(jobs).forEach(([key, value]) => {
|
|
||||||
defaultValues[key] = value.default;
|
|
||||||
});
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/jobs/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -181,6 +187,7 @@ function JobsEdit() {
|
|||||||
/>
|
/>
|
||||||
<ObjectField name="AWX_TASK_ENV" config={jobs.AWX_TASK_ENV} />
|
<ObjectField name="AWX_TASK_ENV" config={jobs.AWX_TASK_ENV} />
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
} from '../../../../../testUtils/enzymeHelpers';
|
} from '../../../../../testUtils/enzymeHelpers';
|
||||||
import mockAllOptions from '../../shared/data.allSettingOptions.json';
|
import mockAllOptions from '../../shared/data.allSettingOptions.json';
|
||||||
import mockJobSettings from '../../shared/data.jobSettings.json';
|
import mockJobSettings from '../../shared/data.jobSettings.json';
|
||||||
import mockDefaultJobSettings from './data.defaultJobSettings.json';
|
|
||||||
import { SettingsProvider } from '../../../../contexts/Settings';
|
import { SettingsProvider } from '../../../../contexts/Settings';
|
||||||
import { SettingsAPI } from '../../../../api';
|
import { SettingsAPI } from '../../../../api';
|
||||||
import JobsEdit from './JobsEdit';
|
import JobsEdit from './JobsEdit';
|
||||||
@@ -19,6 +18,7 @@ describe('<JobsEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: mockJobSettings,
|
data: mockJobSettings,
|
||||||
@@ -51,7 +51,7 @@ describe('<JobsEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -66,8 +66,8 @@ describe('<JobsEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith(mockDefaultJobSettings);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('jobs');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -75,14 +75,19 @@ function LoggingEdit() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
const defaultValues = {};
|
useCallback(async () => {
|
||||||
Object.entries(logging).forEach(([key, value]) => {
|
await SettingsAPI.revertCategory('logging');
|
||||||
defaultValues[key] = value.default;
|
}, []),
|
||||||
});
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleRevertAll = async () => {
|
||||||
|
await revertAll();
|
||||||
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/logging/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -221,6 +226,7 @@ function LoggingEdit() {
|
|||||||
config={logging.LOG_AGGREGATOR_LOGGERS}
|
config={logging.LOG_AGGREGATOR_LOGGERS}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
onSubmit={formik.handleSubmit}
|
onSubmit={formik.handleSubmit}
|
||||||
|
|||||||
@@ -35,29 +35,6 @@ const mockSettings = {
|
|||||||
LOG_AGGREGATOR_MAX_DISK_USAGE_PATH: '/var/lib/awx',
|
LOG_AGGREGATOR_MAX_DISK_USAGE_PATH: '/var/lib/awx',
|
||||||
LOG_AGGREGATOR_RSYSLOGD_DEBUG: false,
|
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 />', () => {
|
describe('<LoggingEdit />', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
@@ -68,6 +45,7 @@ describe('<LoggingEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: mockSettings,
|
data: mockSettings,
|
||||||
@@ -227,7 +205,7 @@ describe('<LoggingEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -242,8 +220,8 @@ describe('<LoggingEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith(mockDefaultSettings);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('logging');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link, Redirect, Route, Switch } from 'react-router-dom';
|
import { Link, Redirect, Route, Switch } from 'react-router-dom';
|
||||||
|
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { PageSection, Card } from '@patternfly/react-core';
|
import { PageSection, Card } from '@patternfly/react-core';
|
||||||
import ContentError from '../../../components/ContentError';
|
import ContentError from '../../../components/ContentError';
|
||||||
import { useConfig } from '../../../contexts/Config';
|
import { useConfig } from '../../../contexts/Config';
|
||||||
import ActivityStreamDetail from './ActivityStreamDetail';
|
import MiscAuthenticationDetail from './MiscAuthenticationDetail';
|
||||||
import ActivityStreamEdit from './ActivityStreamEdit';
|
import MiscAuthenticationEdit from './MiscAuthenticationEdit';
|
||||||
|
|
||||||
function ActivityStream() {
|
function MiscAuthentication() {
|
||||||
const baseURL = '/settings/activity_stream';
|
const baseURL = '/settings/miscellaneous_authentication';
|
||||||
const { me } = useConfig();
|
const { me } = useConfig();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -18,11 +17,11 @@ function ActivityStream() {
|
|||||||
<Switch>
|
<Switch>
|
||||||
<Redirect from={baseURL} to={`${baseURL}/details`} exact />
|
<Redirect from={baseURL} to={`${baseURL}/details`} exact />
|
||||||
<Route path={`${baseURL}/details`}>
|
<Route path={`${baseURL}/details`}>
|
||||||
<ActivityStreamDetail />
|
<MiscAuthenticationDetail />
|
||||||
</Route>
|
</Route>
|
||||||
<Route path={`${baseURL}/edit`}>
|
<Route path={`${baseURL}/edit`}>
|
||||||
{me?.is_superuser ? (
|
{me?.is_superuser ? (
|
||||||
<ActivityStreamEdit />
|
<MiscAuthenticationEdit />
|
||||||
) : (
|
) : (
|
||||||
<Redirect to={`${baseURL}/details`} />
|
<Redirect to={`${baseURL}/details`} />
|
||||||
)}
|
)}
|
||||||
@@ -30,7 +29,7 @@ function ActivityStream() {
|
|||||||
<Route key="not-found" path={`${baseURL}/*`}>
|
<Route key="not-found" path={`${baseURL}/*`}>
|
||||||
<ContentError isNotFound>
|
<ContentError isNotFound>
|
||||||
<Link to={`${baseURL}/details`}>
|
<Link to={`${baseURL}/details`}>
|
||||||
{t`View Activity Stream settings`}
|
{t`View Miscellaneous Authentication settings`}
|
||||||
</Link>
|
</Link>
|
||||||
</ContentError>
|
</ContentError>
|
||||||
</Route>
|
</Route>
|
||||||
@@ -40,4 +39,4 @@ function ActivityStream() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ActivityStream;
|
export default MiscAuthentication;
|
||||||
@@ -5,55 +5,57 @@ import {
|
|||||||
mountWithContexts,
|
mountWithContexts,
|
||||||
waitForElement,
|
waitForElement,
|
||||||
} from '../../../../testUtils/enzymeHelpers';
|
} from '../../../../testUtils/enzymeHelpers';
|
||||||
import ActivityStream from './ActivityStream';
|
|
||||||
import { SettingsAPI } from '../../../api';
|
import { SettingsAPI } from '../../../api';
|
||||||
|
import MiscAuthentication from './MiscAuthentication';
|
||||||
|
|
||||||
jest.mock('../../../api/models/Settings');
|
jest.mock('../../../api');
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
|
||||||
data: {
|
|
||||||
ACTIVITY_STREAM_ENABLED: true,
|
|
||||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('<ActivityStream />', () => {
|
describe('<MiscAuthentication />', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
|
data: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render activity stream details', async () => {
|
test('should render miscellaneous authentication details', async () => {
|
||||||
const history = createMemoryHistory({
|
const history = createMemoryHistory({
|
||||||
initialEntries: ['/settings/activity_stream/details'],
|
initialEntries: ['/settings/miscellaneous_authentication/details'],
|
||||||
});
|
});
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<ActivityStream />, {
|
wrapper = mountWithContexts(<MiscAuthentication />, {
|
||||||
context: { router: { history } },
|
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({
|
const history = createMemoryHistory({
|
||||||
initialEntries: ['/settings/activity_stream/edit'],
|
initialEntries: ['/settings/miscellaneous_authentication/edit'],
|
||||||
});
|
});
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<ActivityStream />, {
|
wrapper = mountWithContexts(<MiscAuthentication />, {
|
||||||
context: { router: { history } },
|
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 () => {
|
test('should show content error when user navigates to erroneous route', async () => {
|
||||||
const history = createMemoryHistory({
|
const history = createMemoryHistory({
|
||||||
initialEntries: ['/settings/activity_stream/foo'],
|
initialEntries: ['/settings/miscellaneous_authentication/foo'],
|
||||||
});
|
});
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<ActivityStream />, {
|
wrapper = mountWithContexts(<MiscAuthentication />, {
|
||||||
context: { router: { history } },
|
context: { router: { history } },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -62,10 +64,10 @@ describe('<ActivityStream />', () => {
|
|||||||
|
|
||||||
test('should redirect to details for users without system admin permissions', async () => {
|
test('should redirect to details for users without system admin permissions', async () => {
|
||||||
const history = createMemoryHistory({
|
const history = createMemoryHistory({
|
||||||
initialEntries: ['/settings/activity_stream/edit'],
|
initialEntries: ['/settings/miscellaneous_authentication/edit'],
|
||||||
});
|
});
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<ActivityStream />, {
|
wrapper = mountWithContexts(<MiscAuthentication />, {
|
||||||
context: {
|
context: {
|
||||||
router: {
|
router: {
|
||||||
history,
|
history,
|
||||||
@@ -79,7 +81,7 @@ describe('<ActivityStream />', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||||
expect(wrapper.find('ActivityStreamDetail').length).toBe(1);
|
expect(wrapper.find('MiscAuthenticationDetail').length).toBe(1);
|
||||||
expect(wrapper.find('ActivityStreamEdit').length).toBe(0);
|
expect(wrapper.find('MiscAuthenticationEdit').length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1,36 +1,27 @@
|
|||||||
import React, { useEffect, useCallback } from 'react';
|
import React, { useEffect, useCallback } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { CaretLeftIcon } from '@patternfly/react-icons';
|
|
||||||
import { Button } from '@patternfly/react-core';
|
import { Button } from '@patternfly/react-core';
|
||||||
|
import { CaretLeftIcon } from '@patternfly/react-icons';
|
||||||
import { CardBody, CardActionsRow } from '../../../../components/Card';
|
import { CardBody, CardActionsRow } from '../../../../components/Card';
|
||||||
import ContentLoading from '../../../../components/ContentLoading';
|
import ContentLoading from '../../../../components/ContentLoading';
|
||||||
import ContentError from '../../../../components/ContentError';
|
import ContentError from '../../../../components/ContentError';
|
||||||
import { DetailList } from '../../../../components/DetailList';
|
import { DetailList } from '../../../../components/DetailList';
|
||||||
import RoutedTabs from '../../../../components/RoutedTabs';
|
import RoutedTabs from '../../../../components/RoutedTabs';
|
||||||
import useRequest from '../../../../util/useRequest';
|
|
||||||
import { useConfig } from '../../../../contexts/Config';
|
import { useConfig } from '../../../../contexts/Config';
|
||||||
import { useSettings } from '../../../../contexts/Settings';
|
import { useSettings } from '../../../../contexts/Settings';
|
||||||
|
import useRequest from '../../../../util/useRequest';
|
||||||
import { SettingsAPI } from '../../../../api';
|
import { SettingsAPI } from '../../../../api';
|
||||||
import { SettingDetail } from '../../shared';
|
import { SettingDetail } from '../../shared';
|
||||||
|
|
||||||
function ActivityStreamDetail() {
|
function MiscAuthenticationDetail() {
|
||||||
const { me } = useConfig();
|
const { me } = useConfig();
|
||||||
const { GET: options } = useSettings();
|
const { GET: options } = useSettings();
|
||||||
|
|
||||||
const { isLoading, error, request, result: activityStream } = useRequest(
|
const { isLoading, error, request, result: authentication } = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
const {
|
const { data } = await SettingsAPI.readCategory('authentication');
|
||||||
data: {
|
return data;
|
||||||
ACTIVITY_STREAM_ENABLED,
|
|
||||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC,
|
|
||||||
},
|
|
||||||
} = await SettingsAPI.readCategory('system');
|
|
||||||
return {
|
|
||||||
ACTIVITY_STREAM_ENABLED,
|
|
||||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC,
|
|
||||||
};
|
|
||||||
}, []),
|
}, []),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
@@ -52,7 +43,7 @@ function ActivityStreamDetail() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t`Details`,
|
name: t`Details`,
|
||||||
link: `/settings/activity_stream/details`,
|
link: `/settings/miscellaneous_authentication/details`,
|
||||||
id: 0,
|
id: 0,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -63,9 +54,9 @@ function ActivityStreamDetail() {
|
|||||||
<CardBody>
|
<CardBody>
|
||||||
{isLoading && <ContentLoading />}
|
{isLoading && <ContentLoading />}
|
||||||
{!isLoading && error && <ContentError error={error} />}
|
{!isLoading && error && <ContentError error={error} />}
|
||||||
{!isLoading && activityStream && (
|
{!isLoading && authentication && (
|
||||||
<DetailList>
|
<DetailList>
|
||||||
{Object.keys(activityStream).map(key => {
|
{Object.keys(authentication).map(key => {
|
||||||
const record = options?.[key];
|
const record = options?.[key];
|
||||||
return (
|
return (
|
||||||
<SettingDetail
|
<SettingDetail
|
||||||
@@ -75,7 +66,7 @@ function ActivityStreamDetail() {
|
|||||||
label={record?.label}
|
label={record?.label}
|
||||||
type={record?.type}
|
type={record?.type}
|
||||||
unit={record?.unit}
|
unit={record?.unit}
|
||||||
value={activityStream?.[key]}
|
value={authentication?.[key]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -84,10 +75,10 @@ function ActivityStreamDetail() {
|
|||||||
{me?.is_superuser && (
|
{me?.is_superuser && (
|
||||||
<CardActionsRow>
|
<CardActionsRow>
|
||||||
<Button
|
<Button
|
||||||
ouiaId="activity-stream-detail-edit-button"
|
ouiaId="authentication-detail-edit-button"
|
||||||
aria-label={t`Edit`}
|
aria-label={t`Edit`}
|
||||||
component={Link}
|
component={Link}
|
||||||
to="/settings/activity_stream/edit"
|
to="/settings/miscellaneous_authentication/edit"
|
||||||
>
|
>
|
||||||
{t`Edit`}
|
{t`Edit`}
|
||||||
</Button>
|
</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,
|
waitForElement,
|
||||||
} from '../../../../../testUtils/enzymeHelpers';
|
} from '../../../../../testUtils/enzymeHelpers';
|
||||||
import mockAllOptions from '../../shared/data.allSettingOptions.json';
|
import mockAllOptions from '../../shared/data.allSettingOptions.json';
|
||||||
|
import mockAllSettings from '../../shared/data.allSettings.json';
|
||||||
import { SettingsProvider } from '../../../../contexts/Settings';
|
import { SettingsProvider } from '../../../../contexts/Settings';
|
||||||
import { SettingsAPI } from '../../../../api';
|
import { SettingsAPI } from '../../../../api';
|
||||||
import ActivityStreamEdit from './ActivityStreamEdit';
|
import MiscAuthenticationEdit from './MiscAuthenticationEdit';
|
||||||
|
|
||||||
jest.mock('../../../../api');
|
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 wrapper;
|
||||||
let history;
|
let history;
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
wrapper.unmount();
|
|
||||||
jest.clearAllMocks();
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
history = createMemoryHistory({
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
initialEntries: ['/settings/activity_stream/edit'],
|
|
||||||
});
|
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
|
||||||
data: {
|
|
||||||
ACTIVITY_STREAM_ENABLED: false,
|
|
||||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
|
data: mockAllSettings,
|
||||||
|
});
|
||||||
|
history = createMemoryHistory({
|
||||||
|
initialEntries: ['/settings/miscellaneous_authentication/edit'],
|
||||||
|
});
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<SettingsProvider value={mockAllOptions.actions}>
|
<SettingsProvider value={mockAllOptions.actions}>
|
||||||
<ActivityStreamEdit />
|
<MiscAuthenticationEdit />
|
||||||
</SettingsProvider>,
|
</SettingsProvider>,
|
||||||
{
|
{
|
||||||
context: { router: { history } },
|
context: { router: { history } },
|
||||||
@@ -45,54 +64,23 @@ describe('<ActivityStreamEdit />', () => {
|
|||||||
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('initially renders without crashing', () => {
|
test('initially renders without crashing', async () => {
|
||||||
expect(wrapper.find('ActivityStreamEdit').length).toBe(1);
|
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 () => {
|
await act(async () => {
|
||||||
wrapper.find('button[aria-label="Cancel"]').invoke('onClick')();
|
wrapper.find('button[aria-label="Save"]').simulate('click');
|
||||||
});
|
|
||||||
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.update();
|
wrapper.update();
|
||||||
expect(
|
const { AUTHENTICATION_BACKENDS, ...rest } = authenticationData;
|
||||||
wrapper.find('Switch#ACTIVITY_STREAM_ENABLED').prop('isChecked')
|
expect(SettingsAPI.updateAll).toHaveBeenCalledWith(rest);
|
||||||
).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,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -107,11 +95,33 @@ describe('<ActivityStreamEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('authentication');
|
||||||
ACTIVITY_STREAM_ENABLED: true,
|
});
|
||||||
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: false,
|
|
||||||
|
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 () => {
|
test('should display error message on unsuccessful submission', async () => {
|
||||||
@@ -138,7 +148,7 @@ describe('<ActivityStreamEdit />', () => {
|
|||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<SettingsProvider value={mockAllOptions.actions}>
|
<SettingsProvider value={mockAllOptions.actions}>
|
||||||
<ActivityStreamEdit />
|
<MiscAuthenticationEdit />
|
||||||
</SettingsProvider>
|
</SettingsProvider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from './MiscAuthenticationEdit';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from './MiscAuthentication';
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Link, Redirect, Route, Switch } from 'react-router-dom';
|
import { Link, Redirect, Route, Switch } from 'react-router-dom';
|
||||||
|
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { PageSection, Card } from '@patternfly/react-core';
|
import { PageSection, Card } from '@patternfly/react-core';
|
||||||
import ContentError from '../../../components/ContentError';
|
import ContentError from '../../../components/ContentError';
|
||||||
|
|||||||
@@ -18,84 +18,49 @@ import { sortNestedDetails, pluck } from '../../shared/settingUtils';
|
|||||||
|
|
||||||
function MiscSystemDetail() {
|
function MiscSystemDetail() {
|
||||||
const { me } = useConfig();
|
const { me } = useConfig();
|
||||||
const { GET: allOptions } = useSettings();
|
const { GET: options } = useSettings();
|
||||||
|
|
||||||
const { isLoading, error, request, result: system } = useRequest(
|
const { isLoading, error, request, result: system } = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
const { data } = await SettingsAPI.readCategory('all');
|
const { data } = await SettingsAPI.readCategory('system');
|
||||||
let DEFAULT_EXECUTION_ENVIRONMENT = '';
|
|
||||||
if (data.DEFAULT_EXECUTION_ENVIRONMENT) {
|
if (data.DEFAULT_EXECUTION_ENVIRONMENT) {
|
||||||
const {
|
const {
|
||||||
data: { name },
|
data: { name },
|
||||||
} = await ExecutionEnvironmentsAPI.readDetail(
|
} = await ExecutionEnvironmentsAPI.readDetail(
|
||||||
data.DEFAULT_EXECUTION_ENVIRONMENT
|
data.DEFAULT_EXECUTION_ENVIRONMENT
|
||||||
);
|
);
|
||||||
DEFAULT_EXECUTION_ENVIRONMENT = name;
|
data.DEFAULT_EXECUTION_ENVIRONMENT = name;
|
||||||
}
|
}
|
||||||
const {
|
|
||||||
OAUTH2_PROVIDER: {
|
const systemData = pluck(
|
||||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
|
||||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
|
||||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
|
||||||
},
|
|
||||||
...pluckedSystemData
|
|
||||||
} = pluck(
|
|
||||||
data,
|
data,
|
||||||
'ALLOW_OAUTH2_FOR_EXTERNAL_USERS',
|
'ACTIVITY_STREAM_ENABLED',
|
||||||
'AUTH_BASIC_ENABLED',
|
'ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC',
|
||||||
'AUTOMATION_ANALYTICS_GATHER_INTERVAL',
|
'AUTOMATION_ANALYTICS_GATHER_INTERVAL',
|
||||||
'AUTOMATION_ANALYTICS_URL',
|
'AUTOMATION_ANALYTICS_URL',
|
||||||
'INSIGHTS_TRACKING_STATE',
|
'INSIGHTS_TRACKING_STATE',
|
||||||
'LOGIN_REDIRECT_OVERRIDE',
|
|
||||||
'MANAGE_ORGANIZATION_AUTH',
|
'MANAGE_ORGANIZATION_AUTH',
|
||||||
'DISABLE_LOCAL_AUTH',
|
|
||||||
'OAUTH2_PROVIDER',
|
|
||||||
'ORG_ADMINS_CAN_SEE_ALL_USERS',
|
'ORG_ADMINS_CAN_SEE_ALL_USERS',
|
||||||
'REDHAT_PASSWORD',
|
|
||||||
'REDHAT_USERNAME',
|
'REDHAT_USERNAME',
|
||||||
'REMOTE_HOST_HEADERS',
|
'REDHAT_PASSWORD',
|
||||||
'SESSIONS_PER_USER',
|
|
||||||
'SESSION_COOKIE_AGE',
|
|
||||||
'SUBSCRIPTIONS_USERNAME',
|
'SUBSCRIPTIONS_USERNAME',
|
||||||
'SUBSCRIPTIONS_PASSWORD',
|
'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 = {};
|
const mergedData = {};
|
||||||
Object.keys(systemData).forEach(key => {
|
Object.keys(systemData).forEach(key => {
|
||||||
mergedData[key] = systemOptions[key];
|
mergedData[key] = options[key];
|
||||||
mergedData[key].value = systemData[key];
|
mergedData[key].value = systemData[key];
|
||||||
});
|
});
|
||||||
return sortNestedDetails(mergedData);
|
return sortNestedDetails(mergedData);
|
||||||
}, [allOptions]),
|
}, [options]),
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -22,28 +22,26 @@ describe('<MiscSystemDetail />', () => {
|
|||||||
SettingsAPI.readCategory = jest.fn();
|
SettingsAPI.readCategory = jest.fn();
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
ALLOW_OAUTH2_FOR_EXTERNAL_USERS: false,
|
ACTIVITY_STREAM_ENABLED: true,
|
||||||
AUTH_BASIC_ENABLED: true,
|
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: false,
|
||||||
AUTOMATION_ANALYTICS_GATHER_INTERVAL: 14400,
|
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',
|
AUTOMATION_ANALYTICS_URL: 'https://example.com',
|
||||||
|
INSTALL_UUID: 'db39b9ec-0c6e-4554-987d-42aw9c732ed8',
|
||||||
|
DEFAULT_EXECUTION_ENVIRONMENT: 1,
|
||||||
CUSTOM_VENV_PATHS: [],
|
CUSTOM_VENV_PATHS: [],
|
||||||
INSIGHTS_TRACKING_STATE: false,
|
INSIGHTS_TRACKING_STATE: false,
|
||||||
LOGIN_REDIRECT_OVERRIDE: 'https://redirect.com',
|
AUTOMATION_ANALYTICS_LAST_GATHER: null,
|
||||||
MANAGE_ORGANIZATION_AUTH: true,
|
AUTOMATION_ANALYTICS_LAST_ENTRIES: 'foo',
|
||||||
DISABLE_LOCAL_AUTH: false,
|
AUTOMATION_ANALYTICS_GATHER_INTERVAL: 14400,
|
||||||
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,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
ExecutionEnvironmentsAPI.readDetail = jest.fn();
|
ExecutionEnvironmentsAPI.readDetail = jest.fn();
|
||||||
@@ -77,14 +75,17 @@ describe('<MiscSystemDetail />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should render expected details', () => {
|
test('should render expected details', () => {
|
||||||
assertDetail(wrapper, 'Access Token Expiration', '1 seconds');
|
|
||||||
assertDetail(wrapper, 'All Users Visible to Organization Admins', 'On');
|
|
||||||
assertDetail(
|
assertDetail(
|
||||||
wrapper,
|
wrapper,
|
||||||
'Allow External Users to Create OAuth2 Tokens',
|
'Unique identifier for an installation',
|
||||||
'Off'
|
'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(
|
assertDetail(
|
||||||
wrapper,
|
wrapper,
|
||||||
'Insights for Ansible Automation Platform Gather Interval',
|
'Insights for Ansible Automation Platform Gather Interval',
|
||||||
@@ -96,32 +97,24 @@ describe('<MiscSystemDetail />', () => {
|
|||||||
'https://example.com'
|
'https://example.com'
|
||||||
);
|
);
|
||||||
assertDetail(wrapper, 'Base URL of the service', 'https://towerhost');
|
assertDetail(wrapper, 'Base URL of the service', 'https://towerhost');
|
||||||
assertDetail(wrapper, 'Enable HTTP Basic Auth', 'On');
|
|
||||||
assertDetail(
|
assertDetail(
|
||||||
wrapper,
|
wrapper,
|
||||||
'Gather data for Insights for Ansible Automation Platform',
|
'Gather data for Insights for Ansible Automation Platform',
|
||||||
'Off'
|
'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(
|
assertDetail(
|
||||||
wrapper,
|
wrapper,
|
||||||
'Organization Admins Can Manage Users and Teams',
|
'Organization Admins Can Manage Users and Teams',
|
||||||
'On'
|
'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 password', 'Encrypted');
|
||||||
assertDetail(wrapper, 'Red Hat customer username', 'mock name');
|
assertDetail(wrapper, 'Red Hat customer username', 'name1');
|
||||||
assertDetail(wrapper, 'Refresh Token Expiration', '3 seconds');
|
assertDetail(wrapper, 'Red Hat or Satellite password', 'Encrypted');
|
||||||
|
assertDetail(wrapper, 'Red Hat or Satellite username', 'name2');
|
||||||
assertVariableDetail(wrapper, 'Remote Host Headers', '[]');
|
assertVariableDetail(wrapper, 'Remote Host Headers', '[]');
|
||||||
|
assertVariableDetail(wrapper, 'Proxy IP Allowed List', '[]');
|
||||||
assertDetail(wrapper, 'Global default execution environment', 'Foo');
|
assertDetail(wrapper, 'Global default execution environment', 'Foo');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -30,76 +30,33 @@ function MiscSystemEdit() {
|
|||||||
|
|
||||||
const { isLoading, error, request: fetchSystem, result: system } = useRequest(
|
const { isLoading, error, request: fetchSystem, result: system } = useRequest(
|
||||||
useCallback(async () => {
|
useCallback(async () => {
|
||||||
const { data } = await SettingsAPI.readCategory('all');
|
const { data } = await SettingsAPI.readCategory('system');
|
||||||
const {
|
const systemData = pluck(
|
||||||
OAUTH2_PROVIDER: {
|
|
||||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
|
||||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
|
||||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
|
||||||
},
|
|
||||||
...pluckedSystemData
|
|
||||||
} = pluck(
|
|
||||||
data,
|
data,
|
||||||
'ALLOW_OAUTH2_FOR_EXTERNAL_USERS',
|
'ACTIVITY_STREAM_ENABLED',
|
||||||
'AUTH_BASIC_ENABLED',
|
'ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC',
|
||||||
'AUTOMATION_ANALYTICS_GATHER_INTERVAL',
|
'AUTOMATION_ANALYTICS_GATHER_INTERVAL',
|
||||||
'AUTOMATION_ANALYTICS_URL',
|
'AUTOMATION_ANALYTICS_URL',
|
||||||
|
'AUTOMATION_ANALYTICS_LAST_ENTRIES',
|
||||||
'INSIGHTS_TRACKING_STATE',
|
'INSIGHTS_TRACKING_STATE',
|
||||||
'LOGIN_REDIRECT_OVERRIDE',
|
|
||||||
'MANAGE_ORGANIZATION_AUTH',
|
'MANAGE_ORGANIZATION_AUTH',
|
||||||
'DISABLE_LOCAL_AUTH',
|
|
||||||
'OAUTH2_PROVIDER',
|
|
||||||
'ORG_ADMINS_CAN_SEE_ALL_USERS',
|
'ORG_ADMINS_CAN_SEE_ALL_USERS',
|
||||||
'REDHAT_PASSWORD',
|
|
||||||
'REDHAT_USERNAME',
|
'REDHAT_USERNAME',
|
||||||
|
'REDHAT_PASSWORD',
|
||||||
|
'SUBSCRIPTIONS_USERNAME',
|
||||||
|
'SUBSCRIPTIONS_PASSWORD',
|
||||||
'REMOTE_HOST_HEADERS',
|
'REMOTE_HOST_HEADERS',
|
||||||
'SESSIONS_PER_USER',
|
|
||||||
'SESSION_COOKIE_AGE',
|
|
||||||
'TOWER_URL_BASE',
|
'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 = {};
|
const mergedData = {};
|
||||||
Object.keys(systemData).forEach(key => {
|
Object.keys(systemData).forEach(key => {
|
||||||
if (!systemOptions[key]) {
|
if (!options[key]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mergedData[key] = systemOptions[key];
|
mergedData[key] = options[key];
|
||||||
mergedData[key].value = systemData[key];
|
mergedData[key].value = systemData[key];
|
||||||
});
|
});
|
||||||
return mergedData;
|
return mergedData;
|
||||||
@@ -122,50 +79,29 @@ function MiscSystemEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
const {
|
useCallback(async () => {
|
||||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
await SettingsAPI.revertCategory('system');
|
||||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
}, []),
|
||||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
null
|
||||||
...formData
|
);
|
||||||
} = form;
|
|
||||||
|
|
||||||
|
const handleSubmit = async form => {
|
||||||
await submitForm({
|
await submitForm({
|
||||||
...formData,
|
...form,
|
||||||
REMOTE_HOST_HEADERS: formatJson(formData.REMOTE_HOST_HEADERS),
|
PROXY_IP_ALLOWED_LIST: formatJson(form.PROXY_IP_ALLOWED_LIST),
|
||||||
OAUTH2_PROVIDER: {
|
REMOTE_HOST_HEADERS: formatJson(form.REMOTE_HOST_HEADERS),
|
||||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
|
||||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
|
||||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
|
||||||
},
|
|
||||||
DEFAULT_EXECUTION_ENVIRONMENT:
|
DEFAULT_EXECUTION_ENVIRONMENT:
|
||||||
formData.DEFAULT_EXECUTION_ENVIRONMENT?.id || null,
|
form.DEFAULT_EXECUTION_ENVIRONMENT?.id || null,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const {
|
await revertAll();
|
||||||
ACCESS_TOKEN_EXPIRE_SECONDS,
|
|
||||||
REFRESH_TOKEN_EXPIRE_SECONDS,
|
|
||||||
AUTHORIZATION_CODE_EXPIRE_SECONDS,
|
|
||||||
...systemData
|
|
||||||
} = system;
|
|
||||||
|
|
||||||
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();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/miscellaneous_system/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -226,6 +162,14 @@ function MiscSystemEdit() {
|
|||||||
return (
|
return (
|
||||||
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
|
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
|
||||||
<FormColumnLayout>
|
<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
|
<ExecutionEnvironmentLookup
|
||||||
helperTextInvalid={
|
helperTextInvalid={
|
||||||
formik.errors.DEFAULT_EXECUTION_ENVIRONMENT
|
formik.errors.DEFAULT_EXECUTION_ENVIRONMENT
|
||||||
@@ -267,52 +211,6 @@ function MiscSystemEdit() {
|
|||||||
name="MANAGE_ORGANIZATION_AUTH"
|
name="MANAGE_ORGANIZATION_AUTH"
|
||||||
config={system.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
|
<BooleanField
|
||||||
name="INSIGHTS_TRACKING_STATE"
|
name="INSIGHTS_TRACKING_STATE"
|
||||||
config={system.INSIGHTS_TRACKING_STATE}
|
config={system.INSIGHTS_TRACKING_STATE}
|
||||||
@@ -325,6 +223,14 @@ function MiscSystemEdit() {
|
|||||||
name="REDHAT_PASSWORD"
|
name="REDHAT_PASSWORD"
|
||||||
config={system.REDHAT_PASSWORD}
|
config={system.REDHAT_PASSWORD}
|
||||||
/>
|
/>
|
||||||
|
<InputField
|
||||||
|
name="SUBSCRIPTIONS_USERNAME"
|
||||||
|
config={system.SUBSCRIPTIONS_USERNAME}
|
||||||
|
/>
|
||||||
|
<EncryptedField
|
||||||
|
name="SUBSCRIPTIONS_PASSWORD"
|
||||||
|
config={system.SUBSCRIPTIONS_PASSWORD}
|
||||||
|
/>
|
||||||
<InputField
|
<InputField
|
||||||
name="AUTOMATION_ANALYTICS_URL"
|
name="AUTOMATION_ANALYTICS_URL"
|
||||||
config={system.AUTOMATION_ANALYTICS_URL}
|
config={system.AUTOMATION_ANALYTICS_URL}
|
||||||
@@ -336,12 +242,22 @@ function MiscSystemEdit() {
|
|||||||
type="number"
|
type="number"
|
||||||
isRequired
|
isRequired
|
||||||
/>
|
/>
|
||||||
|
<InputField
|
||||||
|
name="AUTOMATION_ANALYTICS_LAST_ENTRIES"
|
||||||
|
config={system.AUTOMATION_ANALYTICS_LAST_ENTRIES}
|
||||||
|
/>
|
||||||
<ObjectField
|
<ObjectField
|
||||||
name="REMOTE_HOST_HEADERS"
|
name="REMOTE_HOST_HEADERS"
|
||||||
config={system.REMOTE_HOST_HEADERS}
|
config={system.REMOTE_HOST_HEADERS}
|
||||||
isRequired
|
isRequired
|
||||||
/>
|
/>
|
||||||
|
<ObjectField
|
||||||
|
name="PROXY_IP_ALLOWED_LIST"
|
||||||
|
config={system.PROXY_IP_ALLOWED_LIST}
|
||||||
|
isRequired
|
||||||
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -23,27 +23,22 @@ const mockExecutionEnvironment = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const systemData = {
|
const systemData = {
|
||||||
ALLOW_OAUTH2_FOR_EXTERNAL_USERS: false,
|
ACTIVITY_STREAM_ENABLED: true,
|
||||||
AUTH_BASIC_ENABLED: true,
|
ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC: false,
|
||||||
AUTOMATION_ANALYTICS_GATHER_INTERVAL: 14400,
|
AUTOMATION_ANALYTICS_GATHER_INTERVAL: 14400,
|
||||||
|
AUTOMATION_ANALYTICS_LAST_ENTRIES: '',
|
||||||
AUTOMATION_ANALYTICS_URL: 'https://example.com',
|
AUTOMATION_ANALYTICS_URL: 'https://example.com',
|
||||||
DEFAULT_EXECUTION_ENVIRONMENT: 1,
|
DEFAULT_EXECUTION_ENVIRONMENT: 1,
|
||||||
INSIGHTS_TRACKING_STATE: false,
|
INSIGHTS_TRACKING_STATE: false,
|
||||||
LOGIN_REDIRECT_OVERRIDE: '',
|
|
||||||
MANAGE_ORGANIZATION_AUTH: true,
|
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,
|
ORG_ADMINS_CAN_SEE_ALL_USERS: true,
|
||||||
REDHAT_PASSWORD: '',
|
|
||||||
REDHAT_USERNAME: '',
|
REDHAT_USERNAME: '',
|
||||||
|
REDHAT_PASSWORD: '',
|
||||||
|
SUBSCRIPTIONS_USERNAME: '',
|
||||||
|
SUBSCRIPTIONS_PASSWORD: '',
|
||||||
REMOTE_HOST_HEADERS: ['REMOTE_ADDR', 'REMOTE_HOST'],
|
REMOTE_HOST_HEADERS: ['REMOTE_ADDR', 'REMOTE_HOST'],
|
||||||
SESSIONS_PER_USER: -1,
|
|
||||||
SESSION_COOKIE_AGE: 1800,
|
|
||||||
TOWER_URL_BASE: 'https://localhost:3000',
|
TOWER_URL_BASE: 'https://localhost:3000',
|
||||||
|
PROXY_IP_ALLOWED_LIST: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('<MiscSystemEdit />', () => {
|
describe('<MiscSystemEdit />', () => {
|
||||||
@@ -55,6 +50,7 @@ describe('<MiscSystemEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: mockAllSettings,
|
data: mockAllSettings,
|
||||||
@@ -116,7 +112,7 @@ describe('<MiscSystemEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -131,7 +127,8 @@ describe('<MiscSystemEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
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 () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -47,18 +47,23 @@ function RADIUSEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('radius');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm(form);
|
await submitForm(form);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(radius).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/radius/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -90,6 +95,7 @@ function RADIUSEdit() {
|
|||||||
config={radius.RADIUS_SECRET}
|
config={radius.RADIUS_SECRET}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<RADIUSEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -60,7 +61,7 @@ describe('<RADIUSEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -75,12 +76,8 @@ describe('<RADIUSEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('radius');
|
||||||
RADIUS_SERVER: '',
|
|
||||||
RADIUS_PORT: 1812,
|
|
||||||
RADIUS_SECRET: '',
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -56,6 +56,13 @@ function SAMLEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('saml');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm({
|
await submitForm({
|
||||||
...form,
|
...form,
|
||||||
@@ -86,13 +93,11 @@ function SAMLEdit() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(saml).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/saml/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -185,6 +190,7 @@ function SAMLEdit() {
|
|||||||
config={saml.SOCIAL_AUTH_SAML_EXTRA_DATA}
|
config={saml.SOCIAL_AUTH_SAML_EXTRA_DATA}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<SAMLEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -131,7 +132,7 @@ describe('<SAMLEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -146,26 +147,8 @@ describe('<SAMLEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('saml');
|
||||||
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,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ function SettingList() {
|
|||||||
path: '/settings/miscellaneous_system',
|
path: '/settings/miscellaneous_system',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t`Activity Stream settings`,
|
title: t`Miscellaneous Authentication settings`,
|
||||||
path: '/settings/activity_stream',
|
path: '/settings/miscellaneous_authentication',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t`Logging settings`,
|
title: t`Logging settings`,
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import React, { useCallback, useEffect } from 'react';
|
import React, { useCallback, useEffect } from 'react';
|
||||||
import { Link, Route, Switch, Redirect } from 'react-router-dom';
|
import { Link, Route, Switch, Redirect } from 'react-router-dom';
|
||||||
|
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { PageSection, Card } from '@patternfly/react-core';
|
import { PageSection, Card } from '@patternfly/react-core';
|
||||||
import ContentError from '../../components/ContentError';
|
import ContentError from '../../components/ContentError';
|
||||||
import ContentLoading from '../../components/ContentLoading';
|
import ContentLoading from '../../components/ContentLoading';
|
||||||
import ScreenHeader from '../../components/ScreenHeader';
|
import ScreenHeader from '../../components/ScreenHeader';
|
||||||
import ActivityStream from './ActivityStream';
|
|
||||||
import AzureAD from './AzureAD';
|
import AzureAD from './AzureAD';
|
||||||
import GitHub from './GitHub';
|
import GitHub from './GitHub';
|
||||||
import GoogleOAuth2 from './GoogleOAuth2';
|
import GoogleOAuth2 from './GoogleOAuth2';
|
||||||
@@ -14,6 +12,7 @@ import Jobs from './Jobs';
|
|||||||
import LDAP from './LDAP';
|
import LDAP from './LDAP';
|
||||||
import Subscription from './Subscription';
|
import Subscription from './Subscription';
|
||||||
import Logging from './Logging';
|
import Logging from './Logging';
|
||||||
|
import MiscAuthentication from './MiscAuthentication';
|
||||||
import MiscSystem from './MiscSystem';
|
import MiscSystem from './MiscSystem';
|
||||||
import RADIUS from './RADIUS';
|
import RADIUS from './RADIUS';
|
||||||
import SAML from './SAML';
|
import SAML from './SAML';
|
||||||
@@ -94,6 +93,9 @@ function Settings() {
|
|||||||
'/settings/logging': t`Logging`,
|
'/settings/logging': t`Logging`,
|
||||||
'/settings/logging/details': t`Details`,
|
'/settings/logging/details': t`Details`,
|
||||||
'/settings/logging/edit': t`Edit 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': t`Miscellaneous System`,
|
||||||
'/settings/miscellaneous_system/details': t`Details`,
|
'/settings/miscellaneous_system/details': t`Details`,
|
||||||
'/settings/miscellaneous_system/edit': t`Edit Details`,
|
'/settings/miscellaneous_system/edit': t`Edit Details`,
|
||||||
@@ -142,9 +144,6 @@ function Settings() {
|
|||||||
<SettingsProvider value={result}>
|
<SettingsProvider value={result}>
|
||||||
<ScreenHeader streamType="setting" breadcrumbConfig={breadcrumbConfig} />
|
<ScreenHeader streamType="setting" breadcrumbConfig={breadcrumbConfig} />
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/settings/activity_stream">
|
|
||||||
<ActivityStream />
|
|
||||||
</Route>
|
|
||||||
<Route path="/settings/azure">
|
<Route path="/settings/azure">
|
||||||
<AzureAD />
|
<AzureAD />
|
||||||
</Route>
|
</Route>
|
||||||
@@ -170,6 +169,9 @@ function Settings() {
|
|||||||
<Route path="/settings/logging">
|
<Route path="/settings/logging">
|
||||||
<Logging />
|
<Logging />
|
||||||
</Route>
|
</Route>
|
||||||
|
<Route path="/settings/miscellaneous_authentication">
|
||||||
|
<MiscAuthentication />
|
||||||
|
</Route>
|
||||||
<Route path="/settings/miscellaneous_system">
|
<Route path="/settings/miscellaneous_system">
|
||||||
<MiscSystem />
|
<MiscSystem />
|
||||||
</Route>
|
</Route>
|
||||||
|
|||||||
@@ -51,18 +51,23 @@ function TACACSEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('tacacsplus');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm(form);
|
await submitForm(form);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(tacacs).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push('/settings/tacacs/details');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -107,6 +112,7 @@ function TACACSEdit() {
|
|||||||
config={tacacs.TACACSPLUS_AUTH_PROTOCOL}
|
config={tacacs.TACACSPLUS_AUTH_PROTOCOL}
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<TACACSEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -68,7 +69,7 @@ describe('<TACACSEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -83,14 +84,8 @@ describe('<TACACSEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('tacacsplus');
|
||||||
TACACSPLUS_HOST: '',
|
|
||||||
TACACSPLUS_PORT: 49,
|
|
||||||
TACACSPLUS_SECRET: '',
|
|
||||||
TACACSPLUS_SESSION_TIMEOUT: 5,
|
|
||||||
TACACSPLUS_AUTH_PROTOCOL: 'ascii',
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
@@ -65,18 +65,26 @@ function UIEdit() {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { error: revertError, request: revertAll } = useRequest(
|
||||||
|
useCallback(async () => {
|
||||||
|
await SettingsAPI.revertCategory('ui');
|
||||||
|
}, []),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const handleSubmit = async form => {
|
const handleSubmit = async form => {
|
||||||
await submitForm(form);
|
await submitForm(form);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRevertAll = async () => {
|
const handleRevertAll = async () => {
|
||||||
const defaultValues = Object.assign(
|
await revertAll();
|
||||||
...Object.entries(uiData).map(([key, value]) => ({
|
|
||||||
[key]: value.default,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
await submitForm(defaultValues);
|
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
history.push({
|
||||||
|
pathname: '/settings/ui/details',
|
||||||
|
hardReload: true,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -115,6 +123,7 @@ function UIEdit() {
|
|||||||
type="dataURL"
|
type="dataURL"
|
||||||
/>
|
/>
|
||||||
{submitError && <FormSubmitError error={submitError} />}
|
{submitError && <FormSubmitError error={submitError} />}
|
||||||
|
{revertError && <FormSubmitError error={revertError} />}
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<RevertFormActionGroup
|
<RevertFormActionGroup
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ describe('<UIEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
SettingsAPI.revertCategory.mockResolvedValue({});
|
||||||
SettingsAPI.updateAll.mockResolvedValue({});
|
SettingsAPI.updateAll.mockResolvedValue({});
|
||||||
SettingsAPI.readCategory.mockResolvedValue({
|
SettingsAPI.readCategory.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -62,7 +63,7 @@ describe('<UIEdit />', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send default values to api on form revert all', async () => {
|
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);
|
expect(wrapper.find('RevertAllAlert')).toHaveLength(0);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper
|
wrapper
|
||||||
@@ -77,12 +78,8 @@ describe('<UIEdit />', () => {
|
|||||||
.invoke('onClick')();
|
.invoke('onClick')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledTimes(1);
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledTimes(1);
|
||||||
expect(SettingsAPI.updateAll).toHaveBeenCalledWith({
|
expect(SettingsAPI.revertCategory).toHaveBeenCalledWith('ui');
|
||||||
CUSTOM_LOGIN_INFO: '',
|
|
||||||
CUSTOM_LOGO: '',
|
|
||||||
PENDO_TRACKING_STATE: 'off',
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should successfully send request to api on form submission', async () => {
|
test('should successfully send request to api on form submission', async () => {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user