Compare commits

...

20 Commits

Author SHA1 Message Date
5249e05746 Release candidate 2024-06-10 19:36:11 +02:00
1e7a0dd7a6 Enable to add files to the jar with the post build options 2024-06-10 19:35:56 +02:00
fd67f2402a Release candidate 2024-06-10 17:30:20 +02:00
60a65ede2f Preserve ordering on user attributes 2024-06-10 17:30:00 +02:00
1fa659ce61 Release candidate 2024-06-10 16:01:56 +02:00
0ab903dbc7 Add new build target for Kc 25 https://github.com/p2-inc/keycloak-account-v1/pull/13 2024-06-10 15:29:08 +02:00
70b0a04793 Release candidate 2024-06-10 15:08:46 +02:00
c0df9aa939 Remove logs 2024-06-10 09:32:07 +02:00
60a1886942 Fix path error 2024-06-10 09:28:31 +02:00
1ebf97871b Fix logical error 2024-06-10 09:26:47 +02:00
72e321aa32 Fix update of the build process checkpoint 2024-06-10 09:24:16 +02:00
b0f602b565 Fix post build script 2024-06-10 09:12:24 +02:00
84c774503d Build rework checkpoint 2024-06-10 07:57:12 +02:00
9bbc7cc651 Release candidate 2024-06-09 15:04:47 +02:00
458083fb6d Prettier stable generated code 2024-06-09 15:04:31 +02:00
8dcfc840b4 Remove useless 'as const' 2024-06-09 14:34:41 +02:00
9d06a3a6ad Release candidate 2024-06-09 14:33:42 +02:00
86cd08b954 Add missing file to the NPM bundle 2024-06-09 14:33:29 +02:00
144c3cc082 Release candidate 2024-06-09 11:53:41 +02:00
802cef41a6 Rename KcApp to KcPage 2024-06-09 11:53:25 +02:00
68 changed files with 484 additions and 627 deletions

View File

