Compare commits

...

17 Commits

Author SHA1 Message Date
c059eff170 Update README 2022-09-06 19:14:39 +02:00
b4a22fc9dd Fix readme 2022-09-06 19:13:46 +02:00
6d1cbdc463 Bump version 2022-09-06 19:12:59 +02:00
2bfbba4daf Upgrade tss-react 2022-09-06 17:43:30 +02:00
21ffe82bde Bump version 2022-09-06 17:40:06 +02:00
8e6f597027 Fix bug with --external-assets 2022-09-06 17:39:47 +02:00
16c5065560 Bump version 2022-09-05 00:09:07 +02:00
c4b985f1a4 Fix replacers 2022-09-05 00:08:50 +02:00
042747c7d2 Bump version 2022-09-04 23:19:53 +02:00
e4a46f31de Make it allright not to provide validators object on mock data 2022-09-04 23:19:33 +02:00
6d9e62d2b4 Remove unessesary log 2022-09-04 21:48:46 +02:00
9caaa507b1 Bump version 2022-09-01 22:35:15 +02:00
5c7d3c5b44 lib target ES2017 instead of ES2020 2022-09-01 22:35:01 +02:00
8bac57d87a Bump version 2022-09-01 21:31:41 +02:00
b8d759cd63 Minor refactor for dryness 2022-09-01 21:31:27 +02:00
da72e3e5ac Bump version (changelog ignore) 2022-09-01 21:16:39 +02:00
2afd36fee0 Avoid fetching locale twitch (react 18 useEffect) 2022-09-01 21:16:25 +02:00
11 changed files with 66 additions and 56 deletions

View File

@ -3,11 +3,9 @@ on:
push: push:
branches: branches:
- main - main
- v6
pull_request: pull_request:
branches: branches:
- main - main
- v6
jobs: jobs:

View File

