import type ClientScopeRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientScopeRepresentation"; import type { UserProfileConfig } from "@keycloak/keycloak-admin-client/lib/defs/userProfileMetadata"; import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation"; import { Button, Divider, FormGroup, Grid, GridItem, Radio, Select, SelectOption, SelectVariant, Switch, Tooltip, } from "@patternfly/react-core"; import { isEqual } from "lodash-es"; import { useEffect, useRef, useState } from "react"; import { Controller, useFormContext, useWatch } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { HelpItem } from "ui-shared"; import { adminClient } from "../../../admin-client"; import { FormAccess } from "../../../components/form/FormAccess"; import { KeycloakSpinner } from "../../../components/keycloak-spinner/KeycloakSpinner"; import { KeycloakTextInput } from "../../../components/keycloak-text-input/KeycloakTextInput"; import { useFetch } from "../../../utils/useFetch"; import { useParams } from "../../../utils/useParams"; import { USERNAME_EMAIL } from "../../NewAttributeSettings"; import "../../realm-settings-section.css"; import { GlobeRouteIcon } from "@patternfly/react-icons"; import { AddTranslationsDialog } from "./AddTranslationsDialog"; import useToggle from "../../../utils/useToggle"; import { AttributeParams } from "../../routes/Attribute"; import { useRealm } from "../../../context/realm-context/RealmContext"; const REQUIRED_FOR = [ { label: "requiredForLabel.both", value: ["admin", "user"] }, { label: "requiredForLabel.users", value: ["user"] }, { label: "requiredForLabel.admins", value: ["admin"] }, ] as const; type TranslationForm = { locale: string; value: string; }; type Translations = { key: string; translations: TranslationForm[]; }; export type AttributeGeneralSettingsProps = { onHandlingTranslationData: (data: Translations) => void; onHandlingGeneratedDisplayName: (displayName: string) => void; }; export const AttributeGeneralSettings = ({ onHandlingTranslationData, onHandlingGeneratedDisplayName, }: AttributeGeneralSettingsProps) => { const { t } = useTranslation(); const { realm: realmName } = useRealm(); const form = useFormContext(); const tooltipRef = useRef(); const [clientScopes, setClientScopes] = useState(); const [config, setConfig] = useState(); const [selectEnabledWhenOpen, setSelectEnabledWhenOpen] = useState(false); const [selectRequiredForOpen, setSelectRequiredForOpen] = useState(false); const [isAttributeGroupDropdownOpen, setIsAttributeGroupDropdownOpen] = useState(false); const [addTranslationsModalOpen, toggleModal] = useToggle(); const { attributeName } = useParams(); const editMode = attributeName ? true : false; const [realm, setRealm] = useState(); const [newAttributeName, setNewAttributeName] = useState(""); const [generatedDisplayName, setGeneratedDisplayName] = useState(""); const [translationsData, setTranslationsData] = useState({ key: "", translations: [], }); const displayNameRegex = /\$\{([^}]+)\}/; const handleAttributeNameChange = ( event: React.ChangeEvent, ) => { const newAttributeName = event.target.value; setNewAttributeName(newAttributeName); const newDisplayName = newAttributeName !== "" && realm?.internationalizationEnabled ? "${profile.attributes." + `${newAttributeName}}` : ""; setGeneratedDisplayName(newDisplayName); }; const hasSelector = useWatch({ control: form.control, name: "hasSelector", }); const hasRequiredScopes = useWatch({ control: form.control, name: "hasRequiredScopes", }); const required = useWatch({ control: form.control, name: "isRequired", defaultValue: false, }); const attributeDisplayName = useWatch({ control: form.control, name: "displayName", }); const displayNamePatternMatch = displayNameRegex.test(attributeDisplayName); useFetch( () => adminClient.realms.findOne({ realm: realmName }), (realm) => { if (!realm) { throw new Error(t("notFound")); } setRealm(realm); }, [], ); useFetch(() => adminClient.clientScopes.find(), setClientScopes, []); useFetch(() => adminClient.users.getProfile(), setConfig, []); const handleTranslationsData = (translationsData: Translations) => { onHandlingTranslationData(translationsData); }; const handleGeneratedDisplayName = (displayName: string) => { onHandlingGeneratedDisplayName(displayName); }; useEffect(() => { handleTranslationsData(translationsData); handleGeneratedDisplayName(generatedDisplayName); }, [translationsData, generatedDisplayName]); if (!clientScopes) { return ; } function setHasSelector(hasSelector: boolean) { form.setValue("hasSelector", hasSelector); } function setHasRequiredScopes(hasRequiredScopes: boolean) { form.setValue("hasRequiredScopes", hasRequiredScopes); } const handleTranslationsAdded = (translationsData: Translations) => { setTranslationsData(translationsData); }; const handleToggleDialog = () => { toggleModal(); handleTranslationsData(translationsData); handleGeneratedDisplayName(generatedDisplayName); }; return ( <> {addTranslationsModalOpen && ( { toggleModal(); }} /> )} } fieldId="kc-attribute-name" isRequired validated={form.formState.errors.name ? "error" : "default"} helperTextInvalid={t("validateAttributeName")} > } fieldId="kc-attribute-display-name" > {realm?.internationalizationEnabled && (