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.
- package/bin/main.js +2 -1
- package/bin/shared/constants.d.ts +1 -1
- package/bin/shared/constants.js +2 -1
- package/bin/shared/constants.js.map +1 -1
- package/login/DefaultPage.js +3 -0
- package/login/DefaultPage.js.map +1 -1
- package/login/KcContext/KcContext.d.ts +19 -1
- package/login/KcContext/KcContext.js.map +1 -1
- package/login/KcContext/getKcContextMock.d.ts +1 -1
- package/login/KcContext/kcContextMocks.d.ts +1 -1
- package/login/KcContext/kcContextMocks.js +21 -2
- package/login/KcContext/kcContextMocks.js.map +1 -1
- package/login/i18n/messages_defaultSet/ar.d.ts +1 -0
- package/login/i18n/messages_defaultSet/ar.js +2 -1
- package/login/i18n/messages_defaultSet/ar.js.map +1 -1
- package/login/i18n/messages_defaultSet/ca.d.ts +1 -0
- package/login/i18n/messages_defaultSet/ca.js +2 -1
- package/login/i18n/messages_defaultSet/ca.js.map +1 -1
- package/login/i18n/messages_defaultSet/cs.d.ts +1 -0
- package/login/i18n/messages_defaultSet/cs.js +2 -1
- package/login/i18n/messages_defaultSet/cs.js.map +1 -1
- package/login/i18n/messages_defaultSet/da.d.ts +1 -0
- package/login/i18n/messages_defaultSet/da.js +2 -1
- package/login/i18n/messages_defaultSet/da.js.map +1 -1
- package/login/i18n/messages_defaultSet/de.d.ts +1 -0
- package/login/i18n/messages_defaultSet/de.js +2 -1
- package/login/i18n/messages_defaultSet/de.js.map +1 -1
- package/login/i18n/messages_defaultSet/el.d.ts +1 -0
- package/login/i18n/messages_defaultSet/el.js +2 -1
- package/login/i18n/messages_defaultSet/el.js.map +1 -1
- package/login/i18n/messages_defaultSet/en.d.ts +1 -0
- package/login/i18n/messages_defaultSet/en.js +2 -1
- package/login/i18n/messages_defaultSet/en.js.map +1 -1
- package/login/i18n/messages_defaultSet/es.d.ts +1 -0
- package/login/i18n/messages_defaultSet/es.js +2 -1
- package/login/i18n/messages_defaultSet/es.js.map +1 -1
- package/login/i18n/messages_defaultSet/fa.d.ts +1 -0
- package/login/i18n/messages_defaultSet/fa.js +2 -1
- package/login/i18n/messages_defaultSet/fa.js.map +1 -1
- package/login/i18n/messages_defaultSet/fi.d.ts +1 -0
- package/login/i18n/messages_defaultSet/fi.js +2 -1
- package/login/i18n/messages_defaultSet/fi.js.map +1 -1
- package/login/i18n/messages_defaultSet/fr.d.ts +1 -0
- package/login/i18n/messages_defaultSet/fr.js +2 -1
- package/login/i18n/messages_defaultSet/fr.js.map +1 -1
- package/login/i18n/messages_defaultSet/hu.d.ts +1 -0
- package/login/i18n/messages_defaultSet/hu.js +2 -1
- package/login/i18n/messages_defaultSet/hu.js.map +1 -1
- package/login/i18n/messages_defaultSet/index.d.ts +10 -0
- package/login/i18n/messages_defaultSet/it.d.ts +1 -0
- package/login/i18n/messages_defaultSet/it.js +2 -1
- package/login/i18n/messages_defaultSet/it.js.map +1 -1
- package/login/i18n/messages_defaultSet/ja.d.ts +1 -0
- package/login/i18n/messages_defaultSet/ja.js +2 -1
- package/login/i18n/messages_defaultSet/ja.js.map +1 -1
- package/login/i18n/messages_defaultSet/ka.d.ts +1 -0
- package/login/i18n/messages_defaultSet/ka.js +2 -1
- package/login/i18n/messages_defaultSet/ka.js.map +1 -1
- package/login/i18n/messages_defaultSet/lt.d.ts +1 -0
- package/login/i18n/messages_defaultSet/lt.js +2 -1
- package/login/i18n/messages_defaultSet/lt.js.map +1 -1
- package/login/i18n/messages_defaultSet/lv.d.ts +1 -0
- package/login/i18n/messages_defaultSet/lv.js +2 -1
- package/login/i18n/messages_defaultSet/lv.js.map +1 -1
- package/login/i18n/messages_defaultSet/nl.d.ts +1 -0
- package/login/i18n/messages_defaultSet/nl.js +2 -1
- package/login/i18n/messages_defaultSet/nl.js.map +1 -1
- package/login/i18n/messages_defaultSet/no.d.ts +1 -0
- package/login/i18n/messages_defaultSet/no.js +2 -1
- package/login/i18n/messages_defaultSet/no.js.map +1 -1
- package/login/i18n/messages_defaultSet/pl.d.ts +1 -0
- package/login/i18n/messages_defaultSet/pl.js +2 -1
- package/login/i18n/messages_defaultSet/pl.js.map +1 -1
- package/login/i18n/messages_defaultSet/pt-BR.d.ts +1 -0
- package/login/i18n/messages_defaultSet/pt-BR.js +2 -1
- package/login/i18n/messages_defaultSet/pt-BR.js.map +1 -1
- package/login/i18n/messages_defaultSet/pt.d.ts +1 -0
- package/login/i18n/messages_defaultSet/pt.js +2 -1
- package/login/i18n/messages_defaultSet/pt.js.map +1 -1
- package/login/i18n/messages_defaultSet/ru.d.ts +1 -0
- package/login/i18n/messages_defaultSet/ru.js +2 -1
- package/login/i18n/messages_defaultSet/ru.js.map +1 -1
- package/login/i18n/messages_defaultSet/sk.d.ts +1 -0
- package/login/i18n/messages_defaultSet/sk.js +2 -1
- package/login/i18n/messages_defaultSet/sk.js.map +1 -1
- package/login/i18n/messages_defaultSet/sv.d.ts +1 -0
- package/login/i18n/messages_defaultSet/sv.js +2 -1
- package/login/i18n/messages_defaultSet/sv.js.map +1 -1
- package/login/i18n/messages_defaultSet/th.d.ts +1 -0
- package/login/i18n/messages_defaultSet/th.js +2 -1
- package/login/i18n/messages_defaultSet/th.js.map +1 -1
- package/login/i18n/messages_defaultSet/tr.d.ts +1 -0
- package/login/i18n/messages_defaultSet/tr.js +2 -1
- package/login/i18n/messages_defaultSet/tr.js.map +1 -1
- package/login/i18n/messages_defaultSet/uk.d.ts +1 -0
- package/login/i18n/messages_defaultSet/uk.js +2 -1
- package/login/i18n/messages_defaultSet/uk.js.map +1 -1
- package/login/i18n/messages_defaultSet/zh-CN.d.ts +1 -0
- package/login/i18n/messages_defaultSet/zh-CN.js +2 -1
- package/login/i18n/messages_defaultSet/zh-CN.js.map +1 -1
- package/login/i18n/messages_defaultSet/zh-TW.d.ts +1 -0
- package/login/i18n/messages_defaultSet/zh-TW.js +2 -1
- package/login/i18n/messages_defaultSet/zh-TW.js.map +1 -1
- package/login/lib/kcClsx.d.ts +1 -1
- package/login/lib/kcClsx.js +1 -0
- package/login/lib/kcClsx.js.map +1 -1
- package/login/pages/LoginUsername.js +16 -9
- package/login/pages/LoginUsername.js.map +1 -1
- package/login/pages/LoginUsername.useScript.d.ts +21 -0
- package/login/pages/LoginUsername.useScript.js +47 -0
- package/login/pages/LoginUsername.useScript.js.map +1 -0
- package/login/pages/SelectOrganization.d.ts +7 -0
- package/login/pages/SelectOrganization.js +33 -0
- package/login/pages/SelectOrganization.js.map +1 -0
- package/package.json +10 -1
- package/src/bin/shared/constants.ts +2 -1
- package/src/login/DefaultPage.tsx +3 -0
- package/src/login/KcContext/KcContext.ts +22 -1
- package/src/login/KcContext/kcContextMocks.ts +30 -1
- package/src/login/i18n/messages_defaultSet/ar.ts +2 -1
- package/src/login/i18n/messages_defaultSet/ca.ts +2 -1
- package/src/login/i18n/messages_defaultSet/cs.ts +2 -1
- package/src/login/i18n/messages_defaultSet/da.ts +2 -1
- package/src/login/i18n/messages_defaultSet/de.ts +2 -1
- package/src/login/i18n/messages_defaultSet/el.ts +2 -1
- package/src/login/i18n/messages_defaultSet/en.ts +2 -1
- package/src/login/i18n/messages_defaultSet/es.ts +2 -1
- package/src/login/i18n/messages_defaultSet/fa.ts +2 -1
- package/src/login/i18n/messages_defaultSet/fi.ts +2 -1
- package/src/login/i18n/messages_defaultSet/fr.ts +2 -1
- package/src/login/i18n/messages_defaultSet/hu.ts +2 -1
- package/src/login/i18n/messages_defaultSet/it.ts +2 -1
- package/src/login/i18n/messages_defaultSet/ja.ts +2 -1
- package/src/login/i18n/messages_defaultSet/ka.ts +2 -1
- package/src/login/i18n/messages_defaultSet/lt.ts +2 -1
- package/src/login/i18n/messages_defaultSet/lv.ts +2 -1
- package/src/login/i18n/messages_defaultSet/nl.ts +2 -1
- package/src/login/i18n/messages_defaultSet/no.ts +2 -1
- package/src/login/i18n/messages_defaultSet/pl.ts +2 -1
- package/src/login/i18n/messages_defaultSet/pt-BR.ts +2 -1
- package/src/login/i18n/messages_defaultSet/pt.ts +2 -1
- package/src/login/i18n/messages_defaultSet/ru.ts +2 -1
- package/src/login/i18n/messages_defaultSet/sk.ts +2 -1
- package/src/login/i18n/messages_defaultSet/sv.ts +2 -1
- package/src/login/i18n/messages_defaultSet/th.ts +2 -1
- package/src/login/i18n/messages_defaultSet/tr.ts +2 -1
- package/src/login/i18n/messages_defaultSet/uk.ts +2 -1
- package/src/login/i18n/messages_defaultSet/zh-CN.ts +2 -1
- package/src/login/i18n/messages_defaultSet/zh-TW.ts +2 -1
- package/src/login/lib/kcClsx.ts +2 -0
- package/src/login/pages/LoginUsername.tsx +37 -1
- package/src/login/pages/LoginUsername.useScript.tsx +71 -0
- package/src/login/pages/SelectOrganization.tsx +69 -0
- package/stories/login/pages/SelectOrganization.stories.tsx +18 -0
- 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;
|
|
@@ -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;
|
package/src/login/lib/kcClsx.ts
CHANGED
|
@@ -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 } =
|
|
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
|
+
};
|
package/vite-plugin/index.js
CHANGED
|
@@ -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",
|