UNPKG

@keycloakify/keycloak-admin-ui

Version:
214 lines 11.3 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { KeycloakDataTable, KeycloakSpinner, ListEmptyState, useAlerts, useFetch, } from "../../ui-shared"; import { AlertVariant, Button, ButtonVariant, Chip, ChipGroup, EmptyState, FlexItem, Label, Text, TextContent, Toolbar, ToolbarContent, ToolbarItem, Tooltip, } from "@patternfly/react-core"; import { ExclamationCircleIcon, InfoCircleIcon, WarningTriangleIcon, } from "@patternfly/react-icons"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { Link, useNavigate } from "react-router-dom"; import { useAdminClient } from "../../admin-client"; import { fetchRealmInfo } from "../../context/auth/admin-ui-endpoint"; import { useRealm } from "../../context/realm-context/RealmContext"; import { toAddUser } from "../../user/routes/AddUser"; import { toUser } from "../../user/routes/User"; import { emptyFormatter } from "../../util"; import { useConfirmDialog } from "../../components/confirm-dialog/ConfirmDialog"; import { findUsers } from "../../components/role-mapping/resource"; import { UserDataTableToolbarItems } from "../../components/users/UserDataTableToolbarItems"; const UserDetailLink = (user) => { var _a; const { t } = useTranslation(); const { realm } = useRealm(); return (_jsxs(_Fragment, { children: [_jsxs(Link, { to: toUser({ realm, id: user.id, tab: "settings" }), children: [user.username, _jsx(StatusRow, { user: user })] }), ((_a = user.attributes) === null || _a === void 0 ? void 0 : _a["is_temporary_admin"][0]) === "true" && (_jsx(Tooltip, { content: t("temporaryAdmin"), children: _jsx(WarningTriangleIcon, { className: "pf-v5-u-ml-sm", id: "temporary-admin-label" }) }))] })); }; const StatusRow = ({ user }) => { var _a; const { t } = useTranslation(); return (_jsxs(_Fragment, { children: [!user.enabled && (_jsx(Label, { color: "red", icon: _jsx(InfoCircleIcon, {}), children: t("disabled") })), ((_a = user.bruteForceStatus) === null || _a === void 0 ? void 0 : _a.disabled) && (_jsx(Label, { color: "orange", icon: _jsx(WarningTriangleIcon, {}), children: t("temporaryLocked") }))] })); }; const ValidatedEmail = (user) => { const { t } = useTranslation(); return (_jsxs(_Fragment, { children: [!user.emailVerified && (_jsx(Tooltip, { content: t("notVerified"), children: _jsx(ExclamationCircleIcon, { className: "keycloak__user-section__email-verified" }) })), " ", emptyFormatter()(user.email)] })); }; export function UserDataTable() { const { adminClient } = useAdminClient(); const { t } = useTranslation(); const { addAlert, addError } = useAlerts(); const { realm: realmName, realmRepresentation: realm } = useRealm(); const navigate = useNavigate(); const [uiRealmInfo, setUiRealmInfo] = useState({}); const [searchUser, setSearchUser] = useState(""); const [selectedRows, setSelectedRows] = useState([]); const [searchType, setSearchType] = useState("default"); const [searchDropdownOpen, setSearchDropdownOpen] = useState(false); const [activeFilters, setActiveFilters] = useState({ exact: false, userAttribute: [], }); const [profile, setProfile] = useState({}); const [query, setQuery] = useState(""); const [key, setKey] = useState(0); const refresh = () => setKey(key + 1); useFetch(async () => { try { return await Promise.all([ fetchRealmInfo(adminClient), adminClient.users.getProfile(), ]); } catch (_a) { return [{}, {}]; } }, ([uiRealmInfo, profile]) => { setUiRealmInfo(uiRealmInfo); setProfile(profile); }, []); const loader = async (first, max, search) => { const params = { first: first, max: max, q: query, exact: activeFilters.exact, }; const searchParam = search || searchUser || ""; if (searchParam) { params.search = searchParam; } if (!listUsers && !(params.search || params.q)) { return []; } try { return await findUsers(adminClient, { briefRepresentation: true, ...params, }); } catch (error) { if (uiRealmInfo.userProfileProvidersEnabled) { addError("noUsersFoundErrorStorage", error); } else { addError("noUsersFoundError", error); } return []; } }; const [toggleUnlockUsersDialog, UnlockUsersConfirm] = useConfirmDialog({ titleKey: "unlockAllUsers", messageKey: "unlockUsersConfirm", continueButtonLabel: "unlock", onConfirm: async () => { try { await adminClient.attackDetection.delAll(); refresh(); addAlert(t("unlockUsersSuccess"), AlertVariant.success); } catch (error) { addError("unlockUsersError", error); } }, }); const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ titleKey: "deleteConfirmUsers", messageKey: t("deleteConfirmDialog", { count: selectedRows.length }), continueButtonLabel: "delete", continueButtonVariant: ButtonVariant.danger, onConfirm: async () => { try { for (const user of selectedRows) { await adminClient.users.del({ id: user.id }); } setSelectedRows([]); clearAllFilters(); addAlert(t("userDeletedSuccess"), AlertVariant.success); } catch (error) { addError("userDeletedError", error); } }, }); const goToCreate = () => navigate(toAddUser({ realm: realmName })); if (!uiRealmInfo || !realm) { return _jsx(KeycloakSpinner, {}); } //should *only* list users when no user federation is configured const listUsers = !uiRealmInfo.userProfileProvidersEnabled; const clearAllFilters = () => { setActiveFilters({ exact: false, userAttribute: [] }); setSearchUser(""); setQuery(""); refresh(); }; const createQueryString = (filters) => { return filters.userAttribute .map((filter) => `${filter.name}:${filter.value}`) .join(" "); }; const searchUserWithAttributes = () => { const attributes = createQueryString(activeFilters); setQuery(attributes); refresh(); }; const createAttributeSearchChips = () => { return (_jsx(FlexItem, { children: activeFilters.userAttribute.length > 0 && (_jsx(_Fragment, { children: Object.values(activeFilters.userAttribute).map((entry) => { return (_jsx(ChipGroup, { className: "pf-v5-u-mt-md pf-v5-u-mr-md", "data-testid": "user-attribute-search-chips-group", categoryName: entry.displayName.length ? entry.displayName : entry.name, isClosable: true, onClick: (event) => { event.stopPropagation(); const filtered = [...activeFilters.userAttribute].filter((chip) => chip.name !== entry.name); const active = { userAttribute: filtered, exact: activeFilters.exact, }; setActiveFilters(active); setQuery(createQueryString(active)); refresh(); }, children: _jsx(Chip, { isReadOnly: true, children: entry.value }, entry.name) }, entry.name)); }) })) })); }; const toolbar = () => { return (_jsx(UserDataTableToolbarItems, { searchDropdownOpen: searchDropdownOpen, setSearchDropdownOpen: setSearchDropdownOpen, realm: realm, hasSelectedRows: selectedRows.length === 0, toggleDeleteDialog: toggleDeleteDialog, toggleUnlockUsersDialog: toggleUnlockUsersDialog, goToCreate: goToCreate, searchType: searchType, setSearchType: setSearchType, searchUser: searchUser, setSearchUser: setSearchUser, activeFilters: activeFilters, setActiveFilters: setActiveFilters, refresh: refresh, profile: profile, clearAllFilters: clearAllFilters, createAttributeSearchChips: createAttributeSearchChips, searchUserWithAttributes: searchUserWithAttributes })); }; const subtoolbar = () => { if (!activeFilters.userAttribute.length) { return; } return (_jsxs("div", { className: "user-attribute-search-form-subtoolbar", children: [_jsx(ToolbarItem, { children: createAttributeSearchChips() }), _jsx(ToolbarItem, { children: _jsx(Button, { variant: "link", onClick: () => { clearAllFilters(); }, children: t("clearAllFilters") }) })] })); }; return (_jsxs(_Fragment, { children: [_jsx(DeleteConfirm, {}), _jsx(UnlockUsersConfirm, {}), _jsx(KeycloakDataTable, { isSearching: searchUser !== "" || activeFilters.userAttribute.length !== 0, loader: loader, isPaginated: true, ariaLabelKey: "titleUsers", canSelectAll: true, onSelect: (rows) => setSelectedRows([...rows]), emptyState: !listUsers ? (_jsxs(_Fragment, { children: [_jsx(Toolbar, { children: _jsx(ToolbarContent, { children: toolbar() }) }), _jsx(EmptyState, { "data-testid": "empty-state", variant: "lg", children: _jsx(TextContent, { className: "kc-search-users-text", children: _jsx(Text, { children: t("searchForUserDescription") }) }) })] })) : (_jsx(ListEmptyState, { message: t("noUsersFound"), instructions: t("emptyInstructions"), primaryActionText: t("createNewUser"), onPrimaryAction: goToCreate })), toolbarItem: toolbar(), subToolbar: subtoolbar(), actionResolver: (rowData) => { var _a; const user = rowData.data; if (!((_a = user.access) === null || _a === void 0 ? void 0 : _a.manage)) return []; return [ { title: t("delete"), onClick: () => { setSelectedRows([user]); toggleDeleteDialog(); }, }, ]; }, columns: [ { name: "username", displayKey: "username", cellRenderer: UserDetailLink, }, { name: "email", displayKey: "email", cellRenderer: ValidatedEmail, }, { name: "lastName", displayKey: "lastName", cellFormatters: [emptyFormatter()], }, { name: "firstName", displayKey: "firstName", cellFormatters: [emptyFormatter()], }, ] }, key)] })); } //# sourceMappingURL=UserDataTable.js.map