#354: Feature theme variant

This commit is contained in:
garronej 2023-06-08 23:09:14 +02:00
parent 69c3befb2d
commit ed48669ae1
11 changed files with 65 additions and 28 deletions

View File

@ -8,6 +8,7 @@ export declare namespace KcContext {
export type Common = { export type Common = {
keycloakifyVersion: string; keycloakifyVersion: string;
themeType: "account"; themeType: "account";
themeName: string;
locale?: { locale?: {
supported: { supported: {
url: string; url: string;

View File

@ -9,6 +9,7 @@ const PUBLIC_URL = process.env["PUBLIC_URL"] ?? "/";
export const kcContextCommonMock: KcContext.Common = { export const kcContextCommonMock: KcContext.Common = {
"keycloakifyVersion": "0.0.0", "keycloakifyVersion": "0.0.0",
"themeType": "account", "themeType": "account",
"themeName": "my-theme-name",
"url": { "url": {
"resourcesPath": pathJoin(PUBLIC_URL, resourcesDirPathRelativeToPublicDir), "resourcesPath": pathJoin(PUBLIC_URL, resourcesDirPathRelativeToPublicDir),
"resourcesCommonPath": pathJoin(PUBLIC_URL, resourcesCommonDirPathRelativeToPublicDir), "resourcesCommonPath": pathJoin(PUBLIC_URL, resourcesCommonDirPathRelativeToPublicDir),

View File

@ -16,6 +16,7 @@ export namespace BuildOptions {
isSilent: boolean; isSilent: boolean;
themeVersion: string; themeVersion: string;
themeName: string; themeName: string;
extraThemeNames: string[];
extraLoginPages: string[] | undefined; extraLoginPages: string[] | undefined;
extraAccountPages: string[] | undefined; extraAccountPages: string[] | undefined;
extraThemeProperties?: string[]; extraThemeProperties?: string[];
@ -108,8 +109,17 @@ export function readBuildOptions(params: { projectDirPath: string; processArgv:
const common: BuildOptions.Common = (() => { const common: BuildOptions.Common = (() => {
const { name, keycloakify = {}, version, homepage } = parsedPackageJson; const { name, keycloakify = {}, version, homepage } = parsedPackageJson;
const { extraPages, extraLoginPages, extraAccountPages, extraThemeProperties, groupId, artifactId, bundler, keycloakVersionDefaultAssets } = const {
keycloakify ?? {}; extraPages,
extraLoginPages,
extraAccountPages,
extraThemeProperties,
groupId,
artifactId,
bundler,
keycloakVersionDefaultAssets,
extraThemeNames = []
} = keycloakify ?? {};
const themeName = const themeName =
keycloakify.themeName ?? keycloakify.themeName ??
@ -120,6 +130,7 @@ export function readBuildOptions(params: { projectDirPath: string; processArgv:
return { return {
themeName, themeName,
extraThemeNames,
"bundler": (() => { "bundler": (() => {
const { KEYCLOAKIFY_BUNDLER } = process.env; const { KEYCLOAKIFY_BUNDLER } = process.env;

View File

@ -122,6 +122,7 @@
out["keycloakifyVersion"] = "KEYCLOAKIFY_VERSION_xEdKd3xEdr"; out["keycloakifyVersion"] = "KEYCLOAKIFY_VERSION_xEdKd3xEdr";
out["themeVersion"] = "KEYCLOAKIFY_THEME_VERSION_sIgKd3xEdr3dx"; out["themeVersion"] = "KEYCLOAKIFY_THEME_VERSION_sIgKd3xEdr3dx";
out["themeType"] = "KEYCLOAKIFY_THEME_TYPE_dExKd3xEdr"; out["themeType"] = "KEYCLOAKIFY_THEME_TYPE_dExKd3xEdr";
out["themeName"] = "KEYCLOAKIFY_THEME_NAME_cXxKd3xEer";
out["pageId"] = "${pageId}"; out["pageId"] = "${pageId}";
return out; return out;

View File

@ -17,6 +17,7 @@ export type BuildOptionsLike = BuildOptionsLike.Standalone | BuildOptionsLike.Ex
export namespace BuildOptionsLike { export namespace BuildOptionsLike {
export type Common = { export type Common = {
themeName: string;
customUserAttributes: string[]; customUserAttributes: string[];
themeVersion: string; themeVersion: string;
}; };
@ -134,7 +135,8 @@ export function generateFtlFilesCodeFactory(params: {
) )
.replace("KEYCLOAKIFY_VERSION_xEdKd3xEdr", keycloakifyVersion) .replace("KEYCLOAKIFY_VERSION_xEdKd3xEdr", keycloakifyVersion)
.replace("KEYCLOAKIFY_THEME_VERSION_sIgKd3xEdr3dx", buildOptions.themeVersion) .replace("KEYCLOAKIFY_THEME_VERSION_sIgKd3xEdr3dx", buildOptions.themeVersion)
.replace("KEYCLOAKIFY_THEME_TYPE_dExKd3xEdr", themeType), .replace("KEYCLOAKIFY_THEME_TYPE_dExKd3xEdr", themeType)
.replace("KEYCLOAKIFY_THEME_NAME_cXxKd3xEer", buildOptions.themeName),
"<!-- xIdLqMeOedErIdLsPdNdI9dSlxI -->": [ "<!-- xIdLqMeOedErIdLsPdNdI9dSlxI -->": [
"<#if scripts??>", "<#if scripts??>",
" <#list scripts as script>", " <#list scripts as script>",

View File

@ -7,6 +7,7 @@ import type { BuildOptions } from "./BuildOptions";
export type BuildOptionsLike = { export type BuildOptionsLike = {
themeName: string; themeName: string;
extraThemeNames: string[];
groupId: string; groupId: string;
artifactId?: string; artifactId?: string;
themeVersion: string; themeVersion: string;
@ -26,7 +27,7 @@ export function generateJavaStackFiles(params: {
jarFilePath: string; jarFilePath: string;
} { } {
const { const {
buildOptions: { groupId, themeName, themeVersion, artifactId }, buildOptions: { groupId, themeName, extraThemeNames, themeVersion, artifactId },
keycloakThemeBuildingDirPath, keycloakThemeBuildingDirPath,
doBundlesEmailTemplate doBundlesEmailTemplate
} = params; } = params;
@ -67,12 +68,12 @@ export function generateJavaStackFiles(params: {
Buffer.from( Buffer.from(
JSON.stringify( JSON.stringify(
{ {
"themes": [ "themes": [themeName, ...extraThemeNames].map(themeName => [
{ {
"name": themeName, "name": themeName,
"types": [...themeTypes, ...(doBundlesEmailTemplate ? ["email"] : [])] "types": [...themeTypes, ...(doBundlesEmailTemplate ? ["email"] : [])]
} }
] ])
}, },
null, null,
2 2

View File

@ -6,6 +6,7 @@ import type { BuildOptions } from "./BuildOptions";
export type BuildOptionsLike = { export type BuildOptionsLike = {
themeName: string; themeName: string;
extraThemeNames: string[];
}; };
{ {
@ -27,11 +28,9 @@ export function generateStartKeycloakTestingContainer(params: {
const { const {
keycloakThemeBuildingDirPath, keycloakThemeBuildingDirPath,
keycloakVersion, keycloakVersion,
buildOptions: { themeName } buildOptions: { themeName, extraThemeNames }
} = params; } = params;
const keycloakThemePath = pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName).replace(/\\/g, "/");
fs.writeFileSync( fs.writeFileSync(
pathJoin(keycloakThemeBuildingDirPath, generateStartKeycloakTestingContainer.basename), pathJoin(keycloakThemeBuildingDirPath, generateStartKeycloakTestingContainer.basename),
@ -49,7 +48,13 @@ export function generateStartKeycloakTestingContainer(params: {
" -e KEYCLOAK_ADMIN=admin \\", " -e KEYCLOAK_ADMIN=admin \\",
" -e KEYCLOAK_ADMIN_PASSWORD=admin \\", " -e KEYCLOAK_ADMIN_PASSWORD=admin \\",
" -e JAVA_OPTS=-Dkeycloak.profile=preview \\", " -e JAVA_OPTS=-Dkeycloak.profile=preview \\",
` -v "${keycloakThemePath}":"/opt/keycloak/themes/${themeName}":rw \\`, ...[themeName, ...extraThemeNames].map(
themeName =>
` -v "${pathJoin(keycloakThemeBuildingDirPath, "src", "main", "resources", "theme", themeName).replace(
/\\/g,
"/"
)}":"/opt/keycloak/themes/${themeName}":rw \\`
),
` -it quay.io/keycloak/keycloak:${keycloakVersion} \\`, ` -it quay.io/keycloak/keycloak:${keycloakVersion} \\`,
` start-dev`, ` start-dev`,
"" ""

View File

@ -23,27 +23,38 @@ export async function main() {
const logger = getLogger({ "isSilent": buildOptions.isSilent }); const logger = getLogger({ "isSilent": buildOptions.isSilent });
logger.log("🔏 Building the keycloak theme...⌚"); logger.log("🔏 Building the keycloak theme...⌚");
const { doBundlesEmailTemplate } = await generateTheme({ let doBundlesEmailTemplate: boolean | undefined;
keycloakThemeBuildingDirPath: buildOptions.keycloakifyBuildDirPath,
"emailThemeSrcDirPath": (() => {
const { emailThemeSrcDirPath } = getEmailThemeSrcDirPath({ projectDirPath });
if (emailThemeSrcDirPath === undefined || !fs.existsSync(emailThemeSrcDirPath)) { for (const themeName of [buildOptions.themeName, ...buildOptions.extraThemeNames]) {
return; const { doBundlesEmailTemplate: doBundlesEmailTemplate_ } = await generateTheme({
} keycloakThemeBuildingDirPath: buildOptions.keycloakifyBuildDirPath,
"emailThemeSrcDirPath": (() => {
const { emailThemeSrcDirPath } = getEmailThemeSrcDirPath({ projectDirPath });
return emailThemeSrcDirPath; if (emailThemeSrcDirPath === undefined || !fs.existsSync(emailThemeSrcDirPath)) {
})(), return;
"reactAppBuildDirPath": buildOptions.reactAppBuildDirPath, }
buildOptions,
"keycloakifyVersion": (() => {
const version = JSON.parse(fs.readFileSync(pathJoin(getProjectRoot(), "package.json")).toString("utf8"))["version"];
assert(typeof version === "string"); return emailThemeSrcDirPath;
})(),
"reactAppBuildDirPath": buildOptions.reactAppBuildDirPath,
"buildOptions": {
...buildOptions,
"themeName": themeName
},
"keycloakifyVersion": (() => {
const version = JSON.parse(fs.readFileSync(pathJoin(getProjectRoot(), "package.json")).toString("utf8"))["version"];
return version; assert(typeof version === "string");
})()
}); return version;
})()
});
doBundlesEmailTemplate ??= doBundlesEmailTemplate_;
}
assert(doBundlesEmailTemplate !== undefined);
const { jarFilePath } = generateJavaStackFiles({ const { jarFilePath } = generateJavaStackFiles({
keycloakThemeBuildingDirPath: buildOptions.keycloakifyBuildDirPath, keycloakThemeBuildingDirPath: buildOptions.keycloakifyBuildDirPath,

View File

@ -25,6 +25,7 @@ export type ParsedPackageJson = {
keycloakifyBuildDirPath?: string; keycloakifyBuildDirPath?: string;
customUserAttributes?: string[]; customUserAttributes?: string[];
themeName?: string; themeName?: string;
extraThemeNames?: string[];
}; };
}; };
@ -46,7 +47,8 @@ export const zParsedPackageJson = z.object({
"reactAppBuildDirPath": z.string().optional(), "reactAppBuildDirPath": z.string().optional(),
"keycloakifyBuildDirPath": z.string().optional(), "keycloakifyBuildDirPath": z.string().optional(),
"customUserAttributes": z.array(z.string()).optional(), "customUserAttributes": z.array(z.string()).optional(),
"themeName": z.string().optional() "themeName": z.string().optional(),
"extraThemeNames": z.array(z.string()).optional()
}) })
.optional() .optional()
}); });

View File

@ -39,6 +39,7 @@ export declare namespace KcContext {
export type Common = { export type Common = {
keycloakifyVersion: string; keycloakifyVersion: string;
themeType: "login"; themeType: "login";
themeName: string;
url: { url: {
loginAction: string; loginAction: string;
resourcesPath: string; resourcesPath: string;

View File

@ -105,6 +105,7 @@ const attributesByName = Object.fromEntries(attributes.map(attribute => [attribu
export const kcContextCommonMock: KcContext.Common = { export const kcContextCommonMock: KcContext.Common = {
"keycloakifyVersion": "0.0.0", "keycloakifyVersion": "0.0.0",
"themeType": "login", "themeType": "login",
"themeName": "my-theme-name",
"url": { "url": {
"loginAction": "#", "loginAction": "#",
"resourcesPath": pathJoin(PUBLIC_URL, resourcesDirPathRelativeToPublicDir), "resourcesPath": pathJoin(PUBLIC_URL, resourcesDirPathRelativeToPublicDir),