keycloakify 11.9.16 → 11.11.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.
Files changed (155) hide show
  1. package/bin/main.js +2 -1
  2. package/bin/shared/constants.d.ts +1 -1
  3. package/bin/shared/constants.js +2 -1
  4. package/bin/shared/constants.js.map +1 -1
  5. package/login/DefaultPage.js +3 -0
  6. package/login/DefaultPage.js.map +1 -1
  7. package/login/KcContext/KcContext.d.ts +19 -1
  8. package/login/KcContext/KcContext.js.map +1 -1
  9. package/login/KcContext/getKcContextMock.d.ts +1 -1
  10. package/login/KcContext/kcContextMocks.d.ts +1 -1
  11. package/login/KcContext/kcContextMocks.js +21 -2
  12. package/login/KcContext/kcContextMocks.js.map +1 -1
  13. package/login/i18n/messages_defaultSet/ar.d.ts +1 -0
  14. package/login/i18n/messages_defaultSet/ar.js +2 -1
  15. package/login/i18n/messages_defaultSet/ar.js.map +1 -1
  16. package/login/i18n/messages_defaultSet/ca.d.ts +1 -0
  17. package/login/i18n/messages_defaultSet/ca.js +2 -1
  18. package/login/i18n/messages_defaultSet/ca.js.map +1 -1
  19. package/login/i18n/messages_defaultSet/cs.d.ts +1 -0
  20. package/login/i18n/messages_defaultSet/cs.js +2 -1
  21. package/login/i18n/messages_defaultSet/cs.js.map +1 -1
  22. package/login/i18n/messages_defaultSet/da.d.ts +1 -0
  23. package/login/i18n/messages_defaultSet/da.js +2 -1
  24. package/login/i18n/messages_defaultSet/da.js.map +1 -1
  25. package/login/i18n/messages_defaultSet/de.d.ts +1 -0
  26. package/login/i18n/messages_defaultSet/de.js +2 -1
  27. package/login/i18n/messages_defaultSet/de.js.map +1 -1
  28. package/login/i18n/messages_defaultSet/el.d.ts +1 -0
  29. package/login/i18n/messages_defaultSet/el.js +2 -1
  30. package/login/i18n/messages_defaultSet/el.js.map +1 -1
  31. package/login/i18n/messages_defaultSet/en.d.ts +1 -0
  32. package/login/i18n/messages_defaultSet/en.js +2 -1
  33. package/login/i18n/messages_defaultSet/en.js.map +1 -1
  34. package/login/i18n/messages_defaultSet/es.d.ts +1 -0
  35. package/login/i18n/messages_defaultSet/es.js +2 -1
  36. package/login/i18n/messages_defaultSet/es.js.map +1 -1
  37. package/login/i18n/messages_defaultSet/fa.d.ts +1 -0
  38. package/login/i18n/messages_defaultSet/fa.js +2 -1
  39. package/login/i18n/messages_defaultSet/fa.js.map +1 -1
  40. package/login/i18n/messages_defaultSet/fi.d.ts +1 -0
  41. package/login/i18n/messages_defaultSet/fi.js +2 -1
  42. package/login/i18n/messages_defaultSet/fi.js.map +1 -1
  43. package/login/i18n/messages_defaultSet/fr.d.ts +1 -0
  44. package/login/i18n/messages_defaultSet/fr.js +2 -1
  45. package/login/i18n/messages_defaultSet/fr.js.map +1 -1
  46. package/login/i18n/messages_defaultSet/hu.d.ts +1 -0
  47. package/login/i18n/messages_defaultSet/hu.js +2 -1
  48. package/login/i18n/messages_defaultSet/hu.js.map +1 -1
  49. package/login/i18n/messages_defaultSet/index.d.ts +10 -0
  50. package/login/i18n/messages_defaultSet/it.d.ts +1 -0
  51. package/login/i18n/messages_defaultSet/it.js +2 -1
  52. package/login/i18n/messages_defaultSet/it.js.map +1 -1
  53. package/login/i18n/messages_defaultSet/ja.d.ts +1 -0
  54. package/login/i18n/messages_defaultSet/ja.js +2 -1
  55. package/login/i18n/messages_defaultSet/ja.js.map +1 -1
  56. package/login/i18n/messages_defaultSet/ka.d.ts +1 -0
  57. package/login/i18n/messages_defaultSet/ka.js +2 -1
  58. package/login/i18n/messages_defaultSet/ka.js.map +1 -1
  59. package/login/i18n/messages_defaultSet/lt.d.ts +1 -0
  60. package/login/i18n/messages_defaultSet/lt.js +2 -1
  61. package/login/i18n/messages_defaultSet/lt.js.map +1 -1
  62. package/login/i18n/messages_defaultSet/lv.d.ts +1 -0
  63. package/login/i18n/messages_defaultSet/lv.js +2 -1
  64. package/login/i18n/messages_defaultSet/lv.js.map +1 -1
  65. package/login/i18n/messages_defaultSet/nl.d.ts +1 -0
  66. package/login/i18n/messages_defaultSet/nl.js +2 -1
  67. package/login/i18n/messages_defaultSet/nl.js.map +1 -1
  68. package/login/i18n/messages_defaultSet/no.d.ts +1 -0
  69. package/login/i18n/messages_defaultSet/no.js +2 -1
  70. package/login/i18n/messages_defaultSet/no.js.map +1 -1
  71. package/login/i18n/messages_defaultSet/pl.d.ts +1 -0
  72. package/login/i18n/messages_defaultSet/pl.js +2 -1
  73. package/login/i18n/messages_defaultSet/pl.js.map +1 -1
  74. package/login/i18n/messages_defaultSet/pt-BR.d.ts +1 -0
  75. package/login/i18n/messages_defaultSet/pt-BR.js +2 -1
  76. package/login/i18n/messages_defaultSet/pt-BR.js.map +1 -1
  77. package/login/i18n/messages_defaultSet/pt.d.ts +1 -0
  78. package/login/i18n/messages_defaultSet/pt.js +2 -1
  79. package/login/i18n/messages_defaultSet/pt.js.map +1 -1
  80. package/login/i18n/messages_defaultSet/ru.d.ts +1 -0
  81. package/login/i18n/messages_defaultSet/ru.js +2 -1
  82. package/login/i18n/messages_defaultSet/ru.js.map +1 -1
  83. package/login/i18n/messages_defaultSet/sk.d.ts +1 -0
  84. package/login/i18n/messages_defaultSet/sk.js +2 -1
  85. package/login/i18n/messages_defaultSet/sk.js.map +1 -1
  86. package/login/i18n/messages_defaultSet/sv.d.ts +1 -0
  87. package/login/i18n/messages_defaultSet/sv.js +2 -1
  88. package/login/i18n/messages_defaultSet/sv.js.map +1 -1
  89. package/login/i18n/messages_defaultSet/th.d.ts +1 -0
  90. package/login/i18n/messages_defaultSet/th.js +2 -1
  91. package/login/i18n/messages_defaultSet/th.js.map +1 -1
  92. package/login/i18n/messages_defaultSet/tr.d.ts +1 -0
  93. package/login/i18n/messages_defaultSet/tr.js +2 -1
  94. package/login/i18n/messages_defaultSet/tr.js.map +1 -1
  95. package/login/i18n/messages_defaultSet/uk.d.ts +1 -0
  96. package/login/i18n/messages_defaultSet/uk.js +2 -1
  97. package/login/i18n/messages_defaultSet/uk.js.map +1 -1
  98. package/login/i18n/messages_defaultSet/zh-CN.d.ts +1 -0
  99. package/login/i18n/messages_defaultSet/zh-CN.js +2 -1
  100. package/login/i18n/messages_defaultSet/zh-CN.js.map +1 -1
  101. package/login/i18n/messages_defaultSet/zh-TW.d.ts +1 -0
  102. package/login/i18n/messages_defaultSet/zh-TW.js +2 -1
  103. package/login/i18n/messages_defaultSet/zh-TW.js.map +1 -1
  104. package/login/lib/kcClsx.d.ts +1 -1
  105. package/login/lib/kcClsx.js +1 -0
  106. package/login/lib/kcClsx.js.map +1 -1
  107. package/login/pages/LoginUsername.js +16 -9
  108. package/login/pages/LoginUsername.js.map +1 -1
  109. package/login/pages/LoginUsername.useScript.d.ts +21 -0
  110. package/login/pages/LoginUsername.useScript.js +47 -0
  111. package/login/pages/LoginUsername.useScript.js.map +1 -0
  112. package/login/pages/SelectOrganization.d.ts +7 -0
  113. package/login/pages/SelectOrganization.js +33 -0
  114. package/login/pages/SelectOrganization.js.map +1 -0
  115. package/package.json +10 -1
  116. package/src/bin/shared/constants.ts +2 -1
  117. package/src/login/DefaultPage.tsx +3 -0
  118. package/src/login/KcContext/KcContext.ts +22 -1
  119. package/src/login/KcContext/kcContextMocks.ts +30 -1
  120. package/src/login/i18n/messages_defaultSet/ar.ts +2 -1
  121. package/src/login/i18n/messages_defaultSet/ca.ts +2 -1
  122. package/src/login/i18n/messages_defaultSet/cs.ts +2 -1
  123. package/src/login/i18n/messages_defaultSet/da.ts +2 -1
  124. package/src/login/i18n/messages_defaultSet/de.ts +2 -1
  125. package/src/login/i18n/messages_defaultSet/el.ts +2 -1
  126. package/src/login/i18n/messages_defaultSet/en.ts +2 -1
  127. package/src/login/i18n/messages_defaultSet/es.ts +2 -1
  128. package/src/login/i18n/messages_defaultSet/fa.ts +2 -1
  129. package/src/login/i18n/messages_defaultSet/fi.ts +2 -1
  130. package/src/login/i18n/messages_defaultSet/fr.ts +2 -1
  131. package/src/login/i18n/messages_defaultSet/hu.ts +2 -1
  132. package/src/login/i18n/messages_defaultSet/it.ts +2 -1
  133. package/src/login/i18n/messages_defaultSet/ja.ts +2 -1
  134. package/src/login/i18n/messages_defaultSet/ka.ts +2 -1
  135. package/src/login/i18n/messages_defaultSet/lt.ts +2 -1
  136. package/src/login/i18n/messages_defaultSet/lv.ts +2 -1
  137. package/src/login/i18n/messages_defaultSet/nl.ts +2 -1
  138. package/src/login/i18n/messages_defaultSet/no.ts +2 -1
  139. package/src/login/i18n/messages_defaultSet/pl.ts +2 -1
  140. package/src/login/i18n/messages_defaultSet/pt-BR.ts +2 -1
  141. package/src/login/i18n/messages_defaultSet/pt.ts +2 -1
  142. package/src/login/i18n/messages_defaultSet/ru.ts +2 -1
  143. package/src/login/i18n/messages_defaultSet/sk.ts +2 -1
  144. package/src/login/i18n/messages_defaultSet/sv.ts +2 -1
  145. package/src/login/i18n/messages_defaultSet/th.ts +2 -1
  146. package/src/login/i18n/messages_defaultSet/tr.ts +2 -1
  147. package/src/login/i18n/messages_defaultSet/uk.ts +2 -1
  148. package/src/login/i18n/messages_defaultSet/zh-CN.ts +2 -1
  149. package/src/login/i18n/messages_defaultSet/zh-TW.ts +2 -1
  150. package/src/login/lib/kcClsx.ts +2 -0
  151. package/src/login/pages/LoginUsername.tsx +37 -1
  152. package/src/login/pages/LoginUsername.useScript.tsx +71 -0
  153. package/src/login/pages/SelectOrganization.tsx +69 -0
  154. package/stories/login/pages/SelectOrganization.stories.tsx +18 -0
  155. package/vite-plugin/index.js +2 -1
