/* eslint-disable */ // @ts-nocheck import type GroupRepresentation from "@keycloak/keycloak-admin-client/lib/defs/groupRepresentation"; import { GroupQuery, SubGroupQuery, } from "@keycloak/keycloak-admin-client/lib/resources/groups"; import { ListEmptyState, PaginatingTableToolbar, useFetch, } from "../../../shared/keycloak-ui-shared"; import { Breadcrumb, BreadcrumbItem, Button, DataList, DataListAction, DataListCell, DataListCheck, DataListItem, DataListItemCells, DataListItemRow, Modal, ModalVariant, } from "../../../shared/@patternfly/react-core"; import { AngleRightIcon } from "../../../shared/@patternfly/react-icons"; import { useState } from "react"; import { useTranslation } from "react-i18next"; import { useAdminClient } from "../../admin-client"; import { GroupPath } from "./GroupPath"; import { useGroupResource } from "../../context/group-resource/GroupResourceContext"; import "./group-picker-dialog.css"; export type GroupPickerDialogProps = { id?: string; type: "selectOne" | "selectMany"; filterGroups?: GroupRepresentation[]; text: { title: string; ok: string }; canBrowse?: boolean; isMove?: boolean; onConfirm: (groups: GroupRepresentation[] | undefined) => void; onClose: () => void; }; type SelectableGroup = GroupRepresentation & { checked?: boolean; }; export const GroupPickerDialog = ({ id, type, filterGroups, text, canBrowse = true, isMove = false, onClose, onConfirm, }: GroupPickerDialogProps) => { const { adminClient } = useAdminClient(); const groupResource = useGroupResource(); const { t } = useTranslation(); const [selectedRows, setSelectedRows] = useState([]); const [navigation, setNavigation] = useState([]); const [groups, setGroups] = useState([]); const [filter, setFilter] = useState(""); const [joinedGroups, setJoinedGroups] = useState([]); const [groupId, setGroupId] = useState(); const [max, setMax] = useState(10); const [first, setFirst] = useState(0); const [count, setCount] = useState(0); const currentGroup = () => navigation[navigation.length - 1]; useFetch( async () => { let group; let groups; let existingUserGroups; if (!groupId) { const args: GroupQuery = { first, max: max + 1, }; if (filter !== "") { args.search = filter; } groups = await groupResource.find(args); } else { if (!navigation.map(({ id }) => id).includes(groupId)) { group = await groupResource.findOne({ id: groupId }); if (!group) { throw new Error(t("notFound")); } } const args: SubGroupQuery = { first, max, parentId: groupId, }; groups = await groupResource.listSubGroups(args); } if (id) { existingUserGroups = await adminClient.users.listGroups({ id, }); } return { group, groups, existingUserGroups }; }, async ({ group: selectedGroup, groups, existingUserGroups }) => { setJoinedGroups(existingUserGroups || []); if (selectedGroup) { setNavigation([...navigation, selectedGroup]); setCount(selectedGroup.subGroupCount!); } groups.forEach((group: SelectableGroup) => { group.checked = !!selectedRows.find((r) => r.id === group.id); }); setGroups(groups); if (filter !== "" || !groupId) { setCount(groups.length); } }, [groupId, filter, first, max], ); const isRowDisabled = (row?: GroupRepresentation) => { return [ ...joinedGroups.map((item) => item.id), ...(filterGroups || []).map((group) => group.id), ].some((group) => group === row?.id); }; return ( { onConfirm( type === "selectMany" ? selectedRows : navigation.length ? [currentGroup()] : undefined, ); }} isDisabled={type === "selectMany" && selectedRows.length === 0} > {t(text.ok)} , ]} > { setFirst(first); setMax(max); }} inputGroupName={"search"} inputGroupOnEnter={(search) => { setFilter(search); setFirst(0); setMax(10); setNavigation([]); setGroupId(undefined); }} inputGroupPlaceholder={t("searchForGroups")} > {navigation.length > 0 && ( )} {navigation.map((group, i) => ( {navigation.length - 1 !== i && ( )} {navigation.length - 1 === i && group.name} ))} {filter == "" ? groups.slice(0, max).map((group: SelectableGroup) => ( { setGroupId(group.id); setFirst(0); }} type={type} isSearching={false} selectedRows={selectedRows} setSelectedRows={setSelectedRows} canBrowse={canBrowse} /> )) : groups .map((g) => deepGroup([g])) .flat() .map((g) => ( { setGroupId(group.id); setFilter(""); setFirst(0); }} type={type} isSearching selectedRows={selectedRows} setSelectedRows={setSelectedRows} canBrowse={false} /> ))} {groups.length === 0 && filter === "" && ( )} {groups.length === 0 && filter !== "" && ( )} ); }; function deepGroup(groups: GroupRepresentation[]) { const flattened: GroupRepresentation[] = []; for (const group of groups) { flattened.push(group); if (group.subGroups && group.subGroups.length > 0) { flattened.push(...deepGroup(group.subGroups)); } } return flattened; } type GroupRowProps = { group: SelectableGroup; type: "selectOne" | "selectMany"; isRowDisabled: (row?: GroupRepresentation) => boolean; isSearching: boolean; setIsSearching?: (value: boolean) => void; onSelect?: (group: GroupRepresentation) => void; selectedRows: SelectableGroup[]; setSelectedRows: (groups: SelectableGroup[]) => void; canBrowse: boolean; }; const GroupRow = ({ group, type, isRowDisabled, isSearching, setIsSearching, onSelect, selectedRows, setSelectedRows, canBrowse, }: GroupRowProps) => { const { t } = useTranslation(); return ( { if (type === "selectOne") { onSelect?.(group); } else if ( (e.target as HTMLInputElement).type !== "checkbox" && group.subGroupCount !== 0 ) { onSelect?.(group); setIsSearching?.(false); } }} > {type === "selectMany" && ( { group.checked = checked; let newSelectedRows: SelectableGroup[] = []; if (!group.checked) { newSelectedRows = selectedRows.filter((r) => r.id !== group.id); } else { newSelectedRows = [...selectedRows, group]; } setSelectedRows(newSelectedRows); }} aria-labelledby={`select-${group.name}`} /> )} {isSearching ? ( ) : ( {group.name} )} , ]} /> {(canBrowse || type === "selectOne") && group.subGroupCount !== 0 && ( )} ); };