2021-08-26 08:39:35 +00:00
|
|
|
import type ClientRepresentation from "@keycloak/keycloak-admin-client/lib/defs/clientRepresentation";
|
|
|
|
import type { ProviderRepresentation } from "@keycloak/keycloak-admin-client/lib/defs/serverInfoRepesentation";
|
2022-11-24 15:48:22 +00:00
|
|
|
import type { IFormatter, IFormatterValueType } from "@patternfly/react-table";
|
2024-06-03 15:53:07 +00:00
|
|
|
import { saveAs } from "file-saver";
|
|
|
|
import { flatten } from "flat";
|
|
|
|
import { cloneDeep } from "lodash-es";
|
|
|
|
import { FieldValues, Path, PathValue, UseFormSetValue } from "react-hook-form";
|
2021-12-08 15:08:42 +00:00
|
|
|
import {
|
2024-06-14 12:26:58 +00:00
|
|
|
KeyValueType,
|
2022-04-20 17:11:46 +00:00
|
|
|
arrayToKeyValue,
|
2022-11-24 15:48:22 +00:00
|
|
|
keyValueToArray,
|
2022-04-20 17:11:46 +00:00
|
|
|
} from "./components/key-value-form/key-value-convert";
|
2022-11-24 15:48:22 +00:00
|
|
|
import { ReplaceString } from "./utils/types";
|
2020-08-31 18:26:25 +00:00
|
|
|
|
2020-11-02 20:15:09 +00:00
|
|
|
export const sortProviders = (providers: {
|
|
|
|
[index: string]: ProviderRepresentation;
|
|
|
|
}) => {
|
|
|
|
return [...new Map(Object.entries(providers).sort(sortProvider)).keys()];
|
|
|
|
};
|
|
|
|
|
|
|
|
const sortProvider = (
|
2020-09-01 14:51:59 +00:00
|
|
|
a: [string, ProviderRepresentation],
|
2023-07-11 14:03:21 +00:00
|
|
|
b: [string, ProviderRepresentation],
|
2020-09-01 14:51:59 +00:00
|
|
|
) => {
|
2020-08-31 18:26:25 +00:00
|
|
|
let s1, s2;
|
2020-10-27 11:25:54 +00:00
|
|
|
if (a[1].order !== b[1].order) {
|
2020-08-31 18:26:25 +00:00
|
|
|
s1 = b[1].order;
|
|
|
|
s2 = a[1].order;
|
2020-09-01 14:51:59 +00:00
|
|
|
} else {
|
2020-08-31 18:26:25 +00:00
|
|
|
s1 = a[0];
|
|
|
|
s2 = b[0];
|
2020-09-01 14:51:59 +00:00
|
|
|
}
|
2020-08-31 18:26:25 +00:00
|
|
|
if (s1 < s2) {
|
|
|
|
return -1;
|
|
|
|
} else if (s1 > s2) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
};
|
2020-10-02 13:56:46 +00:00
|
|
|
|
2022-06-24 11:44:15 +00:00
|
|
|
export const toKey = (value: string) => value.replace(/\s/g, "-");
|
|
|
|
|
2020-10-02 13:56:46 +00:00
|
|
|
export const exportClient = (client: ClientRepresentation): void => {
|
2021-12-08 15:08:42 +00:00
|
|
|
const clientCopy = cloneDeep(client);
|
2020-10-02 13:56:46 +00:00
|
|
|
delete clientCopy.id;
|
|
|
|
|
|
|
|
if (clientCopy.protocolMappers) {
|
|
|
|
for (let i = 0; i < clientCopy.protocolMappers.length; i++) {
|
|
|
|
delete clientCopy.protocolMappers[i].id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-18 16:13:39 +00:00
|
|
|
saveAs(
|
2021-10-08 18:21:09 +00:00
|
|
|
new Blob([prettyPrintJSON(clientCopy)], {
|
2020-10-02 13:56:46 +00:00
|
|
|
type: "application/json",
|
|
|
|
}),
|
2023-07-11 14:03:21 +00:00
|
|
|
clientCopy.clientId + ".json",
|
2020-10-02 13:56:46 +00:00
|
|
|
);
|
|
|
|
};
|
2020-10-20 20:47:23 +00:00
|
|
|
|
2021-09-14 15:48:48 +00:00
|
|
|
export const toUpperCase = <T extends string>(name: T) =>
|
|
|
|
(name.charAt(0).toUpperCase() + name.slice(1)) as Capitalize<T>;
|
2021-01-13 19:59:45 +00:00
|
|
|
|
2023-12-05 13:09:55 +00:00
|
|
|
const isAttributesObject = (value: any) =>
|
|
|
|
Object.values(value).filter(
|
|
|
|
(value) => Array.isArray(value) && value.length >= 1,
|
|
|
|
).length !== 0;
|
2021-11-08 09:46:03 +00:00
|
|
|
|
2021-12-08 15:08:42 +00:00
|
|
|
const isAttributeArray = (value: any) => {
|
|
|
|
if (!Array.isArray(value)) {
|
|
|
|
return false;
|
|
|
|
}
|
2022-04-05 07:39:32 +00:00
|
|
|
|
|
|
|
return value.some(
|
2023-07-11 14:03:21 +00:00
|
|
|
(e) => Object.hasOwn(e, "key") && Object.hasOwn(e, "value"),
|
2022-04-05 07:39:32 +00:00
|
|
|
);
|
2020-10-20 20:47:23 +00:00
|
|
|
};
|
|
|
|
|
2021-12-08 15:08:42 +00:00
|
|
|
const isEmpty = (obj: any) => Object.keys(obj).length === 0;
|
2021-08-09 19:28:24 +00:00
|
|
|
|
2022-12-02 14:54:30 +00:00
|
|
|
export function convertAttributeNameToForm<T>(
|
2023-07-11 14:03:21 +00:00
|
|
|
name: string,
|
2022-12-02 14:54:30 +00:00
|
|
|
): PathValue<T, Path<T>> {
|
2022-08-09 08:32:16 +00:00
|
|
|
const index = name.indexOf(".");
|
2022-11-25 14:58:10 +00:00
|
|
|
return `${name.substring(0, index)}.${beerify(
|
2023-07-11 14:03:21 +00:00
|
|
|
name.substring(index + 1),
|
2022-12-02 14:54:30 +00:00
|
|
|
)}` as PathValue<T, Path<T>>;
|
|
|
|
}
|
2022-08-09 08:32:16 +00:00
|
|
|
|
2022-12-02 14:54:30 +00:00
|
|
|
export const beerify = <T extends string>(name: T) =>
|
2022-11-24 15:48:22 +00:00
|
|
|
name.replaceAll(".", "🍺") as ReplaceString<T, ".", "🍺">;
|
|
|
|
|
2023-12-05 13:09:55 +00:00
|
|
|
export const debeerify = <T extends string>(name: T) =>
|
2022-11-24 15:48:22 +00:00
|
|
|
name.replaceAll("🍺", ".") as ReplaceString<T, "🍺", ".">;
|
2022-08-09 08:32:16 +00:00
|
|
|
|
2022-12-02 14:54:30 +00:00
|
|
|
export function convertToFormValues<T extends FieldValues>(
|
|
|
|
obj: FieldValues,
|
2023-07-11 14:03:21 +00:00
|
|
|
setValue: UseFormSetValue<T>,
|
2022-12-02 14:54:30 +00:00
|
|
|
) {
|
|
|
|
Object.entries(obj).map((entry) => {
|
|
|
|
const [key, value] = entry as [Path<T>, any];
|
2021-12-08 15:08:42 +00:00
|
|
|
if (key === "attributes" && isAttributesObject(value)) {
|
2022-04-20 17:11:46 +00:00
|
|
|
setValue(key, arrayToKeyValue(value as Record<string, string[]>));
|
2021-12-08 15:08:42 +00:00
|
|
|
} else if (key === "config" || key === "attributes") {
|
2022-04-27 15:32:47 +00:00
|
|
|
if (!isEmpty(value)) {
|
|
|
|
const flattened: any = flatten(value, { safe: true });
|
|
|
|
const convertedValues = Object.entries(flattened).map(([key, value]) =>
|
2023-11-27 11:52:37 +00:00
|
|
|
Array.isArray(value) && value.length === 1
|
|
|
|
? [key, value[0]]
|
|
|
|
: [key, value],
|
2022-04-27 15:32:47 +00:00
|
|
|
);
|
2022-08-09 08:32:16 +00:00
|
|
|
|
|
|
|
convertedValues.forEach(([k, v]) =>
|
2023-07-11 14:03:21 +00:00
|
|
|
setValue(`${key}.${beerify(k)}` as Path<T>, v),
|
2022-08-09 08:32:16 +00:00
|
|
|
);
|
2022-04-27 15:32:47 +00:00
|
|
|
} else {
|
2022-12-02 14:54:30 +00:00
|
|
|
setValue(key, undefined as PathValue<T, Path<T>>);
|
2022-04-27 15:32:47 +00:00
|
|
|
}
|
2021-12-08 15:08:42 +00:00
|
|
|
} else {
|
|
|
|
setValue(key, value);
|
|
|
|
}
|
2020-10-20 20:47:23 +00:00
|
|
|
});
|
2022-12-02 14:54:30 +00:00
|
|
|
}
|
2020-12-07 18:37:36 +00:00
|
|
|
|
2022-08-29 13:46:28 +00:00
|
|
|
export function convertFormValuesToObject<T extends Record<string, any>, G = T>(
|
2023-07-11 14:03:21 +00:00
|
|
|
obj: T,
|
2022-08-29 13:46:28 +00:00
|
|
|
): G {
|
2021-12-08 15:08:42 +00:00
|
|
|
const result: any = {};
|
|
|
|
Object.entries(obj).map(([key, value]) => {
|
|
|
|
if (isAttributeArray(value)) {
|
2022-04-20 17:11:46 +00:00
|
|
|
result[key] = keyValueToArray(value as KeyValueType[]);
|
2021-12-08 15:08:42 +00:00
|
|
|
} else if (key === "config" || key === "attributes") {
|
2022-08-09 08:32:16 +00:00
|
|
|
result[key] = Object.fromEntries(
|
2023-02-02 14:35:01 +00:00
|
|
|
Object.entries(
|
2023-07-11 14:03:21 +00:00
|
|
|
(value as Record<string, unknown> | undefined) || {},
|
|
|
|
).map(([k, v]) => [debeerify(k), v]),
|
2022-08-09 08:32:16 +00:00
|
|
|
);
|
2021-12-08 15:08:42 +00:00
|
|
|
} else {
|
|
|
|
result[key] = value;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-07-05 11:24:10 +00:00
|
|
|
export const emptyFormatter =
|
|
|
|
(): IFormatter => (data?: IFormatterValueType) => {
|
|
|
|
return data ? data : "—";
|
|
|
|
};
|
2021-01-13 19:59:45 +00:00
|
|
|
|
2021-07-05 11:24:10 +00:00
|
|
|
export const upperCaseFormatter =
|
|
|
|
(): IFormatter => (data?: IFormatterValueType) => {
|
|
|
|
const value = data?.toString();
|
2021-01-20 21:10:25 +00:00
|
|
|
|
2021-07-05 11:24:10 +00:00
|
|
|
return (value ? toUpperCase(value) : undefined) as string;
|
|
|
|
};
|
2021-01-20 21:10:25 +00:00
|
|
|
|
2022-01-17 19:26:42 +00:00
|
|
|
export const alphaRegexPattern = /[^A-Za-z]/g;
|
|
|
|
|
2021-07-05 11:24:10 +00:00
|
|
|
export const emailRegexPattern =
|
|
|
|
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
2021-08-09 19:28:24 +00:00
|
|
|
|
2021-08-20 16:15:12 +00:00
|
|
|
export const KEY_PROVIDER_TYPE = "org.keycloak.keys.KeyProvider";
|
2021-10-08 18:21:09 +00:00
|
|
|
|
|
|
|
export const prettyPrintJSON = (value: any) => JSON.stringify(value, null, 2);
|
2022-07-14 13:02:28 +00:00
|
|
|
|
|
|
|
export const addTrailingSlash = (url: string) =>
|
|
|
|
url.endsWith("/") ? url : url + "/";
|
2023-03-03 12:57:58 +00:00
|
|
|
|
|
|
|
export const generateId = () => Math.floor(Math.random() * 1000);
|
2024-01-08 14:03:26 +00:00
|
|
|
|
|
|
|
export const localeToDisplayName = (locale: string, displayLocale: string) => {
|
|
|
|
try {
|
|
|
|
return new Intl.DisplayNames([displayLocale], { type: "language" }).of(
|
2024-05-06 07:30:14 +00:00
|
|
|
// This is mapping old locale codes to the new locale codes for Simplified and Traditional Chinese.
|
|
|
|
// Once the existing locales have been moved, this code can be removed.
|
|
|
|
locale === "zh-CN" ? "zh-HANS" : locale === "zh-TW" ? "zh-HANT" : locale,
|
2024-01-08 14:03:26 +00:00
|
|
|
);
|
|
|
|
} catch (error) {
|
|
|
|
return locale;
|
|
|
|
}
|
|
|
|
};
|
2024-06-03 15:53:07 +00:00
|
|
|
|
|
|
|
const DARK_MODE_CLASS = "pf-v5-theme-dark";
|
|
|
|
const mediaQuery =
|
|
|
|
window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)");
|
|
|
|
|
|
|
|
updateDarkMode(mediaQuery?.matches);
|
|
|
|
mediaQuery?.addEventListener("change", (event: MediaQueryListEvent) =>
|
|
|
|
updateDarkMode(event.matches),
|
|
|
|
);
|
|
|
|
|
|
|
|
function updateDarkMode(isEnabled: boolean = false) {
|
|
|
|
const { classList } = document.documentElement;
|
|
|
|
|
|
|
|
if (isEnabled) {
|
|
|
|
classList.add(DARK_MODE_CLASS);
|
|
|
|
} else {
|
|
|
|
classList.remove(DARK_MODE_CLASS);
|
|
|
|
}
|
|
|
|
}
|