Compare commits
29 Commits
v10.0.0-rc
...
v10.0.0
Author | SHA1 | Date | |
---|---|---|---|
48501407fc | |||
01cbdee2ca | |||
b70c0af0a9 | |||
dcaee9cb7f | |||
1d8b6c7792 | |||
c98dbe84c6 | |||
1785916d32 | |||
c6cf564842 | |||
380b739017 | |||
c3f3c55303 | |||
2c01018529 | |||
dd2edf3013 | |||
7f3cdf9fac | |||
f75a91fbc1 | |||
f151086bb1 | |||
7c833e6f10 | |||
885e8314e8 | |||
3bdd955ab6 | |||
9499587bad | |||
0879ddba7c | |||
106a1dd4c7 | |||
5580248bcd | |||
c9c10b8fba | |||
ed254922e9 | |||
4b7d1e2cec | |||
775ae57258 | |||
96e4cd79ee | |||
bb70f7df4f | |||
602de2e407 |
@ -240,6 +240,15 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "oliviergoulet5",
|
||||
"name": "Olivier Goulet",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/17685861?v=4",
|
||||
"profile": "https://github.com/oliviergoulet5",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
@ -43,9 +43,6 @@
|
||||
|
||||
Keycloakify is fully compatible with Keycloak 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, [~~22~~](https://github.com/keycloakify/keycloakify/issues/389#issuecomment-1822509763), 23, 24, 25...[and beyond](https://github.com/keycloakify/keycloakify/discussions/346#discussioncomment-5889791)
|
||||
|
||||
> NOTE: Keycloakify 10, while still being tagged as release candidate is the version you should use if you are starting today.
|
||||
> Use `yarn add keycloakify@next` or pin [the latest version candidate](https://www.npmjs.com/package/keycloakify?activeTab=versions).
|
||||
|
||||
## Sponsors
|
||||
|
||||
Friends for the project, we trust and recommend their services.
|
||||
@ -132,6 +129,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/law108000"><img src="https://avatars.githubusercontent.com/u/8112024?v=4?s=100" width="100px;" alt="Rlok"/><br /><sub><b>Rlok</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=law108000" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Moulyy"><img src="https://avatars.githubusercontent.com/u/115405804?v=4?s=100" width="100px;" alt="Moulyy"/><br /><sub><b>Moulyy</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=Moulyy" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/madmadson"><img src="https://avatars.githubusercontent.com/u/798831?v=4?s=100" width="100px;" alt="Tobias Matt"/><br /><sub><b>Tobias Matt</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=madmadson" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/oliviergoulet5"><img src="https://avatars.githubusercontent.com/u/17685861?v=4?s=100" width="100px;" alt="Olivier Goulet"/><br /><sub><b>Olivier Goulet</b></sub></a><br /><a href="https://github.com/keycloakify/keycloakify/commits?author=oliviergoulet5" title="Code">💻</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "keycloakify",
|
||||
"version": "10.0.0-rc.138",
|
||||
"version": "10.0.0",
|
||||
"description": "Create Keycloak themes using React",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -314,7 +314,7 @@ export async function generateResourcesForMainTheme(params: {
|
||||
}
|
||||
|
||||
const { extractedDirPath } = await downloadAndExtractArchive({
|
||||
urlOrPath: "https://repo1.maven.org/maven2/org/keycloak/keycloak-account-ui/25.0.1/keycloak-account-ui-25.0.1.jar",
|
||||
url: "https://repo1.maven.org/maven2/org/keycloak/keycloak-account-ui/25.0.1/keycloak-account-ui-25.0.1.jar",
|
||||
cacheDirPath: buildContext.cacheDirPath,
|
||||
fetchOptions: buildContext.fetchOptions,
|
||||
uniqueIdOfOnArchiveFile: "bring_in_account_v3_i18n_messages",
|
||||
|
@ -78,7 +78,7 @@ program
|
||||
|
||||
program
|
||||
.command<{
|
||||
port: number;
|
||||
port: number | undefined;
|
||||
keycloakVersion: string | undefined;
|
||||
realmJsonFilePath: string | undefined;
|
||||
}>({
|
||||
@ -96,7 +96,7 @@ program
|
||||
return name;
|
||||
})(),
|
||||
description: ["Keycloak server port.", "Example `--port 8085`"].join(" "),
|
||||
defaultValue: 8080
|
||||
defaultValue: undefined
|
||||
})
|
||||
.option({
|
||||
key: "keycloakVersion",
|
||||
|
@ -72,6 +72,7 @@ export type BuildContext = {
|
||||
keycloakExtraArgs: string[];
|
||||
extensionJars: ({ type: "path"; path: string } | { type: "url"; url: string })[];
|
||||
realmJsonFilePath: string | undefined;
|
||||
port: number | undefined;
|
||||
};
|
||||
};
|
||||
|
||||
@ -93,6 +94,7 @@ export type BuildOptions = {
|
||||
keycloakExtraArgs?: string[];
|
||||
extensionJars?: string[];
|
||||
realmJsonFilePath?: string;
|
||||
port?: number;
|
||||
};
|
||||
} & BuildOptions.AccountThemeImplAndKeycloakVersionTargets;
|
||||
|
||||
@ -328,7 +330,8 @@ export function getBuildContext(params: {
|
||||
extensionJars: z.array(z.string()).optional(),
|
||||
realmJsonFilePath: z.string().optional(),
|
||||
dockerExtraArgs: z.array(z.string()).optional(),
|
||||
keycloakExtraArgs: z.array(z.string()).optional()
|
||||
keycloakExtraArgs: z.array(z.string()).optional(),
|
||||
port: z.number().optional()
|
||||
});
|
||||
|
||||
assert<Equals<z.infer<typeof zTargetType>, TargetType>>();
|
||||
@ -967,7 +970,8 @@ export function getBuildContext(params: {
|
||||
: getAbsoluteAndInOsFormatPath({
|
||||
pathIsh: buildOptions.startKeycloakOptions.realmJsonFilePath,
|
||||
cwd: projectDirPath
|
||||
})
|
||||
}),
|
||||
port: buildOptions.startKeycloakOptions?.port
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ export async function downloadKeycloakDefaultTheme(params: {
|
||||
let kcNodeModulesKeepFilePaths_lastAccountV1: Set<string> | undefined = undefined;
|
||||
|
||||
const { extractedDirPath } = await downloadAndExtractArchive({
|
||||
urlOrPath: `https://repo1.maven.org/maven2/org/keycloak/keycloak-themes/${keycloakVersion}/keycloak-themes-${keycloakVersion}.jar`,
|
||||
url: `https://repo1.maven.org/maven2/org/keycloak/keycloak-themes/${keycloakVersion}/keycloak-themes-${keycloakVersion}.jar`,
|
||||
cacheDirPath: buildContext.cacheDirPath,
|
||||
fetchOptions: buildContext.fetchOptions,
|
||||
uniqueIdOfOnArchiveFile: "downloadKeycloakDefaultTheme",
|
||||
|
@ -55,7 +55,7 @@ export async function promptKeycloakVersion(params: {
|
||||
});
|
||||
|
||||
const lastMajorVersions = Array.from(semVersionedTagByMajor.values()).map(
|
||||
({ tag }) => tag
|
||||
({ version }) => `${version.major}.${version.minor}`
|
||||
);
|
||||
|
||||
const { value } = await cliSelect<string>({
|
||||
|
@ -10,7 +10,8 @@ import {
|
||||
join as pathJoin,
|
||||
relative as pathRelative,
|
||||
sep as pathSep,
|
||||
basename as pathBasename
|
||||
basename as pathBasename,
|
||||
dirname as pathDirname
|
||||
} from "path";
|
||||
import * as child_process from "child_process";
|
||||
import chalk from "chalk";
|
||||
@ -29,7 +30,7 @@ import { rm } from "../tools/fs.rm";
|
||||
import { downloadAndExtractArchive } from "../tools/downloadAndExtractArchive";
|
||||
|
||||
export type CliCommandOptions = CliCommandOptions_common & {
|
||||
port: number;
|
||||
port: number | undefined;
|
||||
keycloakVersion: string | undefined;
|
||||
realmJsonFilePath: string | undefined;
|
||||
};
|
||||
@ -200,7 +201,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
const { archiveFilePath } = await downloadAndExtractArchive({
|
||||
cacheDirPath: buildContext.cacheDirPath,
|
||||
fetchOptions: buildContext.fetchOptions,
|
||||
urlOrPath: extensionJar.url,
|
||||
url: extensionJar.url,
|
||||
uniqueIdOfOnArchiveFile: "no extraction",
|
||||
onArchiveFile: async () => {}
|
||||
});
|
||||
@ -211,6 +212,17 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
})
|
||||
);
|
||||
|
||||
const getRealmJsonFilePath_defaultForKeycloakMajor = (
|
||||
keycloakMajorVersionNumber: number
|
||||
) =>
|
||||
pathJoin(
|
||||
getThisCodebaseRootDirPath(),
|
||||
"src",
|
||||
"bin",
|
||||
"start-keycloak",
|
||||
`myrealm-realm-${keycloakMajorVersionNumber}.json`
|
||||
);
|
||||
|
||||
const realmJsonFilePath = await (async () => {
|
||||
if (cliCommandOptions.realmJsonFilePath !== undefined) {
|
||||
if (cliCommandOptions.realmJsonFilePath === "none") {
|
||||
@ -231,20 +243,12 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
}
|
||||
|
||||
const internalFilePath = await (async () => {
|
||||
const dirPath = pathJoin(
|
||||
getThisCodebaseRootDirPath(),
|
||||
"src",
|
||||
"bin",
|
||||
"start-keycloak"
|
||||
const defaultFilePath = getRealmJsonFilePath_defaultForKeycloakMajor(
|
||||
keycloakMajorVersionNumber
|
||||
);
|
||||
|
||||
const filePath = pathJoin(
|
||||
dirPath,
|
||||
`myrealm-realm-${keycloakMajorVersionNumber}.json`
|
||||
);
|
||||
|
||||
if (fs.existsSync(filePath)) {
|
||||
return filePath;
|
||||
if (fs.existsSync(defaultFilePath)) {
|
||||
return defaultFilePath;
|
||||
}
|
||||
|
||||
console.log(
|
||||
@ -255,6 +259,8 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
|
||||
console.log(chalk.cyan("Select what configuration to use:"));
|
||||
|
||||
const dirPath = pathDirname(defaultFilePath);
|
||||
|
||||
const { value } = await cliSelect<string>({
|
||||
values: [
|
||||
...fs
|
||||
@ -296,6 +302,40 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
return filePath;
|
||||
})();
|
||||
|
||||
add_test_user_if_missing: {
|
||||
if (realmJsonFilePath === undefined) {
|
||||
break add_test_user_if_missing;
|
||||
}
|
||||
|
||||
const realm: Record<string, unknown> = JSON.parse(
|
||||
fs.readFileSync(realmJsonFilePath).toString("utf8")
|
||||
);
|
||||
|
||||
if (realm.users !== undefined) {
|
||||
break add_test_user_if_missing;
|
||||
}
|
||||
|
||||
const realmJsonFilePath_internal = (() => {
|
||||
const filePath = getRealmJsonFilePath_defaultForKeycloakMajor(
|
||||
keycloakMajorVersionNumber
|
||||
);
|
||||
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return getRealmJsonFilePath_defaultForKeycloakMajor(25);
|
||||
}
|
||||
|
||||
return filePath;
|
||||
})();
|
||||
|
||||
const users = JSON.parse(
|
||||
fs.readFileSync(realmJsonFilePath_internal).toString("utf8")
|
||||
).users;
|
||||
|
||||
realm.users = users;
|
||||
|
||||
fs.writeFileSync(realmJsonFilePath, JSON.stringify(realm, null, 2), "utf8");
|
||||
}
|
||||
|
||||
async function extractThemeResourcesFromJar() {
|
||||
await extractArchive({
|
||||
archiveFilePath: jarFilePath,
|
||||
@ -334,23 +374,36 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
});
|
||||
} catch {}
|
||||
|
||||
const DEFAULT_PORT = 8080;
|
||||
const port =
|
||||
cliCommandOptions.port ?? buildContext.startKeycloakOptions.port ?? DEFAULT_PORT;
|
||||
|
||||
const SPACE_PLACEHOLDER = "SPACE_PLACEHOLDER_xKLmdPd";
|
||||
|
||||
const dockerRunArgs: string[] = [
|
||||
`-p ${cliCommandOptions.port}:8080`,
|
||||
`--name ${CONTAINER_NAME}`,
|
||||
`-e KEYCLOAK_ADMIN=admin`,
|
||||
`-e KEYCLOAK_ADMIN_PASSWORD=admin`,
|
||||
`-p${SPACE_PLACEHOLDER}${port}:8080`,
|
||||
`--name${SPACE_PLACEHOLDER}${CONTAINER_NAME}`,
|
||||
`-e${SPACE_PLACEHOLDER}KEYCLOAK_ADMIN=admin`,
|
||||
`-e${SPACE_PLACEHOLDER}KEYCLOAK_ADMIN_PASSWORD=admin`,
|
||||
...(buildContext.startKeycloakOptions.dockerExtraArgs.length === 0
|
||||
? []
|
||||
: [
|
||||
buildContext.startKeycloakOptions.dockerExtraArgs.join(
|
||||
SPACE_PLACEHOLDER
|
||||
)
|
||||
]),
|
||||
...(realmJsonFilePath === undefined
|
||||
? []
|
||||
: [
|
||||
`-v ".${pathSep}${pathRelative(process.cwd(), realmJsonFilePath)}":/opt/keycloak/data/import/myrealm-realm.json`
|
||||
`-v${SPACE_PLACEHOLDER}".${pathSep}${pathRelative(process.cwd(), realmJsonFilePath)}":/opt/keycloak/data/import/myrealm-realm.json`
|
||||
]),
|
||||
`-v "./${pathRelative(process.cwd(), jarFilePath_cacheDir)}":/opt/keycloak/providers/keycloak-theme.jar`,
|
||||
`-v${SPACE_PLACEHOLDER}".${pathSep}${pathRelative(process.cwd(), jarFilePath_cacheDir)}":/opt/keycloak/providers/keycloak-theme.jar`,
|
||||
...extensionJarFilePaths.map(
|
||||
jarFilePath =>
|
||||
`-v ".${pathSep}${pathRelative(process.cwd(), jarFilePath)}":/opt/keycloak/providers/${pathBasename(jarFilePath)}`
|
||||
`-v${SPACE_PLACEHOLDER}".${pathSep}${pathRelative(process.cwd(), jarFilePath)}":/opt/keycloak/providers/${pathBasename(jarFilePath)}`
|
||||
),
|
||||
...(keycloakMajorVersionNumber <= 20
|
||||
? ["-e JAVA_OPTS=-Dkeycloak.profile=preview"]
|
||||
? [`-e${SPACE_PLACEHOLDER}JAVA_OPTS=-Dkeycloak.profile=preview`]
|
||||
: []),
|
||||
...[
|
||||
...buildContext.themeNames,
|
||||
@ -374,7 +427,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
}))
|
||||
.map(
|
||||
({ localDirPath, containerDirPath }) =>
|
||||
`-v ".${pathSep}${pathRelative(process.cwd(), localDirPath)}":${containerDirPath}:rw`
|
||||
`-v${SPACE_PLACEHOLDER}".${pathSep}${pathRelative(process.cwd(), localDirPath)}":${containerDirPath}:rw`
|
||||
),
|
||||
...buildContext.environmentVariables
|
||||
.map(({ name }) => ({ name, envValue: process.env[name] }))
|
||||
@ -384,32 +437,40 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
.filter(exclude(undefined))
|
||||
.map(
|
||||
({ name, envValue }) =>
|
||||
`--env ${name}='${envValue.replace(/'/g, "'\\''")}'`
|
||||
`--env${SPACE_PLACEHOLDER}${name}='${envValue.replace(/'/g, "'\\''")}'`
|
||||
),
|
||||
...buildContext.startKeycloakOptions.dockerExtraArgs,
|
||||
`${buildContext.startKeycloakOptions.dockerImage?.reference ?? "quay.io/keycloak/keycloak"}:${dockerImageTag}`,
|
||||
"start-dev",
|
||||
...(21 <= keycloakMajorVersionNumber && keycloakMajorVersionNumber < 24
|
||||
? ["--features=declarative-user-profile"]
|
||||
: []),
|
||||
...(realmJsonFilePath === undefined ? [] : ["--import-realm"]),
|
||||
...buildContext.startKeycloakOptions.keycloakExtraArgs
|
||||
...(buildContext.startKeycloakOptions.keycloakExtraArgs.length === 0
|
||||
? []
|
||||
: [
|
||||
buildContext.startKeycloakOptions.keycloakExtraArgs.join(
|
||||
SPACE_PLACEHOLDER
|
||||
)
|
||||
])
|
||||
];
|
||||
|
||||
console.log(
|
||||
chalk.blue(
|
||||
[
|
||||
`$ docker run \\`,
|
||||
...dockerRunArgs.map(
|
||||
(line, i, arr) => ` ${line}${arr.length - 1 === i ? "" : " \\"}`
|
||||
)
|
||||
...dockerRunArgs
|
||||
.map(arg => arg.replace(new RegExp(SPACE_PLACEHOLDER, "g"), " "))
|
||||
.map(
|
||||
(line, i, arr) =>
|
||||
` ${line}${arr.length - 1 === i ? "" : " \\"}`
|
||||
)
|
||||
].join("\n")
|
||||
)
|
||||
);
|
||||
|
||||
const child = child_process.spawn(
|
||||
"docker",
|
||||
["run", ...dockerRunArgs.map(line => line.split(" ")).flat()],
|
||||
["run", ...dockerRunArgs.map(line => line.split(SPACE_PLACEHOLDER)).flat()],
|
||||
{ shell: true }
|
||||
);
|
||||
|
||||
@ -422,6 +483,18 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
const srcDirPath = pathJoin(buildContext.projectDirPath, "src");
|
||||
|
||||
{
|
||||
const kcHttpRelativePath = (() => {
|
||||
const match = buildContext.startKeycloakOptions.dockerExtraArgs
|
||||
.join(" ")
|
||||
.match(/KC_HTTP_RELATIVE_PATH=([^ ]+)/);
|
||||
|
||||
if (match === null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return match[1];
|
||||
})();
|
||||
|
||||
const handler = async (data: Buffer) => {
|
||||
if (!data.toString("utf8").includes("Listening on: http://0.0.0.0:8080")) {
|
||||
return;
|
||||
@ -439,7 +512,7 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
)} are mounted in the Keycloak container.`,
|
||||
"",
|
||||
`Keycloak Admin console: ${chalk.cyan.bold(
|
||||
`http://localhost:${cliCommandOptions.port}`
|
||||
`http://localhost:${port}${kcHttpRelativePath ?? ""}`
|
||||
)}`,
|
||||
`- user: ${chalk.cyan.bold("admin")}`,
|
||||
`- password: ${chalk.cyan.bold("admin")}`,
|
||||
@ -447,7 +520,21 @@ export async function command(params: { cliCommandOptions: CliCommandOptions })
|
||||
"",
|
||||
`${chalk.green("Your theme is accessible at:")}`,
|
||||
`${chalk.green("➜")} ${chalk.cyan.bold(
|
||||
`https://my-theme.keycloakify.dev${cliCommandOptions.port === 8080 ? "" : `?port=${cliCommandOptions.port}`}`
|
||||
(() => {
|
||||
const url = new URL("https://my-theme.keycloakify.dev");
|
||||
|
||||
if (port !== DEFAULT_PORT) {
|
||||
url.searchParams.set("port", `${port}`);
|
||||
}
|
||||
if (kcHttpRelativePath !== undefined) {
|
||||
url.searchParams.set(
|
||||
"kcHttpRelativePath",
|
||||
kcHttpRelativePath
|
||||
);
|
||||
}
|
||||
|
||||
return url.href;
|
||||
})()
|
||||
)}`,
|
||||
"",
|
||||
"You can login with the following credentials:",
|
||||
|
@ -1,15 +1,14 @@
|
||||
import fetch, { type FetchOptions } from "make-fetch-happen";
|
||||
import { mkdir, unlink, writeFile, readdir, readFile } from "fs/promises";
|
||||
import { dirname as pathDirname, join as pathJoin, basename as pathBasename } from "path";
|
||||
import { dirname as pathDirname, join as pathJoin } from "path";
|
||||
import { assert } from "tsafe/assert";
|
||||
import { extractArchive } from "./extractArchive";
|
||||
import { existsAsync } from "./fs.existsAsync";
|
||||
import * as crypto from "crypto";
|
||||
import { rm } from "./fs.rm";
|
||||
import * as fsPr from "fs/promises";
|
||||
|
||||
export async function downloadAndExtractArchive(params: {
|
||||
urlOrPath: string;
|
||||
url: string;
|
||||
uniqueIdOfOnArchiveFile: string;
|
||||
onArchiveFile: (params: {
|
||||
fileRelativePath: string;
|
||||
@ -21,34 +20,17 @@ export async function downloadAndExtractArchive(params: {
|
||||
}) => Promise<void>;
|
||||
cacheDirPath: string;
|
||||
fetchOptions: FetchOptions | undefined;
|
||||
}): Promise<{ extractedDirPath: string; archiveFilePath: string; }> {
|
||||
const {
|
||||
urlOrPath,
|
||||
uniqueIdOfOnArchiveFile,
|
||||
onArchiveFile,
|
||||
cacheDirPath,
|
||||
fetchOptions
|
||||
} = params;
|
||||
}): Promise<{ extractedDirPath: string; archiveFilePath: string }> {
|
||||
const { url, uniqueIdOfOnArchiveFile, onArchiveFile, cacheDirPath, fetchOptions } =
|
||||
params;
|
||||
|
||||
const isUrl = /^https?:\/\//.test(urlOrPath);
|
||||
|
||||
const archiveFileBasename = isUrl
|
||||
? urlOrPath.split("?")[0].split("/").reverse()[0]
|
||||
: pathBasename(urlOrPath);
|
||||
const archiveFileBasename = url.split("?")[0].split("/").reverse()[0];
|
||||
|
||||
const archiveFilePath = pathJoin(cacheDirPath, archiveFileBasename);
|
||||
|
||||
download: {
|
||||
await mkdir(pathDirname(archiveFilePath), { recursive: true });
|
||||
|
||||
if (!isUrl) {
|
||||
await fsPr.copyFile(urlOrPath, archiveFilePath);
|
||||
|
||||
break download;
|
||||
}
|
||||
|
||||
const url = urlOrPath;
|
||||
|
||||
if (await existsAsync(archiveFilePath)) {
|
||||
const isDownloaded = await SuccessTracker.getIsDownloaded({
|
||||
cacheDirPath,
|
||||
|
@ -58,7 +58,7 @@ export default function UserProfileFormFields(props: UserProfileFormFieldsProps<
|
||||
<label htmlFor={attribute.name} className={kcClsx("kcLabelClass")}>
|
||||
{advancedMsg(attribute.displayName ?? "")}
|
||||
</label>
|
||||
{attribute.required && <>*</>}
|
||||
{attribute.required && <> *</>}
|
||||
</div>
|
||||
<div className={kcClsx("kcInputWrapperClass")}>
|
||||
{attribute.annotations.inputHelperTextBefore !== undefined && (
|
||||
|
@ -1394,14 +1394,10 @@ export function getButtonToDisplayForMultivaluedAttributeField(params: { attribu
|
||||
})();
|
||||
|
||||
if (maxCount === undefined) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (values.length === maxCount) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return values.length !== maxCount;
|
||||
})();
|
||||
|
||||
return { hasRemove, hasAdd };
|
||||
|
@ -153,7 +153,7 @@ export default function WebauthnRegister(props: PageProps<Extract<KcContext, { p
|
||||
|
||||
function getPubKeyCredParams(signatureAlgorithmsList) {
|
||||
let pubKeyCredParams = [];
|
||||
if (signatureAlgorithmsList === []) {
|
||||
if (signatureAlgorithmsList.length === 0) {
|
||||
pubKeyCredParams.push({type: "public-key", alg: -7});
|
||||
return pubKeyCredParams;
|
||||
}
|
||||
@ -184,7 +184,7 @@ export default function WebauthnRegister(props: PageProps<Extract<KcContext, { p
|
||||
}
|
||||
|
||||
function getTransportsAsString(transportsList) {
|
||||
if (transportsList === '' || transportsList.constructor !== Array) return "";
|
||||
if (transportsList === '' || Array.isArray(transportsList)) return "";
|
||||
|
||||
let transportsString = "";
|
||||
|
||||
|
Reference in New Issue
Block a user