UNPKG

@keycloakify/keycloak-admin-ui

Version:
253 lines 13.8 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { KeycloakSelect } from "../ui-shared"; import { Alert, Button, ButtonVariant, Checkbox, DataList, DataListCell, DataListItem, DataListItemCells, DataListItemRow, Divider, Label, Modal, ModalVariant, SelectOption, Stack, StackItem, Text, TextContent, } from "@patternfly/react-core"; import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { useAdminClient } from "../admin-client"; import { useAlerts } from "../ui-shared"; import { JsonFileUpload } from "../components/json-file-upload/JsonFileUpload"; import { KeycloakDataTable } from "../ui-shared"; import { useRealm } from "../context/realm-context/RealmContext"; const INITIAL_RESOURCES = { users: false, clients: false, groups: false, identityProviders: false, realmRoles: false, clientRoles: false, }; export const PartialImportDialog = (props) => { const { adminClient } = useAdminClient(); const { t } = useTranslation(); const { realm } = useRealm(); const [importedFile, setImportedFile] = useState(); const isFileSelected = !!importedFile; const [isRealmSelectOpen, setIsRealmSelectOpen] = useState(false); const [isCollisionSelectOpen, setIsCollisionSelectOpen] = useState(false); const [importInProgress, setImportInProgress] = useState(false); const [collisionOption, setCollisionOption] = useState("FAIL"); const [targetRealm, setTargetRealm] = useState({}); const [importResponse, setImportResponse] = useState(); const { addError } = useAlerts(); const [resourcesToImport, setResourcesToImport] = useState(INITIAL_RESOURCES); const isAnyResourceChecked = Object.values(resourcesToImport).some((checked) => checked); const resetResourcesToImport = () => { setResourcesToImport(INITIAL_RESOURCES); }; const resetInputState = () => { setImportedFile(undefined); setTargetRealm({}); setCollisionOption("FAIL"); resetResourcesToImport(); }; // when dialog opens or closes, clear state useEffect(() => { setImportInProgress(false); setImportResponse(undefined); resetInputState(); }, [props.open]); const handleFileChange = (value) => { resetInputState(); setImportedFile(value); if (!Array.isArray(value)) { setTargetRealm(value); } else if (value.length > 0) { setTargetRealm(value[0]); } }; const handleRealmSelect = (realm) => { setTargetRealm(realm); setIsRealmSelectOpen(false); resetResourcesToImport(); }; const handleResourceCheckBox = (checked, event) => { const resource = event.currentTarget.name; setResourcesToImport({ ...resourcesToImport, [resource]: checked, }); }; const realmSelectOptions = (realms) => realms.map((realm) => (_jsx(SelectOption, { value: realm, "data-testid": realm.id + "-select-option", children: realm.realm || realm.id }, realm.id))); const handleCollisionSelect = (option) => { setCollisionOption(option); setIsCollisionSelectOpen(false); }; const collisionOptions = () => { return [ _jsx(SelectOption, { value: "FAIL", children: t("FAIL") }, "fail"), _jsx(SelectOption, { value: "SKIP", children: t("SKIP") }, "skip"), _jsx(SelectOption, { value: "OVERWRITE", children: t("OVERWRITE") }, "overwrite"), ]; }; const targetHasResources = () => { return (targetHasResource("users") || targetHasResource("groups") || targetHasResource("clients") || targetHasResource("identityProviders") || targetHasRealmRoles() || targetHasClientRoles()); }; const targetHasResource = (resource) => { const value = targetRealm[resource]; return value !== undefined && value.length > 0; }; const targetHasRealmRoles = () => { var _a; const value = (_a = targetRealm.roles) === null || _a === void 0 ? void 0 : _a.realm; return value !== undefined && value.length > 0; }; const targetHasClientRoles = () => { var _a; const value = (_a = targetRealm.roles) === null || _a === void 0 ? void 0 : _a.client; return value !== undefined && Object.keys(value).length > 0; }; const itemCount = (resource) => { var _a, _b, _c, _d, _e; if (!isFileSelected) return 0; if (resource === "realmRoles") { return (_c = (_b = (_a = targetRealm.roles) === null || _a === void 0 ? void 0 : _a.realm) === null || _b === void 0 ? void 0 : _b.length) !== null && _c !== void 0 ? _c : 0; } if (resource === "clientRoles") { return targetHasClientRoles() ? clientRolesCount(targetRealm.roles.client) : 0; } return (_e = (_d = targetRealm[resource]) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0; }; const clientRolesCount = (clientRoles) => Object.values(clientRoles).reduce((total, role) => total + role.length, 0); const resourceDataListItem = (resource, resourceDisplayName) => { return (_jsx(DataListItem, { "aria-labelledby": `${resource}-list-item`, children: _jsx(DataListItemRow, { children: _jsx(DataListItemCells, { dataListCells: [ _jsx(DataListCell, { children: _jsx(Checkbox, { id: `${resource}-checkbox`, label: `${itemCount(resource)} ${resourceDisplayName}`, "aria-labelledby": `${resource}-checkbox`, name: resource, isChecked: resourcesToImport[resource], onChange: (event, checked) => handleResourceCheckBox(checked, event), "data-testid": resource + "-checkbox" }) }, resource), ] }) }) })); }; const jsonForImport = () => { var _a, _b; const jsonToImport = { ifResourceExists: collisionOption, id: targetRealm.id, realm: targetRealm.realm, }; if (resourcesToImport["users"]) jsonToImport.users = targetRealm.users; if (resourcesToImport["groups"]) jsonToImport.groups = targetRealm.groups; if (resourcesToImport["identityProviders"]) jsonToImport.identityProviders = targetRealm.identityProviders; if (resourcesToImport["clients"]) jsonToImport.clients = targetRealm.clients; if (resourcesToImport["realmRoles"] || resourcesToImport["clientRoles"]) { jsonToImport.roles = targetRealm.roles; if (!resourcesToImport["realmRoles"]) (_a = jsonToImport.roles) === null || _a === void 0 ? true : delete _a.realm; if (!resourcesToImport["clientRoles"]) (_b = jsonToImport.roles) === null || _b === void 0 ? true : delete _b.client; } return jsonToImport; }; async function doImport() { if (importInProgress) return; setImportInProgress(true); try { const importResults = await adminClient.realms.partialImport({ realm, rep: jsonForImport(), }); setImportResponse(importResults); } catch (error) { addError("importFail", error); } setImportInProgress(false); } const importModal = () => { return (_jsx(Modal, { variant: ModalVariant.medium, title: t("partialImport"), isOpen: props.open, onClose: props.toggleDialog, actions: [ _jsx(Button, { id: "modal-import", "data-testid": "import-button", isDisabled: !isAnyResourceChecked, onClick: () => { doImport(); }, children: t("import") }, "import"), _jsx(Button, { id: "modal-cancel", "data-testid": "cancel-button", variant: ButtonVariant.link, onClick: () => { props.toggleDialog(); }, children: t("cancel") }, "cancel"), ], children: _jsxs(Stack, { hasGutter: true, children: [_jsx(StackItem, { children: _jsx(TextContent, { children: _jsx(Text, { children: t("partialImportHeaderText") }) }) }), _jsx(StackItem, { children: _jsx(JsonFileUpload, { id: "partial-import-file", allowEditingUploadedText: true, onChange: handleFileChange }) }), isFileSelected && targetHasResources() && (_jsxs(_Fragment, { children: [_jsx(StackItem, { children: _jsx(Divider, {}) }), Array.isArray(importedFile) && importedFile.length > 1 && (_jsxs(StackItem, { children: [_jsxs(Text, { children: [t("selectRealm"), ":"] }), _jsx(KeycloakSelect, { toggleId: "realm-selector", isOpen: isRealmSelectOpen, typeAheadAriaLabel: t("realmSelector"), "aria-label": t("realmSelector"), onToggle: () => setIsRealmSelectOpen(!isRealmSelectOpen), selections: targetRealm.id, onSelect: (value) => handleRealmSelect(value), placeholderText: targetRealm.realm || targetRealm.id, children: realmSelectOptions(importedFile) })] })), _jsxs(StackItem, { children: [_jsxs(Text, { children: [t("chooseResources"), ":"] }), _jsxs(DataList, { "aria-label": t("resourcesToImport"), isCompact: true, children: [targetHasResource("users") && resourceDataListItem("users", t("users")), targetHasResource("groups") && resourceDataListItem("groups", t("groups")), targetHasResource("clients") && resourceDataListItem("clients", t("clients")), targetHasResource("identityProviders") && resourceDataListItem("identityProviders", t("identityProviders")), targetHasRealmRoles() && resourceDataListItem("realmRoles", t("realmRoles")), targetHasClientRoles() && resourceDataListItem("clientRoles", t("clientRoles"))] })] }), _jsxs(StackItem, { children: [_jsxs(Text, { children: [t("selectIfResourceExists"), ":"] }), _jsx(KeycloakSelect, { isOpen: isCollisionSelectOpen, direction: "up", onToggle: () => { setIsCollisionSelectOpen(!isCollisionSelectOpen); }, selections: collisionOption, onSelect: handleCollisionSelect, placeholderText: t(collisionOption), children: collisionOptions() })] })] }))] }) })); }; const importCompleteMessage = () => { return `${t("importAdded", { count: importResponse === null || importResponse === void 0 ? void 0 : importResponse.added, })} ${t("importSkipped", { count: importResponse === null || importResponse === void 0 ? void 0 : importResponse.skipped, })} ${t("importOverwritten", { count: importResponse === null || importResponse === void 0 ? void 0 : importResponse.overwritten, })}`; }; const loader = async (first = 0, max = 15) => { if (!importResponse) { return []; } const last = Math.min(first + max, importResponse.results.length); return importResponse.results.slice(first, last); }; const ActionLabel = (importRecord) => { switch (importRecord.action) { case "ADDED": return (_jsx(Label, { color: "green", children: t("added") }, importRecord.id)); case "SKIPPED": return (_jsx(Label, { color: "orange", children: t("skipped") }, importRecord.id)); case "OVERWRITTEN": return (_jsx(Label, { color: "purple", children: t("overwritten") }, importRecord.id)); default: return ""; } }; const TypeRenderer = (importRecord) => { const typeMap = new Map([ ["CLIENT", t("clients")], ["REALM_ROLE", t("realmRoles")], ["USER", t("users")], ["CLIENT_ROLE", t("clientRoles")], ["IDP", t("identityProviders")], ["GROUP", t("groups")], ]); return _jsx("span", { children: typeMap.get(importRecord.resourceType) }); }; const importCompletedModal = () => { return (_jsxs(Modal, { variant: ModalVariant.medium, title: t("partialImport"), isOpen: props.open, onClose: props.toggleDialog, actions: [ _jsx(Button, { id: "modal-close", "data-testid": "close-button", variant: ButtonVariant.primary, onClick: () => { props.toggleDialog(); }, children: t("close") }, "close"), ], children: [_jsx(Alert, { variant: "success", component: "p", isInline: true, title: importCompleteMessage() }), _jsx(KeycloakDataTable, { loader: loader, isPaginated: true, ariaLabelKey: "partialImport", columns: [ { name: "action", displayKey: "action", cellRenderer: ActionLabel, }, { name: "resourceType", displayKey: "type", cellRenderer: TypeRenderer, }, { name: "resourceName", displayKey: "name", }, { name: "id", displayKey: "id", }, ] })] })); }; if (!importResponse) { return importModal(); } return importCompletedModal(); }; //# sourceMappingURL=PartialImport.js.map