Merge pull request #120 from revolunet/logout

feat: add logout-confirm
This commit is contained in:
Joseph Garrone
2022-07-07 13:40:17 +02:00
committed by GitHub
6 changed files with 100 additions and 3 deletions

View File

@ -5,6 +5,7 @@ import { join as pathJoin } from "path";
import { objectKeys } from "tsafe/objectKeys"; import { objectKeys } from "tsafe/objectKeys";
import { ftlValuesGlobalName } from "../ftlValuesGlobalName"; import { ftlValuesGlobalName } from "../ftlValuesGlobalName";
// https://github.com/keycloak/keycloak/blob/main/services/src/main/java/org/keycloak/forms/login/freemarker/Templates.java
export const pageIds = [ export const pageIds = [
"login.ftl", "login.ftl",
"register.ftl", "register.ftl",
@ -21,6 +22,7 @@ export const pageIds = [
"login-idp-link-email.ftl", "login-idp-link-email.ftl",
"login-page-expired.ftl", "login-page-expired.ftl",
"login-config-totp.ftl", "login-config-totp.ftl",
"logout-confirm.ftl",
] as const; ] as const;
export type PageId = typeof pageIds[number]; export type PageId = typeof pageIds[number];

View File

@ -16,6 +16,7 @@ import { LoginIdpLinkConfirm } from "./LoginIdpLinkConfirm";
import { LoginPageExpired } from "./LoginPageExpired"; import { LoginPageExpired } from "./LoginPageExpired";
import { LoginIdpLinkEmail } from "./LoginIdpLinkEmail"; import { LoginIdpLinkEmail } from "./LoginIdpLinkEmail";
import { LoginConfigTotp } from "./LoginConfigTotp"; import { LoginConfigTotp } from "./LoginConfigTotp";
import { LogoutConfirm } from "./LogoutConfirm";
export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContextBase } & KcProps) => { export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContextBase } & KcProps) => {
switch (kcContext.pageId) { switch (kcContext.pageId) {
@ -49,5 +50,7 @@ export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContextBase }
return <LoginPageExpired {...{ kcContext, ...props }} />; return <LoginPageExpired {...{ kcContext, ...props }} />;
case "login-config-totp.ftl": case "login-config-totp.ftl":
return <LoginConfigTotp {...{ kcContext, ...props }} />; return <LoginConfigTotp {...{ kcContext, ...props }} />;
case "logout-confirm.ftl":
return <LogoutConfirm {...{ kcContext, ...props }} />;
} }
}); });

View File

@ -0,0 +1,61 @@
import { memo } from "react";
import { useCssAndCx } from "tss-react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase";
import { getMsg } from "../i18n";
export const LogoutConfirm = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LogoutConfirm } & KcProps) => {
const { url, client, logoutConfirm } = kcContext;
const { cx } = useCssAndCx();
const { msg, msgStr } = getMsg(kcContext);
return (
<Template
{...{ kcContext, ...props }}
doFetchDefaultThemeResources={true}
displayMessage={false}
headerNode={msg("logoutConfirmTitle")}
formNode={
<>
<div id="kc-logout-confirm" className="content-area">
<p className="instruction">{msg("logoutConfirmHeader")}</p>
<form className="form-actions" action={url.logoutConfirmAction} method="POST">
<input type="hidden" name="session_code" value={logoutConfirm.code} />
<div className={cx(props.kcFormGroupClass)}>
<div id="kc-form-options">
<div className={cx(props.kcFormOptionsWrapperClass)}></div>
</div>
<div id="kc-form-buttons" className={cx(props.kcFormGroupClass)}>
<input
tabIndex={4}
className={cx(
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonBlockClass,
props.kcButtonLargeClass,
)}
name="confirmLogout"
id="kc-logout"
type="submit"
value={msgStr("doLogout")}
/>
</div>
</div>
</form>
<div id="kc-info-message">
{!logoutConfirm.skipLink && client.baseUrl && (
<p>
<a href={client.baseUrl} dangerouslySetInnerHTML={{ __html: msgStr("backToApplication") }} />
</p>
)}
</div>
</div>
</>
}
/>
);
});

View File

@ -25,7 +25,8 @@ export type KcContextBase =
| KcContextBase.LoginIdpLinkConfirm | KcContextBase.LoginIdpLinkConfirm
| KcContextBase.LoginIdpLinkEmail | KcContextBase.LoginIdpLinkEmail
| KcContextBase.LoginPageExpired | KcContextBase.LoginPageExpired
| KcContextBase.LoginConfigTotp; | KcContextBase.LoginConfigTotp
| KcContextBase.LogoutConfirm;
export declare namespace KcContextBase { export declare namespace KcContextBase {
export type Common = { export type Common = {
@ -256,6 +257,20 @@ export declare namespace KcContextBase {
otpCredentials: { id: string; userLabel: string }[]; otpCredentials: { id: string; userLabel: string }[];
}; };
}; };
export type LogoutConfirm = Common & {
pageId: "logout-confirm.ftl";
url: {
logoutConfirmAction: string;
};
client: {
baseUrl?: string;
};
logoutConfirm: {
code: string;
skipLink?: boolean;
};
};
} }
export type Attribute = { export type Attribute = {

View File

@ -411,4 +411,17 @@ export const kcContextMocks: KcContextBase[] = [
}, },
}, },
}), }),
id<KcContextBase.LogoutConfirm>({
...kcContextCommonMock,
"pageId": "logout-confirm.ftl",
"url": {
...kcContextCommonMock.url,
"logoutConfirmAction": "Continuer?",
},
"client": {
"clientId": "myApp",
"baseUrl": "#",
},
"logoutConfirm": { "code": "123", skipLink: false },
}),
]; ];

View File

@ -20,11 +20,14 @@ export const kcMessages = {
"fr": { "fr": {
...kcMessagesBase["fr"], ...kcMessagesBase["fr"],
/* spell-checker: disable */ /* spell-checker: disable */
"shouldBeEqual": "{0} doit être egale à {1}", "shouldBeEqual": "{0} doit être égal à {1}",
"shouldBeDifferent": "{0} doit être différent de {1}", "shouldBeDifferent": "{0} doit être différent de {1}",
"shouldMatchPattern": "Dois respecter le schéma: `/{0}/`", "shouldMatchPattern": "Dois respecter le schéma: `/{0}/`",
"mustBeAnInteger": "Doit être un nombre entiers", "mustBeAnInteger": "Doit être un nombre entier",
"notAValidOption": "N'est pas une option valide", "notAValidOption": "N'est pas une option valide",
"logoutConfirmTitle": "Déconnexion",
"logoutConfirmHeader": "Êtes-vous sûr(e) de vouloir vous déconnecter ?",
"doLogout": "Se déconnecter",
/* spell-checker: enable */ /* spell-checker: enable */
}, },
}; };