@keycloakify/keycloak-admin-ui
Version:
Repackaged Keycloak Admin UI
174 lines • 10.8 kB
JavaScript
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useAlerts } from "../../ui-shared";
import { AlertVariant, Button, ButtonVariant, Dropdown, DropdownItem, DropdownList, MenuToggle, ToolbarItem, } from "@patternfly/react-core";
import { EllipsisVIcon } from "@patternfly/react-icons";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { useAdminClient } from "../../admin-client";
import { ChangeTypeDropdown } from "../../client-scopes/ChangeTypeDropdown";
import { SearchDropdown, SearchToolbar, nameFilter, typeFilter, } from "../../client-scopes/details/SearchFilter";
import { AllClientScopes, CellDropdown, ClientScope, addClientScope, changeClientScope, removeClientScope, } from "../../components/client-scope/ClientScopeTypes";
import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog";
import { ListEmptyState } from "../../ui-shared";
import { KeycloakDataTable } from "../../ui-shared";
import { useAccess } from "../../context/access/Access";
import { useRealm } from "../../context/realm-context/RealmContext";
import { translationFormatter } from "../../utils/translationFormatter";
import useLocaleSort, { mapByKey } from "../../utils/useLocaleSort";
import { toDedicatedScope } from "../../clients/routes/DedicatedScopeDetails";
import { AddScopeDialog } from "../../clients/scopes/AddScopeDialog";
import "./client-scopes.css";
const DEDICATED_ROW = "dedicated";
const TypeSelector = ({ clientId, refresh, fineGrainedAccess, ...scope }) => {
const { adminClient } = useAdminClient();
const { t } = useTranslation();
const { addAlert, addError } = useAlerts();
const { hasAccess } = useAccess();
const isDedicatedRow = (value) => value.id === DEDICATED_ROW;
const isManager = hasAccess("manage-clients") || fineGrainedAccess;
return (_jsx(CellDropdown, { isDisabled: isDedicatedRow(scope) || !isManager, clientScope: scope, type: scope.type, onSelect: async (value) => {
try {
await changeClientScope(adminClient, clientId, scope, scope.type, value);
addAlert(t("clientScopeSuccess"), AlertVariant.success);
refresh();
}
catch (error) {
addError("clientScopeError", error);
}
} }));
};
export const ClientScopes = ({ clientId, protocol, clientName, fineGrainedAccess, }) => {
var _a;
const { adminClient } = useAdminClient();
const { t } = useTranslation();
const { addAlert, addError } = useAlerts();
const { realm } = useRealm();
const localeSort = useLocaleSort();
const [searchType, setSearchType] = useState("name");
const [searchTypeType, setSearchTypeType] = useState(AllClientScopes.none);
const [addDialogOpen, setAddDialogOpen] = useState(false);
const [rest, setRest] = useState();
const [selectedRows, setSelectedRowState] = useState([]);
const setSelectedRows = (rows) => setSelectedRowState(rows.filter(({ id }) => id !== DEDICATED_ROW));
const [kebabOpen, setKebabOpen] = useState(false);
const [key, setKey] = useState(0);
const refresh = () => setKey(key + 1);
const isDedicatedRow = (value) => value.id === DEDICATED_ROW;
const { hasAccess } = useAccess();
const isManager = hasAccess("manage-clients") || fineGrainedAccess;
const isViewer = hasAccess("view-clients") || fineGrainedAccess;
const loader = async (first, max, search) => {
const defaultClientScopes = await adminClient.clients.listDefaultClientScopes({ id: clientId });
const optionalClientScopes = await adminClient.clients.listOptionalClientScopes({ id: clientId });
const clientScopes = await adminClient.clientScopes.find();
const find = (id) => clientScopes.find((clientScope) => id === clientScope.id);
const optional = optionalClientScopes.map((c) => {
const scope = find(c.id);
const row = {
...c,
type: ClientScope.optional,
description: scope === null || scope === void 0 ? void 0 : scope.description,
};
return row;
});
const defaultScopes = defaultClientScopes.map((c) => {
const scope = find(c.id);
const row = {
...c,
type: ClientScope.default,
description: scope === null || scope === void 0 ? void 0 : scope.description,
};
return row;
});
let rows = [...optional, ...defaultScopes];
const names = rows.map((row) => row.name);
setRest(clientScopes
.filter((scope) => !names.includes(scope.name))
.filter((scope) => scope.protocol === protocol));
rows = localeSort(rows, mapByKey("name"));
if (isViewer) {
rows.unshift({
id: DEDICATED_ROW,
name: t("dedicatedScopeName", { clientName }),
type: AllClientScopes.none,
description: t("dedicatedScopeDescription"),
});
}
const filter = searchType === "name" ? nameFilter(search) : typeFilter(searchTypeType);
const firstNum = Number(first);
return rows.filter(filter).slice(firstNum, firstNum + Number(max));
};
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
titleKey: t("deleteClientScope", {
count: selectedRows.length,
name: (_a = selectedRows[0]) === null || _a === void 0 ? void 0 : _a.name,
}),
messageKey: "deleteConfirmClientScopes",
continueButtonLabel: "delete",
continueButtonVariant: ButtonVariant.danger,
onConfirm: async () => {
try {
await removeClientScope(adminClient, clientId, selectedRows[0], selectedRows[0].type);
addAlert(t("clientScopeRemoveSuccess"), AlertVariant.success);
refresh();
}
catch (error) {
addError("clientScopeRemoveError", error);
}
},
});
return (_jsxs(_Fragment, { children: [rest && (_jsx(AddScopeDialog, { clientScopes: rest, clientName: clientName, open: addDialogOpen, toggleDialog: () => setAddDialogOpen(!addDialogOpen), onAdd: async (scopes) => {
try {
await Promise.all(scopes.map(async (scope) => await addClientScope(adminClient, clientId, scope.scope, scope.type)));
addAlert(t("clientScopeSuccess"), AlertVariant.success);
refresh();
}
catch (error) {
addError("clientScopeError", error);
}
} })), _jsx(KeycloakDataTable, { loader: loader, ariaLabelKey: `clientScopeList-${key}`, searchPlaceholderKey: searchType === "name" ? "searchByName" : undefined, canSelectAll: true, isPaginated: true, isSearching: searchType === "type", onSelect: (rows) => setSelectedRows([...rows]), searchTypeComponent: _jsx(SearchDropdown, { searchType: searchType, onSelect: (searchType) => setSearchType(searchType) }), toolbarItem: _jsxs(_Fragment, { children: [_jsx(SearchToolbar, { searchType: searchType, type: searchTypeType, onSelect: (searchType) => setSearchType(searchType), onType: (value) => {
setSearchTypeType(value);
refresh();
} }), isManager && (_jsxs(_Fragment, { children: [_jsx(DeleteConfirm, {}), _jsx(ToolbarItem, { children: _jsx(Button, { onClick: () => setAddDialogOpen(true), children: t("addClientScope") }) }), _jsx(ToolbarItem, { children: _jsx(ChangeTypeDropdown, { clientId: clientId, selectedRows: selectedRows, refresh: refresh }) }), _jsx(ToolbarItem, { children: _jsx(Dropdown, { onOpenChange: (isOpen) => setKebabOpen(isOpen), toggle: (ref) => (_jsx(MenuToggle, { "data-testid": "kebab", "aria-label": "Kebab toggle", ref: ref, variant: "plain", onClick: () => setKebabOpen(!kebabOpen), isExpanded: kebabOpen, children: _jsx(EllipsisVIcon, {}) })), isOpen: kebabOpen, children: _jsx(DropdownList, { children: _jsx(DropdownItem, { isDisabled: selectedRows.length === 0, onClick: async () => {
try {
await Promise.all(selectedRows.map((row) => removeClientScope(adminClient, clientId, { ...row }, row.type)));
setKebabOpen(false);
setSelectedRows([]);
addAlert(t("clientScopeRemoveSuccess"));
refresh();
}
catch (error) {
addError("clientScopeRemoveError", error);
}
}, children: t("remove") }, "deleteAll") }) }) })] }))] }), columns: [
{
name: "name",
displayKey: "assignedClientScope",
cellRenderer: (row) => {
if (isDedicatedRow(row)) {
return (_jsx(Link, { to: toDedicatedScope({ realm, clientId }), children: row.name }));
}
return row.name;
},
},
{
name: "type",
displayKey: "assignedType",
cellRenderer: (row) => (_jsx(TypeSelector, { clientId: clientId, refresh: refresh, ...row })),
},
{ name: "description", cellFormatters: [translationFormatter(t)] },
], actions: isManager
? [
{
title: t("remove"),
onRowClick: async (row) => {
setSelectedRows([row]);
toggleDeleteDialog();
return true;
},
},
]
: [], emptyState: _jsx(ListEmptyState, { message: t("emptyClientScopes"), instructions: t("emptyClientScopesInstructions"), primaryActionText: t("emptyClientScopesPrimaryAction"), onPrimaryAction: () => setAddDialogOpen(true) }) }, key)] }));
};
//# sourceMappingURL=ClientScopes.js.map