@keycloakify/keycloak-admin-ui
Version:
Repackaged Keycloak Admin UI
360 lines • 24.7 kB
JavaScript
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { HelpItem, KeycloakTextArea, TextControl, useAlerts, useFetch, } from "../ui-shared";
import { ActionGroup, AlertVariant, Button, ButtonVariant, DataList, DataListCell, DataListItem, DataListItemCells, DataListItemRow, Divider, DropdownItem, Flex, FlexItem, FormGroup, Label, PageSection, Text, TextVariants, } from "@patternfly/react-core";
import { PlusCircleIcon, TrashIcon } from "@patternfly/react-icons";
import { useState } from "react";
import { Controller, FormProvider, useForm } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { Link, useNavigate } from "react-router-dom";
import { useAdminClient } from "../admin-client";
import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog";
import { FormAccess } from "../components/form/FormAccess";
import { KeycloakSpinner } from "../ui-shared";
import { ViewHeader } from "../components/view-header/ViewHeader";
import { useRealm } from "../context/realm-context/RealmContext";
import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { useParams } from "../utils/useParams";
import { AddClientProfileModal } from "../realm-settings/AddClientProfileModal";
import { toNewClientPolicyCondition } from "../realm-settings/routes/AddCondition";
import { toClientPolicies } from "../realm-settings/routes/ClientPolicies";
import { toClientProfile } from "../realm-settings/routes/ClientProfile";
import { toEditClientPolicy, } from "../realm-settings/routes/EditClientPolicy";
import { toEditClientPolicyCondition } from "../realm-settings/routes/EditCondition";
import "./realm-settings-section.css";
const defaultValues = {
name: "",
description: "",
conditions: [],
enabled: true,
profiles: [],
};
export default function NewClientPolicy() {
var _a, _b, _c;
const { adminClient } = useAdminClient();
const { t } = useTranslation();
const { realm } = useRealm();
const { addAlert, addError } = useAlerts();
const [isGlobalPolicy, setIsGlobalPolicy] = useState(false);
const [policies, setPolicies] = useState();
const [globalPolicies, setGlobalPolicies] = useState();
const [allPolicies, setAllPolicies] = useState();
const [clientProfiles, setClientProfiles] = useState([]);
const [currentPolicy, setCurrentPolicy] = useState();
const [showAddConditionsAndProfilesForm, setShowAddConditionsAndProfilesForm,] = useState(false);
const [conditionToDelete, setConditionToDelete] = useState();
const [profilesModalOpen, setProfilesModalOpen] = useState(false);
const [profileToDelete, setProfileToDelete] = useState();
const { policyName } = useParams();
const navigate = useNavigate();
const form = useForm({
mode: "onChange",
defaultValues,
});
const { handleSubmit } = form;
const formValues = form.getValues();
useFetch(async () => {
const [policies, profiles] = await Promise.all([
adminClient.clientPolicies.listPolicies({
includeGlobalPolicies: true,
}),
adminClient.clientPolicies.listProfiles({
includeGlobalProfiles: true,
}),
]);
return { policies, profiles };
}, ({ policies, profiles }) => {
var _a, _b, _c, _d, _e, _f, _g, _h;
let currentPolicy = (_a = policies.policies) === null || _a === void 0 ? void 0 : _a.find((item) => item.name === policyName);
if (currentPolicy === undefined) {
currentPolicy = (_b = policies.globalPolicies) === null || _b === void 0 ? void 0 : _b.find((item) => item.name === policyName);
setIsGlobalPolicy(currentPolicy !== undefined);
}
const allClientProfiles = [
...((_c = profiles.globalProfiles) !== null && _c !== void 0 ? _c : []),
...((_d = profiles.profiles) !== null && _d !== void 0 ? _d : []),
];
const allClientPolicies = [
...((_e = policies.globalPolicies) !== null && _e !== void 0 ? _e : []),
...((_f = policies.policies) !== null && _f !== void 0 ? _f : []),
];
setPolicies((_g = policies.policies) !== null && _g !== void 0 ? _g : []);
setGlobalPolicies((_h = policies.globalPolicies) !== null && _h !== void 0 ? _h : []);
setAllPolicies(allClientPolicies);
if (currentPolicy) {
setupForm(currentPolicy);
setClientProfiles(allClientProfiles);
setCurrentPolicy(currentPolicy);
setShowAddConditionsAndProfilesForm(true);
}
}, []);
const setupForm = (policy) => {
form.reset(policy);
};
const policy = (allPolicies || []).filter((policy) => policy.name === policyName);
const policyConditions = ((_a = policy[0]) === null || _a === void 0 ? void 0 : _a.conditions) || [];
const policyProfiles = ((_b = policy[0]) === null || _b === void 0 ? void 0 : _b.profiles) || [];
const serverInfo = useServerInfo();
const conditionTypes = (_c = serverInfo.componentTypes) === null || _c === void 0 ? void 0 : _c["org.keycloak.services.clientpolicy.condition.ClientPolicyConditionProvider"];
const save = async () => {
const createdForm = form.getValues();
const createdPolicy = {
...createdForm,
};
const getAllPolicies = () => {
const policyNameExists = policies === null || policies === void 0 ? void 0 : policies.some((policy) => policy.name === createdPolicy.name);
if (policyNameExists) {
return policies === null || policies === void 0 ? void 0 : policies.map((policy) => policy.name === createdPolicy.name ? createdPolicy : policy);
}
else if (createdForm.name !== policyName) {
return policies === null || policies === void 0 ? void 0 : policies.filter((item) => item.name !== policyName).concat(createdForm);
}
return policies === null || policies === void 0 ? void 0 : policies.concat(createdForm);
};
try {
await adminClient.clientPolicies.updatePolicy({
policies: getAllPolicies(),
});
addAlert(policyName
? t("updateClientPolicySuccess")
: t("createClientPolicySuccess"), AlertVariant.success);
navigate(toEditClientPolicy({ realm, policyName: createdForm.name }));
setShowAddConditionsAndProfilesForm(true);
}
catch (error) {
addError("createClientPolicyError", error);
}
};
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
titleKey: t("deleteClientPolicyConfirmTitle"),
messageKey: t("deleteClientPolicyConfirm", {
policyName: policyName,
}),
continueButtonLabel: t("delete"),
continueButtonVariant: ButtonVariant.danger,
onConfirm: async () => {
const updatedPolicies = policies === null || policies === void 0 ? void 0 : policies.filter((policy) => policy.name !== policyName);
try {
await adminClient.clientPolicies.updatePolicy({
policies: updatedPolicies,
});
addAlert(t("deleteClientPolicySuccess"), AlertVariant.success);
navigate(toClientPolicies({
realm,
tab: "policies",
}));
}
catch (error) {
addError("deleteClientPolicyError", error);
}
},
});
const [toggleDeleteConditionDialog, DeleteConditionConfirm] = useConfirmDialog({
titleKey: t("deleteClientPolicyConditionConfirmTitle"),
messageKey: t("deleteClientPolicyConditionConfirm", {
condition: conditionToDelete === null || conditionToDelete === void 0 ? void 0 : conditionToDelete.name,
}),
continueButtonLabel: t("delete"),
continueButtonVariant: ButtonVariant.danger,
onConfirm: async () => {
var _a;
if (conditionToDelete === null || conditionToDelete === void 0 ? void 0 : conditionToDelete.name) {
(_a = currentPolicy === null || currentPolicy === void 0 ? void 0 : currentPolicy.conditions) === null || _a === void 0 ? void 0 : _a.splice(conditionToDelete.idx, 1);
try {
await adminClient.clientPolicies.updatePolicy({
policies: policies,
});
addAlert(t("deleteConditionSuccess"), AlertVariant.success);
navigate(toEditClientPolicy({ realm, policyName: formValues.name }));
}
catch (error) {
addError("deleteConditionError", error);
}
}
else {
const updatedPolicies = policies === null || policies === void 0 ? void 0 : policies.filter((policy) => policy.name !== policyName);
try {
await adminClient.clientPolicies.updatePolicy({
policies: updatedPolicies,
});
addAlert(t("deleteClientSuccess"), AlertVariant.success);
navigate(toClientPolicies({
realm,
tab: "policies",
}));
}
catch (error) {
addError("deleteClientError", error);
}
}
},
});
const [toggleDeleteProfileDialog, DeleteProfileConfirm] = useConfirmDialog({
titleKey: t("deleteClientPolicyProfileConfirmTitle"),
messageKey: t("deleteClientPolicyProfileConfirm", {
profileName: profileToDelete === null || profileToDelete === void 0 ? void 0 : profileToDelete.name,
policyName,
}),
continueButtonLabel: t("delete"),
continueButtonVariant: ButtonVariant.danger,
onConfirm: async () => {
var _a;
if (profileToDelete === null || profileToDelete === void 0 ? void 0 : profileToDelete.name) {
(_a = currentPolicy === null || currentPolicy === void 0 ? void 0 : currentPolicy.profiles) === null || _a === void 0 ? void 0 : _a.splice(profileToDelete.idx, 1);
try {
await adminClient.clientPolicies.updatePolicy({
policies: policies,
});
addAlert(t("deleteClientPolicyProfileSuccess"), AlertVariant.success);
form.setValue("profiles", (currentPolicy === null || currentPolicy === void 0 ? void 0 : currentPolicy.profiles) || []);
navigate(toEditClientPolicy({ realm, policyName: formValues.name }));
}
catch (error) {
addError("deleteClientPolicyProfileError", error);
}
}
else {
const updatedPolicies = policies === null || policies === void 0 ? void 0 : policies.filter((policy) => policy.name !== policyName);
try {
await adminClient.clientPolicies.updatePolicy({
policies: updatedPolicies,
});
addAlert(t("deleteClientSuccess"), AlertVariant.success);
navigate(toClientPolicies({
realm,
tab: "policies",
}));
}
catch (error) {
addError("deleteClientError", error);
}
}
},
});
const reset = () => {
if ((currentPolicy === null || currentPolicy === void 0 ? void 0 : currentPolicy.name) !== undefined) {
form.setValue("name", currentPolicy.name);
}
if ((currentPolicy === null || currentPolicy === void 0 ? void 0 : currentPolicy.description) !== undefined) {
form.setValue("description", currentPolicy.description);
}
};
const toggleModal = () => {
setProfilesModalOpen(!profilesModalOpen);
};
const addProfiles = async (profiles) => {
const createdPolicy = {
...currentPolicy,
profiles: policyProfiles.concat(profiles),
conditions: currentPolicy === null || currentPolicy === void 0 ? void 0 : currentPolicy.conditions,
};
const index = policies === null || policies === void 0 ? void 0 : policies.findIndex((policy) => createdPolicy.name === policy.name);
if (index === undefined || index === -1) {
return;
}
const newPolicies = [
...(policies || []).slice(0, index),
createdPolicy,
...(policies || []).slice(index + 1),
];
try {
await adminClient.clientPolicies.updatePolicy({
policies: newPolicies,
});
setPolicies(newPolicies);
const allClientPolicies = [...(globalPolicies || []), ...newPolicies];
setAllPolicies(allClientPolicies);
setCurrentPolicy(createdPolicy);
form.setValue("profiles", createdPolicy.profiles);
navigate(toEditClientPolicy({ realm, policyName: formValues.name }));
addAlert(t("addClientProfileSuccess"), AlertVariant.success);
}
catch (error) {
addError("addClientProfileError", error);
}
};
const [toggleDisableDialog, DisableConfirm] = useConfirmDialog({
titleKey: "disablePolicyConfirmTitle",
messageKey: "disablePolicyConfirm",
continueButtonLabel: "disable",
onConfirm: () => {
form.setValue("enabled", !form.getValues().enabled);
save();
},
});
if (!policies) {
return _jsx(KeycloakSpinner, {});
}
return (_jsxs(_Fragment, { children: [_jsx(DeleteConditionConfirm, {}), _jsx(DeleteProfileConfirm, {}), _jsx(AddClientProfileModal, { onConfirm: (profiles) => {
addProfiles(profiles.map((item) => item.name));
}, allProfiles: policyProfiles, open: profilesModalOpen, toggleDialog: toggleModal }), _jsx(Controller, { name: "enabled", defaultValue: true, control: form.control, render: ({ field }) => (_jsxs(_Fragment, { children: [_jsx(DisableConfirm, {}), _jsx(DeleteConfirm, {}), _jsx(ViewHeader, { titleKey: showAddConditionsAndProfilesForm || policyName
? policyName
: "createPolicy", badges: [
{
id: "global-client-policy-badge",
text: isGlobalPolicy ? (_jsx(Label, { color: "blue", children: t("global") })) : (""),
},
], divider: true, dropdownItems: (showAddConditionsAndProfilesForm || policyName) &&
!isGlobalPolicy
? [
_jsx(DropdownItem, { value: "delete", onClick: () => {
toggleDeleteDialog();
}, "data-testid": "deleteClientPolicyDropdown", children: t("deleteClientPolicy") }, "delete"),
]
: undefined, isReadOnly: isGlobalPolicy, isEnabled: field.value, onToggle: (value) => {
if (!value) {
toggleDisableDialog();
}
else {
field.onChange(value);
save();
}
} })] })) }), _jsx(PageSection, { variant: "light", children: _jsx(FormAccess, { onSubmit: handleSubmit(save), isHorizontal: true, role: "view-realm", className: "pf-v5-u-mt-lg", children: _jsxs(FormProvider, { ...form, children: [_jsx(TextControl, { name: "name", label: t("name"), rules: {
required: { value: true, message: t("required") },
validate: (value) => policies.some((policy) => policy.name === value)
? t("createClientProfileNameHelperText").toString()
: true,
} }), _jsx(FormGroup, { label: t("description"), fieldId: "kc-description", children: _jsx(KeycloakTextArea, { "aria-label": t("description"), id: "kc-client-policy-description", "data-testid": "client-policy-description", ...form.register("description") }) }), _jsxs(ActionGroup, { children: [_jsx(Button, { variant: "primary", type: "submit", "data-testid": "saveCreatePolicy", isDisabled: !form.formState.isValid || isGlobalPolicy, children: t("save") }), _jsx(Button, { id: "cancelCreatePolicy", variant: "link", onClick: () => (showAddConditionsAndProfilesForm || policyName) &&
!isGlobalPolicy
? reset()
: navigate(toClientPolicies({
realm,
tab: "policies",
})), "data-testid": "cancelCreatePolicy", children: showAddConditionsAndProfilesForm && !isGlobalPolicy
? t("reload")
: t("cancel") })] }), (showAddConditionsAndProfilesForm ||
form.formState.isSubmitted) && (_jsxs(_Fragment, { children: [_jsxs(Flex, { children: [_jsx(FlexItem, { children: _jsxs(Text, { className: "kc-conditions", component: TextVariants.h1, children: [t("conditions"), _jsx(HelpItem, { helpText: t("conditionsHelp"), fieldLabelId: "conditions" })] }) }), !isGlobalPolicy && (_jsx(FlexItem, { align: { default: "alignRight" }, children: _jsx(Button, { id: "addCondition", component: (props) => (_jsx(Link, { ...props, to: toNewClientPolicyCondition({
realm,
policyName: policyName,
}) })), variant: "link", className: "kc-addCondition", "data-testid": "addCondition", icon: _jsx(PlusCircleIcon, {}), children: t("addCondition") }) }))] }), policyConditions.length > 0 ? (_jsx(DataList, { "aria-label": t("conditions"), isCompact: true, children: policyConditions.map((condition, idx) => (_jsx(DataListItem, { "aria-labelledby": "conditions-list-item", id: condition.condition, "data-testid": "conditions-list-item", children: _jsx(DataListItemRow, { "data-testid": "conditions-list-row", children: _jsx(DataListItemCells, { dataListCells: [
_jsxs(DataListCell, { "data-testid": "condition-type", children: [Object.keys(condition.configuration)
.length !== 0 ? (_jsx(Link, { "data-testid": `${condition.condition}-condition-link`, to: toEditClientPolicyCondition({
realm,
conditionName: condition.condition,
policyName: policyName,
}), className: "kc-condition-link", children: condition.condition }, condition.condition)) : (condition.condition), conditionTypes === null || conditionTypes === void 0 ? void 0 : conditionTypes.map((type) => type.id === condition.condition && (_jsxs(_Fragment, { children: [_jsx(HelpItem, { helpText: type.helpText, fieldLabelId: condition.condition }), !isGlobalPolicy && (_jsx(Button, { variant: "link", "aria-label": "remove-condition", isInline: true, icon: _jsx(TrashIcon, { className: "kc-conditionType-trash-icon", "data-testid": `delete-${condition.condition}-condition`, onClick: () => {
toggleDeleteConditionDialog();
setConditionToDelete({
idx: idx,
name: type.id,
});
} }) }))] })))] }, `name-${idx}`),
] }) }) }, `list-item-${idx}`))) })) : (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(Text, { className: "kc-emptyConditions", component: TextVariants.h2, children: t("emptyConditions") })] }))] })), (showAddConditionsAndProfilesForm ||
form.formState.isSubmitted) && (_jsxs(_Fragment, { children: [_jsxs(Flex, { children: [_jsx(FlexItem, { children: _jsxs(Text, { className: "kc-client-profiles", component: TextVariants.h1, children: [t("clientProfiles"), _jsx(HelpItem, { helpText: t("clientProfilesHelp"), fieldLabelId: "clientProfiles" })] }) }), !isGlobalPolicy && (_jsx(FlexItem, { align: { default: "alignRight" }, children: _jsx(Button, { id: "addClientProfile", variant: "link", className: "kc-addClientProfile", "data-testid": "addClientProfile", icon: _jsx(PlusCircleIcon, {}), onClick: toggleModal, children: t("addClientProfile") }) }))] }), policyProfiles.length > 0 ? (_jsx(DataList, { "aria-label": t("profiles"), isCompact: true, children: policyProfiles.map((profile, idx) => (_jsx(DataListItem, { "aria-labelledby": `${profile}-profile-list-item`, id: `${profile}-profile-list-item`, "data-testid": "profile-list-item", children: _jsx(DataListItemRow, { "data-testid": "profile-list-row", children: _jsx(DataListItemCells, { dataListCells: [
_jsxs(DataListCell, { "data-testid": "profile-name", children: [profile && (_jsx(Link, { "data-testid": "profile-name-link", to: toClientProfile({
realm,
profileName: profile,
}), className: "kc-profile-link", children: profile }, profile)), policyProfiles
.filter((type) => type === profile)
.map((type) => {
var _a;
return (_jsxs(_Fragment, { children: [_jsx(HelpItem, { helpText: (_a = clientProfiles.find((profile) => type === profile.name)) === null || _a === void 0 ? void 0 : _a.description, fieldLabelId: profile }), !isGlobalPolicy && (_jsx(Button, { variant: "link", "aria-label": "remove-client-profile", isInline: true, icon: _jsx(TrashIcon, { className: "kc-conditionType-trash-icon", "data-testid": "deleteClientProfileDropdown", onClick: () => {
toggleDeleteProfileDialog();
setProfileToDelete({
idx: idx,
name: type,
});
} }) }))] }));
})] }, "name"),
] }) }) }, profile))) })) : (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(Text, { className: "kc-emptyClientProfiles", component: TextVariants.h2, children: t("emptyProfiles") })] }))] }))] }) }) })] }));
}
//# sourceMappingURL=NewClientPolicy.js.map