Better debugging experience with user profile
This commit is contained in:
parent
59386241b4
commit
747248454d
@ -1,13 +1,12 @@
|
|||||||
import type { KcContextBase } from "./KcContextBase";
|
import type { KcContextBase, Attribute } from "./KcContextBase";
|
||||||
import { kcContextMocks, kcContextCommonMock } from "./kcContextMocks";
|
import { kcContextMocks, kcContextCommonMock } from "./kcContextMocks";
|
||||||
import { ftlValuesGlobalName } from "../../bin/build-keycloak-theme/ftlValuesGlobalName";
|
|
||||||
import type { AndByDiscriminatingKey } from "../tools/AndByDiscriminatingKey";
|
|
||||||
import type { DeepPartial } from "../tools/DeepPartial";
|
import type { DeepPartial } from "../tools/DeepPartial";
|
||||||
import { deepAssign } from "../tools/deepAssign";
|
import { deepAssign } from "../tools/deepAssign";
|
||||||
|
import { id } from "tsafe/id";
|
||||||
export type ExtendsKcContextBase<KcContextExtended extends { pageId: string }> = [KcContextExtended] extends [never]
|
import { exclude } from "tsafe/exclude";
|
||||||
? KcContextBase
|
import { assert } from "tsafe/assert";
|
||||||
: AndByDiscriminatingKey<"pageId", KcContextExtended & KcContextBase.Common, KcContextBase>;
|
import type { ExtendsKcContextBase } from "./getKcContextFromWindow";
|
||||||
|
import { getKcContextFromWindow } from "./getKcContextFromWindow";
|
||||||
|
|
||||||
export function getKcContext<KcContextExtended extends { pageId: string } = never>(params?: {
|
export function getKcContext<KcContextExtended extends { pageId: string } = never>(params?: {
|
||||||
mockPageId?: ExtendsKcContextBase<KcContextExtended>["pageId"];
|
mockPageId?: ExtendsKcContextBase<KcContextExtended>["pageId"];
|
||||||
@ -44,12 +43,55 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
|
|||||||
"target": kcContext,
|
"target": kcContext,
|
||||||
"source": partialKcContextCustomMock,
|
"source": partialKcContextCustomMock,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (partialKcContextCustomMock.pageId === "register-user-profile.ftl") {
|
||||||
|
assert(kcContextDefaultMock?.pageId === "register-user-profile.ftl");
|
||||||
|
|
||||||
|
const { attributes } = kcContextDefaultMock.profile;
|
||||||
|
|
||||||
|
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes = [];
|
||||||
|
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName = {};
|
||||||
|
|
||||||
|
const partialAttributes = [
|
||||||
|
...((partialKcContextCustomMock as DeepPartial<KcContextBase.RegisterUserProfile>).profile?.attributes ?? []),
|
||||||
|
].filter(exclude(undefined));
|
||||||
|
|
||||||
|
attributes.forEach(attribute => {
|
||||||
|
const partialAttribute = partialAttributes.find(({ name }) => name === attribute.name);
|
||||||
|
|
||||||
|
const augmentedAttribute: Attribute = {} as any;
|
||||||
|
|
||||||
|
deepAssign({
|
||||||
|
"target": augmentedAttribute,
|
||||||
|
"source": attribute,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (partialAttribute !== undefined) {
|
||||||
|
partialAttributes.splice(partialAttributes.indexOf(partialAttribute), 1);
|
||||||
|
|
||||||
|
deepAssign({
|
||||||
|
"target": augmentedAttribute,
|
||||||
|
"source": partialAttribute,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes.push(augmentedAttribute);
|
||||||
|
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[augmentedAttribute.name] = augmentedAttribute;
|
||||||
|
});
|
||||||
|
|
||||||
|
partialAttributes.forEach(partialAttribute => {
|
||||||
|
const { name } = partialAttribute;
|
||||||
|
|
||||||
|
assert(name !== undefined, "If you define a mock attribute it must have at least a name");
|
||||||
|
|
||||||
|
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes.push(partialAttribute as any);
|
||||||
|
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[name] = partialAttribute as any;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { kcContext };
|
return { kcContext };
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return { "kcContext": getKcContextFromWindow<KcContextExtended>() };
|
||||||
"kcContext": typeof window === "undefined" ? undefined : (window as any)[ftlValuesGlobalName],
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
11
src/lib/getKcContext/getKcContextFromWindow.ts
Normal file
11
src/lib/getKcContext/getKcContextFromWindow.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import type { KcContextBase } from "./KcContextBase";
|
||||||
|
import type { AndByDiscriminatingKey } from "../tools/AndByDiscriminatingKey";
|
||||||
|
import { ftlValuesGlobalName } from "../../bin/build-keycloak-theme/ftlValuesGlobalName";
|
||||||
|
|
||||||
|
export type ExtendsKcContextBase<KcContextExtended extends { pageId: string }> = [KcContextExtended] extends [never]
|
||||||
|
? KcContextBase
|
||||||
|
: AndByDiscriminatingKey<"pageId", KcContextExtended & KcContextBase.Common, KcContextBase>;
|
||||||
|
|
||||||
|
export function getKcContextFromWindow<KcContextExtended extends { pageId: string } = never>(): ExtendsKcContextBase<KcContextExtended> | undefined {
|
||||||
|
return typeof window === "undefined" ? undefined : (window as any)[ftlValuesGlobalName];
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
export type { KcContextBase, Attribute, Validators } from "./KcContextBase";
|
export type { KcContextBase, Attribute, Validators } from "./KcContextBase";
|
||||||
|
export type { ExtendsKcContextBase } from "./getKcContextFromWindow";
|
||||||
export { getKcContext } from "./getKcContext";
|
export { getKcContext } from "./getKcContext";
|
||||||
|
@ -278,29 +278,6 @@ export const kcContextMocks: KcContextBase[] = [
|
|||||||
"readOnly": false,
|
"readOnly": false,
|
||||||
"name": "lastName",
|
"name": "lastName",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"validators": {
|
|
||||||
"length": {
|
|
||||||
"ignore.empty.value": true,
|
|
||||||
"min": "3",
|
|
||||||
"max": "9",
|
|
||||||
},
|
|
||||||
"up-immutable-attribute": {},
|
|
||||||
"up-attribute-required-by-metadata-value": {},
|
|
||||||
"email": {
|
|
||||||
"ignore.empty.value": true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"displayName": "${foo}",
|
|
||||||
"annotations": {
|
|
||||||
"this_is_second_key": "this_is_second_value",
|
|
||||||
"this_is_first_key": "this_is_first_value",
|
|
||||||
},
|
|
||||||
"required": true,
|
|
||||||
"groupAnnotations": {},
|
|
||||||
"readOnly": false,
|
|
||||||
"name": "foo",
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createUseGlobalState } from "powerhooks/useGlobalState";
|
import { createUseGlobalState } from "powerhooks/useGlobalState";
|
||||||
import { getKcContext } from "../getKcContext";
|
import { getKcContextFromWindow } from "../getKcContext/getKcContextFromWindow";
|
||||||
import { getBestMatchAmongKcLanguageTag } from "./KcLanguageTag";
|
import { getBestMatchAmongKcLanguageTag } from "./KcLanguageTag";
|
||||||
import type { StatefulEvt } from "powerhooks";
|
import type { StatefulEvt } from "powerhooks";
|
||||||
import { KcLanguageTag } from "./KcLanguageTag";
|
import { KcLanguageTag } from "./KcLanguageTag";
|
||||||
@ -8,7 +8,7 @@ import { KcLanguageTag } from "./KcLanguageTag";
|
|||||||
const wrap = createUseGlobalState(
|
const wrap = createUseGlobalState(
|
||||||
"kcLanguageTag",
|
"kcLanguageTag",
|
||||||
() => {
|
() => {
|
||||||
const { kcContext } = getKcContext();
|
const kcContext = getKcContextFromWindow();
|
||||||
|
|
||||||
const languageLike = kcContext?.locale?.current ?? (typeof navigator === "undefined" ? undefined : navigator.language);
|
const languageLike = kcContext?.locale?.current ?? (typeof navigator === "undefined" ? undefined : navigator.language);
|
||||||
|
|
||||||
|
@ -1,9 +1,38 @@
|
|||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
import { is } from "tsafe/is";
|
import { is } from "tsafe/is";
|
||||||
|
|
||||||
|
function deepClone<T>(src: T): T {
|
||||||
|
const generateId = (() => {
|
||||||
|
const prefix = "xIfKdLsIIdJdLdOeJqePe";
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
return () => `${prefix}${counter++}`;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const map = new Map<string, Function>();
|
||||||
|
|
||||||
|
return JSON.parse(
|
||||||
|
JSON.stringify(src, (...[, value]) => {
|
||||||
|
if (typeof value === "function") {
|
||||||
|
const id = generateId();
|
||||||
|
|
||||||
|
map.set(id, value);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}),
|
||||||
|
(...[, value]) => (typeof value === "string" && map.has(value) ? map.get(value) : value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
//Warning: Be mindful that because of array this is not idempotent.
|
//Warning: Be mindful that because of array this is not idempotent.
|
||||||
export function deepAssign(params: { target: Record<string, unknown>; source: Record<string, unknown> }) {
|
export function deepAssign(params: { target: Record<string, unknown>; source: Record<string, unknown> }) {
|
||||||
const { target, source } = params;
|
const { target } = params;
|
||||||
|
|
||||||
|
const source = deepClone(params.source);
|
||||||
|
|
||||||
Object.keys(source).forEach(key => {
|
Object.keys(source).forEach(key => {
|
||||||
var dereferencedSource = source[key];
|
var dereferencedSource = source[key];
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { getKcContext } from "../../lib/getKcContext";
|
import { getKcContext } from "../../lib/getKcContext";
|
||||||
import type { KcContextBase } from "../../lib/getKcContext";
|
import type { KcContextBase } from "../../lib/getKcContext";
|
||||||
import type { ExtendsKcContextBase } from "../../lib/getKcContext/getKcContext";
|
import type { ExtendsKcContextBase } from "../../lib/getKcContext";
|
||||||
import { same } from "evt/tools/inDepth";
|
import { same } from "evt/tools/inDepth";
|
||||||
import { assert } from "tsafe/assert";
|
import { assert } from "tsafe/assert";
|
||||||
import type { Equals } from "tsafe";
|
import type { Equals } from "tsafe";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user