@ -1,6 +1,6 @@
{
"name": "keycloakify",
"version": "10.0.0-rc.41",
"version": "10.0.0-rc.48",
"description": "Create Keycloak themes using React",
"repository": {
"type": "git",
@ -44,6 +44,7 @@
"dist/bin/shared/constants.js",
"dist/bin/shared/constants.d.ts",
"dist/bin/shared/constants.js.map",
"dist/bin/shared/buildContext.d.ts",
"!dist/vite-plugin/",
"dist/vite-plugin/index.d.ts",
"dist/vite-plugin/vite-plugin.d.ts",

View File

@ -1,63 +0,0 @@
import { join as pathJoin, relative as pathRelative, sep as pathSep } from "path";
import { promptKeycloakVersion } from "./shared/promptKeycloakVersion";
import { getBuildContext } from "./shared/buildContext";
import { downloadKeycloakDefaultTheme } from "./shared/downloadKeycloakDefaultTheme";
import { transformCodebase } from "./tools/transformCodebase";
import type { CliCommandOptions } from "./main";
import chalk from "chalk";
export async function command(params: { cliCommandOptions: CliCommandOptions }) {
const { cliCommandOptions } = params;
const buildContext = getBuildContext({
cliCommandOptions
});
console.log(
chalk.cyan(
"Select the Keycloak version from which you want to download the builtins theme:"
)
);
const { keycloakVersion } = await promptKeycloakVersion({
startingFromMajor: undefined,
cacheDirPath: buildContext.cacheDirPath
});
console.log(`${keycloakVersion}`);
const destDirPath = pathJoin(
buildContext.keycloakifyBuildDirPath,
"src",
"main",
"resources",
"theme"
);
console.log(
[
`Downloading builtins theme of Keycloak ${keycloakVersion} here:`,
`- ${chalk.bold(
`.${pathSep}${pathJoin(pathRelative(process.cwd(), destDirPath), "base")}`
)}`,
`- ${chalk.bold(
`.${pathSep}${pathJoin(
pathRelative(process.cwd(), destDirPath),
"keycloak"
)}`
)}`
].join("\n")
);
const { defaultThemeDirPath } = await downloadKeycloakDefaultTheme({
keycloakVersion,
buildContext
});
transformCodebase({
srcDirPath: defaultThemeDirPath,
destDirPath
});
console.log(chalk.green(`✓ done`));
}

View File

@ -149,7 +149,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
break edit_KcApp;
}
const kcAppTsxPath = pathJoin(themeSrcDirPath, themeType, "KcApp.tsx");
const kcAppTsxPath = pathJoin(themeSrcDirPath, themeType, "KcPage.tsx");
const kcAppTsxCode = fs.readFileSync(kcAppTsxPath).toString("utf8");
@ -172,7 +172,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
if (kcAppTsxCode === modifiedKcAppTsxCode) {
console.log(
chalk.red(
"Unable to automatically update KcApp.tsx, please update it manually"
"Unable to automatically update KcPage.tsx, please update it manually"
)
);
return;
@ -201,7 +201,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
".",
pathRelative(process.cwd(), themeSrcDirPath),
themeType,
"KcApp.tsx"
"KcPage.tsx"
)
)}:`,
chalk.grey("```"),
@ -215,7 +215,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
),
...[
``,
` export default function KcApp(props: { kcContext: KcContext; }) {`,
` export default function KcPage(props: { kcContext: KcContext; }) {`,
``,
` // ...`,
``,

View File

@ -32,12 +32,14 @@ export async function buildJar(params: {
jarFileBasename: string;
keycloakAccountV1Version: KeycloakAccountV1Version;
keycloakThemeAdditionalInfoExtensionVersion: KeycloakThemeAdditionalInfoExtensionVersion;
resourcesDirPath: string;
buildContext: BuildContextLike;
}): Promise<void> {
const {
jarFileBasename,
keycloakAccountV1Version,
keycloakThemeAdditionalInfoExtensionVersion,
resourcesDirPath,
buildContext
} = params;
@ -48,35 +50,10 @@ export async function buildJar(params: {
rmSync(keycloakifyBuildTmpDirPath, { recursive: true, force: true });
{
const transformCodebase_common = (params: {
fileRelativePath: string;
sourceCode: Buffer;
}): { modifiedSourceCode: Buffer } | undefined => {
const { fileRelativePath, sourceCode } = params;
if (
fileRelativePath ===
getMetaInfKeycloakThemesJsonFilePath({ keycloakifyBuildDirPath: "." })
) {
return { modifiedSourceCode: sourceCode };
}
for (const themeName of [...buildContext.themeNames, accountV1ThemeName]) {
if (
isInside({
dirPath: pathJoin("src", "main", "resources", "theme", themeName),
filePath: fileRelativePath
})
) {
return { modifiedSourceCode: sourceCode };
}
}
return undefined;
};
const transformCodebase_patchForUsingBuiltinAccountV1 =
transformCodebase({
srcDirPath: resourcesDirPath,
destDirPath: pathJoin(keycloakifyBuildTmpDirPath, "src", "main", "resources"),
transformSourceCode:
keycloakAccountV1Version !== null
? undefined
: (params: {
@ -87,13 +64,7 @@ export async function buildJar(params: {
if (
isInside({
dirPath: pathJoin(
"src",
"main",
"resources",
"theme",
accountV1ThemeName
),
dirPath: pathJoin("theme", accountV1ThemeName),
filePath: fileRelativePath
})
) {
@ -103,7 +74,7 @@ export async function buildJar(params: {
if (
fileRelativePath ===
getMetaInfKeycloakThemesJsonFilePath({
keycloakifyBuildDirPath: "."
resourcesDirPath: "."
})
) {
const keycloakThemesJsonParsed = JSON.parse(
@ -128,15 +99,7 @@ export async function buildJar(params: {
for (const themeName of buildContext.themeNames) {
if (
fileRelativePath ===
pathJoin(
"src",
"main",
"resources",
"theme",
themeName,
"account",
"theme.properties"
)
pathJoin("theme", themeName, "account", "theme.properties")
) {
const modifiedSourceCode = Buffer.from(
sourceCode
@ -157,31 +120,8 @@ export async function buildJar(params: {
}
return { modifiedSourceCode: sourceCode };
};
transformCodebase({
srcDirPath: buildContext.keycloakifyBuildDirPath,
destDirPath: keycloakifyBuildTmpDirPath,
transformSourceCode: params => {
const resultCommon = transformCodebase_common(params);
if (transformCodebase_patchForUsingBuiltinAccountV1 === undefined) {
return resultCommon;
}
if (resultCommon === undefined) {
return undefined;
}
const { modifiedSourceCode } = resultCommon;
return transformCodebase_patchForUsingBuiltinAccountV1({
...params,
sourceCode: modifiedSourceCode
});
}
});
}
}
});
route_legacy_pages: {
// NOTE: If there's no account theme there is no special target for keycloak 24 and up so we create

View File

@ -8,7 +8,7 @@ import { getKeycloakVersionRangeForJar } from "./getKeycloakVersionRangeForJar";
import { buildJar, BuildContextLike as BuildContextLike_buildJar } from "./buildJar";
import type { BuildContext } from "../../shared/buildContext";
import { getJarFileBasename } from "../../shared/getJarFileBasename";
import { readMetaInfKeycloakThemes } from "../../shared/metaInfKeycloakThemes";
import { readMetaInfKeycloakThemes_fromResourcesDirPath } from "../../shared/metaInfKeycloakThemes";
import { accountV1ThemeName } from "../../shared/constants";
export type BuildContextLike = BuildContextLike_buildJar & {
@ -18,12 +18,14 @@ export type BuildContextLike = BuildContextLike_buildJar & {
assert<BuildContext extends BuildContextLike ? true : false>();
export async function buildJars(params: {
resourcesDirPath: string;
onlyBuildJarFileBasename: string | undefined;
buildContext: BuildContextLike;
}): Promise<void> {
const { buildContext } = params;
const { onlyBuildJarFileBasename, resourcesDirPath, buildContext } = params;
const doesImplementAccountTheme = readMetaInfKeycloakThemes({
keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath
const doesImplementAccountTheme = readMetaInfKeycloakThemes_fromResourcesDirPath({
resourcesDirPath
}).themes.some(({ name }) => name === accountV1ThemeName);
await Promise.all(
@ -56,12 +58,20 @@ export async function buildJars(params: {
keycloakVersionRange
});
if (
onlyBuildJarFileBasename !== undefined &&
onlyBuildJarFileBasename !== jarFileBasename
) {
return undefined;
}
return {
keycloakThemeAdditionalInfoExtensionVersion,
jarFileBasename
};
}
)
.filter(exclude(undefined))
.map(
({
keycloakThemeAdditionalInfoExtensionVersion,
@ -71,6 +81,7 @@ export async function buildJars(params: {
jarFileBasename,
keycloakAccountV1Version,
keycloakThemeAdditionalInfoExtensionVersion,
resourcesDirPath,
buildContext
})
)

View File

@ -1,5 +1,5 @@
// NOTE: v0.5 is a dummy version.
export const keycloakAccountV1Versions = [null, "0.3", "0.4"] as const;
export const keycloakAccountV1Versions = [null, "0.3", "0.4", "0.6"] as const;
/**
* https://central.sonatype.com/artifact/io.phasetwo.keycloak/keycloak-account-v1

View File

@ -44,12 +44,20 @@ export function getKeycloakVersionRangeForJar(params: {
case null:
return undefined;
case "1.1.5":
return "24-and-above" as const;
return "24" as const;
}
assert<
Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>
>(false);
case "0.6":
switch (keycloakThemeAdditionalInfoExtensionVersion) {
case null:
return undefined;
case "1.1.5":
return "25-and-above" as const;
}
}
assert<Equals<typeof keycloakAccountV1Version, never>>(false);
})();
assert<
@ -65,7 +73,6 @@ export function getKeycloakVersionRangeForJar(params: {
if (keycloakAccountV1Version !== null) {
return undefined;
}
switch (keycloakThemeAdditionalInfoExtensionVersion) {
case null:
return "21-and-below";

View File

@ -184,6 +184,28 @@ try {
};
</#if>
attributes_to_attributesByName: {
if( !out["profile"] ){
break attributes_to_attributesByName;
}
if( !out["profile"]["attributes"] ){
break attributes_to_attributesByName;
}
var attributes = out["profile"]["attributes"];
delete out["profile"]["attributes"];
out["profile"]["attributesByName"] = {};
attributes.forEach(function(attribute){
out["profile"]["attributesByName"][attribute.name] = attribute;
});
}
return out;
function decodeHtmlEntities(htmlStr){
@ -287,8 +309,8 @@ function decodeHtmlEntities(htmlStr){
key == "realmAttributes" &&
are_same_path(path, [])
) || (
<#-- attributesByName adds a lot of noise to the output and is not needed -->
key == "attributes" &&
<#-- attributesByName adds a lot of noise to the output and is not needed, we already have profile.attributes -->
key == "attributesByName" &&
are_same_path(path, ["profile"])
) || (
<#-- We already have the attributes in profile speedup the rendering by filtering it out from the register object -->

View File

@ -13,13 +13,15 @@ import { transformCodebase } from "../../tools/transformCodebase";
export type BuildContextLike = {
cacheDirPath: string;
npmWorkspaceRootDirPath: string;
keycloakifyBuildDirPath: string;
};
assert<BuildContext extends BuildContextLike ? true : false>();
export async function bringInAccountV1(params: { buildContext: BuildContextLike }) {
const { buildContext } = params;
export async function bringInAccountV1(params: {
resourcesDirPath: string;
buildContext: BuildContextLike;
}) {
const { resourcesDirPath, buildContext } = params;
const { defaultThemeDirPath } = await downloadKeycloakDefaultTheme({
keycloakVersion: lastKeycloakVersionWithAccountV1,
@ -27,10 +29,7 @@ export async function bringInAccountV1(params: { buildContext: BuildContextLike
});
const accountV1DirPath = pathJoin(
buildContext.keycloakifyBuildDirPath,
"src",
"main",
"resources",
resourcesDirPath,
"theme",
accountV1ThemeName,
"account"

View File

@ -5,6 +5,8 @@ import {
type BuildContextLike as BuildContextLike_generateSrcMainResourcesForMainTheme
} from "./generateSrcMainResourcesForMainTheme";
import { generateSrcMainResourcesForThemeVariant } from "./generateSrcMainResourcesForThemeVariant";
import fs from "fs";
import { rmSync } from "../../tools/fs.rmSync";
export type BuildContextLike = BuildContextLike_generateSrcMainResourcesForMainTheme & {
themeNames: string[];
@ -14,21 +16,27 @@ assert<BuildContext extends BuildContextLike ? true : false>();
export async function generateSrcMainResources(params: {
buildContext: BuildContextLike;
resourcesDirPath: string;
}): Promise<void> {
const { buildContext } = params;
const { resourcesDirPath, buildContext } = params;
const [themeName, ...themeVariantNames] = buildContext.themeNames;
if (fs.existsSync(resourcesDirPath)) {
rmSync(resourcesDirPath, { recursive: true });
}
await generateSrcMainResourcesForMainTheme({
resourcesDirPath,
themeName,
buildContext
});
for (const themeVariantName of themeVariantNames) {
generateSrcMainResourcesForThemeVariant({
resourcesDirPath,
themeName,
themeVariantName,
buildContext
themeVariantName
});
}
}

View File

@ -43,14 +43,10 @@ import { escapeStringForPropertiesFile } from "../../tools/escapeStringForProper
export type BuildContextLike = BuildContextLike_kcContextExclusionsFtlCode &
BuildContextLike_downloadKeycloakStaticResources &
BuildContextLike_bringInAccountV1 & {
bundler: "vite" | "webpack";
extraThemeProperties: string[] | undefined;
loginThemeResourcesFromKeycloakVersion: string;
projectBuildDirPath: string;
assetsDirPath: string;
urlPathname: string | undefined;
projectDirPath: string;
keycloakifyBuildDirPath: string;
projectBuildDirPath: string;
environmentVariables: { name: string; default: string }[];
};
@ -58,9 +54,10 @@ assert<BuildContext extends BuildContextLike ? true : false>();
export async function generateSrcMainResourcesForMainTheme(params: {
themeName: string;
resourcesDirPath: string;
buildContext: BuildContextLike;
}): Promise<void> {
const { themeName, buildContext } = params;
const { themeName, resourcesDirPath, buildContext } = params;
const { themeSrcDirPath } = getThemeSrcDirPath({
projectDirPath: buildContext.projectDirPath
@ -68,15 +65,7 @@ export async function generateSrcMainResourcesForMainTheme(params: {
const getThemeTypeDirPath = (params: { themeType: ThemeType | "email" }) => {
const { themeType } = params;
return pathJoin(
buildContext.keycloakifyBuildDirPath,
"src",
"main",
"resources",
"theme",
themeName,
themeType
);
return pathJoin(resourcesDirPath, "theme", themeName, themeType);
};
const cssGlobalsToDefine: Record<string, string> = {};
@ -207,8 +196,6 @@ export async function generateSrcMainResourcesForMainTheme(params: {
].forEach(pageId => {
const { ftlCode } = generateFtlFilesCode({ pageId });
fs.mkdirSync(themeTypeDirPath, { recursive: true });
fs.writeFileSync(
pathJoin(themeTypeDirPath, pageId),
Buffer.from(ftlCode, "utf8")
@ -291,6 +278,7 @@ export async function generateSrcMainResourcesForMainTheme(params: {
if (implementedThemeTypes.account) {
await bringInAccountV1({
resourcesDirPath,
buildContext
});
}
@ -313,7 +301,7 @@ export async function generateSrcMainResourcesForMainTheme(params: {
}
writeMetaInfKeycloakThemes({
keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath,
resourcesDirPath,
metaInfKeycloakThemes
});
}

View File

@ -2,7 +2,7 @@ import { join as pathJoin, extname as pathExtname, sep as pathSep } from "path";
import { transformCodebase } from "../../tools/transformCodebase";
import type { BuildContext } from "../../shared/buildContext";
import {
readMetaInfKeycloakThemes,
readMetaInfKeycloakThemes_fromResourcesDirPath,
writeMetaInfKeycloakThemes
} from "../../shared/metaInfKeycloakThemes";
import { assert } from "tsafe/assert";
@ -14,20 +14,13 @@ export type BuildContextLike = {
assert<BuildContext extends BuildContextLike ? true : false>();
export function generateSrcMainResourcesForThemeVariant(params: {
resourcesDirPath: string;
themeName: string;
themeVariantName: string;
buildContext: BuildContextLike;
}) {
const { themeName, themeVariantName, buildContext } = params;
const { resourcesDirPath, themeName, themeVariantName } = params;
const mainThemeDirPath = pathJoin(
buildContext.keycloakifyBuildDirPath,
"src",
"main",
"resources",
"theme",
themeName
);
const mainThemeDirPath = pathJoin(resourcesDirPath, "theme", themeName);
transformCodebase({
srcDirPath: mainThemeDirPath,
@ -57,9 +50,10 @@ export function generateSrcMainResourcesForThemeVariant(params: {
});
{
const updatedMetaInfKeycloakThemes = readMetaInfKeycloakThemes({
keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath
});
const updatedMetaInfKeycloakThemes =
readMetaInfKeycloakThemes_fromResourcesDirPath({
resourcesDirPath
});
updatedMetaInfKeycloakThemes.themes.push({
name: themeVariantName,
@ -73,7 +67,7 @@ export function generateSrcMainResourcesForThemeVariant(params: {
});
writeMetaInfKeycloakThemes({
keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath,
resourcesDirPath,
metaInfKeycloakThemes: updatedMetaInfKeycloakThemes
});
}

View File

@ -1,74 +0,0 @@
import * as fs from "fs";
import {
join as pathJoin,
relative as pathRelative,
basename as pathBasename
} from "path";
import { assert } from "tsafe/assert";
import type { BuildContext } from "../shared/buildContext";
import { accountV1ThemeName } from "../shared/constants";
export type BuildContextLike = {
keycloakifyBuildDirPath: string;
themeNames: string[];
};
assert<BuildContext extends BuildContextLike ? true : false>();
generateStartKeycloakTestingContainer.basename = "start_keycloak_testing_container.sh";
const containerName = "keycloak-testing-container";
const keycloakVersion = "24.0.4";
/** Files for being able to run a hot reload keycloak container */
export function generateStartKeycloakTestingContainer(params: {
jarFilePath: string;
doesImplementAccountTheme: boolean;
buildContext: BuildContextLike;
}) {
const { jarFilePath, doesImplementAccountTheme, buildContext } = params;
const themeRelativeDirPath = pathJoin("src", "main", "resources", "theme");
fs.writeFileSync(
pathJoin(
buildContext.keycloakifyBuildDirPath,
generateStartKeycloakTestingContainer.basename
),
Buffer.from(
[
"#!/usr/bin/env bash",
"",
`docker rm ${containerName} || true`,
"",
`cd "${buildContext.keycloakifyBuildDirPath}"`,
"",
"docker run \\",
" -p 8080:8080 \\",
` --name ${containerName} \\`,
" -e KEYCLOAK_ADMIN=admin \\",
" -e KEYCLOAK_ADMIN_PASSWORD=admin \\",
` -v "${pathJoin(
"$(pwd)",
pathRelative(buildContext.keycloakifyBuildDirPath, jarFilePath)
)}":"/opt/keycloak/providers/${pathBasename(jarFilePath)}" \\`,
[
...(doesImplementAccountTheme ? [accountV1ThemeName] : []),
...buildContext.themeNames
].map(
themeName =>
` -v "${pathJoin(
"$(pwd)",
themeRelativeDirPath,
themeName
).replace(/\\/g, "/")}":"/opt/keycloak/themes/${themeName}":rw \\`
),
` -it quay.io/keycloak/keycloak:${keycloakVersion} \\`,
` start-dev`,
""
].join("\n"),
"utf8"
),
{ mode: 0o755 }
);
}

View File

@ -3,12 +3,16 @@ import { join as pathJoin, relative as pathRelative, sep as pathSep } from "path
import * as child_process from "child_process";
import * as fs from "fs";
import { getBuildContext } from "../shared/buildContext";
import { vitePluginSubScriptEnvNames, skipBuildJarsEnvName } from "../shared/constants";
import {
vitePluginSubScriptEnvNames,
onlyBuildJarFileBasenameEnvName
} from "../shared/constants";
import { buildJars } from "./buildJars";
import type { CliCommandOptions } from "../main";
import chalk from "chalk";
import { readThisNpmPackageVersion } from "../tools/readThisNpmPackageVersion";
import * as os from "os";
import { rmSync } from "../tools/fs.rmSync";
export async function command(params: { cliCommandOptions: CliCommandOptions }) {
exit_if_maven_not_installed: {
@ -76,7 +80,12 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
);
}
await generateSrcMainResources({ buildContext });
const resourcesDirPath = pathJoin(buildContext.keycloakifyBuildDirPath, "resources");
await generateSrcMainResources({
resourcesDirPath,
buildContext
});
run_post_build_script: {
if (buildContext.bundler !== "vite") {
@ -93,15 +102,17 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
});
}
build_jars: {
if (process.env[skipBuildJarsEnvName]) {
break build_jars;
}
await buildJars({
resourcesDirPath,
buildContext,
onlyBuildJarFileBasename: process.env[onlyBuildJarFileBasenameEnvName]
});
await buildJars({ buildContext });
}
rmSync(resourcesDirPath, { recursive: true });
console.log(
chalk.green(`✓ built in ${((Date.now() - startTime) / 1000).toFixed(2)}s`)
chalk.green(
`✓ keycloak theme built in ${((Date.now() - startTime) / 1000).toFixed(2)}s`
)
);
}

View File

@ -134,20 +134,6 @@ program
}
});
program
.command({
name: "download-keycloak-default-theme",
description: "Download the built-in Keycloak theme."
})
.task({
skip,
handler: async cliCommandOptions => {
const { command } = await import("./download-keycloak-default-theme");
await command({ cliCommandOptions });
}
});
program
.command({
name: "eject-page",

View File

@ -5,5 +5,5 @@ export type KeycloakVersionRange =
export namespace KeycloakVersionRange {
export type WithoutAccountTheme = "21-and-below" | "22-and-above";
export type WithAccountTheme = "21-and-below" | "23" | "24-and-above";
export type WithAccountTheme = "21-and-below" | "23" | "24" | "25-and-above";
}

View File

@ -12,7 +12,7 @@ import { vitePluginSubScriptEnvNames } from "./constants";
export type BuildContext = {
bundler: "vite" | "webpack";
themeVersion: string;
themeNames: string[];
themeNames: [string, ...string[]];
extraThemeProperties: string[] | undefined;
groupId: string;
artifactId: string;
@ -147,7 +147,7 @@ export function getBuildContext(params: {
...resolvedViteConfig?.buildOptions
};
const themeNames = (() => {
const themeNames = ((): [string, ...string[]] => {
if (buildOptions.themeName === undefined) {
return [
parsedPackageJson.name
@ -161,7 +161,11 @@ export function getBuildContext(params: {
return [buildOptions.themeName];
}
return buildOptions.themeName;
const [mainThemeName, ...themeVariantNames] = buildOptions.themeName;
assert(mainThemeName !== undefined);
return [mainThemeName, ...themeVariantNames];
})();
const projectBuildDirPath = (() => {

View File

@ -16,7 +16,7 @@ export const vitePluginSubScriptEnvNames = {
resolveViteConfig: "KEYCLOAKIFY_RESOLVE_VITE_CONFIG"
} as const;
export const skipBuildJarsEnvName = "KEYCLOAKIFY_SKIP_BUILD_JAR";
export const onlyBuildJarFileBasenameEnvName = "KEYCLOAKIFY_ONLY_BUILD_JAR_FILE_BASENAME";
export const loginThemePageIds = [
"login.ftl",

View File

@ -58,7 +58,8 @@ export async function generateKcGenTs(params: {
2
)};`,
``,
`/* prettier-ignore-end */`
`/* prettier-ignore-end */`,
``
].join("\n"),
"utf8"
);

View File

@ -1,50 +1,73 @@
import { join as pathJoin, dirname as pathDirname } from "path";
import type { ThemeType } from "./constants";
import * as fs from "fs";
import { assert } from "tsafe/assert";
import { extractArchive } from "../tools/extractArchive";
export type MetaInfKeycloakTheme = {
themes: { name: string; types: (ThemeType | "email")[] }[];
};
export function getMetaInfKeycloakThemesJsonFilePath(params: {
keycloakifyBuildDirPath: string;
resourcesDirPath: string;
}) {
const { keycloakifyBuildDirPath } = params;
const { resourcesDirPath } = params;
return pathJoin(
keycloakifyBuildDirPath === "." ? "" : keycloakifyBuildDirPath,
"src",
"main",
"resources",
resourcesDirPath === "." ? "" : resourcesDirPath,
"META-INF",
"keycloak-themes.json"
);
}
export function readMetaInfKeycloakThemes(params: {
keycloakifyBuildDirPath: string;
}): MetaInfKeycloakTheme {
const { keycloakifyBuildDirPath } = params;
export function readMetaInfKeycloakThemes_fromResourcesDirPath(params: {
resourcesDirPath: string;
}) {
const { resourcesDirPath } = params;
return JSON.parse(
fs
.readFileSync(
getMetaInfKeycloakThemesJsonFilePath({
keycloakifyBuildDirPath
resourcesDirPath
})
)
.toString("utf8")
) as MetaInfKeycloakTheme;
}
export async function readMetaInfKeycloakThemes_fromJar(params: {
jarFilePath: string;
}): Promise<MetaInfKeycloakTheme> {
const { jarFilePath } = params;
let metaInfKeycloakThemes: MetaInfKeycloakTheme | undefined = undefined;
await extractArchive({
archiveFilePath: jarFilePath,
onArchiveFile: async ({ relativeFilePathInArchive, readFile, earlyExit }) => {
if (
relativeFilePathInArchive ===
getMetaInfKeycloakThemesJsonFilePath({ resourcesDirPath: "." })
) {
metaInfKeycloakThemes = JSON.parse((await readFile()).toString("utf8"));
earlyExit();
}
}
});
assert(metaInfKeycloakThemes !== undefined);
return metaInfKeycloakThemes;
}
export function writeMetaInfKeycloakThemes(params: {
keycloakifyBuildDirPath: string;
resourcesDirPath: string;
metaInfKeycloakThemes: MetaInfKeycloakTheme;
}) {
const { keycloakifyBuildDirPath, metaInfKeycloakThemes } = params;
const { resourcesDirPath, metaInfKeycloakThemes } = params;
const metaInfKeycloakThemesJsonPath = getMetaInfKeycloakThemesJsonFilePath({
keycloakifyBuildDirPath
resourcesDirPath
});
{

View File

@ -1,4 +1,4 @@
import { skipBuildJarsEnvName } from "../shared/constants";
import { onlyBuildJarFileBasenameEnvName } from "../shared/constants";
import * as child_process from "child_process";
import { Deferred } from "evt/tools/Deferred";
import { assert } from "tsafe/assert";
@ -14,10 +14,10 @@ export type BuildContextLike = {
assert<BuildContext extends BuildContextLike ? true : false>();
export async function keycloakifyBuild(params: {
doSkipBuildJars: boolean;
onlyBuildJarFileBasename: string | undefined;
buildContext: BuildContextLike;
}): Promise<{ isKeycloakifyBuildSuccess: boolean }> {
const { buildContext, doSkipBuildJars } = params;
const { buildContext, onlyBuildJarFileBasename } = params;
const dResult = new Deferred<{ isSuccess: boolean }>();
@ -25,7 +25,7 @@ export async function keycloakifyBuild(params: {
cwd: buildContext.projectDirPath,
env: {
...process.env,
...(doSkipBuildJars ? { [skipBuildJarsEnvName]: "true" } : {})
[onlyBuildJarFileBasenameEnvName]: onlyBuildJarFileBasename
}
});

View File

@ -2,7 +2,7 @@ import { getBuildContext } from "../shared/buildContext";
import { exclude } from "tsafe/exclude";
import type { CliCommandOptions as CliCommandOptions_common } from "../main";
import { promptKeycloakVersion } from "../shared/promptKeycloakVersion";
import { readMetaInfKeycloakThemes } from "../shared/metaInfKeycloakThemes";
import { readMetaInfKeycloakThemes_fromJar } from "../shared/metaInfKeycloakThemes";
import { accountV1ThemeName, containerName } from "../shared/constants";
import { SemVer } from "../tools/SemVer";
import type { KeycloakVersionRange } from "../shared/KeycloakVersionRange";
@ -21,6 +21,9 @@ import * as runExclusive from "run-exclusive";
import { extractArchive } from "../tools/extractArchive";
import { appBuild } from "./appBuild";
import { keycloakifyBuild } from "./keycloakifyBuild";
import { isInside } from "../tools/isInside";
import { existsAsync } from "../tools/fs.existsAsync";
import { rm } from "../tools/fs.rm";
export type CliCommandOptions = CliCommandOptions_common & {
port: number;
@ -98,7 +101,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
}
const { isKeycloakifyBuildSuccess } = await keycloakifyBuild({
doSkipBuildJars: false,
onlyBuildJarFileBasename: undefined,
buildContext
});
@ -112,13 +115,31 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
}
}
const metaInfKeycloakThemes = readMetaInfKeycloakThemes({
keycloakifyBuildDirPath: buildContext.keycloakifyBuildDirPath
});
const { doesImplementAccountTheme } = await (async () => {
const latestJarFilePath = fs
.readdirSync(buildContext.keycloakifyBuildDirPath)
.filter(fileBasename => fileBasename.endsWith(".jar"))
.map(fileBasename =>
pathJoin(buildContext.keycloakifyBuildDirPath, fileBasename)
)
.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)[0];
const doesImplementAccountTheme = metaInfKeycloakThemes.themes.some(
({ name }) => name === accountV1ThemeName
);
assert(latestJarFilePath !== undefined);
const metaInfKeycloakThemes = await readMetaInfKeycloakThemes_fromJar({
jarFilePath: latestJarFilePath
});
const mainThemeEntry = metaInfKeycloakThemes.themes.find(
({ name }) => name === buildContext.themeNames[0]
);
assert(mainThemeEntry !== undefined);
const doesImplementAccountTheme = mainThemeEntry.types.includes("account");
return { doesImplementAccountTheme };
})();
const { keycloakVersion, keycloakMajorNumber: keycloakMajorVersionNumber } =
await (async function getKeycloakMajor(): Promise<{
@ -172,7 +193,11 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
return "23" as const;
}
return "24-and-above" as const;
if (keycloakMajorVersionNumber === 24) {
return "24" as const;
}
return "25-and-above" as const;
})();
assert<
@ -262,65 +287,30 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
const jarFilePath = pathJoin(buildContext.keycloakifyBuildDirPath, jarFileBasename);
const { doUseBuiltInAccountV1Theme } = await (async () => {
let doUseBuiltInAccountV1Theme = false;
async function extractThemeResourcesFromJar() {
await extractArchive({
archiveFilePath: jarFilePath,
onArchiveFile: async ({ relativeFilePathInArchive, readFile, earlyExit }) => {
for (const themeName of buildContext.themeNames) {
if (
relativeFilePathInArchive ===
pathJoin("theme", themeName, "account", "theme.properties")
) {
if (
(await readFile())
.toString("utf8")
.includes("parent=keycloak")
) {
doUseBuiltInAccountV1Theme = true;
}
earlyExit();
}
onArchiveFile: async ({ relativeFilePathInArchive, writeFile }) => {
if (isInside({ dirPath: "theme", filePath: relativeFilePathInArchive })) {
await writeFile({
filePath: pathJoin(
buildContext.keycloakifyBuildDirPath,
relativeFilePathInArchive
)
});
}
}
});
}
return { doUseBuiltInAccountV1Theme };
})();
{
const destDirPath = pathJoin(buildContext.keycloakifyBuildDirPath, "theme");
if (await existsAsync(destDirPath)) {
await rm(destDirPath, { recursive: true });
}
}
const accountThemePropertyPatch = !doUseBuiltInAccountV1Theme
? undefined
: () => {
for (const themeName of buildContext.themeNames) {
const filePath = pathJoin(
buildContext.keycloakifyBuildDirPath,
"src",
"main",
"resources",
"theme",
themeName,
"account",
"theme.properties"
);
const sourceCode = fs.readFileSync(filePath);
const modifiedSourceCode = Buffer.from(
sourceCode
.toString("utf8")
.replace(`parent=${accountV1ThemeName}`, "parent=keycloak"),
"utf8"
);
assert(Buffer.compare(modifiedSourceCode, sourceCode) !== 0);
fs.writeFileSync(filePath, modifiedSourceCode);
}
};
accountThemePropertyPatch?.();
await extractThemeResourcesFromJar();
try {
child_process.execSync(`docker rm --force ${containerName}`, {
@ -348,14 +338,19 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
: []),
...[
...buildContext.themeNames,
...(doUseBuiltInAccountV1Theme ? [] : [accountV1ThemeName])
...(fs.existsSync(
pathJoin(
buildContext.keycloakifyBuildDirPath,
"theme",
accountV1ThemeName
)
)
? [accountV1ThemeName]
: [])
]
.map(themeName => ({
localDirPath: pathJoin(
buildContext.keycloakifyBuildDirPath,
"src",
"main",
"resources",
"theme",
themeName
),
@ -451,7 +446,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
}
const { isKeycloakifyBuildSuccess } = await keycloakifyBuild({
doSkipBuildJars: true,
onlyBuildJarFileBasename: jarFileBasename,
buildContext
});
@ -459,7 +454,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
return;
}
accountThemePropertyPatch?.();
await extractThemeResourcesFromJar();
console.log(chalk.green("Theme rebuilt and updated in Keycloak."));
});

View File

@ -33,7 +33,7 @@ export function keycloakify(params?: Params) {
let shouldGenerateSourcemap: boolean | undefined = undefined;
const plugin = {
name: "keycloakify" as const,
name: "keycloakify",
configResolved: async resolvedConfig => {
shouldGenerateSourcemap = resolvedConfig.build.sourcemap !== false;
@ -47,6 +47,10 @@ export function keycloakify(params?: Params) {
const buildContext = JSON.parse(envValue) as BuildContext;
process.chdir(
pathJoin(buildContext.keycloakifyBuildDirPath, "resources")
);
await postBuild?.(buildContext);
process.exit(0);

View File

@ -4,7 +4,7 @@ import { useI18n } from "./i18n";
import type { KcContext } from "./KcContext";
import Template from "../../dist/account/Template";
export default function KcApp(props: { kcContext: KcContext }) {
export default function KcPage(props: { kcContext: KcContext }) {
const { kcContext } = props;
const { i18n } = useI18n({ kcContext });

View File

@ -3,7 +3,7 @@ import type { DeepPartial } from "../../dist/tools/DeepPartial";
import type { KcContext } from "./KcContext";
import { createGetKcContextMock } from "../../dist/account/KcContext";
import type { KcContextExtension, KcContextExtensionPerPage } from "./KcContext";
import KcApp from "./KcApp";
import KcPage from "./KcPage";
import { themeNames, kcEnvDefaults } from "../kc.gen";
const kcContextExtension: KcContextExtension = {
@ -21,10 +21,10 @@ export const { getKcContextMock } = createGetKcContextMock({
overridesPerPage: {}
});
export function createPageStory<PageId extends KcContext["pageId"]>(params: { pageId: PageId }) {
export function createKcPageStory<PageId extends KcContext["pageId"]>(params: { pageId: PageId }) {
const { pageId } = params;
function PageStory(props: { kcContext?: DeepPartial<Extract<KcContext, { pageId: PageId }>> }) {
function KcPageStory(props: { kcContext?: DeepPartial<Extract<KcContext, { pageId: PageId }>> }) {
const { kcContext: overrides } = props;
const kcContextMock = getKcContextMock({
@ -34,10 +34,10 @@ export function createPageStory<PageId extends KcContext["pageId"]>(params: { pa
return (
<React.StrictMode>
<KcApp kcContext={kcContextMock} />
<KcPage kcContext={kcContextMock} />
</React.StrictMode>
);
}
return { PageStory };
return { KcPageStory };
}

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "account.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "account.ftl" });
const meta = {
title: "account/account.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,25 +1,25 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "federatedIdentity.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "federatedIdentity.ftl" });
const meta = {
title: "account/federatedIdentity.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};
export const NotConnected: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
pageId: "federatedIdentity.ftl",
federatedIdentity: {

View File

@ -1,15 +1,15 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({
const { KcPageStory } = createKcPageStory({
pageId: "log.ftl"
});
const meta = {
title: "account/log.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
@ -17,7 +17,7 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
log: {
events: [

View File

@ -1,25 +1,25 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "password.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "password.ftl" });
const meta = {
title: "account/password.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};
export const WithMessage: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
message: { type: "success", summary: "This is a test message" }
}}

View File

@ -1,13 +1,13 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "sessions.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "sessions.ftl" });
const meta = {
title: "account/sessions.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
@ -15,7 +15,7 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
sessions: {
sessions: [
@ -45,7 +45,7 @@ export const Default: Story = {
export const WithError: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
url: { passwordUrl: "/auth/realms/keycloakify/account/password" },
stateChecker: "xQ7EOgFrLi4EvnJ8dbXKhwFGWk_bkOp0X89mhilt1os",

View File

@ -1,13 +1,13 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "totp.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "totp.ftl" });
const meta = {
title: "account/totp.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
@ -15,7 +15,7 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
totp: {
enabled: false,
@ -51,7 +51,7 @@ export const Default: Story = {
export const WithTotpEnabled: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
totp: {
enabled: true,
@ -98,7 +98,7 @@ export const WithTotpEnabled: Story = {
export const WithManualMode: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
mode: "manual",
totp: {
@ -136,7 +136,7 @@ export const WithManualMode: Story = {
export const MoreThanOneTotpProviders: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
totp: {
enabled: true,

View File

@ -6,7 +6,7 @@ import { useDownloadTerms } from "../../dist/login/lib/useDownloadTerms";
import Template from "../../dist/login/Template";
import UserProfileFormFields from "../../dist/login/UserProfileFormFields";
export default function KcApp(props: { kcContext: KcContext }) {
export default function KcPage(props: { kcContext: KcContext }) {
const { kcContext } = props;
const { i18n } = useI18n({ kcContext });

View File

@ -3,7 +3,7 @@ import type { DeepPartial } from "../../dist/tools/DeepPartial";
import type { KcContext } from "./KcContext";
import { createGetKcContextMock } from "../../dist/login/KcContext";
import type { KcContextExtension, KcContextExtensionPerPage } from "./KcContext";
import KcApp from "./KcApp";
import KcPage from "./KcPage";
import { themeNames, kcEnvDefaults } from "../kc.gen";
const kcContextExtension: KcContextExtension = {
@ -21,10 +21,10 @@ export const { getKcContextMock } = createGetKcContextMock({
overridesPerPage: {}
});
export function createPageStory<PageId extends KcContext["pageId"]>(params: { pageId: PageId }) {
export function createKcPageStory<PageId extends KcContext["pageId"]>(params: { pageId: PageId }) {
const { pageId } = params;
function PageStory(props: { kcContext?: DeepPartial<Extract<KcContext, { pageId: PageId }>> }) {
function KcPageStory(props: { kcContext?: DeepPartial<Extract<KcContext, { pageId: PageId }>> }) {
const { kcContext: overrides } = props;
const kcContextMock = getKcContextMock({
@ -34,10 +34,10 @@ export function createPageStory<PageId extends KcContext["pageId"]>(params: { pa
return (
<React.StrictMode>
<KcApp kcContext={kcContextMock} />
<KcPage kcContext={kcContextMock} />
</React.StrictMode>
);
}
return { PageStory };
return { KcPageStory };
}

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "code.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "code.ftl" });
const meta = {
title: "login/code.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "delete-account-confirm.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "delete-account-confirm.ftl" });
const meta = {
title: "login/delete-account-confirm.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "delete-credential.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "delete-credential.ftl" });
const meta = {
title: "login/delete-credential.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,25 +1,25 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "error.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "error.ftl" });
const meta = {
title: "login/error.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};
export const WithAnotherMessage: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
message: { summary: "With another error message" }
}}

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "frontchannel-logout.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "frontchannel-logout.ftl" });
const meta = {
title: "login/frontchannel-logout.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "idp-review-user-profile.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "idp-review-user-profile.ftl" });
const meta = {
title: "login/idp-review-user-profile.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,13 +1,13 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "info.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "info.ftl" });
const meta = {
title: "login/info.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
@ -15,7 +15,7 @@ type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
message: {
summary: "Server info message"
@ -27,7 +27,7 @@ export const Default: Story = {
export const WithLinkBack: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
message: {
summary: "Server message"
@ -40,7 +40,7 @@ export const WithLinkBack: Story = {
export const WithRequiredActions: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
message: {
summary: "Server message"

View File

@ -1,25 +1,25 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login.ftl" });
const meta = {
title: "login/login.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};
export const WithoutRegistration: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
realm: { registrationAllowed: false }
}}
@ -29,7 +29,7 @@ export const WithoutRegistration: Story = {
export const WithoutRememberMe: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
realm: { rememberMe: false }
}}
@ -39,7 +39,7 @@ export const WithoutRememberMe: Story = {
export const WithoutPasswordReset: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
realm: { resetPasswordAllowed: false }
}}
@ -49,7 +49,7 @@ export const WithoutPasswordReset: Story = {
export const WithEmailAsUsername: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
realm: { loginWithEmailAllowed: false }
}}
@ -59,7 +59,7 @@ export const WithEmailAsUsername: Story = {
export const WithPresetUsername: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
login: { username: "max.mustermann@mail.com" }
}}
@ -69,7 +69,7 @@ export const WithPresetUsername: Story = {
export const WithImmutablePresetUsername: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
auth: {
attemptedUsername: "max.mustermann@mail.com",
@ -87,7 +87,7 @@ export const WithImmutablePresetUsername: Story = {
export const WithSocialProviders: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
social: {
displayInfo: true,
@ -173,7 +173,7 @@ export const WithSocialProviders: Story = {
export const WithoutPasswordField: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
realm: { password: false }
}}

View File

@ -1,25 +1,25 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-config-totp.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-config-totp.ftl" });
const meta = {
title: "login/login-config-totp.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};
export const WithManualSetUp: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
mode: "manual"
}}
@ -29,7 +29,7 @@ export const WithManualSetUp: Story = {
export const WithError: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
messagesPerField: {
get: (fieldName: string) => (fieldName === "totp" ? "Invalid TOTP" : undefined),

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-oauth2-device-verify-user-code.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-oauth2-device-verify-user-code.ftl" });
const meta = {
title: "login/login-oauth2-device-verify-user-code.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-idp-link-confirm.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-idp-link-confirm.ftl" });
const meta = {
title: "login/login-idp-link-confirm.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-idp-link-email.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-idp-link-email.ftl" });
const meta = {
title: "login/login-idp-link-email.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-oauth2-device-verify-user-code.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-oauth2-device-verify-user-code.ftl" });
const meta = {
title: "login/login-oauth2-device-verify-user-code.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-oauth-grant.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-oauth-grant.ftl" });
const meta = {
title: "login/login-oauth-grant.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-otp.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-otp.ftl" });
const meta = {
title: "login/login-otp.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-page-expired.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-page-expired.ftl" });
const meta = {
title: "login/login-page-expired.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-password.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-password.ftl" });
const meta = {
title: "login/login-password.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-recovery-authn-code-config.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-recovery-authn-code-config.ftl" });
const meta = {
title: "login/login-recovery-authn-code-config.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-recovery-authn-code-input.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-recovery-authn-code-input.ftl" });
const meta = {
title: "login/login-recovery-authn-code-input.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-reset-otp.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-reset-otp.ftl" });
const meta = {
title: "login/login-reset-otp.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,25 +1,25 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-reset-password.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-reset-password.ftl" });
const meta = {
title: "login/login-reset-password.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};
export const WithEmailAsUsername: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
realm: {
loginWithEmailAllowed: true,

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-update-password.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-update-password.ftl" });
const meta = {
title: "login/login-update-password.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-update-profile.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-update-profile.ftl" });
const meta = {
title: "login/login-update-profile.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,25 +1,25 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-username.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-username.ftl" });
const meta = {
title: "login/login-username.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};
export const WithEmailAsUsername: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
realm: {
loginWithEmailAllowed: true,

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-verify-email.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-verify-email.ftl" });
const meta = {
title: "login/login-verify-email.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "login-x509-info.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "login-x509-info.ftl" });
const meta = {
title: "login/login-x509-info.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "logout-confirm.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "logout-confirm.ftl" });
const meta = {
title: "login/logout-confirm.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,25 +1,25 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "register.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "register.ftl" });
const meta = {
title: "login/register.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};
export const WithFieldError: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
profile: {
attributesByName: {
@ -41,7 +41,7 @@ export const WithFieldError: Story = {
export const WithEmailAsUsername: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
realm: {
registrationEmailAsUsername: true
@ -53,7 +53,7 @@ export const WithEmailAsUsername: Story = {
export const WithoutPassword: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
passwordRequired: false
}}
@ -63,7 +63,7 @@ export const WithoutPassword: Story = {
export const WithRecaptcha: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
scripts: ["https://www.google.com/recaptcha/api.js?hl=en"],
recaptchaRequired: true,
@ -75,7 +75,7 @@ export const WithRecaptcha: Story = {
export const WithRecaptchaFrench: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
locale: {
currentLanguageTag: "fr"
@ -90,7 +90,7 @@ export const WithRecaptchaFrench: Story = {
export const WithPresets: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
profile: {
attributesByName: {

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "saml-post-form.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "saml-post-form.ftl" });
const meta = {
title: "login/saml-post-form.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,25 +1,25 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "select-authenticator.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "select-authenticator.ftl" });
const meta = {
title: "login/select-authenticator.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};
export const WithDifferentAuthenticationMethods: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
auth: {
authenticationSelections: [

View File

@ -1,25 +1,25 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "terms.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "terms.ftl" });
const meta = {
title: "login/terms.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};
export const French: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
locale: {
currentLanguageTag: "fr"
@ -31,7 +31,7 @@ export const French: Story = {
export const Spanish: Story = {
render: () => (
<PageStory
<KcPageStory
kcContext={{
locale: {
currentLanguageTag: "es"

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "update-email.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "update-email.ftl" });
const meta = {
title: "login/update-email.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "webauthn-authenticate.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "webauthn-authenticate.ftl" });
const meta = {
title: "login/webauthn-authenticate.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "webauthn-error.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "webauthn-error.ftl" });
const meta = {
title: "login/webauthn-error.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};

View File

@ -1,18 +1,18 @@
import React from "react";
import type { Meta, StoryObj } from "@storybook/react";
import { createPageStory } from "../PageStory";
import { createKcPageStory } from "../KcPageStory";
const { PageStory } = createPageStory({ pageId: "webauthn-register.ftl" });
const { KcPageStory } = createKcPageStory({ pageId: "webauthn-register.ftl" });
const meta = {
title: "login/webauthn-register.ftl",
component: PageStory
} satisfies Meta<typeof PageStory>;
component: KcPageStory
} satisfies Meta<typeof KcPageStory>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
render: () => <PageStory />
render: () => <KcPageStory />
};