diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 368bd3cc..4435b228 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,7 +22,6 @@ jobs: PACKAGE_MANAGER=yarn fi $PACKAGE_MANAGER run format:check - test: runs-on: macos-10.15 needs: test_formatting @@ -33,7 +32,7 @@ jobs: steps: - name: Tell if project is using npm or yarn id: step1 - uses: garronej/github_actions_toolkit@v2.2 + uses: garronej/ts-ci@v1.1.3 with: action_name: tell_if_project_uses_npm_or_yarn - uses: actions/checkout@v2.3.4 @@ -51,28 +50,35 @@ jobs: npm test check_if_version_upgraded: name: Check if version upgrade - if: github.event_name == 'push' + # We run this only if it's a push on the default branch or if it's a PR from a + # branch (meaning not a PR from a fork). It would be more straightforward to test if secrets.NPM_TOKEN is + # defined but GitHub Action don't allow it yet. + if: | + github.event_name == 'push' || + github.event.pull_request.head.repo.owner.login == github.event.pull_request.base.repo.owner.login runs-on: ubuntu-latest needs: test outputs: from_version: ${{ steps.step1.outputs.from_version }} to_version: ${{ steps.step1.outputs.to_version }} - is_upgraded_version: ${{steps.step1.outputs.is_upgraded_version }} + is_upgraded_version: ${{ steps.step1.outputs.is_upgraded_version }} + is_release_beta: ${{steps.step1.outputs.is_release_beta }} steps: - - uses: garronej/github_actions_toolkit@v2.2 + - uses: garronej/ts-ci@v1.1.3 id: step1 with: action_name: is_package_json_version_upgraded + branch: ${{ github.head_ref || github.ref }} update_changelog: runs-on: ubuntu-latest needs: check_if_version_upgraded if: needs.check_if_version_upgraded.outputs.is_upgraded_version == 'true' steps: - - uses: garronej/github_actions_toolkit@v2.4 + - uses: garronej/ts-ci@v1.1.3 with: action_name: update_changelog - branch: ${{ github.ref }} + branch: ${{ github.head_ref || github.ref }} create_github_release: runs-on: ubuntu-latest @@ -80,9 +86,6 @@ jobs: - update_changelog - check_if_version_upgraded steps: - - uses: actions/checkout@v2 - with: - ref: ${{ github.ref }} - name: Build GitHub release body id: step1 run: | @@ -98,10 +101,10 @@ jobs: with: name: Release v${{ needs.check_if_version_upgraded.outputs.to_version }} tag_name: v${{ needs.check_if_version_upgraded.outputs.to_version }} - target_commitish: ${{ github.ref }} + target_commitish: ${{ github.head_ref || github.ref }} body: ${{ steps.step1.outputs.body }} draft: false - prerelease: false + prerelease: ${{ needs.check_if_version_upgraded.outputs.is_release_beta == 'true' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -138,7 +141,12 @@ jobs: echo "Can't publish on NPM, You must first create a secret called NPM_TOKEN that contains your NPM auth token. https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets" false fi - npm publish + EXTRA_ARGS="" + if [ "$IS_BETA" = "true" ]; then + EXTRA_ARGS="--tag beta" + fi + npm publish $EXTRA_ARGS env: NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} - VERSION: ${{ needs.check_if_version_upgraded.outputs.to_version }} \ No newline at end of file + VERSION: ${{ needs.check_if_version_upgraded.outputs.to_version }} + IS_BETA: ${{ needs.check_if_version_upgraded.outputs.is_release_beta }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d10b8b..643eb121 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,85 @@ +### **4.5.1** (2022-01-18) + +- fix previous version + +## **4.5.0** (2022-01-18) + +- Read public/CNAME for domain name in --externel-assets mode + +## **4.4.0** (2022-01-01) + +- Merge pull request #73 from lazToum/main + +(feature) added login-page-expired.ftl +- added login-page-expired.ftl +- Add update instruction for 4.3.0 + +## **4.3.0** (2021-12-27) + +- Merge pull request #72 from praiz/main + +feat(*): added login-update-password +- feat(*): added login-update-password + +### **4.2.21** (2021-12-27) + +- update dependencies + +### **4.2.19** (2021-12-21) + +- Merge pull request #70 from VBustamante/patch-1 +- Added realm name field to KcContext mocks object +- Merge pull request #69 from VBustamante/patch-1 + +Adding name field to realm in KcContext type +- Adding name field to realm in KcContext type + +### **4.2.18** (2021-12-17) + +- Improve css url() import (fix CRA 5) + +### **4.2.17** (2021-12-16) + +- Fix path.join polyfill + +### **4.2.16** (2021-12-16) + + + +### **4.2.15** (2021-12-16) + +- use custom polyfill for path.join (fix webpack 5 build) + +### **4.2.14** (2021-12-12) + +- Merge pull request #65 from InseeFrLab/doge_ftl_errors + +Prevent ftl errors in Keycloak log +- Encourage users to report errors in logs +- Fix ftl error related to url.loginAction in saml-post-form.ftl +- Ftl prevent error with updateProfileCtx +- Ftl prevent error with auth.attemptedUsername +- Fix ftl error as comment formatting +- Merge remote-tracking branch 'origin/main' into doge_ftl_errors +- Update README, remove all instruction about errors in logs +- Avoid error in Keycloak logs, fix long template loading time +- Add missing collon in README sample code + +Add miss ',' + +### **4.2.13** (2021-12-08) + +- Fix broken link about how to import fonts #62 +- Add a video to show how to test the theme in a local container + +### **4.2.12** (2021-12-08) + +- Update post build instructions + +### **4.2.11** (2021-12-07) + + + ### **4.2.10** (2021-11-12) - Export an exaustive list of KcLanguageTag diff --git a/README.md b/README.md index 57e0d08f..a6bdce4c 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,21 @@ ๐Ÿ” Create Keycloak themes using React ๐Ÿ”

