From 6cdb83d73027c2d9ed3c199dc47cd607616af7db Mon Sep 17 00:00:00 2001 From: Joseph Garrone Date: Sun, 2 Jun 2024 00:24:07 +0200 Subject: [PATCH] Fix the way we handle multivalued single fileld (multiselct, multiselect-checkboxes) --- src/login/lib/useUserProfileForm.tsx | 37 ++++++++++++++++++++++------ src/tools/deepAssign.ts | 4 +-- src/tools/deepClone.ts | 19 -------------- 3 files changed, 32 insertions(+), 28 deletions(-) delete mode 100644 src/tools/deepClone.ts diff --git a/src/login/lib/useUserProfileForm.tsx b/src/login/lib/useUserProfileForm.tsx index 7493ebe7..c265a470 100644 --- a/src/login/lib/useUserProfileForm.tsx +++ b/src/login/lib/useUserProfileForm.tsx @@ -9,6 +9,7 @@ import type { KcContext, PasswordPolicies } from "keycloakify/login/kcContext/Kc import { assert, type Equals } from "tsafe/assert"; import { formatNumber } from "keycloakify/tools/formatNumber"; import { createUseInsertScriptTags } from "keycloakify/tools/useInsertScriptTags"; +import { structuredCloneButFunctions } from "tools/structuredCloneButFunctions"; import type { I18n } from "../i18n"; export type FormFieldError = { @@ -242,7 +243,7 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy })(); for (const attribute of attributes) { - syntheticAttributes.push(attribute); + syntheticAttributes.push(structuredCloneButFunctions(attribute)); add_password_and_password_confirm: { if (!kcContext.passwordRequired) { @@ -284,6 +285,21 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy } } + // NOTE: Consistency patch + syntheticAttributes.forEach(attribute => { + if (getIsMultivaluedSingleField({ attribute })) { + attribute.multivalued = true; + } + + if (attribute.multivalued) { + attribute.values ??= attribute.value !== undefined ? [attribute.value] : []; + delete attribute.value; + } else { + attribute.value ??= attribute.values?.[0]; + delete attribute.values; + } + }); + return syntheticAttributes; })(); @@ -299,10 +315,10 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy break handle_multi_valued_attribute; } - const values = attribute.values ?? [""]; + const values = attribute.values?.length ? attribute.values : [""]; apply_validator_min_range: { - if (attribute.annotations.inputType?.startsWith("multiselect")) { + if (getIsMultivaluedSingleField({ attribute })) { break apply_validator_min_range; } @@ -349,7 +365,8 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy attributeName: attribute.name, formFieldStates: initialFormFieldState }), - hasLostFocusAtLeastOnce: valueOrValues instanceof Array ? valueOrValues.map(() => false) : false, + hasLostFocusAtLeastOnce: + valueOrValues instanceof Array && !getIsMultivaluedSingleField({ attribute }) ? valueOrValues.map(() => false) : false, valueOrValues: valueOrValues })) }; @@ -543,7 +560,7 @@ function useGetErrors(params: { kcContext: Pick { var dereferencedSource = source[key]; diff --git a/src/tools/deepClone.ts b/src/tools/deepClone.ts deleted file mode 100644 index 78833adf..00000000 --- a/src/tools/deepClone.ts +++ /dev/null @@ -1,19 +0,0 @@ -import "minimal-polyfills/Object.fromEntries"; - -export function deepClone(o: T): T { - if (!(o instanceof Object)) { - return o; - } - - if (typeof o === "function") { - return o; - } - - if (o instanceof Array) { - return o.map(deepClone) as any; - } - - return Object.fromEntries( - Object.entries(o).map(([key, value]) => [key, deepClone(value)]) - ) as any; -}