@keycloakify/keycloak-admin-ui
Version:
Repackaged Keycloak Admin UI
135 lines • 7.46 kB
JavaScript
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { KeycloakSelect, SelectVariant, useFetch, } from "../../ui-shared";
import { Button, ButtonVariant, Chip, ChipGroup, SelectOption, } from "@patternfly/react-core";
import { useState } from "react";
import { Controller, useFormContext, } 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 { useRealm } from "../../context/realm-context/RealmContext";
import useToggle from "../../utils/useToggle";
import { toCreatePolicy } from "../../clients/routes/NewPolicy";
import { toPolicyDetails } from "../../clients/routes/PolicyDetails";
import { toResourceDetails } from "../../clients/routes/Resource";
import { NewPolicyDialog } from "../../clients/authorization/NewPolicyDialog";
const typeMapping = {
resources: {
searchFunction: "listResources",
fetchFunction: "getAssociatedResources",
},
policies: {
searchFunction: "listPolicies",
fetchFunction: "getAssociatedPolicies",
},
};
export const ResourcesPolicySelect = ({ name, clientId, permissionId, variant = SelectVariant.typeaheadMulti, preSelected, isRequired = false, }) => {
const { adminClient } = useAdminClient();
const { realm } = useRealm();
const { t } = useTranslation();
const navigate = useNavigate();
const { control, formState: { errors, isDirty }, } = useFormContext();
const [items, setItems] = useState([]);
const [search, setSearch] = useState("");
const [open, setOpen] = useState(false);
const [createPolicyDialog, toggleCreatePolicyDialog] = useToggle();
const [policyProviders, setPolicyProviders] = useState();
const [onUnsavedChangesConfirm, setOnUnsavedChangesConfirm] = useState();
const functions = typeMapping[name];
const convert = (p) => ({
id: "_id" in p ? p._id : "id" in p ? p.id : undefined,
name: p.name,
type: p.type,
});
useFetch(async () => {
const params = Object.assign({ id: clientId, first: 0, max: 10, permission: "false" }, search === "" ? null : { name: search });
return await Promise.all([
adminClient.clients.listPolicyProviders({ id: clientId }),
adminClient.clients[functions.searchFunction](params),
permissionId
? adminClient.clients[functions.fetchFunction]({
id: clientId,
permissionId,
})
: Promise.resolve([]),
]);
}, ([providers, ...policies]) => {
setPolicyProviders(providers.filter((p) => p.type !== "resource" && p.type !== "scope"));
setItems(policies
.flat()
.filter((r) => typeof r !== "string")
.map(convert)
.filter(({ id }, index, self) => index === self.findIndex(({ id: otherId }) => id === otherId)));
}, [search]);
const [toggleUnsavedChangesDialog, UnsavedChangesConfirm] = useConfirmDialog({
titleKey: t("unsavedChangesTitle"),
messageKey: t("unsavedChangesConfirm"),
continueButtonLabel: t("continue"),
continueButtonVariant: ButtonVariant.danger,
onConfirm: () => onUnsavedChangesConfirm === null || onUnsavedChangesConfirm === void 0 ? void 0 : onUnsavedChangesConfirm(),
});
const to = (policy) => name === "policies"
? toPolicyDetails({
realm: realm,
id: clientId,
policyId: policy.id,
policyType: policy.type,
})
: toResourceDetails({
realm,
id: clientId,
resourceId: policy.id,
});
const toSelectOptions = () => items.map((p) => (_jsx(SelectOption, { value: p.id, children: p.name }, p.id)));
const toChipGroupItems = (field) => {
var _a;
return (_jsx(ChipGroup, { children: (_a = field.value) === null || _a === void 0 ? void 0 : _a.map((permissionId) => {
const item = items.find((permission) => permission.id === permissionId);
if (!item)
return;
const route = to(item);
return (_jsx(Chip, { onClick: () => {
var _a;
field.onChange((_a = field.value) === null || _a === void 0 ? void 0 : _a.filter((id) => id !== item.id));
}, children: _jsx(Link, { to: route, onClick: (event) => {
if (isDirty) {
event.preventDefault();
setOnUnsavedChangesConfirm(() => () => navigate(route));
toggleUnsavedChangesDialog();
}
}, children: item.name }) }, item.id));
}) }));
};
return (_jsxs(_Fragment, { children: [_jsx(UnsavedChangesConfirm, {}), createPolicyDialog && (_jsx(NewPolicyDialog, { policyProviders: policyProviders, onSelect: (p) => {
navigate(toCreatePolicy({ id: clientId, realm, policyType: p.type }));
}, toggleDialog: toggleCreatePolicyDialog })), _jsx(Controller, { name: name, defaultValue: preSelected ? [preSelected] : [], control: control, rules: { validate: (value) => !isRequired || value.length > 0 }, render: ({ field }) => (_jsx(KeycloakSelect, { toggleId: name, variant: variant, onToggle: (val) => setOpen(val), onFilter: (filter) => {
setSearch(filter);
return toSelectOptions();
}, onClear: () => {
field.onChange([]);
setSearch("");
}, selections: field.value, onSelect: (selectedValue) => {
var _a;
const option = selectedValue.toString();
if (variant === SelectVariant.typeaheadMulti) {
const changedValue = ((_a = field.value) === null || _a === void 0 ? void 0 : _a.find((p) => p === option))
? field.value.filter((p) => p !== option)
: [...field.value, option];
field.onChange(changedValue);
}
else {
field.onChange([option]);
}
setSearch("");
}, isOpen: open, "aria-label": t(name), isDisabled: !!preSelected, validated: errors[name] ? "error" : "default", typeAheadAriaLabel: t(name), chipGroupComponent: toChipGroupItems(field), footer: name === "policies" ? (_jsx(Button, { variant: "link", isInline: true, onClick: () => {
if (isDirty) {
setOpen(false);
setOnUnsavedChangesConfirm(() => toggleCreatePolicyDialog);
toggleUnsavedChangesDialog();
}
else {
toggleCreatePolicyDialog();
}
}, children: t("createPolicy") })) : undefined, children: toSelectOptions() })) })] }));
};
//# sourceMappingURL=ResourcesPolicySelect.js.map