Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
d24a8e99cc | ||
|
59d2d56091 | ||
|
8515b7060a | ||
|
a076b3f4d0 | ||
|
1e3240ef35 | ||
|
d767080dfe | ||
|
b228eda488 | ||
|
35f54964ce | ||
|
759b834ccc | ||
|
137e12cbbb | ||
|
57b08d9dea | ||
|
1dd7b673a1 | ||
|
b00ffc50c3 | ||
|
f9db40d33d | ||
|
4bc6a843d8 | ||
|
da3e7514f0 | ||
|
bc396bc41b | ||
|
947efe8d63 | ||
|
64189bf8fe | ||
|
400c630418 | ||
|
402360b436 | ||
|
9f001f1521 | ||
|
368e3a32c5 |
@ -345,6 +345,24 @@
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "kodebach",
|
||||
"name": "Klemens Böswirth",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/23529132?v=4",
|
||||
"profile": "https://github.com/kodebach",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "wnmzzzz",
|
||||
"name": "wnmzzzz",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/117174301?v=4",
|
||||
"profile": "https://github.com/wnmzzzz",
|
||||
"contributions": [
|
||||
"test"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
@ -6,7 +6,7 @@
|
||||
<br>
|
||||
<br>
|
||||
<a href="https://github.com/garronej/keycloakify/actions">
|
||||
<img src="https://github.com/garronej/keycloakify/workflows/ci/badge.svg?branch=main">
|
||||
<img src="https://github.com/keycloakify/keycloakify/actions/workflows/ci.yaml/badge.svg">
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/keycloakify">
|
||||
<img src="https://img.shields.io/npm/dm/keycloakify">
|
||||
@ -171,6 +171,8 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://t.me/AAT_L"><img src="https://avatars.githubusercontent.com/u/118743608?v=4?s=100" width="100px;" alt="Lesha"/><br /><sub><b>Lesha</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=EternalSide" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://blog.bacongobbler.com"><img src="https://avatars.githubusercontent.com/u/1360539?v=4?s=100" width="100px;" alt="Matthew Fisher"/><br /><sub><b>Matthew Fisher</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=bacongobbler" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kodebach"><img src="https://avatars.githubusercontent.com/u/23529132?v=4?s=100" width="100px;" alt="Klemens Böswirth"/><br /><sub><b>Klemens Böswirth</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=kodebach" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wnmzzzz"><img src="https://avatars.githubusercontent.com/u/117174301?v=4?s=100" width="100px;" alt="wnmzzzz"/><br /><sub><b>wnmzzzz</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=wnmzzzz" title="Tests">⚠️</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "keycloakify",
|
||||
"version": "11.8.19",
|
||||
"version": "11.8.23",
|
||||
"description": "Framework to create custom Keycloak UIs",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -18,7 +18,7 @@ export async function command(params: { buildContext: BuildContext }) {
|
||||
const { buildContext } = params;
|
||||
|
||||
const { hasBeenHandled } = await maybeDelegateCommandToCustomHandler({
|
||||
commandName: "initialize-account-theme",
|
||||
commandName: "initialize-email-theme",
|
||||
buildContext
|
||||
});
|
||||
|
||||
|
@ -45,12 +45,12 @@ export async function getExtensionModuleFileSourceCodeReadyToBeCopied(params: {
|
||||
`This file has been claimed for ownership from ${extensionModuleName} version ${extensionModuleVersion}.`,
|
||||
`To relinquish ownership and restore this file to its original content, run the following command:`,
|
||||
``,
|
||||
`$ npx keycloakify own --path '${path}' --revert`
|
||||
`$ npx keycloakify own --path "${path}" --revert`
|
||||
]
|
||||
: [
|
||||
`WARNING: Before modifying this file, run the following command:`,
|
||||
``,
|
||||
`$ npx keycloakify own --path '${path}'`,
|
||||
`$ npx keycloakify own --path "${path}"`,
|
||||
``,
|
||||
`This file is provided by ${extensionModuleName} version ${extensionModuleVersion}.`,
|
||||
`It was copied into your repository by the postinstall script: \`keycloakify sync-extensions\`.`
|
||||
|
@ -14,6 +14,8 @@ export function getAbsoluteAndInOsFormatPath(params: {
|
||||
|
||||
let pathOut = pathIsh;
|
||||
|
||||
pathOut = pathOut.replace(/^['"]/, "").replace(/['"]$/, "");
|
||||
|
||||
pathOut = pathOut.replace(/\//g, pathSep);
|
||||
|
||||
if (pathOut.startsWith("~")) {
|
||||
|
@ -52,10 +52,26 @@ export async function getPrettier(): Promise<PrettierAndConfigHash> {
|
||||
// So we do a sketchy eval to bypass ncc.
|
||||
// We make sure to only do that when linking, otherwise we import properly.
|
||||
if (readThisNpmPackageVersion().startsWith("0.0.0")) {
|
||||
eval(
|
||||
`${symToStr({ prettier })} = require("${pathResolve(pathJoin(getNodeModulesBinDirPath({ packageJsonFilePath: undefined }), "..", "prettier"))}")`
|
||||
const prettierDirPath = pathResolve(
|
||||
pathJoin(
|
||||
getNodeModulesBinDirPath({ packageJsonFilePath: undefined }),
|
||||
"..",
|
||||
"prettier"
|
||||
)
|
||||
);
|
||||
|
||||
const isCJS = typeof module !== "undefined" && module.exports;
|
||||
|
||||
if (isCJS) {
|
||||
eval(`${symToStr({ prettier })} = require("${prettierDirPath}")`);
|
||||
} else {
|
||||
prettier = await new Promise(_resolve => {
|
||||
eval(
|
||||
`import("file:///${pathJoin(prettierDirPath, "index.mjs").replace(/\\/g, "/")}").then(prettier => _resolve(prettier))`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
assert(!is<undefined>(prettier));
|
||||
|
||||
break import_prettier;
|
||||
|
@ -90,7 +90,6 @@ export default function UserProfileFormFields(props: UserProfileFormFieldsProps<
|
||||
{advancedMsg(attribute.annotations.inputHelperTextAfter)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{AfterField !== undefined && (
|
||||
<AfterField
|
||||
attribute={attribute}
|
||||
@ -107,6 +106,10 @@ export default function UserProfileFormFields(props: UserProfileFormFieldsProps<
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
{/* See: https://github.com/keycloak/keycloak/issues/38029 */}
|
||||
{kcContext.locale !== undefined && formFieldStates.find(x => x.attribute.name === "locale") === undefined && (
|
||||
<input type="hidden" name="locale" value={i18n.currentLanguage.languageTag} />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -217,25 +217,6 @@ export function createGetI18n<
|
||||
return enabledLanguages;
|
||||
})();
|
||||
|
||||
// See: https://github.com/keycloak/keycloak/issues/38029
|
||||
patch_keycloak_issue_38029: {
|
||||
const enabledLanguage_current = enabledLanguages.find(({ languageTag }) => languageTag === currentLanguage.languageTag);
|
||||
|
||||
assert(enabledLanguage_current !== undefined);
|
||||
|
||||
if (!enabledLanguage_current.href.includes("kc_locale=")) {
|
||||
// NOTE: Probably a mock
|
||||
break patch_keycloak_issue_38029;
|
||||
}
|
||||
|
||||
// NOTE: Best effort, we don't wait for it to be done
|
||||
// and we don't handle errors
|
||||
fetch(enabledLanguage_current.href).then(
|
||||
() => {},
|
||||
() => {}
|
||||
);
|
||||
}
|
||||
|
||||
const { createI18nTranslationFunctions } = createI18nTranslationFunctionsFactory<MessageKey_themeDefined>({
|
||||
themeName: kcContext.themeName,
|
||||
messages_themeDefined:
|
||||
|
@ -31,10 +31,10 @@ export default function Info(props: PageProps<Extract<KcContext, { pageId: "info
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: kcSanitize(
|
||||
(() => {
|
||||
let html = message.summary;
|
||||
let html = message.summary?.trim();
|
||||
|
||||
if (requiredActions) {
|
||||
html += "<b>";
|
||||
html += " <b>";
|
||||
|
||||
html += requiredActions.map(requiredAction => advancedMsgStr(`requiredAction.${requiredAction}`)).join(", ");
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Fragment } from "react";
|
||||
import { Fragment, useState } from "react";
|
||||
import { getKcClsx } from "keycloakify/login/lib/kcClsx";
|
||||
import { kcSanitize } from "keycloakify/lib/kcSanitize";
|
||||
import type { PageProps } from "keycloakify/login/pages/PageProps";
|
||||
@ -17,6 +17,8 @@ export default function LoginOtp(props: PageProps<Extract<KcContext, { pageId: "
|
||||
|
||||
const { msg, msgStr } = i18n;
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
return (
|
||||
<Template
|
||||
kcContext={kcContext}
|
||||
@ -26,7 +28,16 @@ export default function LoginOtp(props: PageProps<Extract<KcContext, { pageId: "
|
||||
displayMessage={!messagesPerField.existsError("totp")}
|
||||
headerNode={msg("doLogIn")}
|
||||
>
|
||||
<form id="kc-otp-login-form" className={kcClsx("kcFormClass")} action={url.loginAction} method="post">
|
||||
<form
|
||||
id="kc-otp-login-form"
|
||||
className={kcClsx("kcFormClass")}
|
||||
action={url.loginAction}
|
||||
onSubmit={() => {
|
||||
setIsSubmitting(true);
|
||||
return true;
|
||||
}}
|
||||
method="post"
|
||||
>
|
||||
{otpLogin.userOtpCredentials.length > 1 && (
|
||||
<div className={kcClsx("kcFormGroupClass")}>
|
||||
<div className={kcClsx("kcInputWrapperClass")}>
|
||||
@ -94,6 +105,7 @@ export default function LoginOtp(props: PageProps<Extract<KcContext, { pageId: "
|
||||
id="kc-login"
|
||||
type="submit"
|
||||
value={msgStr("doLogIn")}
|
||||
disabled={isSubmitting}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -46,7 +46,7 @@ export const WithRequiredActions: Story = {
|
||||
kcContext={{
|
||||
messageHeader: "Message header",
|
||||
message: {
|
||||
summary: "Required actions: "
|
||||
summary: "Required actions:"
|
||||
},
|
||||
requiredActions: ["CONFIGURE_TOTP", "UPDATE_PROFILE", "VERIFY_EMAIL", "CUSTOM_ACTION"],
|
||||
"x-keycloakify": {
|
||||
|
@ -62,3 +62,22 @@ export const WithPasswordConfirmError: Story = {
|
||||
/>
|
||||
)
|
||||
};
|
||||
|
||||
/**
|
||||
* WithAppInitiatedAction:
|
||||
* - Purpose: Tests when the update password action was triggered by an app.
|
||||
* - Scenario: Simulates the case where the user presses a 'change password' button in an app and is redirected to Keycloak to change it.
|
||||
* - Key Aspect: Ensures the 'Cancel' button is shown correctly, which displays only when the action is app initiated.
|
||||
*/
|
||||
export const WithAppInitiatedAction: Story = {
|
||||
render: () => (
|
||||
<KcPageStory
|
||||
kcContext={{
|
||||
url: {
|
||||
loginAction: "/mock-login-action"
|
||||
},
|
||||
isAppInitiatedAction: true
|
||||
}}
|
||||
/>
|
||||
)
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user