keycloak-scim/src/realm-settings/NewAttributeSettings.tsx

206 lines
5.8 KiB
TypeScript
Raw Normal View History

import React, { useState } from "react";
import {
ActionGroup,
AlertVariant,
Button,
Form,
PageSection,
} from "@patternfly/react-core";
import { FormProvider, useForm, useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link, useHistory } from "react-router-dom";
import { ScrollForm } from "../components/scroll-form/ScrollForm";
import { useRealm } from "../context/realm-context/RealmContext";
import type UserProfileConfig from "@keycloak/keycloak-admin-client/lib/defs/userProfileConfig";
import { AttributeGeneralSettings } from "./user-profile/attribute/AttributeGeneralSettings";
import { AttributePermission } from "./user-profile/attribute/AttributePermission";
import { AttributeValidations } from "./user-profile/attribute/AttributeValidations";
import { toUserProfile } from "./routes/UserProfile";
import "./realm-settings-section.css";
import { ViewHeader } from "../components/view-header/ViewHeader";
import { AttributeAnnotations } from "./user-profile/attribute/AttributeAnnotations";
import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import { useAlerts } from "../components/alert/Alerts";
import { UserProfileProvider } from "./user-profile/UserProfileContext";
import type { UserProfileAttribute } from "@keycloak/keycloak-admin-client/lib/defs/userProfileConfig";
import type { KeyValueType } from "../components/attribute-form/attribute-convert";
import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation";
type UserProfileAttributeType = UserProfileAttribute &
AttributeRequired &
Permission;
type AttributeRequired = {
roles: string[];
scopeRequired: string[];
enabledWhen: boolean;
requiredWhen: boolean;
};
type Permission = {
view: PermissionView[];
edit: PermissionEdit[];
};
type PermissionView = [
{
adminView: boolean;
userView: boolean;
}
];
type PermissionEdit = [
{
adminEdit: boolean;
userEdit: boolean;
}
];
const CreateAttributeFormContent = ({
save,
}: {
save: (profileConfig: UserProfileConfig) => void;
}) => {
const { t } = useTranslation("realm-settings");
const form = useFormContext();
const { realm } = useRealm();
return (
<UserProfileProvider>
<ScrollForm
sections={[
t("generalSettings"),
t("permission"),
t("validations"),
t("annotations"),
]}
>
<AttributeGeneralSettings />
<AttributePermission />
<AttributeValidations />
<AttributeAnnotations />
</ScrollForm>
<Form onSubmit={form.handleSubmit(save)}>
<ActionGroup className="keycloak__form_actions">
<Button
variant="primary"
type="submit"
data-testid="attribute-create"
>
{t("common:create")}
</Button>
<Link
to={toUserProfile({ realm, tab: "attributes" })}
data-testid="attribute-cancel"
className="kc-attributeCancel"
>
{t("common:cancel")}
</Link>
</ActionGroup>
</Form>
</UserProfileProvider>
);
};
export default function NewAttributeSettings() {
const { realm: realmName } = useRealm();
const adminClient = useAdminClient();
const form = useForm<UserProfileConfig>();
const { t } = useTranslation("realm-settings");
const history = useHistory();
const { addAlert, addError } = useAlerts();
const [config, setConfig] = useState<UserProfileConfig | null>(null);
const [clientScopes, setClientScopes] =
useState<ClientScopeRepresentation[]>();
useFetch(
() =>
Promise.all([
adminClient.users.getProfile({ realm: realmName }),
adminClient.clientScopes.find(),
]),
([config, clientScopes]) => {
setConfig(config);
setClientScopes(clientScopes);
},
[]
);
const save = async (profileConfig: UserProfileAttributeType) => {
const scopeNames = clientScopes?.map((clientScope) => clientScope.name);
const selector = {
scopes: profileConfig.enabledWhen
? scopeNames
: profileConfig.selector?.scopes,
};
const required = {
roles: profileConfig.roles,
scopes: profileConfig.requiredWhen
? scopeNames
: profileConfig.scopeRequired,
};
const validations = profileConfig.validations?.reduce(
(prevValidations: any, currentValidations: any) => {
prevValidations[currentValidations.name] =
currentValidations.config.length === 0
? {}
: currentValidations.config;
return prevValidations;
},
{}
);
const annotations = (profileConfig.annotations! as KeyValueType[]).reduce(
(obj, item) => Object.assign(obj, { [item.key]: item.value }),
{}
);
const newAttribute = [
{
name: profileConfig.name,
displayName: profileConfig.displayName,
required,
validations,
selector,
permissions: profileConfig.permissions,
annotations,
},
];
const newAttributesList = config?.attributes!.concat(
newAttribute as UserProfileAttribute
);
try {
await adminClient.users.updateProfile({
attributes: newAttributesList,
realm: realmName,
});
history.push(toUserProfile({ realm: realmName, tab: "attributes" }));
addAlert(
t("realm-settings:createAttributeSuccess"),
AlertVariant.success
);
} catch (error) {
addError("realm-settings:createAttributeError", error);
}
};
return (
<FormProvider {...form}>
<ViewHeader
titleKey={t("createAttribute")}
subKey={t("createAttributeSubTitle")}
/>
<PageSection variant="light">
<CreateAttributeFormContent save={() => form.handleSubmit(save)()} />
</PageSection>
</FormProvider>
);
}