@@ -391,7 +391,8 @@ const messages = {
391
391
  selectAnOption: "Selecione uma opção",
392
392
  remove: "Remover",
393
393
  addValue: "Adicionar valor",
394
- languages: "Idiomas"
394
+ languages: "Idiomas",
395
+ "organization.select": "Selecione uma organização para continuar:"
395
396
  };
396
397
 
397
398
  export default messages;
@@ -512,7 +512,8 @@ const messages = {
512
512
  selectAnOption: "Selecione uma opção",
513
513
  remove: "Remover",
514
514
  addValue: "Adicionar valor",
515
- languages: "Idiomas"
515
+ languages: "Idiomas",
516
+ "organization.select": "Selecione uma organização para continuar:"
516
517
  };
517
518
 
518
519
  export default messages;
@@ -252,7 +252,8 @@ const messages = {
252
252
  selectAnOption: "Выберите вариант",
253
253
  remove: "Удалить",
254
254
  addValue: "Добавить значение",
255
- languages: "Языки"
255
+ languages: "Языки",
256
+ "organization.select": "Выберите организацию, чтобы продолжить:"
256
257
  };
257
258
 
258
259
  export default messages;
@@ -496,7 +496,8 @@ const messages = {
496
496
  selectAnOption: "Vyberte možnosť",
497
497
  remove: "Odstrániť",
498
498
  addValue: "Pridať hodnotu",
499
- languages: "Jazyky"
499
+ languages: "Jazyky",
500
+ "organization.select": "Vyberte organizáciu, aby ste pokračovali:"
500
501
  };
