Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
e3bd7f3bc5 | |||
e14f187fc0 | |||
da495b90ae | |||
8d9b80f549 | |||
2e9da33622 | |||
6f416ad335 | |||
4e982ee898 | |||
bcb514ae9c | |||
cfdad8d71d | |||
39ad1eb8d1 | |||
3d1d2e316b | |||
dd217e8a46 | |||
1339a96ea4 | |||
616e834c90 | |||
80eaa77acc |
@ -1,3 +1,3 @@
|
||||
Looking to contribute? Thank you! PR are more than welcome.
|
||||
|
||||
Please refers to [this documentation page](https://docs.keycloakify.dev/contributing) that will help you get started.
|
||||
Please refers to [this documentation page](https://docs.keycloakify.dev/faq-and-help/contributing) that will help you get started.
|
||||
|
@ -41,7 +41,7 @@
|
||||
<img width="400" src="https://github.com/user-attachments/assets/6bf3bef9-00b0-4460-97b9-0d2da8500798">
|
||||
</p>
|
||||
|
||||
Keycloakify is fully compatible with Keycloak from version 11 to 25...[and beyond](https://github.com/keycloakify/keycloakify/discussions/346#discussioncomment-5889791)
|
||||
Keycloakify is fully compatible with Keycloak from version 11 to 26...[and beyond](https://github.com/keycloakify/keycloakify/discussions/346#discussioncomment-5889791)
|
||||
|
||||
## Sponsors
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "keycloakify",
|
||||
"version": "11.2.6",
|
||||
"version": "11.2.10",
|
||||
"description": "Framework to create custom Keycloak UIs",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -197,7 +197,7 @@ export async function buildJar(params: {
|
||||
|
||||
await new Promise<void>((resolve, reject) =>
|
||||
child_process.exec(
|
||||
`mvn install -Dmaven.repo.local="${pathJoin(keycloakifyBuildCacheDirPath, ".m2")}"`,
|
||||
`mvn clean install -Dmaven.repo.local="${pathJoin(keycloakifyBuildCacheDirPath, ".m2")}"`,
|
||||
{ cwd: keycloakifyBuildCacheDirPath },
|
||||
error => {
|
||||
if (error !== null) {
|
||||
|
@ -52,9 +52,9 @@ export function getKeycloakVersionRangeForJar(params: {
|
||||
case "0.6":
|
||||
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
||||
case null:
|
||||
return undefined;
|
||||
return "26-and-above" as const;
|
||||
case "1.1.5":
|
||||
return "25-and-above" as const;
|
||||
return "25" as const;
|
||||
}
|
||||
}
|
||||
assert<Equals<typeof keycloakAccountV1Version, never>>(false);
|
||||
@ -75,9 +75,9 @@ export function getKeycloakVersionRangeForJar(params: {
|
||||
}
|
||||
switch (keycloakThemeAdditionalInfoExtensionVersion) {
|
||||
case null:
|
||||
return "21-and-below";
|
||||
return "all-other-versions";
|
||||
case "1.1.5":
|
||||
return "22-and-above";
|
||||
return "22-to-25";
|
||||
}
|
||||
assert<Equals<typeof keycloakThemeAdditionalInfoExtensionVersion, never>>(
|
||||
false
|
||||
|
@ -235,6 +235,9 @@ function decodeHtmlEntities(htmlStr){
|
||||
"identityFederationEnabled",
|
||||
"userManagedAccessAllowed"
|
||||
]?seq_contains(key)
|
||||
) || (
|
||||
["flowContext", "session", "realm"]?seq_contains(key) &&
|
||||
areSamePath(path, ["social"])
|
||||
)
|
||||
>
|
||||
<#-- <#local outSeq += ["/*" + path?join(".") + "." + key + " excluded*/"]> -->
|
||||
|
@ -3,7 +3,7 @@ export type KeycloakVersionRange =
|
||||
| KeycloakVersionRange.WithoutAccountV1Theme;
|
||||
|
||||
export namespace KeycloakVersionRange {
|
||||
export type WithoutAccountV1Theme = "21-and-below" | "22-and-above";
|
||||
export type WithoutAccountV1Theme = "22-to-25" | "all-other-versions";
|
||||
|
||||
export type WithAccountV1Theme = "21-and-below" | "23" | "24" | "25-and-above";
|
||||
export type WithAccountV1Theme = "21-and-below" | "23" | "24" | "25" | "26-and-above";
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import { type ThemeType } from "./constants";
|
||||
import { id } from "tsafe/id";
|
||||
import chalk from "chalk";
|
||||
import { getProxyFetchOptions, type ProxyFetchOptions } from "../tools/fetchProxyOptions";
|
||||
import { is } from "tsafe/is";
|
||||
|
||||
export type BuildContext = {
|
||||
themeVersion: string;
|
||||
@ -276,7 +277,8 @@ export function getBuildContext(params: {
|
||||
"21-and-below": z.union([z.boolean(), z.string()]),
|
||||
"23": z.union([z.boolean(), z.string()]),
|
||||
"24": z.union([z.boolean(), z.string()]),
|
||||
"25-and-above": z.union([z.boolean(), z.string()])
|
||||
"25": z.union([z.boolean(), z.string()]),
|
||||
"26-and-above": z.union([z.boolean(), z.string()])
|
||||
})
|
||||
.optional()
|
||||
});
|
||||
@ -297,8 +299,8 @@ export function getBuildContext(params: {
|
||||
]),
|
||||
keycloakVersionTargets: z
|
||||
.object({
|
||||
"21-and-below": z.union([z.boolean(), z.string()]),
|
||||
"22-and-above": z.union([z.boolean(), z.string()])
|
||||
"22-to-25": z.union([z.boolean(), z.string()]),
|
||||
"all-other-versions": z.union([z.boolean(), z.string()])
|
||||
})
|
||||
.optional()
|
||||
});
|
||||
@ -766,7 +768,11 @@ export function getBuildContext(params: {
|
||||
return "24" as const;
|
||||
}
|
||||
|
||||
return "25-and-above" as const;
|
||||
if (buildForKeycloakMajorVersionNumber === 25) {
|
||||
return "25" as const;
|
||||
}
|
||||
|
||||
return "26-and-above" as const;
|
||||
})();
|
||||
|
||||
assert<
|
||||
@ -779,11 +785,14 @@ export function getBuildContext(params: {
|
||||
return keycloakVersionRange;
|
||||
} else {
|
||||
const keycloakVersionRange = (() => {
|
||||
if (buildForKeycloakMajorVersionNumber <= 21) {
|
||||
return "21-and-below" as const;
|
||||
if (
|
||||
buildForKeycloakMajorVersionNumber <= 21 ||
|
||||
buildForKeycloakMajorVersionNumber >= 26
|
||||
) {
|
||||
return "all-other-versions" as const;
|
||||
}
|
||||
|
||||
return "22-and-above" as const;
|
||||
return "22-to-25" as const;
|
||||
})();
|
||||
|
||||
assert<
|
||||
@ -801,6 +810,12 @@ export function getBuildContext(params: {
|
||||
use_custom_jar_basename: {
|
||||
const { keycloakVersionTargets } = buildOptions;
|
||||
|
||||
assert(
|
||||
is<Record<KeycloakVersionRange, string | boolean>>(
|
||||
keycloakVersionTargets
|
||||
)
|
||||
);
|
||||
|
||||
if (keycloakVersionTargets === undefined) {
|
||||
break use_custom_jar_basename;
|
||||
}
|
||||
@ -845,7 +860,8 @@ export function getBuildContext(params: {
|
||||
"21-and-below",
|
||||
"23",
|
||||
"24",
|
||||
"25-and-above"
|
||||
"25",
|
||||
"26-and-above"
|
||||
] as const) {
|
||||
assert<
|
||||
Equals<
|
||||
@ -861,8 +877,8 @@ export function getBuildContext(params: {
|
||||
}
|
||||
} else {
|
||||
for (const keycloakVersionRange of [
|
||||
"21-and-below",
|
||||
"22-and-above"
|
||||
"22-to-25",
|
||||
"all-other-versions"
|
||||
] as const) {
|
||||
assert<
|
||||
Equals<
|
||||
@ -888,7 +904,17 @@ export function getBuildContext(params: {
|
||||
const jarTargets: BuildContext["jarTargets"] = [];
|
||||
|
||||
for (const [keycloakVersionRange, jarNameOrBoolean] of objectEntries(
|
||||
buildOptions.keycloakVersionTargets
|
||||
(() => {
|
||||
const { keycloakVersionTargets } = buildOptions;
|
||||
|
||||
assert(
|
||||
is<Record<KeycloakVersionRange, string | boolean>>(
|
||||
keycloakVersionTargets
|
||||
)
|
||||
);
|
||||
|
||||
return keycloakVersionTargets;
|
||||
})()
|
||||
)) {
|
||||
if (jarNameOrBoolean === false) {
|
||||
continue;
|
||||
|
2400
src/bin/start-keycloak/myrealm-realm-26.json
Normal file
2400
src/bin/start-keycloak/myrealm-realm-26.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -434,9 +434,7 @@ function AddRemoveButtonsMultiValuedAttribute(props: {
|
||||
}
|
||||
|
||||
function InputTagSelects(props: InputFieldByTypeProps) {
|
||||
const { attribute, dispatchFormAction, kcClsx, valueOrValues } = props;
|
||||
|
||||
const { advancedMsg } = props.i18n;
|
||||
const { attribute, dispatchFormAction, kcClsx, i18n, valueOrValues } = props;
|
||||
|
||||
const { classDiv, classInput, classLabel, inputType } = (() => {
|
||||
const { inputType } = attribute.annotations;
|
||||
@ -533,7 +531,7 @@ function InputTagSelects(props: InputFieldByTypeProps) {
|
||||
htmlFor={`${attribute.name}-${option}`}
|
||||
className={`${classLabel}${attribute.readOnly ? ` ${kcClsx("kcInputClassRadioCheckboxLabelDisabled")}` : ""}`}
|
||||
>
|
||||
{advancedMsg(option)}
|
||||
{inputLabel(i18n, attribute, option)}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
@ -580,8 +578,6 @@ function TextareaTag(props: InputFieldByTypeProps) {
|
||||
function SelectTag(props: InputFieldByTypeProps) {
|
||||
const { attribute, dispatchFormAction, kcClsx, displayableErrors, i18n, valueOrValues } = props;
|
||||
|
||||
const { advancedMsgStr } = i18n;
|
||||
|
||||
const isMultiple = attribute.annotations.inputType === "multiselect";
|
||||
|
||||
return (
|
||||
@ -645,22 +641,26 @@ function SelectTag(props: InputFieldByTypeProps) {
|
||||
|
||||
return options.map(option => (
|
||||
<option key={option} value={option}>
|
||||
{(() => {
|
||||
if (attribute.annotations.inputOptionLabels !== undefined) {
|
||||
const { inputOptionLabels } = attribute.annotations;
|
||||
|
||||
return advancedMsgStr(inputOptionLabels[option] ?? option);
|
||||
}
|
||||
|
||||
if (attribute.annotations.inputOptionLabelsI18nPrefix !== undefined) {
|
||||
return advancedMsgStr(`${attribute.annotations.inputOptionLabelsI18nPrefix}.${option}`);
|
||||
}
|
||||
|
||||
return option;
|
||||
})()}
|
||||
{inputLabel(i18n, attribute, option)}
|
||||
</option>
|
||||
));
|
||||
})()}
|
||||
</select>
|
||||
);
|
||||
}
|
||||
|
||||
function inputLabel(i18n: I18n, attribute: Attribute, option: string) {
|
||||
const { advancedMsg } = i18n;
|
||||
|
||||
if (attribute.annotations.inputOptionLabels !== undefined) {
|
||||
const { inputOptionLabels } = attribute.annotations;
|
||||
|
||||
return advancedMsg(inputOptionLabels[option] ?? option);
|
||||
}
|
||||
|
||||
if (attribute.annotations.inputOptionLabelsI18nPrefix !== undefined) {
|
||||
return advancedMsg(`${attribute.annotations.inputOptionLabelsI18nPrefix}.${option}`);
|
||||
}
|
||||
|
||||
return option;
|
||||
}
|
||||
|
@ -115,6 +115,38 @@ export const WithFavoritePet: Story = {
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
export const WithNewsletter: Story = {
|
||||
render: () => (
|
||||
<KcPageStory
|
||||
kcContext={{
|
||||
profile: {
|
||||
attributesByName: {
|
||||
newsletter: {
|
||||
name: "newsletter",
|
||||
displayName: "Sign up to the newsletter",
|
||||
validators: {
|
||||
options: {
|
||||
options: ["yes"]
|
||||
}
|
||||
},
|
||||
annotations: {
|
||||
inputOptionLabels: {
|
||||
"yes": "I want my email inbox filled with spam"
|
||||
},
|
||||
inputType: "multiselect-checkboxes"
|
||||
},
|
||||
required: false,
|
||||
readOnly: false
|
||||
} satisfies Attribute
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
export const WithEmailAsUsername: Story = {
|
||||
render: () => (
|
||||
<KcPageStory
|
||||
|
Reference in New Issue
Block a user