diff --git a/frontend/src/__tests__/metrics-poller-test.jsx b/frontend/src/__tests__/metrics-poller-test.jsx
deleted file mode 100644
index cd652cf5e7..0000000000
--- a/frontend/src/__tests__/metrics-poller-test.jsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import configureStore from 'redux-mock-store';
-import { List } from 'immutable';
-import thunkMiddleware from 'redux-thunk';
-import fetchMock from 'fetch-mock';
-import MetricsPoller from '../metrics-poller';
-
-const mockStore = configureStore([thunkMiddleware]);
-
-describe('metrics-poller.js', () => {
- afterEach(() => {
- fetchMock.reset();
- fetchMock.restore();
- });
-
- test('Should not start poller before toggles are recieved', () => {
- const initialState = { features: List.of([{ name: 'test1' }]) };
- const store = mockStore(initialState);
- fetchMock.getOnce('api/admin/metrics/feature-toggles', {
- body: { lastHour: {}, lastMinute: {} },
- headers: { 'content-type': 'application/json' },
- });
-
- const metricsPoller = new MetricsPoller(store);
- metricsPoller.start();
-
- expect(metricsPoller.timer).toBeUndefined();
- });
-
- test('Should not start poller when state does not contain toggles', () => {
- const initialState = { features: new List([]) };
- const store = mockStore(initialState);
-
- const metricsPoller = new MetricsPoller(store);
- metricsPoller.start();
-
- store.dispatch({
- type: 'some',
- receivedAt: Date.now(),
- });
-
- expect(metricsPoller.timer).toBeUndefined();
- });
-
- test('Should start poller when state gets toggles', () => {
- fetchMock.getOnce('api/admin/metrics/feature-toggles', {
- body: { lastHour: {}, lastMinute: {} },
- headers: { 'content-type': 'application/json' },
- });
-
- const initialState = { features: List.of([{ name: 'test1' }]) };
- const store = mockStore(initialState);
-
- const metricsPoller = new MetricsPoller(store);
- metricsPoller.start();
-
- store.dispatch({
- type: 'RECEIVE_FEATURE_TOGGLES',
- featureToggles: [{ name: 'test' }],
- receivedAt: Date.now(),
- });
-
- expect(metricsPoller.timer).toBeDefined();
- });
-});
diff --git a/frontend/src/component/App.tsx b/frontend/src/component/App.tsx
index 9ed8fce469..445ce09672 100644
--- a/frontend/src/component/App.tsx
+++ b/frontend/src/component/App.tsx
@@ -13,8 +13,8 @@ import IAuthStatus from '../interfaces/user';
import { useEffect } from 'react';
import NotFound from './common/NotFound/NotFound';
import Feedback from './common/Feedback';
-import { SWRConfig } from 'swr';
import useToast from '../hooks/useToast';
+import SWRProvider from './providers/SWRProvider/SWRProvider';
interface IAppProps extends RouteComponentProps {
user: IAuthStatus;
@@ -75,55 +75,34 @@ const App = ({ location, user, fetchUiBootstrap, feedback }: IAppProps) => {
};
return (
- {
- // Never retry on 404.
- if (error.status === 404) {
- return error;
- }
- setTimeout(() => revalidate({ retryCount }), 5000);
- },
- onError: error => {
- if (!isUnauthorized()) {
- setToastData({
- show: true,
- type: 'error',
- text: error.message,
- });
- }
- },
- }}
+
+ {' '}
{renderMainLayoutRoutes()}
{renderStandaloneRoutes()}
-
-
+
+
{toast}
-
+
);
};
// Set state to any for now, to avoid typing up entire state object while converting to tsx.
diff --git a/frontend/src/component/addons/AddonList/AvailableAddons/AvailableAddons.jsx b/frontend/src/component/addons/AddonList/AvailableAddons/AvailableAddons.jsx
index 9f19deec45..95fb25e755 100644
--- a/frontend/src/component/addons/AddonList/AvailableAddons/AvailableAddons.jsx
+++ b/frontend/src/component/addons/AddonList/AvailableAddons/AvailableAddons.jsx
@@ -9,7 +9,7 @@ import {
ListItemText,
} from '@material-ui/core';
import ConditionallyRender from '../../../common/ConditionallyRender/ConditionallyRender';
-import { CREATE_ADDON } from '../../../AccessProvider/permissions';
+import { CREATE_ADDON } from '../../../providers/AccessProvider/permissions';
import PropTypes from 'prop-types';
const AvailableAddons = ({ providers, getIcon, hasAccess, history }) => {
diff --git a/frontend/src/component/addons/AddonList/ConfiguredAddons/ConfiguredAddons.jsx b/frontend/src/component/addons/AddonList/ConfiguredAddons/ConfiguredAddons.jsx
index 1107444ef3..7346408721 100644
--- a/frontend/src/component/addons/AddonList/ConfiguredAddons/ConfiguredAddons.jsx
+++ b/frontend/src/component/addons/AddonList/ConfiguredAddons/ConfiguredAddons.jsx
@@ -13,7 +13,7 @@ import ConditionallyRender from '../../../common/ConditionallyRender/Conditional
import {
DELETE_ADDON,
UPDATE_ADDON,
-} from '../../../AccessProvider/permissions';
+} from '../../../providers/AccessProvider/permissions';
import { Link } from 'react-router-dom';
import PageContent from '../../../common/PageContent/PageContent';
import PropTypes from 'prop-types';
diff --git a/frontend/src/component/api-token/ApiTokenList/ApiTokenList.tsx b/frontend/src/component/api-token/ApiTokenList/ApiTokenList.tsx
index 66b56c2862..152ee21a7b 100644
--- a/frontend/src/component/api-token/ApiTokenList/ApiTokenList.tsx
+++ b/frontend/src/component/api-token/ApiTokenList/ApiTokenList.tsx
@@ -1,24 +1,37 @@
import { useContext, useState } from 'react';
import { Link } from 'react-router-dom';
-import { Button, IconButton, Table, TableBody, TableCell, TableHead, TableRow, } from '@material-ui/core';
+import {
+ Button,
+ IconButton,
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableRow,
+} from '@material-ui/core';
import AccessContext from '../../../contexts/AccessContext';
import useToast from '../../../hooks/useToast';
import useLoading from '../../../hooks/useLoading';
import useApiTokens from '../../../hooks/api/getters/useApiTokens/useApiTokens';
import useUiConfig from '../../../hooks/api/getters/useUiConfig/useUiConfig';
-import useApiTokensApi, { IApiTokenCreate } from '../../../hooks/api/actions/useApiTokensApi/useApiTokensApi';
+import useApiTokensApi, {
+ IApiTokenCreate,
+} from '../../../hooks/api/actions/useApiTokensApi/useApiTokensApi';
import ApiError from '../../common/ApiError/ApiError';
import PageContent from '../../common/PageContent';
import HeaderTitle from '../../common/HeaderTitle';
import ConditionallyRender from '../../common/ConditionallyRender';
-import { CREATE_API_TOKEN, DELETE_API_TOKEN } from '../../AccessProvider/permissions';
+import {
+ CREATE_API_TOKEN,
+ DELETE_API_TOKEN,
+} from '../../providers/AccessProvider/permissions';
import { useStyles } from './ApiTokenList.styles';
import { formatDateWithLocale } from '../../common/util';
import Secret from './secret';
import { Delete, FileCopy } from '@material-ui/icons';
import ApiTokenCreate from '../ApiTokenCreate/ApiTokenCreate';
import Dialogue from '../../common/Dialogue';
-import {CREATE_API_TOKEN_BUTTON} from '../../../testIds'
+import { CREATE_API_TOKEN_BUTTON } from '../../../testIds';
import { Alert } from '@material-ui/lab';
interface IApiToken {
@@ -54,7 +67,6 @@ const ApiTokenList = ({ location }: IApiTokenList) => {
const closeDialog = () => {
setDialog(false);
};
-
const renderError = () => {
return (
@@ -74,7 +86,7 @@ const ApiTokenList = ({ location }: IApiTokenList) => {
show: true,
text: 'Successfully created API token.',
});
- }
+ };
const copyToken = (value: string) => {
navigator.clipboard.writeText(value);
setToastData({
@@ -85,7 +97,7 @@ const ApiTokenList = ({ location }: IApiTokenList) => {
};
const onDeleteToken = async () => {
- if(delToken) {
+ if (delToken) {
await deleteToken(delToken.secret);
}
setDeleteToken(undefined);
@@ -99,12 +111,12 @@ const ApiTokenList = ({ location }: IApiTokenList) => {
};
const renderProject = (projectId: string) => {
- if(!projectId || projectId === '*') {
+ if (!projectId || projectId === '*') {
return projectId;
} else {
- return ( {projectId});
+ return {projectId};
}
- }
+ };
const renderApiTokens = (tokens: IApiToken[]) => {
return (
@@ -112,65 +124,106 @@ const ApiTokenList = ({ location }: IApiTokenList) => {
Created
- Username
- Type
-
- Project
- Environment
- >} />
+
+ Username
+
+
+ Type
+
+
+
+ Project
+
+
+ Environment
+
+ >
+ }
+ />
Secret
Token
- Actions
+
+ Actions
+
{tokens.map(item => {
return (
-
+
{formatDateWithLocale(
item.createdAt,
location.locale
)}
-
+
{item.username}
-
+
{item.type}
-
-
- {renderProject(item.project)}
-
-
- {item.environment}
-
-
- Type: {item.type}
- Env: {item.environment}
- Project: {renderProject(item.project)}
-
- >}
- elseShow={<>
-
- Type: {item.type}
- Username: {item.username}
-
- >}
+
+
+ {renderProject(item.project)}
+
+
+ {item.environment}
+
+
+ Type: {item.type}
+
+ Env: {item.environment}
+
+ Project: {' '}
+ {renderProject(item.project)}
+
+ >
+ }
+ elseShow={
+ <>
+
+ Type: {item.type}
+
+ Username: {item.username}
+
+ >
+ }
/>
-
+
{
- copyToken(item.secret)
- } }
- >
-
+ copyToken(item.secret);
+ }}
+ >
+
{
onClick={() => {
setDeleteToken(item);
setShowDelete(true);
- } }
+ }}
>
- } />
+ }
+ />
);
})}
- )
- }
+ );
+ };
return (
Create API token} />} />}
- >
+ headerContent={
+
+ Create API token
+
+ }
+ />
+ }
+ />
+ }
+ >
Read the{' '}
@@ -218,7 +287,9 @@ const ApiTokenList = ({ location }: IApiTokenList) => {
API URL: {' '}
- {uiConfig.unleashUrl}/api/
+
+ {uiConfig.unleashUrl}/api/
+
@@ -230,7 +301,11 @@ const ApiTokenList = ({ location }: IApiTokenList) => {
/>
{toast}
-
+
{
title="Confirm deletion"
>
- Are you sure you want to delete the following API token?
+ Are you sure you want to delete the following API token?
+
- username : {delToken?.username}
- type : {delToken?.type}
+
+ username :{' '}
+ {delToken?.username}
+
+
+ type :{' '}
+ {delToken?.type}
+
diff --git a/frontend/src/component/application/__tests__/application-edit-component-test.js b/frontend/src/component/application/__tests__/application-edit-component-test.js
index 7c184d3f7a..e30be6ed7f 100644
--- a/frontend/src/component/application/__tests__/application-edit-component-test.js
+++ b/frontend/src/component/application/__tests__/application-edit-component-test.js
@@ -4,11 +4,11 @@ import { ThemeProvider } from '@material-ui/core';
import ClientApplications from '../application-edit-component';
import renderer from 'react-test-renderer';
import { MemoryRouter } from 'react-router-dom';
-import { ADMIN } from '../../AccessProvider/permissions';
+import { ADMIN } from '../../providers/AccessProvider/permissions';
import theme from '../../../themes/main-theme';
import { createFakeStore } from '../../../accessStoreFake';
-import AccessProvider from '../../AccessProvider/AccessProvider';
+import AccessProvider from '../../providers/AccessProvider/AccessProvider';
test('renders correctly if no application', () => {
const tree = renderer
diff --git a/frontend/src/component/application/application-edit-component.js b/frontend/src/component/application/application-edit-component.js
index d2e7fdccda..ecab61cd3e 100644
--- a/frontend/src/component/application/application-edit-component.js
+++ b/frontend/src/component/application/application-edit-component.js
@@ -18,7 +18,7 @@ import {
formatFullDateTimeWithLocale,
formatDateWithLocale,
} from '../common/util';
-import { UPDATE_APPLICATION } from '../AccessProvider/permissions';
+import { UPDATE_APPLICATION } from '../providers/AccessProvider/permissions';
import ApplicationView from './application-view';
import ApplicationUpdate from './application-update';
import TabNav from '../common/TabNav/TabNav';
diff --git a/frontend/src/component/application/application-view.jsx b/frontend/src/component/application/application-view.jsx
index 2bc1dd5c85..db769e2533 100644
--- a/frontend/src/component/application/application-view.jsx
+++ b/frontend/src/component/application/application-view.jsx
@@ -13,7 +13,10 @@ import {
import { Report, Extension, Timeline } from '@material-ui/icons';
import { shorten } from '../common';
-import { CREATE_FEATURE, CREATE_STRATEGY } from '../AccessProvider/permissions';
+import {
+ CREATE_FEATURE,
+ CREATE_STRATEGY,
+} from '../providers/AccessProvider/permissions';
import ConditionallyRender from '../common/ConditionallyRender/ConditionallyRender';
import { getTogglePath } from '../../utils/route-path-helpers';
function ApplicationView({
@@ -33,9 +36,7 @@ function ApplicationView({
{name}
- }
+ primary={ {name}}
secondary={'Missing, want to create?'}
/>
diff --git a/frontend/src/component/context/ContextList/ContextList.jsx b/frontend/src/component/context/ContextList/ContextList.jsx
index 0d9c2feac7..21e2d8b191 100644
--- a/frontend/src/component/context/ContextList/ContextList.jsx
+++ b/frontend/src/component/context/ContextList/ContextList.jsx
@@ -5,7 +5,7 @@ import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyR
import {
CREATE_CONTEXT_FIELD,
DELETE_CONTEXT_FIELD,
-} from '../../AccessProvider/permissions';
+} from '../../providers/AccessProvider/permissions';
import {
IconButton,
List,
diff --git a/frontend/src/component/environments/EnvironmentList/EnvironmentListItem/EnvironmentListItem.tsx b/frontend/src/component/environments/EnvironmentList/EnvironmentListItem/EnvironmentListItem.tsx
index 081f73b50c..cfcfa6742f 100644
--- a/frontend/src/component/environments/EnvironmentList/EnvironmentListItem/EnvironmentListItem.tsx
+++ b/frontend/src/component/environments/EnvironmentList/EnvironmentListItem/EnvironmentListItem.tsx
@@ -20,7 +20,7 @@ import AccessContext from '../../../../contexts/AccessContext';
import {
DELETE_ENVIRONMENT,
UPDATE_ENVIRONMENT,
-} from '../../../AccessProvider/permissions';
+} from '../../../providers/AccessProvider/permissions';
import { useDrag, useDrop, DropTargetMonitor } from 'react-dnd';
import { XYCoord } from 'dnd-core';
diff --git a/frontend/src/component/feature/FeatureCreate/FeatureCreate.tsx b/frontend/src/component/feature/FeatureCreate/FeatureCreate.tsx
index 757c66b7e9..ffc487b739 100644
--- a/frontend/src/component/feature/FeatureCreate/FeatureCreate.tsx
+++ b/frontend/src/component/feature/FeatureCreate/FeatureCreate.tsx
@@ -30,7 +30,7 @@ const FeatureCreate = () => {
const { projectId } = useParams();
const { createFeatureToggle, validateFeatureToggleName } = useFeatureApi();
const history = useHistory();
- const [ toggle, setToggle ] = useState({
+ const [toggle, setToggle] = useState({
name: loadNameFromUrl(),
description: '',
type: 'release',
@@ -41,7 +41,6 @@ const FeatureCreate = () => {
});
const [errors, setErrors] = useState({});
-
useEffect(() => {
window.onbeforeunload = () =>
'Data will be lost if you leave the page, are you sure?';
@@ -52,10 +51,7 @@ const FeatureCreate = () => {
};
}, []);
- const onCancel = () => history.push(
- `/projects/${projectId}`
- );
-
+ const onCancel = () => history.push(`/projects/${projectId}`);
const validateName = async (featureToggleName: string) => {
const e = { ...errors };
@@ -80,25 +76,25 @@ const FeatureCreate = () => {
try {
await createFeatureToggle(projectId, toggle).then(() =>
- history.push(
- getTogglePath(toggle.project, toggle.name, true)
- )
+ history.push(getTogglePath(toggle.project, toggle.name, true))
);
// Trigger
} catch (e: any) {
if (e.toString().includes('not allowed to be empty')) {
- setErrors({ name: 'Name is not allowed to be empty' })
+ setErrors({ name: 'Name is not allowed to be empty' });
}
}
};
- const setValue = (field:string, value:string) => {
- setToggle({...toggle, [field]: value})
- }
-
+ const setValue = (field: string, value: string) => {
+ setToggle({ ...toggle, [field]: value });
+ };
return (
-
+
diff --git a/frontend/src/component/project/ProjectList/ProjectList.tsx b/frontend/src/component/project/ProjectList/ProjectList.tsx
index 9e77ee26c3..470cd788e1 100644
--- a/frontend/src/component/project/ProjectList/ProjectList.tsx
+++ b/frontend/src/component/project/ProjectList/ProjectList.tsx
@@ -14,7 +14,7 @@ import PageContent from '../../common/PageContent';
import AccessContext from '../../../contexts/AccessContext';
import HeaderTitle from '../../common/HeaderTitle';
import ResponsiveButton from '../../common/ResponsiveButton/ResponsiveButton';
-import { CREATE_PROJECT } from '../../AccessProvider/permissions';
+import { CREATE_PROJECT } from '../../providers/AccessProvider/permissions';
import { Add } from '@material-ui/icons';
import ApiError from '../../common/ApiError/ApiError';
@@ -26,21 +26,21 @@ type projectMap = {
};
function resolveCreateButtonData(isOss: boolean, hasAccess: boolean) {
- if(isOss) {
+ if (isOss) {
return {
title: 'You must be on a paid subscription to create new projects',
- disabled: true
- }
+ disabled: true,
+ };
} else if (!hasAccess) {
return {
- title: 'You do not have permissions create new projects',
- disabled: true
- }
+ title: 'You do not have permission to create new projects',
+ disabled: true,
+ };
} else {
return {
title: 'Click to create a new project',
- disabled: false
- }
+ disabled: false,
+ };
}
}
@@ -64,7 +64,10 @@ const ProjectListNew = () => {
setFetchedProjects(prev => ({ ...prev, [projectId]: true }));
};
- const createButtonData = resolveCreateButtonData(isOss(), hasAccess(CREATE_PROJECT));
+ const createButtonData = resolveCreateButtonData(
+ isOss(),
+ hasAccess(CREATE_PROJECT)
+ );
const renderError = () => {
return (
diff --git a/frontend/src/component/project/form-project-component.tsx b/frontend/src/component/project/form-project-component.tsx
index 4909e92136..00c4919042 100644
--- a/frontend/src/component/project/form-project-component.tsx
+++ b/frontend/src/component/project/form-project-component.tsx
@@ -9,7 +9,7 @@ import { trim } from '../common/util';
import PageContent from '../common/PageContent/PageContent';
import AccessContext from '../../contexts/AccessContext';
import ConditionallyRender from '../common/ConditionallyRender';
-import { CREATE_PROJECT } from '../AccessProvider/permissions';
+import { CREATE_PROJECT } from '../providers/AccessProvider/permissions';
import HeaderTitle from '../common/HeaderTitle';
import useUiConfig from '../../hooks/api/getters/useUiConfig/useUiConfig';
import { Alert } from '@material-ui/lab';
@@ -28,29 +28,28 @@ const ProjectFormComponent = (props: ProjectFormComponentProps) => {
const { editMode } = props;
const { hasAccess } = useContext(AccessContext);
- const [project, setProject ] = useState(props.project || {});
- const [errors, setErrors ] = useState({});
+ const [project, setProject] = useState(props.project || {});
+ const [errors, setErrors] = useState({});
const { isOss, loading } = useUiConfig();
const ref = useLoading(loading);
-
useEffect(() => {
- if(!project.id && props.project.id) {
+ if (!project.id && props.project.id) {
setProject(props.project);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.project]);
const setValue = (field: string, value: string) => {
- const p = {...project}
+ const p = { ...project };
p[field] = value;
- setProject(p)
+ setProject(p);
};
const validateId = async (id: string) => {
if (editMode) return true;
- const e = {...errors};
+ const e = { ...errors };
try {
await props.validateId(id);
e.id = undefined;
@@ -58,14 +57,14 @@ const ProjectFormComponent = (props: ProjectFormComponentProps) => {
e.id = err.message;
}
- setErrors(e)
+ setErrors(e);
if (e.id) return false;
return true;
};
const validateName = () => {
if (project.name.length === 0) {
- setErrors({...errors, name: 'Name can not be empty.' })
+ setErrors({ ...errors, name: 'Name can not be empty.' });
return false;
}
return true;
@@ -111,91 +110,103 @@ const ProjectFormComponent = (props: ProjectFormComponentProps) => {
/>
}
>
-
-
- {submitText} project requires a paid version of Unleash.
- Check out getunleash.io {' '}
- to learn more.
-
- } elseShow={
- <>
-
- Projects allows you to group feature toggles together in the
- management UI.
-
-
+ >
+ }
+ />
);
-}
+};
ProjectFormComponent.propTypes = {
project: PropTypes.object.isRequired,
diff --git a/frontend/src/component/AccessProvider/AccessProvider.tsx b/frontend/src/component/providers/AccessProvider/AccessProvider.tsx
similarity index 96%
rename from frontend/src/component/AccessProvider/AccessProvider.tsx
rename to frontend/src/component/providers/AccessProvider/AccessProvider.tsx
index 31d2c9f3c3..94978d5a0a 100644
--- a/frontend/src/component/AccessProvider/AccessProvider.tsx
+++ b/frontend/src/component/providers/AccessProvider/AccessProvider.tsx
@@ -1,6 +1,6 @@
import { FC } from 'react';
-import AccessContext from '../../contexts/AccessContext';
+import AccessContext from '../../../contexts/AccessContext';
import { ADMIN } from './permissions';
// TODO: Type up redux store
diff --git a/frontend/src/component/AccessProvider/permissions.ts b/frontend/src/component/providers/AccessProvider/permissions.ts
similarity index 100%
rename from frontend/src/component/AccessProvider/permissions.ts
rename to frontend/src/component/providers/AccessProvider/permissions.ts
diff --git a/frontend/src/component/providers/SWRProvider/SWRProvider.tsx b/frontend/src/component/providers/SWRProvider/SWRProvider.tsx
new file mode 100644
index 0000000000..31d87304f1
--- /dev/null
+++ b/frontend/src/component/providers/SWRProvider/SWRProvider.tsx
@@ -0,0 +1,67 @@
+import { USER_CACHE_KEY } from '../../../hooks/api/getters/useUser/useUser';
+import { mutate, SWRConfig, useSWRConfig } from 'swr';
+import { useHistory } from 'react-router';
+import { IToast } from '../../../hooks/useToast';
+
+interface ISWRProviderProps {
+ setToastData: (toastData: IToast) => void;
+ isUnauthorized: () => boolean;
+}
+
+const SWRProvider: React.FC = ({
+ children,
+ setToastData,
+ isUnauthorized,
+}) => {
+ const { cache } = useSWRConfig();
+ const history = useHistory();
+
+ const handleFetchError = error => {
+ if (error.status === 401) {
+ cache.clear();
+ const path = location.pathname;
+
+ mutate(USER_CACHE_KEY, { ...error.info }, false);
+ if (path === '/login') {
+ return;
+ }
+
+ history.push('/login');
+ return;
+ }
+
+ if (!isUnauthorized()) {
+ setToastData({
+ show: true,
+ type: 'error',
+ text: error.message,
+ });
+ }
+ };
+
+ return (
+ {
+ // Never retry on 404 or 401.
+ if (error.status < 499) {
+ return error;
+ }
+
+ setTimeout(() => revalidate({ retryCount }), 5000);
+ },
+ onError: handleFetchError,
+ }}
+ >
+ {children}
+
+ );
+};
+
+export default SWRProvider;
diff --git a/frontend/src/component/strategies/StrategiesList/StrategiesList.jsx b/frontend/src/component/strategies/StrategiesList/StrategiesList.jsx
index ca035ea138..30dcd3ac77 100644
--- a/frontend/src/component/strategies/StrategiesList/StrategiesList.jsx
+++ b/frontend/src/component/strategies/StrategiesList/StrategiesList.jsx
@@ -24,7 +24,7 @@ import {
import {
CREATE_STRATEGY,
DELETE_STRATEGY,
-} from '../../AccessProvider/permissions';
+} from '../../providers/AccessProvider/permissions';
import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender';
import PageContent from '../../common/PageContent/PageContent';
diff --git a/frontend/src/component/strategies/__tests__/list-component-test.jsx b/frontend/src/component/strategies/__tests__/list-component-test.jsx
index 02872e8ff1..bc9abb9a02 100644
--- a/frontend/src/component/strategies/__tests__/list-component-test.jsx
+++ b/frontend/src/component/strategies/__tests__/list-component-test.jsx
@@ -5,9 +5,9 @@ import { ThemeProvider } from '@material-ui/core';
import StrategiesListComponent from '../StrategiesList/StrategiesList';
import renderer from 'react-test-renderer';
import theme from '../../../themes/main-theme';
-import AccessProvider from '../../AccessProvider/AccessProvider';
+import AccessProvider from '../../providers/AccessProvider/AccessProvider';
import { createFakeStore } from '../../../accessStoreFake';
-import { ADMIN } from '../../AccessProvider/permissions';
+import { ADMIN } from '../../providers/AccessProvider/permissions';
test('renders correctly with one strategy', () => {
const strategy = {
diff --git a/frontend/src/component/strategies/__tests__/strategy-details-component-test.jsx b/frontend/src/component/strategies/__tests__/strategy-details-component-test.jsx
index 9e560ace50..f63c0c6c78 100644
--- a/frontend/src/component/strategies/__tests__/strategy-details-component-test.jsx
+++ b/frontend/src/component/strategies/__tests__/strategy-details-component-test.jsx
@@ -5,7 +5,7 @@ import renderer from 'react-test-renderer';
import { MemoryRouter } from 'react-router-dom';
import theme from '../../../themes/main-theme';
import { createFakeStore } from '../../../accessStoreFake';
-import AccessProvider from '../../AccessProvider/AccessProvider';
+import AccessProvider from '../../providers/AccessProvider/AccessProvider';
test('renders correctly with one strategy', () => {
const strategy = {
diff --git a/frontend/src/component/strategies/strategy-details-component.jsx b/frontend/src/component/strategies/strategy-details-component.jsx
index 58b55ef6eb..df23ced4df 100644
--- a/frontend/src/component/strategies/strategy-details-component.jsx
+++ b/frontend/src/component/strategies/strategy-details-component.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Grid, Typography } from '@material-ui/core';
import ShowStrategy from './show-strategy-component';
import EditStrategy from './CreateStrategy';
-import { UPDATE_STRATEGY } from '../AccessProvider/permissions';
+import { UPDATE_STRATEGY } from '../providers/AccessProvider/permissions';
import ConditionallyRender from '../common/ConditionallyRender/ConditionallyRender';
import TabNav from '../common/TabNav/TabNav';
import PageContent from '../common/PageContent/PageContent';
diff --git a/frontend/src/component/tag-types/TagTypeList/TagTypeList.jsx b/frontend/src/component/tag-types/TagTypeList/TagTypeList.jsx
index 2a0c00a099..46a984ee9e 100644
--- a/frontend/src/component/tag-types/TagTypeList/TagTypeList.jsx
+++ b/frontend/src/component/tag-types/TagTypeList/TagTypeList.jsx
@@ -19,7 +19,7 @@ import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyR
import {
CREATE_TAG_TYPE,
DELETE_TAG_TYPE,
-} from '../../AccessProvider/permissions';
+} from '../../providers/AccessProvider/permissions';
import Dialogue from '../../common/Dialogue/Dialogue';
import useMediaQuery from '@material-ui/core/useMediaQuery';
diff --git a/frontend/src/component/tag-types/__tests__/tag-type-create-component-test.js b/frontend/src/component/tag-types/__tests__/tag-type-create-component-test.js
index 0e1bd7250d..f43bb99bde 100644
--- a/frontend/src/component/tag-types/__tests__/tag-type-create-component-test.js
+++ b/frontend/src/component/tag-types/__tests__/tag-type-create-component-test.js
@@ -3,12 +3,12 @@ import { ThemeProvider } from '@material-ui/core';
import TagTypes from '../form-tag-type-component';
import renderer from 'react-test-renderer';
import theme from '../../../themes/main-theme';
-import AccessProvider from '../../AccessProvider/AccessProvider';
+import AccessProvider from '../../providers/AccessProvider/AccessProvider';
import { createFakeStore } from '../../../accessStoreFake';
import {
CREATE_TAG_TYPE,
UPDATE_TAG_TYPE,
-} from '../../AccessProvider/permissions';
+} from '../../providers/AccessProvider/permissions';
jest.mock('@material-ui/core/TextField');
diff --git a/frontend/src/component/tag-types/__tests__/tag-type-list-component-test.js b/frontend/src/component/tag-types/__tests__/tag-type-list-component-test.js
index ebdedf1750..49174f12f9 100644
--- a/frontend/src/component/tag-types/__tests__/tag-type-list-component-test.js
+++ b/frontend/src/component/tag-types/__tests__/tag-type-list-component-test.js
@@ -6,14 +6,14 @@ import { MemoryRouter } from 'react-router-dom';
import { ThemeProvider } from '@material-ui/styles';
import theme from '../../../themes/main-theme';
import { createFakeStore } from '../../../accessStoreFake';
-import AccessProvider from '../../AccessProvider/AccessProvider';
+import AccessProvider from '../../providers/AccessProvider/AccessProvider';
import {
ADMIN,
CREATE_TAG_TYPE,
UPDATE_TAG_TYPE,
DELETE_TAG_TYPE,
-} from '../../AccessProvider/permissions';
+} from '../../providers/AccessProvider/permissions';
test('renders an empty list correctly', () => {
const tree = renderer.create(
diff --git a/frontend/src/component/tag-types/form-tag-type-component.js b/frontend/src/component/tag-types/form-tag-type-component.js
index 6caab8c50d..e0e80c38c6 100644
--- a/frontend/src/component/tag-types/form-tag-type-component.js
+++ b/frontend/src/component/tag-types/form-tag-type-component.js
@@ -12,7 +12,7 @@ import AccessContext from '../../contexts/AccessContext';
import {
CREATE_TAG_TYPE,
UPDATE_TAG_TYPE,
-} from '../AccessProvider/permissions';
+} from '../providers/AccessProvider/permissions';
import ConditionallyRender from '../common/ConditionallyRender';
const AddTagTypeComponent = ({
diff --git a/frontend/src/component/tags/TagList/TagList.jsx b/frontend/src/component/tags/TagList/TagList.jsx
index 442b9bce17..0369048b4c 100644
--- a/frontend/src/component/tags/TagList/TagList.jsx
+++ b/frontend/src/component/tags/TagList/TagList.jsx
@@ -14,7 +14,10 @@ import {
} from '@material-ui/core';
import { Add, Label, Delete } from '@material-ui/icons';
-import { CREATE_TAG, DELETE_TAG } from '../../AccessProvider/permissions';
+import {
+ CREATE_TAG,
+ DELETE_TAG,
+} from '../../providers/AccessProvider/permissions';
import ConditionallyRender from '../../common/ConditionallyRender/ConditionallyRender';
import HeaderTitle from '../../common/HeaderTitle';
import PageContent from '../../common/PageContent/PageContent';
diff --git a/frontend/src/component/user/Authentication/Authentication.tsx b/frontend/src/component/user/Authentication/Authentication.tsx
new file mode 100644
index 0000000000..a48dc932b5
--- /dev/null
+++ b/frontend/src/component/user/Authentication/Authentication.tsx
@@ -0,0 +1,102 @@
+import SimpleAuth from '../SimpleAuth/SimpleAuth';
+import AuthenticationCustomComponent from '../authentication-custom-component';
+import PasswordAuth from '../PasswordAuth/PasswordAuth';
+import HostedAuth from '../HostedAuth/HostedAuth';
+import DemoAuth from '../DemoAuth';
+
+import {
+ SIMPLE_TYPE,
+ DEMO_TYPE,
+ PASSWORD_TYPE,
+ HOSTED_TYPE,
+} from '../../../constants/authTypes';
+import SecondaryLoginActions from '../common/SecondaryLoginActions/SecondaryLoginActions';
+import useUser from '../../../hooks/api/getters/useUser/useUser';
+import { IUser } from '../../../interfaces/user';
+import { useHistory } from 'react-router';
+import useQueryParams from '../../../hooks/useQueryParams';
+import ConditionallyRender from '../../common/ConditionallyRender';
+import { Alert } from '@material-ui/lab';
+
+interface IAuthenticationProps {
+ insecureLogin: (path: string, user: IUser) => void;
+ passwordLogin: (path: string, user: IUser) => void;
+ demoLogin: (path: string, user: IUser) => void;
+ history: any;
+}
+
+const Authentication = ({
+ insecureLogin,
+ passwordLogin,
+ demoLogin,
+}: IAuthenticationProps) => {
+ const { authDetails } = useUser();
+ const history = useHistory();
+ const params = useQueryParams();
+
+ const error = params.get('errorMsg');
+
+ if (!authDetails) return null;
+
+ let content;
+ if (authDetails.type === PASSWORD_TYPE) {
+ content = (
+ <>
+
+ }
+ />
+ >
+ );
+ } else if (authDetails.type === SIMPLE_TYPE) {
+ content = (
+
+ );
+ } else if (authDetails.type === DEMO_TYPE) {
+ content = (
+
+ );
+ } else if (authDetails.type === HOSTED_TYPE) {
+ content = (
+ <>
+
+ }
+ />
+ >
+ );
+ } else {
+ content = ;
+ }
+ return (
+ <>
+
+ {error}}
+ />
+
+ {content}
+ >
+ );
+};
+
+export default Authentication;
diff --git a/frontend/src/component/user/authentication-container.jsx b/frontend/src/component/user/Authentication/index.js
similarity index 54%
rename from frontend/src/component/user/authentication-container.jsx
rename to frontend/src/component/user/Authentication/index.js
index 8a5556dc8b..ad12103f8b 100644
--- a/frontend/src/component/user/authentication-container.jsx
+++ b/frontend/src/component/user/Authentication/index.js
@@ -1,10 +1,10 @@
import { connect } from 'react-redux';
-import AuthenticationComponent from './authentication-component';
+import AuthenticationComponent from './Authentication';
import {
insecureLogin,
passwordLogin,
demoLogin,
-} from '../../store/user/actions';
+} from '../../../store/user/actions';
const mapDispatchToProps = (dispatch, props) => ({
demoLogin: (path, user) => demoLogin(path, user)(dispatch),
@@ -12,12 +12,4 @@ const mapDispatchToProps = (dispatch, props) => ({
passwordLogin: (path, user) => passwordLogin(path, user)(dispatch),
});
-const mapStateToProps = state => ({
- user: state.user.toJS(),
- flags: state.uiConfig.toJS().flags,
-});
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps
-)(AuthenticationComponent);
+export default connect(null, mapDispatchToProps)(AuthenticationComponent);
diff --git a/frontend/src/component/user/HostedAuth/HostedAuth.jsx b/frontend/src/component/user/HostedAuth/HostedAuth.jsx
index cdd6b7996b..4289d69e3a 100644
--- a/frontend/src/component/user/HostedAuth/HostedAuth.jsx
+++ b/frontend/src/component/user/HostedAuth/HostedAuth.jsx
@@ -79,50 +79,58 @@ const HostedAuth = ({ authDetails, passwordLogin }) => {
}
/>
-
-
- {apiError}
-
-
- setUsername(evt.target.value)}
- value={username}
- error={!!usernameError}
- helperText={usernameError}
- variant="outlined"
- size="small"
- />
- setPassword(evt.target.value)}
- name="password"
- type="password"
- value={password}
- error={!!passwordError}
- helperText={passwordError}
- variant="outlined"
- size="small"
- />
-
-
+
- Sign in
-
-
-
-
+ {apiError}
+
+
+ setUsername(evt.target.value)}
+ value={username}
+ error={!!usernameError}
+ helperText={usernameError}
+ variant="outlined"
+ size="small"
+ />
+ setPassword(evt.target.value)}
+ name="password"
+ type="password"
+ value={password}
+ error={!!passwordError}
+ helperText={passwordError}
+ variant="outlined"
+ size="small"
+ />
+
+
+ Sign in
+
+
+
+
+ }
+ />
>
);
};
diff --git a/frontend/src/component/user/Login/Login.jsx b/frontend/src/component/user/Login/Login.tsx
similarity index 76%
rename from frontend/src/component/user/Login/Login.jsx
rename to frontend/src/component/user/Login/Login.tsx
index e1966aae12..29fd52f91f 100644
--- a/frontend/src/component/user/Login/Login.jsx
+++ b/frontend/src/component/user/Login/Login.tsx
@@ -1,6 +1,6 @@
import { useEffect } from 'react';
-import AuthenticationContainer from '../authentication-container';
+import AuthenticationContainer from '../Authentication';
import ConditionallyRender from '../../common/ConditionallyRender';
import { useStyles } from './Login.styles';
@@ -8,22 +8,21 @@ import useQueryParams from '../../../hooks/useQueryParams';
import ResetPasswordSuccess from '../common/ResetPasswordSuccess/ResetPasswordSuccess';
import StandaloneLayout from '../common/StandaloneLayout/StandaloneLayout';
import { DEMO_TYPE } from '../../../constants/authTypes';
+import useUser from '../../../hooks/api/getters/useUser/useUser';
+import { useHistory } from 'react-router';
-const Login = ({ history, user, fetchUser }) => {
+const Login = () => {
const styles = useStyles();
+ const { permissions, authDetails } = useUser();
const query = useQueryParams();
+ const history = useHistory();
useEffect(() => {
- fetchUser();
- /* eslint-disable-next-line */
- }, []);
-
- useEffect(() => {
- if (user.permissions.length > 0) {
+ if (permissions?.length > 0) {
history.push('features');
}
/* eslint-disable-next-line */
- }, [user.permissions]);
+ }, [permissions.length]);
const resetPassword = query.get('reset') === 'true';
@@ -31,7 +30,7 @@ const Login = ({ history, user, fetchUser }) => {
Login to continue the great work
diff --git a/frontend/src/component/user/Login/index.js b/frontend/src/component/user/Login/index.js
deleted file mode 100644
index 149911f048..0000000000
--- a/frontend/src/component/user/Login/index.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import { connect } from 'react-redux';
-import { fetchUser } from '../../../store/user/actions';
-import Login from './Login';
-
-const mapStateToProps = state => ({
- user: state.user.toJS(),
- flags: state.uiConfig.toJS().flags,
-});
-
-const mapDispatchToProps = {
- fetchUser,
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(Login);
diff --git a/frontend/src/component/user/PasswordAuth/PasswordAuth.jsx b/frontend/src/component/user/PasswordAuth/PasswordAuth.jsx
index d79ef045fc..c9f0432439 100644
--- a/frontend/src/component/user/PasswordAuth/PasswordAuth.jsx
+++ b/frontend/src/component/user/PasswordAuth/PasswordAuth.jsx
@@ -79,59 +79,67 @@ const PasswordAuth = ({ authDetails, passwordLogin }) => {
const { usernameError, passwordError, apiError } = errors;
return (
-
-
- {apiError}
-
- }
- />
+
+
+ {apiError}
+
+ }
+ />
-
- setUsername(evt.target.value)}
- value={username}
- error={!!usernameError}
- helperText={usernameError}
- variant="outlined"
- autoComplete="true"
- size="small"
- data-test={LOGIN_EMAIL_ID}
- />
- setPassword(evt.target.value)}
- name="password"
- type="password"
- value={password}
- error={!!passwordError}
- helperText={passwordError}
- variant="outlined"
- autoComplete="true"
- size="small"
- data-test={LOGIN_PASSWORD_ID}
- />
-
- Sign in
-
-
-
+
+ setUsername(evt.target.value)}
+ value={username}
+ error={!!usernameError}
+ helperText={usernameError}
+ variant="outlined"
+ autoComplete="true"
+ size="small"
+ data-test={LOGIN_EMAIL_ID}
+ />
+ setPassword(evt.target.value)}
+ name="password"
+ type="password"
+ value={password}
+ error={!!passwordError}
+ helperText={passwordError}
+ variant="outlined"
+ autoComplete="true"
+ size="small"
+ data-test={LOGIN_PASSWORD_ID}
+ />
+
+ Sign in
+
+
+
+ }
+ />
);
};
diff --git a/frontend/src/component/user/authentication-component.jsx b/frontend/src/component/user/authentication-component.jsx
deleted file mode 100644
index 37d7c86041..0000000000
--- a/frontend/src/component/user/authentication-component.jsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import SimpleAuth from './SimpleAuth/SimpleAuth';
-import AuthenticationCustomComponent from './authentication-custom-component';
-import PasswordAuth from './PasswordAuth/PasswordAuth';
-import HostedAuth from './HostedAuth/HostedAuth';
-import DemoAuth from './DemoAuth';
-
-import {
- SIMPLE_TYPE,
- DEMO_TYPE,
- PASSWORD_TYPE,
- HOSTED_TYPE,
-} from '../../constants/authTypes';
-import SecondaryLoginActions from './common/SecondaryLoginActions/SecondaryLoginActions';
-
-class AuthComponent extends React.Component {
- static propTypes = {
- user: PropTypes.object.isRequired,
- demoLogin: PropTypes.func.isRequired,
- insecureLogin: PropTypes.func.isRequired,
- passwordLogin: PropTypes.func.isRequired,
- history: PropTypes.object.isRequired,
- };
-
- render() {
- const authDetails = this.props.user.authDetails;
-
- if (!authDetails) return null;
-
- let content;
- if (authDetails.type === PASSWORD_TYPE) {
- content = (
- <>
-
-
- >
- );
- } else if (authDetails.type === SIMPLE_TYPE) {
- content = (
-
- );
- } else if (authDetails.type === DEMO_TYPE) {
- content = (
-
- );
- } else if (authDetails.type === HOSTED_TYPE) {
- content = (
- <>
-
-
- >
- );
- } else {
- content = (
-
- );
- }
- return <>{content}>;
- }
-}
-
-export default AuthComponent;
diff --git a/frontend/src/hooks/api/getters/httpErrorResponseHandler.ts b/frontend/src/hooks/api/getters/httpErrorResponseHandler.ts
index 4222588146..5d5a86f8fe 100644
--- a/frontend/src/hooks/api/getters/httpErrorResponseHandler.ts
+++ b/frontend/src/hooks/api/getters/httpErrorResponseHandler.ts
@@ -1,6 +1,8 @@
const handleErrorResponses = (target: string) => async (res: Response) => {
if (!res.ok) {
- const error = new Error(`An error occurred while trying to get ${target}`);
+ const error = new Error(
+ `An error occurred while trying to get ${target}`
+ );
// Try to resolve body, but don't rethrow res.json is not a function
try {
// @ts-ignore
@@ -16,6 +18,6 @@ const handleErrorResponses = (target: string) => async (res: Response) => {
throw error;
}
return res;
-}
+};
export default handleErrorResponses;
diff --git a/frontend/src/hooks/api/getters/useUser/useUser.ts b/frontend/src/hooks/api/getters/useUser/useUser.ts
index 69e855ca18..d6178a5fec 100644
--- a/frontend/src/hooks/api/getters/useUser/useUser.ts
+++ b/frontend/src/hooks/api/getters/useUser/useUser.ts
@@ -4,20 +4,23 @@ import { formatApiPath } from '../../../../utils/format-path';
import { IPermission } from '../../../../interfaces/user';
import handleErrorResponses from '../httpErrorResponseHandler';
+export const USER_CACHE_KEY = `api/admin/user`;
+
const useUser = () => {
- const KEY = `api/admin/user`;
const fetcher = () => {
const path = formatApiPath(`api/admin/user`);
return fetch(path, {
method: 'GET',
- }).then(handleErrorResponses('User info')).then(res => res.json());
+ })
+ .then(handleErrorResponses('User info'))
+ .then(res => res.json());
};
- const { data, error } = useSWR(KEY, fetcher);
+ const { data, error } = useSWR(USER_CACHE_KEY, fetcher);
const [loading, setLoading] = useState(!error && !data);
const refetch = () => {
- mutate(KEY);
+ mutate(USER_CACHE_KEY);
};
useEffect(() => {
@@ -28,6 +31,7 @@ const useUser = () => {
user: data?.user || {},
permissions: (data?.permissions || []) as IPermission[],
feedback: data?.feedback || [],
+ authDetails: data || {},
error,
loading,
refetch,
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx
index eceea903ea..462b9f0e01 100644
--- a/frontend/src/index.tsx
+++ b/frontend/src/index.tsx
@@ -15,11 +15,10 @@ import { StylesProvider } from '@material-ui/core/styles';
import mainTheme from './themes/main-theme';
import store from './store';
-import MetricsPoller from './metrics-poller';
import App from './component/AppContainer';
import ScrollToTop from './component/scroll-to-top';
import { writeWarning } from './security-logger';
-import AccessProvider from './component/AccessProvider/AccessProvider';
+import AccessProvider from './component/providers/AccessProvider/AccessProvider';
import { getBasePath } from './utils/format-path';
let composeEnhancers;
@@ -38,8 +37,6 @@ const unleashStore = createStore(
store,
composeEnhancers(applyMiddleware(thunkMiddleware))
);
-const metricsPoller = new MetricsPoller(unleashStore);
-metricsPoller.start();
ReactDOM.render(
diff --git a/frontend/src/metrics-poller.js b/frontend/src/metrics-poller.js
deleted file mode 100644
index 940e6b4c73..0000000000
--- a/frontend/src/metrics-poller.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { fetchFeatureMetrics } from './store/feature-metrics/actions';
-
-class MetricsPoller {
- constructor(store) {
- this.store = store;
- this.timer = undefined;
- }
-
- start() {
- this.store.subscribe(() => {
- const features = this.store.getState().features;
- if (!this.timer && features.size > 0) {
- this.timer = setInterval(this.fetchMetrics.bind(this), 5000);
- this.fetchMetrics();
- }
- });
- }
-
- fetchMetrics() {
- this.store.dispatch(fetchFeatureMetrics());
- }
-
- destroy() {
- if (this.timer) {
- clearTimeout(this.timer);
- this.timer = undefined;
- }
- }
-}
-
-export default MetricsPoller;
diff --git a/frontend/src/page/admin/auth/google-auth.jsx b/frontend/src/page/admin/auth/google-auth.jsx
index 73a824ea75..cec55b9145 100644
--- a/frontend/src/page/admin/auth/google-auth.jsx
+++ b/frontend/src/page/admin/auth/google-auth.jsx
@@ -1,10 +1,16 @@
import React, { useState, useEffect, useContext } from 'react';
import PropTypes from 'prop-types';
-import { Button, FormControlLabel, Grid, Switch, TextField } from '@material-ui/core';
+import {
+ Button,
+ FormControlLabel,
+ Grid,
+ Switch,
+ TextField,
+} from '@material-ui/core';
import { Alert } from '@material-ui/lab';
import PageContent from '../../../component/common/PageContent/PageContent';
import AccessContext from '../../../contexts/AccessContext';
-import { ADMIN } from '../../../component/AccessProvider/permissions';
+import { ADMIN } from '../../../component/providers/AccessProvider/permissions';
const initialState = {
enabled: false,
@@ -93,12 +99,14 @@ function GoogleAuth({
}
+ control={
+
+ }
label={data.enabled ? 'Enabled' : 'Disabled'}
/>
diff --git a/frontend/src/page/admin/auth/oidc-auth.jsx b/frontend/src/page/admin/auth/oidc-auth.jsx
index b0e2a92e8c..dafd4a9207 100644
--- a/frontend/src/page/admin/auth/oidc-auth.jsx
+++ b/frontend/src/page/admin/auth/oidc-auth.jsx
@@ -1,10 +1,16 @@
import React, { useState, useEffect, useContext } from 'react';
import PropTypes from 'prop-types';
-import { Button, FormControlLabel, Grid, Switch, TextField } from '@material-ui/core';
+import {
+ Button,
+ FormControlLabel,
+ Grid,
+ Switch,
+ TextField,
+} from '@material-ui/core';
import { Alert } from '@material-ui/lab';
import PageContent from '../../../component/common/PageContent/PageContent';
import AccessContext from '../../../contexts/AccessContext';
-import { ADMIN } from '../../../component/AccessProvider/permissions';
+import { ADMIN } from '../../../component/providers/AccessProvider/permissions';
import AutoCreateForm from './AutoCreateForm/AutoCreateForm';
const initialState = {
@@ -57,7 +63,7 @@ function OidcAuth({ config, getOidcConfig, updateOidcConfig, unleashUrl }) {
...data,
[field]: value,
});
- }
+ };
const onSubmit = async e => {
e.preventDefault();
@@ -100,12 +106,14 @@ function OidcAuth({ config, getOidcConfig, updateOidcConfig, unleashUrl }) {
}
+ control={
+
+ }
label={data.enabled ? 'Enabled' : 'Disabled'}
/>
@@ -125,7 +133,6 @@ function OidcAuth({ config, getOidcConfig, updateOidcConfig, unleashUrl }) {
style={{ width: '400px' }}
variant="outlined"
size="small"
-
/>
@@ -151,7 +158,9 @@ function OidcAuth({ config, getOidcConfig, updateOidcConfig, unleashUrl }) {
Client secret
- (Required) Client secret of your OpenID application.
+
+ (Required) Client secret of your OpenID application.{' '}
+
(Optional) Enable Single Sign-Out
- If you enable Single Sign-Out Unleash will redirect the user to the IDP as part of the Sign-out process.
+
+ If you enable Single Sign-Out Unleash will redirect
+ the user to the IDP as part of the Sign-out process.
+
}
- label={data.enableSingleSignOut ? 'Enabled' : 'Disabled'}
+ control={
+
+ }
+ label={
+ data.enableSingleSignOut
+ ? 'Enabled'
+ : 'Disabled'
+ }
/>
@@ -199,7 +217,7 @@ function OidcAuth({ config, getOidcConfig, updateOidcConfig, unleashUrl }) {
Save
{' '}
{info}
- {error}
+ {error}
diff --git a/frontend/src/page/admin/auth/saml-auth.jsx b/frontend/src/page/admin/auth/saml-auth.jsx
index 10dd50c467..d0d703cb79 100644
--- a/frontend/src/page/admin/auth/saml-auth.jsx
+++ b/frontend/src/page/admin/auth/saml-auth.jsx
@@ -1,10 +1,16 @@
import React, { useState, useEffect, useContext } from 'react';
import PropTypes from 'prop-types';
-import { Button, FormControlLabel, Grid, Switch, TextField } from '@material-ui/core';
+import {
+ Button,
+ FormControlLabel,
+ Grid,
+ Switch,
+ TextField,
+} from '@material-ui/core';
import { Alert } from '@material-ui/lab';
import PageContent from '../../../component/common/PageContent/PageContent';
import AccessContext from '../../../contexts/AccessContext';
-import { ADMIN } from '../../../component/AccessProvider/permissions';
+import { ADMIN } from '../../../component/providers/AccessProvider/permissions';
import AutoCreateForm from './AutoCreateForm/AutoCreateForm';
const initialState = {
@@ -51,7 +57,7 @@ function SamlAuth({ config, getSamlConfig, updateSamlConfig, unleashUrl }) {
...data,
[field]: value,
});
- }
+ };
const onSubmit = async e => {
e.preventDefault();
@@ -92,12 +98,14 @@ function SamlAuth({ config, getSamlConfig, updateSamlConfig, unleashUrl }) {
}
+ control={
+
+ }
label={data.enabled ? 'Enabled' : 'Disabled'}
/>
@@ -136,7 +144,7 @@ function SamlAuth({ config, getSamlConfig, updateSamlConfig, unleashUrl }) {
name="signOnUrl"
value={data.signOnUrl || ''}
disabled={!data.enabled}
- style={{ width: '400px'}}
+ style={{ width: '400px' }}
variant="outlined"
size="small"
required
@@ -158,12 +166,13 @@ function SamlAuth({ config, getSamlConfig, updateSamlConfig, unleashUrl }) {
name="certificate"
value={data.certificate || ''}
disabled={!data.enabled}
- style={{width: '100%'}}
+ style={{ width: '100%' }}
InputProps={{
style: {
fontSize: '0.6em',
fontFamily: 'monospace',
- }}}
+ },
+ }}
multiline
rows={14}
rowsMax={14}
@@ -189,7 +198,7 @@ function SamlAuth({ config, getSamlConfig, updateSamlConfig, unleashUrl }) {
name="signOutUrl"
value={data.signOutUrl || ''}
disabled={!data.enabled}
- style={{ width: '400px'}}
+ style={{ width: '400px' }}
variant="outlined"
size="small"
/>
@@ -199,8 +208,10 @@ function SamlAuth({ config, getSamlConfig, updateSamlConfig, unleashUrl }) {
Service Provider X.509 Certificate
- (Optional) The private certificate used by the Service Provider used to sign the SAML 2.0
- request towards the IDP. E.g. used to sign single logout requests (SLO).
+ (Optional) The private certificate used by the
+ Service Provider used to sign the SAML 2.0 request
+ towards the IDP. E.g. used to sign single logout
+ requests (SLO).
@@ -210,12 +221,13 @@ function SamlAuth({ config, getSamlConfig, updateSamlConfig, unleashUrl }) {
name="spCertificate"
value={data.spCertificate || ''}
disabled={!data.enabled}
- style={{width: '100%'}}
+ style={{ width: '100%' }}
InputProps={{
style: {
fontSize: '0.6em',
fontFamily: 'monospace',
- }}}
+ },
+ }}
multiline
rows={14}
rowsMax={14}
diff --git a/frontend/src/page/admin/invoice/index.js b/frontend/src/page/admin/invoice/index.js
index c6e79ad81d..43ea093daf 100644
--- a/frontend/src/page/admin/invoice/index.js
+++ b/frontend/src/page/admin/invoice/index.js
@@ -2,7 +2,7 @@ import { useContext } from 'react';
import PropTypes from 'prop-types';
import InvoiceList from './invoice-container';
import AccessContext from '../../../contexts/AccessContext';
-import { ADMIN } from '../../../component/AccessProvider/permissions';
+import { ADMIN } from '../../../component/providers/AccessProvider/permissions';
import ConditionallyRender from '../../../component/common/ConditionallyRender';
import { Alert } from '@material-ui/lab';
@@ -13,17 +13,13 @@ const InvoiceAdminPage = ({ history }) => {
- }
+ show={
}
elseShow={
You need to be instance admin to access this section.
}
-
/>
-
);
};
diff --git a/frontend/src/page/admin/users/UsersList/UserListItem/UserListItem.tsx b/frontend/src/page/admin/users/UsersList/UserListItem/UserListItem.tsx
index cf791b93fe..db130f87e9 100644
--- a/frontend/src/page/admin/users/UsersList/UserListItem/UserListItem.tsx
+++ b/frontend/src/page/admin/users/UsersList/UserListItem/UserListItem.tsx
@@ -7,7 +7,7 @@ import {
} from '@material-ui/core';
import { Edit, Lock, Delete } from '@material-ui/icons';
import { SyntheticEvent, useContext } from 'react';
-import { ADMIN } from '../../../../../component/AccessProvider/permissions';
+import { ADMIN } from '../../../../../component/providers/AccessProvider/permissions';
import ConditionallyRender from '../../../../../component/common/ConditionallyRender';
import { formatDateWithLocale } from '../../../../../component/common/util';
import AccessContext from '../../../../../contexts/AccessContext';
diff --git a/frontend/src/page/admin/users/UsersList/UsersList.jsx b/frontend/src/page/admin/users/UsersList/UsersList.jsx
index 980135434b..e85a23c786 100644
--- a/frontend/src/page/admin/users/UsersList/UsersList.jsx
+++ b/frontend/src/page/admin/users/UsersList/UsersList.jsx
@@ -14,7 +14,7 @@ import UpdateUser from '../update-user-component';
import DelUser from '../del-user-component';
import ConditionallyRender from '../../../../component/common/ConditionallyRender/ConditionallyRender';
import AccessContext from '../../../../contexts/AccessContext';
-import { ADMIN } from '../../../../component/AccessProvider/permissions';
+import { ADMIN } from '../../../../component/providers/AccessProvider/permissions';
import ConfirmUserAdded from '../ConfirmUserAdded/ConfirmUserAdded';
import useUsers from '../../../../hooks/api/getters/useUsers/useUsers';
import useAdminUsersApi from '../../../../hooks/api/actions/useAdminUsersApi/useAdminUsersApi';
diff --git a/frontend/src/page/admin/users/index.js b/frontend/src/page/admin/users/index.js
index c3e081146a..bd175339ac 100644
--- a/frontend/src/page/admin/users/index.js
+++ b/frontend/src/page/admin/users/index.js
@@ -5,7 +5,7 @@ import AdminMenu from '../admin-menu';
import PageContent from '../../../component/common/PageContent/PageContent';
import AccessContext from '../../../contexts/AccessContext';
import ConditionallyRender from '../../../component/common/ConditionallyRender';
-import { ADMIN } from '../../../component/AccessProvider/permissions';
+import { ADMIN } from '../../../component/providers/AccessProvider/permissions';
import { Alert } from '@material-ui/lab';
import HeaderTitle from '../../../component/common/HeaderTitle';
import { Button } from '@material-ui/core';
diff --git a/frontend/src/page/history/index.js b/frontend/src/page/history/index.js
index 7ca21fa67a..a5f86a8c30 100644
--- a/frontend/src/page/history/index.js
+++ b/frontend/src/page/history/index.js
@@ -1,6 +1,6 @@
import { Alert } from '@material-ui/lab';
import React, { useContext } from 'react';
-import { ADMIN } from '../../component/AccessProvider/permissions';
+import { ADMIN } from '../../component/providers/AccessProvider/permissions';
import ConditionallyRender from '../../component/common/ConditionallyRender';
import HistoryComponent from '../../component/history/EventHistory';
import AccessContext from '../../contexts/AccessContext';
diff --git a/frontend/src/utils/project-filter-generator.ts b/frontend/src/utils/project-filter-generator.ts
index d8c6dc101f..3e271fd478 100644
--- a/frontend/src/utils/project-filter-generator.ts
+++ b/frontend/src/utils/project-filter-generator.ts
@@ -1,4 +1,4 @@
-import { ADMIN } from '../component/AccessProvider/permissions';
+import { ADMIN } from '../component/providers/AccessProvider/permissions';
import IAuthStatus, { IPermission } from '../interfaces/user';
type objectIdx = {
@@ -24,6 +24,6 @@ export const projectFilterGenerator = (
{}
);
return (projectId: string) => {
- return admin || permissionMap[projectId]
+ return admin || permissionMap[projectId];
};
};