501
502
 
502
503
  export default messages;
@@ -222,7 +222,8 @@ const messages = {
222
222
  selectAnOption: "Välj ett alternativ",
223
223
  remove: "Ta bort",
224
224
  addValue: "Lägg till värde",
225
- languages: "Språk"
225
+ languages: "Språk",
226
+ "organization.select": "Välj en organisation för att fortsätta:"
226
227
  };
227
228
 
228
229
  export default messages;
@@ -484,7 +484,8 @@ const messages = {
484
484
  selectAnOption: "เลือกตัวเลือก",
485
485
  remove: "ลบ",
486
486
  addValue: "เพิ่มค่า",
487
- languages: "ภาษา"
487
+ languages: "ภาษา",
488
+ "organization.select": "เลือกองค์กรเพื่อดำเนินการต่อ:"
488
489
  };
489
490
 
490
491
  export default messages;
@@ -299,7 +299,8 @@ const messages = {
299
299
  selectAnOption: "Bir seçenek seçin",
300
300
  remove: "Kaldır",
301
301
  addValue: "Değer ekle",
302
- languages: "Diller"
302
+ languages: "Diller",
303
+ "organization.select": "Devam etmek için bir organizasyon seçin:"
303
304
  };
304
305
 
305
306
  export default messages;
@@ -510,7 +510,8 @@ const messages = {
510
510
  selectAnOption: "Виберіть опцію",
511
511
  remove: "Видалити",
512
512
  addValue: "Додати значення",
513
- languages: "Мови"
513
+ languages: "Мови",
514
+ "organization.select": "Виберіть організацію, щоб продовжити:"
514
515
  };
