import type { ConfigPropertyRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/authenticatorConfigInfoRepresentation"; import type ClientProfileRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientProfileRepresentation"; import type ComponentTypeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentTypeRepresentation"; import { ActionGroup, AlertVariant, Button, FormGroup, PageSection, Select, SelectOption, SelectVariant, } from "@patternfly/react-core"; import { useState } from "react"; import { Controller, FormProvider, useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { Link, useNavigate } from "react-router-dom"; import { HelpItem } from "ui-shared"; import { adminClient } from "../admin-client"; import { useAlerts } from "../components/alert/Alerts"; import { DynamicComponents } from "../components/dynamic/DynamicComponents"; import { FormAccess } from "../components/form/FormAccess"; import { ViewHeader } from "../components/view-header/ViewHeader"; import { useServerInfo } from "../context/server-info/ServerInfoProvider"; import { useFetch } from "../utils/useFetch"; import { useParams } from "../utils/useParams"; import { ClientProfileParams, toClientProfile } from "./routes/ClientProfile"; import type { ExecutorParams } from "./routes/Executor"; type ExecutorForm = { config?: object; executor: string; }; const defaultValues: ExecutorForm = { config: {}, executor: "", }; export default function ExecutorForm() { const { t } = useTranslation(); const navigate = useNavigate(); const { realm, profileName } = useParams(); const { executorName } = useParams(); const { addAlert, addError } = useAlerts(); const [selectExecutorTypeOpen, setSelectExecutorTypeOpen] = useState(false); const serverInfo = useServerInfo(); const executorTypes = serverInfo.componentTypes?.[ "org.keycloak.services.clientpolicy.executor.ClientPolicyExecutorProvider" ]; const [executors, setExecutors] = useState([]); const [executorProperties, setExecutorProperties] = useState< ConfigPropertyRepresentation[] >([]); const [globalProfiles, setGlobalProfiles] = useState< ClientProfileRepresentation[] >([]); const [profiles, setProfiles] = useState([]); const form = useForm({ defaultValues }); const { control, reset, handleSubmit } = form; const editMode = !!executorName; const setupForm = (profiles: ClientProfileRepresentation[]) => { const profile = profiles.find((profile) => profile.name === profileName); const executor = profile?.executors?.find( (executor) => executor.executor === executorName, ); if (executor) reset({ config: executor.configuration }); }; useFetch( () => adminClient.clientPolicies.listProfiles({ includeGlobalProfiles: true }), (profiles) => { setGlobalProfiles(profiles.globalProfiles!); setProfiles(profiles.profiles!); setupForm(profiles.profiles!); setupForm(profiles.globalProfiles!); }, [], ); const save = async () => { const formValues = form.getValues(); const updatedProfiles = profiles.map((profile) => { if (profile.name !== profileName) { return profile; } const executors = (profile.executors ?? []).concat({ executor: formValues.executor, configuration: formValues.config || {}, }); if (editMode) { const profileExecutor = profile.executors!.find( (executor) => executor.executor === executorName, ); profileExecutor!.configuration = { ...profileExecutor!.configuration, ...formValues.config, }; } if (editMode) { return profile; } return { ...profile, executors, }; }); try { await adminClient.clientPolicies.createProfiles({ profiles: updatedProfiles, globalProfiles: globalProfiles, }); addAlert( editMode ? t("updateExecutorSuccess") : t("addExecutorSuccess"), AlertVariant.success, ); navigate(toClientProfile({ realm, profileName })); } catch (error) { addError(editMode ? "updateExecutorError" : "addExecutorError", error); } }; const globalProfile = globalProfiles.find( (globalProfile) => globalProfile.name === profileName, ); const profileExecutorType = executorTypes?.find( (executor) => executor.id === executorName, ); const editedProfileExecutors = profileExecutorType?.properties.map( (property) => { const globalDefaultValues = editMode ? property.defaultValue : ""; return { ...property, defaultValue: globalDefaultValues, }; }, ); return ( <> 0 && executors[0].helpText! !== "" ? ( ) : editMode ? ( ) : undefined } > ( )} /> {!globalProfile && ( )} {editMode && globalProfile && (
)}
); }