Compare commits

...

26 Commits

Author SHA1 Message Date
918a80cfb6 Update changelog v0.3.22 2021-04-08 13:48:41 +00:00
ed7d5eabcb Bump version (changelog ignore) 2021-04-08 15:43:12 +02:00
2795109162 update powerhooks 2021-04-08 15:42:41 +02:00
966f277628 Support terms and condition 2021-04-08 15:41:40 +02:00
36d60411f9 Fix info.ftl 2021-04-08 12:54:29 +02:00
60fe33f3fd Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-08 12:20:14 +02:00
1df685df92 For useKcMessage we prefer returning callbacks with a changing references 2021-04-08 12:20:06 +02:00
7894d95ace Update changelog v0.3.21 2021-04-04 19:20:27 +00:00
a8b4493aa1 update yarn.lock (changelog ignore) 2021-04-04 21:17:35 +02:00
715a7399cf Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-04 21:12:39 +02:00
a1e59bae23 Update powerhooks 2021-04-04 21:12:30 +02:00
b0819314a1 Update changelog v0.3.20 2021-04-01 22:37:41 +00:00
0099442543 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-01 23:43:14 +02:00
66a0b07228 Bump version (changelog ignore) 2021-04-01 23:43:08 +02:00
85f9544754 Always catch freemarker errors 2021-04-01 23:42:31 +02:00
2f16a09ab8 Update changelog v0.3.19 2021-04-01 15:21:10 +00:00
183ae98c30 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-01 17:16:01 +02:00
ba15e63879 Bump version (changelog ignore) 2021-04-01 17:15:55 +02:00
654277feda Fix previous release 2021-04-01 17:15:28 +02:00
81279a5cc5 Update changelog v0.3.18 2021-04-01 15:04:08 +00:00
59f0a843b0 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-04-01 16:52:53 +02:00
c094f70171 Bump version (changelog ignore) 2021-04-01 16:51:50 +02:00
0858fe6319 Fix error.ftt, Adopt best effort strategy to convert ftl values into JS 2021-04-01 16:51:28 +02:00
5012ec0ccc Update changelog v0.3.17 2021-03-29 04:33:07 +00:00
990a24fab2 Merge branch 'main' of https://github.com/InseeFrLab/keycloakify into main 2021-03-29 06:27:19 +02:00
036b6bf82a Use push instead of replace in keycloak-js adapter to enable going back 2021-03-29 06:27:12 +02:00
24 changed files with 732 additions and 229 deletions

View File

@ -1,3 +1,30 @@
### **0.3.22** (2021-04-08)
- update powerhooks
- Support terms and condition
- Fix info.ftl
- For useKcMessage we prefer returning callbacks with a changing references
### **0.3.21** (2021-04-04)
- Update powerhooks
### **0.3.20** (2021-04-01)
- Always catch freemarker errors
### **0.3.19** (2021-04-01)
- Fix previous release
### **0.3.18** (2021-04-01)
- Fix error.ftt, Adopt best effort strategy to convert ftl values into JS
### **0.3.17** (2021-03-29)
- Use push instead of replace in keycloak-js adapter to enable going back
### **0.3.15** (2021-03-28)
- Remove all reference to --external-assets, broken feature

View File

@ -1,6 +1,6 @@
{
"name": "keycloakify",
"version": "0.3.15",
"version": "0.3.22",
"description": "Keycloak theme generator for Reacts app",
"repository": {
"type": "git",
@ -14,8 +14,7 @@
"grant-exec-perms": "node dist/bin/tools/grant-exec-perms.js",
"test": "node dist/test",
"copy-files": "copyfiles -u 1 src/**/*.ftl src/**/*.xml src/**/*.js dist/",
"generate-messages": "node dist/bin/generate-i18n-messages.js",
"watch": "tsc -w"
"generate-messages": "node dist/bin/generate-i18n-messages.js"
},
"bin": {
"build-keycloak-theme": "dist/bin/build-keycloak-theme/index.js",
@ -54,8 +53,8 @@
"evt": "2.0.0-beta.15",
"minimal-polyfills": "^2.1.6",
"path": "^0.12.7",
"powerhooks": "^0.0.27",
"powerhooks": "^0.0.36",
"scripting-tools": "^0.19.13",
"tss-react": "^0.0.11"
"tss-react": "^0.0.12"
}
}

View File

