UNPKG

@keycloakify/keycloak-admin-ui

Version:
250 lines 19.1 kB
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; import { useAlerts, useFetch } from "../ui-shared"; import { AlertVariant, ButtonVariant, Divider, DropdownItem, Label, PageSection, Tab, TabTitleText, Tooltip, } from "@patternfly/react-core"; import { InfoCircleIcon } from "@patternfly/react-icons"; import { cloneDeep, sortBy } from "lodash-es"; import { useMemo, useState } from "react"; import { Controller, FormProvider, useForm, useWatch } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import { useAdminClient } from "../admin-client"; import { ConfirmDialogModal, useConfirmDialog, } from "../components/confirm-dialog/ConfirmDialog"; import { DownloadDialog } from "../components/download-dialog/DownloadDialog"; import { KeycloakSpinner } from "../ui-shared"; import { PermissionsTab } from "../components/permission-tab/PermissionTab"; import { RolesList } from "../components/roles-list/RolesList"; import { RoutableTabs, useRoutableTab, } from "../components/routable-tabs/RoutableTabs"; import { ViewHeader, } from "../components/view-header/ViewHeader"; import { useAccess } from "../context/access/Access"; import { useRealm } from "../context/realm-context/RealmContext"; import { convertAttributeNameToForm, convertFormValuesToObject, convertToFormValues, exportClient, } from "../util"; import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled"; import { useParams } from "../utils/useParams"; import useToggle from "../utils/useToggle"; import { AdvancedTab } from "../clients/AdvancedTab"; import { ClientSessions } from "../clients/ClientSessions"; import { ClientSettings } from "../clients/ClientSettings"; import { AuthorizationEvaluate } from "../clients/authorization/AuthorizationEvaluate"; import { AuthorizationExport } from "../clients/authorization/AuthorizationExport"; import { AuthorizationPermissions } from "../clients/authorization/Permissions"; import { AuthorizationPolicies } from "../clients/authorization/Policies"; import { AuthorizationResources } from "../clients/authorization/Resources"; import { AuthorizationScopes } from "../clients/authorization/Scopes"; import { AuthorizationSettings } from "../clients/authorization/Settings"; import { Credentials } from "../clients/credentials/Credentials"; import { Keys } from "../clients/keys/Keys"; import { SamlKeys } from "../clients/keys/SamlKeys"; import { toAuthorizationTab, } from "../clients/routes/AuthenticationTab"; import { toClient } from "../clients/routes/Client"; import { toClientRole } from "../clients/routes/ClientRole"; import { toClientScopesTab } from "../clients/routes/ClientScopeTab"; import { toClients } from "../clients/routes/Clients"; import { toCreateRole } from "../clients/routes/NewRole"; import { ClientScopes } from "../clients/scopes/ClientScopes"; import { EvaluateScopes } from "../clients/scopes/EvaluateScopes"; import { ServiceAccount } from "../clients/service-account/ServiceAccount"; import { getProtocolName, isRealmClient } from "../clients/utils"; const ClientDetailHeader = ({ onChange, value, save, client, toggleDownloadDialog, toggleDeleteDialog, }) => { var _a; const { t } = useTranslation(); const [toggleDisableDialog, DisableConfirm] = useConfirmDialog({ titleKey: "disableConfirmClientTitle", messageKey: "disableConfirmClient", continueButtonLabel: "disable", onConfirm: () => { onChange(!value); save(); }, }); const badges = useMemo(() => { var _a; const protocolName = getProtocolName(t, (_a = client.protocol) !== null && _a !== void 0 ? _a : "openid-connect"); const text = client.bearerOnly ? (_jsx(Tooltip, { "data-testid": "bearer-only-explainer-tooltip", content: t("explainBearerOnly"), children: _jsx(Label, { "data-testid": "bearer-only-explainer-label", icon: _jsx(InfoCircleIcon, {}), children: protocolName }) })) : (_jsx(Label, { children: protocolName })); return [{ text }]; }, [client, t]); const { hasAccess } = useAccess(); const isManager = hasAccess("manage-clients") || ((_a = client.access) === null || _a === void 0 ? void 0 : _a.configure); const dropdownItems = [ _jsx(DropdownItem, { onClick: toggleDownloadDialog, children: t("downloadAdapterConfig") }, "download"), _jsx(DropdownItem, { onClick: () => exportClient(client), children: t("export") }, "export"), ...(!isRealmClient(client) && isManager ? [ _jsx(Divider, {}, "divider"), _jsx(DropdownItem, { "data-testid": "delete-client", onClick: toggleDeleteDialog, children: t("delete") }, "delete"), ] : []), ]; return (_jsxs(_Fragment, { children: [_jsx(DisableConfirm, {}), _jsx(ViewHeader, { titleKey: client.clientId, subKey: "clientsExplain", badges: badges, divider: false, isReadOnly: !isManager, helpTextKey: "enableDisable", dropdownItems: dropdownItems, isEnabled: value, onToggle: (value) => { if (!value) { toggleDisableDialog(); } else { onChange(value); save(); } } })] })); }; export default function ClientDetails() { var _a, _b, _c, _d, _e, _f; const { adminClient } = useAdminClient(); const { t } = useTranslation(); const { addAlert, addError } = useAlerts(); const { realm } = useRealm(); const { hasAccess } = useAccess(); const isFeatureEnabled = useIsFeatureEnabled(); const hasManageAuthorization = hasAccess("manage-authorization"); const hasViewAuthorization = hasAccess("view-authorization"); const hasManageClients = hasAccess("manage-clients"); const hasViewClients = hasAccess("view-clients"); const hasViewUsers = hasAccess("view-users"); const permissionsEnabled = isFeatureEnabled(Feature.AdminFineGrainedAuthz) && (hasManageAuthorization || hasViewAuthorization); const navigate = useNavigate(); const [downloadDialogOpen, toggleDownloadDialogOpen] = useToggle(); const [changeAuthenticatorOpen, toggleChangeAuthenticatorOpen] = useToggle(); const form = useForm(); const { clientId } = useParams(); const [key, setKey] = useState(0); const clientAuthenticatorType = useWatch({ control: form.control, name: "clientAuthenticatorType", defaultValue: "client-secret", }); const [client, setClient] = useState(); const loader = async () => { const roles = await adminClient.clients.listRoles({ id: clientId }); return sortBy(roles, (role) => { var _a; return (_a = role.name) === null || _a === void 0 ? void 0 : _a.toUpperCase(); }); }; const useTab = (tab) => useRoutableTab(toClient({ realm, clientId, tab, })); const settingsTab = useTab("settings"); const keysTab = useTab("keys"); const credentialsTab = useTab("credentials"); const rolesTab = useTab("roles"); const clientScopesTab = useTab("clientScopes"); const authorizationTab = useTab("authorization"); const serviceAccountTab = useTab("serviceAccount"); const sessionsTab = useTab("sessions"); const permissionsTab = useTab("permissions"); const advancedTab = useTab("advanced"); const useClientScopesTab = (tab) => useRoutableTab(toClientScopesTab({ realm, clientId, tab, })); const clientScopesSetupTab = useClientScopesTab("setup"); const clientScopesEvaluateTab = useClientScopesTab("evaluate"); const useAuthorizationTab = (tab) => useRoutableTab(toAuthorizationTab({ realm, clientId, tab, })); const authorizationSettingsTab = useAuthorizationTab("settings"); const authorizationResourcesTab = useAuthorizationTab("resources"); const authorizationScopesTab = useAuthorizationTab("scopes"); const authorizationPoliciesTab = useAuthorizationTab("policies"); const authorizationPermissionsTab = useAuthorizationTab("permissions"); const authorizationEvaluateTab = useAuthorizationTab("evaluate"); const authorizationExportTab = useAuthorizationTab("export"); const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ titleKey: "clientDeleteConfirmTitle", messageKey: "clientDeleteConfirm", continueButtonLabel: "delete", continueButtonVariant: ButtonVariant.danger, onConfirm: async () => { try { await adminClient.clients.del({ id: clientId }); addAlert(t("clientDeletedSuccess"), AlertVariant.success); navigate(toClients({ realm })); } catch (error) { addError("clientDeleteError", error); } }, }); const setupForm = (client) => { var _a; form.reset({ ...client }); convertToFormValues(client, form.setValue); if ((_a = client.attributes) === null || _a === void 0 ? void 0 : _a["acr.loa.map"]) { form.setValue(convertAttributeNameToForm("attributes.acr.loa.map"), // @ts-ignore Object.entries(JSON.parse(client.attributes["acr.loa.map"])).flatMap(([key, value]) => ({ key, value }))); } }; useFetch(() => adminClient.clients.findOne({ id: clientId }), (fetchedClient) => { if (!fetchedClient) { throw new Error(t("notFound")); } setClient(cloneDeep(fetchedClient)); setupForm(fetchedClient); }, [clientId, key]); const save = async ({ confirmed = false, messageKey = "clientSaveSuccess" } = { confirmed: false, messageKey: "clientSaveSuccess", }) => { var _a, _b; if (!(await form.trigger())) { return; } if (!(client === null || client === void 0 ? void 0 : client.publicClient) && (client === null || client === void 0 ? void 0 : client.clientAuthenticatorType) !== clientAuthenticatorType && !confirmed) { toggleChangeAuthenticatorOpen(); return; } const values = convertFormValuesToObject(form.getValues()); const submittedClient = convertFormValuesToObject(values); if ((_a = submittedClient.attributes) === null || _a === void 0 ? void 0 : _a["acr.loa.map"]) { submittedClient.attributes["acr.loa.map"] = JSON.stringify(Object.fromEntries(submittedClient.attributes["acr.loa.map"] .filter(({ key }) => key !== "") .map(({ key, value }) => [key, value]))); } try { const newClient = { ...client, ...submittedClient, }; newClient.clientId = (_b = newClient.clientId) === null || _b === void 0 ? void 0 : _b.trim(); await adminClient.clients.update({ id: clientId }, newClient); setupForm(newClient); setClient(newClient); addAlert(t(messageKey), AlertVariant.success); } catch (error) { addError("clientSaveError", error); } }; if (!client) { return _jsx(KeycloakSpinner, {}); } return (_jsxs(_Fragment, { children: [_jsx(ConfirmDialogModal, { continueButtonLabel: "yes", cancelButtonLabel: "no", titleKey: t("changeAuthenticatorConfirmTitle", { clientAuthenticatorType: clientAuthenticatorType, }), open: changeAuthenticatorOpen, toggleDialog: toggleChangeAuthenticatorOpen, onConfirm: () => save({ confirmed: true }), children: _jsx(_Fragment, { children: t("changeAuthenticatorConfirm", { clientAuthenticatorType: clientAuthenticatorType, }) }) }), _jsx(DeleteConfirm, {}), downloadDialogOpen && (_jsx(DownloadDialog, { id: client.id, protocol: client.protocol, open: true, toggleDialog: toggleDownloadDialogOpen })), _jsx(Controller, { name: "enabled", control: form.control, defaultValue: true, render: ({ field }) => (_jsx(ClientDetailHeader, { value: field.value, onChange: field.onChange, client: client, save: save, toggleDeleteDialog: toggleDeleteDialog, toggleDownloadDialog: toggleDownloadDialogOpen })) }), _jsx(PageSection, { variant: "light", className: "pf-v5-u-p-0", children: _jsx(FormProvider, { ...form, children: _jsxs(RoutableTabs, { "data-testid": "client-tabs", "aria-label": "client-tabs", isBox: true, mountOnEnter: true, children: [_jsx(Tab, { id: "settings", "data-testid": "clientSettingsTab", title: _jsx(TabTitleText, { children: t("settings") }), ...settingsTab, children: _jsx(ClientSettings, { client: client, save: () => save(), reset: () => setupForm(client) }) }), ((!client.publicClient && !isRealmClient(client)) || client.protocol === "saml") && (_jsxs(Tab, { id: "keys", "data-testid": "keysTab", title: _jsx(TabTitleText, { children: t("keys") }), ...keysTab, children: [client.protocol === "openid-connect" && (_jsx(Keys, { clientId: clientId, save: save, hasConfigureAccess: (_a = client.access) === null || _a === void 0 ? void 0 : _a.configure })), client.protocol === "saml" && (_jsx(SamlKeys, { clientId: clientId, save: save }))] })), !client.publicClient && !isRealmClient(client) && (hasViewClients || ((_b = client.access) === null || _b === void 0 ? void 0 : _b.configure) || ((_c = client.access) === null || _c === void 0 ? void 0 : _c.view)) && (_jsx(Tab, { id: "credentials", title: _jsx(TabTitleText, { children: t("credentials") }), ...credentialsTab, children: _jsx(Credentials, { client: client, save: save, refresh: () => setKey(key + 1) }, key) })), _jsx(Tab, { id: "roles", "data-testid": "rolesTab", title: _jsx(TabTitleText, { children: t("roles") }), ...rolesTab, children: _jsx(RolesList, { loader: loader, paginated: false, messageBundle: "client", toCreate: toCreateRole({ realm, clientId: client.id }), toDetail: (roleId) => toClientRole({ realm, clientId: client.id, id: roleId, tab: "details", }), isReadOnly: !(hasManageClients || ((_d = client.access) === null || _d === void 0 ? void 0 : _d.configure)) }) }), !isRealmClient(client) && !client.bearerOnly && (_jsx(Tab, { id: "clientScopes", "data-testid": "clientScopesTab", title: _jsx(TabTitleText, { children: t("clientScopes") }), ...clientScopesTab, children: _jsxs(RoutableTabs, { defaultLocation: toClientScopesTab({ realm, clientId, tab: "setup", }), children: [_jsx(Tab, { id: "setup", "data-testid": "clientScopesSetupTab", title: _jsx(TabTitleText, { children: t("setup") }), ...clientScopesSetupTab, children: _jsx(ClientScopes, { clientName: client.clientId, clientId: clientId, protocol: client.protocol, fineGrainedAccess: (_e = client.access) === null || _e === void 0 ? void 0 : _e.manage }) }), _jsx(Tab, { id: "evaluate", "data-testid": "clientScopesEvaluateTab", title: _jsx(TabTitleText, { children: t("evaluate") }), ...clientScopesEvaluateTab, children: _jsx(EvaluateScopes, { clientId: clientId, protocol: client.protocol }) })] }) })), client.authorizationServicesEnabled && (hasManageAuthorization || hasViewAuthorization) && (_jsx(Tab, { id: "authorization", "data-testid": "authorizationTab", title: _jsx(TabTitleText, { children: t("authorization") }), ...authorizationTab, children: _jsxs(RoutableTabs, { mountOnEnter: true, unmountOnExit: true, defaultLocation: toAuthorizationTab({ realm, clientId, tab: "settings", }), children: [_jsx(Tab, { id: "settings", "data-testid": "authorizationSettings", title: _jsx(TabTitleText, { children: t("settings") }), ...authorizationSettingsTab, children: _jsx(AuthorizationSettings, { clientId: clientId }) }), _jsx(Tab, { id: "resources", "data-testid": "authorizationResources", title: _jsx(TabTitleText, { children: t("resources") }), ...authorizationResourcesTab, children: _jsx(AuthorizationResources, { clientId: clientId, isDisabled: !hasManageAuthorization }) }), _jsx(Tab, { id: "scopes", "data-testid": "authorizationScopes", title: _jsx(TabTitleText, { children: t("scopes") }), ...authorizationScopesTab, children: _jsx(AuthorizationScopes, { clientId: clientId, isDisabled: !hasManageAuthorization }) }), _jsx(Tab, { id: "policies", "data-testid": "authorizationPolicies", title: _jsx(TabTitleText, { children: t("policies") }), ...authorizationPoliciesTab, children: _jsx(AuthorizationPolicies, { clientId: clientId, isDisabled: !hasManageAuthorization }) }), _jsx(Tab, { id: "permissions", "data-testid": "authorizationPermissions", title: _jsx(TabTitleText, { children: t("permissions") }), ...authorizationPermissionsTab, children: _jsx(AuthorizationPermissions, { clientId: clientId, isDisabled: !hasManageAuthorization }) }), hasViewUsers && (_jsx(Tab, { id: "evaluate", "data-testid": "authorizationEvaluate", title: _jsx(TabTitleText, { children: t("evaluate") }), ...authorizationEvaluateTab, children: _jsx(AuthorizationEvaluate, { client: client, save: save }) })), hasAccess("manage-authorization") && (_jsx(Tab, { id: "export", "data-testid": "authorizationExport", title: _jsx(TabTitleText, { children: t("export") }), ...authorizationExportTab, children: _jsx(AuthorizationExport, {}) }))] }) })), client.serviceAccountsEnabled && hasViewUsers && (_jsx(Tab, { id: "serviceAccount", "data-testid": "serviceAccountTab", title: _jsx(TabTitleText, { children: t("serviceAccount") }), ...serviceAccountTab, children: _jsx(ServiceAccount, { client: client }) })), _jsx(Tab, { id: "sessions", "data-testid": "sessionsTab", title: _jsx(TabTitleText, { children: t("sessions") }), ...sessionsTab, children: _jsx(ClientSessions, { client: client }) }), permissionsEnabled && (hasManageClients || ((_f = client.access) === null || _f === void 0 ? void 0 : _f.manage)) && (_jsx(Tab, { id: "permissions", "data-testid": "permissionsTab", title: _jsx(TabTitleText, { children: t("permissions") }), ...permissionsTab, children: _jsx(PermissionsTab, { id: client.id, type: "clients" }) })), _jsx(Tab, { id: "advanced", "data-testid": "advancedTab", title: _jsx(TabTitleText, { children: t("advanced") }), ...advancedTab, children: _jsx(AdvancedTab, { save: save, client: client }) })] }) }) })] })); } //# sourceMappingURL=ClientDetails.js.map