Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
ea3d8a5634 | |||
48aab2d92a | |||
00eab73954 | |||
5f6f8b12bd | |||
c2d4d6fd49 | |||
04b660ff9b | |||
c292d926be | |||
23b83ceef7 | |||
1324648db6 | |||
735bff3348 | |||
05a6aee782 | |||
c7349c2556 | |||
51f3d06752 | |||
31759d86ab | |||
7c6eed99d2 | |||
bc4b0ec17d | |||
f766348b87 | |||
82281303d0 | |||
1caa17beb0 | |||
1c4d346f9f |
29
CHANGELOG.md
29
CHANGELOG.md
@ -1,3 +1,32 @@
|
|||||||
|
## **5.7.0** (2022-07-07)
|
||||||
|
|
||||||
|
- Merge pull request #120 from revolunet/logout
|
||||||
|
|
||||||
|
feat: add logout-confirm
|
||||||
|
- fix: use kcMessages
|
||||||
|
- fix: add translations FR
|
||||||
|
- feat: add logout-confirm
|
||||||
|
|
||||||
|
### **5.6.5** (2022-07-06)
|
||||||
|
|
||||||
|
- Merge pull request #133 from bardius/fix/Issue-131-include-all-nested-folders-in-artifact-unzip
|
||||||
|
|
||||||
|
fix: Issue-131: include all nested folders in artifact unzip
|
||||||
|
- Merge pull request #132 from bardius/fix/Issue-130-fix-equality-detection-of-nested-ftl-object-properties
|
||||||
|
|
||||||
|
fix: Issue-130: fix equality detection of nested ftl object property …
|
||||||
|
- fix: Issue-131: include all nested folders in artifact unzip
|
||||||
|
- fix: Issue-130: fix equality detection of nested ftl object property paths
|
||||||
|
|
||||||
|
### **5.6.4** (2022-07-06)
|
||||||
|
|
||||||
|
- Fix login-register-email.ftl
|
||||||
|
- Update to Keycloak 18.0.2 for the test container
|
||||||
|
|
||||||
|
### **5.6.3** (2022-07-03)
|
||||||
|
|
||||||
|
- update powerhooks
|
||||||
|
|
||||||
### **5.6.2** (2022-07-03)
|
### **5.6.2** (2022-07-03)
|
||||||
|
|
||||||
- Update powerhooks and EVT
|
- Update powerhooks and EVT
|
||||||
|
@ -38,6 +38,14 @@
|
|||||||
|
|
||||||
# Changelog highlights
|
# Changelog highlights
|
||||||
|
|
||||||
|
## 5.7.0
|
||||||
|
|
||||||
|
- Feat `logout-confirm.ftl`. [PR](https://github.com/InseeFrLab/keycloakify/pull/120)
|
||||||
|
|
||||||
|
## 5.6.4
|
||||||
|
|
||||||
|
Fix `login-verify-email.ftl` page. [Before](https://user-images.githubusercontent.com/6702424/177436014-0bad22c4-5bfb-45bb-8fc9-dad65143cd0c.png) - [After](https://user-images.githubusercontent.com/6702424/177435797-ec5d7db3-84cf-49cb-8efc-3427a81f744e.png)
|
||||||
|
|
||||||
## v5.6.0
|
## v5.6.0
|
||||||
|
|
||||||
Add support for `login-config-totp.ftl` page [#127](https://github.com/InseeFrLab/keycloakify/pull/127).
|
Add support for `login-config-totp.ftl` page [#127](https://github.com/InseeFrLab/keycloakify/pull/127).
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "keycloakify",
|
"name": "keycloakify",
|
||||||
"version": "5.6.2",
|
"version": "5.7.0",
|
||||||
"description": "Keycloak theme generator for Reacts app",
|
"description": "Keycloak theme generator for Reacts app",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -81,7 +81,7 @@
|
|||||||
"memoizee": "^0.4.15",
|
"memoizee": "^0.4.15",
|
||||||
"minimal-polyfills": "^2.2.1",
|
"minimal-polyfills": "^2.2.1",
|
||||||
"path-browserify": "^1.0.1",
|
"path-browserify": "^1.0.1",
|
||||||
"powerhooks": "^0.20.2",
|
"powerhooks": "^0.20.3",
|
||||||
"react-markdown": "^5.0.3",
|
"react-markdown": "^5.0.3",
|
||||||
"scripting-tools": "^0.19.13",
|
"scripting-tools": "^0.19.13",
|
||||||
"tsafe": "^0.10.0",
|
"tsafe": "^0.10.0",
|
||||||
|
@ -91,8 +91,8 @@ export function main() {
|
|||||||
"cwd": keycloakThemeBuildingDirPath,
|
"cwd": keycloakThemeBuildingDirPath,
|
||||||
});
|
});
|
||||||
|
|
||||||
//We want, however to test in a container running the latest Keycloak version
|
//We want, however, to test in a container running the latest Keycloak version
|
||||||
const containerKeycloakVersion = "18.0.0";
|
const containerKeycloakVersion = "18.0.2";
|
||||||
|
|
||||||
generateStartKeycloakTestingContainer({
|
generateStartKeycloakTestingContainer({
|
||||||
keycloakThemeBuildingDirPath,
|
keycloakThemeBuildingDirPath,
|
||||||
|
@ -305,7 +305,7 @@ ${ftl_object_to_js_code_declaring_an_object(.data_model, [])?no_esc};
|
|||||||
</#function>
|
</#function>
|
||||||
<#function are_same_path path searchedPath>
|
<#function are_same_path path searchedPath>
|
||||||
|
|
||||||
<#if path?size != path?size>
|
<#if path?size != searchedPath?size>
|
||||||
<#return false>
|
<#return false>
|
||||||
</#if>
|
</#if>
|
||||||
|
|
||||||
|
@ -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];
|
||||||
|
@ -17,7 +17,7 @@ export function downloadAndUnzip(params: { url: string; destDirPath: string; pat
|
|||||||
|
|
||||||
execSync(`curl -L ${url} -o ${zipFilePath}`, { "cwd": tmpDirPath });
|
execSync(`curl -L ${url} -o ${zipFilePath}`, { "cwd": tmpDirPath });
|
||||||
|
|
||||||
execSync(`unzip ${zipFilePath}${pathOfDirToExtractInArchive === undefined ? "" : ` "${pathOfDirToExtractInArchive}/*"`}`, {
|
execSync(`unzip ${zipFilePath}${pathOfDirToExtractInArchive === undefined ? "" : ` "${pathOfDirToExtractInArchive}/**/*"`}`, {
|
||||||
"cwd": tmpDirPath,
|
"cwd": tmpDirPath,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -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 }} />;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -7,7 +7,7 @@ import { getMsg } from "../i18n";
|
|||||||
export const LoginVerifyEmail = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginVerifyEmail } & KcProps) => {
|
export const LoginVerifyEmail = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginVerifyEmail } & KcProps) => {
|
||||||
const { msg } = getMsg(kcContext);
|
const { msg } = getMsg(kcContext);
|
||||||
|
|
||||||
const { url } = kcContext;
|
const { url, user } = kcContext;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Template
|
<Template
|
||||||
@ -17,10 +17,12 @@ export const LoginVerifyEmail = memo(({ kcContext, ...props }: { kcContext: KcCo
|
|||||||
headerNode={msg("emailVerifyTitle")}
|
headerNode={msg("emailVerifyTitle")}
|
||||||
formNode={
|
formNode={
|
||||||
<>
|
<>
|
||||||
<p className="instruction">{msg("emailVerifyInstruction1")}</p>
|
<p className="instruction">{msg("emailVerifyInstruction1", user?.email)}</p>
|
||||||
<p className="instruction">
|
<p className="instruction">
|
||||||
{msg("emailVerifyInstruction2")}
|
{msg("emailVerifyInstruction2")}
|
||||||
|
<br />
|
||||||
<a href={url.loginAction}>{msg("doClickHere")}</a>
|
<a href={url.loginAction}>{msg("doClickHere")}</a>
|
||||||
|
|
||||||
{msg("emailVerifyInstruction3")}
|
{msg("emailVerifyInstruction3")}
|
||||||
</p>
|
</p>
|
||||||
</>
|
</>
|
||||||
|
61
src/lib/components/LogoutConfirm.tsx
Normal file
61
src/lib/components/LogoutConfirm.tsx
Normal 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>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
@ -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 = {
|
||||||
@ -179,6 +180,10 @@ export declare namespace KcContextBase {
|
|||||||
|
|
||||||
export type LoginVerifyEmail = Common & {
|
export type LoginVerifyEmail = Common & {
|
||||||
pageId: "login-verify-email.ftl";
|
pageId: "login-verify-email.ftl";
|
||||||
|
//NOTE: Optional because maybe it wasn't defined in older keycloak versions.
|
||||||
|
user?: {
|
||||||
|
email: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Terms = Common & {
|
export type Terms = Common & {
|
||||||
@ -252,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 = {
|
||||||
|
@ -337,6 +337,9 @@ export const kcContextMocks: KcContextBase[] = [
|
|||||||
id<KcContextBase.LoginVerifyEmail>({
|
id<KcContextBase.LoginVerifyEmail>({
|
||||||
...kcContextCommonMock,
|
...kcContextCommonMock,
|
||||||
"pageId": "login-verify-email.ftl",
|
"pageId": "login-verify-email.ftl",
|
||||||
|
"user": {
|
||||||
|
"email": "john.doe@gmail.com",
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
id<KcContextBase.Terms>({
|
id<KcContextBase.Terms>({
|
||||||
...kcContextCommonMock,
|
...kcContextCommonMock,
|
||||||
@ -408,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 },
|
||||||
|
}),
|
||||||
];
|
];
|
||||||
|
@ -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 */
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1420,10 +1420,10 @@ please-upgrade-node@^3.2.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
semver-compare "^1.0.0"
|
semver-compare "^1.0.0"
|
||||||
|
|
||||||
powerhooks@^0.20.2:
|
powerhooks@^0.20.3:
|
||||||
version "0.20.2"
|
version "0.20.3"
|
||||||
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-0.20.2.tgz#620936f9a2849489757a6409b6b31f6895f28eab"
|
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-0.20.3.tgz#0a2bb6ac3d6bae527df5889e107f76c7ccca8104"
|
||||||
integrity sha512-+gqFAHUms0CbvoXXIo/dWm2y2wrbHokU+JVj4V+L/OeKu+Pr9DgJLiVIND/ZmjBKciB3ZhP3SWRo/4qfvMCACw==
|
integrity sha512-SrcDdt+Lo+TGtJHRLyrWS6glN3bfjBZETU+LIWWD5ohvwR8ofBcMiPML/sqecPhF+9sRzAdOrimHcQSQxetvSg==
|
||||||
dependencies:
|
dependencies:
|
||||||
evt "2.0.0-beta.45"
|
evt "2.0.0-beta.45"
|
||||||
memoizee "^0.4.15"
|
memoizee "^0.4.15"
|
||||||
|
Reference in New Issue
Block a user