diff --git a/frontend/src/component/admin/auth/AuthSettings.tsx b/frontend/src/component/admin/auth/AuthSettings.tsx index db1eb4aaa9..255dd7e754 100644 --- a/frontend/src/component/admin/auth/AuthSettings.tsx +++ b/frontend/src/component/admin/auth/AuthSettings.tsx @@ -11,15 +11,11 @@ import { ADMIN } from '@server/types/permissions'; import { PremiumFeature } from 'component/common/PremiumFeature/PremiumFeature'; import { useState } from 'react'; import { TabPanel } from 'component/common/TabNav/TabPanel/TabPanel'; -import { useUiFlag } from 'hooks/useUiFlag'; -import { ScimSettings } from './ScimSettings/ScimSettings'; export const AuthSettings = () => { const { authenticationType } = useUiConfig().uiConfig; const { uiConfig } = useUiConfig(); - const scimEnabled = useUiFlag('scimApi'); - const tabs = [ { label: 'OpenID Connect', @@ -41,13 +37,6 @@ export const AuthSettings = () => { (item) => uiConfig.flags?.googleAuthEnabled || item.label !== 'Google', ); - if (scimEnabled) { - tabs.push({ - label: 'Provisioning (SCIM)', - component: , - }); - } - const [activeTab, setActiveTab] = useState(0); return ( diff --git a/frontend/src/component/admin/auth/OidcAuth/OidcAuth.tsx b/frontend/src/component/admin/auth/OidcAuth/OidcAuth.tsx index 70ab4e5151..570e8bb988 100644 --- a/frontend/src/component/admin/auth/OidcAuth/OidcAuth.tsx +++ b/frontend/src/component/admin/auth/OidcAuth/OidcAuth.tsx @@ -21,6 +21,10 @@ 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, @@ -85,6 +89,22 @@ export const OidcAuth = () => { }); }; + const { + settings, + enabled, + setEnabled, + assumeControlOfExisting, + setAssumeControlOfExisting, + newToken, + tokenGenerationDialog, + setTokenGenerationDialog, + tokenDialog, + setTokenDialog, + loading: scimLoading, + saveScimSettings, + onGenerateNewTokenConfirm, + } = useScim(); + const onSubmit = async (event: React.SyntheticEvent) => { event.preventDefault(); @@ -94,11 +114,14 @@ export const OidcAuth = () => { title: 'Settings stored', type: 'success', }); + saveScimSettings(); } catch (error: unknown) { setToastApiError(formatUnknownError(error)); } }; + const scimEnabled = useUiFlag('scimApi'); + return ( <> @@ -255,6 +278,32 @@ export const OidcAuth = () => { data={data} setValue={setValue} /> + + + } + /> + { + { }); }; + const { + settings, + enabled, + setEnabled, + assumeControlOfExisting, + setAssumeControlOfExisting, + newToken, + tokenGenerationDialog, + setTokenGenerationDialog, + tokenDialog, + setTokenDialog, + loading: scimLoading, + saveScimSettings, + onGenerateNewTokenConfirm, + } = useScim(); + const onSubmit = async (event: React.SyntheticEvent) => { event.preventDefault(); @@ -85,11 +105,14 @@ export const SamlAuth = () => { title: 'Settings stored', type: 'success', }); + saveScimSettings(); } catch (error: unknown) { setToastApiError(formatUnknownError(error)); } }; + const scimEnabled = useUiFlag('scimApi'); + return ( <> @@ -263,6 +286,31 @@ export const SamlAuth = () => { setValue={setValue} /> + + } + /> + { - const { setToastData, setToastApiError } = useToast(); +export interface IScimSettingsParameters { + disabled: boolean; + loading: boolean; + enabled: boolean; + setEnabled: React.Dispatch>; + assumeControlOfExisting: boolean; + setAssumeControlOfExisting: React.Dispatch>; + newToken: string; + settings: ScimSettings; + tokenGenerationDialog: boolean; + setTokenGenerationDialog: React.Dispatch>; + onGenerateNewTokenConfirm: () => void; + tokenDialog: boolean; + setTokenDialog: React.Dispatch>; +} + +export const ScimConfigSettings = ({ + disabled, + loading, + enabled, + setEnabled, + assumeControlOfExisting, + setAssumeControlOfExisting, + newToken, + settings, + tokenGenerationDialog, + setTokenGenerationDialog, + onGenerateNewTokenConfirm, + tokenDialog, + setTokenDialog, +}: IScimSettingsParameters) => { const { uiConfig } = useUiConfig(); - const { settings, refetch } = useScimSettings(); - const { saveSettings, generateNewToken, errors, loading } = - useScimSettingsApi(); - - const [enabled, setEnabled] = useState(false); - - const [tokenGenerationDialog, setTokenGenerationDialog] = useState(false); - const [tokenDialog, setTokenDialog] = useState(false); - const [newToken, setNewToken] = useState(''); - - useEffect(() => { - setEnabled(settings.enabled ?? false); - }, [settings]); - - const onSubmit = async (event: React.SyntheticEvent) => { - event.preventDefault(); - - try { - await saveSettings({ enabled }); - 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 onGenerateNewToken = async () => { setTokenGenerationDialog(true); }; - const onGenerateNewTokenConfirm = async () => { - setTokenGenerationDialog(false); - const token = await generateNewToken(); - setNewToken(token); - setTokenDialog(true); - }; - return ( <> + SCIM Provisioning @@ -79,56 +63,68 @@ export const ScimSettings = () => { - - - - Enable - Enable SCIM provisioning. - - - - setEnabled(enabled) - } - value={enabled} - name='enabled' - checked={enabled} - /> - } - label={enabled ? 'Enabled' : 'Disabled'} - /> - + + + Enable + Enable SCIM provisioning. + + setEnabled(enabled)} + value={enabled} + name='enabled' + checked={enabled} + disabled={disabled} + /> + } + label={enabled ? 'Enabled' : 'Disabled'} + /> + + - - - - Save - - - Generate new token - - } - /> - + + + Assume control + Assumes control of users and groups - + + + setAssumeControlOfExisting(set_enabled) + } + value={assumeControlOfExisting} + name='assumeControlOfExisting' + checked={assumeControlOfExisting} + disabled={disabled} + /> + } + label={assumeControlOfExisting ? 'Enabled' : 'Disabled'} + /> + + + + + + + Generate new token + + } + /> + + { diff --git a/frontend/src/hooks/useScim.ts b/frontend/src/hooks/useScim.ts new file mode 100644 index 0000000000..80a1ebaa8f --- /dev/null +++ b/frontend/src/hooks/useScim.ts @@ -0,0 +1,66 @@ +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, + }; +};
Enable SCIM provisioning.
Assumes control of users and groups