UNPKG

@keycloakify/keycloak-admin-ui

Version:
301 lines 19.2 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { getI18n } from "react-i18next"; import { HelpItem, TextControl, useAlerts, useFetch, } from "../../ui-shared"; import { ActionGroup, Alert, Button, FormGroup, Grid, GridItem, PageSection, Text, TextContent, TextInput, } from "@patternfly/react-core"; import { GlobeRouteIcon } from "@patternfly/react-icons"; import { useEffect, useMemo, useState } from "react"; import { FormProvider, useForm, useWatch, } from "react-hook-form"; import { useTranslation } from "react-i18next"; import { Link, useNavigate, useParams } from "react-router-dom"; import { useAdminClient } from "../../admin-client"; import { FormAccess } from "../../components/form/FormAccess"; import { KeyValueInput } from "../../components/key-value-form/KeyValueInput"; import { ViewHeader } from "../../components/view-header/ViewHeader"; import { useRealm } from "../../context/realm-context/RealmContext"; import useLocale from "../../utils/useLocale"; import useToggle from "../../utils/useToggle"; import "../realm-settings-section.css"; import { toUserProfile } from "../../realm-settings/routes/UserProfile"; import { useUserProfile } from "../../realm-settings/user-profile/UserProfileContext"; import { AddTranslationsDialog, } from "../../realm-settings/user-profile/attribute/AddTranslationsDialog"; function parseAnnotations(input) { return Object.entries(input).reduce((p, [key, value]) => { if (typeof value === "string") { return [...p, { key, value }]; } else { return [...p]; } }, []); } function transformAnnotations(input) { return Object.fromEntries(input .filter((annotation) => annotation.key.length > 0) .map((annotation) => [annotation.key, annotation.value])); } const defaultValues = { annotations: [], displayDescription: "", displayHeader: "", name: "", }; export default function AttributesGroupForm() { const { adminClient } = useAdminClient(); const { t } = useTranslation(); const { realm: realmName, realmRepresentation: realm } = useRealm(); const { config, save } = useUserProfile(); const navigate = useNavigate(); const combinedLocales = useLocale(); const params = useParams(); const form = useForm({ defaultValues }); const { addError } = useAlerts(); const editMode = params.name ? true : false; const [newAttributesGroupName, setNewAttributesGroupName] = useState(""); const [generatedAttributesGroupDisplayName, setGeneratedAttributesGroupDisplayName,] = useState(""); const [generatedAttributesGroupDisplayDescription, setGeneratedAttributesGroupDisplayDescription,] = useState(""); const [addTranslationsModalOpen, toggleModal] = useToggle(); const regexPattern = /\$\{([^}]+)\}/; const [type, setType] = useState(); const [translationsData, setTranslationsData] = useState({ displayHeader: { key: "", translations: [], }, displayDescription: { key: "", translations: [], }, }); const matchingGroup = useMemo(() => { var _a; return (_a = config === null || config === void 0 ? void 0 : config.groups) === null || _a === void 0 ? void 0 : _a.find(({ name }) => name === params.name); }, [config === null || config === void 0 ? void 0 : config.groups]); useEffect(() => { if (!matchingGroup) { return; } const annotations = matchingGroup.annotations ? parseAnnotations(matchingGroup.annotations) : []; form.reset({ ...defaultValues, ...matchingGroup, annotations }); }, [matchingGroup]); useEffect(() => { form.setValue("displayHeader", matchingGroup ? matchingGroup.displayHeader : generatedAttributesGroupDisplayName); form.setValue("displayDescription", matchingGroup ? matchingGroup.displayDescription : generatedAttributesGroupDisplayDescription); }, [ generatedAttributesGroupDisplayName, generatedAttributesGroupDisplayDescription, ]); useFetch(async () => { const translationsToSaveDisplayHeader = []; const translationsToSaveDisplayDescription = []; const formData = form.getValues(); const translationsResults = await Promise.all(combinedLocales.map(async (selectedLocale) => { var _a, _b, _c, _d; try { const translations = await adminClient.realms.getRealmLocalizationTexts({ realm: realmName, selectedLocale, }); const formattedDisplayHeaderKey = (_a = formData.displayHeader) === null || _a === void 0 ? void 0 : _a.substring(2, formData.displayHeader.length - 1); const formattedDisplayDescriptionKey = (_b = formData.displayDescription) === null || _b === void 0 ? void 0 : _b.substring(2, formData.displayDescription.length - 1); return { locale: selectedLocale, headerTranslation: (_c = translations[formattedDisplayHeaderKey]) !== null && _c !== void 0 ? _c : "", descriptionTranslation: (_d = translations[formattedDisplayDescriptionKey]) !== null && _d !== void 0 ? _d : "", }; } catch (error) { console.error(`Error fetching translations for ${selectedLocale}:`, error); return null; } })); translationsResults.forEach((translationsResult) => { var _a, _b; if (translationsResult) { const { locale, headerTranslation, descriptionTranslation } = translationsResult; translationsToSaveDisplayHeader.push({ key: (_a = formData.displayHeader) === null || _a === void 0 ? void 0 : _a.substring(2, formData.displayHeader.length - 1), translations: [ { locale, value: headerTranslation, }, ], }); translationsToSaveDisplayDescription.push({ key: (_b = formData.displayDescription) === null || _b === void 0 ? void 0 : _b.substring(2, formData.displayDescription.length - 1), translations: [ { locale, value: descriptionTranslation, }, ], }); } }); return { translationsToSaveDisplayHeader, translationsToSaveDisplayDescription, }; }, (data) => { setTranslationsData({ displayHeader: { key: data.translationsToSaveDisplayHeader[0].key, translations: data.translationsToSaveDisplayHeader.flatMap((translationData) => translationData.translations), }, displayDescription: { key: data.translationsToSaveDisplayDescription[0].key, translations: data.translationsToSaveDisplayDescription.flatMap((translationData) => translationData.translations), }, }); }, [combinedLocales]); const saveTranslations = async () => { const addLocalization = async (key, locale, value) => { try { await adminClient.realms.addLocalization({ realm: realmName, selectedLocale: locale, key: key, }, value); } catch (error) { console.error(`Error saving translation for locale ${locale}: ${error}`); } }; try { if (translationsData.displayHeader && translationsData.displayHeader.translations.length > 0) { for (const translation of translationsData.displayHeader.translations) { await addLocalization(translationsData.displayHeader.key, translation.locale, translation.value); } } if (translationsData.displayDescription && translationsData.displayDescription.translations.length > 0) { for (const translation of translationsData.displayDescription .translations) { await addLocalization(translationsData.displayDescription.key, translation.locale, translation.value); } } } catch (error) { console.error(`Error while processing translations: ${error}`); } }; const onSubmit = async (values) => { var _a; if (!config) { return; } const groups = [...((_a = config.groups) !== null && _a !== void 0 ? _a : [])]; const updateAt = matchingGroup ? groups.indexOf(matchingGroup) : -1; const updatedGroup = { ...values, annotations: transformAnnotations(values.annotations), }; if (updateAt === -1) { groups.push(updatedGroup); } else { groups[updateAt] = updatedGroup; } if (realm === null || realm === void 0 ? void 0 : realm.internationalizationEnabled) { const hasNonEmptyDisplayHeaderTranslations = translationsData.displayHeader.translations.some((translation) => translation.value.trim() !== ""); const hasNonEmptyDisplayDescriptionTranslations = translationsData.displayDescription.translations.some((translation) => translation.value.trim() !== ""); if (!hasNonEmptyDisplayHeaderTranslations || !hasNonEmptyDisplayDescriptionTranslations) { addError("createAttributeError", t("translationError")); return; } } const success = await save({ ...config, groups }); if (success) { await saveTranslations(); getI18n().reloadResources(); navigate(toUserProfile({ realm: realmName, tab: "attributes-group" })); } }; const attributesGroupDisplayName = useWatch({ control: form.control, name: "displayHeader", }); const attributesGroupDisplayDescription = useWatch({ control: form.control, name: "displayDescription", }); const handleAttributesGroupNameChange = (event, value) => { const newDisplayName = value !== "" && (realm === null || realm === void 0 ? void 0 : realm.internationalizationEnabled) ? "${profile.attribute-group." + `${value}}` : ""; const newDisplayDescription = value !== "" && (realm === null || realm === void 0 ? void 0 : realm.internationalizationEnabled) ? "${profile.attribute-group-description." + `${value}}` : ""; setNewAttributesGroupName(value); setGeneratedAttributesGroupDisplayName(newDisplayName); setGeneratedAttributesGroupDisplayDescription(newDisplayDescription); }; const attributesGroupDisplayPatternMatch = regexPattern.test(attributesGroupDisplayName || attributesGroupDisplayDescription); const formattedAttributesGroupDisplayName = attributesGroupDisplayName === null || attributesGroupDisplayName === void 0 ? void 0 : attributesGroupDisplayName.substring(2, attributesGroupDisplayName.length - 1); const formattedAttributesGroupDisplayDescription = attributesGroupDisplayDescription === null || attributesGroupDisplayDescription === void 0 ? void 0 : attributesGroupDisplayDescription.substring(2, attributesGroupDisplayDescription.length - 1); const handleHeaderTranslationsAdded = (headerTranslations) => { setTranslationsData((prev) => ({ ...prev, displayHeader: headerTranslations, })); }; const handleDescriptionTranslationsAdded = (descriptionTranslations) => { setTranslationsData((prev) => ({ ...prev, displayDescription: descriptionTranslations, })); }; const handleToggleDialog = () => { toggleModal(); }; const groupDisplayNameKey = type === "displayHeader" ? formattedAttributesGroupDisplayName : `profile.attribute-group.${newAttributesGroupName}`; const groupDisplayDescriptionKey = type === "displayDescription" ? formattedAttributesGroupDisplayDescription : `profile.attribute-group-description.${newAttributesGroupName}`; return (_jsxs(_Fragment, { children: [addTranslationsModalOpen && (_jsx(AddTranslationsDialog, { translationKey: type === "displayHeader" ? groupDisplayNameKey : groupDisplayDescriptionKey, type: type === "displayHeader" ? "displayHeader" : "displayDescription", translations: type === "displayHeader" ? translationsData.displayHeader : translationsData.displayDescription, onTranslationsAdded: type === "displayHeader" ? handleHeaderTranslationsAdded : handleDescriptionTranslationsAdded, toggleDialog: handleToggleDialog, onCancel: () => { toggleModal(); } })), _jsx(ViewHeader, { titleKey: matchingGroup ? "editGroupText" : "createGroupText", divider: true }), _jsx(PageSection, { variant: "light", onSubmit: form.handleSubmit(onSubmit), children: _jsx(FormAccess, { isHorizontal: true, role: "manage-realm", children: _jsxs(FormProvider, { ...form, children: [_jsx(TextControl, { name: "name", label: t("nameField"), labelIcon: t("nameHintHelp"), isDisabled: !!matchingGroup || editMode, rules: { required: { value: true, message: t("required"), }, onChange: (event) => { handleAttributesGroupNameChange(event, event.target.value); }, } }), !!matchingGroup && (_jsx("input", { type: "hidden", ...form.register("name") })), _jsx(FormGroup, { label: t("displayHeaderField"), labelIcon: _jsx(HelpItem, { helpText: t("displayHeaderHintHelp"), fieldLabelId: "displayHeaderField" }), fieldId: "kc-attributes-group-display-header", children: _jsxs(Grid, { hasGutter: true, children: [_jsxs(GridItem, { span: (realm === null || realm === void 0 ? void 0 : realm.internationalizationEnabled) ? 11 : 12, children: [_jsx(TextInput, { id: "kc-attributes-group-display-header", "data-testid": "attributes-group-display-header", isDisabled: ((realm === null || realm === void 0 ? void 0 : realm.internationalizationEnabled) && newAttributesGroupName !== "") || (editMode && attributesGroupDisplayPatternMatch), value: editMode ? attributesGroupDisplayName : (realm === null || realm === void 0 ? void 0 : realm.internationalizationEnabled) ? generatedAttributesGroupDisplayName : undefined, ...form.register("displayHeader") }), generatedAttributesGroupDisplayName && (_jsx(Alert, { className: "pf-v5-u-mt-sm", variant: "info", isInline: true, isPlain: true, title: t("addAttributesGroupTranslationInfo") }))] }), (realm === null || realm === void 0 ? void 0 : realm.internationalizationEnabled) && (_jsx(GridItem, { span: 1, children: _jsx(Button, { variant: "link", className: "pf-m-plain", "data-testid": "addAttributeDisplayNameTranslationBtn", "aria-label": t("addAttributeDisplayNameTranslation"), isDisabled: !newAttributesGroupName && !editMode, onClick: () => { setType("displayHeader"); toggleModal(); }, icon: _jsx(GlobeRouteIcon, {}) }) }))] }) }), _jsx(FormGroup, { label: t("displayDescriptionField"), labelIcon: _jsx(HelpItem, { helpText: t("displayDescriptionHintHelp"), fieldLabelId: "displayDescriptionField" }), fieldId: "kc-attributes-group-display-description", children: _jsxs(Grid, { hasGutter: true, children: [_jsxs(GridItem, { span: (realm === null || realm === void 0 ? void 0 : realm.internationalizationEnabled) ? 11 : 12, children: [_jsx(TextInput, { id: "kc-attributes-group-display-description", "data-testid": "attributes-group-display-description", isDisabled: ((realm === null || realm === void 0 ? void 0 : realm.internationalizationEnabled) && newAttributesGroupName !== "") || (editMode && attributesGroupDisplayPatternMatch), value: editMode ? attributesGroupDisplayDescription : (realm === null || realm === void 0 ? void 0 : realm.internationalizationEnabled) ? generatedAttributesGroupDisplayDescription : undefined, ...form.register("displayDescription") }), generatedAttributesGroupDisplayDescription && (_jsx(Alert, { className: "pf-v5-u-mt-sm", variant: "info", isInline: true, isPlain: true, title: t("addAttributesGroupTranslationInfo") }))] }), (realm === null || realm === void 0 ? void 0 : realm.internationalizationEnabled) && (_jsx(GridItem, { span: 1, children: _jsx(Button, { variant: "link", className: "pf-m-plain", "data-testid": "addAttributeDisplayDescriptionTranslationBtn", "aria-label": t("addAttributeDisplayDescriptionTranslation"), isDisabled: !newAttributesGroupName && !editMode, onClick: () => { setType("displayDescription"); toggleModal(); }, icon: _jsx(GlobeRouteIcon, {}) }) }))] }) }), _jsx(TextContent, { children: _jsx(Text, { component: "h2", children: t("annotationsText") }) }), _jsx(FormGroup, { label: t("annotationsText"), fieldId: "kc-annotations", children: _jsx(KeyValueInput, { label: t("annotationsText"), name: "annotations" }) }), _jsxs(ActionGroup, { children: [_jsx(Button, { variant: "primary", type: "submit", "data-testid": "saveGroupBtn", children: t("save") }), _jsx(Button, { variant: "link", component: (props) => (_jsx(Link, { ...props, to: toUserProfile({ realm: realmName, tab: "attributes-group", }) })), children: t("cancel") })] })] }) }) })] })); } //# sourceMappingURL=AttributesGroupForm.js.map