@ -0,0 +1,263 @@
<script>const _=
{
"url": {
"loginAction": (function (){
<#attempt>
return "${url.loginAction?no_esc}";
<#recover>
</#attempt>
})(),
"resourcesPath": (function (){
<#attempt>
return "${url.resourcesPath?no_esc}";
<#recover>
</#attempt>
})(),
"resourcesCommonPath": (function (){
<#attempt>
return "${url.resourcesCommonPath?no_esc}";
<#recover>
</#attempt>
})(),
"loginRestartFlowUrl": (function (){
<#attempt>
return "${url.loginRestartFlowUrl?no_esc}";
<#recover>
</#attempt>
})(),
"loginUrl": (function (){
<#attempt>
return "${url.loginUrl?no_esc}";
<#recover>
</#attempt>
})()
},
"realm": {
"displayName": (function (){
<#attempt>
return "${realm.displayName!''}" || undefined;
<#recover>
</#attempt>
})(),
"displayNameHtml": (function (){
<#attempt>
return "${realm.displayNameHtml!''}" || undefined;
<#recover>
</#attempt>
})(),
"internationalizationEnabled": (function (){
<#attempt>
return ${realm.internationalizationEnabled?c};
<#recover>
</#attempt>
})(),
"registrationEmailAsUsername": (function (){
<#attempt>
return ${realm.registrationEmailAsUsername?c};
<#recover>
</#attempt>
})()
},
"locale": (function (){
<#attempt>
<#if realm.internationalizationEnabled>
return {
"supported": (function(){
var out= [];
<#attempt>
<#list locale.supported as lng>
out.push({
"url": (function (){
<#attempt>
return "${lng.url?no_esc}";
<#recover>
</#attempt>
})(),
"label": (function (){
<#attempt>
return "${lng.label}";
<#recover>
</#attempt>
})(),
"languageTag": (function (){
<#attempt>
return "${lng.languageTag}";
<#recover>
</#attempt>
})()
});
</#list>
<#recover>
</#attempt>
return out;
})(),
"current": (function (){
<#attempt>
return "${locale.current}";
<#recover>
</#attempt>
})()
};
</#if>
<#recover>
</#attempt>
})(),
"auth": (function (){
<#attempt>
<#if auth?has_content>
var out= {
"showUsername": (function (){
<#attempt>
return ${auth.showUsername()?c};
<#recover>
</#attempt>
})(),
"showResetCredentials": (function (){
<#attempt>
return ${auth.showResetCredentials()?c};
<#recover>
</#attempt>
})(),
"showTryAnotherWayLink": (function(){
<#attempt>
return ${auth.showTryAnotherWayLink()?c};
<#recover>
</#attempt>
})()
};
<#attempt>
<#if auth.showUsername() && !auth.showResetCredentials()>
Object.assign(
out,
{
"attemptedUsername": (function (){
<#attempt>
return "${auth.attemptedUsername}";
<#recover>
</#attempt>
})()
}
);
</#if>
<#recover>
</#attempt>
return out;
</#if>
<#recover>
</#attempt>
})(),
"scripts": (function(){
var out = [];
<#attempt>
<#if scripts??>
<#attempt>
<#list scripts as script>
out.push((function (){
<#attempt>
return "${script}";
<#recover>
</#attempt>
})());
</#list>
<#recover>
</#attempt>
</#if>
<#recover>
</#attempt>
return out;
})(),
"message": (function (){
<#attempt>
<#if message?has_content>
return { 
"type": (function (){
<#attempt>
return "${message.type}";
<#recover>
</#attempt>
})(),
"summary": (function (){
<#attempt>
return String.htmlUnescape("${message.summary}");
<#recover>
</#attempt>
})()
};
</#if>
<#recover>
</#attempt>
})(),
"isAppInitiatedAction": (function (){
<#attempt>
<#if isAppInitiatedAction??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})()
}
</script>

View File

@ -2,13 +2,21 @@
{
"client": (function (){
<#attempt>
<#if client??>
return {
"baseUrl": "${(client.baseUrl!'')?no_esc}" || undefined
"baseUrl": (function (){
<#attempt>
return "${(client.baseUrl!'')?no_esc}" || undefined;
<#recover>
</#attempt>
})()
};
</#if>
return undefined;
<#recover>
</#attempt>
})()
}

View File

@ -10,7 +10,11 @@ import fs from "fs";
import { join as pathJoin } from "path";
import { objectKeys } from "evt/tools/typeSafety/objectKeys";
export const pageIds = ["login.ftl", "register.ftl", "info.ftl", "error.ftl", "login-reset-password.ftl", "login-verify-email.ftl"] as const;
export const pageIds = [
"login.ftl", "register.ftl", "info.ftl",
"error.ftl", "login-reset-password.ftl",
"login-verify-email.ftl", "terms.ftl"
] as const;
export type PageId = typeof pageIds[number];
@ -19,7 +23,7 @@ function loadAdjacentFile(fileBasename: string) {
.toString("utf8");
};
function loadFtlFile(ftlFileBasename: PageId | "template.ftl") {
function loadFtlFile(ftlFileBasename: PageId | "common.ftl") {
try {
return loadAdjacentFile(ftlFileBasename)
@ -91,7 +95,7 @@ export function generateFtlFilesCodeFactory(
//FTL is no valid html, we can't insert with cheerio, we put placeholder for injecting later.
const ftlCommonPlaceholders = {
'{ "x": "vIdLqMeOed9sdLdIdOxdK0d" }': loadFtlFile("template.ftl"),
'{ "x": "vIdLqMeOed9sdLdIdOxdK0d" }': loadFtlFile("common.ftl"),
'<!-- xIdLqMeOedErIdLsPdNdI9dSlxI -->':
[
'<#if scripts??>',

View File

@ -1,37 +1,82 @@
<script>const _=
{
"messageHeader": "${messageHeader!''}" || undefined,
"messageHeader": (function (){
<#attempt>
return "${messageHeader!''}" || undefined;
<#recover>
</#attempt>
})(),
"requiredActions": (function (){
<#attempt>
<#if requiredActions??>
var out =[];
<#attempt>
<#list requiredActions>
<#attempt>
<#items as reqActionItem>
out.push("${reqActionItem}");
</#items></b>
out.push((function (){
<#attempt>
return "${reqActionItem}";
<#recover>
</#attempt>
})());
</#items>
<#recover>
</#attempt>
</#list>
<#recover>
</#attempt>
return out;
<#else>
return undefined;
</#if>
<#recover>
</#attempt>
})(),
"skipLink": (function (){
<#attempt>
<#if skipLink??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})(),
"pageRedirectUri": "${(pageRedirectUri!'')?no_esc}" || undefined,
"actionUri": "${(actionUri!'')?no_esc}" || undefined,
"pageRedirectUri": (function (){
<#attempt>
return "${(pageRedirectUri!'')?no_esc}" || undefined;
<#recover>
</#attempt>
})(),
"actionUri": (function (){
<#attempt>
return "${(actionUri!'')?no_esc}" || undefined;
<#recover>
</#attempt>
})(),
"client": {
"baseUrl": "${(client.baseUrl!'')?no_esc}" || undefined
"baseUrl": (function(){
<#attempt>
return "${(client.baseUrl!'')?no_esc}" || undefined;
<#recover>
</#attempt>
})()
}
}
</script>

View File

@ -1,7 +1,14 @@
<script>const _=
{
"realm": {
"loginWithEmailAllowed": ${realm.loginWithEmailAllowed?c}
},
"loginWithEmailAllowed": (function (){
<#attempt>
return ${realm.loginWithEmailAllowed?c};
<#recover>
</#attempt>
})()
}
}
</script>

View File

@ -1,83 +1,160 @@
<script>const _=
{
"url": {
"loginResetCredentialsUrl": "${url.loginResetCredentialsUrl?no_esc}",
"registrationUrl": "${url.registrationUrl?no_esc}"
"loginResetCredentialsUrl": (function (){
<#attempt>
return "${url.loginResetCredentialsUrl?no_esc}";
<#recover>
</#attempt>
})(),
"registrationUrl": (function (){
<#attempt>
return "${url.registrationUrl?no_esc}";
<#recover>
</#attempt>
})()
},
"realm": {
"loginWithEmailAllowed": ${realm.loginWithEmailAllowed?c},
"rememberMe": ${realm.rememberMe?c},
"password": ${realm.password?c},
"resetPasswordAllowed": ${realm.resetPasswordAllowed?c},
"registrationAllowed": ${realm.registrationAllowed?c}
"loginWithEmailAllowed": (function(){
<#attempt>
return ${realm.loginWithEmailAllowed?c};
<#recover>
</#attempt>
})(),
"rememberMe": (function (){
<#attempt>
return ${realm.rememberMe?c};
<#recover>
</#attempt>
})(),
"password": (function (){
<#attempt>
return ${realm.password?c};
<#recover>
</#attempt>
})(),
"resetPasswordAllowed": (function (){
<#attempt>
return ${realm.resetPasswordAllowed?c};
<#recover>
</#attempt>
})(),
"registrationAllowed": (function (){
<#attempt>
return ${realm.registrationAllowed?c};
<#recover>
</#attempt>
})()
},
"auth": (function (){
<#attempt>
<#if auth?has_content>
var out= {
"selectedCredential": "${auth.selectedCredential!''}" || undefined
return {
"selectedCredential": (function (){
<#attempt>
return "${auth.selectedCredential!''}" || undefined;
<#recover>
</#attempt>
})()
};
return out;
</#if>
return undefined;
<#recover>
</#attempt>
})(),
"social": {
"displayInfo": ${social.displayInfo?c},
"displayInfo": (function (){
<#attempt>
return ${social.displayInfo?c};
<#recover>
</#attempt>
})(),
"providers": (()=>{
<#attempt>
<#if social.providers??>
var out= [];
<#attempt>
<#list social.providers as p>
out.push({
"loginUrl": "${p.loginUrl?no_esc}",
"alias": "${p.alias}",
"providerId": "${p.providerId}",
"displayName": "${p.displayName}"
"loginUrl": (function (){
<#attempt>
return "${p.loginUrl?no_esc}";
<#recover>
</#attempt>
})(),
"alias": (function (){
<#attempt>
return "${p.alias}";
<#recover>
</#attempt>
})(),
"providerId": (function (){
<#attempt>
return "${p.providerId}";
<#recover>
</#attempt>
})(),
"displayName": (function (){
<#attempt>
return "${p.displayName}";
<#recover>
</#attempt>
})()
});
</#list>
<#recover>
</#attempt>
return out;
</#if>
return undefined;
<#recover>
</#attempt>
})()
},
"usernameEditDisabled": (function () {
<#attempt>
<#if usernameEditDisabled??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})(),
"login": {
"username": "${login.username!''}" || undefined,
"username": (function (){
<#attempt>
return "${login.username!''}" || undefined;
<#recover>
</#attempt>
})(),
"rememberMe": (function (){
<#attempt>
<#if login.rememberMe??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})()
},
"registrationDisabled": (function (){
<#attempt>
<#if registrationDisabled??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})()
}
</script>

View File

@ -1,46 +1,152 @@
<script>const _=
{
"url": {
"registrationAction": "${url.registrationAction?no_esc}"
"registrationAction": (function (){
<#attempt>
return "${url.registrationAction?no_esc}";
<#recover>
</#attempt>
})()
},
"messagesPerField": {
"printIfExists": function (key, x) {
switch(key){
case "userLabel": "${messagesPerField.printIfExists('userLabel','1')}" ? x : undefined;
case "username": "${messagesPerField.printIfExists('username','1')}" ? x : undefined;
case "email": "${messagesPerField.printIfExists('email','1')}" ? x : undefined;
case "firstName": "${messagesPerField.printIfExists('firstName','1')}" ? x : undefined;
case "lastName": "${messagesPerField.printIfExists('lastName','1')}" ? x : undefined;
case "password": "${messagesPerField.printIfExists('password','1')}" ? x : undefined;
case "password-confirm": "${messagesPerField.printIfExists('password-confirm','1')}" ? x : undefined;
case "userLabel": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('userLabel','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "username": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('username','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "email": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('email','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "firstName": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('firstName','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "lastName": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('lastName','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "password": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('password','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
case "password-confirm": return (function (){
<#attempt>
return "${messagesPerField.printIfExists('password-confirm','1')}" ? x : undefined;
<#recover>
</#attempt>
})();
}
}
},
"register": {
"formData": {
"firstName": "${register.formData.firstName!''}" || undefined,
"displayName": "${register.formData.displayName!''}" || undefined,
"lastName": "${register.formData.lastName!''}" || undefined,
"email": "${register.formData.email!''}" || undefined,
"username": "${register.formData.username!''}" || undefined
"firstName": (function (){
<#attempt>
return "${register.formData.firstName!''}" || undefined;
<#recover>
</#attempt>
})(),
"displayName": (function (){
<#attempt>
return "${register.formData.displayName!''}" || undefined;
<#recover>
</#attempt>
})(),
"lastName": (function (){
<#attempt>
return "${register.formData.lastName!''}" || undefined;
<#recover>
</#attempt>
})(),
"email": (function(){
<#attempt>
return "${register.formData.email!''}" || undefined;
<#recover>
</#attempt>
})(),
"username": (function (){
<#attempt>
return "${register.formData.username!''}" || undefined;
<#recover>
</#attempt>
})()
}
},
"passwordRequired": (function (){
<#attempt>
<#if passwordRequired??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})(),
"recaptchaRequired": (function (){
<#attempt>
<#if passwordRequired??>
return true;
</#if>
<#recover>
</#attempt>
return false;
})(),
"recaptchaSiteKey": "${recaptchaSiteKey!''}" || undefined
"recaptchaSiteKey": (function (){
<#attempt>
return "${recaptchaSiteKey!''}" || undefined;
<#recover>
</#attempt>
})()
}
</script>

View File

@ -1,114 +0,0 @@
<script>const _=
{
"url": {
"loginAction": "${url.loginAction?no_esc}",
"resourcesPath": "${url.resourcesPath?no_esc}",
"resourcesCommonPath": "${url.resourcesCommonPath?no_esc}",
"loginRestartFlowUrl": "${url.loginRestartFlowUrl?no_esc}",
"loginUrl": "${url.loginUrl?no_esc}"
},
"realm": {
"displayName": "${realm.displayName!''}" || undefined,
"displayNameHtml": "${realm.displayNameHtml!''}" || undefined,
"internationalizationEnabled": ${realm.internationalizationEnabled?c},
"registrationEmailAsUsername": ${realm.registrationEmailAsUsername?c},
},
"locale": (function (){
<#if realm.internationalizationEnabled>
return {
"supported": (function(){
<#if realm.internationalizationEnabled>
var out= [];
<#list locale.supported as lng>
out.push({
"url": "${lng.url?no_esc}",
"label": "${lng.label}",
"languageTag": "${lng.languageTag}"
});
</#list>
return out;
</#if>
return undefined;
})(),
"current": "${locale.current}"
};
</#if>
return undefined;
})(),
"auth": (function (){
<#if auth?has_content>
var out= {
"showUsername": ${auth.showUsername()?c},
"showResetCredentials": ${auth.showResetCredentials()?c},
"showTryAnotherWayLink": ${auth.showTryAnotherWayLink()?c},
};
<#if auth.showUsername() && !auth.showResetCredentials()>
Object.assign(
out,
{
"attemptedUsername": "${auth.attemptedUsername}"
}
);
</#if>
return out;
</#if>
return undefined;
})(),
"scripts": (function(){
var out = [];
<#if scripts??>
<#list scripts as script>
out.push("${script}");
</#list>
</#if>
return out;
})(),
"message": (function (){
<#if message?has_content>
return { 
"type": "${message.type}",
"summary": String.htmlUnescape("${message.summary}")
};
</#if>
return undefined;
})(),
"isAppInitiatedAction": (function (){
<#if isAppInitiatedAction??>
return true;
</#if>
return false;
})()
}
</script>

View File

@ -65,7 +65,7 @@ Object.keys(record).forEach(pageType => {
'//PLEASE DO NOT EDIT MANUALLY',
'',
'/* spell-checker: disable */',
`export const messages= ${JSON.stringify(record[pageType], null, 2)} as const;`,
`export const messages= ${JSON.stringify(record[pageType], null, 2)};`,
'/* spell-checker: enable */'
].join("\n"), "utf8")
);

View File

@ -53,13 +53,13 @@ export const Info = memo(({ kcContext, ...props }: { kcContext: KcContext.Info;
{
!skipLink &&
pageRedirectUri !== undefined ?
<p><a href="${pageRedirectUri}">${(msg("backToApplication"))}</a></p>
<p><a href={pageRedirectUri}>{(msg("backToApplication"))}</a></p>
:
actionUri !== undefined ?
<p><a href="${actionUri}">${msg("proceedWithAction")}</a></p>
<p><a href={actionUri}>{msg("proceedWithAction")}</a></p>
:
client.baseUrl !== undefined &&
<p><a href="${client.baseUrl}">${msg("backToApplication")}</a></p>
<p><a href={client.baseUrl}>{msg("backToApplication")}</a></p>
}
</div>

View File

@ -8,6 +8,7 @@ import { Info } from "./Info";
import { Error } from "./Error";
import { LoginResetPassword } from "./LoginResetPassword";
import { LoginVerifyEmail } from "./LoginVerifyEmail";
import { Terms } from "./Terms";
export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContext; } & KcProps ) => {
switch (kcContext.pageId) {
@ -17,5 +18,6 @@ export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContext; } &
case "error.ftl": return <Error {...{ kcContext, ...props }} />;
case "login-reset-password.ftl": return <LoginResetPassword {...{ kcContext, ...props }} />;
case "login-verify-email.ftl": return <LoginVerifyEmail {...{ kcContext, ...props }} />;
case "terms.ftl": return <Terms {...{ kcContext, ...props }}/>;
}
});

View File

@ -25,7 +25,7 @@ export type TemplateProps = {
showUsernameNode?: ReactNode;
formNode: ReactNode;
infoNode?: ReactNode;
} & { kcContext: KcContext.Template; } & KcTemplateProps;
} & { kcContext: KcContext; } & KcTemplateProps;
export const Template = memo((props: TemplateProps) => {

View File

@ -0,0 +1,57 @@
import { memo } from "react";
import { Template } from "./Template";
import type { KcProps } from "./KcProps";
import type { KcContext } from "../KcContext";
import { useKcMessage } from "../i18n/useKcMessage";
import { cx } from "tss-react";
export const Terms = memo(({ kcContext, ...props }: { kcContext: KcContext.Terms; } & KcProps) => {
const { msg, msgStr } = useKcMessage();
const { url } = kcContext;
return (
<Template
{...{ kcContext, ...props }}
displayMessage={false}
headerNode={msg("termsTitle")}
formNode={
<>
<div id="kc-terms-text">
{msg("termsText")}
</div>
<form className="form-actions" action={url.loginAction} method="POST">
<input
className={cx(
props.kcButtonClass,
props.kcButtonClass,
props.kcButtonClass,
props.kcButtonPrimaryClass,
props.kcButtonLargeClass
)}
name="accept"
id="kc-accept"
type="submit"
value={msgStr("doAccept")}
/>
<input
className={cx(
props.kcButtonClass,
props.kcButtonDefaultClass,
props.kcButtonLargeClass
)}
name="cancel"
id="kc-decline"
type="submit"
value={msgStr("doDecline")}
/>
</form>
<div className="clearfix" />
</>
}
/>
);
});

View File

@ -3060,5 +3060,5 @@ export const messages= {
"locale_ru": "Русский",
"locale_zh-CN": "中文简体"
}
} as const;
};
/* spell-checker: enable */

View File

@ -240,5 +240,5 @@ export const messages= {
"pairwiseFailedToGetRedirectURIs": "无法从服务器获得重定向URL",
"pairwiseRedirectURIsMismatch": "客户端的重定向URI与服务器端获取的URI配置不匹配。"
}
} as const;
};
/* spell-checker: enable */

View File

@ -634,5 +634,5 @@ export const messages= {
"eventUpdateTotpBody": "您账户的OTP 配置在{0} 由 {1}更改. 如非本人操作,请联系管理员。",
"eventUpdateTotpBodyHtml": "<p>您账户的OTP 配置在{0} 由 {1}更改. 如非本人操作,请联系管理员。</p>"
}
} as const;
};
/* spell-checker: enable */

View File

@ -4360,5 +4360,5 @@ export const messages= {
"invalidParameterMessage": "无效的参数 : {0}",
"alreadyLoggedIn": "您已经登录"
}
} as const;
};
/* spell-checker: enable */

View File

@ -1,9 +1,10 @@
import { useCallback } from "react";
import { useKcLanguageTag } from "./useKcLanguageTag";
import { messages } from "./generated_messages/login";
import { useConstCallback } from "powerhooks";
import type { ReactNode } from "react";
import { id } from "evt/tools/typeSafety/id";
//@ts-ignore
import * as markdown from "markdown";
export type MessageKey = keyof typeof messages["en"];
@ -11,7 +12,7 @@ export function useKcMessage() {
const { kcLanguageTag } = useKcLanguageTag();
const msgStr = useConstCallback(
const msgStr = useCallback(
(key: MessageKey, ...args: (string | undefined)[]): string => {
let str: string = messages[kcLanguageTag as any as "en"][key] ?? messages["en"][key];
@ -28,14 +29,21 @@ export function useKcMessage() {
return str;
}
},
[kcLanguageTag]
);
const msg = useConstCallback(
id<(...args: Parameters<typeof msgStr>) => ReactNode>(
(key, ...args) =>
<span className={key} dangerouslySetInnerHTML={{ "__html": msgStr(key, ...args) }} />
)
const msg = useCallback<(...args: Parameters<typeof msgStr>) => ReactNode>(
(key, ...args) =>
<span
className={key}
dangerouslySetInnerHTML={{
"__html":
markdown.toHTML(msgStr(key, ...args))
}}
/>
,
[kcLanguageTag]
);
return { msg, msgStr };

View File

@ -10,12 +10,18 @@ import type { LanguageLabel } from "./i18n/KcLanguageTag";
type ExtractAfterStartingWith<Prefix extends string, StrEnum> =
StrEnum extends `${Prefix}${infer U}` ? U : never;
/** Take theses type definition with a grain of salt.
* Some values might be undefined on some pages.
* (ex: url.loginAction is undefined on error.ftl)
*/
export type KcContext =
KcContext.Login | KcContext.Register | KcContext.Info |
KcContext.Error | KcContext.LoginResetPassword | KcContext.LoginVerifyEmail;
KcContext.Error | KcContext.LoginResetPassword | KcContext.LoginVerifyEmail |
KcContext.Terms;
export declare namespace KcContext {
export type Template = {
export type Common = {
url: {
loginAction: string;
resourcesPath: string;
@ -27,7 +33,7 @@ export declare namespace KcContext {
displayName?: string;
displayNameHtml?: string;
internationalizationEnabled: boolean;
registrationEmailAsUsername: boolean; //<---
registrationEmailAsUsername: boolean;
};
/** Undefined if !realm.internationalizationEnabled */
locale?: {
@ -55,7 +61,7 @@ export declare namespace KcContext {
isAppInitiatedAction: boolean;
};
export type Login = Template & {
export type Login = Common & {
pageId: "login.ftl";
url: {
loginResetCredentialsUrl: string;
@ -88,7 +94,7 @@ export declare namespace KcContext {
};
};
export type Register = Template & {
export type Register = Common & {
pageId: "register.ftl";
url: {
registrationAction: string;
@ -120,7 +126,7 @@ export declare namespace KcContext {
recaptchaSiteKey?: string;
};
export type Info = Template & {
export type Info = Common & {
pageId: "info.ftl";
messageHeader?: string;
requiredActions?: ExtractAfterStartingWith<"requiredAction.", MessageKey>[];
@ -132,24 +138,28 @@ export declare namespace KcContext {
}
};
export type Error = Template & {
export type Error = Common & {
pageId: "error.ftl";
client?: {
baseUrl?: string;
}
};
export type LoginResetPassword = Template & {
export type LoginResetPassword = Common & {
pageId: "login-reset-password.ftl";
realm: {
loginWithEmailAllowed: boolean;
}
};
export type LoginVerifyEmail = Template & {
export type LoginVerifyEmail = Common & {
pageId: "login-verify-email.ftl";
};
export type Terms = Common & {
pageId: "terms.ftl";
};
}
doExtends<KcContext["pageId"], PageId>();

View File

@ -6,7 +6,7 @@ import { getKcLanguageTagLabel } from "../i18n/KcLanguageTag";
//NOTE: Aside because we want to be able to import them from node
import { resourcesCommonPath, resourcesPath } from "./urlResourcesPath";
export const kcTemplateContext: KcContext.Template = {
const kcCommonContext: KcContext.Common = {
"url": {
"loginAction": "#",
"resourcesPath": `${process.env["PUBLIC_URL"]}/${resourcesPath}`,
@ -111,7 +111,7 @@ export const kcTemplateContext: KcContext.Template = {
};
Object.defineProperty(
kcTemplateContext.locale!,
kcCommonContext.locale!,
"current",
{
"get": () => getKcLanguageTagLabel(getEvtKcLanguage().state),
@ -120,22 +120,22 @@ Object.defineProperty(
);
export const kcLoginContext: KcContext.Login = {
...kcTemplateContext,
...kcCommonContext,
"pageId": "login.ftl",
"url": {
...kcTemplateContext.url,
...kcCommonContext.url,
"loginResetCredentialsUrl": "/auth/realms/myrealm/login-actions/reset-credentials?client_id=account&tab_id=HoAx28ja4xg",
"registrationUrl": "/auth/realms/myrealm/login-actions/registration?client_id=account&tab_id=HoAx28ja4xg"
},
"realm": {
...kcTemplateContext.realm,
...kcCommonContext.realm,
"loginWithEmailAllowed": true,
"rememberMe": true,
"password": true,
"resetPasswordAllowed": true,
"registrationAllowed": true
},
"auth": kcTemplateContext.auth!,
"auth": kcCommonContext.auth!,
"social": {
"displayInfo": true
},
@ -147,7 +147,7 @@ export const kcLoginContext: KcContext.Login = {
};
export const kcRegisterContext: KcContext.Register = {
...kcTemplateContext,
...kcCommonContext,
"url": {
...kcLoginContext.url,
"registrationAction": "http://localhost:8080/auth/realms/myrealm/login-actions/registration?session_code=gwZdUeO7pbYpFTRxiIxRg_QtzMbtFTKrNu6XW_f8asM&execution=12146ce0-b139-4bbd-b25b-0eccfee6577e&client_id=account&tab_id=uS8lYfebLa0"
@ -166,7 +166,7 @@ export const kcRegisterContext: KcContext.Register = {
};
export const kcInfoContext: KcContext.Info ={
...kcTemplateContext,
...kcCommonContext,
"pageId": "info.ftl",
"messageHeader": "<Message header>",
"requiredActions": undefined,
@ -178,7 +178,7 @@ export const kcInfoContext: KcContext.Info ={
};
export const kcErrorContext: KcContext.Error = {
...kcTemplateContext,
...kcCommonContext,
"pageId": "error.ftl",
"client": {
"baseUrl": "#"
@ -186,16 +186,21 @@ export const kcErrorContext: KcContext.Error = {
};
export const kcLoginResetPasswordContext: KcContext.LoginResetPassword = {
...kcTemplateContext,
...kcCommonContext,
"pageId": "login-reset-password.ftl",
"realm":{
...kcTemplateContext.realm,
...kcCommonContext.realm,
"loginWithEmailAllowed": false
}
};
export const kcLoginVerifyEmailContext: KcContext.LoginVerifyEmail = {
...kcTemplateContext,
...kcCommonContext,
"pageId": "login-verify-email.ftl"
};
export const kcTermContext: KcContext.Terms = {
...kcCommonContext,
"pageId": "terms.ftl"
};

View File

@ -66,13 +66,12 @@ export function createKeycloakAdapter(
return {
"login": options => {
window.location.replace(
window.location.href=
transformUrlBeforeRedirect(
keycloakInstance.createLoginUrl(
options
)
)
);
);
return neverResolvingPromise;
},
"logout": options => {
@ -86,13 +85,13 @@ export function createKeycloakAdapter(
return neverResolvingPromise;
},
"register": options => {
window.location.replace(
window.location.href =
transformUrlBeforeRedirect(
keycloakInstance.createRegisterUrl(
options
)
)
);
);
return neverResolvingPromise;
},
"accountManagement": () => {

View File

@ -747,10 +747,10 @@ path@^0.12.7:
process "^0.11.1"
util "^0.10.3"
powerhooks@^0.0.27:
version "0.0.27"
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-0.0.27.tgz#e9dc29258860d2f6bf32b249d9cba07c6f53f393"
integrity sha512-ohayWhtIEdLqiC2th/GEhaRfOhqekFg2uFo0JZ8Dn7oTnAZybs618QJeq5ag9oy3lFVzl+kbROpVa8Ch5zrkaA==
powerhooks@^0.0.36:
version "0.0.36"
resolved "https://registry.yarnpkg.com/powerhooks/-/powerhooks-0.0.36.tgz#d973d339ad8ca7ce52ea9d288ebe8e138df7d769"
integrity sha512-0fEGKLfJmuFeEYDGsAlTuvGKKdqOH059xezosmYRoGurfC1bbUlaNJD+TuzOT5cTGURi88DCLcDnhk/2eLyCyA==
dependencies:
evt "2.0.0-beta.15"
memoizee "^0.4.15"
@ -927,10 +927,10 @@ to-fast-properties@^2.0.0:
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
tss-react@^0.0.11:
version "0.0.11"
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-0.0.11.tgz#1cd061927744cd4fc9b7346e2fd1cfcf896a18d5"
integrity sha512-j8CDpHHIl6S6/mX+AmK08v7waPqwgNA7urHOD3qknCgbY79LRlS7he5DF4NUNE/5B4/Btc3F25w+KqgChNbyGw==
tss-react@^0.0.12:
version "0.0.12"
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-0.0.12.tgz#6463617ae5e7f670742e48e497d8825d59e2a2e9"
integrity sha512-oHekukqdaE71uhHx4XEdHy6aMnDYhoHLWB94iy2Fy9X8btH2lJH1joPj0zS1q7+1Xy2TydkLEZsTq3ElVd7ZqA==
dependencies:
"@emotion/css" "^11.1.3"