- - - - - + + + + + + + + + + + + + + + @@ -20,10 +30,9 @@

-**NEW in v4** - -- Out of the box [frontend form validation](#user-profile-and-frontend-form-validation) ๐Ÿฅณ -- Improvements (and breaking changes in `import { useKcMessage } from "keycloakify"`. +> **New in v4.4.0**: Feature [`login-page-expired.ftl`](https://user-images.githubusercontent.com/6702424/147856832-38c042a7-9fc8-473f-9595-e00123095ca6.png). +> Every time a page is added it's a breaking change for non CSS-only theme. +> Change [this](https://github.com/garronej/keycloakify-demo-app/blob/812754109c61157741f4a0b222026deb1538a02d/src/KcApp/KcApp.tsx#L18) and [this](https://github.com/garronej/keycloakify-demo-app/blob/812754109c61157741f4a0b222026deb1538a02d/src/KcApp/KcApp.tsx#L39) to update. # Motivations @@ -71,12 +80,12 @@ If you already have a Keycloak custom theme, it can be easily ported to Keycloak - [GitHub Actions](#github-actions) - [Limitations](#limitations) - [`process.env.PUBLIC_URL` not supported.](#processenvpublic_url-not-supported) - - [`@font-face` importing fonts from theย `src/` dir](#font-face-importing-fonts-from-thesrc-dir) + - [`@font-face` importing fonts from the `src/` dir](#font-face-importing-fonts-from-the-src-dir) - [Example of setup that **won't** work](#example-of-setup-that-wont-work) - [Possible workarounds](#possible-workarounds) - [Implement context persistence (optional)](#implement-context-persistence-optional) - [Kickstart video](#kickstart-video) -- [About the errors related to `objectToJson` in Keycloak logs.](#about-the-errors-related-to-objecttojson-in-keycloak-logs) +- [FTL errors related to `ftl_object_to_js_code_declaring_an_object` in Keycloak logs.](#ftl-errors-related-to-ftl_object_to_js_code_declaring_an_object-in-keycloak-logs) - [Adding custom message (to `i18n/useKcMessage.tsx`)](#adding-custom-message-to-i18nusekcmessagetsx) - [Email domain whitelist](#email-domain-whitelist) - [Changelog highlights](#changelog-highlights) @@ -87,6 +96,8 @@ If you already have a Keycloak custom theme, it can be easily ported to Keycloak # Requirements +On Windows OS you'll have to use [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10). More info [here](https://github.com/InseeFrLab/keycloakify/issues/54%23issuecomment-984834217) + Tested with the following Keycloak versions: - [11.0.3](https://hub.docker.com/layers/jboss/keycloak/11.0.3/images/sha256-4438f1e51c1369371cb807dffa526e1208086b3ebb9cab009830a178de949782?context=explore) @@ -96,7 +107,7 @@ Tested with the following Keycloak versions: This tool will be maintained to stay compatible with Keycloak v11 and up, however, the default pages you will get (before you customize it) will always be the ones of Keycloak v11. -This tool assumes you are bundling your app with Webpack (tested with 4.44.2) . +This tool assumes you are bundling your app with Webpack (tested with the versions that ships with CRA v4.44.2 and v5.0.0) . It assumes there is a `build/` directory at the root of your react project directory containing a `index.html` file and a `build/static/` directory generated by webpack. For more information see [this issue](https://github.com/InseeFrLab/keycloakify/issues/5#issuecomment-832296432) @@ -104,9 +115,7 @@ For more information see [this issue](https://github.com/InseeFrLab/keycloakify/ **All this is defaults with [`create-react-app`](https://create-react-app.dev)** (tested with 4.0.3) - `mvn` ([Maven](https://maven.apache.org/)), `rm`, `mkdir`, `curl`, `unzip` are assumed to be available. -- `docker` must be up and running when running `yarn keycloak`. - -On Windows you'll have to use [WSL](https://docs.microsoft.com/en-us/windows/wsl/install-win10). +- `docker` must be up and running when running `start_keycloak_testing_container.sh` (Instructions provided after running `yarn keycloak`). ## My framework doesnโ€™t seem to be supported, what can I do? @@ -151,27 +160,23 @@ your index should look something like: `src/index.tsx` ```tsx -import {ย App } from ".//App"; -import { - KcApp, - defaultKcProps, - getKcContext -} from "keycloakify"; -import {ย css }ย from "tss-react/@emotion/css"; +import { App } from ".//App"; +import { KcApp, defaultKcProps, getKcContext } from "keycloakify"; +import { css } from "tss-react/@emotion/css"; const { kcContext } = getKcContext(); const myClassName = css({ "color": "red" }); reactDom.render( - - document.getElementById("root") + , + document.getElementById("root"), ); ``` @@ -212,8 +217,8 @@ reactDom.render(

-Example of a customization using only CSS: [here](https://github.com/InseeFrLab/onyxia-ui/blob/012639d62327a9a56be80c46e32c32c9497b82db/src/app/components/KcApp.tsx) -(the [index.tsx](https://github.com/InseeFrLab/onyxia-ui/blob/012639d62327a9a56be80c46e32c32c9497b82db/src/app/index.tsx#L89-L94) ) +Example of a customization using only CSS: [here](https://github.com/InseeFrLab/onyxia-web/blob/012639d62327a9a56be80c46e32c32c9497b82db/src/app/components/KcApp.tsx) +(the [index.tsx](https://github.com/InseeFrLab/onyxia-web/blob/012639d62327a9a56be80c46e32c32c9497b82db/src/app/index.tsx#L89-L94) ) and the result you can expect:

@@ -228,7 +233,7 @@ If you want to go beyond only customizing the CSS you can re-implement some of t pages or even add new ones. If you want to go this way checkout the demo setup provided [here](https://github.com/garronej/keycloakify-demo-app/tree/look_and_feel). -If you prefer a real life example you can checkout [onyxia-web's source](https://github.com/InseeFrLab/onyxia-web/tree/main/src/app/components/KcApp). +If you prefer a real life example you can checkout [onyxia-web's source](https://github.com/InseeFrLab/onyxia-web/tree/main/src/ui/components/KcApp). The web app is in production [here](https://datalab.sspcloud.fr). Main takeaways are: @@ -290,7 +295,7 @@ If you are specifically building a theme to integrate with an app or a website t to first browse unauthenticated before logging in, you will get a significant performance boost if you jump through those hoops: -- Provide the url of your app in the `homepage` field of package.json. [ex](https://github.com/garronej/keycloakify-demo-app/blob/7847cc70ef374ab26a6cc7953461cf25603e9a6d/package.json#L2) +- Provide the url of your app in the `homepage` field of package.json. [ex](https://github.com/garronej/keycloakify-demo-app/blob/7847cc70ef374ab26a6cc7953461cf25603e9a6d/package.json#L2) or in a `public/CNAME` file. [ex](https://github.com/garronej/keycloakify-demo-app/blob/main/public/CNAME). - Build the theme using `npx build-keycloak-theme --external-assets` [ex](https://github.com/garronej/keycloakify-demo-app/blob/7847cc70ef374ab26a6cc7953461cf25603e9a6d/.github/workflows/ci.yaml#L21) - Enable [long-term assets caching](https://create-react-app.dev/docs/production-build/#static-file-caching) on the server hosting your app. - Make sure not to build your app and the keycloak theme separately @@ -357,7 +362,7 @@ the building and publishing of the theme (the .jar file). You won't be able to [import things from your public directory **in your JavaScript code**](https://create-react-app.dev/docs/using-the-public-folder/#adding-assets-outside-of-the-module-system). (This isn't recommended anyway). -## `@font-face` importing fonts from theย `src/` dir +## `@font-face` importing fonts from the `src/` dir If you are building the theme with [--external-assets](#enable-loading-in-a-blink-of-a-eye-of-login-pages-) this limitation doesn't apply, you can import fonts however you see fit. @@ -373,7 +378,8 @@ this limitation doesn't apply, you can import fonts however you see fit. - If it is possible, use Google Fonts or any other font provider. - If you want to host your font recommended approach is to move your fonts into the `public` directory and to place your `@font-face` statements in the `public/index.html`. - Example [here](https://github.com/InseeFrLab/onyxia-ui/blob/0e3a04610cfe872ca71dad59e05ced8f785dee4b/public/index.html#L6-L51). + Example [here](https://github.com/garronej/keycloakify-demo-app/blob/9aa2dbaec28a7786d6b2983c9a59d393dec1b2d6/public/index.html#L27-L73) + (and the font are [here](https://github.com/garronej/keycloakify-demo-app/tree/main/public/fonts/WorkSans)). - You can also [use non relative url](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/src/fonts.scss#L16) but don't forget [`Access-Control-Allow-Origin`](https://github.com/garronej/keycloakify-demo-app/blob/2de8a9eb6f5de9c94f9cd3991faad0377e63268c/nginx.conf#L17-L19). # Implement context persistence (optional) @@ -433,33 +439,29 @@ keycloakInstance.init({ If you really want to go the extra miles and avoid having the white flash of the blank html before the js bundle have been evaluated -[here is a snippet](https://github.com/InseeFrLab/onyxia-ui/blob/a77eb502870cfe6878edd0d956c646d28746d053/public/index.html#L5-L54) that you can place in your `public/index.html` if you are using `powerhooks/useGlobalState`. +[here is a snippet](https://github.com/InseeFrLab/onyxia-web/blob/e1c1f309aaa3d5f860df39ba0b75cce89c88a9de/public/index.html#L117-L166) that you can place in your `public/index.html` if you are using `powerhooks/useGlobalState`. # Kickstart video _NOTE: keycloak-react-theming was renamed keycloakify since this video was recorded_ [![kickstart_video](https://user-images.githubusercontent.com/6702424/108877866-f146ee80-75ff-11eb-8120-003b3c5f6dd8.png)](https://youtu.be/xTz0Rj7i2v8) -# About the errors related to `objectToJson` in Keycloak logs. +# FTL errors related to `ftl_object_to_js_code_declaring_an_object` in Keycloak logs. -The logs of your keycloak server will always show this kind of errors every time a client request a page: +If you ever encounter one of these errors: ```log FTL stack trace ("~" means nesting-related): - - Failed at: #local value = object[key] [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 70, column 21] - - Reached through: @compress [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 36, column 5] - - Reached through: @objectToJson_please_ignore_errors object=value depth=(dep... [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 81, column 27] - - Reached through: @compress [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 36, column 5] - - Reached through: @objectToJson_please_ignore_errors object=(.data_model) de... [in template "login.ftl" at line 163, column 43] + - Failed at: #local value = object[key] [in template "login.ftl" in macro "ftl_object_to_js_code_declaring_an_object" at line 70, column 21] + - Reached through: @compress [in template "login.ftl" in macro "ftl_object_to_js_code_declaring_an_object" at line 36, column 5] + - Reached through: @ftl_object_to_js_code_declaring_an_object object=value depth=(dep... [in template "login.ftl" in macro "ftl_object_to_js_code_declaring_an_object" at line 81, column 27] + - Reached through: @compress [in template "login.ftl" in macro "ftl_object_to_js_code_declaring_an_object" at line 36, column 5] + - Reached through: @ftl_object_to_js_code_declaring_an_object object=(.data_model) de... [in template "login.ftl" at line 163, column 43] ``` -Theses are expected to show up in the log. -Unfortunately, there is nothing I know of that can be done to avoid them or even mute them. -They can be, however, safely ignored. - -To [converts the `.ftl` values into a JavaScript object](https://github.com/InseeFrLab/keycloakify/blob/main/src/bin/build-keycloak-theme/generateFtl/common.ftl) -without making assumptions on the `.data_model` we have to do things that throws. -It's all-right because every statement that can fail is inside an `<#attempt><#recorver>` block but it results in errors being printed to the logs. +It's just noise, they can be safely ignored. +You can, however, and are encouraged to, report any that you would spot. +Just open an issue about it and I will release a patched version of Keycloakify in the better delays. # Adding custom message (to `i18n/useKcMessage.tsx`) @@ -477,6 +479,10 @@ and `kcRegisterContext["authorizedMailDomains"]` to validate on. # Changelog highlights +> **New in v4.3.0**: Feature [`login-update-password.ftl`](https://user-images.githubusercontent.com/6702424/147517600-6191cf72-93dd-437b-a35c-47180142063e.png). +> Every time a page is added it's a breaking change for non CSS-only theme. +> Change [this](https://github.com/garronej/keycloakify-demo-app/blob/df664c13c77ce3c53ac7df0622d94d04e76d3f9f/src/KcApp/KcApp.tsx#L17) and [this](https://github.com/garronej/keycloakify-demo-app/blob/df664c13c77ce3c53ac7df0622d94d04e76d3f9f/src/KcApp/KcApp.tsx#L37) to update. + ## v4 - Out of the box [frontend form validation](#user-profile-and-frontend-form-validation) ๐Ÿฅณ diff --git a/package.json b/package.json index 31058b86..4a20108d 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "keycloakify", - "version": "4.2.10", + "version": "4.5.1", "description": "Keycloak theme generator for Reacts app", "repository": { "type": "git", @@ -58,7 +58,7 @@ "@emotion/react": "^11.4.1", "powerhooks": "^0.10.0", "react": "^16.8.0 || ^17.0.0", - "tss-react": "^1.1.0" + "tss-react": "^1.1.0 || ^3.0.0" }, "devDependencies": { "@emotion/react": "^11.4.1", @@ -72,16 +72,16 @@ "properties-parser": "^0.3.1", "react": "^17.0.1", "rimraf": "^3.0.2", - "tss-react": "^1.1.0", + "tss-react": "^3.0.0", "typescript": "^4.2.3" }, "dependencies": { "cheerio": "^1.0.0-rc.5", - "evt": "2.0.0-beta.38", + "evt": "2.0.0-beta.39", "minimal-polyfills": "^2.2.1", "path-browserify": "^1.0.1", "react-markdown": "^5.0.3", "scripting-tools": "^0.19.13", - "tsafe": "^0.8.1" + "tsafe": "^0.9.0" } } diff --git a/src/bin/build-keycloak-theme/build-keycloak-theme.ts b/src/bin/build-keycloak-theme/build-keycloak-theme.ts index dd599d2b..9ee8a052 100644 --- a/src/bin/build-keycloak-theme/build-keycloak-theme.ts +++ b/src/bin/build-keycloak-theme/build-keycloak-theme.ts @@ -4,6 +4,7 @@ import { join as pathJoin, relative as pathRelative, basename as pathBasename } import * as child_process from "child_process"; import { generateDebugFiles, containerLaunchScriptBasename } from "./generateDebugFiles"; import { URL } from "url"; +import * as fs from "fs"; type ParsedPackageJson = { name: string; @@ -41,7 +42,17 @@ export function main() { const url = (() => { const { homepage } = parsedPackageJson; - return homepage === undefined ? undefined : new URL(homepage); + if (homepage !== undefined) { + return new URL(homepage); + } + + const cnameFilePath = pathJoin(reactProjectDirPath, "public", "CNAME"); + + if (fs.existsSync(cnameFilePath)) { + return new URL(`https://${fs.readFileSync(cnameFilePath).toString("utf8").replace(/\s+$/, "")}`); + } + + return undefined; })(); return { @@ -121,11 +132,14 @@ export function main() { "", `๐Ÿ‘‰ $ ./${pathRelative(reactProjectDirPath, pathJoin(keycloakThemeBuildingDirPath, containerLaunchScriptBasename))} ๐Ÿ‘ˆ`, "", - 'To enable the theme within keycloak log into the admin console ( ๐Ÿ‘‰ http://localhost:8080 username: admin, password: admin ๐Ÿ‘ˆ), create a realm (called "myrealm" for example),', - `go to your realm settings, click on the theme tab then select ${themeName}.`, - `More details: https://www.keycloak.org/getting-started/getting-started-docker`, + "Once your container is up and running: ", + "- Log into the admin console ๐Ÿ‘‰ http://localhost:8080 username: admin, password: admin ๐Ÿ‘ˆ", + '- Create a realm named "myrealm"', + '- Create a client with id "myclient" and root url: "https://www.keycloak.org/app/"', + `- Select Login Theme: ${themeName} (don't forget to save at the bottom of the page)`, + `- Go to ๐Ÿ‘‰ https://www.keycloak.org/app/ ๐Ÿ‘ˆ Click "Save" then "Sign in". You should see your login page`, "", - "Once your container is up and configured ๐Ÿ‘‰ http://localhost:8080/auth/realms/myrealm/account ๐Ÿ‘ˆ", + "Video demoing this process: https://youtu.be/N3wlBoH4hKg", "", ].join("\n"), ); diff --git a/src/bin/build-keycloak-theme/generateFtl/Object.deepAssign.js b/src/bin/build-keycloak-theme/generateFtl/Object.deepAssign.js deleted file mode 100644 index 028d9990..00000000 --- a/src/bin/build-keycloak-theme/generateFtl/Object.deepAssign.js +++ /dev/null @@ -1,28 +0,0 @@ - -Object.defineProperty( - Object, - "deepAssign", - { - "value": function callee(target, source) { - Object.keys(source).forEach(function (key) { - var value = source[key]; - if (target[key] === undefined) { - target[key] = value; - return; - } - if (value instanceof Object) { - if (value instanceof Array) { - value.forEach(function (entry) { - target[key].push(entry); - }); - return; - } - callee(target[key], value); - return; - } - target[key] = value; - }); - return target; - } - } -); \ No newline at end of file diff --git a/src/bin/build-keycloak-theme/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl b/src/bin/build-keycloak-theme/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl new file mode 100644 index 00000000..b1e6627d --- /dev/null +++ b/src/bin/build-keycloak-theme/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl @@ -0,0 +1,290 @@ + \ No newline at end of file diff --git a/src/bin/build-keycloak-theme/generateFtl/generateFtl.ts b/src/bin/build-keycloak-theme/generateFtl/generateFtl.ts index 36bd7eac..f2bd3b95 100644 --- a/src/bin/build-keycloak-theme/generateFtl/generateFtl.ts +++ b/src/bin/build-keycloak-theme/generateFtl/generateFtl.ts @@ -16,15 +16,13 @@ export const pageIds = [ "terms.ftl", "login-otp.ftl", "login-update-profile.ftl", + "login-update-password.ftl", "login-idp-link-confirm.ftl", + "login-page-expired.ftl", ] as const; export type PageId = typeof pageIds[number]; -function loadAdjacentFile(fileBasename: string) { - return fs.readFileSync(pathJoin(__dirname, fileBasename)).toString("utf8"); -} - export function generateFtlFilesCodeFactory(params: { cssGlobalsToDefine: Record; indexHtmlCode: string; @@ -77,8 +75,11 @@ export function generateFtlFilesCodeFactory(params: { ); //FTL is no valid html, we can't insert with cheerio, we put placeholder for injecting later. - const ftlPlaceholders = { - '{ "x": "vIdLqMeOed9sdLdIdOxdK0d" }': loadAdjacentFile("common.ftl").match(/^", - "", "", - pageSpecificCodePlaceholder, - "", - objectKeys(ftlPlaceholders)[1], + objectKeys(replaceValueBySearchValue)[1], ].join("\n"), ); @@ -129,21 +120,13 @@ export function generateFtlFilesCodeFactory(params: { const $ = cheerio.load(partiallyFixedIndexHtmlCode); - let ftlCode = $.html().replace( - pageSpecificCodePlaceholder, - [ - "", - ].join("\n"), - ); + let ftlCode = $.html(); - objectKeys(ftlPlaceholders).forEach( - id => (ftlCode = ftlCode.replace(id, ftlPlaceholders[id]).replace("ftl_template_for_replacement", pageId)), - ); + Object.entries({ + ...replaceValueBySearchValue, + //If updated, don't forget to change in the ftl script as well. + "PAGE_ID_xIgLsPgGId9D8e": pageId, + }).map(([searchValue, replaceValue]) => (ftlCode = ftlCode.replace(searchValue, replaceValue))); return { ftlCode }; } diff --git a/src/bin/build-keycloak-theme/replaceImportFromStatic.ts b/src/bin/build-keycloak-theme/replaceImportFromStatic.ts index 0d7d9be0..55b11ab3 100644 --- a/src/bin/build-keycloak-theme/replaceImportFromStatic.ts +++ b/src/bin/build-keycloak-theme/replaceImportFromStatic.ts @@ -37,7 +37,7 @@ export function replaceImportsInInlineCssCode(params: { cssCode: string; urlPath const { cssCode, urlPathname, urlOrigin } = params; const fixedCssCode = cssCode.replace( - urlPathname === "/" ? /url\(\/([^/][^)]+)\)/g : new RegExp(`url\\(${urlPathname}([^)]+)\\)`, "g"), + urlPathname === "/" ? /url\(["']?\/([^/][^)"']+)["']?\)/g : new RegExp(`url\\(["']?${urlPathname}([^)"']+)["']?\\)`, "g"), (...[, group]) => `url(${urlOrigin === undefined ? "${url.resourcesPath}/build/" + group : params.urlOrigin + urlPathname + group})`, ); @@ -52,7 +52,7 @@ export function replaceImportsInCssCode(params: { cssCode: string }): { const cssGlobalsToDefine: Record = {}; - new Set(cssCode.match(/url\(\/[^/][^)]+\)[^;}]*/g) ?? []).forEach( + new Set(cssCode.match(/url\(["']?\/[^/][^)"']+["']?\)[^;}]*/g) ?? []).forEach( match => (cssGlobalsToDefine["url" + crypto.createHash("sha256").update(match).digest("hex").substring(0, 15)] = match), ); diff --git a/src/lib/components/KcApp.tsx b/src/lib/components/KcApp.tsx index 91190eba..1538b666 100644 --- a/src/lib/components/KcApp.tsx +++ b/src/lib/components/KcApp.tsx @@ -10,8 +10,10 @@ import { LoginResetPassword } from "./LoginResetPassword"; import { LoginVerifyEmail } from "./LoginVerifyEmail"; import { Terms } from "./Terms"; import { LoginOtp } from "./LoginOtp"; +import { LoginUpdatePassword } from "./LoginUpdatePassword"; import { LoginUpdateProfile } from "./LoginUpdateProfile"; import { LoginIdpLinkConfirm } from "./LoginIdpLinkConfirm"; +import { LoginPageExpired } from "./LoginPageExpired"; export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContextBase } & KcProps) => { switch (kcContext.pageId) { @@ -33,9 +35,13 @@ export const KcApp = memo(({ kcContext, ...props }: { kcContext: KcContextBase } return ; case "login-otp.ftl": return ; + case "login-update-password.ftl": + return ; case "login-update-profile.ftl": return ; case "login-idp-link-confirm.ftl": return ; + case "login-page-expired.ftl": + return ; } }); diff --git a/src/lib/components/LoginOtp.tsx b/src/lib/components/LoginOtp.tsx index f09df5da..2406aef6 100644 --- a/src/lib/components/LoginOtp.tsx +++ b/src/lib/components/LoginOtp.tsx @@ -4,7 +4,7 @@ import type { KcProps } from "./KcProps"; import type { KcContextBase } from "../getKcContext/KcContextBase"; import { useKcMessage } from "../i18n/useKcMessage"; import { headInsert } from "../tools/headInsert"; -import { join as pathJoin } from "path"; +import { pathJoin } from "../tools/pathJoin"; import { useCssAndCx } from "tss-react"; export const LoginOtp = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginOtp } & KcProps) => { diff --git a/src/lib/components/LoginPageExpired.tsx b/src/lib/components/LoginPageExpired.tsx new file mode 100644 index 00000000..02960fee --- /dev/null +++ b/src/lib/components/LoginPageExpired.tsx @@ -0,0 +1,36 @@ +import { memo } from "react"; +import { Template } from "./Template"; +import type { KcProps } from "./KcProps"; +import type { KcContextBase } from "../getKcContext/KcContextBase"; +import { useKcMessage } from "../i18n/useKcMessage"; + +export const LoginPageExpired = memo(({ kcContext, ...props }: { kcContext: KcContextBase.LoginPageExpired } & KcProps) => { + const { url } = kcContext; + + const { msg } = useKcMessage(); + + return ( +