Add Info page, refactor
This commit is contained in:
@ -57,6 +57,6 @@
|
|||||||
"evt": "2.0.0-beta.15",
|
"evt": "2.0.0-beta.15",
|
||||||
"minimal-polyfills": "^2.1.6",
|
"minimal-polyfills": "^2.1.6",
|
||||||
"powerhooks": "^0.0.17",
|
"powerhooks": "^0.0.17",
|
||||||
"tss-react": "^0.0.9"
|
"tss-react": "^0.0.11"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import fs from "fs";
|
|||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin } from "path";
|
||||||
import { objectKeys } from "evt/tools/typeSafety/objectKeys";
|
import { objectKeys } from "evt/tools/typeSafety/objectKeys";
|
||||||
|
|
||||||
function loadFtlFile(ftlFileBasename: "template.ftl" | "login.ftl" | "register.ftl") {
|
function loadFtlFile(ftlFileBasename: "template.ftl" | "login.ftl" | "register.ftl" | "info.ftl") {
|
||||||
return fs.readFileSync(pathJoin(__dirname, ftlFileBasename))
|
return fs.readFileSync(pathJoin(__dirname, ftlFileBasename))
|
||||||
.toString("utf8")
|
.toString("utf8")
|
||||||
.match(/^<script>const _=((?:.|\n)+)<\/script>[\n]?$/)![1];
|
.match(/^<script>const _=((?:.|\n)+)<\/script>[\n]?$/)![1];
|
||||||
@ -98,7 +98,7 @@ export function generateFtlFilesCodeFactory(
|
|||||||
|
|
||||||
function generateFtlFilesCode(
|
function generateFtlFilesCode(
|
||||||
params: {
|
params: {
|
||||||
pageBasename: "login.ftl" | "register.ftl"
|
pageBasename: "login.ftl" | "register.ftl" | "info.ftl"
|
||||||
}
|
}
|
||||||
): { ftlCode: string; } {
|
): { ftlCode: string; } {
|
||||||
|
|
||||||
|
37
src/bin/build-keycloak-theme/generateFtl/info.ftl
Normal file
37
src/bin/build-keycloak-theme/generateFtl/info.ftl
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<script>const _=
|
||||||
|
{
|
||||||
|
"messageHeader": "${messageHeader!''}" || undefined,
|
||||||
|
"requiredActions": (function (){
|
||||||
|
|
||||||
|
<#if requiredActions??>
|
||||||
|
|
||||||
|
var out =[];
|
||||||
|
|
||||||
|
<#list requiredActions>
|
||||||
|
<#items as reqActionItem>
|
||||||
|
out.push("${reqActionItem}");
|
||||||
|
</#items></b>
|
||||||
|
</#list>
|
||||||
|
|
||||||
|
return out;
|
||||||
|
|
||||||
|
<#else>
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
|
||||||
|
})(),
|
||||||
|
"skipLink": (function (){
|
||||||
|
|
||||||
|
<#if skipLink??>
|
||||||
|
return true;
|
||||||
|
</#if>
|
||||||
|
return false;
|
||||||
|
|
||||||
|
})(),
|
||||||
|
"pageRedirectUri": "${(pageRedirectUri!'')?no_esc}" || undefined,
|
||||||
|
"actionUri": "${(actionUri!'')?no_esc}" || undefined,
|
||||||
|
"client": {
|
||||||
|
"baseUrl": "${(actionUri!'')?no_esc}" || undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
76
src/lib/components/Info.tsx
Normal file
76
src/lib/components/Info.tsx
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
import { memo } from "react";
|
||||||
|
import { Template } from "./Template";
|
||||||
|
import type { KcProps } from "./KcProps";
|
||||||
|
import { assert } from "../tools/assert";
|
||||||
|
import { kcContext } from "../kcContext";
|
||||||
|
import { useKcTranslation } from "../i18n/useKcTranslation";
|
||||||
|
|
||||||
|
export const Info = memo((props: KcProps) => {
|
||||||
|
|
||||||
|
const { t } = useKcTranslation();
|
||||||
|
|
||||||
|
assert(
|
||||||
|
kcContext !== undefined &&
|
||||||
|
kcContext.pageBasename === "info.ftl" &&
|
||||||
|
kcContext.message !== undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
const {
|
||||||
|
messageHeader,
|
||||||
|
message,
|
||||||
|
requiredActions,
|
||||||
|
skipLink,
|
||||||
|
pageRedirectUri,
|
||||||
|
actionUri,
|
||||||
|
client
|
||||||
|
} = kcContext;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Template
|
||||||
|
{...props}
|
||||||
|
displayMessage={false}
|
||||||
|
headerNode={
|
||||||
|
messageHeader !== undefined ?
|
||||||
|
<>{messageHeader}</>
|
||||||
|
:
|
||||||
|
<>{message.summary}</>
|
||||||
|
}
|
||||||
|
formNode={
|
||||||
|
<div id="kc-info-message">
|
||||||
|
<p className="instruction">{message.summary}
|
||||||
|
|
||||||
|
{
|
||||||
|
requiredActions !== undefined &&
|
||||||
|
<b>
|
||||||
|
{
|
||||||
|
requiredActions
|
||||||
|
.map(requiredAction => t(`requiredAction.${requiredAction}` as const))
|
||||||
|
.join(",")
|
||||||
|
}
|
||||||
|
|
||||||
|
</b>
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
</p>
|
||||||
|
{
|
||||||
|
!skipLink &&
|
||||||
|
pageRedirectUri !== undefined ?
|
||||||
|
<p><a href="${pageRedirectUri}">${(t("backToApplication"))}</a></p>
|
||||||
|
:
|
||||||
|
actionUri !== undefined ?
|
||||||
|
<p><a href="${actionUri}">${t("proceedWithAction")}</a></p>
|
||||||
|
:
|
||||||
|
client.baseUrl !== undefined &&
|
||||||
|
<p><a href="${client.baseUrl}">${t("backToApplication")}</a></p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
@ -2,23 +2,20 @@
|
|||||||
import { memo } from "react";
|
import { memo } from "react";
|
||||||
import { kcContext } from "../kcContext";
|
import { kcContext } from "../kcContext";
|
||||||
import { assert } from "../tools/assert";
|
import { assert } from "../tools/assert";
|
||||||
import type { KcPagesProperties } from "./KcProperties";
|
import type { KcProps } from "./KcProps";
|
||||||
import { Login } from "./Login";
|
import { Login } from "./Login";
|
||||||
import { Register } from "./Register";
|
import { Register } from "./Register";
|
||||||
|
import { Info } from "./Info";
|
||||||
|
|
||||||
export type KcAppProps = {
|
|
||||||
kcProperties?: KcPagesProperties;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const KcApp = memo((props: KcAppProps) => {
|
export const KcApp = memo((props: KcProps) => {
|
||||||
|
|
||||||
const { kcProperties } = props;
|
|
||||||
|
|
||||||
assert(kcContext !== undefined, "App is not currently served by a Keycloak server");
|
assert(kcContext !== undefined, "App is not currently served by a Keycloak server");
|
||||||
|
|
||||||
switch (kcContext.pageBasename) {
|
switch (kcContext.pageBasename) {
|
||||||
case "login.ftl": return <Login kcProperties={kcProperties} />;
|
case "login.ftl": return <Login {...props} />;
|
||||||
case "register.ftl": return <Register kcProperties={kcProperties} />;
|
case "register.ftl": return <Register {...props} />;
|
||||||
|
case "info.ftl": return <Info {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
@ -1,192 +0,0 @@
|
|||||||
|
|
||||||
import { allPropertiesValuesToUndefined } from "../tools/allPropertiesValuesToUndefined";
|
|
||||||
|
|
||||||
/** Class names can be provided as an array or separated by whitespace */
|
|
||||||
export type KcClasses<CssClasses extends string> = { [key in CssClasses]?: string[] | string };
|
|
||||||
|
|
||||||
export type KcTemplateCssClasses =
|
|
||||||
"kcHtmlClass" |
|
|
||||||
"kcLoginClass" |
|
|
||||||
"kcHeaderClass" |
|
|
||||||
"kcHeaderWrapperClass" |
|
|
||||||
"kcFormCardClass" |
|
|
||||||
"kcFormCardAccountClass" |
|
|
||||||
"kcFormHeaderClass" |
|
|
||||||
"kcLocaleWrapperClass" |
|
|
||||||
"kcContentWrapperClass" |
|
|
||||||
"kcLabelWrapperClass" |
|
|
||||||
"kcContentWrapperClass" |
|
|
||||||
"kcLabelWrapperClass" |
|
|
||||||
"kcFormGroupClass" |
|
|
||||||
"kcResetFlowIcon" |
|
|
||||||
"kcResetFlowIcon" |
|
|
||||||
"kcFeedbackSuccessIcon" |
|
|
||||||
"kcFeedbackWarningIcon" |
|
|
||||||
"kcFeedbackErrorIcon" |
|
|
||||||
"kcFeedbackInfoIcon" |
|
|
||||||
"kcContentWrapperClass" |
|
|
||||||
"kcFormSocialAccountContentClass" |
|
|
||||||
"kcFormSocialAccountClass" |
|
|
||||||
"kcSignUpClass" |
|
|
||||||
"kcInfoAreaWrapperClass"
|
|
||||||
;
|
|
||||||
|
|
||||||
export type KcTemplateProperties = {
|
|
||||||
stylesCommon?: string[];
|
|
||||||
styles?: string[];
|
|
||||||
scripts?: string[];
|
|
||||||
} & KcClasses<KcTemplateCssClasses>;
|
|
||||||
|
|
||||||
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"
|
|
||||||
],
|
|
||||||
"kcHtmlClass": "login-pf",
|
|
||||||
"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-signup"
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Tu use if you don't want any default */
|
|
||||||
export const allClearKcTemplateProperties =
|
|
||||||
allPropertiesValuesToUndefined(defaultKcTemplateProperties);
|
|
||||||
|
|
||||||
export type KcPagesProperties = KcClasses<
|
|
||||||
KcTemplateCssClasses |
|
|
||||||
"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 defaultKcPagesProperties: KcPagesProperties = {
|
|
||||||
...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(defaultKcPagesProperties);
|
|
205
src/lib/components/KcProps.ts
Normal file
205
src/lib/components/KcProps.ts
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
|
||||||
|
import { allPropertiesValuesToUndefined } from "../tools/allPropertiesValuesToUndefined";
|
||||||
|
import { doExtends } from "evt/tools/typeSafety/doExtends";
|
||||||
|
|
||||||
|
/** Class names can be provided as an array or separated by whitespace */
|
||||||
|
export type KcPropsGeneric<CssClasses extends string> = { [key in CssClasses]: readonly string[] | string | undefined; };
|
||||||
|
|
||||||
|
export type KcTemplateClassKey =
|
||||||
|
"stylesCommon" |
|
||||||
|
"styles" |
|
||||||
|
"scripts" |
|
||||||
|
"kcHtmlClass" |
|
||||||
|
"kcLoginClass" |
|
||||||
|
"kcHeaderClass" |
|
||||||
|
"kcHeaderWrapperClass" |
|
||||||
|
"kcFormCardClass" |
|
||||||
|
"kcFormCardAccountClass" |
|
||||||
|
"kcFormHeaderClass" |
|
||||||
|
"kcLocaleWrapperClass" |
|
||||||
|
"kcContentWrapperClass" |
|
||||||
|
"kcLabelWrapperClass" |
|
||||||
|
"kcContentWrapperClass" |
|
||||||
|
"kcLabelWrapperClass" |
|
||||||
|
"kcFormGroupClass" |
|
||||||
|
"kcResetFlowIcon" |
|
||||||
|
"kcResetFlowIcon" |
|
||||||
|
"kcFeedbackSuccessIcon" |
|
||||||
|
"kcFeedbackWarningIcon" |
|
||||||
|
"kcFeedbackErrorIcon" |
|
||||||
|
"kcFeedbackInfoIcon" |
|
||||||
|
"kcContentWrapperClass" |
|
||||||
|
"kcFormSocialAccountContentClass" |
|
||||||
|
"kcFormSocialAccountClass" |
|
||||||
|
"kcSignUpClass" |
|
||||||
|
"kcInfoAreaWrapperClass"
|
||||||
|
;
|
||||||
|
|
||||||
|
export type KcTemplateProps = KcPropsGeneric<KcTemplateClassKey>;
|
||||||
|
|
||||||
|
export const defaultKcTemplateProps = {
|
||||||
|
"stylesCommon": [
|
||||||
|
"node_modules/patternfly/dist/css/patternfly.min.css",
|
||||||
|
"node_modules/patternfly/dist/css/patternfly-additions.min.css",
|
||||||
|
"lib/zocial/zocial.css"
|
||||||
|
],
|
||||||
|
"styles": ["css/login.css"],
|
||||||
|
"scripts": [],
|
||||||
|
"kcHtmlClass": ["login-pf"],
|
||||||
|
"kcLoginClass": ["login-pf-page"],
|
||||||
|
"kcContentWrapperClass": ["row"],
|
||||||
|
"kcHeaderClass": ["login-pf-page-header"],
|
||||||
|
"kcHeaderWrapperClass": [],
|
||||||
|
"kcFormCardClass": ["card-pf"],
|
||||||
|
"kcFormCardAccountClass": ["login-pf-accounts"],
|
||||||
|
"kcFormSocialAccountClass": ["login-pf-social-section"],
|
||||||
|
"kcFormSocialAccountContentClass": ["col-xs-12", "col-sm-6"],
|
||||||
|
"kcFormHeaderClass": ["login-pf-header"],
|
||||||
|
"kcLocaleWrapperClass": [],
|
||||||
|
"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-signup"],
|
||||||
|
"kcInfoAreaWrapperClass": []
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
|
||||||
|
doExtends<typeof defaultKcTemplateProps, KcTemplateProps>();
|
||||||
|
|
||||||
|
/** Tu use if you don't want any default */
|
||||||
|
export const allClearKcTemplateProps =
|
||||||
|
allPropertiesValuesToUndefined(defaultKcTemplateProps);
|
||||||
|
|
||||||
|
doExtends<typeof allClearKcTemplateProps, KcTemplateProps>();
|
||||||
|
|
||||||
|
export type KcProps = KcPropsGeneric<
|
||||||
|
KcTemplateClassKey |
|
||||||
|
"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 defaultKcProps = {
|
||||||
|
...defaultKcTemplateProps,
|
||||||
|
"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"],
|
||||||
|
"kcFormOptionsWrapperClass": []
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
doExtends<typeof defaultKcProps, KcProps>();
|
||||||
|
|
||||||
|
/** Tu use if you don't want any default */
|
||||||
|
export const allClearKcProps =
|
||||||
|
allPropertiesValuesToUndefined(defaultKcProps);
|
||||||
|
|
||||||
|
doExtends<typeof allClearKcProps, KcProps>();
|
||||||
|
|
@ -1,40 +1,27 @@
|
|||||||
|
|
||||||
import { useState, memo } from "react";
|
import { useState, memo } from "react";
|
||||||
import { Template } from "./Template";
|
import { Template } from "./Template";
|
||||||
import type { KcPagesProperties } from "./KcProperties";
|
import type { KcProps } from "./KcProps";
|
||||||
import { defaultKcPagesProperties } from "./KcProperties";
|
|
||||||
import { assert } from "../tools/assert";
|
import { assert } from "../tools/assert";
|
||||||
import { kcContext } from "../kcContext";
|
import { kcContext } from "../kcContext";
|
||||||
import { useKcTranslation } from "../i18n/useKcTranslation";
|
import { useKcTranslation } from "../i18n/useKcTranslation";
|
||||||
import { cx } from "tss-react";
|
import { cx } from "tss-react";
|
||||||
import { useConstCallback } from "powerhooks";
|
import { useConstCallback } from "powerhooks";
|
||||||
|
|
||||||
export type LoginProps = {
|
export const Login = memo((props: KcProps) => {
|
||||||
kcProperties?: KcPagesProperties;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Login = memo((props: LoginProps) => {
|
|
||||||
|
|
||||||
const { kcProperties = {} } = props;
|
|
||||||
|
|
||||||
const { t, tStr } = useKcTranslation();
|
const { t, tStr } = useKcTranslation();
|
||||||
|
|
||||||
Object.assign(kcProperties, defaultKcPagesProperties);
|
assert(
|
||||||
|
kcContext !== undefined &&
|
||||||
|
kcContext.pageBasename === "login.ftl"
|
||||||
|
);
|
||||||
|
|
||||||
const [{
|
const {
|
||||||
social, realm, url,
|
social, realm, url,
|
||||||
usernameEditDisabled, login,
|
usernameEditDisabled, login,
|
||||||
auth, registrationDisabled
|
auth, registrationDisabled
|
||||||
}] = useState(() => {
|
} = kcContext;
|
||||||
|
|
||||||
assert(
|
|
||||||
kcContext !== undefined &&
|
|
||||||
kcContext.pageBasename === "login.ftl"
|
|
||||||
);
|
|
||||||
|
|
||||||
return kcContext;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
|
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
|
||||||
|
|
||||||
@ -44,25 +31,25 @@ export const Login = memo((props: LoginProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Template
|
<Template
|
||||||
|
{...props}
|
||||||
displayInfo={social.displayInfo}
|
displayInfo={social.displayInfo}
|
||||||
displayWide={realm.password && social.providers !== undefined}
|
displayWide={realm.password && social.providers !== undefined}
|
||||||
kcProperties={kcProperties}
|
|
||||||
headerNode={t("doLogIn")}
|
headerNode={t("doLogIn")}
|
||||||
formNode={
|
formNode={
|
||||||
<div
|
<div
|
||||||
id="kc-form"
|
id="kc-form"
|
||||||
className={cx(realm.password && social.providers !== undefined && kcProperties.kcContentWrapperClass)}
|
className={cx(realm.password && social.providers !== undefined && props.kcContentWrapperClass)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
id="kc-form-wrapper"
|
id="kc-form-wrapper"
|
||||||
className={cx(realm.password && social.providers && [kcProperties.kcFormSocialAccountContentClass, kcProperties.kcFormSocialAccountClass])}
|
className={cx(realm.password && social.providers && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
realm.password &&
|
realm.password &&
|
||||||
(
|
(
|
||||||
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
|
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
|
||||||
<div className={cx(kcProperties.kcFormGroupClass)}>
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
<label htmlFor="username" className={cx(kcProperties.kcLabelClass)}>
|
<label htmlFor="username" className={cx(props.kcLabelClass)}>
|
||||||
{
|
{
|
||||||
!realm.loginWithEmailAllowed ?
|
!realm.loginWithEmailAllowed ?
|
||||||
t("username")
|
t("username")
|
||||||
@ -77,35 +64,35 @@ export const Login = memo((props: LoginProps) => {
|
|||||||
<input
|
<input
|
||||||
tabIndex={1}
|
tabIndex={1}
|
||||||
id="username"
|
id="username"
|
||||||
className={cx(kcProperties.kcInputClass)}
|
className={cx(props.kcInputClass)}
|
||||||
name="username"
|
name="username"
|
||||||
defaultValue={login.username ?? ''}
|
defaultValue={login.username ?? ''}
|
||||||
type="text"
|
type="text"
|
||||||
{...(usernameEditDisabled ? { "disabled": true } : { "autoFocus": true, "autocomplete": "off" })}
|
{...(usernameEditDisabled ? { "disabled": true } : { "autoFocus": true, "autocomplete": "off" })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(kcProperties.kcFormGroupClass)}>
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
<label htmlFor="password" className={cx(kcProperties.kcLabelClass)}>
|
<label htmlFor="password" className={cx(props.kcLabelClass)}>
|
||||||
{t("password")}
|
{t("password")}
|
||||||
</label>
|
</label>
|
||||||
<input tabIndex={2} id="password" className={cx(kcProperties.kcInputClass)} name="password" type="password" autoComplete="off" />
|
<input tabIndex={2} id="password" className={cx(props.kcInputClass)} name="password" type="password" autoComplete="off" />
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(kcProperties.kcFormGroupClass, kcProperties.kcFormSettingClass)}>
|
<div className={cx(props.kcFormGroupClass, props.kcFormSettingClass)}>
|
||||||
<div id="kc-form-options">
|
<div id="kc-form-options">
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
realm.rememberMe &&
|
realm.rememberMe &&
|
||||||
!usernameEditDisabled
|
!usernameEditDisabled
|
||||||
) &&
|
) &&
|
||||||
<div className="checkbox">
|
<div className="checkbox">
|
||||||
<label>
|
<label>
|
||||||
<input tabIndex={3} id="rememberMe" name="rememberMe" type="checkbox" {...(login.rememberMe ? { "checked": true } : {})}/>
|
<input tabIndex={3} id="rememberMe" name="rememberMe" type="checkbox" {...(login.rememberMe ? { "checked": true } : {})} />
|
||||||
{t("rememberMe")}
|
{t("rememberMe")}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(kcProperties.kcFormOptionsWrapperClass)}>
|
<div className={cx(props.kcFormOptionsWrapperClass)}>
|
||||||
{
|
{
|
||||||
realm.resetPasswordAllowed &&
|
realm.resetPasswordAllowed &&
|
||||||
<span>
|
<span>
|
||||||
@ -115,7 +102,7 @@ export const Login = memo((props: LoginProps) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div id="kc-form-buttons" className={cx(kcProperties.kcFormGroupClass)}>
|
<div id="kc-form-buttons" className={cx(props.kcFormGroupClass)}>
|
||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
id="id-hidden-input"
|
id="id-hidden-input"
|
||||||
@ -124,7 +111,7 @@ export const Login = memo((props: LoginProps) => {
|
|||||||
/>
|
/>
|
||||||
<input
|
<input
|
||||||
tabIndex={4}
|
tabIndex={4}
|
||||||
className={cx(kcProperties.kcButtonClass, kcProperties.kcButtonPrimaryClass, kcProperties.kcButtonBlockClass, kcProperties.kcButtonLargeClass)} name="login" id="kc-login" type="submit"
|
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)} name="login" id="kc-login" type="submit"
|
||||||
value={tStr("doLogIn")}
|
value={tStr("doLogIn")}
|
||||||
disabled={isLoginButtonDisabled}
|
disabled={isLoginButtonDisabled}
|
||||||
/>
|
/>
|
||||||
@ -135,11 +122,11 @@ export const Login = memo((props: LoginProps) => {
|
|||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
(realm.password && social.providers !== undefined) &&
|
(realm.password && social.providers !== undefined) &&
|
||||||
<div id="kc-social-providers" className={cx(kcProperties.kcFormSocialAccountContentClass, kcProperties.kcFormSocialAccountClass)}>
|
<div id="kc-social-providers" className={cx(props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass)}>
|
||||||
<ul className={cx(kcProperties.kcFormSocialAccountListClass, social.providers.length > 4 && kcProperties.kcFormSocialAccountDoubleListClass)}>
|
<ul className={cx(props.kcFormSocialAccountListClass, social.providers.length > 4 && props.kcFormSocialAccountDoubleListClass)}>
|
||||||
{
|
{
|
||||||
social.providers.map(p =>
|
social.providers.map(p =>
|
||||||
<li className={cx(kcProperties.kcFormSocialAccountListLinkClass)}>
|
<li className={cx(props.kcFormSocialAccountListLinkClass)}>
|
||||||
<a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}>
|
<a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}>
|
||||||
<span>{p.displayName}</span>
|
<span>{p.displayName}</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -1,27 +1,21 @@
|
|||||||
|
import { memo } from "react";
|
||||||
|
|
||||||
import { useState, memo } from "react";
|
|
||||||
import { Template } from "./Template";
|
import { Template } from "./Template";
|
||||||
import type { KcPagesProperties } from "./KcProperties";
|
import type { KcProps } from "./KcProps";
|
||||||
import { defaultKcPagesProperties } from "./KcProperties";
|
|
||||||
import { assert } from "../tools/assert";
|
import { assert } from "../tools/assert";
|
||||||
import { kcContext } from "../kcContext";
|
import { kcContext } from "../kcContext";
|
||||||
import { useKcTranslation } from "../i18n/useKcTranslation";
|
import { useKcTranslation } from "../i18n/useKcTranslation";
|
||||||
import { cx } from "tss-react";
|
import { cx } from "tss-react";
|
||||||
|
|
||||||
export type RegisterPageProps = {
|
export const Register = memo((props: KcProps) => {
|
||||||
kcProperties?: KcPagesProperties;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Register = memo((props: RegisterPageProps) => {
|
|
||||||
|
|
||||||
const { kcProperties = {} } = props;
|
|
||||||
|
|
||||||
const { t, tStr } = useKcTranslation();
|
const { t, tStr } = useKcTranslation();
|
||||||
|
|
||||||
Object.assign(kcProperties, defaultKcPagesProperties);
|
assert(
|
||||||
|
kcContext !== undefined &&
|
||||||
|
kcContext.pageBasename === "register.ftl"
|
||||||
|
);
|
||||||
|
|
||||||
const [{
|
const {
|
||||||
url,
|
url,
|
||||||
messagesPerField,
|
messagesPerField,
|
||||||
register,
|
register,
|
||||||
@ -29,91 +23,80 @@ export const Register = memo((props: RegisterPageProps) => {
|
|||||||
passwordRequired,
|
passwordRequired,
|
||||||
recaptchaRequired,
|
recaptchaRequired,
|
||||||
recaptchaSiteKey
|
recaptchaSiteKey
|
||||||
}] = useState(() => {
|
} = kcContext;
|
||||||
|
|
||||||
assert(
|
|
||||||
kcContext !== undefined &&
|
|
||||||
kcContext.pageBasename === "register.ftl"
|
|
||||||
);
|
|
||||||
|
|
||||||
return kcContext;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Template
|
<Template
|
||||||
kcProperties={kcProperties}
|
{...props}
|
||||||
headerNode={t("registerTitle")}
|
headerNode={t("registerTitle")}
|
||||||
formNode={
|
formNode={
|
||||||
<form id="kc-register-form" className={cx(kcProperties.kcFormClass)} action={url.registrationAction} method="post">
|
<form id="kc-register-form" className={cx(props.kcFormClass)} action={url.registrationAction} method="post">
|
||||||
|
|
||||||
<div className={cx(kcProperties.kcFormGroupClass, messagesPerField.printIfExists('firstName', kcProperties.kcFormGroupErrorClass))}>
|
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists('firstName', props.kcFormGroupErrorClass))}>
|
||||||
<div className={cx(kcProperties.kcLabelWrapperClass)}>
|
<div className={cx(props.kcLabelWrapperClass)}>
|
||||||
<label htmlFor="firstName" className={cx(kcProperties.kcLabelClass)}>{t("firstName")}</label>
|
<label htmlFor="firstName" className={cx(props.kcLabelClass)}>{t("firstName")}</label>
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(kcProperties.kcInputWrapperClass)}>
|
<div className={cx(props.kcInputWrapperClass)}>
|
||||||
<input type="text" id="firstName" className={cx(kcProperties.kcInputClass)} name="firstName"
|
<input type="text" id="firstName" className={cx(props.kcInputClass)} name="firstName"
|
||||||
defaultValue={register.formData.firstName ?? ""}
|
defaultValue={register.formData.firstName ?? ""}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={cx(kcProperties.kcFormGroupClass, messagesPerField.printIfExists("lastName", kcProperties.kcFormGroupErrorClass))}>
|
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("lastName", props.kcFormGroupErrorClass))}>
|
||||||
<div className={cx(kcProperties.kcLabelWrapperClass)}>
|
<div className={cx(props.kcLabelWrapperClass)}>
|
||||||
<label htmlFor="lastName" className={cx(kcProperties.kcLabelClass)}>{t("lastName")}</label>
|
<label htmlFor="lastName" className={cx(props.kcLabelClass)}>{t("lastName")}</label>
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(kcProperties.kcInputWrapperClass)}>
|
<div className={cx(props.kcInputWrapperClass)}>
|
||||||
<input type="text" id="lastName" className={cx(kcProperties.kcInputClass)} name="lastName"
|
<input type="text" id="lastName" className={cx(props.kcInputClass)} name="lastName"
|
||||||
defaultValue={register.formData.lastName ?? ""}
|
defaultValue={register.formData.lastName ?? ""}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={cx(kcProperties.kcFormGroupClass, messagesPerField.printIfExists('email', kcProperties.kcFormGroupErrorClass))}>
|
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists('email', props.kcFormGroupErrorClass))}>
|
||||||
<div className={cx(kcProperties.kcLabelWrapperClass)}>
|
<div className={cx(props.kcLabelWrapperClass)}>
|
||||||
<label htmlFor="email" className={cx(kcProperties.kcLabelClass)}>{t("email")}</label>
|
<label htmlFor="email" className={cx(props.kcLabelClass)}>{t("email")}</label>
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(kcProperties.kcInputWrapperClass)}>
|
<div className={cx(props.kcInputWrapperClass)}>
|
||||||
<input type="text" id="email" className={cx(kcProperties.kcInputClass)} name="email"
|
<input type="text" id="email" className={cx(props.kcInputClass)} name="email"
|
||||||
defaultValue={register.formData.email ?? ""} autoComplete="email"
|
defaultValue={register.formData.email ?? ""} autoComplete="email"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
!realm.registrationEmailAsUsername &&
|
!realm.registrationEmailAsUsername &&
|
||||||
|
|
||||||
<div className={cx(kcProperties.kcFormGroupClass, messagesPerField.printIfExists('username', kcProperties.kcFormGroupErrorClass))}>
|
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists('username', props.kcFormGroupErrorClass))}>
|
||||||
<div className={cx(kcProperties.kcLabelWrapperClass)}>
|
<div className={cx(props.kcLabelWrapperClass)}>
|
||||||
<label htmlFor="username" className={cx(kcProperties.kcLabelClass)}>{t("username")}</label>
|
<label htmlFor="username" className={cx(props.kcLabelClass)}>{t("username")}</label>
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(kcProperties.kcInputWrapperClass)}>
|
<div className={cx(props.kcInputWrapperClass)}>
|
||||||
<input type="text" id="username" className={cx(kcProperties.kcInputClass)} name="username"
|
<input type="text" id="username" className={cx(props.kcInputClass)} name="username"
|
||||||
defaultValue={register.formData.username ?? ""} autoComplete="username" />
|
defaultValue={register.formData.username ?? ""} autoComplete="username" />
|
||||||
</div>
|
</div>
|
||||||
</div >
|
</div >
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
passwordRequired &&
|
passwordRequired &&
|
||||||
<>
|
<>
|
||||||
|
|
||||||
<div className={cx(kcProperties.kcFormGroupClass, messagesPerField.printIfExists("password", kcProperties.kcFormGroupErrorClass))}>
|
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("password", props.kcFormGroupErrorClass))}>
|
||||||
<div className={cx(kcProperties.kcLabelWrapperClass)}>
|
<div className={cx(props.kcLabelWrapperClass)}>
|
||||||
<label htmlFor="password" className={cx(kcProperties.kcLabelClass)}>{t("password")}</label>
|
<label htmlFor="password" className={cx(props.kcLabelClass)}>{t("password")}</label>
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(kcProperties.kcInputWrapperClass)}>
|
<div className={cx(props.kcInputWrapperClass)}>
|
||||||
<input type="password" id="password" className={cx(kcProperties.kcInputClass)} name="password" autoComplete="new-password" />
|
<input type="password" id="password" className={cx(props.kcInputClass)} name="password" autoComplete="new-password" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={cx(kcProperties.kcFormGroupClass, messagesPerField.printIfExists("password-confirm", kcProperties.kcFormGroupErrorClass))}>
|
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("password-confirm", props.kcFormGroupErrorClass))}>
|
||||||
<div className={cx(kcProperties.kcLabelWrapperClass)}>
|
<div className={cx(props.kcLabelWrapperClass)}>
|
||||||
<label htmlFor="password-confirm" className={cx(kcProperties.kcLabelClass)}>{t("passwordConfirm")}</label>
|
<label htmlFor="password-confirm" className={cx(props.kcLabelClass)}>{t("passwordConfirm")}</label>
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(kcProperties.kcInputWrapperClass)}>
|
<div className={cx(props.kcInputWrapperClass)}>
|
||||||
<input type="password" id="password-confirm" className={cx(kcProperties.kcInputClass)} name="password-confirm" />
|
<input type="password" id="password-confirm" className={cx(props.kcInputClass)} name="password-confirm" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@ -122,23 +105,20 @@ export const Register = memo((props: RegisterPageProps) => {
|
|||||||
{
|
{
|
||||||
recaptchaRequired &&
|
recaptchaRequired &&
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<div className={cx(kcProperties.kcInputWrapperClass)}>
|
<div className={cx(props.kcInputWrapperClass)}>
|
||||||
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey}></div>
|
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey}></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
|
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}>
|
||||||
|
<div className={cx(props.kcFormOptionsWrapperClass)}>
|
||||||
<div className={cx(kcProperties.kcFormGroupClass)}>
|
|
||||||
<div id="kc-form-options" className={cx(kcProperties.kcFormOptionsClass)}>
|
|
||||||
<div className={cx(kcProperties.kcFormOptionsWrapperClass)}>
|
|
||||||
<span><a href={url.loginUrl}>{t("backToLogin")}</a></span>
|
<span><a href={url.loginUrl}>{t("backToLogin")}</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="kc-form-buttons" className={cx(kcProperties.kcFormButtonsClass)}>
|
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}>
|
||||||
<input className={cx(kcProperties.kcButtonClass, kcProperties.kcButtonPrimaryClass, kcProperties.kcButtonBlockClass, kcProperties.kcButtonLargeClass)} type="submit"
|
<input className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonBlockClass, props.kcButtonLargeClass)} type="submit"
|
||||||
defaultValue={tStr("doRegister")} />
|
defaultValue={tStr("doRegister")} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -147,10 +127,3 @@ export const Register = memo((props: RegisterPageProps) => {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
|
|
||||||
|
|
||||||
|
@ -12,11 +12,9 @@ import { useCallbackFactory } from "powerhooks";
|
|||||||
import { appendHead } from "../tools/appendHead";
|
import { appendHead } from "../tools/appendHead";
|
||||||
import { join as pathJoin } from "path";
|
import { join as pathJoin } from "path";
|
||||||
import { useConstCallback } from "powerhooks";
|
import { useConstCallback } from "powerhooks";
|
||||||
import type { KcTemplateProperties } from "./KcProperties";
|
import type { KcTemplateProps } from "./KcProps";
|
||||||
import { defaultKcTemplateProperties } from "./KcProperties";
|
|
||||||
|
|
||||||
export type TemplateProps = {
|
export type TemplateProps = {
|
||||||
kcProperties: KcTemplateProperties;
|
|
||||||
displayInfo?: boolean;
|
displayInfo?: boolean;
|
||||||
displayMessage?: boolean;
|
displayMessage?: boolean;
|
||||||
displayRequiredFields?: boolean;
|
displayRequiredFields?: boolean;
|
||||||
@ -26,7 +24,7 @@ export type TemplateProps = {
|
|||||||
showUsernameNode?: ReactNode;
|
showUsernameNode?: ReactNode;
|
||||||
formNode: ReactNode;
|
formNode: ReactNode;
|
||||||
displayInfoNode?: ReactNode;
|
displayInfoNode?: ReactNode;
|
||||||
};
|
} & KcTemplateProps;
|
||||||
|
|
||||||
|
|
||||||
export const Template = memo((props: TemplateProps) => {
|
export const Template = memo((props: TemplateProps) => {
|
||||||
@ -37,7 +35,6 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
displayRequiredFields = false,
|
displayRequiredFields = false,
|
||||||
displayWide = false,
|
displayWide = false,
|
||||||
showAnotherWayIfPresent = true,
|
showAnotherWayIfPresent = true,
|
||||||
kcProperties = {},
|
|
||||||
headerNode,
|
headerNode,
|
||||||
showUsernameNode = null,
|
showUsernameNode = null,
|
||||||
formNode,
|
formNode,
|
||||||
@ -48,8 +45,6 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
|
|
||||||
const { t } = useKcTranslation();
|
const { t } = useKcTranslation();
|
||||||
|
|
||||||
Object.assign(kcProperties, defaultKcTemplateProperties);
|
|
||||||
|
|
||||||
const { kcLanguageTag, setKcLanguageTag } = useKcLanguageTag();
|
const { kcLanguageTag, setKcLanguageTag } = useKcLanguageTag();
|
||||||
|
|
||||||
const onChangeLanguageClickFactory = useCallbackFactory(
|
const onChangeLanguageClickFactory = useCallbackFactory(
|
||||||
@ -76,10 +71,12 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
|
|
||||||
let isUnmounted = false;
|
let isUnmounted = false;
|
||||||
|
|
||||||
|
const toArr= (x: string | readonly string[] | undefined )=> typeof x === "string" ? x.split(" ") : x ?? [];
|
||||||
|
|
||||||
Promise.all(
|
Promise.all(
|
||||||
[
|
[
|
||||||
...(kcProperties.stylesCommon ?? []).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)),
|
...toArr(props.stylesCommon).map(relativePath => pathJoin(url.resourcesCommonPath, relativePath)),
|
||||||
...(kcProperties.styles ?? []).map(relativePath => pathJoin(url.resourcesPath, relativePath))
|
...toArr(props.styles).map(relativePath => pathJoin(url.resourcesPath, relativePath))
|
||||||
].map(href => appendHead({
|
].map(href => appendHead({
|
||||||
"type": "css",
|
"type": "css",
|
||||||
href
|
href
|
||||||
@ -93,7 +90,7 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
kcProperties.scripts?.forEach(
|
toArr(props.scripts).forEach(
|
||||||
relativePath => appendHead({
|
relativePath => appendHead({
|
||||||
"type": "javascript",
|
"type": "javascript",
|
||||||
"src": pathJoin(url.resourcesPath, relativePath)
|
"src": pathJoin(url.resourcesPath, relativePath)
|
||||||
@ -102,7 +99,7 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
|
|
||||||
document.getElementsByTagName("html")[0]
|
document.getElementsByTagName("html")[0]
|
||||||
.classList
|
.classList
|
||||||
.add(cx(kcProperties.kcHtmlClass));
|
.add(cx(props.kcHtmlClass));
|
||||||
|
|
||||||
return () => { isUnmounted = true; };
|
return () => { isUnmounted = true; };
|
||||||
|
|
||||||
@ -113,16 +110,16 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx(kcProperties.kcLoginClass)}>
|
<div className={cx(props.kcLoginClass)}>
|
||||||
|
|
||||||
<div id="kc-header" className={cx(kcProperties.kcHeaderClass)}>
|
<div id="kc-header" className={cx(props.kcHeaderClass)}>
|
||||||
<div id="kc-header-wrapper" className={cx(kcProperties.kcHeaderWrapperClass)}>
|
<div id="kc-header-wrapper" className={cx(props.kcHeaderWrapperClass)}>
|
||||||
{t("loginTitleHtml", realm.displayNameHtml)}
|
{t("loginTitleHtml", realm.displayNameHtml)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={cx(kcProperties.kcFormCardClass, displayWide && kcProperties.kcFormCardAccountClass)}>
|
<div className={cx(props.kcFormCardClass, displayWide && props.kcFormCardAccountClass)}>
|
||||||
<header className={cx(kcProperties.kcFormHeaderClass)}>
|
<header className={cx(props.kcFormHeaderClass)}>
|
||||||
{
|
{
|
||||||
(
|
(
|
||||||
realm.internationalizationEnabled &&
|
realm.internationalizationEnabled &&
|
||||||
@ -130,7 +127,7 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
locale.supported.length > 1
|
locale.supported.length > 1
|
||||||
) &&
|
) &&
|
||||||
<div id="kc-locale">
|
<div id="kc-locale">
|
||||||
<div id="kc-locale-wrapper" className={cx(kcProperties.kcLocaleWrapperClass)}>
|
<div id="kc-locale-wrapper" className={cx(props.kcLocaleWrapperClass)}>
|
||||||
<div className="kc-dropdown" id="kc-locale-dropdown">
|
<div className="kc-dropdown" id="kc-locale-dropdown">
|
||||||
<a href="#" id="kc-current-locale-link">
|
<a href="#" id="kc-current-locale-link">
|
||||||
{getKcLanguageTagLabel(kcLanguageTag)}
|
{getKcLanguageTagLabel(kcLanguageTag)}
|
||||||
@ -164,8 +161,8 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
displayRequiredFields ?
|
displayRequiredFields ?
|
||||||
(
|
(
|
||||||
|
|
||||||
<div className={cx(kcProperties.kcContentWrapperClass)}>
|
<div className={cx(props.kcContentWrapperClass)}>
|
||||||
<div className={cx(kcProperties.kcLabelWrapperClass, "subtitle")}>
|
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
|
||||||
<span className="subtitle">
|
<span className="subtitle">
|
||||||
<span className="required">*</span>
|
<span className="required">*</span>
|
||||||
{t("requiredFields")}
|
{t("requiredFields")}
|
||||||
@ -185,18 +182,18 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
)
|
)
|
||||||
) : (
|
) : (
|
||||||
displayRequiredFields ? (
|
displayRequiredFields ? (
|
||||||
<div className={cx(kcProperties.kcContentWrapperClass)}>
|
<div className={cx(props.kcContentWrapperClass)}>
|
||||||
<div className={cx(kcProperties.kcLabelWrapperClass, "subtitle")}>
|
<div className={cx(props.kcLabelWrapperClass, "subtitle")}>
|
||||||
<span className="subtitle"><span className="required">*</span> {t("requiredFields")}</span>
|
<span className="subtitle"><span className="required">*</span> {t("requiredFields")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-10">
|
<div className="col-md-10">
|
||||||
{showUsernameNode}
|
{showUsernameNode}
|
||||||
<div className={cx(kcProperties.kcFormGroupClass)}>
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
<div id="kc-username">
|
<div id="kc-username">
|
||||||
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
|
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
|
||||||
<a id="reset-login" href={url.loginRestartFlowUrl}>
|
<a id="reset-login" href={url.loginRestartFlowUrl}>
|
||||||
<div className="kc-login-tooltip">
|
<div className="kc-login-tooltip">
|
||||||
<i className={cx(kcProperties.kcResetFlowIcon)}></i>
|
<i className={cx(props.kcResetFlowIcon)}></i>
|
||||||
<span className="kc-tooltip-text">{t("restartLoginTooltip")}</span>
|
<span className="kc-tooltip-text">{t("restartLoginTooltip")}</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@ -207,12 +204,12 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{showUsernameNode}
|
{showUsernameNode}
|
||||||
<div className={cx(kcProperties.kcFormGroupClass)}>
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
<div id="kc-username">
|
<div id="kc-username">
|
||||||
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
|
<label id="kc-attempted-username">{auth?.attemptedUsername}</label>
|
||||||
<a id="reset-login" href={url.loginRestartFlowUrl}>
|
<a id="reset-login" href={url.loginRestartFlowUrl}>
|
||||||
<div className="kc-login-tooltip">
|
<div className="kc-login-tooltip">
|
||||||
<i className={cx(kcProperties.kcResetFlowIcon)}></i>
|
<i className={cx(props.kcResetFlowIcon)}></i>
|
||||||
<span className="kc-tooltip-text">{t("restartLoginTooltip")}</span>
|
<span className="kc-tooltip-text">{t("restartLoginTooltip")}</span>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
@ -236,10 +233,10 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
)
|
)
|
||||||
) &&
|
) &&
|
||||||
<div className={cx("alert", `alert-${message.type}`)}>
|
<div className={cx("alert", `alert-${message.type}`)}>
|
||||||
{message.type === "success" && <span className={cx(kcProperties.kcFeedbackSuccessIcon)}></span>}
|
{message.type === "success" && <span className={cx(props.kcFeedbackSuccessIcon)}></span>}
|
||||||
{message.type === "warning" && <span className={cx(kcProperties.kcFeedbackWarningIcon)}></span>}
|
{message.type === "warning" && <span className={cx(props.kcFeedbackWarningIcon)}></span>}
|
||||||
{message.type === "error" && <span className={cx(kcProperties.kcFeedbackErrorIcon)}></span>}
|
{message.type === "error" && <span className={cx(props.kcFeedbackErrorIcon)}></span>}
|
||||||
{message.type === "info" && <span className={cx(kcProperties.kcFeedbackInfoIcon)}></span>}
|
{message.type === "info" && <span className={cx(props.kcFeedbackInfoIcon)}></span>}
|
||||||
<span className="kc-feedback-text">{message.summary}</span>
|
<span className="kc-feedback-text">{message.summary}</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@ -251,9 +248,9 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
showAnotherWayIfPresent
|
showAnotherWayIfPresent
|
||||||
) &&
|
) &&
|
||||||
|
|
||||||
<form id="kc-select-try-another-way-form" action={url.loginAction} method="post" className={cx(displayWide && kcProperties.kcContentWrapperClass)} >
|
<form id="kc-select-try-another-way-form" action={url.loginAction} method="post" className={cx(displayWide && props.kcContentWrapperClass)} >
|
||||||
<div className={cx(displayWide && [kcProperties.kcFormSocialAccountContentClass, kcProperties.kcFormSocialAccountClass])} >
|
<div className={cx(displayWide && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])} >
|
||||||
<div className={cx(kcProperties.kcFormGroupClass)}>
|
<div className={cx(props.kcFormGroupClass)}>
|
||||||
<input type="hidden" name="tryAnotherWay" value="on" />
|
<input type="hidden" name="tryAnotherWay" value="on" />
|
||||||
<a href="#" id="try-another-way" onClick={onTryAnotherWayClick}>{t("doTryAnotherWay")}</a>
|
<a href="#" id="try-another-way" onClick={onTryAnotherWayClick}>{t("doTryAnotherWay")}</a>
|
||||||
</div>
|
</div>
|
||||||
@ -263,8 +260,8 @@ export const Template = memo((props: TemplateProps) => {
|
|||||||
{
|
{
|
||||||
displayInfo &&
|
displayInfo &&
|
||||||
|
|
||||||
<div id="kc-info" className={cx(kcProperties.kcSignUpClass)}>
|
<div id="kc-info" className={cx(props.kcSignUpClass)}>
|
||||||
<div id="kc-info-wrapper" className={cx(kcProperties.kcInfoAreaWrapperClass)}>
|
<div id="kc-info-wrapper" className={cx(props.kcInfoAreaWrapperClass)}>
|
||||||
{displayInfoNode}
|
{displayInfoNode}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,7 +4,10 @@ export * from "./i18n/KcLanguageTag";
|
|||||||
export * from "./i18n/useKcLanguageTag";
|
export * from "./i18n/useKcLanguageTag";
|
||||||
export * from "./i18n/useKcTranslation";
|
export * from "./i18n/useKcTranslation";
|
||||||
|
|
||||||
export * from "./components/KcProperties";
|
export * from "./components/KcProps";
|
||||||
export * from "./components/Login";
|
export * from "./components/Login";
|
||||||
export * from "./components/Template";
|
export * from "./components/Template";
|
||||||
export * from "./components/KcApp";
|
export * from "./components/KcApp";
|
||||||
|
export * from "./components/Info";
|
||||||
|
|
||||||
|
export * from "./tools/assert";
|
@ -4,9 +4,18 @@ import type { generateFtlFilesCodeFactory } from "../bin/build-keycloak-theme/ge
|
|||||||
import { id } from "evt/tools/typeSafety/id";
|
import { id } from "evt/tools/typeSafety/id";
|
||||||
import type { KcLanguageTag } from "./i18n/KcLanguageTag";
|
import type { KcLanguageTag } from "./i18n/KcLanguageTag";
|
||||||
import { doExtends } from "evt/tools/typeSafety/doExtends";
|
import { doExtends } from "evt/tools/typeSafety/doExtends";
|
||||||
|
import type { MessageKey } from "./i18n/useKcTranslation";
|
||||||
|
|
||||||
export type KcContext = KcContext.Login | KcContext.Register;
|
type ExtractAfterStartingWith<Prefix extends string, StrEnum> =
|
||||||
|
StrEnum extends `${Prefix}${infer U}` ? U : never;
|
||||||
|
|
||||||
|
const x: "33" | "44" = null as any;;
|
||||||
|
|
||||||
|
const y: `foo.${typeof x}` = `foo.${x}` as const;
|
||||||
|
|
||||||
|
y;
|
||||||
|
|
||||||
|
export type KcContext = KcContext.Login | KcContext.Register | KcContext.Info;
|
||||||
export declare namespace KcContext {
|
export declare namespace KcContext {
|
||||||
|
|
||||||
export type Template = {
|
export type Template = {
|
||||||
@ -117,6 +126,18 @@ export declare namespace KcContext {
|
|||||||
recaptchaSiteKey?: string;
|
recaptchaSiteKey?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Info = Template & {
|
||||||
|
pageBasename: "info.ftl";
|
||||||
|
messageHeader?: string;
|
||||||
|
requiredActions?: ExtractAfterStartingWith<"requiredAction.",MessageKey>[];
|
||||||
|
skipLink: boolean;
|
||||||
|
pageRedirectUri?: string;
|
||||||
|
actionUri?: string;
|
||||||
|
client: {
|
||||||
|
baseUrl?: string;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
36
yarn.lock
36
yarn.lock
@ -177,9 +177,9 @@
|
|||||||
universal-user-agent "^6.0.0"
|
universal-user-agent "^6.0.0"
|
||||||
|
|
||||||
"@octokit/openapi-types@^5.3.0":
|
"@octokit/openapi-types@^5.3.0":
|
||||||
version "5.3.0"
|
version "5.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-5.3.0.tgz#29e3faa119da90082dc653ea74c8bb345d197bf7"
|
resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-5.3.1.tgz#a49d119a1b9e47b7a9f5133ab14be2d8afaa183d"
|
||||||
integrity sha512-5q2qBz4iZ0xS/DEJ0ROusFbN4cVlbJE9GvOByen+mv7artuGXfVhONqcuRd7jYN2glTmCnzcZw+X6LrjRVqs0A==
|
integrity sha512-TvVk2QuIA0lQZcIMd6xbdGaGDVeNYIOa3l1ZVagAIk5K3t/WMYbcg4BISNDhzdVhm/TgQB26frAgd/GV81aHJA==
|
||||||
|
|
||||||
"@octokit/plugin-paginate-rest@^2.6.2":
|
"@octokit/plugin-paginate-rest@^2.6.2":
|
||||||
version "2.11.0"
|
version "2.11.0"
|
||||||
@ -193,10 +193,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz#70a62be213e1edc04bb8897ee48c311482f9700d"
|
resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz#70a62be213e1edc04bb8897ee48c311482f9700d"
|
||||||
integrity sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==
|
integrity sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==
|
||||||
|
|
||||||
"@octokit/plugin-rest-endpoint-methods@4.13.3":
|
"@octokit/plugin-rest-endpoint-methods@4.13.4":
|
||||||
version "4.13.3"
|
version "4.13.4"
|
||||||
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.13.3.tgz#17ba3a24adce0933129cfefa6d44e7da2eeac04b"
|
resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-4.13.4.tgz#093b130d558760f6bc912c6f622ce502522410af"
|
||||||
integrity sha512-nMGS2osFcWXRfHkDR0d+lB1zpMPTZJ0NjysPUfs7BT5/juNG/Q0+5UB6nC1f62jPzun154qekzwOb7Q5oahCXQ==
|
integrity sha512-MGxptzVfiP8O+aydC/riheYzS/yJ9P16M29OuvtZep/sF5sKuOCQP8Wf83YCKXRsQF+ZpYfke2snbPPSIMZKzg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@octokit/types" "^6.12.0"
|
"@octokit/types" "^6.12.0"
|
||||||
deprecation "^2.3.1"
|
deprecation "^2.3.1"
|
||||||
@ -225,14 +225,14 @@
|
|||||||
universal-user-agent "^6.0.0"
|
universal-user-agent "^6.0.0"
|
||||||
|
|
||||||
"@octokit/rest@^18.0.0":
|
"@octokit/rest@^18.0.0":
|
||||||
version "18.3.3"
|
version "18.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.3.3.tgz#a3b0f24bf5c42cacd93dbc48576b5d4d4e032a38"
|
resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.3.4.tgz#8e7ab02cd509e2fe7e71917a54254a8f8b827f20"
|
||||||
integrity sha512-OxElwBanZn1AShCaIrRTLM9PwhGE5/busMke/go30OWAQ+eJMD7Us/67mtapE77EYY4FM2tvb4Eg25rZaA/NPA==
|
integrity sha512-NES0pHbwyFB1D0jrLkdnIXgEmze/gLE0JoSNgfAe4vwD77/qaQGO/lRWNuPPsoBVBjiW6mmA9CU5cYHujJTKQA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@octokit/core" "^3.2.3"
|
"@octokit/core" "^3.2.3"
|
||||||
"@octokit/plugin-paginate-rest" "^2.6.2"
|
"@octokit/plugin-paginate-rest" "^2.6.2"
|
||||||
"@octokit/plugin-request-log" "^1.0.2"
|
"@octokit/plugin-request-log" "^1.0.2"
|
||||||
"@octokit/plugin-rest-endpoint-methods" "4.13.3"
|
"@octokit/plugin-rest-endpoint-methods" "4.13.4"
|
||||||
|
|
||||||
"@octokit/types@^6.0.3", "@octokit/types@^6.11.0", "@octokit/types@^6.12.0", "@octokit/types@^6.7.1":
|
"@octokit/types@^6.0.3", "@octokit/types@^6.11.0", "@octokit/types@^6.12.0", "@octokit/types@^6.7.1":
|
||||||
version "6.12.0"
|
version "6.12.0"
|
||||||
@ -303,9 +303,9 @@ balanced-match@^1.0.0:
|
|||||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||||
|
|
||||||
before-after-hook@^2.1.0:
|
before-after-hook@^2.1.0:
|
||||||
version "2.1.1"
|
version "2.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.1.tgz#99ae36992b5cfab4a83f6bee74ab27835f28f405"
|
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.0.tgz#09c40d92e936c64777aa385c4e9b904f8147eaf0"
|
||||||
integrity sha512-5ekuQOvO04MDj7kYZJaMab2S8SPjGJbotVNyv7QYFCOAwrGZs/YnoDNlh1U+m5hl7H2D/+n0taaAV/tfyd3KMA==
|
integrity sha512-jH6rKQIfroBbhEXVmI7XmXe3ix5S/PgJqpzdDPnR8JGLHWNYLsYZ6tK5iWOF/Ra3oqEX0NobXGlzbiylIzVphQ==
|
||||||
|
|
||||||
boolbase@^1.0.0:
|
boolbase@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
@ -1112,10 +1112,10 @@ to-fast-properties@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||||
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
|
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
|
||||||
|
|
||||||
tss-react@^0.0.9:
|
tss-react@^0.0.11:
|
||||||
version "0.0.9"
|
version "0.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-0.0.9.tgz#4f07be32ad8a9c7db2881236b80fd4715384fe92"
|
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-0.0.11.tgz#1cd061927744cd4fc9b7346e2fd1cfcf896a18d5"
|
||||||
integrity sha512-1Vo1UQrj18RaQIla/pes717iBzuYwVpQq/BdK/jREpm6kVS4HpoYXQlM0A0wp2ToG3kvFdop5STqowW3sviCfw==
|
integrity sha512-j8CDpHHIl6S6/mX+AmK08v7waPqwgNA7urHOD3qknCgbY79LRlS7he5DF4NUNE/5B4/Btc3F25w+KqgChNbyGw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@emotion/css" "^11.1.3"
|
"@emotion/css" "^11.1.3"
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user