Fix auto enable themes when using start-keycloak

This commit is contained in:
Joseph Garrone 2025-01-05 04:26:45 +01:00
parent deaeab0f61
commit 7e7996e40c
4 changed files with 92 additions and 64 deletions

View File

@ -122,7 +122,17 @@ export async function buildJar(params: {
themes: await (async () => { themes: await (async () => {
const dirPath = pathJoin(tmpResourcesDirPath, "theme"); const dirPath = pathJoin(tmpResourcesDirPath, "theme");
const themeNames = await fs.readdir(dirPath); const themeNames = (await fs.readdir(dirPath)).sort(
(a, b) => {
const indexA = buildContext.themeNames.indexOf(a);
const indexB = buildContext.themeNames.indexOf(b);
const orderA = indexA === -1 ? Infinity : indexA;
const orderB = indexB === -1 ? Infinity : indexB;
return orderA - orderB;
}
);
return Promise.all( return Promise.all(
themeNames.map(async themeName => { themeNames.map(async themeName => {

View File

@ -1,28 +1,20 @@
import { assert } from "tsafe/assert"; import { assert } from "tsafe/assert";
import type { ParsedRealmJson } from "./ParsedRealmJson"; import type { ParsedRealmJson } from "./ParsedRealmJson";
import { getDefaultConfig } from "./defaultConfig"; import { getDefaultConfig } from "./defaultConfig";
import type { BuildContext } from "../../shared/buildContext"; import { TEST_APP_URL, type ThemeType, THEME_TYPES } from "../../shared/constants";
import { objectKeys } from "tsafe/objectKeys";
import { TEST_APP_URL } from "../../shared/constants";
import { sameFactory } from "evt/tools/inDepth/same"; import { sameFactory } from "evt/tools/inDepth/same";
export type BuildContextLike = {
themeNames: BuildContext["themeNames"];
implementedThemeTypes: BuildContext["implementedThemeTypes"];
};
assert<BuildContext extends BuildContextLike ? true : false>;
export function prepareRealmConfig(params: { export function prepareRealmConfig(params: {
parsedRealmJson: ParsedRealmJson; parsedRealmJson: ParsedRealmJson;
keycloakMajorVersionNumber: number; keycloakMajorVersionNumber: number;
buildContext: BuildContextLike; parsedKeycloakThemesJsonEntry: { name: string; types: (ThemeType | "email")[] };
}): { }): {
realmName: string; realmName: string;
clientName: string; clientName: string;
username: string; username: string;
} { } {
const { parsedRealmJson, keycloakMajorVersionNumber, buildContext } = params; const { parsedRealmJson, keycloakMajorVersionNumber, parsedKeycloakThemesJsonEntry } =
params;
const { username } = addOrEditTestUser({ const { username } = addOrEditTestUser({
parsedRealmJson, parsedRealmJson,
@ -38,8 +30,7 @@ export function prepareRealmConfig(params: {
enableCustomThemes({ enableCustomThemes({
parsedRealmJson, parsedRealmJson,
themeName: buildContext.themeNames[0], parsedKeycloakThemesJsonEntry
implementedThemeTypes: buildContext.implementedThemeTypes
}); });
enable_custom_events_listeners: { enable_custom_events_listeners: {
@ -63,17 +54,15 @@ export function prepareRealmConfig(params: {
function enableCustomThemes(params: { function enableCustomThemes(params: {
parsedRealmJson: ParsedRealmJson; parsedRealmJson: ParsedRealmJson;
themeName: string; parsedKeycloakThemesJsonEntry: { name: string; types: (ThemeType | "email")[] };
implementedThemeTypes: BuildContextLike["implementedThemeTypes"];
}) { }) {
const { parsedRealmJson, themeName, implementedThemeTypes } = params; const { parsedRealmJson, parsedKeycloakThemesJsonEntry } = params;
for (const themeType of objectKeys(implementedThemeTypes)) { for (const themeType of [...THEME_TYPES, "email"] as const) {
if (!implementedThemeTypes[themeType].isImplemented) { parsedRealmJson[`${themeType}Theme` as const] =
continue; !parsedKeycloakThemesJsonEntry.types.includes(themeType)
} ? ""
: parsedKeycloakThemesJsonEntry.name;
parsedRealmJson[`${themeType}Theme` as const] = themeName;
} }
} }

View File

@ -1,10 +1,7 @@
import type { BuildContext } from "../../shared/buildContext"; import type { BuildContext } from "../../shared/buildContext";
import { assert } from "tsafe/assert"; import { assert } from "tsafe/assert";
import { getDefaultConfig } from "./defaultConfig"; import { getDefaultConfig } from "./defaultConfig";
import { import { prepareRealmConfig } from "./prepareRealmConfig";
prepareRealmConfig,
type BuildContextLike as BuildContextLike_prepareRealmConfig
} from "./prepareRealmConfig";
import * as fs from "fs"; import * as fs from "fs";
import { import {
join as pathJoin, join as pathJoin,
@ -24,18 +21,19 @@ import {
} from "./dumpContainerConfig"; } from "./dumpContainerConfig";
import * as runExclusive from "run-exclusive"; import * as runExclusive from "run-exclusive";
import { waitForDebounceFactory } from "powerhooks/tools/waitForDebounce"; import { waitForDebounceFactory } from "powerhooks/tools/waitForDebounce";
import type { ThemeType } from "../../shared/constants";
import chalk from "chalk"; import chalk from "chalk";
export type BuildContextLike = BuildContextLike_dumpContainerConfig & export type BuildContextLike = BuildContextLike_dumpContainerConfig & {
BuildContextLike_prepareRealmConfig & { projectDirPath: string;
projectDirPath: string; };
};
assert<BuildContext extends BuildContextLike ? true : false>; assert<BuildContext extends BuildContextLike ? true : false>;
export async function getRealmConfig(params: { export async function getRealmConfig(params: {
keycloakMajorVersionNumber: number; keycloakMajorVersionNumber: number;
realmJsonFilePath_userProvided: string | undefined; realmJsonFilePath_userProvided: string | undefined;
parsedKeycloakThemesJsonEntry: { name: string; types: (ThemeType | "email")[] };
buildContext: BuildContextLike; buildContext: BuildContextLike;
}): Promise<{ }): Promise<{
realmJsonFilePath: string; realmJsonFilePath: string;
@ -44,8 +42,12 @@ export async function getRealmConfig(params: {
username: string; username: string;
onRealmConfigChange: () => Promise<void>; onRealmConfigChange: () => Promise<void>;
}> { }> {
const { keycloakMajorVersionNumber, realmJsonFilePath_userProvided, buildContext } = const {
params; keycloakMajorVersionNumber,
realmJsonFilePath_userProvided,
parsedKeycloakThemesJsonEntry,
buildContext
} = params;
const realmJsonFilePath = pathJoin( const realmJsonFilePath = pathJoin(
buildContext.projectDirPath, buildContext.projectDirPath,
@ -71,8 +73,8 @@ export async function getRealmConfig(params: {
const { clientName, realmName, username } = prepareRealmConfig({ const { clientName, realmName, username } = prepareRealmConfig({
parsedRealmJson, parsedRealmJson,
buildContext, keycloakMajorVersionNumber,
keycloakMajorVersionNumber parsedKeycloakThemesJsonEntry
}); });
{ {

View File

@ -4,7 +4,8 @@ import {
CONTAINER_NAME, CONTAINER_NAME,
KEYCLOAKIFY_SPA_DEV_SERVER_PORT, KEYCLOAKIFY_SPA_DEV_SERVER_PORT,
KEYCLOAKIFY_LOGIN_JAR_BASENAME, KEYCLOAKIFY_LOGIN_JAR_BASENAME,
TEST_APP_URL TEST_APP_URL,
ThemeType
} from "../shared/constants"; } from "../shared/constants";
import { SemVer } from "../tools/SemVer"; import { SemVer } from "../tools/SemVer";
import { assert, type Equals } from "tsafe/assert"; import { assert, type Equals } from "tsafe/assert";
@ -34,6 +35,7 @@ import { startViteDevServer } from "./startViteDevServer";
import { getSupportedKeycloakMajorVersions } from "./realmConfig/defaultConfig"; import { getSupportedKeycloakMajorVersions } from "./realmConfig/defaultConfig";
import { getSupportedDockerImageTags } from "./getSupportedDockerImageTags"; import { getSupportedDockerImageTags } from "./getSupportedDockerImageTags";
import { getRealmConfig } from "./realmConfig"; import { getRealmConfig } from "./realmConfig";
import { id } from "tsafe/id";
export async function command(params: { export async function command(params: {
buildContext: BuildContext; buildContext: BuildContext;
@ -270,32 +272,6 @@ export async function command(params: {
return wrap.majorVersionNumber; return wrap.majorVersionNumber;
})(); })();
const { clientName, onRealmConfigChange, realmJsonFilePath, realmName, username } =
await getRealmConfig({
keycloakMajorVersionNumber,
realmJsonFilePath_userProvided: await (async () => {
if (cliCommandOptions.realmJsonFilePath !== undefined) {
return getAbsoluteAndInOsFormatPath({
pathIsh: cliCommandOptions.realmJsonFilePath,
cwd: process.cwd()
});
}
if (buildContext.startKeycloakOptions.realmJsonFilePath !== undefined) {
assert(
await existsAsync(
buildContext.startKeycloakOptions.realmJsonFilePath
),
`${pathRelative(process.cwd(), buildContext.startKeycloakOptions.realmJsonFilePath)} does not exist`
);
return buildContext.startKeycloakOptions.realmJsonFilePath;
}
return undefined;
})(),
buildContext
});
{ {
const { isAppBuildSuccess } = await appBuild({ const { isAppBuildSuccess } = await appBuild({
buildContext buildContext
@ -376,10 +352,24 @@ export async function command(params: {
)) ))
]; ];
let parsedKeycloakThemesJson = id<
{ themes: { name: string; types: (ThemeType | "email")[] }[] } | undefined
>(undefined);
async function extractThemeResourcesFromJar() { async function extractThemeResourcesFromJar() {
await extractArchive({ await extractArchive({
archiveFilePath: jarFilePath, archiveFilePath: jarFilePath,
onArchiveFile: async ({ relativeFilePathInArchive, writeFile }) => { onArchiveFile: async ({ relativeFilePathInArchive, writeFile, readFile }) => {
if (
relativeFilePathInArchive ===
pathJoin("META-INF", "keycloak-themes.json") &&
parsedKeycloakThemesJson === undefined
) {
parsedKeycloakThemesJson = JSON.parse(
(await readFile()).toString("utf8")
);
}
if (isInside({ dirPath: "theme", filePath: relativeFilePathInArchive })) { if (isInside({ dirPath: "theme", filePath: relativeFilePathInArchive })) {
await writeFile({ await writeFile({
filePath: pathJoin( filePath: pathJoin(
@ -401,6 +391,43 @@ export async function command(params: {
await extractThemeResourcesFromJar(); await extractThemeResourcesFromJar();
assert(parsedKeycloakThemesJson !== undefined);
const { clientName, onRealmConfigChange, realmJsonFilePath, realmName, username } =
await getRealmConfig({
keycloakMajorVersionNumber,
parsedKeycloakThemesJsonEntry: (() => {
const entry = parsedKeycloakThemesJson.themes.find(
({ name }) => name === buildContext.themeNames[0]
);
assert(entry !== undefined);
return entry;
})(),
realmJsonFilePath_userProvided: await (async () => {
if (cliCommandOptions.realmJsonFilePath !== undefined) {
return getAbsoluteAndInOsFormatPath({
pathIsh: cliCommandOptions.realmJsonFilePath,
cwd: process.cwd()
});
}
if (buildContext.startKeycloakOptions.realmJsonFilePath !== undefined) {
assert(
await existsAsync(
buildContext.startKeycloakOptions.realmJsonFilePath
),
`${pathRelative(process.cwd(), buildContext.startKeycloakOptions.realmJsonFilePath)} does not exist`
);
return buildContext.startKeycloakOptions.realmJsonFilePath;
}
return undefined;
})(),
buildContext
});
const jarFilePath_cacheDir = pathJoin( const jarFilePath_cacheDir = pathJoin(
buildContext.cacheDirPath, buildContext.cacheDirPath,
pathBasename(jarFilePath) pathBasename(jarFilePath)