keycloakify 10.0.0-rc.22 → 10.0.0-rc.24
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/PUBLIC_URL.d.ts +1 -1
- package/PUBLIC_URL.js +1 -1
- package/PUBLIC_URL.js.map +1 -1
- package/account/Fallback.js.map +1 -1
- package/account/Template.js +3 -3
- package/account/Template.js.map +1 -1
- package/account/i18n/baseMessages/index.js.map +1 -1
- package/account/i18n/i18n.js.map +1 -1
- package/account/index.d.ts +2 -2
- package/account/index.js +1 -2
- package/account/index.js.map +1 -1
- package/account/kcContext/KcContext.d.ts +12 -0
- package/account/kcContext/KcContext.js.map +1 -1
- package/account/kcContext/getKcContextMock.d.ts +24 -0
- package/account/kcContext/getKcContextMock.js +28 -0
- package/account/kcContext/getKcContextMock.js.map +1 -0
- package/account/kcContext/index.d.ts +2 -1
- package/account/kcContext/index.js +1 -1
- package/account/kcContext/index.js.map +1 -1
- package/account/kcContext/kcContextMocks.js +23 -91
- package/account/kcContext/kcContextMocks.js.map +1 -1
- package/account/pages/Account.js +1 -1
- package/account/pages/Account.js.map +1 -1
- package/account/pages/Applications.js +2 -2
- package/account/pages/Applications.js.map +1 -1
- package/account/pages/FederatedIdentity.js +1 -1
- package/account/pages/FederatedIdentity.js.map +1 -1
- package/account/pages/Log.js +1 -1
- package/account/pages/Log.js.map +1 -1
- package/account/pages/Password.js +6 -4
- package/account/pages/Password.js.map +1 -1
- package/account/pages/Sessions.js +1 -1
- package/account/pages/Sessions.js.map +1 -1
- package/account/pages/Totp.js +1 -1
- package/account/pages/Totp.js.map +1 -1
- package/bin/main.js +174 -162
- package/lib/BASE_URL.js.map +1 -1
- package/login/Fallback.js.map +1 -1
- package/login/Template.js +7 -7
- package/login/Template.js.map +1 -1
- package/login/UserProfileFormFields.js +24 -68
- package/login/UserProfileFormFields.js.map +1 -1
- package/login/i18n/baseMessages/index.js.map +1 -1
- package/login/i18n/i18n.d.ts +1 -1
- package/login/i18n/i18n.js +1 -1
- package/login/i18n/i18n.js.map +1 -1
- package/login/index.d.ts +2 -3
- package/login/index.js +1 -2
- package/login/index.js.map +1 -1
- package/login/kcContext/KcContext.d.ts +23 -13
- package/login/kcContext/KcContext.js.map +1 -1
- package/login/kcContext/getKcContextMock.d.ts +24 -0
- package/login/kcContext/getKcContextMock.js +28 -0
- package/login/kcContext/getKcContextMock.js.map +1 -0
- package/login/kcContext/index.d.ts +2 -1
- package/login/kcContext/index.js +1 -1
- package/login/kcContext/index.js.map +1 -1
- package/login/kcContext/kcContextMocks.js +29 -103
- package/login/kcContext/kcContextMocks.js.map +1 -1
- package/login/lib/useDownloadTerms.js +8 -14
- package/login/lib/useDownloadTerms.js.map +1 -1
- package/login/lib/useGetClassName.js +1 -1
- package/login/lib/useGetClassName.js.map +1 -1
- package/login/lib/useUserProfileForm.d.ts +9 -1
- package/login/lib/useUserProfileForm.js +94 -15
- package/login/lib/useUserProfileForm.js.map +1 -1
- package/login/pages/Code.js +1 -1
- package/login/pages/Code.js.map +1 -1
- package/login/pages/DeleteAccountConfirm.js +2 -2
- package/login/pages/DeleteAccountConfirm.js.map +1 -1
- package/login/pages/DeleteCredential.js +1 -1
- package/login/pages/DeleteCredential.js.map +1 -1
- package/login/pages/Error.js +1 -1
- package/login/pages/Error.js.map +1 -1
- package/login/pages/FrontchannelLogout.js +1 -1
- package/login/pages/FrontchannelLogout.js.map +1 -1
- package/login/pages/IdpReviewUserProfile.js +1 -1
- package/login/pages/IdpReviewUserProfile.js.map +1 -1
- package/login/pages/Info.js +5 -5
- package/login/pages/Info.js.map +1 -1
- package/login/pages/Login.js +4 -4
- package/login/pages/Login.js.map +1 -1
- package/login/pages/LoginConfigTotp.js +2 -2
- package/login/pages/LoginConfigTotp.js.map +1 -1
- package/login/pages/LoginIdpLinkConfirm.js +1 -1
- package/login/pages/LoginIdpLinkConfirm.js.map +1 -1
- package/login/pages/LoginIdpLinkEmail.js +1 -1
- package/login/pages/LoginIdpLinkEmail.js.map +1 -1
- package/login/pages/LoginOauth2DeviceVerifyUserCode.js +1 -1
- package/login/pages/LoginOauth2DeviceVerifyUserCode.js.map +1 -1
- package/login/pages/LoginOauthGrant.js +2 -2
- package/login/pages/LoginOauthGrant.js.map +1 -1
- package/login/pages/LoginOtp.js +1 -1
- package/login/pages/LoginOtp.js.map +1 -1
- package/login/pages/LoginPageExpired.js +1 -1
- package/login/pages/LoginPageExpired.js.map +1 -1
- package/login/pages/LoginPassword.js +3 -3
- package/login/pages/LoginPassword.js.map +1 -1
- package/login/pages/LoginRecoveryAuthnCodeConfig.js +10 -10
- package/login/pages/LoginRecoveryAuthnCodeConfig.js.map +1 -1
- package/login/pages/LoginRecoveryAuthnCodeInput.js +1 -1
- package/login/pages/LoginRecoveryAuthnCodeInput.js.map +1 -1
- package/login/pages/LoginResetOtp.js +1 -1
- package/login/pages/LoginResetOtp.js.map +1 -1
- package/login/pages/LoginResetPassword.js +2 -2
- package/login/pages/LoginResetPassword.js.map +1 -1
- package/login/pages/LoginUpdatePassword.js +3 -3
- package/login/pages/LoginUpdatePassword.js.map +1 -1
- package/login/pages/LoginUpdateProfile.js +4 -2
- package/login/pages/LoginUpdateProfile.js.map +1 -1
- package/login/pages/LoginUsername.js +3 -3
- package/login/pages/LoginUsername.js.map +1 -1
- package/login/pages/LoginVerifyEmail.js +1 -1
- package/login/pages/LoginVerifyEmail.js.map +1 -1
- package/login/pages/LoginX509Info.js +1 -1
- package/login/pages/LoginX509Info.js.map +1 -1
- package/login/pages/LogoutConfirm.js +1 -1
- package/login/pages/LogoutConfirm.js.map +1 -1
- package/login/pages/Register.js +8 -4
- package/login/pages/Register.js.map +1 -1
- package/login/pages/SamlPostForm.js +1 -1
- package/login/pages/SamlPostForm.js.map +1 -1
- package/login/pages/SelectAuthenticator.js +2 -2
- package/login/pages/SelectAuthenticator.js.map +1 -1
- package/login/pages/Terms.js +1 -1
- package/login/pages/Terms.js.map +1 -1
- package/login/pages/UpdateEmail.js +5 -3
- package/login/pages/UpdateEmail.js.map +1 -1
- package/login/pages/WebauthnAuthenticate.js +8 -8
- package/login/pages/WebauthnAuthenticate.js.map +1 -1
- package/login/pages/WebauthnError.js +2 -2
- package/login/pages/WebauthnError.js.map +1 -1
- package/login/pages/WebauthnRegister.js +5 -5
- package/login/pages/WebauthnRegister.js.map +1 -1
- package/package.json +26 -38
- package/src/PUBLIC_URL.ts +1 -1
- package/src/account/Template.tsx +2 -3
- package/src/account/index.ts +2 -2
- package/src/account/kcContext/KcContext.ts +19 -1
- package/src/account/kcContext/getKcContextMock.ts +80 -0
- package/src/account/kcContext/index.ts +2 -1
- package/src/account/kcContext/kcContextMocks.ts +26 -91
- package/src/bin/copy-keycloak-resources-to-public.ts +1 -4
- package/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +19 -11
- package/src/bin/start-keycloak/start-keycloak.ts +18 -5
- package/src/bin/tools/getNpmWorkspaceRootDirPath.ts +25 -25
- package/src/login/Template.tsx +4 -5
- package/src/login/UserProfileFormFields.tsx +28 -80
- package/src/login/i18n/i18n.tsx +3 -3
- package/src/login/index.ts +6 -3
- package/src/login/kcContext/KcContext.ts +43 -31
- package/src/login/kcContext/getKcContextMock.ts +80 -0
- package/src/login/kcContext/index.ts +7 -1
- package/src/login/kcContext/kcContextMocks.ts +92 -165
- package/src/login/lib/useDownloadTerms.ts +10 -24
- package/src/login/lib/useGetClassName.ts +1 -1
- package/src/login/lib/useUserProfileForm.tsx +117 -13
- package/src/login/pages/LoginConfigTotp.tsx +1 -1
- package/src/login/pages/LoginRecoveryAuthnCodeConfig.tsx +7 -8
- package/src/login/pages/WebauthnAuthenticate.tsx +2 -3
- package/src/login/pages/WebauthnRegister.tsx +2 -3
- package/src/tools/ExtractAfterStartingWith.ts +4 -0
- package/src/tools/StatefulObservable/hooks/useRerenderOnChange.ts +4 -4
- package/src/tools/ValueOf.ts +2 -0
- package/src/tools/deepAssign.ts +51 -20
- package/src/tools/structuredCloneButFunctions.ts +24 -0
- package/src/tools/useInsertLinkTags.ts +78 -87
- package/src/tools/useInsertScriptTags.ts +69 -78
- package/src/tools/useOnFirstMount.ts +18 -0
- package/tools/Array.prototype.every.js.map +1 -1
- package/tools/ExtractAfterStartingWith.d.ts +1 -0
- package/tools/ExtractAfterStartingWith.js +2 -0
- package/tools/ExtractAfterStartingWith.js.map +1 -0
- package/tools/HTMLElement.prototype.prepend.js.map +1 -1
- package/tools/StatefulObservable/StatefulObservable.js.map +1 -1
- package/tools/StatefulObservable/hooks/useRerenderOnChange.d.ts +1 -1
- package/tools/StatefulObservable/hooks/useRerenderOnChange.js +4 -4
- package/tools/StatefulObservable/hooks/useRerenderOnChange.js.map +1 -1
- package/tools/ValueOf.d.ts +2 -0
- package/tools/ValueOf.js +2 -0
- package/tools/ValueOf.js.map +1 -0
- package/tools/clsx.js.map +1 -1
- package/tools/deepAssign.d.ts +1 -0
- package/tools/deepAssign.js +39 -16
- package/tools/deepAssign.js.map +1 -1
- package/tools/formatNumber.js.map +1 -1
- package/tools/structuredCloneButFunctions.d.ts +7 -0
- package/tools/structuredCloneButFunctions.js +19 -0
- package/tools/structuredCloneButFunctions.js.map +1 -0
- package/tools/useInsertLinkTags.d.ts +11 -6
- package/tools/useInsertLinkTags.js +53 -53
- package/tools/useInsertLinkTags.js.map +1 -1
- package/tools/useInsertScriptTags.d.ts +15 -6
- package/tools/useInsertScriptTags.js +56 -64
- package/tools/useInsertScriptTags.js.map +1 -1
- package/tools/useOnFirstMount.d.ts +2 -0
- package/tools/useOnFirstMount.js +15 -0
- package/tools/useOnFirstMount.js.map +1 -0
- package/tools/useSetClassName.js.map +1 -1
- package/vite-plugin/index.js +66 -64
- package/account/kcContext/createGetKcContext.d.ts +0 -19
- package/account/kcContext/createGetKcContext.js +0 -78
- package/account/kcContext/createGetKcContext.js.map +0 -1
- package/account/kcContext/getKcContext.d.ts +0 -13
- package/account/kcContext/getKcContext.js +0 -13
- package/account/kcContext/getKcContext.js.map +0 -1
- package/account/kcContext/getKcContextFromWindow.d.ts +0 -10
- package/account/kcContext/getKcContextFromWindow.js +0 -5
- package/account/kcContext/getKcContextFromWindow.js.map +0 -1
- package/login/kcContext/createGetKcContext.d.ts +0 -19
- package/login/kcContext/createGetKcContext.js +0 -117
- package/login/kcContext/createGetKcContext.js.map +0 -1
- package/login/kcContext/getKcContext.d.ts +0 -13
- package/login/kcContext/getKcContext.js +0 -13
- package/login/kcContext/getKcContext.js.map +0 -1
- package/login/kcContext/getKcContextFromWindow.d.ts +0 -10
- package/login/kcContext/getKcContextFromWindow.js +0 -5
- package/login/kcContext/getKcContextFromWindow.js.map +0 -1
- package/src/account/kcContext/createGetKcContext.ts +0 -134
- package/src/account/kcContext/getKcContext.ts +0 -23
- package/src/account/kcContext/getKcContextFromWindow.ts +0 -15
- package/src/login/kcContext/createGetKcContext.ts +0 -206
- package/src/login/kcContext/getKcContext.ts +0 -23
- package/src/login/kcContext/getKcContextFromWindow.ts +0 -15
- package/src/tools/AndByDiscriminatingKey.ts +0 -31
- package/src/tools/deepClone.ts +0 -19
- package/src/tools/memoize.ts +0 -55
- package/tools/AndByDiscriminatingKey.d.ts +0 -5
- package/tools/AndByDiscriminatingKey.js +0 -2
- package/tools/AndByDiscriminatingKey.js.map +0 -1
- package/tools/deepClone.d.ts +0 -2
- package/tools/deepClone.js +0 -14
- package/tools/deepClone.js.map +0 -1
- package/tools/memoize.d.ts +0 -7
- package/tools/memoize.js +0 -38
- package/tools/memoize.js.map +0 -1
@@ -9,75 +9,72 @@ import { id } from "tsafe/id";
|
|
9
9
|
import { assert, type Equals } from "tsafe/assert";
|
10
10
|
import { BASE_URL } from "keycloakify/lib/BASE_URL";
|
11
11
|
|
12
|
-
const
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
displayName: "${username}",
|
22
|
-
annotations: {},
|
23
|
-
required: true,
|
24
|
-
autocomplete: "username",
|
25
|
-
readOnly: false,
|
26
|
-
name: "username",
|
27
|
-
value: "xxxx"
|
28
|
-
},
|
29
|
-
{
|
30
|
-
validators: {
|
31
|
-
length: {
|
32
|
-
max: "255",
|
33
|
-
"ignore.empty.value": true
|
34
|
-
},
|
35
|
-
email: {
|
36
|
-
"ignore.empty.value": true
|
12
|
+
const attributesByName = Object.fromEntries(
|
13
|
+
id<Attribute[]>([
|
14
|
+
{
|
15
|
+
validators: {
|
16
|
+
length: {
|
17
|
+
"ignore.empty.value": true,
|
18
|
+
min: "3",
|
19
|
+
max: "255"
|
20
|
+
}
|
37
21
|
},
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
22
|
+
displayName: "${username}",
|
23
|
+
annotations: {},
|
24
|
+
required: true,
|
25
|
+
autocomplete: "username",
|
26
|
+
readOnly: false,
|
27
|
+
name: "username"
|
42
28
|
},
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
29
|
+
{
|
30
|
+
validators: {
|
31
|
+
length: {
|
32
|
+
max: "255",
|
33
|
+
"ignore.empty.value": true
|
34
|
+
},
|
35
|
+
email: {
|
36
|
+
"ignore.empty.value": true
|
37
|
+
},
|
38
|
+
pattern: {
|
39
|
+
"ignore.empty.value": true,
|
40
|
+
pattern: "gmail\\.com$"
|
41
|
+
}
|
42
|
+
},
|
43
|
+
displayName: "${email}",
|
44
|
+
annotations: {},
|
45
|
+
required: true,
|
46
|
+
autocomplete: "email",
|
47
|
+
readOnly: false,
|
48
|
+
name: "email"
|
56
49
|
},
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
50
|
+
{
|
51
|
+
validators: {
|
52
|
+
length: {
|
53
|
+
max: "255",
|
54
|
+
"ignore.empty.value": true
|
55
|
+
}
|
56
|
+
},
|
57
|
+
displayName: "${firstName}",
|
58
|
+
annotations: {},
|
59
|
+
required: true,
|
60
|
+
readOnly: false,
|
61
|
+
name: "firstName"
|
69
62
|
},
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
63
|
+
{
|
64
|
+
validators: {
|
65
|
+
length: {
|
66
|
+
max: "255",
|
67
|
+
"ignore.empty.value": true
|
68
|
+
}
|
69
|
+
},
|
70
|
+
displayName: "${lastName}",
|
71
|
+
annotations: {},
|
72
|
+
required: true,
|
73
|
+
readOnly: false,
|
74
|
+
name: "lastName"
|
75
|
+
}
|
76
|
+
]).map(attribute => [attribute.name, attribute])
|
77
|
+
);
|
81
78
|
|
82
79
|
const resourcesPath = `${BASE_URL}${keycloak_resources}/login/resources`;
|
83
80
|
|
@@ -116,98 +113,34 @@ export const kcContextCommonMock: KcContext.Common = {
|
|
116
113
|
locale: {
|
117
114
|
supported: [
|
118
115
|
/* spell-checker: disable */
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
languageTag: "sv"
|
138
|
-
},
|
139
|
-
{
|
140
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pt-BR",
|
141
|
-
label: "Português (Brasil)",
|
142
|
-
languageTag: "pt-BR"
|
143
|
-
},
|
144
|
-
{
|
145
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=lt",
|
146
|
-
label: "Lietuvių",
|
147
|
-
languageTag: "lt"
|
148
|
-
},
|
149
|
-
{
|
150
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=en",
|
151
|
-
label: "English",
|
152
|
-
languageTag: "en"
|
153
|
-
},
|
154
|
-
{
|
155
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=it",
|
156
|
-
label: "Italiano",
|
157
|
-
languageTag: "it"
|
158
|
-
},
|
159
|
-
{
|
160
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=fr",
|
161
|
-
label: "Français",
|
162
|
-
languageTag: "fr"
|
163
|
-
},
|
164
|
-
{
|
165
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=zh-CN",
|
166
|
-
label: "中文简体",
|
167
|
-
languageTag: "zh-CN"
|
168
|
-
},
|
169
|
-
{
|
170
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=es",
|
171
|
-
label: "Español",
|
172
|
-
languageTag: "es"
|
173
|
-
},
|
174
|
-
{
|
175
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=cs",
|
176
|
-
label: "Čeština",
|
177
|
-
languageTag: "cs"
|
178
|
-
},
|
179
|
-
{
|
180
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ja",
|
181
|
-
label: "日本語",
|
182
|
-
languageTag: "ja"
|
183
|
-
},
|
184
|
-
{
|
185
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=sk",
|
186
|
-
label: "Slovenčina",
|
187
|
-
languageTag: "sk"
|
188
|
-
},
|
189
|
-
{
|
190
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=pl",
|
191
|
-
label: "Polski",
|
192
|
-
languageTag: "pl"
|
193
|
-
},
|
194
|
-
{
|
195
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=ca",
|
196
|
-
label: "Català",
|
197
|
-
languageTag: "ca"
|
198
|
-
},
|
199
|
-
{
|
200
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=nl",
|
201
|
-
label: "Nederlands",
|
202
|
-
languageTag: "nl"
|
203
|
-
},
|
204
|
-
{
|
205
|
-
url: "/auth/realms/myrealm/login-actions/authenticate?client_id=account&tab_id=HoAx28ja4xg&execution=ee6c2834-46a4-4a20-a1b6-f6d6f6451b36&kc_locale=tr",
|
206
|
-
label: "Türkçe",
|
207
|
-
languageTag: "tr"
|
208
|
-
}
|
116
|
+
["de", "Deutsch"],
|
117
|
+
["no", "Norsk"],
|
118
|
+
["ru", "Русский"],
|
119
|
+
["sv", "Svenska"],
|
120
|
+
["pt-BR", "Português (Brasil)"],
|
121
|
+
["lt", "Lietuvių"],
|
122
|
+
["en", "English"],
|
123
|
+
["it", "Italiano"],
|
124
|
+
["fr", "Français"],
|
125
|
+
["zh-CN", "中文简体"],
|
126
|
+
["es", "Español"],
|
127
|
+
["cs", "Čeština"],
|
128
|
+
["ja", "日本語"],
|
129
|
+
["sk", "Slovenčina"],
|
130
|
+
["pl", "Polski"],
|
131
|
+
["ca", "Català"],
|
132
|
+
["nl", "Nederlands"],
|
133
|
+
["tr", "Türkçe"]
|
209
134
|
/* spell-checker: enable */
|
210
|
-
]
|
135
|
+
].map(
|
136
|
+
([languageTag, label]) =>
|
137
|
+
({
|
138
|
+
languageTag,
|
139
|
+
label,
|
140
|
+
url: "https://gist.github.com/garronej/52baaca1bb925f2296ab32741e062b8e"
|
141
|
+
}) as const
|
142
|
+
),
|
143
|
+
|
211
144
|
currentLanguageTag: "en"
|
212
145
|
},
|
213
146
|
auth: {
|
@@ -269,7 +202,6 @@ export const kcContextMocks = [
|
|
269
202
|
recaptchaRequired: false,
|
270
203
|
pageId: "register.ftl",
|
271
204
|
profile: {
|
272
|
-
attributes,
|
273
205
|
attributesByName
|
274
206
|
},
|
275
207
|
scripts: [
|
@@ -421,7 +353,6 @@ export const kcContextMocks = [
|
|
421
353
|
...kcContextCommonMock,
|
422
354
|
pageId: "login-update-profile.ftl",
|
423
355
|
profile: {
|
424
|
-
attributes,
|
425
356
|
attributesByName
|
426
357
|
}
|
427
358
|
}),
|
@@ -478,7 +409,6 @@ export const kcContextMocks = [
|
|
478
409
|
...kcContextCommonMock,
|
479
410
|
pageId: "idp-review-user-profile.ftl",
|
480
411
|
profile: {
|
481
|
-
attributes,
|
482
412
|
attributesByName
|
483
413
|
}
|
484
414
|
}),
|
@@ -486,12 +416,9 @@ export const kcContextMocks = [
|
|
486
416
|
...kcContextCommonMock,
|
487
417
|
pageId: "update-email.ftl",
|
488
418
|
profile: {
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
.filter(attribute => attribute.name === "email")
|
493
|
-
.map(attribute => [attribute.name, attribute])
|
494
|
-
)
|
419
|
+
attributesByName: {
|
420
|
+
email: attributesByName["email"]
|
421
|
+
}
|
495
422
|
}
|
496
423
|
}),
|
497
424
|
id<KcContext.SelectAuthenticator>({
|
@@ -1,14 +1,11 @@
|
|
1
|
-
import { useEffect } from "react";
|
2
|
-
import { memoize } from "keycloakify/tools/memoize";
|
3
1
|
import { fallbackLanguageTag } from "keycloakify/login/i18n/i18n";
|
4
|
-
import { useConst } from "keycloakify/tools/useConst";
|
5
|
-
import { useConstCallback } from "keycloakify/tools/useConstCallback";
|
6
2
|
import { assert } from "tsafe/assert";
|
7
3
|
import {
|
8
4
|
createStatefulObservable,
|
9
5
|
useRerenderOnChange
|
10
6
|
} from "keycloakify/tools/StatefulObservable";
|
11
7
|
import { KcContext } from "../kcContext";
|
8
|
+
import { useOnFistMount } from "keycloakify/tools/useOnFirstMount";
|
12
9
|
|
13
10
|
const obsTermsMarkdown = createStatefulObservable<string | undefined>(() => undefined);
|
14
11
|
|
@@ -27,29 +24,18 @@ export function useDownloadTerms(params: {
|
|
27
24
|
kcContext: KcContextLike;
|
28
25
|
downloadTermMarkdown: (params: { currentLanguageTag: string }) => Promise<string>;
|
29
26
|
}) {
|
30
|
-
const { kcContext } = params;
|
27
|
+
const { kcContext, downloadTermMarkdown } = params;
|
31
28
|
|
32
|
-
|
33
|
-
const { downloadTermMarkdown } = params;
|
34
|
-
|
35
|
-
const downloadTermMarkdownConst = useConstCallback(downloadTermMarkdown);
|
36
|
-
|
37
|
-
const downloadTermMarkdownMemoized = useConst(() =>
|
38
|
-
memoize((currentLanguageTag: string) =>
|
39
|
-
downloadTermMarkdownConst({ currentLanguageTag })
|
40
|
-
)
|
41
|
-
);
|
42
|
-
|
43
|
-
return { downloadTermMarkdownMemoized };
|
44
|
-
})();
|
45
|
-
|
46
|
-
useEffect(() => {
|
29
|
+
useOnFistMount(async () => {
|
47
30
|
if (kcContext.pageId === "terms.ftl" || kcContext.termsAcceptanceRequired) {
|
48
|
-
|
49
|
-
|
50
|
-
|
31
|
+
const termsMarkdown = await downloadTermMarkdown({
|
32
|
+
currentLanguageTag:
|
33
|
+
kcContext.locale?.currentLanguageTag ?? fallbackLanguageTag
|
34
|
+
});
|
35
|
+
|
36
|
+
obsTermsMarkdown.current = termsMarkdown;
|
51
37
|
}
|
52
|
-
}
|
38
|
+
});
|
53
39
|
}
|
54
40
|
|
55
41
|
export function useTermsMarkdown() {
|
@@ -3,6 +3,7 @@ import type { ClassKey } from "keycloakify/login/TemplateProps";
|
|
3
3
|
|
4
4
|
export const { useGetClassName } = createUseClassName<ClassKey>({
|
5
5
|
defaultClasses: {
|
6
|
+
kcHtmlClass: "login-pf",
|
6
7
|
kcBodyClass: undefined,
|
7
8
|
kcHeaderWrapperClass: undefined,
|
8
9
|
kcLocaleWrapperClass: undefined,
|
@@ -54,7 +55,6 @@ export const { useGetClassName } = createUseClassName<ClassKey>({
|
|
54
55
|
kcLogoLink: "http://www.keycloak.org",
|
55
56
|
kcContainerClass: "container-fluid",
|
56
57
|
kcSelectAuthListItemTitle: "select-auth-box-paragraph",
|
57
|
-
kcHtmlClass: "login-pf",
|
58
58
|
kcLoginOTPListItemTitleClass: "pf-c-tile__title",
|
59
59
|
"kcLogoIdP-openshift-v4": "pf-icon pf-icon-openshift",
|
60
60
|
kcWebAuthnUnknownIcon: "pficon pficon-key unknown-transport-class",
|
@@ -8,7 +8,8 @@ import { emailRegexp } from "keycloakify/tools/emailRegExp";
|
|
8
8
|
import type { KcContext, PasswordPolicies } from "keycloakify/login/kcContext/KcContext";
|
9
9
|
import { assert, type Equals } from "tsafe/assert";
|
10
10
|
import { formatNumber } from "keycloakify/tools/formatNumber";
|
11
|
-
import {
|
11
|
+
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
12
|
+
import { structuredCloneButFunctions } from "keycloakify/tools/structuredCloneButFunctions";
|
12
13
|
import type { I18n } from "../i18n";
|
13
14
|
|
14
15
|
export type FormFieldError = {
|
@@ -67,7 +68,7 @@ export type FormAction =
|
|
67
68
|
export type KcContextLike = {
|
68
69
|
messagesPerField: Pick<KcContext.Common["messagesPerField"], "existsError" | "get">;
|
69
70
|
profile: {
|
70
|
-
|
71
|
+
attributesByName: Record<string, Attribute>;
|
71
72
|
html5DataAnnotations?: Record<string, string>;
|
72
73
|
};
|
73
74
|
passwordRequired?: boolean;
|
@@ -102,12 +103,11 @@ namespace internal {
|
|
102
103
|
};
|
103
104
|
}
|
104
105
|
|
105
|
-
const { useInsertScriptTags } = createUseInsertScriptTags();
|
106
|
-
|
107
106
|
export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTypeOfUseUserProfileForm {
|
108
107
|
const { kcContext, i18n, doMakeUserConfirmPassword } = params;
|
109
108
|
|
110
109
|
const { insertScriptTags } = useInsertScriptTags({
|
110
|
+
componentOrHookName: "useUserProfileForm",
|
111
111
|
scriptTags: Object.keys(kcContext.profile?.html5DataAnnotations ?? {})
|
112
112
|
.filter(key => key !== "kcMultivalued" && key !== "kcNumberFormat") // NOTE: Keycloakify handles it.
|
113
113
|
.map(key => ({
|
@@ -136,7 +136,11 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy
|
|
136
136
|
|
137
137
|
const attributes = (() => {
|
138
138
|
retrocompat_patch: {
|
139
|
-
if (
|
139
|
+
if (
|
140
|
+
"profile" in kcContext &&
|
141
|
+
"attributesByName" in kcContext.profile &&
|
142
|
+
Object.keys(kcContext.profile.attributesByName).length !== 0
|
143
|
+
) {
|
140
144
|
break retrocompat_patch;
|
141
145
|
}
|
142
146
|
|
@@ -216,7 +220,7 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy
|
|
216
220
|
assert(false, "Unable to mock user profile from the current kcContext");
|
217
221
|
}
|
218
222
|
|
219
|
-
return kcContext.profile.
|
223
|
+
return Object.values(kcContext.profile.attributesByName).map(attribute_pre_group_patch => {
|
220
224
|
if (typeof attribute_pre_group_patch.group === "string" && attribute_pre_group_patch.group !== "") {
|
221
225
|
const { group, groupDisplayHeader, groupDisplayDescription, groupAnnotations, ...rest } =
|
222
226
|
attribute_pre_group_patch as Attribute & {
|
@@ -242,7 +246,7 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy
|
|
242
246
|
})();
|
243
247
|
|
244
248
|
for (const attribute of attributes) {
|
245
|
-
syntheticAttributes.push(attribute);
|
249
|
+
syntheticAttributes.push(structuredCloneButFunctions(attribute));
|
246
250
|
|
247
251
|
add_password_and_password_confirm: {
|
248
252
|
if (!kcContext.passwordRequired) {
|
@@ -284,6 +288,21 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy
|
|
284
288
|
}
|
285
289
|
}
|
286
290
|
|
291
|
+
// NOTE: Consistency patch
|
292
|
+
syntheticAttributes.forEach(attribute => {
|
293
|
+
if (getIsMultivaluedSingleField({ attribute })) {
|
294
|
+
attribute.multivalued = true;
|
295
|
+
}
|
296
|
+
|
297
|
+
if (attribute.multivalued) {
|
298
|
+
attribute.values ??= attribute.value !== undefined ? [attribute.value] : [];
|
299
|
+
delete attribute.value;
|
300
|
+
} else {
|
301
|
+
attribute.value ??= attribute.values?.[0];
|
302
|
+
delete attribute.values;
|
303
|
+
}
|
304
|
+
});
|
305
|
+
|
287
306
|
return syntheticAttributes;
|
288
307
|
})();
|
289
308
|
|
@@ -299,10 +318,10 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy
|
|
299
318
|
break handle_multi_valued_attribute;
|
300
319
|
}
|
301
320
|
|
302
|
-
const values = attribute.values
|
321
|
+
const values = attribute.values?.length ? attribute.values : [""];
|
303
322
|
|
304
323
|
apply_validator_min_range: {
|
305
|
-
if (attribute
|
324
|
+
if (getIsMultivaluedSingleField({ attribute })) {
|
306
325
|
break apply_validator_min_range;
|
307
326
|
}
|
308
327
|
|
@@ -349,7 +368,8 @@ export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTy
|
|
349
368
|
attributeName: attribute.name,
|
350
369
|
formFieldStates: initialFormFieldState
|
351
370
|
}),
|
352
|
-
hasLostFocusAtLeastOnce:
|
371
|
+
hasLostFocusAtLeastOnce:
|
372
|
+
valueOrValues instanceof Array && !getIsMultivaluedSingleField({ attribute }) ? valueOrValues.map(() => false) : false,
|
353
373
|
valueOrValues: valueOrValues
|
354
374
|
}))
|
355
375
|
};
|
@@ -543,7 +563,7 @@ function useGetErrors(params: { kcContext: Pick<KcContextLike, "messagesPerField
|
|
543
563
|
|
544
564
|
server_side_error: {
|
545
565
|
if (attribute.multivalued) {
|
546
|
-
const defaultValues = attribute.values
|
566
|
+
const defaultValues = attribute.values?.length ? attribute.values : [""];
|
547
567
|
|
548
568
|
assert(valueOrValues instanceof Array);
|
549
569
|
|
@@ -595,7 +615,7 @@ function useGetErrors(params: { kcContext: Pick<KcContextLike, "messagesPerField
|
|
595
615
|
break handle_multi_valued_multi_fields;
|
596
616
|
}
|
597
617
|
|
598
|
-
if (attribute
|
618
|
+
if (getIsMultivaluedSingleField({ attribute })) {
|
599
619
|
break handle_multi_valued_multi_fields;
|
600
620
|
}
|
601
621
|
|
@@ -674,7 +694,7 @@ function useGetErrors(params: { kcContext: Pick<KcContextLike, "messagesPerField
|
|
674
694
|
break handle_multi_valued_single_field;
|
675
695
|
}
|
676
696
|
|
677
|
-
if (!attribute
|
697
|
+
if (!getIsMultivaluedSingleField({ attribute })) {
|
678
698
|
break handle_multi_valued_single_field;
|
679
699
|
}
|
680
700
|
|
@@ -913,6 +933,10 @@ function useGetErrors(params: { kcContext: Pick<KcContextLike, "messagesPerField
|
|
913
933
|
return valueOrValues;
|
914
934
|
})();
|
915
935
|
|
936
|
+
if (usernameValue === "") {
|
937
|
+
break check_password_policy_x;
|
938
|
+
}
|
939
|
+
|
916
940
|
if (value !== usernameValue) {
|
917
941
|
break check_password_policy_x;
|
918
942
|
}
|
@@ -950,6 +974,10 @@ function useGetErrors(params: { kcContext: Pick<KcContextLike, "messagesPerField
|
|
950
974
|
{
|
951
975
|
const emailValue = emailFormFieldState.valueOrValues;
|
952
976
|
|
977
|
+
if (emailValue === "") {
|
978
|
+
break check_password_policy_x;
|
979
|
+
}
|
980
|
+
|
953
981
|
if (value !== emailValue) {
|
954
982
|
break check_password_policy_x;
|
955
983
|
}
|
@@ -1239,3 +1267,79 @@ function useGetErrors(params: { kcContext: Pick<KcContextLike, "messagesPerField
|
|
1239
1267
|
|
1240
1268
|
return { getErrors };
|
1241
1269
|
}
|
1270
|
+
|
1271
|
+
function getIsMultivaluedSingleField(params: { attribute: Attribute }) {
|
1272
|
+
const { attribute } = params;
|
1273
|
+
|
1274
|
+
return attribute.annotations.inputType?.startsWith("multiselect") ?? false;
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
export function getButtonToDisplayForMultivaluedAttributeField(params: { attribute: Attribute; values: string[]; fieldIndex: number }) {
|
1278
|
+
const { attribute, values, fieldIndex } = params;
|
1279
|
+
|
1280
|
+
const hasRemove = (() => {
|
1281
|
+
if (values.length === 1) {
|
1282
|
+
return false;
|
1283
|
+
}
|
1284
|
+
|
1285
|
+
const minCount = (() => {
|
1286
|
+
const { multivalued } = attribute.validators;
|
1287
|
+
|
1288
|
+
if (multivalued === undefined) {
|
1289
|
+
return undefined;
|
1290
|
+
}
|
1291
|
+
|
1292
|
+
const minStr = multivalued.min;
|
1293
|
+
|
1294
|
+
if (minStr === undefined) {
|
1295
|
+
return undefined;
|
1296
|
+
}
|
1297
|
+
|
1298
|
+
return parseInt(`${minStr}`);
|
1299
|
+
})();
|
1300
|
+
|
1301
|
+
if (minCount === undefined) {
|
1302
|
+
return true;
|
1303
|
+
}
|
1304
|
+
|
1305
|
+
if (values.length === minCount) {
|
1306
|
+
return false;
|
1307
|
+
}
|
1308
|
+
|
1309
|
+
return true;
|
1310
|
+
})();
|
1311
|
+
|
1312
|
+
const hasAdd = (() => {
|
1313
|
+
if (fieldIndex + 1 !== values.length) {
|
1314
|
+
return false;
|
1315
|
+
}
|
1316
|
+
|
1317
|
+
const maxCount = (() => {
|
1318
|
+
const { multivalued } = attribute.validators;
|
1319
|
+
|
1320
|
+
if (multivalued === undefined) {
|
1321
|
+
return undefined;
|
1322
|
+
}
|
1323
|
+
|
1324
|
+
const maxStr = multivalued.max;
|
1325
|
+
|
1326
|
+
if (maxStr === undefined) {
|
1327
|
+
return undefined;
|
1328
|
+
}
|
1329
|
+
|
1330
|
+
return parseInt(`${maxStr}`);
|
1331
|
+
})();
|
1332
|
+
|
1333
|
+
if (maxCount === undefined) {
|
1334
|
+
return false;
|
1335
|
+
}
|
1336
|
+
|
1337
|
+
if (values.length === maxCount) {
|
1338
|
+
return false;
|
1339
|
+
}
|
1340
|
+
|
1341
|
+
return true;
|
1342
|
+
})();
|
1343
|
+
|
1344
|
+
return { hasRemove, hasAdd };
|
1345
|
+
}
|
@@ -25,7 +25,7 @@ export default function LoginConfigTotp(props: PageProps<Extract<KcContext, { pa
|
|
25
25
|
|
26
26
|
<ul id="kc-totp-supported-apps">
|
27
27
|
{totp.supportedApplications.map(app => (
|
28
|
-
<li>{advancedMsg(app)}</li>
|
28
|
+
<li key={app}>{advancedMsg(app)}</li>
|
29
29
|
))}
|
30
30
|
</ul>
|
31
31
|
</li>
|
@@ -2,12 +2,10 @@ import { useEffect } from "react";
|
|
2
2
|
import { clsx } from "keycloakify/tools/clsx";
|
3
3
|
import type { PageProps } from "keycloakify/login/pages/PageProps";
|
4
4
|
import { useGetClassName } from "keycloakify/login/lib/useGetClassName";
|
5
|
-
import {
|
5
|
+
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
6
6
|
import type { KcContext } from "../kcContext";
|
7
7
|
import type { I18n } from "../i18n";
|
8
8
|
|
9
|
-
const { useInsertScriptTags } = createUseInsertScriptTags();
|
10
|
-
|
11
9
|
export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<KcContext, { pageId: "login-recovery-authn-code-config.ftl" }>, I18n>) {
|
12
10
|
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
|
13
11
|
|
@@ -21,6 +19,7 @@ export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<Kc
|
|
21
19
|
const { msg, msgStr } = i18n;
|
22
20
|
|
23
21
|
const { insertScriptTags } = useInsertScriptTags({
|
22
|
+
componentOrHookName: "LoginRecoveryAuthnCodeConfig",
|
24
23
|
scriptTags: [
|
25
24
|
{
|
26
25
|
type: "text/javascript",
|
@@ -31,7 +30,7 @@ export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<Kc
|
|
31
30
|
var tmpTextarea = document.createElement("textarea");
|
32
31
|
var codes = document.getElementById("kc-recovery-codes-list").getElementsByTagName("li");
|
33
32
|
for (i = 0; i < codes.length; i++) {
|
34
|
-
tmpTextarea.value = tmpTextarea.value + codes[i].innerText + "
|
33
|
+
tmpTextarea.value = tmpTextarea.value + codes[i].innerText + "\\n";
|
35
34
|
}
|
36
35
|
document.body.appendChild(tmpTextarea);
|
37
36
|
tmpTextarea.select();
|
@@ -65,7 +64,7 @@ export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<Kc
|
|
65
64
|
|
66
65
|
for (var i = 0; i < recoveryCodes.length; i++) {
|
67
66
|
var recoveryCodeLiElement = recoveryCodes[i].innerText;
|
68
|
-
recoveryCodeList += recoveryCodeLiElement + "
|
67
|
+
recoveryCodeList += recoveryCodeLiElement + "\\r\\n";
|
69
68
|
}
|
70
69
|
|
71
70
|
return recoveryCodeList;
|
@@ -84,9 +83,9 @@ export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<Kc
|
|
84
83
|
};
|
85
84
|
|
86
85
|
return fileBodyContent =
|
87
|
-
"${msgStr("recovery-codes-download-file-header")}
|
88
|
-
recoveryCodeList + "
|
89
|
-
"${msgStr("recovery-codes-download-file-description")}
|
86
|
+
"${msgStr("recovery-codes-download-file-header")}\\n\\n" +
|
87
|
+
recoveryCodeList + "\\n" +
|
88
|
+
"${msgStr("recovery-codes-download-file-description")}\\n\\n" +
|
90
89
|
"${msgStr("recovery-codes-download-file-date")} " + formatCurrentDateTime();
|
91
90
|
}
|
92
91
|
|