import React, { useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { TFunction } from "i18next"; import { IFormatter, IFormatterValueType, Table, TableBody, TableHeader, TableVariant, } from "@patternfly/react-table"; import { Button, Dropdown, DropdownItem, DropdownToggle, Select, Spinner, Split, SplitItem, } from "@patternfly/react-core"; import { FilterIcon } from "@patternfly/react-icons"; import ClientScopeRepresentation from "keycloak-admin/lib/defs/clientScopeRepresentation"; import KeycloakAdminClient from "keycloak-admin"; import { useAdminClient } from "../../context/auth/AdminClient"; import { TableToolbar } from "../../components/table-toolbar/TableToolbar"; import { ListEmptyState } from "../../components/list-empty-state/ListEmptyState"; import { AddScopeDialog } from "./AddScopeDialog"; import { clientScopeTypesSelectOptions, ClientScopeType, ClientScope, } from "./ClientScopeTypes"; export type ClientScopesProps = { clientId: string; protocol: string; }; const firstUpperCase = (name: string) => name.charAt(0).toUpperCase() + name.slice(1); const changeScope = async ( adminClient: KeycloakAdminClient, clientId: string, clientScope: ClientScopeRepresentation, type: ClientScopeType, changeTo: ClientScopeType ) => { const typeToName = firstUpperCase(type); const changeToName = firstUpperCase(changeTo); const indexedAdminClient = (adminClient.clients as unknown) as { [index: string]: Function; }; await indexedAdminClient[`del${typeToName}ClientScope`]({ id: clientId, clientScopeId: clientScope.id!, }); await indexedAdminClient[`add${changeToName}ClientScope`]({ id: clientId, clientScopeId: clientScope.id!, }); }; type CellDropdownProps = { clientId: string; clientScope: ClientScopeRepresentation; type: ClientScopeType; }; const CellDropdown = ({ clientId, clientScope, type }: CellDropdownProps) => { const adminClient = useAdminClient(); const { t } = useTranslation("clients"); const [open, setOpen] = useState(false); return ( ); }; type SearchType = "client" | "assigned"; type TableRow = { clientScope: ClientScopeRepresentation; type: ClientScopeType; cells: (string | undefined)[]; }; export const ClientScopes = ({ clientId, protocol }: ClientScopesProps) => { const { t } = useTranslation("clients"); const adminClient = useAdminClient(); const [searchToggle, setSearchToggle] = useState(false); const [searchType, setSearchType] = useState("client"); const [addToggle, setAddToggle] = useState(false); const [addDialogOpen, setAddDialogOpen] = useState(false); const [rows, setRows] = useState(); const [rest, setRest] = useState(); const loader = async () => { 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: string) => clientScopes.find((clientScope) => id === clientScope.id)!; const optional = optionalClientScopes.map((c) => { const scope = find(c.id!); return { clientScope: c, type: ClientScope.optional, cells: [c.name, c.id, scope.description], }; }); const defaultScopes = defaultClientScopes.map((c) => { const scope = find(c.id!); return { clientScope: c, type: ClientScope.default, cells: [c.name, c.id, scope.description], }; }); setRows([...optional, ...defaultScopes]); }; useEffect(() => { loader(); }, []); useEffect(() => { if (rows) { loadRest(rows); } }, [rows]); const loadRest = async (rows: { cells: (string | undefined)[] }[]) => { const clientScopes = await adminClient.clientScopes.find(); const names = rows.map((row) => row.cells[0]); setRest( clientScopes .filter((scope) => !names.includes(scope.name)) .filter((scope) => scope.protocol === protocol) ); }; const dropdown = (): IFormatter => (data?: IFormatterValueType) => { if (!data) { return <>; } const row = rows?.find((row) => row.clientScope.id === data.toString())!; return ( ); }; const filterData = () => {}; return ( <> {!rows && (
)} {rows && rows.length > 0 && ( <> {rest && ( setAddDialogOpen(!addDialogOpen)} /> )} setSearchToggle(!searchToggle)} > {t(`clientScopeSearch.${searchType}`)} } aria-label="Select Input" isOpen={searchToggle} dropdownItems={[ { setSearchType("client"); setSearchToggle(false); }} > {t("clientScopeSearch.client")} , { setSearchType("assigned"); setSearchToggle(false); }} > {t("clientScopeSearch.assigned")} , ]} /> } inputGroupName="clientsScopeToolbarTextInput" inputGroupPlaceholder={t("searchByName")} inputGroupOnChange={filterData} toolbarItem={ } > {}} variant={TableVariant.compact} cells={[ t("name"), { title: t("description"), cellFormatters: [dropdown()] }, t("protocol"), ]} rows={rows} actions={[ { title: t("common:remove"), onClick: () => {}, }, ]} aria-label={t("clientScopeList")} >
)} {rows && rows.length === 0 && ( {}} /> )} ); };