keycloakify 6.1.0 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/keycloakify/generateFtl/generateFtl.d.ts +1 -1
- package/bin/keycloakify/generateFtl/generateFtl.js +2 -1
- package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
- package/bin/tsconfig.tsbuildinfo +1 -1
- package/lib/components/KcApp.js +3 -0
- package/lib/components/KcApp.js.map +1 -1
- package/lib/components/RegisterUserProfile.js +3 -62
- package/lib/components/RegisterUserProfile.js.map +1 -1
- package/lib/components/UpdateUserProfile.d.ts +9 -0
- package/lib/components/UpdateUserProfile.js +32 -0
- package/lib/components/UpdateUserProfile.js.map +1 -0
- package/lib/components/shared/UserProfileCommons.d.ts +17 -0
- package/lib/components/shared/UserProfileCommons.js +76 -0
- package/lib/components/shared/UserProfileCommons.js.map +1 -0
- package/lib/getKcContext/KcContextBase.d.ts +9 -1
- package/lib/getKcContext/KcContextBase.js.map +1 -1
- package/lib/getKcContext/kcContextMocks/kcContextMocks.js +103 -98
- package/lib/getKcContext/kcContextMocks/kcContextMocks.js.map +1 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/useFormValidationSlice.d.ts +1 -1
- package/package.json +9 -1
- package/src/bin/keycloakify/generateFtl/generateFtl.ts +2 -1
- package/src/lib/components/KcApp.tsx +3 -0
- package/src/lib/components/RegisterUserProfile.tsx +10 -157
- package/src/lib/components/UpdateUserProfile.tsx +77 -0
- package/src/lib/components/shared/UserProfileCommons.tsx +172 -0
- package/src/lib/getKcContext/KcContextBase.ts +11 -1
- package/src/lib/getKcContext/kcContextMocks/kcContextMocks.ts +105 -98
- package/src/lib/useFormValidationSlice.tsx +1 -1
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "keycloakify",
|
3
|
-
"version": "6.
|
3
|
+
"version": "6.2.0",
|
4
4
|
"description": "Keycloak theme generator for Reacts app",
|
5
5
|
"repository": {
|
6
6
|
"type": "git",
|
@@ -78,6 +78,8 @@
|
|
78
78
|
"src/lib/components/RegisterUserProfile.tsx",
|
79
79
|
"src/lib/components/Template.tsx",
|
80
80
|
"src/lib/components/Terms.tsx",
|
81
|
+
"src/lib/components/UpdateUserProfile.tsx",
|
82
|
+
"src/lib/components/shared/UserProfileCommons.tsx",
|
81
83
|
"src/lib/getKcContext/KcContextBase.ts",
|
82
84
|
"src/lib/getKcContext/getKcContext.ts",
|
83
85
|
"src/lib/getKcContext/getKcContextFromWindow.ts",
|
@@ -487,6 +489,12 @@
|
|
487
489
|
"lib/components/Terms.d.ts",
|
488
490
|
"lib/components/Terms.js",
|
489
491
|
"lib/components/Terms.js.map",
|
492
|
+
"lib/components/UpdateUserProfile.d.ts",
|
493
|
+
"lib/components/UpdateUserProfile.js",
|
494
|
+
"lib/components/UpdateUserProfile.js.map",
|
495
|
+
"lib/components/shared/UserProfileCommons.d.ts",
|
496
|
+
"lib/components/shared/UserProfileCommons.js",
|
497
|
+
"lib/components/shared/UserProfileCommons.js.map",
|
490
498
|
"lib/getKcContext/KcContextBase.d.ts",
|
491
499
|
"lib/getKcContext/KcContextBase.js",
|
492
500
|
"lib/getKcContext/KcContextBase.js.map",
|
@@ -27,7 +27,8 @@ export const pageIds = [
|
|
27
27
|
"login-idp-link-email.ftl",
|
28
28
|
"login-page-expired.ftl",
|
29
29
|
"login-config-totp.ftl",
|
30
|
-
"logout-confirm.ftl"
|
30
|
+
"logout-confirm.ftl",
|
31
|
+
"update-user-profile.ftl"
|
31
32
|
] as const;
|
32
33
|
|
33
34
|
export type BuildOptionsLike = BuildOptionsLike.Standalone | BuildOptionsLike.ExternalAssets;
|
@@ -20,6 +20,7 @@ const LoginPageExpired = lazy(() => import("./LoginPageExpired"));
|
|
20
20
|
const LoginIdpLinkEmail = lazy(() => import("./LoginIdpLinkEmail"));
|
21
21
|
const LoginConfigTotp = lazy(() => import("./LoginConfigTotp"));
|
22
22
|
const LogoutConfirm = lazy(() => import("./LogoutConfirm"));
|
23
|
+
const UpdateUserProfile = lazy(() => import("./UpdateUserProfile"));
|
23
24
|
|
24
25
|
const KcApp = memo(({ kcContext, i18n: userProvidedI18n, ...kcProps }: { kcContext: KcContextBase; i18n?: I18n } & KcProps) => {
|
25
26
|
const i18n = (function useClosure() {
|
@@ -74,6 +75,8 @@ const KcApp = memo(({ kcContext, i18n: userProvidedI18n, ...kcProps }: { kcConte
|
|
74
75
|
return <LoginConfigTotp {...{ kcContext, ...props }} />;
|
75
76
|
case "logout-confirm.ftl":
|
76
77
|
return <LogoutConfirm {...{ kcContext, ...props }} />;
|
78
|
+
case "update-user-profile.ftl":
|
79
|
+
return <UpdateUserProfile {...{ kcContext, ...props }} />;
|
77
80
|
}
|
78
81
|
})()}
|
79
82
|
</Suspense>
|
@@ -1,12 +1,10 @@
|
|
1
|
-
import React, { useMemo, memo,
|
1
|
+
import React, { useMemo, memo, useState } from "react";
|
2
2
|
import Template from "./Template";
|
3
3
|
import type { KcProps } from "./KcProps";
|
4
|
-
import type { KcContextBase
|
4
|
+
import type { KcContextBase } from "../getKcContext/KcContextBase";
|
5
5
|
import { useCssAndCx } from "../tools/useCssAndCx";
|
6
|
-
import type { ReactComponent } from "../tools/ReactComponent";
|
7
|
-
import { useCallbackFactory } from "powerhooks/useCallbackFactory";
|
8
|
-
import { useFormValidationSlice } from "../useFormValidationSlice";
|
9
6
|
import type { I18n } from "../i18n";
|
7
|
+
import { UserProfileFormFields } from "./shared/UserProfileCommons";
|
10
8
|
|
11
9
|
const RegisterUserProfile = memo(({ kcContext, i18n, ...props_ }: { kcContext: KcContextBase.RegisterUserProfile; i18n: I18n } & KcProps) => {
|
12
10
|
const { url, messagesPerField, recaptchaRequired, recaptchaSiteKey } = kcContext;
|
@@ -34,7 +32,13 @@ const RegisterUserProfile = memo(({ kcContext, i18n, ...props_ }: { kcContext: K
|
|
34
32
|
headerNode={msg("registerTitle")}
|
35
33
|
formNode={
|
36
34
|
<form id="kc-register-form" className={cx(props.kcFormClass)} action={url.registrationAction} method="post">
|
37
|
-
<UserProfileFormFields
|
35
|
+
<UserProfileFormFields
|
36
|
+
kcContext={kcContext}
|
37
|
+
doInsertPasswordFields={true}
|
38
|
+
onIsFormSubmittableValueChange={setIsFomSubmittable}
|
39
|
+
i18n={i18n}
|
40
|
+
{...props}
|
41
|
+
/>
|
38
42
|
{recaptchaRequired && (
|
39
43
|
<div className="form-group">
|
40
44
|
<div className={cx(props.kcInputWrapperClass)}>
|
@@ -66,155 +70,4 @@ const RegisterUserProfile = memo(({ kcContext, i18n, ...props_ }: { kcContext: K
|
|
66
70
|
);
|
67
71
|
});
|
68
72
|
|
69
|
-
type UserProfileFormFieldsProps = { kcContext: KcContextBase.RegisterUserProfile; i18n: I18n } & KcProps &
|
70
|
-
Partial<Record<"BeforeField" | "AfterField", ReactComponent<{ attribute: Attribute }>>> & {
|
71
|
-
onIsFormSubmittableValueChange: (isFormSubmittable: boolean) => void;
|
72
|
-
};
|
73
|
-
|
74
|
-
const UserProfileFormFields = memo(({ kcContext, onIsFormSubmittableValueChange, i18n, ...props }: UserProfileFormFieldsProps) => {
|
75
|
-
const { cx, css } = useCssAndCx();
|
76
|
-
|
77
|
-
const { advancedMsg } = i18n;
|
78
|
-
|
79
|
-
const {
|
80
|
-
formValidationState: { fieldStateByAttributeName, isFormSubmittable },
|
81
|
-
formValidationReducer,
|
82
|
-
attributesWithPassword
|
83
|
-
} = useFormValidationSlice({
|
84
|
-
kcContext,
|
85
|
-
i18n
|
86
|
-
});
|
87
|
-
|
88
|
-
useEffect(() => {
|
89
|
-
onIsFormSubmittableValueChange(isFormSubmittable);
|
90
|
-
}, [isFormSubmittable]);
|
91
|
-
|
92
|
-
const onChangeFactory = useCallbackFactory(
|
93
|
-
(
|
94
|
-
[name]: [string],
|
95
|
-
[
|
96
|
-
{
|
97
|
-
target: { value }
|
98
|
-
}
|
99
|
-
]: [React.ChangeEvent<HTMLInputElement | HTMLSelectElement>]
|
100
|
-
) =>
|
101
|
-
formValidationReducer({
|
102
|
-
"action": "update value",
|
103
|
-
name,
|
104
|
-
"newValue": value
|
105
|
-
})
|
106
|
-
);
|
107
|
-
|
108
|
-
const onBlurFactory = useCallbackFactory(([name]: [string]) =>
|
109
|
-
formValidationReducer({
|
110
|
-
"action": "focus lost",
|
111
|
-
name
|
112
|
-
})
|
113
|
-
);
|
114
|
-
|
115
|
-
let currentGroup = "";
|
116
|
-
|
117
|
-
return (
|
118
|
-
<>
|
119
|
-
{attributesWithPassword.map((attribute, i) => {
|
120
|
-
const { group = "", groupDisplayHeader = "", groupDisplayDescription = "" } = attribute;
|
121
|
-
|
122
|
-
const { value, displayableErrors } = fieldStateByAttributeName[attribute.name];
|
123
|
-
|
124
|
-
const formGroupClassName = cx(props.kcFormGroupClass, displayableErrors.length !== 0 && props.kcFormGroupErrorClass);
|
125
|
-
|
126
|
-
return (
|
127
|
-
<Fragment key={i}>
|
128
|
-
{group !== currentGroup && (currentGroup = group) !== "" && (
|
129
|
-
<div className={formGroupClassName}>
|
130
|
-
<div className={cx(props.kcContentWrapperClass)}>
|
131
|
-
<label id={`header-${group}`} className={cx(props.kcFormGroupHeader)}>
|
132
|
-
{advancedMsg(groupDisplayHeader) || currentGroup}
|
133
|
-
</label>
|
134
|
-
</div>
|
135
|
-
{groupDisplayDescription !== "" && (
|
136
|
-
<div className={cx(props.kcLabelWrapperClass)}>
|
137
|
-
<label id={`description-${group}`} className={`${cx(props.kcLabelClass)}`}>
|
138
|
-
{advancedMsg(groupDisplayDescription)}
|
139
|
-
</label>
|
140
|
-
</div>
|
141
|
-
)}
|
142
|
-
</div>
|
143
|
-
)}
|
144
|
-
<div className={formGroupClassName}>
|
145
|
-
<div className={cx(props.kcLabelWrapperClass)}>
|
146
|
-
<label htmlFor={attribute.name} className={cx(props.kcLabelClass)}>
|
147
|
-
{advancedMsg(attribute.displayName ?? "")}
|
148
|
-
</label>
|
149
|
-
{attribute.required && <>*</>}
|
150
|
-
</div>
|
151
|
-
<div className={cx(props.kcInputWrapperClass)}>
|
152
|
-
{(() => {
|
153
|
-
const { options } = attribute.validators;
|
154
|
-
|
155
|
-
if (options !== undefined) {
|
156
|
-
return (
|
157
|
-
<select
|
158
|
-
id={attribute.name}
|
159
|
-
name={attribute.name}
|
160
|
-
onChange={onChangeFactory(attribute.name)}
|
161
|
-
onBlur={onBlurFactory(attribute.name)}
|
162
|
-
value={value}
|
163
|
-
>
|
164
|
-
{options.options.map(option => (
|
165
|
-
<option key={option} value={option}>
|
166
|
-
{option}
|
167
|
-
</option>
|
168
|
-
))}
|
169
|
-
</select>
|
170
|
-
);
|
171
|
-
}
|
172
|
-
|
173
|
-
return (
|
174
|
-
<input
|
175
|
-
type={(() => {
|
176
|
-
switch (attribute.name) {
|
177
|
-
case "password-confirm":
|
178
|
-
case "password":
|
179
|
-
return "password";
|
180
|
-
default:
|
181
|
-
return "text";
|
182
|
-
}
|
183
|
-
})()}
|
184
|
-
id={attribute.name}
|
185
|
-
name={attribute.name}
|
186
|
-
value={value}
|
187
|
-
onChange={onChangeFactory(attribute.name)}
|
188
|
-
className={cx(props.kcInputClass)}
|
189
|
-
aria-invalid={displayableErrors.length !== 0}
|
190
|
-
disabled={attribute.readOnly}
|
191
|
-
autoComplete={attribute.autocomplete}
|
192
|
-
onBlur={onBlurFactory(attribute.name)}
|
193
|
-
/>
|
194
|
-
);
|
195
|
-
})()}
|
196
|
-
{displayableErrors.length !== 0 && (
|
197
|
-
<span
|
198
|
-
id={`input-error-${attribute.name}`}
|
199
|
-
className={cx(
|
200
|
-
props.kcInputErrorMessageClass,
|
201
|
-
css({
|
202
|
-
"position": displayableErrors.length === 1 ? "absolute" : undefined,
|
203
|
-
"& > span": { "display": "block" }
|
204
|
-
})
|
205
|
-
)}
|
206
|
-
aria-live="polite"
|
207
|
-
>
|
208
|
-
{displayableErrors.map(({ errorMessage }) => errorMessage)}
|
209
|
-
</span>
|
210
|
-
)}
|
211
|
-
</div>
|
212
|
-
</div>
|
213
|
-
</Fragment>
|
214
|
-
);
|
215
|
-
})}
|
216
|
-
</>
|
217
|
-
);
|
218
|
-
});
|
219
|
-
|
220
73
|
export default RegisterUserProfile;
|
@@ -0,0 +1,77 @@
|
|
1
|
+
import React, { useState, memo } from "react";
|
2
|
+
import Template from "./Template";
|
3
|
+
import type { KcProps } from "./KcProps";
|
4
|
+
import type { KcContextBase } from "../getKcContext/KcContextBase";
|
5
|
+
import { useCssAndCx } from "../tools/useCssAndCx";
|
6
|
+
import type { I18n } from "../i18n";
|
7
|
+
import { UserProfileFormFields } from "./shared/UserProfileCommons";
|
8
|
+
|
9
|
+
const LoginUpdateProfile = memo(({ kcContext, i18n, ...props }: { kcContext: KcContextBase.UpdateUserProfile; i18n: I18n } & KcProps) => {
|
10
|
+
const { cx } = useCssAndCx();
|
11
|
+
|
12
|
+
const { msg, msgStr } = i18n;
|
13
|
+
|
14
|
+
const { url, isAppInitiatedAction } = kcContext;
|
15
|
+
|
16
|
+
const [isFomSubmittable, setIsFomSubmittable] = useState(false);
|
17
|
+
|
18
|
+
return (
|
19
|
+
<Template
|
20
|
+
{...{ kcContext, i18n, ...props }}
|
21
|
+
doFetchDefaultThemeResources={true}
|
22
|
+
headerNode={msg("loginProfileTitle")}
|
23
|
+
formNode={
|
24
|
+
<form id="kc-update-profile-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post">
|
25
|
+
<UserProfileFormFields
|
26
|
+
kcContext={kcContext}
|
27
|
+
doInsertPasswordFields={true}
|
28
|
+
onIsFormSubmittableValueChange={setIsFomSubmittable}
|
29
|
+
i18n={i18n}
|
30
|
+
{...props}
|
31
|
+
/>
|
32
|
+
|
33
|
+
<div className={cx(props.kcFormGroupClass)}>
|
34
|
+
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
|
35
|
+
<div className={cx(props.kcFormOptionsWrapperClass)}></div>
|
36
|
+
</div>
|
37
|
+
|
38
|
+
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
|
39
|
+
{isAppInitiatedAction ? (
|
40
|
+
<>
|
41
|
+
<input
|
42
|
+
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonLargeClass)}
|
43
|
+
type="submit"
|
44
|
+
value={msgStr("doSubmit")}
|
45
|
+
/>
|
46
|
+
<button
|
47
|
+
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonLargeClass)}
|
48
|
+
type="submit"
|
49
|
+
name="cancel-aia"
|
50
|
+
value="true"
|
51
|
+
formNoValidate
|
52
|
+
>
|
53
|
+
{msg("doCancel")}
|
54
|
+
</button>
|
55
|
+
</>
|
56
|
+
) : (
|
57
|
+
<input
|
58
|
+
className={cx(
|
59
|
+
props.kcButtonClass,
|
60
|
+
props.kcButtonPrimaryClass,
|
61
|
+
props.kcButtonBlockClass,
|
62
|
+
props.kcButtonLargeClass
|
63
|
+
)}
|
64
|
+
type="submit"
|
65
|
+
defaultValue={msgStr("doSubmit")}
|
66
|
+
disabled={!isFomSubmittable}
|
67
|
+
/>
|
68
|
+
)}
|
69
|
+
</div>
|
70
|
+
</div>
|
71
|
+
</form>
|
72
|
+
}
|
73
|
+
/>
|
74
|
+
);
|
75
|
+
});
|
76
|
+
|
77
|
+
export default LoginUpdateProfile;
|
@@ -0,0 +1,172 @@
|
|
1
|
+
import React, { memo, useEffect, Fragment } from "react";
|
2
|
+
import type { KcProps } from "../KcProps";
|
3
|
+
import type { Attribute } from "../../getKcContext/KcContextBase";
|
4
|
+
import { useCssAndCx } from "../../tools/useCssAndCx";
|
5
|
+
import type { ReactComponent } from "../../tools/ReactComponent";
|
6
|
+
import { useCallbackFactory } from "powerhooks/useCallbackFactory";
|
7
|
+
import { useFormValidationSlice } from "../../useFormValidationSlice";
|
8
|
+
import type { I18n } from "../../i18n";
|
9
|
+
import type { Param0 } from "tsafe/Param0";
|
10
|
+
|
11
|
+
export type UserProfileFormFieldsProps = {
|
12
|
+
//kcContext: KcContextBase.RegisterUserProfile;
|
13
|
+
kcContext: Param0<typeof useFormValidationSlice>["kcContext"];
|
14
|
+
doInsertPasswordFields: boolean;
|
15
|
+
i18n: I18n;
|
16
|
+
} & KcProps &
|
17
|
+
Partial<Record<"BeforeField" | "AfterField", ReactComponent<{ attribute: Attribute }>>> & {
|
18
|
+
onIsFormSubmittableValueChange: (isFormSubmittable: boolean) => void;
|
19
|
+
};
|
20
|
+
|
21
|
+
export const UserProfileFormFields = memo(
|
22
|
+
({ kcContext, doInsertPasswordFields, onIsFormSubmittableValueChange, i18n, BeforeField, AfterField, ...props }: UserProfileFormFieldsProps) => {
|
23
|
+
const { cx, css } = useCssAndCx();
|
24
|
+
|
25
|
+
const { advancedMsg } = i18n;
|
26
|
+
|
27
|
+
const {
|
28
|
+
formValidationState: { fieldStateByAttributeName, isFormSubmittable },
|
29
|
+
formValidationReducer,
|
30
|
+
attributesWithPassword
|
31
|
+
} = useFormValidationSlice({
|
32
|
+
kcContext,
|
33
|
+
i18n
|
34
|
+
});
|
35
|
+
|
36
|
+
useEffect(() => {
|
37
|
+
onIsFormSubmittableValueChange(isFormSubmittable);
|
38
|
+
}, [isFormSubmittable]);
|
39
|
+
|
40
|
+
const onChangeFactory = useCallbackFactory(
|
41
|
+
(
|
42
|
+
[name]: [string],
|
43
|
+
[
|
44
|
+
{
|
45
|
+
target: { value }
|
46
|
+
}
|
47
|
+
]: [React.ChangeEvent<HTMLInputElement | HTMLSelectElement>]
|
48
|
+
) =>
|
49
|
+
formValidationReducer({
|
50
|
+
"action": "update value",
|
51
|
+
name,
|
52
|
+
"newValue": value
|
53
|
+
})
|
54
|
+
);
|
55
|
+
|
56
|
+
const onBlurFactory = useCallbackFactory(([name]: [string]) =>
|
57
|
+
formValidationReducer({
|
58
|
+
"action": "focus lost",
|
59
|
+
name
|
60
|
+
})
|
61
|
+
);
|
62
|
+
|
63
|
+
let currentGroup = "";
|
64
|
+
|
65
|
+
return (
|
66
|
+
<>
|
67
|
+
{(doInsertPasswordFields ? attributesWithPassword : kcContext.profile.attributes).map((attribute, i) => {
|
68
|
+
const { group = "", groupDisplayHeader = "", groupDisplayDescription = "" } = attribute;
|
69
|
+
|
70
|
+
const { value, displayableErrors } = fieldStateByAttributeName[attribute.name];
|
71
|
+
|
72
|
+
const formGroupClassName = cx(props.kcFormGroupClass, displayableErrors.length !== 0 && props.kcFormGroupErrorClass);
|
73
|
+
|
74
|
+
return (
|
75
|
+
<Fragment key={i}>
|
76
|
+
{group !== currentGroup && (currentGroup = group) !== "" && (
|
77
|
+
<div className={formGroupClassName}>
|
78
|
+
<div className={cx(props.kcContentWrapperClass)}>
|
79
|
+
<label id={`header-${group}`} className={cx(props.kcFormGroupHeader)}>
|
80
|
+
{advancedMsg(groupDisplayHeader) || currentGroup}
|
81
|
+
</label>
|
82
|
+
</div>
|
83
|
+
{groupDisplayDescription !== "" && (
|
84
|
+
<div className={cx(props.kcLabelWrapperClass)}>
|
85
|
+
<label id={`description-${group}`} className={`${cx(props.kcLabelClass)}`}>
|
86
|
+
{advancedMsg(groupDisplayDescription)}
|
87
|
+
</label>
|
88
|
+
</div>
|
89
|
+
)}
|
90
|
+
</div>
|
91
|
+
)}
|
92
|
+
|
93
|
+
{BeforeField && <BeforeField attribute={attribute} />}
|
94
|
+
|
95
|
+
<div className={formGroupClassName}>
|
96
|
+
<div className={cx(props.kcLabelWrapperClass)}>
|
97
|
+
<label htmlFor={attribute.name} className={cx(props.kcLabelClass)}>
|
98
|
+
{advancedMsg(attribute.displayName ?? "")}
|
99
|
+
</label>
|
100
|
+
{attribute.required && <>*</>}
|
101
|
+
</div>
|
102
|
+
<div className={cx(props.kcInputWrapperClass)}>
|
103
|
+
{(() => {
|
104
|
+
const { options } = attribute.validators;
|
105
|
+
|
106
|
+
if (options !== undefined) {
|
107
|
+
return (
|
108
|
+
<select
|
109
|
+
id={attribute.name}
|
110
|
+
name={attribute.name}
|
111
|
+
onChange={onChangeFactory(attribute.name)}
|
112
|
+
onBlur={onBlurFactory(attribute.name)}
|
113
|
+
value={value}
|
114
|
+
>
|
115
|
+
{options.options.map(option => (
|
116
|
+
<option key={option} value={option}>
|
117
|
+
{option}
|
118
|
+
</option>
|
119
|
+
))}
|
120
|
+
</select>
|
121
|
+
);
|
122
|
+
}
|
123
|
+
|
124
|
+
return (
|
125
|
+
<input
|
126
|
+
type={(() => {
|
127
|
+
switch (attribute.name) {
|
128
|
+
case "password-confirm":
|
129
|
+
case "password":
|
130
|
+
return "password";
|
131
|
+
default:
|
132
|
+
return "text";
|
133
|
+
}
|
134
|
+
})()}
|
135
|
+
id={attribute.name}
|
136
|
+
name={attribute.name}
|
137
|
+
value={value}
|
138
|
+
onChange={onChangeFactory(attribute.name)}
|
139
|
+
className={cx(props.kcInputClass)}
|
140
|
+
aria-invalid={displayableErrors.length !== 0}
|
141
|
+
disabled={attribute.readOnly}
|
142
|
+
autoComplete={attribute.autocomplete}
|
143
|
+
onBlur={onBlurFactory(attribute.name)}
|
144
|
+
/>
|
145
|
+
);
|
146
|
+
})()}
|
147
|
+
{displayableErrors.length !== 0 && (
|
148
|
+
<span
|
149
|
+
id={`input-error-${attribute.name}`}
|
150
|
+
className={cx(
|
151
|
+
props.kcInputErrorMessageClass,
|
152
|
+
css({
|
153
|
+
"position": displayableErrors.length === 1 ? "absolute" : undefined,
|
154
|
+
"& > span": { "display": "block" }
|
155
|
+
})
|
156
|
+
)}
|
157
|
+
aria-live="polite"
|
158
|
+
>
|
159
|
+
{displayableErrors.map(({ errorMessage }) => errorMessage)}
|
160
|
+
</span>
|
161
|
+
)}
|
162
|
+
</div>
|
163
|
+
</div>
|
164
|
+
|
165
|
+
{AfterField && <AfterField attribute={attribute} />}
|
166
|
+
</Fragment>
|
167
|
+
);
|
168
|
+
})}
|
169
|
+
</>
|
170
|
+
);
|
171
|
+
}
|
172
|
+
);
|
@@ -25,7 +25,8 @@ export type KcContextBase =
|
|
25
25
|
| KcContextBase.LoginIdpLinkEmail
|
26
26
|
| KcContextBase.LoginPageExpired
|
27
27
|
| KcContextBase.LoginConfigTotp
|
28
|
-
| KcContextBase.LogoutConfirm
|
28
|
+
| KcContextBase.LogoutConfirm
|
29
|
+
| KcContextBase.UpdateUserProfile;
|
29
30
|
|
30
31
|
export declare namespace KcContextBase {
|
31
32
|
export type Common = {
|
@@ -270,6 +271,15 @@ export declare namespace KcContextBase {
|
|
270
271
|
skipLink?: boolean;
|
271
272
|
};
|
272
273
|
};
|
274
|
+
|
275
|
+
export type UpdateUserProfile = Common & {
|
276
|
+
pageId: "update-user-profile.ftl";
|
277
|
+
profile: {
|
278
|
+
context: "REGISTRATION_PROFILE";
|
279
|
+
attributes: Attribute[];
|
280
|
+
attributesByName: Record<string, Attribute>;
|
281
|
+
};
|
282
|
+
};
|
273
283
|
}
|
274
284
|
|
275
285
|
export type Attribute = {
|