mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-10 15:32:05 -03:30
refactor the keyValue input to have a override component (#40130)
fixes: #40129 Signed-off-by: Erik Jan de Wit <erikjan.dewit@gmail.com>
This commit is contained in:
parent
25b88392cc
commit
066fd26dd7
@ -9,7 +9,7 @@ import { useState } from "react";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAdminClient } from "../../admin-client";
|
||||
import { KeySelect } from "../key-value-form/KeySelect";
|
||||
import { KeySelect } from "../../realm-settings/user-profile/attribute/KeySelect";
|
||||
import type { ComponentProps } from "./components";
|
||||
|
||||
export const UserProfileAttributeListComponent = ({
|
||||
@ -40,7 +40,7 @@ export const UserProfileAttributeListComponent = ({
|
||||
|
||||
return config.attributes.map((option) => ({
|
||||
key: option.name!,
|
||||
label: option.name!,
|
||||
value: option.name!,
|
||||
}));
|
||||
};
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ import {
|
||||
TextInput,
|
||||
} from "@patternfly/react-core";
|
||||
import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons";
|
||||
import { Fragment } from "react";
|
||||
import { Fragment, FunctionComponent, PropsWithChildren } from "react";
|
||||
import {
|
||||
FieldValues,
|
||||
useFieldArray,
|
||||
@ -21,27 +21,34 @@ import {
|
||||
} from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
import { KeySelect } from "./KeySelect";
|
||||
import { ValueSelect } from "./ValueSelect";
|
||||
|
||||
export type DefaultValue = {
|
||||
key: string;
|
||||
values?: string[];
|
||||
label: string;
|
||||
};
|
||||
|
||||
type KeyValueInputProps = {
|
||||
type Field = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
type ValueField = Field & {
|
||||
keyValue: string;
|
||||
};
|
||||
|
||||
type KeyValueInputProps = PropsWithChildren & {
|
||||
name: string;
|
||||
label?: string;
|
||||
defaultKeyValue?: DefaultValue[];
|
||||
isDisabled?: boolean;
|
||||
KeyComponent?: FunctionComponent<Field>;
|
||||
ValueComponent?: FunctionComponent<ValueField>;
|
||||
};
|
||||
|
||||
export const KeyValueInput = ({
|
||||
name,
|
||||
label = "attributes",
|
||||
defaultKeyValue,
|
||||
isDisabled = false,
|
||||
KeyComponent,
|
||||
ValueComponent,
|
||||
}: KeyValueInputProps) => {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
@ -80,12 +87,8 @@ export const KeyValueInput = ({
|
||||
return (
|
||||
<Fragment key={attribute.id}>
|
||||
<GridItem span={5}>
|
||||
{defaultKeyValue ? (
|
||||
<KeySelect
|
||||
name={`${name}.${index}.key`}
|
||||
selectItems={defaultKeyValue}
|
||||
rules={{ required: true }}
|
||||
/>
|
||||
{KeyComponent ? (
|
||||
<KeyComponent name={`${name}.${index}.key`} />
|
||||
) : (
|
||||
<TextInput
|
||||
placeholder={t("keyPlaceholder")}
|
||||
@ -106,12 +109,10 @@ export const KeyValueInput = ({
|
||||
)}
|
||||
</GridItem>
|
||||
<GridItem span={5}>
|
||||
{defaultKeyValue ? (
|
||||
<ValueSelect
|
||||
{ValueComponent ? (
|
||||
<ValueComponent
|
||||
name={`${name}.${index}.value`}
|
||||
keyValue={values[index]?.key}
|
||||
selectItems={defaultKeyValue}
|
||||
rules={{ required: true }}
|
||||
/>
|
||||
) : (
|
||||
<TextInput
|
||||
|
||||
@ -104,9 +104,9 @@ export { HelpHeader } from "./components/help-enabler/HelpHeader";
|
||||
export { FileUploadForm } from "./components/json-file-upload/FileUploadForm";
|
||||
export { JsonFileUpload } from "./components/json-file-upload/JsonFileUpload";
|
||||
export { AttributesForm } from "./components/key-value-form/AttributeForm";
|
||||
export { KeySelect } from "./components/key-value-form/KeySelect";
|
||||
export { KeySelect } from "./realm-settings/user-profile/attribute/KeySelect";
|
||||
export { KeyValueInput } from "./components/key-value-form/KeyValueInput";
|
||||
export { ValueSelect } from "./components/key-value-form/ValueSelect";
|
||||
export { ValueSelect } from "./realm-settings/user-profile/attribute/ValueSelect";
|
||||
export { ClickableCard } from "./components/keycloak-card/ClickableCard";
|
||||
export { KeycloakCard } from "./components/keycloak-card/KeycloakCard";
|
||||
export { MultiLineInput } from "./components/multi-line-input/MultiLineInput";
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import { FormGroup, Grid, GridItem, TextInput } from "@patternfly/react-core";
|
||||
import { useFormContext } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FormGroup, Grid, GridItem } from "@patternfly/react-core";
|
||||
|
||||
import { FormAccess } from "../../../components/form/FormAccess";
|
||||
import { KeyValueInput } from "../../../components/key-value-form/KeyValueInput";
|
||||
import { KeySelect } from "./KeySelect";
|
||||
import { ValueSelect } from "./ValueSelect";
|
||||
|
||||
import "../../realm-settings-section.css";
|
||||
|
||||
export const AttributeAnnotations = () => {
|
||||
const { t } = useTranslation();
|
||||
const { register } = useFormContext();
|
||||
|
||||
return (
|
||||
<FormAccess role="manage-realm" isHorizontal>
|
||||
@ -22,70 +25,90 @@ export const AttributeAnnotations = () => {
|
||||
<KeyValueInput
|
||||
name="annotations"
|
||||
label={t("annotations")}
|
||||
defaultKeyValue={[
|
||||
{
|
||||
key: "inputType",
|
||||
label: t("inputType"),
|
||||
values: [
|
||||
"text",
|
||||
"textarea",
|
||||
"select",
|
||||
"select-radiobuttons",
|
||||
"multiselect",
|
||||
"multiselect-checkboxes",
|
||||
"html5-email",
|
||||
"html5-tel",
|
||||
"html5-url",
|
||||
"html5-number",
|
||||
"html5-range",
|
||||
"html5-datetime-local",
|
||||
"html5-date",
|
||||
"html5-month",
|
||||
"html5-week",
|
||||
"html5-time",
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "inputHelperTextBefore",
|
||||
label: t("inputHelperTextBefore"),
|
||||
},
|
||||
{
|
||||
key: "inputHelperTextAfter",
|
||||
label: t("inputHelperTextAfter"),
|
||||
},
|
||||
{
|
||||
key: "inputOptionLabelsI18nPrefix",
|
||||
label: t("inputOptionLabelsI18nPrefix"),
|
||||
},
|
||||
{
|
||||
key: "inputTypePlaceholder",
|
||||
label: t("inputTypePlaceholder"),
|
||||
},
|
||||
{
|
||||
key: "inputTypeSize",
|
||||
label: t("inputTypeSize"),
|
||||
},
|
||||
{
|
||||
key: "inputTypeCols",
|
||||
label: t("inputTypeCols"),
|
||||
},
|
||||
{
|
||||
key: "inputTypeRows",
|
||||
label: t("inputTypeRows"),
|
||||
},
|
||||
{
|
||||
key: "inputTypeStep",
|
||||
label: t("inputTypeStep"),
|
||||
},
|
||||
{
|
||||
key: "kcNumberFormat",
|
||||
label: t("kcNumberFormat"),
|
||||
},
|
||||
{
|
||||
key: "kcNumberUnFormat",
|
||||
label: t("kcNumberUnFormat"),
|
||||
},
|
||||
]}
|
||||
KeyComponent={(props) => (
|
||||
<KeySelect
|
||||
{...props}
|
||||
selectItems={[
|
||||
{
|
||||
key: "inputType",
|
||||
value: t("inputType"),
|
||||
},
|
||||
{
|
||||
key: "inputHelperTextBefore",
|
||||
value: t("inputHelperTextBefore"),
|
||||
},
|
||||
{
|
||||
key: "inputHelperTextAfter",
|
||||
value: t("inputHelperTextAfter"),
|
||||
},
|
||||
{
|
||||
key: "inputOptionLabelsI18nPrefix",
|
||||
value: t("inputOptionLabelsI18nPrefix"),
|
||||
},
|
||||
{
|
||||
key: "inputTypePlaceholder",
|
||||
value: t("inputTypePlaceholder"),
|
||||
},
|
||||
{
|
||||
key: "inputTypeSize",
|
||||
value: t("inputTypeSize"),
|
||||
},
|
||||
{
|
||||
key: "inputTypeCols",
|
||||
value: t("inputTypeCols"),
|
||||
},
|
||||
{
|
||||
key: "inputTypeRows",
|
||||
value: t("inputTypeRows"),
|
||||
},
|
||||
{
|
||||
key: "inputTypeStep",
|
||||
value: t("inputTypeStep"),
|
||||
},
|
||||
{
|
||||
key: "kcNumberFormat",
|
||||
value: t("kcNumberFormat"),
|
||||
},
|
||||
{
|
||||
key: "kcNumberUnFormat",
|
||||
value: t("kcNumberUnFormat"),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
ValueComponent={(props) =>
|
||||
props.keyValue === "inputType" ? (
|
||||
<ValueSelect
|
||||
selectItems={[
|
||||
"text",
|
||||
"textarea",
|
||||
"select",
|
||||
"select-radiobuttons",
|
||||
"multiselect",
|
||||
"multiselect-checkboxes",
|
||||
"html5-email",
|
||||
"html5-tel",
|
||||
"html5-url",
|
||||
"html5-number",
|
||||
"html5-range",
|
||||
"html5-datetime-local",
|
||||
"html5-date",
|
||||
"html5-month",
|
||||
"html5-week",
|
||||
"html5-time",
|
||||
]}
|
||||
rules={{ required: true }}
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
<TextInput
|
||||
aria-label={t("customValue")}
|
||||
data-testid={props.name}
|
||||
{...props}
|
||||
{...register(props.name)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
import { KeycloakSelect } from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
KeycloakSelect,
|
||||
SelectControlOption,
|
||||
} from "@keycloak/keycloak-ui-shared";
|
||||
import {
|
||||
Grid,
|
||||
GridItem,
|
||||
@ -8,11 +11,10 @@ import {
|
||||
import { useState } from "react";
|
||||
import { UseControllerProps, useController } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import useToggle from "../../utils/useToggle";
|
||||
import { DefaultValue } from "./KeyValueInput";
|
||||
import useToggle from "../../../utils/useToggle";
|
||||
|
||||
type KeySelectProp = UseControllerProps & {
|
||||
selectItems: DefaultValue[];
|
||||
selectItems: SelectControlOption[];
|
||||
};
|
||||
|
||||
export const KeySelect = ({ selectItems, ...rest }: KeySelectProp) => {
|
||||
@ -44,7 +46,7 @@ export const KeySelect = ({ selectItems, ...rest }: KeySelectProp) => {
|
||||
</SelectOption>,
|
||||
...selectItems.map((item) => (
|
||||
<SelectOption key={item.key} value={item.key}>
|
||||
{item.label}
|
||||
{item.value}
|
||||
</SelectOption>
|
||||
)),
|
||||
]}
|
||||
@ -1,30 +1,19 @@
|
||||
import { KeycloakSelect } from "@keycloak/keycloak-ui-shared";
|
||||
import { SelectOption, TextInput } from "@patternfly/react-core";
|
||||
import { useMemo, useState } from "react";
|
||||
import { SelectOption } from "@patternfly/react-core";
|
||||
import { useState } from "react";
|
||||
import { UseControllerProps, useController } from "react-hook-form";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { DefaultValue } from "./KeyValueInput";
|
||||
|
||||
type ValueSelectProps = UseControllerProps & {
|
||||
selectItems: DefaultValue[];
|
||||
keyValue: string;
|
||||
selectItems: string[];
|
||||
};
|
||||
|
||||
export const ValueSelect = ({
|
||||
selectItems,
|
||||
keyValue,
|
||||
...rest
|
||||
}: ValueSelectProps) => {
|
||||
export const ValueSelect = ({ selectItems, ...rest }: ValueSelectProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { field } = useController(rest);
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const defaultItem = useMemo(
|
||||
() => selectItems.find((v) => v.key === keyValue),
|
||||
[selectItems, keyValue],
|
||||
);
|
||||
|
||||
return defaultItem?.values ? (
|
||||
return (
|
||||
<KeycloakSelect
|
||||
onToggle={(isOpen) => setOpen(isOpen)}
|
||||
isOpen={open}
|
||||
@ -35,17 +24,11 @@ export const ValueSelect = ({
|
||||
selections={field.value ? [field.value] : t("choose")}
|
||||
placeholderText={t("valuePlaceholder")}
|
||||
>
|
||||
{defaultItem.values.map((item) => (
|
||||
{selectItems.map((item) => (
|
||||
<SelectOption key={item} value={item}>
|
||||
{item}
|
||||
</SelectOption>
|
||||
))}
|
||||
</KeycloakSelect>
|
||||
) : (
|
||||
<TextInput
|
||||
aria-label={t("customValue")}
|
||||
data-testid={rest.name}
|
||||
{...field}
|
||||
/>
|
||||
);
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user