UNPKG

@keycloakify/keycloak-admin-ui

Version:
360 lines 24.7 kB
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