/* eslint-disable */ // @ts-nocheck import AuthenticationFlowRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticationFlowRepresentation"; import type { AuthenticationProviderRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigRepresentation"; import AuthenticatorConfigRepresentation from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigRepresentation"; import { useAlerts, useFetch } from "../../shared/keycloak-ui-shared"; import { AlertVariant, Button, ButtonVariant, DragDrop, DropdownItem, Droppable, Label, PageSection, ToggleGroup, ToggleGroupItem, Toolbar, ToolbarContent, ToolbarItem, } from "../../shared/@patternfly/react-core"; import { DomainIcon, TableIcon } from "../../shared/@patternfly/react-icons"; import { Table, Tbody } from "../../shared/@patternfly/react-table"; import { useState } from "react"; import { Trans, useTranslation } from "react-i18next"; import { useNavigate, useParams } from "react-router-dom"; import { useAdminClient } from "../admin-client"; import { useConfirmDialog } from "../components/confirm-dialog/ConfirmDialog"; import { ViewHeader } from "../components/view-header/ViewHeader"; import { useRealm } from "../context/realm-context/RealmContext"; import useToggle from "../utils/useToggle"; import { BindFlowDialog } from "./BindFlowDialog"; import { BuildInLabel } from "./BuildInLabel"; import { DuplicateFlowModal } from "./DuplicateFlowModal"; import { EditFlowModal } from "./EditFlowModal"; import { EmptyExecutionState } from "./EmptyExecutionState"; import { AuthenticationProviderContextProvider } from "./components/AuthenticationProviderContext"; import { FlowDiagram } from "./components/FlowDiagram"; import { FlowHeader } from "./components/FlowHeader"; import { FlowRow } from "./components/FlowRow"; import { AddStepModal } from "./components/modals/AddStepModal"; import { AddSubFlowModal, Flow } from "./components/modals/AddSubFlowModal"; import { ExecutionList, ExpandableExecution, IndexChange, LevelChange, } from "./execution-model"; import { toAuthentication } from "./routes/Authentication"; import { toFlow, type FlowParams } from "./routes/Flow"; export const providerConditionFilter = ( value: AuthenticationProviderRepresentation, ) => value.displayName?.startsWith("Condition "); export default function FlowDetails() { const { adminClient } = useAdminClient(); const { t } = useTranslation(); const { realm } = useRealm(); const { addAlert, addError } = useAlerts(); const { id, usedBy, builtIn } = useParams(); const navigate = useNavigate(); const [key, setKey] = useState(0); const refresh = () => setKey(new Date().getTime()); const [tableView, setTableView] = useState(true); const [flow, setFlow] = useState(); const [executionList, setExecutionList] = useState(); const [liveText, setLiveText] = useState(""); const [showAddExecutionDialog, setShowAddExecutionDialog] = useState(); const [showAddSubFlowDialog, setShowSubFlowDialog] = useState(); const [selectedExecution, setSelectedExecution] = useState(); const [open, toggleOpen, setOpen] = useToggle(); const [edit, setEdit] = useState(false); const [bindFlowOpen, toggleBindFlow] = useToggle(); useFetch( async () => { const flows = await adminClient.authenticationManagement.getFlows(); const flow = flows.find((f) => f.id === id); if (!flow) { throw new Error(t("notFound")); } const executions = await adminClient.authenticationManagement.getExecutions({ flow: flow.alias!, }); return { flow, executions }; }, ({ flow, executions }) => { setFlow(flow); setExecutionList(new ExecutionList(executions)); }, [key], ); const executeChange = async ( ex: AuthenticationFlowRepresentation | ExpandableExecution, change: LevelChange | IndexChange, ) => { try { let id = ex.id!; if ("parent" in change) { let config: AuthenticatorConfigRepresentation = {}; if ("authenticationConfig" in ex) { config = await adminClient.authenticationManagement.getConfig({ id: ex.authenticationConfig as string, }); } try { await adminClient.authenticationManagement.delExecution({ id }); } catch { // skipping already deleted execution } if ("authenticationFlow" in ex) { const executionFlow = ex as ExpandableExecution; const result = await adminClient.authenticationManagement.addFlowToFlow({ flow: change.parent?.displayName! || flow?.alias!, alias: executionFlow.displayName!, description: executionFlow.description!, provider: ex.providerId!, type: "basic-flow", }); id = result.id!; ex.executionList?.forEach((e, i) => executeChange(e, { parent: { ...ex, id: result.id }, newIndex: i, oldIndex: i, }), ); } else { const result = await adminClient.authenticationManagement.addExecutionToFlow({ flow: change.parent?.displayName! || flow?.alias!, provider: ex.providerId!, }); if (config.id) { const newConfig = { id: result.id, alias: config.alias, config: config.config, }; await adminClient.authenticationManagement.createConfig(newConfig); } id = result.id!; } } const times = change.newIndex - change.oldIndex; for (let index = 0; index < Math.abs(times); index++) { if (times > 0) { await adminClient.authenticationManagement.lowerPriorityExecution({ id, }); } else { await adminClient.authenticationManagement.raisePriorityExecution({ id, }); } } refresh(); addAlert(t("updateFlowSuccess"), AlertVariant.success); } catch (error) { addError("updateFlowError", error); } }; const update = async (execution: ExpandableExecution) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { executionList, isCollapsed, ...ex } = execution; try { await adminClient.authenticationManagement.updateExecution( { flow: flow?.alias! }, ex, ); refresh(); addAlert(t("updateFlowSuccess"), AlertVariant.success); } catch (error) { addError("updateFlowError", error); } }; const addExecution = async ( name: string, type: AuthenticationProviderRepresentation, ) => { try { await adminClient.authenticationManagement.addExecutionToFlow({ flow: name, provider: type.id!, }); refresh(); addAlert(t("updateFlowSuccess"), AlertVariant.success); } catch (error) { addError("updateFlowError", error); } }; const addFlow = async ( flow: string, { name, description = "", type, provider }: Flow, ) => { try { await adminClient.authenticationManagement.addFlowToFlow({ flow, alias: name, description, provider, type, }); refresh(); addAlert(t("updateFlowSuccess"), AlertVariant.success); } catch (error) { addError("updateFlowError", error); } }; const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ titleKey: t("deleteConfirmExecution", { name: selectedExecution?.displayName, }), children: ( {" "} {{ name: selectedExecution?.displayName }}. ), continueButtonLabel: "delete", continueButtonVariant: ButtonVariant.danger, onConfirm: async () => { try { await adminClient.authenticationManagement.delExecution({ id: selectedExecution?.id!, }); addAlert(t("deleteExecutionSuccess"), AlertVariant.success); refresh(); } catch (error) { addError("deleteExecutionError", error); } }, }); const [toggleDeleteFlow, DeleteFlowConfirm] = useConfirmDialog({ titleKey: "deleteConfirmFlow", children: ( {" "} {{ flow: flow?.alias || "" }}. ), continueButtonLabel: "delete", continueButtonVariant: ButtonVariant.danger, onConfirm: async () => { try { await adminClient.authenticationManagement.deleteFlow({ flowId: flow!.id!, }); navigate(toAuthentication({ realm })); addAlert(t("deleteFlowSuccess"), AlertVariant.success); } catch (error) { addError("deleteFlowError", error); } }, }); const hasExecutions = executionList?.expandableList.length !== 0; const dropdownItems = [ ...(usedBy !== "DEFAULT" ? [ {t("bindFlow")} , ] : []), setOpen(true)}> {t("duplicate")} , ...(!builtIn ? [ setEdit(true)} > {t("editInfo")} , ] : []), ...(!builtIn && !usedBy ? [ toggleDeleteFlow()} > {t("delete")} , ] : []), ]; return ( {bindFlowOpen && ( { toggleBindFlow(); navigate( toFlow({ realm, id: id!, usedBy: usedBy ? "DEFAULT" : "notInUse", builtIn: builtIn ? "builtIn" : undefined, }), ); }} /> )} {open && flow && ( { refresh(); setOpen(false); }} /> )} {edit && ( { setEdit(!edit); refresh(); }} /> )} {t(`used.${usedBy}`)} }, builtIn ? { text: , id: "builtIn", } : {}, ]} dropdownItems={dropdownItems} /> {executionList && hasExecutions && ( <> } aria-label={t("tableView")} buttonId="tableView" isSelected={tableView} onChange={() => setTableView(true)} /> } aria-label={t("diagramView")} buttonId="diagramView" isSelected={!tableView} onChange={() => setTableView(false)} /> {tableView && ( { const item = executionList.findExecution(index)!; setLiveText(t("onDragStart", { item: item.displayName })); if (!item.isCollapsed) { item.isCollapsed = true; setExecutionList(executionList.clone()); } return true; }} onDragMove={({ index }) => { const dragged = executionList.findExecution(index); setLiveText(t("onDragMove", { item: dragged?.displayName })); }} onDrop={(source, dest) => { if (dest) { if (source.index === dest.index) { return false; } const dragged = executionList.findExecution(source.index)!; const order = executionList.order().map((ex) => ex.id!); setLiveText( t("onDragFinish", { list: dragged.displayName }), ); const [removed] = order.splice(source.index, 1); order.splice(dest.index, 0, removed); const change = executionList.getChange(dragged, order); void executeChange(dragged, change); return true; } else { setLiveText(t("onDragCancel")); return false; } }} > <> {executionList.expandableList.map((execution) => ( { execution.isCollapsed = !execution.isCollapsed; setExecutionList(executionList.clone()); }} onRowChange={update} onAddExecution={(execution, type) => addExecution(execution.displayName!, type) } onAddFlow={(execution, flow) => addFlow(execution.displayName!, flow) } onDelete={(execution) => { setSelectedExecution(execution); toggleDeleteDialog(); }} /> ))}
)} {flow && ( <> {showAddExecutionDialog && ( { if (type) { await addExecution(flow.alias!, type); } setShowAddExecutionDialog(false); }} /> )} {showAddSubFlowDialog && ( setShowSubFlowDialog(false)} onConfirm={async (newFlow) => { await addFlow(flow.alias!, newFlow); setShowSubFlowDialog(false); }} /> )} )}
{liveText}
)} {!tableView && executionList?.expandableList && ( )} {!executionList?.expandableList || (flow && !hasExecutions && ( addExecution(flow.alias!, type)} onAddFlow={(newFlow) => addFlow(flow.alias!, newFlow)} /> ))}
); }