@keycloakify/keycloak-admin-ui
Version:
Repackaged Keycloak Admin UI
250 lines • 19.1 kB
JavaScript
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