@ -2,7 +2,7 @@
<img src="https://user-images.githubusercontent.com/6702424/109387840-eba11f80-7903-11eb-9050-db1dad883f78.png"> <img src="https://user-images.githubusercontent.com/6702424/109387840-eba11f80-7903-11eb-9050-db1dad883f78.png">
</p> </p>
<p align="center"> <p align="center">
<i>🔏 Create Keycloak themes using React 🔏</i> <i>🔏 Create Keycloak themes using React 🔏</i>
<br> <br>
<br> <br>
<a href="https://github.com/garronej/keycloakify/actions"> <a href="https://github.com/garronej/keycloakify/actions">
@ -36,6 +36,10 @@
<img src="https://user-images.githubusercontent.com/6702424/110260457-a1c3d380-7fac-11eb-853a-80459b65626b.png"> <img src="https://user-images.githubusercontent.com/6702424/110260457-a1c3d380-7fac-11eb-853a-80459b65626b.png">
</p> </p>
> 🗣 V6 have been released 🎉
> [It features major improvements](/#600).
> Checkout [the migration guide](https://docs.keycloakify.dev/v5-to-v6).
# Changelog highlights # Changelog highlights
## 6.0.0 ## 6.0.0
@ -45,7 +49,7 @@
- Real i18n API. - Real i18n API.
- Actual documentation for build options. - Actual documentation for build options.
Checkout the migration guide. Checkout [the migration guide](https://docs.keycloakify.dev/v5-to-v6)
## 5.8.0 ## 5.8.0

View File

@ -1,6 +1,6 @@
{ {
"name": "keycloakify", "name": "keycloakify",
"version": "6.0.0-beta.8", "version": "6.0.0",
"description": "Keycloak theme generator for Reacts app", "description": "Keycloak theme generator for Reacts app",
"repository": { "repository": {
"type": "git", "type": "git",
@ -83,7 +83,7 @@
"react-markdown": "^5.0.3", "react-markdown": "^5.0.3",
"scripting-tools": "^0.19.13", "scripting-tools": "^0.19.13",
"tsafe": "^1.0.1", "tsafe": "^1.0.1",
"tss-react": "^4.0.0", "tss-react": "^4.1.1",
"zod": "^3.17.10" "zod": "^3.17.10"
} }
} }

View File

@ -41,10 +41,10 @@ export function replaceImportsFromStaticInJsCode(params: { jsCode: string; build
const { jsCode, buildOptions } = params; const { jsCode, buildOptions } = params;
const getReplaceArgs = (language: "js" | "css"): Parameters<typeof String.prototype.replace> => [ const getReplaceArgs = (language: "js" | "css"): Parameters<typeof String.prototype.replace> => [
new RegExp(`([a-zA-Z]+)\\.([a-zA-Z]+)=function\\(([a-zA-Z]+)\\){return"static\\/${language}\\/"`, "g"), new RegExp(`([a-zA-Z_]+)\\.([a-zA-Z]+)=function\\(([a-zA-Z]+)\\){return"static\\/${language}\\/"`, "g"),
(...[, n, u, e]) => ` (...[, n, u, e]) => `
${n}[(function(){ ${n}[(function(){
var pd= Object.getOwnPropertyDescriptor(n, "p"); var pd= Object.getOwnPropertyDescriptor(${n}, "p");
if( pd === undefined || pd.configurable ){ if( pd === undefined || pd.configurable ){
${ ${
buildOptions.isStandalone buildOptions.isStandalone
@ -57,7 +57,7 @@ export function replaceImportsFromStaticInJsCode(params: { jsCode: string; build
: ` : `
var p= ""; var p= "";
Object.defineProperty(${n}, "p", { Object.defineProperty(${n}, "p", {
get: function() { return ("${ftlValuesGlobalName}" in window ? "${buildOptions.urlOrigin}" : "") + p; }, get: function() { return "${ftlValuesGlobalName}" in window ? "${buildOptions.urlOrigin}" : p; },
set: function (value){ p = value;} set: function (value){ p = value;}
}); });
` `
@ -73,13 +73,13 @@ export function replaceImportsFromStaticInJsCode(params: { jsCode: string; build
.replace(/([a-zA-Z]+\.[a-zA-Z]+)\+"static\//g, (...[, group]) => .replace(/([a-zA-Z]+\.[a-zA-Z]+)\+"static\//g, (...[, group]) =>
buildOptions.isStandalone buildOptions.isStandalone
? `window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/` ? `window.${ftlValuesGlobalName}.url.resourcesPath + "/build/static/`
: `("${ftlValuesGlobalName}" in window ? "${buildOptions.urlOrigin}" : "") + ${group} + "static/` : `("${ftlValuesGlobalName}" in window ? "${buildOptions.urlOrigin}" : ${group}) + "static/`
) )
//TODO: Write a test case for this //TODO: Write a test case for this
.replace(/".chunk.css",([a-zA-Z])+=([a-zA-Z]+\.[a-zA-Z]+)\+([a-zA-Z]+),/, (...[, group1, group2, group3]) => .replace(/".chunk.css",([a-zA-Z])+=([a-zA-Z]+\.[a-zA-Z]+)\+([a-zA-Z]+),/, (...[, group1, group2, group3]) =>
buildOptions.isStandalone buildOptions.isStandalone
? `".chunk.css",${group1} = window.${ftlValuesGlobalName}.url.resourcesPath + "/build/" + ${group3},` ? `".chunk.css",${group1} = window.${ftlValuesGlobalName}.url.resourcesPath + "/build/" + ${group3},`
: `".chunk.css",${group1} = ("${ftlValuesGlobalName}" in window ? "${buildOptions.urlOrigin}" : "") + ${group2} + ${group3},` : `".chunk.css",${group1} = ("${ftlValuesGlobalName}" in window ? "${buildOptions.urlOrigin}" : ${group2}) + ${group3},`
); );
return { fixedJsCode }; return { fixedJsCode };

View File

@ -81,8 +81,6 @@ const testAppPaths = (() => {
.filter(exclude(undefined)); .filter(exclude(undefined));
})(); })();
console.log(testAppPaths);
if (testAppPaths.length === 0) { if (testAppPaths.length === 0) {
console.error("No test app to link into!"); console.error("No test app to link into!");
process.exit(-1); process.exit(-1);

View File

@ -21,7 +21,7 @@ const LoginIdpLinkEmail = lazy(() => import("./LoginIdpLinkEmail"));
const LoginConfigTotp = lazy(() => import("./LoginConfigTotp")); const LoginConfigTotp = lazy(() => import("./LoginConfigTotp"));
const LogoutConfirm = lazy(() => import("./LogoutConfirm")); const LogoutConfirm = lazy(() => import("./LogoutConfirm"));
const KcApp = memo(({ kcContext, i18n: userProvidedI18n, ...props }: { kcContext: KcContextBase; i18n?: I18n } & KcProps) => { const KcApp = memo(({ kcContext, i18n: userProvidedI18n, ...kcProps }: { kcContext: KcContextBase; i18n?: I18n } & KcProps) => {
const i18n = (function useClosure() { const i18n = (function useClosure() {
const i18n = useI18n({ const i18n = useI18n({
kcContext, kcContext,
@ -36,42 +36,44 @@ const KcApp = memo(({ kcContext, i18n: userProvidedI18n, ...props }: { kcContext
return null; return null;
} }
const props = { i18n, ...kcProps };
return ( return (
<Suspense> <Suspense>
{(() => { {(() => {
switch (kcContext.pageId) { switch (kcContext.pageId) {
case "login.ftl": case "login.ftl":
return <Login {...{ kcContext, i18n, ...props }} />; return <Login {...{ kcContext, ...props }} />;
case "register.ftl": case "register.ftl":
return <Register {...{ kcContext, i18n, ...props }} />; return <Register {...{ kcContext, ...props }} />;
case "register-user-profile.ftl": case "register-user-profile.ftl":
return <RegisterUserProfile {...{ kcContext, i18n, ...props }} />; return <RegisterUserProfile {...{ kcContext, ...props }} />;
case "info.ftl": case "info.ftl":
return <Info {...{ kcContext, i18n, ...props }} />; return <Info {...{ kcContext, ...props }} />;
case "error.ftl": case "error.ftl":
return <Error {...{ kcContext, i18n, ...props }} />; return <Error {...{ kcContext, ...props }} />;
case "login-reset-password.ftl": case "login-reset-password.ftl":
return <LoginResetPassword {...{ kcContext, i18n, ...props }} />; return <LoginResetPassword {...{ kcContext, ...props }} />;
case "login-verify-email.ftl": case "login-verify-email.ftl":
return <LoginVerifyEmail {...{ kcContext, i18n, ...props }} />; return <LoginVerifyEmail {...{ kcContext, ...props }} />;
case "terms.ftl": case "terms.ftl":
return <Terms {...{ kcContext, i18n, ...props }} />; return <Terms {...{ kcContext, ...props }} />;
case "login-otp.ftl": case "login-otp.ftl":
return <LoginOtp {...{ kcContext, i18n, ...props }} />; return <LoginOtp {...{ kcContext, ...props }} />;
case "login-update-password.ftl": case "login-update-password.ftl":
return <LoginUpdatePassword {...{ kcContext, i18n, ...props }} />; return <LoginUpdatePassword {...{ kcContext, ...props }} />;
case "login-update-profile.ftl": case "login-update-profile.ftl":
return <LoginUpdateProfile {...{ kcContext, i18n, ...props }} />; return <LoginUpdateProfile {...{ kcContext, ...props }} />;
case "login-idp-link-confirm.ftl": case "login-idp-link-confirm.ftl":
return <LoginIdpLinkConfirm {...{ kcContext, i18n, ...props }} />; return <LoginIdpLinkConfirm {...{ kcContext, ...props }} />;
case "login-idp-link-email.ftl": case "login-idp-link-email.ftl":
return <LoginIdpLinkEmail {...{ kcContext, i18n, ...props }} />; return <LoginIdpLinkEmail {...{ kcContext, ...props }} />;
case "login-page-expired.ftl": case "login-page-expired.ftl":
return <LoginPageExpired {...{ kcContext, i18n, ...props }} />; return <LoginPageExpired {...{ kcContext, ...props }} />;
case "login-config-totp.ftl": case "login-config-totp.ftl":
return <LoginConfigTotp {...{ kcContext, i18n, ...props }} />; return <LoginConfigTotp {...{ kcContext, ...props }} />;
case "logout-confirm.ftl": case "logout-confirm.ftl":
return <LogoutConfirm {...{ kcContext, i18n, ...props }} />; return <LogoutConfirm {...{ kcContext, ...props }} />;
} }
})()} })()}
</Suspense> </Suspense>

View File

@ -60,6 +60,8 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
].filter(exclude(undefined)); ].filter(exclude(undefined));
attributes.forEach(attribute => { attributes.forEach(attribute => {
console.log("====>", attribute);
const partialAttribute = partialAttributes.find(({ name }) => name === attribute.name); const partialAttribute = partialAttributes.find(({ name }) => name === attribute.name);
const augmentedAttribute: Attribute = {} as any; const augmentedAttribute: Attribute = {} as any;
@ -82,14 +84,16 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[augmentedAttribute.name] = augmentedAttribute; id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[augmentedAttribute.name] = augmentedAttribute;
}); });
partialAttributes.forEach(partialAttribute => { partialAttributes
const { name } = partialAttribute; .map(partialAttribute => ({ "validators": {}, ...partialAttribute }))
.forEach(partialAttribute => {
const { name } = partialAttribute;
assert(name !== undefined, "If you define a mock attribute it must have at least a name"); assert(name !== undefined, "If you define a mock attribute it must have at least a name");
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes.push(partialAttribute as any); id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes.push(partialAttribute as any);
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[name] = partialAttribute as any; id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[name] = partialAttribute as any;
}); });
} }
} }

View File

@ -1,6 +1,6 @@
import "minimal-polyfills/Object.fromEntries"; import "minimal-polyfills/Object.fromEntries";
//NOTE for later: https://github.com/remarkjs/react-markdown/blob/236182ecf30bd89c1e5a7652acaf8d0bf81e6170/src/renderers.js#L7-L35 //NOTE for later: https://github.com/remarkjs/react-markdown/blob/236182ecf30bd89c1e5a7652acaf8d0bf81e6170/src/renderers.js#L7-L35
import React, { useEffect, useState } from "react"; import React, { useEffect, useState, useRef } from "react";
import ReactMarkdown from "react-markdown"; import ReactMarkdown from "react-markdown";
import type baseMessages from "./generated_messages/18.0.1/login/en"; import type baseMessages from "./generated_messages/18.0.1/login/en";
import { assert } from "tsafe/assert"; import { assert } from "tsafe/assert";
@ -76,13 +76,17 @@ export function __unsafe_useI18n<ExtraMessageKey extends string = never>(params:
const [i18n, setI18n] = useState<I18n<ExtraMessageKey | MessageKeyBase> | undefined>(undefined); const [i18n, setI18n] = useState<I18n<ExtraMessageKey | MessageKeyBase> | undefined>(undefined);
const refHasStartedFetching = useRef(false);
useEffect(() => { useEffect(() => {
if (doSkip) { if (doSkip || refHasStartedFetching.current) {
return; return;
} }
let isMounted = true; let isMounted = true;
refHasStartedFetching.current = true;
(async () => { (async () => {
const { currentLanguageTag = fallbackLanguageTag } = kcContext.locale ?? {}; const { currentLanguageTag = fallbackLanguageTag } = kcContext.locale ?? {};

View File

@ -4,7 +4,7 @@
"outDir": "../../dist/lib", "outDir": "../../dist/lib",
"rootDir": ".", "rootDir": ".",
"module": "ES2020", "module": "ES2020",
"target": "ES2020", "target": "ES2017",
"lib": ["es2015", "DOM", "ES2019.Object"], "lib": ["es2015", "DOM", "ES2019.Object"],
"moduleResolution": "node", "moduleResolution": "node",
"jsx": "react", "jsx": "react",

View File

@ -19,7 +19,7 @@ import { assetIsSameCode } from "../tools/assertIsSameCode";
}[e] + ".chunk.js" }[e] + ".chunk.js"
} }
n.u=function(e){return"static/js/" + e + "." + { __webpack_require__.u=function(e){return"static/js/" + e + "." + {
147: "6c5cee76", 147: "6c5cee76",
787: "8da10fcf", 787: "8da10fcf",
922: "be170a73" 922: "be170a73"
@ -54,10 +54,10 @@ import { assetIsSameCode } from "../tools/assertIsSameCode";
}[e] + ".chunk.js" }[e] + ".chunk.js"
} }
n[(function (){ __webpack_require__[(function (){
var pd= Object.getOwnPropertyDescriptor(n, "p"); var pd= Object.getOwnPropertyDescriptor(__webpack_require__, "p");
if( pd === undefined || pd.configurable ){ if( pd === undefined || pd.configurable ){
Object.defineProperty(n, "p", { Object.defineProperty(__webpack_require__, "p", {
get: function() { return window.kcContext.url.resourcesPath; }, get: function() { return window.kcContext.url.resourcesPath; },
set: function (){} set: function (){}
}); });
@ -72,7 +72,7 @@ import { assetIsSameCode } from "../tools/assertIsSameCode";
} }
t[(function (){ t[(function (){
var pd= Object.getOwnPropertyDescriptor(n, "p"); var pd= Object.getOwnPropertyDescriptor(t, "p");
if( pd === undefined || pd.configurable ){ if( pd === undefined || pd.configurable ){
Object.defineProperty(t, "p", { Object.defineProperty(t, "p", {
get: function() { return window.kcContext.url.resourcesPath; }, get: function() { return window.kcContext.url.resourcesPath; },
@ -103,23 +103,23 @@ import { assetIsSameCode } from "../tools/assertIsSameCode";
const fixedJsCodeExpected = ` const fixedJsCodeExpected = `
function f() { function f() {
return ("kcContext" in window ? "https://demo-app.keycloakify.dev" : "") + a.p + "static/js/" + ({}[e] || e) + "." + { return ("kcContext" in window ? "https://demo-app.keycloakify.dev" : a.p) + "static/js/" + ({}[e] || e) + "." + {
3: "0664cdc0" 3: "0664cdc0"
}[e] + ".chunk.js" }[e] + ".chunk.js"
} }
function sameAsF() { function sameAsF() {
return ("kcContext" in window ? "https://demo-app.keycloakify.dev" : "") + a.p + "static/js/" + ({}[e] || e) + "." + { return ("kcContext" in window ? "https://demo-app.keycloakify.dev" : a.p) + "static/js/" + ({}[e] || e) + "." + {
3: "0664cdc0" 3: "0664cdc0"
}[e] + ".chunk.js" }[e] + ".chunk.js"
} }
n[(function (){ __webpack_require__[(function (){
var pd= Object.getOwnPropertyDescriptor(n, "p"); var pd= Object.getOwnPropertyDescriptor(__webpack_require__, "p");
if( pd === undefined || pd.configurable ){ if( pd === undefined || pd.configurable ){
var p= ""; var p= "";
Object.defineProperty(n, "p", { Object.defineProperty(__webpack_require__, "p", {
get: function() { return ("kcContext" in window ? "https://demo-app.keycloakify.dev" : "") + p; }, get: function() { return "kcContext" in window ? "https://demo-app.keycloakify.dev" : p; },
set: function (value){ p = value; } set: function (value){ p = value; }
}); });
} }
@ -133,11 +133,11 @@ import { assetIsSameCode } from "../tools/assertIsSameCode";
} }
t[(function (){ t[(function (){
var pd= Object.getOwnPropertyDescriptor(n, "p"); var pd= Object.getOwnPropertyDescriptor(t, "p");
if( pd === undefined || pd.configurable ){ if( pd === undefined || pd.configurable ){
var p= ""; var p= "";
Object.defineProperty(t, "p", { Object.defineProperty(t, "p", {
get: function() { return ("kcContext" in window ? "https://demo-app.keycloakify.dev" : "") + p; }, get: function() { return "kcContext" in window ? "https://demo-app.keycloakify.dev" : p; },
set: function (value){ p = value; } set: function (value){ p = value; }
}); });
} }

View File

@ -1733,10 +1733,10 @@ tslib@^2.1.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
tss-react@^4.0.0: tss-react@^4.1.1:
version "4.0.0" version "4.1.1"
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-4.0.0.tgz#cdd9d4c4ae24de04c13b9deff59b50fdf6ce10ae" resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-4.1.1.tgz#207220417e4b2f8eb26d8280ab9cdeb385063069"
integrity sha512-pPkOKWiWWPbKdQFnGGeHEgRceUwkjrv0eldVCAdBll3j6Y3Ys/xwqsnlWYwWOU3SMJygVRE/S4CsIYx6KPpOkA== integrity sha512-K1U2s/GGw+XycUjJGztJsLUhwm8KJWz5afL5WZU3SwMeQsA+gbETM6bSxVk2/DXBdw9uYLL9jkSYPAXh0tfYBw==
dependencies: dependencies:
"@emotion/cache" "*" "@emotion/cache" "*"
"@emotion/serialize" "*" "@emotion/serialize" "*"