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