Implement login
This commit is contained in:
parent
6a93c6e894
commit
e5e39d036d
@ -55,6 +55,7 @@
|
||||
"dependencies": {
|
||||
"cheerio": "^1.0.0-rc.5",
|
||||
"evt": "^1.9.12",
|
||||
"minimal-polyfills": "^2.1.6",
|
||||
"powerhooks": "^0.0.14",
|
||||
"tss-react": "^0.0.9"
|
||||
}
|
||||
|
@ -4,12 +4,19 @@
|
||||
"loginAction": "${url.loginAction}",
|
||||
"resourcesPath": "${url.resourcesPath}",
|
||||
"resourcesCommonPath": "${url.resourcesCommonPath}",
|
||||
"loginRestartFlowUrl": "${url.loginRestartFlowUrl}"
|
||||
"loginRestartFlowUrl": "${url.loginRestartFlowUrl}",
|
||||
"loginResetCredentialsUrl": "${url.loginResetCredentialsUrl}",
|
||||
"registrationUrl": "${url.registrationUrl}"
|
||||
},
|
||||
"realm": {
|
||||
"displayName": "${realm.displayName!''}" || undefined,
|
||||
"displayNameHtml": "${realm.displayNameHtml!''}" || undefined,
|
||||
"internationalizationEnabled": ${realm.internationalizationEnabled?c}
|
||||
"internationalizationEnabled": ${realm.internationalizationEnabled?c},
|
||||
"password": ${realm.password?c},
|
||||
"loginWithEmailAllowed": ${realm.loginWithEmailAllowed?c},
|
||||
"registrationEmailAsUsername": ${realm.registrationEmailAsUsername?c},
|
||||
"rememberMe": ${realm.rememberMe?c},
|
||||
"resetPasswordAllowed": ${realm.resetPasswordAllowed?c}
|
||||
},
|
||||
"locale": (function (){
|
||||
|
||||
@ -54,6 +61,7 @@
|
||||
"showUsername": ${auth.showUsername()?c},
|
||||
"showResetCredentials": ${auth.showResetCredentials()?c},
|
||||
"showTryAnotherWayLink": ${auth.showTryAnotherWayLink()?c}
|
||||
"selectedCredential": "${auth.selectedCredential!''}" || undefined
|
||||
};
|
||||
|
||||
<#if auth.showUsername() && !auth.showResetCredentials()>
|
||||
@ -107,7 +115,59 @@
|
||||
</#if>
|
||||
return false;
|
||||
|
||||
})()
|
||||
})(),
|
||||
"social": {
|
||||
"displayInfo": ${social.displayInfo?c},
|
||||
"providers": (()=>{
|
||||
|
||||
<#if social.providers??>
|
||||
|
||||
var out= [];
|
||||
|
||||
<#list social.providers as p>
|
||||
out.push({
|
||||
"loginUrl": "${p.loginUrl}",
|
||||
"alias": "${p.alias}",
|
||||
"providerId": "${p.providerId}",
|
||||
"displayName": "${p.displayName}"
|
||||
});
|
||||
</#list>
|
||||
|
||||
return out;
|
||||
|
||||
</#if>
|
||||
|
||||
return undefined;
|
||||
|
||||
})()
|
||||
},
|
||||
"usernameEditDisabled": (function () {
|
||||
|
||||
<#if usernameEditDisabled??>
|
||||
return true;
|
||||
</#if>
|
||||
return false;
|
||||
|
||||
})(),
|
||||
"login": {
|
||||
"username": "${login.username!''}" || undefined,
|
||||
"rememberMe": (function (){
|
||||
|
||||
<#if login.rememberMe??>
|
||||
return true;
|
||||
</#if>
|
||||
return false;
|
||||
|
||||
|
||||
})()
|
||||
},
|
||||
"registrationDisabled": (function (){
|
||||
|
||||
<#if registrationDisabled??>
|
||||
return true;
|
||||
</#if>
|
||||
return false;
|
||||
|
||||
})
|
||||
}
|
||||
</script>
|
@ -1,18 +1,154 @@
|
||||
|
||||
/*
|
||||
import { useState, memo } from "react";
|
||||
import { KcProperties, Template } from "./Template";
|
||||
import { assert } from "evt/tools/typeSafety/assert";
|
||||
import { keycloakPagesContext } from "./keycloakFtlValues";
|
||||
import { useState, memo } from "react";
|
||||
import { allPropertiesValuesToUndefined } from "./tools/allPropertiesValuesToUndefined";
|
||||
import { Template, defaultKcTemplateProperties } from "./Template";
|
||||
import type { KcTemplateProperties, KcClasses } from "./Template";
|
||||
import { assert } from "evt/tools/typeSafety/assert";
|
||||
import { keycloakPagesContext } from "./keycloakFtlValues";
|
||||
import { useKeycloakThemeTranslation } from "./i18n/useKeycloakTranslation";
|
||||
import { cx } from "tss-react";
|
||||
import { useConstCallback } from "powerhooks";
|
||||
|
||||
export type KcLoginPageProperties = KcTemplateProperties & KcClasses<
|
||||
"kcLogoLink" |
|
||||
"kcLogoClass" |
|
||||
"kcContainerClass" |
|
||||
"kcContentClass" |
|
||||
"kcFeedbackAreaClass" |
|
||||
"kcLocaleClass" |
|
||||
"kcAlertIconClasserror" |
|
||||
"kcFormAreaClass" |
|
||||
"kcFormSocialAccountListClass" |
|
||||
"kcFormSocialAccountDoubleListClass" |
|
||||
"kcFormSocialAccountListLinkClass" |
|
||||
"kcWebAuthnKeyIcon" |
|
||||
"kcFormClass" |
|
||||
"kcFormGroupErrorClass" |
|
||||
"kcLabelClass" |
|
||||
"kcInputClass" |
|
||||
"kcInputWrapperClass" |
|
||||
"kcFormOptionsClass" |
|
||||
"kcFormButtonsClass" |
|
||||
"kcFormSettingClass" |
|
||||
"kcTextareaClass" |
|
||||
"kcInfoAreaClass" |
|
||||
"kcButtonClass" |
|
||||
"kcButtonPrimaryClass" |
|
||||
"kcButtonDefaultClass" |
|
||||
"kcButtonLargeClass" |
|
||||
"kcButtonBlockClass" |
|
||||
"kcInputLargeClass" |
|
||||
"kcSrOnlyClass" |
|
||||
"kcSelectAuthListClass" |
|
||||
"kcSelectAuthListItemClass" |
|
||||
"kcSelectAuthListItemInfoClass" |
|
||||
"kcSelectAuthListItemLeftClass" |
|
||||
"kcSelectAuthListItemBodyClass" |
|
||||
"kcSelectAuthListItemDescriptionClass" |
|
||||
"kcSelectAuthListItemHeadingClass" |
|
||||
"kcSelectAuthListItemHelpTextClass" |
|
||||
"kcAuthenticatorDefaultClass" |
|
||||
"kcAuthenticatorPasswordClass" |
|
||||
"kcAuthenticatorOTPClass" |
|
||||
"kcAuthenticatorWebAuthnClass" |
|
||||
"kcAuthenticatorWebAuthnPasswordlessClass" |
|
||||
"kcSelectOTPListClass" |
|
||||
"kcSelectOTPListItemClass" |
|
||||
"kcAuthenticatorOtpCircleClass" |
|
||||
"kcSelectOTPItemHeadingClass" |
|
||||
"kcFormOptionsWrapperClass"
|
||||
>;
|
||||
|
||||
export const defaultKcLoginPageProperties: KcLoginPageProperties = {
|
||||
...defaultKcTemplateProperties,
|
||||
"kcLogoLink": "http://www.keycloak.org",
|
||||
"kcLogoClass": "login-pf-brand",
|
||||
"kcContainerClass": "container-fluid",
|
||||
"kcContentClass": "col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3 col-lg-6 col-lg-offset-3",
|
||||
"kcFeedbackAreaClass": "col-md-12",
|
||||
"kcLocaleClass": "col-xs-12 col-sm-1",
|
||||
"kcAlertIconClasserror": "pficon pficon-error-circle-o",
|
||||
|
||||
"kcFormAreaClass": "col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-2",
|
||||
"kcFormSocialAccountListClass": "login-pf-social list-unstyled login-pf-social-all",
|
||||
"kcFormSocialAccountDoubleListClass": "login-pf-social-double-col",
|
||||
"kcFormSocialAccountListLinkClass": "login-pf-social-link",
|
||||
"kcWebAuthnKeyIcon": "pficon pficon-key",
|
||||
|
||||
"kcFormClass": "form-horizontal",
|
||||
"kcFormGroupErrorClass": "has-error",
|
||||
"kcLabelClass": "control-label",
|
||||
"kcInputClass": "form-control",
|
||||
"kcInputWrapperClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12",
|
||||
"kcFormOptionsClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12",
|
||||
"kcFormButtonsClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12",
|
||||
"kcFormSettingClass": "login-pf-settings",
|
||||
"kcTextareaClass": "form-control",
|
||||
|
||||
"kcInfoAreaClass": "col-xs-12 col-sm-4 col-md-4 col-lg-5 details",
|
||||
|
||||
// css classes for form buttons main class used for all buttons
|
||||
"kcButtonClass": "btn",
|
||||
// classes defining priority of the button - primary or default (there is typically only one priority button for the form)
|
||||
"kcButtonPrimaryClass": "btn-primary",
|
||||
"kcButtonDefaultClass": "btn-default",
|
||||
// classes defining size of the button
|
||||
"kcButtonLargeClass": "btn-lg",
|
||||
"kcButtonBlockClass": "btn-block",
|
||||
|
||||
// css classes for input
|
||||
"kcInputLargeClass": "input-lg",
|
||||
|
||||
// css classes for form accessability
|
||||
"kcSrOnlyClass": "sr-only",
|
||||
|
||||
// css classes for select-authenticator form
|
||||
"kcSelectAuthListClass": "list-group list-view-pf",
|
||||
"kcSelectAuthListItemClass": "list-group-item list-view-pf-stacked",
|
||||
"kcSelectAuthListItemInfoClass": "list-view-pf-main-info",
|
||||
"kcSelectAuthListItemLeftClass": "list-view-pf-left",
|
||||
"kcSelectAuthListItemBodyClass": "list-view-pf-body",
|
||||
"kcSelectAuthListItemDescriptionClass": "list-view-pf-description",
|
||||
"kcSelectAuthListItemHeadingClass": "list-group-item-heading",
|
||||
"kcSelectAuthListItemHelpTextClass": "list-group-item-text",
|
||||
|
||||
// css classes for the authenticators
|
||||
"kcAuthenticatorDefaultClass": "fa list-view-pf-icon-lg",
|
||||
"kcAuthenticatorPasswordClass": "fa fa-unlock list-view-pf-icon-lg",
|
||||
"kcAuthenticatorOTPClass": "fa fa-mobile list-view-pf-icon-lg",
|
||||
"kcAuthenticatorWebAuthnClass": "fa fa-key list-view-pf-icon-lg",
|
||||
"kcAuthenticatorWebAuthnPasswordlessClass": "fa fa-key list-view-pf-icon-lg",
|
||||
|
||||
//css classes for the OTP Login Form
|
||||
"kcSelectOTPListClass": "card-pf card-pf-view card-pf-view-select card-pf-view-single-select",
|
||||
"kcSelectOTPListItemClass": "card-pf-body card-pf-top-element",
|
||||
"kcAuthenticatorOtpCircleClass": "fa fa-mobile card-pf-icon-circle",
|
||||
"kcSelectOTPItemHeadingClass": "card-pf-title text-center"
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Tu use if you don't want any default */
|
||||
export const allClearKcLoginPageProperties =
|
||||
allPropertiesValuesToUndefined(defaultKcLoginPageProperties);
|
||||
|
||||
export type Props = {
|
||||
properties: KcProperties;
|
||||
properties?: KcLoginPageProperties;
|
||||
};
|
||||
|
||||
export const LoginPage = memo((props: Props) => {
|
||||
|
||||
const { properties = {} } = props;
|
||||
|
||||
const [{ }] = useState(() => {
|
||||
const { t, tStr } = useKeycloakThemeTranslation();
|
||||
|
||||
Object.assign(properties, defaultKcLoginPageProperties);
|
||||
|
||||
const [{
|
||||
social, realm, url,
|
||||
usernameEditDisabled, login,
|
||||
auth, registrationDisabled
|
||||
}] = useState(() => {
|
||||
|
||||
assert(keycloakPagesContext !== undefined);
|
||||
|
||||
@ -20,12 +156,145 @@ export const LoginPage = memo((props: Props)=>{
|
||||
|
||||
});
|
||||
|
||||
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
|
||||
|
||||
return (
|
||||
<Template/>
|
||||
const onSubmit = useConstCallback(() =>
|
||||
(setIsLoginButtonDisabled(true), true)
|
||||
);
|
||||
|
||||
});
|
||||
*/
|
||||
|
||||
export {};
|
||||
return (
|
||||
<Template
|
||||
displayInfo={social.displayInfo}
|
||||
displayWide={realm.password && social.providers !== undefined}
|
||||
properties={properties}
|
||||
headerNode={t("doLogIn")}
|
||||
showUsernameNode={null}
|
||||
formNode={
|
||||
|
||||
|
||||
<div
|
||||
id="kc-form"
|
||||
className={cx(realm.password && social.providers !== undefined && properties.kcContentWrapperClass)}
|
||||
>
|
||||
<div
|
||||
id="kc-form-wrapper"
|
||||
className={cx(realm.password && social.providers && [properties.kcFormSocialAccountContentClass, properties.kcFormSocialAccountClass])}
|
||||
>
|
||||
{
|
||||
realm.password &&
|
||||
(
|
||||
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
|
||||
<div className={cx(properties.kcFormGroupClass)}>
|
||||
<label htmlFor="username" className={cx(properties.kcLabelClass)}>
|
||||
{
|
||||
!realm.loginWithEmailAllowed ?
|
||||
t("username")
|
||||
:
|
||||
(
|
||||
!realm.registrationEmailAsUsername ?
|
||||
t("usernameOrEmail") :
|
||||
t("email")
|
||||
)
|
||||
}
|
||||
|
||||
</label>
|
||||
<input
|
||||
tabIndex={1}
|
||||
id="username"
|
||||
className={cx(properties.kcInputClass)}
|
||||
name="username"
|
||||
value={login.username ?? ''}
|
||||
type="text"
|
||||
{...(usernameEditDisabled ? { "disabled": true } : { "autofocus": true, "autocomplete": "off" })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={cx(properties.kcFormGroupClass)}>
|
||||
<label htmlFor="password" className={cx(properties.kcLabelClass)}>
|
||||
{t("password")}
|
||||
</label>
|
||||
<input tabIndex={2} id="password" className={cx(properties.kcInputClass)} name="password" type="password" autoComplete="off" />
|
||||
</div>
|
||||
|
||||
<div className={cx(properties.kcFormGroupClass, properties.kcFormSettingClass)}>
|
||||
<div id="kc-form-options">
|
||||
{
|
||||
(
|
||||
realm.rememberMe &&
|
||||
!usernameEditDisabled
|
||||
) &&
|
||||
<div className="checkbox">
|
||||
<label>
|
||||
<input tabIndex={3} id="rememberMe" name="rememberMe" type="checkbox" {...(login.rememberMe ? { "checked": true } : {})}> {t("rememberMe")}</input>
|
||||
</label>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div className={cx(properties.kcFormOptionsWrapperClass)}>
|
||||
{
|
||||
realm.resetPasswordAllowed &&
|
||||
<span>
|
||||
<a tabIndex={5} href={url.loginResetCredentialsUrl}>{t("doForgotPassword")}</a>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="kc-form-buttons" className={cx(properties.kcFormGroupClass)}>
|
||||
<input
|
||||
type="hidden"
|
||||
id="id-hidden-input"
|
||||
name="credentialId"
|
||||
{...(auth?.selectedCredential !== undefined ? { "value": auth.selectedCredential } : {})}
|
||||
/>
|
||||
<input
|
||||
tabIndex={4}
|
||||
className={cx(properties.kcButtonClass, properties.kcButtonPrimaryClass, properties.kcButtonBlockClass, properties.kcButtonLargeClass)} name="login" id="kc-login" type="submit"
|
||||
value={tStr("doLogIn")}
|
||||
disabled={isLoginButtonDisabled}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
{
|
||||
(realm.password && social.providers !== undefined) &&
|
||||
<div id="kc-social-providers" className={cx(properties.kcFormSocialAccountContentClass, properties.kcFormSocialAccountClass)}>
|
||||
<ul className={cx(properties.kcFormSocialAccountListClass, social.providers.length > 4 && properties.kcFormSocialAccountDoubleListClass)}>
|
||||
{
|
||||
social.providers.map(p =>
|
||||
<li className={cx(properties.kcFormSocialAccountListLinkClass)}>
|
||||
<a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}>
|
||||
<span>{p.displayName}</span>
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
displayInfoNode={
|
||||
(
|
||||
realm.password &&
|
||||
realm.resetPasswordAllowed &&
|
||||
!registrationDisabled
|
||||
) &&
|
||||
<div id="kc-registration">
|
||||
<span>
|
||||
{t("noAccount")}
|
||||
<a tabIndex={6} href={url.registrationUrl}>
|
||||
{t("doRegister")}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
import { useState, useEffect, memo } from "react";
|
||||
import type { ReactNode } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useKeycloakThemeTranslation } from "./i18n/useKeycloakTranslation";
|
||||
import { keycloakPagesContext } from "./keycloakFtlValues";
|
||||
import { assert } from "evt/tools/typeSafety/assert";
|
||||
@ -12,10 +12,25 @@ import { appendLinkInHead } from "./tools/appendLinkInHead";
|
||||
import { appendScriptInHead } from "./tools/appendScriptInHead";
|
||||
import { join as pathJoin } from "path";
|
||||
import { useConstCallback } from "powerhooks";
|
||||
import { allPropertiesValuesToUndefined } from "./tools/allPropertiesValuesToUndefined";
|
||||
|
||||
type KcClasses<T extends string> = { [key in T]?: string[] | string };
|
||||
export type Props = {
|
||||
displayInfo?: boolean;
|
||||
displayMessage?: boolean;
|
||||
displayRequiredFields?: boolean;
|
||||
displayWide?: boolean;
|
||||
showAnotherWayIfPresent?: boolean;
|
||||
properties: KcTemplateProperties;
|
||||
headerNode: ReactNode;
|
||||
showUsernameNode: ReactNode;
|
||||
formNode: ReactNode;
|
||||
displayInfoNode: ReactNode;
|
||||
};
|
||||
|
||||
export type KcProperties = {
|
||||
/** Class names can be provided as an array or separated by whitespace */
|
||||
export type KcClasses<T extends string> = { [key in T]?: string[] | string };
|
||||
|
||||
export type KcTemplateProperties = {
|
||||
stylesCommon?: string[];
|
||||
styles?: string[];
|
||||
scripts?: string[];
|
||||
@ -45,20 +60,36 @@ export type KcProperties = {
|
||||
"kcInfoAreaWrapperClass"
|
||||
>;
|
||||
|
||||
export type Props = {
|
||||
displayInfo?: boolean;
|
||||
displayMessage: boolean;
|
||||
displayRequiredFields: boolean;
|
||||
displayWide: boolean;
|
||||
showAnotherWayIfPresent: boolean;
|
||||
properties?: KcProperties;
|
||||
headerNode: ReactNode;
|
||||
showUsernameNode: ReactNode;
|
||||
formNode: ReactNode;
|
||||
displayInfoNode: ReactNode;
|
||||
export const defaultKcTemplateProperties: KcTemplateProperties = {
|
||||
"styles": ["css/login.css"],
|
||||
"stylesCommon": [
|
||||
...[".min.css", "-additions.min.css"]
|
||||
.map(end => `node_modules/patternfly/dist/css/patternfly${end}`),
|
||||
"lib/zocial/zocial.css"
|
||||
],
|
||||
"kcLoginClass": "login-pf-page",
|
||||
"kcContentWrapperClass": "row",
|
||||
"kcHeaderClass": "login-pf-page-header",
|
||||
"kcFormCardClass": "card-pf",
|
||||
"kcFormCardAccountClass": "login-pf-accounts",
|
||||
"kcFormSocialAccountClass": "login-pf-social-section",
|
||||
"kcFormSocialAccountContentClass": "col-xs-12 col-sm-6",
|
||||
"kcFormHeaderClass": "login-pf-header",
|
||||
"kcFeedbackErrorIcon": "pficon pficon-error-circle-o",
|
||||
"kcFeedbackWarningIcon": "pficon pficon-warning-triangle-o",
|
||||
"kcFeedbackSuccessIcon": "pficon pficon-ok",
|
||||
"kcFeedbackInfoIcon": "pficon pficon-info",
|
||||
"kcResetFlowIcon": "pficon pficon-arrow fa-2x",
|
||||
"kcFormGroupClass": "form-group",
|
||||
"kcLabelWrapperClass": "col-xs-12 col-sm-12 col-md-12 col-lg-12",
|
||||
"kcSignUpClass": "login-pf-sighup"
|
||||
};
|
||||
|
||||
export function Template(props: Props) {
|
||||
/** Tu use if you don't want any default */
|
||||
export const allClearKcTemplateProperties =
|
||||
allPropertiesValuesToUndefined(defaultKcTemplateProperties);
|
||||
|
||||
export const Template = memo((props: Props) =>{
|
||||
|
||||
const {
|
||||
displayInfo = false,
|
||||
@ -75,6 +106,8 @@ export function Template(props: Props) {
|
||||
|
||||
const { t } = useKeycloakThemeTranslation();
|
||||
|
||||
Object.assign(properties, defaultKcTemplateProperties);
|
||||
|
||||
const { keycloakLanguage, setKeycloakLanguage } = useKeycloakLanguage();
|
||||
|
||||
const onChangeLanguageClickFactory = useCallbackFactory(
|
||||
@ -286,4 +319,4 @@ export function Template(props: Props) {
|
||||
</div >
|
||||
</div >
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -3,18 +3,18 @@ import { useKeycloakLanguage } from "./useKeycloakLanguage";
|
||||
import { messages } from "./generated_messages/login";
|
||||
import { useConstCallback } from "powerhooks";
|
||||
import type { ReactNode } from "react";
|
||||
import { id } from "evt/tools/typeSafety/id";
|
||||
|
||||
export type MessageKey = keyof typeof messages["en"]
|
||||
|
||||
export type MessageKey = keyof typeof messages["en"];
|
||||
|
||||
export function useKeycloakThemeTranslation() {
|
||||
|
||||
const { keycloakLanguage } = useKeycloakLanguage();
|
||||
|
||||
const t = useConstCallback(
|
||||
(key: MessageKey, ...args: (string | undefined)[]): ReactNode => {
|
||||
const tStr = useConstCallback(
|
||||
(key: MessageKey, ...args: (string | undefined)[]): string => {
|
||||
|
||||
let out: string = messages[keycloakLanguage as any as "en"][key] ?? messages["en"][key];
|
||||
let str: string = messages[keycloakLanguage as any as "en"][key] ?? messages["en"][key];
|
||||
|
||||
args.forEach((arg, i) => {
|
||||
|
||||
@ -22,15 +22,22 @@ export function useKeycloakThemeTranslation() {
|
||||
return;
|
||||
}
|
||||
|
||||
out = out.replace(new RegExp(`\\{${i}\\}`, "g"), arg);
|
||||
str = str.replace(new RegExp(`\\{${i}\\}`, "g"), arg);
|
||||
|
||||
});
|
||||
|
||||
return <span className={key} dangerouslySetInnerHTML={{ "__html": out }} />;
|
||||
return str;
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
return { t };
|
||||
const t = useConstCallback(
|
||||
id<(...args: Parameters<typeof tStr>) => ReactNode>(
|
||||
(key, ...args) =>
|
||||
<span className={key} dangerouslySetInnerHTML={{ "__html": tStr(key, ...args) }} />
|
||||
)
|
||||
);
|
||||
|
||||
return { t, tStr };
|
||||
|
||||
}
|
@ -13,12 +13,19 @@ export type KeycloakFtlValues = {
|
||||
resourcesPath: string;
|
||||
resourcesCommonPath: string;
|
||||
loginRestartFlowUrl: string;
|
||||
},
|
||||
loginResetCredentialsUrl: string;
|
||||
registrationUrl: string;
|
||||
};
|
||||
realm: {
|
||||
displayName?: string;
|
||||
displayNameHtml?: string;
|
||||
internationalizationEnabled: boolean;
|
||||
},
|
||||
password: boolean;
|
||||
loginWithEmailAllowed: boolean;
|
||||
registrationEmailAsUsername: boolean;
|
||||
rememberMe: boolean;
|
||||
resetPasswordAllowed: boolean;
|
||||
};
|
||||
/** Undefined if !realm.internationalizationEnabled */
|
||||
locale?: {
|
||||
supported: {
|
||||
@ -38,13 +45,29 @@ export type KeycloakFtlValues = {
|
||||
showResetCredentials: boolean;
|
||||
showTryAnotherWayLink: boolean;
|
||||
attemptedUsername?: boolean;
|
||||
},
|
||||
selectedCredential?: string;
|
||||
};
|
||||
scripts: string[];
|
||||
message?: {
|
||||
type: "success" | "warning" | "error" | "info";
|
||||
summary: string;
|
||||
},
|
||||
};
|
||||
isAppInitiatedAction: boolean;
|
||||
social: {
|
||||
displayInfo: boolean;
|
||||
providers?: {
|
||||
loginUrl: string;
|
||||
alias: string;
|
||||
providerId: string;
|
||||
displayName: string;
|
||||
}[]
|
||||
};
|
||||
usernameEditDisabled: boolean;
|
||||
login: {
|
||||
username?: string;
|
||||
rememberMe: boolean;
|
||||
};
|
||||
registrationDisabled: boolean;
|
||||
};
|
||||
|
||||
export const { keycloakPagesContext } =
|
||||
|
10
src/lib/tools/allPropertiesValuesToUndefined.ts
Normal file
10
src/lib/tools/allPropertiesValuesToUndefined.ts
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
|
||||
import "minimal-polyfills/Object.fromEntries";
|
||||
|
||||
export function allPropertiesValuesToUndefined<T extends Record<string, unknown>>(obj: T): Record<keyof T, undefined> {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj)
|
||||
.map(([key]) => [key, undefined])
|
||||
) as any;
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
"module": "CommonJS",
|
||||
"target": "es5",
|
||||
"lib": ["es2015", "DOM"],
|
||||
"lib": ["es2015", "DOM", "ES2019.Object"],
|
||||
"esModuleInterop": true,
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
|
@ -816,7 +816,7 @@ memoizee@^0.4.15:
|
||||
next-tick "^1.1.0"
|
||||
timers-ext "^0.1.7"
|
||||
|
||||
minimal-polyfills@^2.1.5:
|
||||
minimal-polyfills@^2.1.5, minimal-polyfills@^2.1.6:
|
||||
version "2.1.6"
|
||||
resolved "https://registry.yarnpkg.com/minimal-polyfills/-/minimal-polyfills-2.1.6.tgz#eab50832add31afd40a22b38fb76d1fdcd2a51e4"
|
||||
integrity sha512-vqoxj7eMzsqX0M6/dkgoNFPw6Mztgn5qjSl0bWGboQeU7Y4UPLeyoqQw6JI+0qmBcJYdkr3nK7dqY8u/fgRp5g==
|
||||
|
Loading…
x
Reference in New Issue
Block a user