1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-28 00:06:53 +01:00

feat: move SCIM config into separate tab (#7055)

Moves SCIM config back into separate tab


![image](https://github.com/Unleash/unleash/assets/707867/910f2128-08de-4460-a9e8-a606342669cd)
This commit is contained in:
David Leek 2024-05-16 08:01:32 +02:00 committed by GitHub
parent acb663df7a
commit 793cd76e93
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 126 additions and 218 deletions

View File

@ -2,8 +2,10 @@ import { Alert, Tab, Tabs } from '@mui/material';
import { PageContent } from 'component/common/PageContent/PageContent';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { useUiFlag } from 'hooks/useUiFlag';
import { OidcAuth } from './OidcAuth/OidcAuth';
import { SamlAuth } from './SamlAuth/SamlAuth';
import { ScimSettings } from './ScimSettings/ScimSettings';
import { PasswordAuth } from './PasswordAuth/PasswordAuth';
import { GoogleAuth } from './GoogleAuth/GoogleAuth';
import { PermissionGuard } from 'component/common/PermissionGuard/PermissionGuard';
@ -14,7 +16,7 @@ import { TabPanel } from 'component/common/TabNav/TabPanel/TabPanel';
export const AuthSettings = () => {
const { authenticationType } = useUiConfig().uiConfig;
const { uiConfig } = useUiConfig();
const { uiConfig, isEnterprise } = useUiConfig();
const tabs = [
{
@ -37,6 +39,13 @@ export const AuthSettings = () => {
(item) => uiConfig.flags?.googleAuthEnabled || item.label !== 'Google',
);
if (isEnterprise() && useUiFlag('scimApi')) {
tabs.push({
label: 'SCIM',
component: <ScimSettings />,
});
}
const [activeTab, setActiveTab] = useState(0);
return (

View File

@ -17,10 +17,6 @@ import { formatUnknownError } from 'utils/formatUnknownError';
import { removeEmptyStringFields } from 'utils/removeEmptyStringFields';
import { SsoGroupSettings } from '../SsoGroupSettings';
import type { IRole } from 'interfaces/role';
import { useUiFlag } from 'hooks/useUiFlag';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useScim } from 'hooks/useScim';
import { ScimConfigSettings } from '../ScimSettings/ScimSettings';
const initialState = {
enabled: false,
@ -80,24 +76,6 @@ export const SamlAuth = () => {
});
};
const scimEnabled = useUiFlag('scimApi');
const {
settings,
enabled,
setEnabled,
assumeControlOfExisting,
setAssumeControlOfExisting,
newToken,
tokenGenerationDialog,
setTokenGenerationDialog,
tokenDialog,
setTokenDialog,
loading: scimLoading,
saveScimSettings,
onGenerateNewTokenConfirm,
} = useScim();
const onSubmit = async (event: React.SyntheticEvent) => {
event.preventDefault();
@ -107,9 +85,6 @@ export const SamlAuth = () => {
title: 'Settings stored',
type: 'success',
});
if (scimEnabled) {
saveScimSettings();
}
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
}
@ -288,31 +263,6 @@ export const SamlAuth = () => {
setValue={setValue}
/>
<ConditionallyRender
condition={scimEnabled}
show={
<ScimConfigSettings
disabled={!data.enabled}
settings={settings}
enabled={enabled}
setEnabled={setEnabled}
assumeControlOfExisting={assumeControlOfExisting}
setAssumeControlOfExisting={
setAssumeControlOfExisting
}
newToken={newToken}
tokenGenerationDialog={tokenGenerationDialog}
setTokenGenerationDialog={setTokenGenerationDialog}
tokenDialog={tokenDialog}
setTokenDialog={setTokenDialog}
loading={scimLoading}
onGenerateNewTokenConfirm={
onGenerateNewTokenConfirm
}
/>
}
/>
<AutoCreateForm
data={data}
setValue={setValue}

View File

@ -1,51 +1,74 @@
import { Button, FormControlLabel, Grid, Switch } from '@mui/material';
import { Button, FormControlLabel, Grid, Switch, styled } from '@mui/material';
import { Alert } from '@mui/material';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { ScimTokenGenerationDialog } from './ScimTokenGenerationDialog';
import { ScimTokenDialog } from './ScimTokenDialog';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import type { ScimSettings } from 'hooks/api/getters/useScimSettings/useScimSettings';
import { useEffect, useState } from 'react';
import { formatUnknownError } from 'utils/formatUnknownError';
import useToast from 'hooks/useToast';
import { useScimSettingsApi } from 'hooks/api/actions/useScimSettingsApi/useScimSettingsApi';
import { useScimSettings } from 'hooks/api/getters/useScimSettings/useScimSettings';
export interface IScimSettingsParameters {
disabled: boolean;
loading: boolean;
enabled: boolean;
setEnabled: React.Dispatch<React.SetStateAction<boolean>>;
assumeControlOfExisting: boolean;
setAssumeControlOfExisting: React.Dispatch<React.SetStateAction<boolean>>;
newToken: string;
settings: ScimSettings;
tokenGenerationDialog: boolean;
setTokenGenerationDialog: React.Dispatch<React.SetStateAction<boolean>>;
onGenerateNewTokenConfirm: () => void;
tokenDialog: boolean;
setTokenDialog: React.Dispatch<React.SetStateAction<boolean>>;
}
const StyledContainer = styled('div')(({ theme }) => ({
padding: theme.spacing(3),
border: `1px solid ${theme.palette.divider}`,
borderRadius: theme.shape.borderRadiusLarge,
}));
export const ScimConfigSettings = ({
disabled,
loading,
enabled,
setEnabled,
assumeControlOfExisting,
setAssumeControlOfExisting,
newToken,
settings,
tokenGenerationDialog,
setTokenGenerationDialog,
onGenerateNewTokenConfirm,
tokenDialog,
setTokenDialog,
}: IScimSettingsParameters) => {
const StyledTitleDiv = styled('div')(({ theme }) => ({
marginBottom: theme.spacing(1),
}));
export const ScimSettings = () => {
const { uiConfig } = useUiConfig();
const { setToastData, setToastApiError } = useToast();
const [newToken, setNewToken] = useState('');
const [tokenGenerationDialog, setTokenGenerationDialog] = useState(false);
const [tokenDialog, setTokenDialog] = useState(false);
const { settings, refetch } = useScimSettings();
const [enabled, setEnabled] = useState(settings.enabled ?? true);
useEffect(() => {
setEnabled(settings.enabled ?? false);
}, [settings]);
const { saveSettings, generateNewToken, errors, loading } =
useScimSettingsApi();
const onGenerateNewToken = async () => {
setTokenGenerationDialog(true);
};
const onGenerateNewTokenConfirm = async () => {
setTokenGenerationDialog(false);
const token = await generateNewToken();
setNewToken(token);
setTokenDialog(true);
};
const saveScimSettings = async (enabled: boolean) => {
try {
setEnabled(enabled);
await saveSettings({ enabled, assumeControlOfExisting: false });
if (enabled && !settings.hasToken) {
const token = await generateNewToken();
setNewToken(token);
setTokenDialog(true);
}
setToastData({
title: 'Settings stored',
type: 'success',
});
await refetch();
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
}
};
return (
<>
<h3>SCIM Provisioning</h3>
<Grid container sx={{ mb: 3 }}>
<Grid item md={12}>
<Alert severity='info'>
@ -63,77 +86,69 @@ export const ScimConfigSettings = ({
</Alert>
</Grid>
</Grid>
<Grid container spacing={3}>
<Grid item md={5} mb={2}>
<strong>Enable</strong>
<p>Enable SCIM provisioning.</p>
<StyledContainer>
<Grid container spacing={3}>
<Grid item md={10.5} mb={2}>
<StyledTitleDiv>
<strong>SCIM provisioning</strong>
</StyledTitleDiv>
<p>
Enables SCIM provisioning. If SCIM provisioning has
not previously been enabled here this will also set
up a new auth token to use with your SCIM client,
and display it to the user. After the dialog has
been closed, this token will not be displayed again.
If you need a new token you can click the Generate
new token button below which will replace the old
token with a new token, and similarly display the
new token one time to the user.
</p>
</Grid>
<Grid item md={1.5}>
<FormControlLabel
control={
<Switch
onChange={(_, enabled) => {
saveScimSettings(enabled);
}}
value={enabled}
name='enabled'
checked={enabled}
/>
}
label={enabled ? 'Enabled' : 'Disabled'}
/>
</Grid>
</Grid>
<Grid item md={6}>
<FormControlLabel
control={
<Switch
onChange={(_, enabled) => setEnabled(enabled)}
value={enabled}
name='enabled'
checked={enabled}
disabled={disabled}
/>
}
label={enabled ? 'Enabled' : 'Disabled'}
/>
</Grid>
</Grid>
<Grid container spacing={3}>
<Grid item md={5} mb={2}>
<strong>Assume control</strong>
<p>Assumes control of users and groups</p>
<Grid container spacing={3}>
<Grid item md={5} mb={2}>
<ConditionallyRender
condition={Boolean(settings.hasToken)}
show={
<Button
variant='outlined'
color='error'
disabled={loading}
onClick={onGenerateNewToken}
>
Generate new token
</Button>
}
/>
</Grid>
</Grid>
<Grid item md={6}>
<FormControlLabel
control={
<Switch
onChange={(_, set_enabled) =>
setAssumeControlOfExisting(set_enabled)
}
value={assumeControlOfExisting}
name='assumeControlOfExisting'
checked={assumeControlOfExisting}
disabled={disabled}
/>
}
label={assumeControlOfExisting ? 'Enabled' : 'Disabled'}
/>
</Grid>
</Grid>
<Grid container spacing={3}>
<Grid item md={5} mb={2}>
<ConditionallyRender
condition={Boolean(settings.hasToken)}
show={
<Button
variant='outlined'
color='error'
disabled={loading}
onClick={onGenerateNewToken}
>
Generate new token
</Button>
}
/>
</Grid>
</Grid>
<ScimTokenGenerationDialog
open={tokenGenerationDialog}
setOpen={setTokenGenerationDialog}
onConfirm={onGenerateNewTokenConfirm}
/>
<ScimTokenDialog
open={tokenDialog}
setOpen={setTokenDialog}
token={newToken}
/>
<ScimTokenGenerationDialog
open={tokenGenerationDialog}
setOpen={setTokenGenerationDialog}
onConfirm={onGenerateNewTokenConfirm}
/>
<ScimTokenDialog
open={tokenDialog}
setOpen={setTokenDialog}
token={newToken}
/>
</StyledContainer>
</>
);
};

View File

@ -1,66 +0,0 @@
import { useScimSettingsApi } from 'hooks/api/actions/useScimSettingsApi/useScimSettingsApi';
import { useEffect, useState } from 'react';
import { formatUnknownError } from 'utils/formatUnknownError';
import useToast from 'hooks/useToast';
import { useScimSettings } from './api/getters/useScimSettings/useScimSettings';
export const useScim = () => {
const [newToken, setNewToken] = useState('');
const [enabled, setEnabled] = useState(false);
const [tokenGenerationDialog, setTokenGenerationDialog] = useState(false);
const [tokenDialog, setTokenDialog] = useState(false);
const [assumeControlOfExisting, setAssumeControlOfExisting] =
useState(false);
const { saveSettings, generateNewToken, errors, loading } =
useScimSettingsApi();
const { settings, refetch } = useScimSettings();
const { setToastData, setToastApiError } = useToast();
const saveScimSettings = async () => {
try {
await saveSettings({ enabled, assumeControlOfExisting });
if (enabled && !settings.hasToken) {
const token = await generateNewToken();
setNewToken(token);
setTokenDialog(true);
}
setToastData({
title: 'Settings stored',
type: 'success',
});
refetch();
} catch (error: unknown) {
setToastApiError(formatUnknownError(error));
}
};
const onGenerateNewTokenConfirm = async () => {
setTokenGenerationDialog(false);
const token = await generateNewToken();
setNewToken(token);
setTokenDialog(true);
};
useEffect(() => {
setEnabled(settings.enabled ?? false);
setAssumeControlOfExisting(settings.assumeControlOfExisting ?? false);
}, [settings]);
return {
settings,
enabled,
setEnabled,
assumeControlOfExisting,
setAssumeControlOfExisting,
newToken,
tokenGenerationDialog,
setTokenGenerationDialog,
tokenDialog,
setTokenDialog,
loading,
saveScimSettings,
onGenerateNewTokenConfirm,
};
};