Add user profile tab to realm settings (#1509)
This commit is contained in:
parent
f57f8c5560
commit
c61ba73781
4 changed files with 164 additions and 1 deletions
|
@ -51,6 +51,7 @@ import { HelpItem } from "../components/help-enabler/HelpItem";
|
|||
import { DEFAULT_LOCALE } from "../i18n";
|
||||
import { toDashboard } from "../dashboard/routes/Dashboard";
|
||||
import environment from "../environment";
|
||||
import { UserProfileTab } from "./UserProfileTab";
|
||||
|
||||
type RealmSettingsHeaderProps = {
|
||||
onChange: (value: boolean) => void;
|
||||
|
@ -438,6 +439,15 @@ export const RealmSettingsTabs = ({
|
|||
</Tab>
|
||||
</Tabs>
|
||||
</Tab>
|
||||
<Tab
|
||||
eventKey="userProfile"
|
||||
data-testid="rs-user-profile-tab"
|
||||
title={
|
||||
<TabTitleText>{t("realm-settings:userProfile")}</TabTitleText>
|
||||
}
|
||||
>
|
||||
<UserProfileTab />
|
||||
</Tab>
|
||||
</KeycloakTabs>
|
||||
</FormProvider>
|
||||
</PageSection>
|
||||
|
|
144
src/realm-settings/UserProfileTab.tsx
Normal file
144
src/realm-settings/UserProfileTab.tsx
Normal file
|
@ -0,0 +1,144 @@
|
|||
import type ClientProfilesRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfilesRepresentation";
|
||||
import { CodeEditor, Language } from "@patternfly/react-code-editor";
|
||||
import {
|
||||
ActionGroup,
|
||||
AlertVariant,
|
||||
Button,
|
||||
Form,
|
||||
PageSection,
|
||||
Tab,
|
||||
Tabs,
|
||||
TabTitleText,
|
||||
} from "@patternfly/react-core";
|
||||
import type { editor } from "monaco-editor";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAlerts } from "../components/alert/Alerts";
|
||||
import { useAdminClient, useFetch } from "../context/auth/AdminClient";
|
||||
import { useRealm } from "../context/realm-context/RealmContext";
|
||||
import { prettyPrintJSON } from "../util";
|
||||
|
||||
export const UserProfileTab = () => {
|
||||
const adminClient = useAdminClient();
|
||||
const { realm } = useRealm();
|
||||
const { t } = useTranslation("realm-settings");
|
||||
const { addAlert, addError } = useAlerts();
|
||||
const [activeTab, setActiveTab] = useState("attributes");
|
||||
const [profiles, setProfiles] = useState<ClientProfilesRepresentation>();
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [refreshCount, setRefreshCount] = useState(0);
|
||||
|
||||
useFetch(
|
||||
() =>
|
||||
adminClient.clientPolicies.listProfiles({
|
||||
includeGlobalProfiles: true,
|
||||
realm,
|
||||
}),
|
||||
(profiles) => setProfiles(profiles),
|
||||
[refreshCount]
|
||||
);
|
||||
|
||||
async function onSave(updatedProfiles: ClientProfilesRepresentation) {
|
||||
setIsSaving(true);
|
||||
|
||||
try {
|
||||
await adminClient.clientPolicies.createProfiles({
|
||||
...updatedProfiles,
|
||||
realm,
|
||||
});
|
||||
|
||||
setRefreshCount(refreshCount + 1);
|
||||
addAlert(t("userProfileSuccess"), AlertVariant.success);
|
||||
} catch (error) {
|
||||
addError("realm-settings:userProfileError", error);
|
||||
}
|
||||
|
||||
setIsSaving(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
activeKey={activeTab}
|
||||
onSelect={(_, key) => setActiveTab(key.toString())}
|
||||
>
|
||||
<Tab
|
||||
eventKey="attributes"
|
||||
title={<TabTitleText>{t("attributes")}</TabTitleText>}
|
||||
></Tab>
|
||||
<Tab
|
||||
eventKey="attributesGroup"
|
||||
title={<TabTitleText>{t("attributesGroup")}</TabTitleText>}
|
||||
></Tab>
|
||||
<Tab
|
||||
eventKey="jsonEditor"
|
||||
title={<TabTitleText>{t("jsonEditor")}</TabTitleText>}
|
||||
>
|
||||
{/** The code editor needs to be rendered conditionally to prevent it from being initialized
|
||||
* while the tab contents are hidden. If the contents of the tab are hidden then it
|
||||
* might not initialize correctly.
|
||||
*/}
|
||||
{activeTab === "jsonEditor" && (
|
||||
<JsonEditorTab
|
||||
profiles={profiles}
|
||||
onSave={onSave}
|
||||
isSaving={isSaving}
|
||||
/>
|
||||
)}
|
||||
</Tab>
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
type JsonEditorTabProps = {
|
||||
profiles?: ClientProfilesRepresentation;
|
||||
onSave: (profiles: ClientProfilesRepresentation) => void;
|
||||
isSaving: boolean;
|
||||
};
|
||||
|
||||
const JsonEditorTab = ({ profiles, onSave, isSaving }: JsonEditorTabProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { addError } = useAlerts();
|
||||
const [editor, setEditor] = useState<editor.IStandaloneCodeEditor>();
|
||||
|
||||
useEffect(() => resetCode(), [profiles, editor]);
|
||||
|
||||
function resetCode() {
|
||||
editor?.setValue(profiles ? prettyPrintJSON(profiles) : "");
|
||||
}
|
||||
|
||||
function save() {
|
||||
const value = editor?.getValue();
|
||||
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
onSave(JSON.parse(value));
|
||||
} catch (error) {
|
||||
addError("realm-settings:invalidJsonError", error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<PageSection variant="light">
|
||||
<CodeEditor
|
||||
language={Language.json}
|
||||
height="30rem"
|
||||
onEditorDidMount={(editor) => setEditor(editor)}
|
||||
isLanguageLabelVisible
|
||||
/>
|
||||
<Form>
|
||||
<ActionGroup>
|
||||
<Button variant="primary" onClick={save} isDisabled={isSaving}>
|
||||
{t("common:save")}
|
||||
</Button>
|
||||
<Button variant="link" onClick={resetCode} isDisabled={isSaving}>
|
||||
{t("common:revert")}
|
||||
</Button>
|
||||
</ActionGroup>
|
||||
</Form>
|
||||
</PageSection>
|
||||
);
|
||||
};
|
|
@ -338,6 +338,14 @@ export default {
|
|||
addClientProfile: "Add client profile",
|
||||
emptyProfiles: "No client profiles configured",
|
||||
tokens: "Tokens",
|
||||
userProfile: "User profile",
|
||||
jsonEditor: "JSON editor",
|
||||
attributes: "Attributes",
|
||||
attributesGroup: "Attributes group",
|
||||
invalidJsonError:
|
||||
"Unable to save user profile, the provided information is not valid JSON.",
|
||||
userProfileSuccess: "User profile settings successfully updated.",
|
||||
userProfileError: "Could not update user profile settings: {{error}}",
|
||||
key: "Key",
|
||||
value: "Value",
|
||||
status: "Status",
|
||||
|
|
|
@ -13,7 +13,8 @@ export type RealmSettingsTab =
|
|||
| "securityDefences"
|
||||
| "sessions"
|
||||
| "tokens"
|
||||
| "clientPolicies";
|
||||
| "clientPolicies"
|
||||
| "userProfile";
|
||||
|
||||
export type RealmSettingsParams = {
|
||||
realm: string;
|
||||
|
|
Loading…
Reference in a new issue