2023-03-17 20:40:29 +01:00
|
|
|
import { assert } from "keycloakify/tools/assert";
|
|
|
|
import { clsx } from "keycloakify/tools/clsx";
|
2023-03-20 05:14:25 +01:00
|
|
|
import { usePrepareTemplate } from "keycloakify/lib/usePrepareTemplate";
|
2023-03-21 05:27:31 +01:00
|
|
|
import { type TemplateProps } from "keycloakify/login/TemplateProps";
|
|
|
|
import { useGetClassName } from "keycloakify/login/lib/useGetClassName";
|
2023-03-19 14:48:01 +01:00
|
|
|
import type { KcContext } from "./kcContext";
|
2023-03-18 18:54:33 +01:00
|
|
|
import type { I18n } from "./i18n";
|
2023-03-17 20:40:29 +01:00
|
|
|
|
|
|
|
export default function Template(props: TemplateProps<KcContext, I18n>) {
|
2023-02-25 18:11:23 +01:00
|
|
|
const {
|
|
|
|
displayInfo = false,
|
|
|
|
displayMessage = true,
|
|
|
|
displayRequiredFields = false,
|
|
|
|
headerNode,
|
|
|
|
showUsernameNode = null,
|
2024-04-13 03:26:15 +02:00
|
|
|
socialProvidersNode = null,
|
2023-02-25 18:11:23 +01:00
|
|
|
infoNode = null,
|
|
|
|
kcContext,
|
|
|
|
i18n,
|
2023-03-17 20:40:29 +01:00
|
|
|
doUseDefaultCss,
|
2023-03-21 02:36:13 +01:00
|
|
|
classes,
|
|
|
|
children
|
2023-02-25 18:11:23 +01:00
|
|
|
} = props;
|
|
|
|
|
2023-03-21 05:27:31 +01:00
|
|
|
const { getClassName } = useGetClassName({ doUseDefaultCss, classes });
|
2023-03-17 20:40:29 +01:00
|
|
|
|
2024-04-13 03:26:15 +02:00
|
|
|
const { msg, msgStr, changeLocale, labelBySupportedLanguageTag, currentLanguageTag } = i18n;
|
2023-02-25 18:11:23 +01:00
|
|
|
|
2024-04-13 01:26:41 +02:00
|
|
|
const { realm, locale, auth, url, message, isAppInitiatedAction, authenticationSession } = kcContext;
|
2023-02-25 18:11:23 +01:00
|
|
|
|
2023-02-27 10:39:22 +01:00
|
|
|
const { isReady } = usePrepareTemplate({
|
2024-04-13 01:26:41 +02:00
|
|
|
"styles": !doUseDefaultCss
|
|
|
|
? []
|
|
|
|
: [
|
|
|
|
`${url.resourcesCommonPath}/node_modules/@patternfly/patternfly/patternfly.min.css`,
|
|
|
|
`${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly.min.css`,
|
|
|
|
`${url.resourcesCommonPath}/node_modules/patternfly/dist/css/patternfly-additions.min.css`,
|
|
|
|
`${url.resourcesCommonPath}/lib/pficon/pficon.css`,
|
|
|
|
`${url.resourcesPath}/css/login.css`
|
|
|
|
],
|
|
|
|
"scripts": [
|
|
|
|
{
|
|
|
|
"isModule": true,
|
|
|
|
"source": {
|
|
|
|
"type": "url",
|
|
|
|
"src": `${url.resourcesPath}/js/menu-button-links.js`
|
|
|
|
}
|
|
|
|
},
|
|
|
|
...(authenticationSession === undefined
|
|
|
|
? []
|
|
|
|
: [
|
|
|
|
{
|
|
|
|
"isModule": true,
|
|
|
|
"source": {
|
|
|
|
"type": "inline" as const,
|
|
|
|
"code": [
|
|
|
|
`import { checkCookiesAndSetTimer } from "${url.resourcesPath}/js/authChecker.js";`,
|
|
|
|
``,
|
|
|
|
`checkCookiesAndSetTimer(`,
|
|
|
|
` "${authenticationSession.authSessionId}",`,
|
|
|
|
` "${authenticationSession.tabId}",`,
|
|
|
|
` "${url.ssoLoginInOtherTabsUrl}"`,
|
|
|
|
`);`
|
|
|
|
].join("\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
])
|
2023-03-17 20:40:29 +01:00
|
|
|
],
|
2023-03-20 05:14:25 +01:00
|
|
|
"htmlClassName": getClassName("kcHtmlClass"),
|
2024-04-10 01:22:49 +02:00
|
|
|
"bodyClassName": getClassName("kcBodyClass"),
|
|
|
|
"htmlLangProperty": locale?.currentLanguageTag,
|
2024-04-30 12:07:35 +02:00
|
|
|
"documentTitle": msgStr("loginTitle", kcContext.realm.displayName)
|
2023-02-27 10:39:22 +01:00
|
|
|
});
|
2023-02-25 18:11:23 +01:00
|
|
|
|
2023-02-27 10:39:22 +01:00
|
|
|
if (!isReady) {
|
2023-02-25 18:11:23 +01:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (
|
2023-03-17 20:40:29 +01:00
|
|
|
<div className={getClassName("kcLoginClass")}>
|
|
|
|
<div id="kc-header" className={getClassName("kcHeaderClass")}>
|
|
|
|
<div id="kc-header-wrapper" className={getClassName("kcHeaderWrapperClass")}>
|
2023-02-25 18:11:23 +01:00
|
|
|
{msg("loginTitleHtml", realm.displayNameHtml)}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2024-04-13 03:26:15 +02:00
|
|
|
<div className={getClassName("kcFormCardClass")}>
|
2023-03-17 20:40:29 +01:00
|
|
|
<header className={getClassName("kcFormHeaderClass")}>
|
2023-02-25 18:11:23 +01:00
|
|
|
{realm.internationalizationEnabled && (assert(locale !== undefined), true) && locale.supported.length > 1 && (
|
2024-04-13 03:26:15 +02:00
|
|
|
<div className={getClassName("kcLocaleMainClass")} id="kc-locale">
|
2023-03-17 20:40:29 +01:00
|
|
|
<div id="kc-locale-wrapper" className={getClassName("kcLocaleWrapperClass")}>
|
2024-04-13 03:26:15 +02:00
|
|
|
<div id="kc-locale-dropdown" className={clsx("menu-button-links", getClassName("kcLocaleDropDownClass"))}>
|
2023-02-25 18:11:23 +01:00
|
|
|
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
|
|
|
<a href="#" id="kc-current-locale-link">
|
|
|
|
{labelBySupportedLanguageTag[currentLanguageTag]}
|
|
|
|
</a>
|
|
|
|
<ul>
|
|
|
|
{locale.supported.map(({ languageTag }) => (
|
|
|
|
<li key={languageTag} className="kc-dropdown-item">
|
|
|
|
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
2023-02-25 20:11:55 +01:00
|
|
|
<a href="#" onClick={() => changeLocale(languageTag)}>
|
2023-02-25 18:11:23 +01:00
|
|
|
{labelBySupportedLanguageTag[languageTag]}
|
|
|
|
</a>
|
|
|
|
</li>
|
|
|
|
))}
|
|
|
|
</ul>
|
2024-04-13 03:26:15 +02:00
|
|
|
|
|
|
|
<button
|
|
|
|
tabIndex={1}
|
|
|
|
id="kc-current-locale-link"
|
|
|
|
aria-label={msgStr("languages" as any)}
|
|
|
|
aria-haspopup={true}
|
|
|
|
aria-expanded={false}
|
|
|
|
aria-controls="language-switch1"
|
|
|
|
>
|
|
|
|
{labelBySupportedLanguageTag[currentLanguageTag]}
|
|
|
|
</button>
|
|
|
|
<ul
|
|
|
|
role="menu"
|
|
|
|
tabIndex={-1}
|
|
|
|
aria-labelledby="kc-current-locale-link"
|
|
|
|
aria-activedescendant=""
|
|
|
|
id="language-switch1"
|
|
|
|
className={getClassName("kcLocaleListClass")}
|
|
|
|
>
|
|
|
|
{locale.supported.map(({ languageTag }, i) => (
|
|
|
|
<li key={languageTag} className={getClassName("kcLocaleListItemClass")} role="none">
|
|
|
|
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
|
|
|
<a
|
|
|
|
role="menuitem"
|
|
|
|
id={`language-${i}`}
|
|
|
|
className={getClassName("kcLocaleItemClass")}
|
|
|
|
href="#"
|
|
|
|
onClick={() => changeLocale(languageTag)}
|
|
|
|
>
|
|
|
|
{labelBySupportedLanguageTag[languageTag]}
|
|
|
|
</a>
|
|
|
|
</li>
|
|
|
|
))}
|
|
|
|
</ul>
|
2023-02-25 18:11:23 +01:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
{!(auth !== undefined && auth.showUsername && !auth.showResetCredentials) ? (
|
|
|
|
displayRequiredFields ? (
|
2023-03-17 20:40:29 +01:00
|
|
|
<div className={getClassName("kcContentWrapperClass")}>
|
|
|
|
<div className={clsx(getClassName("kcLabelWrapperClass"), "subtitle")}>
|
2023-02-25 18:11:23 +01:00
|
|
|
<span className="subtitle">
|
|
|
|
<span className="required">*</span>
|
|
|
|
{msg("requiredFields")}
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
<div className="col-md-10">
|
|
|
|
<h1 id="kc-page-title">{headerNode}</h1>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<h1 id="kc-page-title">{headerNode}</h1>
|
|
|
|
)
|
|
|
|
) : displayRequiredFields ? (
|
2023-03-17 20:40:29 +01:00
|
|
|
<div className={getClassName("kcContentWrapperClass")}>
|
|
|
|
<div className={clsx(getClassName("kcLabelWrapperClass"), "subtitle")}>
|
2023-02-25 18:11:23 +01:00
|
|
|
<span className="subtitle">
|
|
|
|
<span className="required">*</span> {msg("requiredFields")}
|
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
<div className="col-md-10">
|
|
|
|
{showUsernameNode}
|
2024-04-13 03:26:15 +02:00
|
|
|
<div id="kc-username" className={getClassName("kcFormGroupClass")}>
|
|
|
|
<label id="kc-attempted-username">{auth.attemptedUsername}</label>
|
|
|
|
<a id="reset-login" href={url.loginRestartFlowUrl} aria-label={msgStr("restartLoginTooltip")}>
|
2023-02-25 18:11:23 +01:00
|
|
|
<div className="kc-login-tooltip">
|
2023-03-17 20:40:29 +01:00
|
|
|
<i className={getClassName("kcResetFlowIcon")}></i>
|
2023-02-25 18:11:23 +01:00
|
|
|
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
|
|
|
|
</div>
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
2024-04-13 03:26:15 +02:00
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<>
|
|
|
|
{showUsernameNode}
|
|
|
|
<div id="kc-username" className={getClassName("kcFormGroupClass")}>
|
|
|
|
<label id="kc-attempted-username">{auth.attemptedUsername}</label>
|
|
|
|
<a id="reset-login" href={url.loginRestartFlowUrl} aria-label={msgStr("restartLoginTooltip")}>
|
|
|
|
<div className="kc-login-tooltip">
|
|
|
|
<i className={getClassName("kcResetFlowIcon")}></i>
|
|
|
|
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
|
|
|
|
</div>
|
|
|
|
</a>
|
|
|
|
</div>
|
2023-02-25 18:11:23 +01:00
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</header>
|
|
|
|
<div id="kc-content">
|
|
|
|
<div id="kc-content-wrapper">
|
|
|
|
{/* App-initiated actions should not see warning messages about the need to complete the action during login. */}
|
|
|
|
{displayMessage && message !== undefined && (message.type !== "warning" || !isAppInitiatedAction) && (
|
2024-04-13 03:26:15 +02:00
|
|
|
<div
|
|
|
|
className={clsx(
|
|
|
|
`alert-${message.type}`,
|
|
|
|
getClassName("kcAlertClass"),
|
|
|
|
`pf-m-${message?.type === "error" ? "danger" : message.type}`
|
|
|
|
)}
|
|
|
|
>
|
|
|
|
<div className="pf-c-alert__icon">
|
|
|
|
{message.type === "success" && <span className={getClassName("kcFeedbackSuccessIcon")}></span>}
|
|
|
|
{message.type === "warning" && <span className={getClassName("kcFeedbackWarningIcon")}></span>}
|
|
|
|
{message.type === "error" && <span className={getClassName("kcFeedbackErrorIcon")}></span>}
|
|
|
|
{message.type === "info" && <span className={getClassName("kcFeedbackInfoIcon")}></span>}
|
|
|
|
</div>
|
2023-02-25 18:11:23 +01:00
|
|
|
<span
|
2024-04-13 03:26:15 +02:00
|
|
|
className={getClassName("kcAlertTitleClass")}
|
2023-02-25 18:11:23 +01:00
|
|
|
dangerouslySetInnerHTML={{
|
|
|
|
"__html": message.summary
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
)}
|
2023-03-21 02:36:13 +01:00
|
|
|
{children}
|
2024-04-13 03:26:15 +02:00
|
|
|
{auth !== undefined && auth.showTryAnotherWayLink && (
|
|
|
|
<form id="kc-select-try-another-way-form" action={url.loginAction} method="post">
|
|
|
|
<div className={getClassName("kcFormGroupClass")}>
|
2023-03-17 20:40:29 +01:00
|
|
|
<div className={getClassName("kcFormGroupClass")}>
|
2023-02-25 18:11:23 +01:00
|
|
|
<input type="hidden" name="tryAnotherWay" value="on" />
|
|
|
|
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
|
2023-02-25 20:11:55 +01:00
|
|
|
<a
|
|
|
|
href="#"
|
|
|
|
id="try-another-way"
|
|
|
|
onClick={() => {
|
|
|
|
document.forms["kc-select-try-another-way-form" as never].submit();
|
|
|
|
return false;
|
|
|
|
}}
|
|
|
|
>
|
2023-02-25 18:11:23 +01:00
|
|
|
{msg("doTryAnotherWay")}
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
)}
|
2024-04-13 03:26:15 +02:00
|
|
|
{socialProvidersNode}
|
2023-02-25 18:11:23 +01:00
|
|
|
{displayInfo && (
|
2023-03-17 20:40:29 +01:00
|
|
|
<div id="kc-info" className={getClassName("kcSignUpClass")}>
|
|
|
|
<div id="kc-info-wrapper" className={getClassName("kcInfoAreaWrapperClass")}>
|
2023-02-25 18:11:23 +01:00
|
|
|
{infoNode}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|