diff --git a/scripts/generate-i18n-messages.ts b/scripts/generate-i18n-messages.ts index a50ff2e6..e6fc3104 100644 --- a/scripts/generate-i18n-messages.ts +++ b/scripts/generate-i18n-messages.ts @@ -37,7 +37,7 @@ async function generateI18nMessages() { const record: { [themeType: string]: { [language: string]: Dictionary } } = {}; - for (const themeType of THEME_TYPES) { + for (const themeType of THEME_TYPES.filter(themeType => themeType !== "admin")) { const { extractedDirPath } = await downloadKeycloakDefaultTheme({ keycloakVersionId: (() => { switch (themeType) { diff --git a/src/bin/add-story.ts b/src/bin/add-story.ts index 66ab40ff..dc528a5e 100644 --- a/src/bin/add-story.ts +++ b/src/bin/add-story.ts @@ -5,8 +5,7 @@ import { ACCOUNT_THEME_PAGE_IDS, type LoginThemePageId, type AccountThemePageId, - THEME_TYPES, - type ThemeType + THEME_TYPES } from "./shared/constants"; import { capitalize } from "tsafe/capitalize"; import * as fs from "fs"; @@ -39,6 +38,8 @@ export async function command(params: { buildContext: BuildContext }) { return buildContext.implementedThemeTypes.account.isImplemented; case "login": return buildContext.implementedThemeTypes.login.isImplemented; + case "admin": + return buildContext.implementedThemeTypes.admin.isImplemented; } assert>(false); }); @@ -49,7 +50,7 @@ export async function command(params: { buildContext: BuildContext }) { return values[0]; } - const { value } = await cliSelect({ + const { value } = await cliSelect({ values }).catch(() => { process.exit(-1); @@ -68,6 +69,16 @@ export async function command(params: { buildContext: BuildContext }) { ); process.exit(0); + return; + } + + if (themeType === "admin") { + console.log( + `${chalk.red("✗")} Sorry, there is no Storybook support for the Account UI.` + ); + + process.exit(0); + return; } console.log(`→ ${themeType}`); diff --git a/src/bin/eject-page.ts b/src/bin/eject-page.ts index 2cb2d9af..279f03e1 100644 --- a/src/bin/eject-page.ts +++ b/src/bin/eject-page.ts @@ -7,8 +7,7 @@ import { ACCOUNT_THEME_PAGE_IDS, type LoginThemePageId, type AccountThemePageId, - THEME_TYPES, - type ThemeType + THEME_TYPES } from "./shared/constants"; import { capitalize } from "tsafe/capitalize"; import * as fs from "fs"; @@ -46,6 +45,8 @@ export async function command(params: { buildContext: BuildContext }) { return buildContext.implementedThemeTypes.account.isImplemented; case "login": return buildContext.implementedThemeTypes.login.isImplemented; + case "admin": + return buildContext.implementedThemeTypes.admin.isImplemented; } assert>(false); }); @@ -56,7 +57,7 @@ export async function command(params: { buildContext: BuildContext }) { return values[0]; } - const { value } = await cliSelect({ + const { value } = await cliSelect({ values }).catch(() => { process.exit(-1); @@ -66,21 +67,22 @@ export async function command(params: { buildContext: BuildContext }) { })(); if ( - themeType === "account" && - (assert(buildContext.implementedThemeTypes.account.isImplemented), - buildContext.implementedThemeTypes.account.type === "Single-Page") + themeType === "admin" || + (themeType === "account" && + (assert(buildContext.implementedThemeTypes.account.isImplemented), + buildContext.implementedThemeTypes.account.type === "Single-Page")) ) { const srcDirPath = pathJoin( pathDirname(buildContext.packageJsonFilePath), "node_modules", "@keycloakify", - "keycloak-account-ui", + `keycloak-${themeType}-ui`, "src" ); console.log( [ - `There isn't an interactive CLI to eject components of the Single-Page Account theme.`, + `There isn't an interactive CLI to eject components of the ${themeType} UI.`, `You can however copy paste into your codebase the any file or directory from the following source directory:`, ``, `${chalk.bold(pathJoin(pathRelative(process.cwd(), srcDirPath)))}`, @@ -89,7 +91,8 @@ export async function command(params: { buildContext: BuildContext }) { ); eject_entrypoint: { - const kcAccountUiTsxFileRelativePath = "KcAccountUi.tsx"; + const kcAccountUiTsxFileRelativePath = + `Kc${capitalize(themeType)}Ui.tsx` as const; const accountThemeSrcDirPath = pathJoin( buildContext.themeSrcDirPath, @@ -120,7 +123,7 @@ export async function command(params: { buildContext: BuildContext }) { ).replace(/.tsx$/, ""); const modifiedKcPageTsxCode = kcPageTsxCode.replace( - `@keycloakify/keycloak-account-ui/${componentName}`, + `@keycloakify/keycloak-${themeType}-ui/${componentName}`, `./${componentName}` ); @@ -146,6 +149,7 @@ export async function command(params: { buildContext: BuildContext }) { } process.exit(0); + return; } console.log(`→ ${themeType}`); diff --git a/src/bin/initialize-account-theme/initialize-account-theme.ts b/src/bin/initialize-account-theme/initialize-account-theme.ts index dd7c61c8..0caead70 100644 --- a/src/bin/initialize-account-theme/initialize-account-theme.ts +++ b/src/bin/initialize-account-theme/initialize-account-theme.ts @@ -1,12 +1,12 @@ import type { BuildContext } from "../shared/buildContext"; import cliSelect from "cli-select"; -import child_process from "child_process"; import chalk from "chalk"; import { join as pathJoin, relative as pathRelative } from "path"; import * as fs from "fs"; import { updateAccountThemeImplementationInConfig } from "./updateAccountThemeImplementationInConfig"; import { command as updateKcGenCommand } from "../update-kc-gen"; import { maybeDelegateCommandToCustomHandler } from "../shared/customHandler_delegate"; +import { exitIfUncommittedChanges } from "../shared/exitIfUncommittedChanges"; export async function command(params: { buildContext: BuildContext }) { const { buildContext } = params; @@ -38,37 +38,9 @@ export async function command(params: { buildContext: BuildContext }) { process.exit(-1); } - exit_if_uncommitted_changes: { - let hasUncommittedChanges: boolean | undefined = undefined; - - try { - hasUncommittedChanges = - child_process - .execSync(`git status --porcelain`, { - cwd: buildContext.projectDirPath - }) - .toString() - .trim() !== ""; - } catch { - // Probably not a git repository - break exit_if_uncommitted_changes; - } - - if (!hasUncommittedChanges) { - break exit_if_uncommitted_changes; - } - console.warn( - [ - chalk.red( - "Please commit or stash your changes before running this command.\n" - ), - "This command will modify your project's files so it's better to have a clean working directory", - "so that you can easily see what has been changed and revert if needed." - ].join(" ") - ); - - process.exit(-1); - } + exitIfUncommittedChanges({ + projectDirPath: buildContext.projectDirPath + }); const { value: accountThemeType } = await cliSelect({ values: ["Single-Page" as const, "Multi-Page" as const] diff --git a/src/bin/initialize-admin-theme/copyBoilerplate.ts b/src/bin/initialize-admin-theme/copyBoilerplate.ts new file mode 100644 index 00000000..f2e6e7ca --- /dev/null +++ b/src/bin/initialize-admin-theme/copyBoilerplate.ts @@ -0,0 +1,19 @@ +import * as fs from "fs"; +import { join as pathJoin } from "path"; +import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath"; + +export function copyBoilerplate(params: { adminThemeSrcDirPath: string }) { + const { adminThemeSrcDirPath } = params; + + fs.cpSync( + pathJoin( + getThisCodebaseRootDirPath(), + "src", + "bin", + "initialize-admin-theme", + "src" + ), + adminThemeSrcDirPath, + { recursive: true } + ); +} diff --git a/src/bin/initialize-admin-theme/index.ts b/src/bin/initialize-admin-theme/index.ts new file mode 100644 index 00000000..b229b5f4 --- /dev/null +++ b/src/bin/initialize-admin-theme/index.ts @@ -0,0 +1 @@ +export * from "./initialize-admin-theme"; diff --git a/src/bin/initialize-admin-theme/initialize-admin-theme.ts b/src/bin/initialize-admin-theme/initialize-admin-theme.ts new file mode 100644 index 00000000..e6ba503b --- /dev/null +++ b/src/bin/initialize-admin-theme/initialize-admin-theme.ts @@ -0,0 +1,60 @@ +import type { BuildContext } from "../shared/buildContext"; +import chalk from "chalk"; +import { join as pathJoin, relative as pathRelative } from "path"; +import * as fs from "fs"; +import { command as updateKcGenCommand } from "../update-kc-gen"; +import { maybeDelegateCommandToCustomHandler } from "../shared/customHandler_delegate"; +import { exitIfUncommittedChanges } from "../shared/exitIfUncommittedChanges"; +import { initializeAdminTheme } from "./initializeAdminTheme"; + +export async function command(params: { buildContext: BuildContext }) { + const { buildContext } = params; + + const { hasBeenHandled } = maybeDelegateCommandToCustomHandler({ + commandName: "initialize-admin-theme", + buildContext + }); + + if (hasBeenHandled) { + return; + } + + const adminThemeSrcDirPath = pathJoin(buildContext.themeSrcDirPath, "admin"); + + if ( + fs.existsSync(adminThemeSrcDirPath) && + fs.readdirSync(adminThemeSrcDirPath).length > 0 + ) { + console.warn( + chalk.red( + `There is already a ${pathRelative( + process.cwd(), + adminThemeSrcDirPath + )} directory in your project. Aborting.` + ) + ); + + process.exit(-1); + } + + exitIfUncommittedChanges({ + projectDirPath: buildContext.projectDirPath + }); + + await initializeAdminTheme({ + adminThemeSrcDirPath, + buildContext + }); + + await updateKcGenCommand({ + buildContext: { + ...buildContext, + implementedThemeTypes: { + ...buildContext.implementedThemeTypes, + admin: { + isImplemented: true + } + } + } + }); +} diff --git a/src/bin/initialize-admin-theme/initializeAdminTheme.ts b/src/bin/initialize-admin-theme/initializeAdminTheme.ts new file mode 100644 index 00000000..8498eefa --- /dev/null +++ b/src/bin/initialize-admin-theme/initializeAdminTheme.ts @@ -0,0 +1,150 @@ +import { join as pathJoin, relative as pathRelative, dirname as pathDirname } from "path"; +import type { BuildContext } from "../shared/buildContext"; +import * as fs from "fs"; +import chalk from "chalk"; +import { + getLatestsSemVersionedTag, + type BuildContextLike as BuildContextLike_getLatestsSemVersionedTag +} from "../shared/getLatestsSemVersionedTag"; +import { SemVer } from "../tools/SemVer"; +import fetch from "make-fetch-happen"; +import { z } from "zod"; +import { assert, type Equals } from "tsafe/assert"; +import { is } from "tsafe/is"; +import { id } from "tsafe/id"; +import { npmInstall } from "../tools/npmInstall"; +import { copyBoilerplate } from "./copyBoilerplate"; +import { getThisCodebaseRootDirPath } from "../tools/getThisCodebaseRootDirPath"; + +type BuildContextLike = BuildContextLike_getLatestsSemVersionedTag & { + fetchOptions: BuildContext["fetchOptions"]; + packageJsonFilePath: string; +}; + +assert(); + +export async function initializeAdminTheme(params: { + adminThemeSrcDirPath: string; + buildContext: BuildContextLike; +}) { + const { adminThemeSrcDirPath, buildContext } = params; + + const OWNER = "keycloakify"; + const REPO = "keycloak-admin-ui"; + + const [semVersionedTag] = await getLatestsSemVersionedTag({ + owner: OWNER, + repo: REPO, + count: 1, + doIgnoreReleaseCandidates: false, + buildContext + }); + + const dependencies = await fetch( + `https://raw.githubusercontent.com/${OWNER}/${REPO}/${semVersionedTag.tag}/dependencies.gen.json`, + buildContext.fetchOptions + ) + .then(r => r.json()) + .then( + (() => { + type Dependencies = { + dependencies: Record; + devDependencies?: Record; + }; + + const zDependencies = (() => { + type TargetType = Dependencies; + + const zTargetType = z.object({ + dependencies: z.record(z.string()), + devDependencies: z.record(z.string()).optional() + }); + + assert, TargetType>>(); + + return id>(zTargetType); + })(); + + return o => zDependencies.parse(o); + })() + ); + + dependencies.dependencies["@keycloakify/keycloak-admin-ui"] = SemVer.stringify( + semVersionedTag.version + ); + + const parsedPackageJson = (() => { + type ParsedPackageJson = { + dependencies?: Record; + devDependencies?: Record; + }; + + const zParsedPackageJson = (() => { + type TargetType = ParsedPackageJson; + + const zTargetType = z.object({ + dependencies: z.record(z.string()).optional(), + devDependencies: z.record(z.string()).optional() + }); + + assert, TargetType>>(); + + return id>(zTargetType); + })(); + const parsedPackageJson = JSON.parse( + fs.readFileSync(buildContext.packageJsonFilePath).toString("utf8") + ); + + zParsedPackageJson.parse(parsedPackageJson); + + assert(is(parsedPackageJson)); + + return parsedPackageJson; + })(); + + parsedPackageJson.dependencies = { + ...parsedPackageJson.dependencies, + ...dependencies.dependencies + }; + + parsedPackageJson.devDependencies = { + ...parsedPackageJson.devDependencies, + ...dependencies.devDependencies + }; + + if (Object.keys(parsedPackageJson.devDependencies).length === 0) { + delete parsedPackageJson.devDependencies; + } + + fs.writeFileSync( + buildContext.packageJsonFilePath, + JSON.stringify(parsedPackageJson, undefined, 4) + ); + + run_npm_install: { + if ( + JSON.parse( + fs + .readFileSync(pathJoin(getThisCodebaseRootDirPath(), "package.json")) + .toString("utf8") + )["version"] === "0.0.0" + ) { + //NOTE: Linked version + break run_npm_install; + } + + npmInstall({ packageJsonDirPath: pathDirname(buildContext.packageJsonFilePath) }); + } + + copyBoilerplate({ adminThemeSrcDirPath }); + + console.log( + [ + chalk.green("The Admin theme has been successfully initialized."), + `Using Admin UI of Keycloak version: ${chalk.bold(semVersionedTag.tag.split("-")[0])}`, + `Directory created: ${chalk.bold(pathRelative(process.cwd(), adminThemeSrcDirPath))}`, + `Dependencies added to your project's package.json: `, + chalk.bold(JSON.stringify(dependencies, null, 2)) + ].join("\n") + ); +} diff --git a/src/bin/initialize-admin-theme/src/KcContext.ts b/src/bin/initialize-admin-theme/src/KcContext.ts new file mode 100644 index 00000000..e86dc980 --- /dev/null +++ b/src/bin/initialize-admin-theme/src/KcContext.ts @@ -0,0 +1,7 @@ +import type { KcContextLike } from "@keycloakify/keycloak-admin-ui"; +import type { KcEnvName } from "../kc.gen"; + +export type KcContext = KcContextLike & { + themeType: "admin"; + properties: Record; +}; diff --git a/src/bin/initialize-admin-theme/src/KcPage.tsx b/src/bin/initialize-admin-theme/src/KcPage.tsx new file mode 100644 index 00000000..f5f08f1f --- /dev/null +++ b/src/bin/initialize-admin-theme/src/KcPage.tsx @@ -0,0 +1,11 @@ +import { lazy } from "react"; +import { KcAdminUiLoader } from "@keycloakify/keycloak-admin-ui"; +import type { KcContext } from "./KcContext"; + +const KcAdminUi = lazy(() => import("@keycloakify/keycloak-admin-ui/KcAdminUi")); + +export default function KcPage(props: { kcContext: KcContext }) { + const { kcContext } = props; + + return ; +} diff --git a/src/bin/keycloakify/generateResources/generateMessageProperties.ts b/src/bin/keycloakify/generateResources/generateMessageProperties.ts index fc65b2fa..7ccd3003 100644 --- a/src/bin/keycloakify/generateResources/generateMessageProperties.ts +++ b/src/bin/keycloakify/generateResources/generateMessageProperties.ts @@ -22,7 +22,7 @@ assert(); export function generateMessageProperties(params: { buildContext: BuildContextLike; - themeType: ThemeType; + themeType: Exclude; }): { languageTags: string[]; writeMessagePropertiesFiles: (params: { diff --git a/src/bin/keycloakify/generateResources/generateResources.ts b/src/bin/keycloakify/generateResources/generateResources.ts index b56878a2..d549967a 100644 --- a/src/bin/keycloakify/generateResources/generateResources.ts +++ b/src/bin/keycloakify/generateResources/generateResources.ts @@ -19,7 +19,8 @@ import { type ThemeType, LOGIN_THEME_PAGE_IDS, ACCOUNT_THEME_PAGE_IDS, - WELL_KNOWN_DIRECTORY_BASE_NAME + WELL_KNOWN_DIRECTORY_BASE_NAME, + THEME_TYPES } from "../../shared/constants"; import { assert, type Equals } from "tsafe/assert"; import { readFieldNameUsage } from "./readFieldNameUsage"; @@ -78,15 +79,29 @@ export async function generateResources(params: { Record void> > = {}; - for (const themeType of ["login", "account"] as const) { + for (const themeType of THEME_TYPES) { if (!buildContext.implementedThemeTypes[themeType].isImplemented) { continue; } - const isForAccountSpa = - themeType === "account" && - (assert(buildContext.implementedThemeTypes.account.isImplemented), - buildContext.implementedThemeTypes.account.type === "Single-Page"); + const getAccountThemeType = () => { + assert(themeType === "account"); + + assert(buildContext.implementedThemeTypes.account.isImplemented); + + return buildContext.implementedThemeTypes.account.type; + }; + + const isSpa = (() => { + switch (themeType) { + case "login": + return false; + case "account": + return getAccountThemeType() === "Single-Page"; + case "admin": + return true; + } + })(); const themeTypeDirPath = getThemeTypeDirPath({ themeName, themeType }); @@ -101,7 +116,7 @@ export async function generateResources(params: { rmSync(destDirPath, { recursive: true, force: true }); if ( - themeType === "account" && + themeType !== "login" && buildContext.implementedThemeTypes.login.isImplemented ) { // NOTE: We prevent doing it twice, it has been done for the login theme. @@ -194,10 +209,14 @@ export async function generateResources(params: { case "login": return LOGIN_THEME_PAGE_IDS; case "account": - return isForAccountSpa ? ["index.ftl"] : ACCOUNT_THEME_PAGE_IDS; + return getAccountThemeType() === "Single-Page" + ? ["index.ftl"] + : ACCOUNT_THEME_PAGE_IDS; + case "admin": + return ["index.ftl"]; } })(), - ...(isForAccountSpa + ...(isSpa ? [] : readExtraPagesNames({ themeType, @@ -215,10 +234,12 @@ export async function generateResources(params: { let languageTags: string[] | undefined = undefined; i18n_messages_generation: { - if (isForAccountSpa) { + if (isSpa) { break i18n_messages_generation; } + assert(themeType !== "admin"); + const wrap = generateMessageProperties({ buildContext, themeType @@ -231,16 +252,15 @@ export async function generateResources(params: { writeMessagePropertiesFiles; } - bring_in_account_v3_i18n_messages: { - if (!buildContext.implementedThemeTypes.account.isImplemented) { - break bring_in_account_v3_i18n_messages; - } - if (buildContext.implementedThemeTypes.account.type !== "Single-Page") { - break bring_in_account_v3_i18n_messages; + bring_in_spas_messages: { + if (!isSpa) { + break bring_in_spas_messages; } + assert(themeType !== "login"); + const accountUiDirPath = child_process - .execSync("npm list @keycloakify/keycloak-account-ui --parseable", { + .execSync(`npm list @keycloakify/keycloak-${themeType}-ui --parseable`, { cwd: pathDirname(buildContext.packageJsonFilePath) }) .toString("utf8") @@ -255,7 +275,7 @@ export async function generateResources(params: { } const messagesDirPath_dest = pathJoin( - getThemeTypeDirPath({ themeName, themeType: "account" }), + getThemeTypeDirPath({ themeName, themeType }), "messages" ); @@ -267,7 +287,7 @@ export async function generateResources(params: { apply_theme_changes: { const messagesDirPath_theme = pathJoin( buildContext.themeSrcDirPath, - "account", + themeType, "messages" ); @@ -316,7 +336,7 @@ export async function generateResources(params: { } keycloak_static_resources: { - if (isForAccountSpa) { + if (isSpa) { break keycloak_static_resources; } @@ -339,13 +359,22 @@ export async function generateResources(params: { `parent=${(() => { switch (themeType) { case "account": - return isForAccountSpa ? "base" : "account-v1"; + switch (getAccountThemeType()) { + case "Multi-Page": + return "account-v1"; + case "Single-Page": + return "base"; + } case "login": return "keycloak"; + case "admin": + return "base"; } assert>(false); })()}`, - ...(isForAccountSpa ? ["deprecatedMode=false"] : []), + ...(themeType === "account" && getAccountThemeType() === "Single-Page" + ? ["deprecatedMode=false"] + : []), ...(buildContext.extraThemeProperties ?? []), ...buildContext.environmentVariables.map( ({ name, default: defaultValue }) => diff --git a/src/bin/main.ts b/src/bin/main.ts index a6abe1f5..0047b715 100644 --- a/src/bin/main.ts +++ b/src/bin/main.ts @@ -197,6 +197,20 @@ program } }); +program + .command({ + name: "initialize-admin-theme", + description: "Initialize the admin theme." + }) + .task({ + skip, + handler: async ({ projectDirPath }) => { + const { command } = await import("./initialize-admin-theme"); + + await command({ buildContext: getBuildContext({ projectDirPath }) }); + } + }); + program .command({ name: "copy-keycloak-resources-to-public", diff --git a/src/bin/shared/buildContext.ts b/src/bin/shared/buildContext.ts index 89afa6f9..4cb8a552 100644 --- a/src/bin/shared/buildContext.ts +++ b/src/bin/shared/buildContext.ts @@ -52,6 +52,7 @@ export type BuildContext = { account: | { isImplemented: false } | { isImplemented: true; type: "Single-Page" | "Multi-Page" }; + admin: { isImplemented: boolean }; }; packageJsonFilePath: string; bundler: "vite" | "webpack"; @@ -448,7 +449,10 @@ export function getBuildContext(params: { isImplemented: true, type: buildOptions.accountThemeImplementation }; - })() + })(), + admin: { + isImplemented: fs.existsSync(pathJoin(themeSrcDirPath, "admin")) + } }; if ( diff --git a/src/bin/shared/constants.ts b/src/bin/shared/constants.ts index d2137b14..cfddb472 100644 --- a/src/bin/shared/constants.ts +++ b/src/bin/shared/constants.ts @@ -4,7 +4,7 @@ export const WELL_KNOWN_DIRECTORY_BASE_NAME = { DIST: "dist" } as const; -export const THEME_TYPES = ["login", "account"] as const; +export const THEME_TYPES = ["login", "account", "admin"] as const; export type ThemeType = (typeof THEME_TYPES)[number]; diff --git a/src/bin/shared/customHandler.ts b/src/bin/shared/customHandler.ts index 7c0b9e1c..9e2cafa5 100644 --- a/src/bin/shared/customHandler.ts +++ b/src/bin/shared/customHandler.ts @@ -11,6 +11,7 @@ export type CommandName = | "eject-page" | "add-story" | "initialize-account-theme" + | "initialize-admin-theme" | "initialize-email-theme" | "copy-keycloak-resources-to-public"; diff --git a/src/bin/shared/exitIfUncommittedChanges.ts b/src/bin/shared/exitIfUncommittedChanges.ts new file mode 100644 index 00000000..6cf9b8c9 --- /dev/null +++ b/src/bin/shared/exitIfUncommittedChanges.ts @@ -0,0 +1,36 @@ +import child_process from "child_process"; +import chalk from "chalk"; + +export function exitIfUncommittedChanges(params: { projectDirPath: string }) { + const { projectDirPath } = params; + + let hasUncommittedChanges: boolean | undefined = undefined; + + try { + hasUncommittedChanges = + child_process + .execSync(`git status --porcelain`, { + cwd: projectDirPath + }) + .toString() + .trim() !== ""; + } catch { + // Probably not a git repository + return; + } + + if (!hasUncommittedChanges) { + return; + } + console.warn( + [ + chalk.red( + "Please commit or stash your changes before running this command.\n" + ), + "This command will modify your project's files so it's better to have a clean working directory", + "so that you can easily see what has been changed and revert if needed." + ].join(" ") + ); + + process.exit(-1); +} diff --git a/src/bin/tsconfig.json b/src/bin/tsconfig.json index b1a87db0..eda3bac6 100644 --- a/src/bin/tsconfig.json +++ b/src/bin/tsconfig.json @@ -10,5 +10,5 @@ "rootDir": "." }, "include": ["**/*.ts", "**/*.tsx"], - "exclude": ["initialize-account-theme/src"] + "exclude": ["initialize-account-theme/src", "initialize-admin-theme/src"] } diff --git a/src/bin/update-kc-gen.ts b/src/bin/update-kc-gen.ts index 985b3710..24e8d95b 100644 --- a/src/bin/update-kc-gen.ts +++ b/src/bin/update-kc-gen.ts @@ -22,6 +22,7 @@ export async function command(params: { buildContext: BuildContext }) { const hasLoginTheme = buildContext.implementedThemeTypes.login.isImplemented; const hasAccountTheme = buildContext.implementedThemeTypes.account.isImplemented; + const hasAdminTheme = buildContext.implementedThemeTypes.admin.isImplemented; const newContent = [ ``, @@ -54,6 +55,7 @@ export async function command(params: { buildContext: BuildContext }) { `export type KcContext =`, hasLoginTheme && ` | import("./login/KcContext").KcContext`, hasAccountTheme && ` | import("./account/KcContext").KcContext`, + hasAdminTheme && ` | import("./admin/KcContext").KcContext`, ` ;`, ``, `declare global {`, @@ -66,6 +68,8 @@ export async function command(params: { buildContext: BuildContext }) { `export const KcLoginPage = lazy(() => import("./login/KcPage"));`, hasAccountTheme && `export const KcAccountPage = lazy(() => import("./account/KcPage"));`, + hasAdminTheme && + `export const KcAdminPage = lazy(() => import("./admin/KcPage"));`, ``, `export function KcPage(`, ` props: {`, @@ -82,6 +86,8 @@ export async function command(params: { buildContext: BuildContext }) { ` case "login": return ;`, hasAccountTheme && ` case "account": return ;`, + hasAdminTheme && + ` case "admin": return ;`, ` }`, ` })()}`, ` `, diff --git a/test/tsconfig.json b/test/tsconfig.json index b47111ab..ae92c7bf 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -17,5 +17,8 @@ "skipLibCheck": true }, "include": ["../src", "."], - "exclude": ["../src/bin/initialize-account-theme/src"] + "exclude": [ + "../src/bin/initialize-account-theme/src", + "../src/bin/initialize-admin-theme/src" + ] }