515
516
 
516
517
  export default messages;
@@ -455,7 +455,8 @@ const messages = {
455
455
  selectAnOption: "选择一个选项",
456
456
  remove: "移除",
457
457
  addValue: "添加值",
458
- languages: "语言"
458
+ languages: "语言",
459
+ "organization.select": "选择一个组织以继续:"
459
460
  };
460
461
 
461
462
  export default messages;
@@ -464,7 +464,8 @@ const messages = {
464
464
  selectAnOption: "選擇一個選項",
465
465
  remove: "移除",
466
466
  addValue: "添加值",
467
- languages: "語言"
467
+ languages: "語言",
468
+ "organization.select": "選擇一個組織以繼續:"
468
469
  };
469
470
 
470
471
  export default messages;
@@ -122,6 +122,7 @@ export type ClassKey =
122
122
  | "kcFormHeaderClass"
123
123
  | "kcFormSocialAccountGridItem"
124
124
  | "kcButtonPrimaryClass"
125
+ | "kcButtonSecondaryClass"
125
126
  | "kcInputHelperTextBeforeClass"
126
127
  | "kcLogoIdP-github"
127
128
  | "kcLabelClass";
@@ -256,6 +257,7 @@ export const { getKcClsx } = createGetKcClsx<ClassKey>({
256
257
  kcFormHeaderClass: "login-pf-header",
257
258
  kcFormSocialAccountGridItem: "pf-l-grid__item",
258
259
  kcButtonPrimaryClass: "pf-m-primary",
260
+ kcButtonSecondaryClass: "pf-m-secondary",
259
261
  kcInputHelperTextBeforeClass:
260
262
  "pf-c-form__helper-text pf-c-form__helper-text-before",
261
263
  "kcLogoIdP-github": "fa fa-github",
@@ -4,6 +4,7 @@ import { getKcClsx } from "keycloakify/login/lib/kcClsx";
4
4
  import type { PageProps } from "keycloakify/login/pages/PageProps";
5
5
  import type { KcContext } from "../KcContext";
6
6
  import type { I18n } from "../i18n";
7
+ import { useScript } from "keycloakify/login/pages/LoginUsername.useScript";
7
8
 
8
9
  export default function LoginUsername(props: PageProps<Extract<KcContext, { pageId: "login-username.ftl" }>, I18n>) {
9
10
  const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
@@ -13,12 +14,21 @@ export default function LoginUsername(props: PageProps<Extract<KcContext, { page
13
14
  classes
14
15
  });
15
16
 
16
- const { social, realm, url, usernameHidden, login, registrationDisabled, messagesPerField } = kcContext;
17
+ const { social, realm, url, usernameHidden, login, registrationDisabled, messagesPerField, enableWebAuthnConditionalUI, authenticators } =
18
+ kcContext;
17
19
 
18
20
  const { msg, msgStr } = i18n;
19
21
 
20
22
  const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
21
23
 
24
+ const authButtonId = "authenticateWebAuthnButton";
25
+
26
+ useScript({
27
+ authButtonId,
28
+ kcContext,
29
+ i18n
30
+ });
31
+
22
32
  return (
23
33
  <Template
24
34
  kcContext={kcContext}
@@ -143,6 +153,32 @@ export default function LoginUsername(props: PageProps<Extract<KcContext, { page
143
153
  )}
144
154
  </div>
145
155
  </div>
156
+ {enableWebAuthnConditionalUI && (
157
+ <>
158
+ <form id="webauth" action={url.loginAction} method="post">
159
+ <input type="hidden" id="clientDataJSON" name="clientDataJSON" />
160
+ <input type="hidden" id="authenticatorData" name="authenticatorData" />
161
+ <input type="hidden" id="signature" name="signature" />
162
+ <input type="hidden" id="credentialId" name="credentialId" />
163
+ <input type="hidden" id="userHandle" name="userHandle" />
164
+ <input type="hidden" id="error" name="error" />
165
+ </form>
166
+
167
+ {authenticators !== undefined && Object.keys(authenticators).length !== 0 && (
168
+ <>
169
+ <form id="authn_select" className={kcClsx("kcFormClass")}>
170
+ {authenticators.authenticators.map((authenticator, i) => (
171
+ <input key={i} type="hidden" name="authn_use_chk" readOnly value={authenticator.credentialId} />
172
+ ))}
173
+ </form>
174
+ </>
175
+ )}
176
+ <br />
177
+ <a id={authButtonId} href="#" className={kcClsx("kcButtonSecondaryClass", "kcButtonBlockClass")}>
178
+ {msg("passkey-doAuthenticate")}
179
+ </a>
180
+ </>
181
+ )}
146
182
  </Template>
147
183
  );
148
184
  }
@@ -0,0 +1,71 @@
1
+ import { useEffect } from "react";
2
+ import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
3
+ import { assert } from "keycloakify/tools/assert";
4
+ import { KcContext } from "keycloakify/login/KcContext/KcContext";
5
+ import { waitForElementMountedOnDom } from "keycloakify/tools/waitForElementMountedOnDom";
6
+
7
+ type KcContextLike = {
8
+ url: {
9
+ resourcesPath: string;
10
+ };
11
+ isUserIdentified: "true" | "false";
12
+ challenge: string;
13
+ userVerification: KcContext.WebauthnAuthenticate["userVerification"];
14
+ rpId: string;
15
+ createTimeout: number | string;
16
+ };
17
+
18
+ assert<keyof KcContextLike extends keyof KcContext.LoginUsername ? true : false>();
19
+ assert<KcContext.LoginUsername extends KcContextLike ? true : false>();
20
+
21
+ type I18nLike = {
22
+ msgStr: (key: "webauthn-unsupported-browser-text") => string;
23
+ isFetchingTranslations: boolean;
24
+ };
25
+
26
+ export function useScript(params: { authButtonId: string; kcContext: KcContextLike; i18n: I18nLike }) {
27
+ const { authButtonId, kcContext, i18n } = params;
28
+
29
+ const { url, isUserIdentified, challenge, userVerification, rpId, createTimeout } = kcContext;
30
+
31
+ const { msgStr, isFetchingTranslations } = i18n;
32
+
33
+ const { insertScriptTags } = useInsertScriptTags({
34
+ componentOrHookName: "LoginUsername",
35
+ scriptTags: [
36
+ {
37
+ type: "module",
38
+ textContent: () => `
39
+
40
+ import { authenticateByWebAuthn } from "${url.resourcesPath}/js/webauthnAuthenticate.js";
41
+ const authButton = document.getElementById('${authButtonId}');
42
+ authButton.addEventListener("click", function() {
43
+ const input = {
44
+ isUserIdentified : ${isUserIdentified},
45
+ challenge : '${challenge}',
46
+ userVerification : '${userVerification}',
47
+ rpId : '${rpId}',
48
+ createTimeout : ${createTimeout},
49
+ errmsg : ${JSON.stringify(msgStr("webauthn-unsupported-browser-text"))}
50
+ };
51
+ authenticateByWebAuthn(input);
52
+ });
53
+ `
54
+ }
55
+ ]
56
+ });
57
+
58
+ useEffect(() => {
59
+ if (isFetchingTranslations) {
60
+ return;
61
+ }
62
+
63
+ (async () => {
64
+ await waitForElementMountedOnDom({
65
+ elementId: authButtonId
66
+ });
67
+
68
+ insertScriptTags();
69
+ })();
70
+ }, [isFetchingTranslations]);
71
+ }
@@ -0,0 +1,69 @@
1
+ import { MouseEvent, useRef, useState } from "react";
2
+ import { getKcClsx } from "keycloakify/login/lib/kcClsx";
3
+ import type { PageProps } from "keycloakify/login/pages/PageProps";
4
+ import type { KcContext } from "../KcContext";
5
+ import type { I18n } from "../i18n";
6
+
7
+ export default function SelectOrganization(props: PageProps<Extract<KcContext, { pageId: "select-organization.ftl" }>, I18n>) {
8
+ const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
9
+
10
+ const { kcClsx } = getKcClsx({
11
+ doUseDefaultCss,
12
+ classes
13
+ });
14
+
15
+ const { url, user } = kcContext;
16
+
17
+ const { msg } = i18n;
18
+
19
+ const [isSubmitting, setIsSubmitting] = useState(false);
20
+ const formRef = useRef<HTMLFormElement>(null);
21
+ const organizationInputRef = useRef<HTMLInputElement>(null);
22
+
23
+ const onOrganizationClick = (organizationAlias: string) => (event: MouseEvent<HTMLButtonElement>) => {
24
+ event.preventDefault();
25
+
26
+ if (!organizationInputRef.current || !formRef.current) {
27
+ return;
28
+ }
29
+
30
+ organizationInputRef.current.value = organizationAlias;
31
+ setIsSubmitting(true);
32
+
33
+ if (typeof formRef.current.requestSubmit === "function") {
34
+ formRef.current.requestSubmit();
35
+ return;
36
+ }
37
+
38
+ formRef.current.submit();
39
+ };
40
+
41
+ const organizations = user.organizations ?? [];
42
+ const shouldDisplayGrid = organizations.length > 3;
43
+
44
+ return (
45
+ <Template kcContext={kcContext} i18n={i18n} doUseDefaultCss={doUseDefaultCss} classes={classes} headerNode={null}>
46
+ <form ref={formRef} action={url.loginAction} className="form-vertical" method="post">
47
+ <div id="kc-user-organizations" className={kcClsx("kcFormGroupClass")}>
48
+ <h2>{msg("organization.select")}</h2>
49
+ <ul className={kcClsx("kcFormSocialAccountListClass", shouldDisplayGrid && "kcFormSocialAccountListGridClass")}>
50
+ {organizations.map(({ alias, name }) => (
51
+ <li key={alias}>
52
+ <button
53
+ id={`organization-${alias}`}
54
+ className={kcClsx("kcFormSocialAccountListButtonClass", shouldDisplayGrid && "kcFormSocialAccountGridItem")}
55
+ type="button"
56
+ onClick={onOrganizationClick(alias)}
57
+ disabled={isSubmitting}
58
+ >
59
+ <span className={kcClsx("kcFormSocialAccountNameClass")}>{name ?? alias}</span>
60
+ </button>
61
+ </li>
62
+ ))}
63
+ </ul>
64
+ </div>
65
+ <input ref={organizationInputRef} type="hidden" name="kc.org" />
66
+ </form>
67
+ </Template>
68
+ );
69
+ }
@@ -0,0 +1,18 @@
1
+ import React from "react";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+ import { createKcPageStory } from "../KcPageStory";
4
+
5
+ const { KcPageStory } = createKcPageStory({ pageId: "select-organization.ftl" });
6
+
7
+ const meta = {
8
+ title: "login/select-organization.ftl",
9
+ component: KcPageStory
10
+ } satisfies Meta<typeof KcPageStory>;
11
+
12
+ export default meta;
13
+
14
+ type Story = StoryObj<typeof meta>;
15
+
16
+ export const Default: Story = {
17
+ render: () => <KcPageStory />
18
+ };
@@ -1076,7 +1076,8 @@ const LOGIN_THEME_PAGE_IDS = [
1076
1076
  "login-x509-info.ftl",
1077
1077
  "webauthn-error.ftl",
1078
1078
  "login-passkeys-conditional-authenticate.ftl",
1079
- "login-idp-link-confirm-override.ftl"
1079
+ "login-idp-link-confirm-override.ftl",
1080
+ "select-organization.ftl"
1080
1081
  ];
1081
1082
  const ACCOUNT_THEME_PAGE_IDS = [
1082
1083
  "password.ftl",