Skip to content

Commit 066fd26

Browse files
authored
refactor the keyValue input to have a override component (#40130)
fixes: #40129 Signed-off-by: Erik Jan de Wit <[email protected]>
1 parent 25b8839 commit 066fd26

File tree

6 files changed

+124
-115
lines changed

6 files changed

+124
-115
lines changed

js/apps/admin-ui/src/components/dynamic/UserProfileAttributeListComponent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { useState } from "react";
99
import { useFormContext } from "react-hook-form";
1010
import { useTranslation } from "react-i18next";
1111
import { useAdminClient } from "../../admin-client";
12-
import { KeySelect } from "../key-value-form/KeySelect";
12+
import { KeySelect } from "../../realm-settings/user-profile/attribute/KeySelect";
1313
import type { ComponentProps } from "./components";
1414

1515
export const UserProfileAttributeListComponent = ({
@@ -40,7 +40,7 @@ export const UserProfileAttributeListComponent = ({
4040

4141
return config.attributes.map((option) => ({
4242
key: option.name!,
43-
label: option.name!,
43+
value: option.name!,
4444
}));
4545
};
4646

js/apps/admin-ui/src/components/key-value-form/KeyValueInput.tsx

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
TextInput,
1313
} from "@patternfly/react-core";
1414
import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons";
15-
import { Fragment } from "react";
15+
import { Fragment, FunctionComponent, PropsWithChildren } from "react";
1616
import {
1717
FieldValues,
1818
useFieldArray,
@@ -21,27 +21,34 @@ import {
2121
} from "react-hook-form";
2222
import { useTranslation } from "react-i18next";
2323

24-
import { KeySelect } from "./KeySelect";
25-
import { ValueSelect } from "./ValueSelect";
26-
2724
export type DefaultValue = {
2825
key: string;
2926
values?: string[];
3027
label: string;
3128
};
3229

33-
type KeyValueInputProps = {
30+
type Field = {
31+
name: string;
32+
};
33+
34+
type ValueField = Field & {
35+
keyValue: string;
36+
};
37+
38+
type KeyValueInputProps = PropsWithChildren & {
3439
name: string;
3540
label?: string;
36-
defaultKeyValue?: DefaultValue[];
3741
isDisabled?: boolean;
42+
KeyComponent?: FunctionComponent<Field>;
43+
ValueComponent?: FunctionComponent<ValueField>;
3844
};
3945

4046
export const KeyValueInput = ({
4147
name,
4248
label = "attributes",
43-
defaultKeyValue,
4449
isDisabled = false,
50+
KeyComponent,
51+
ValueComponent,
4552
}: KeyValueInputProps) => {
4653
const { t } = useTranslation();
4754
const {
@@ -80,12 +87,8 @@ export const KeyValueInput = ({
8087
return (
8188
<Fragment key={attribute.id}>
8289
<GridItem span={5}>
83-
{defaultKeyValue ? (
84-
<KeySelect
85-
name={`${name}.${index}.key`}
86-
selectItems={defaultKeyValue}
87-
rules={{ required: true }}
88-
/>
90+
{KeyComponent ? (
91+
<KeyComponent name={`${name}.${index}.key`} />
8992
) : (
9093
<TextInput
9194
placeholder={t("keyPlaceholder")}
@@ -106,12 +109,10 @@ export const KeyValueInput = ({
106109
)}
107110
</GridItem>
108111
<GridItem span={5}>
109-
{defaultKeyValue ? (
110-
<ValueSelect
112+
{ValueComponent ? (
113+
<ValueComponent
111114
name={`${name}.${index}.value`}
112115
keyValue={values[index]?.key}
113-
selectItems={defaultKeyValue}
114-
rules={{ required: true }}
115116
/>
116117
) : (
117118
<TextInput

js/apps/admin-ui/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ export { HelpHeader } from "./components/help-enabler/HelpHeader";
104104
export { FileUploadForm } from "./components/json-file-upload/FileUploadForm";
105105
export { JsonFileUpload } from "./components/json-file-upload/JsonFileUpload";
106106
export { AttributesForm } from "./components/key-value-form/AttributeForm";
107-
export { KeySelect } from "./components/key-value-form/KeySelect";
107+
export { KeySelect } from "./realm-settings/user-profile/attribute/KeySelect";
108108
export { KeyValueInput } from "./components/key-value-form/KeyValueInput";
109-
export { ValueSelect } from "./components/key-value-form/ValueSelect";
109+
export { ValueSelect } from "./realm-settings/user-profile/attribute/ValueSelect";
110110
export { ClickableCard } from "./components/keycloak-card/ClickableCard";
111111
export { KeycloakCard } from "./components/keycloak-card/KeycloakCard";
112112
export { MultiLineInput } from "./components/multi-line-input/MultiLineInput";

js/apps/admin-ui/src/realm-settings/user-profile/attribute/AttributeAnnotations.tsx

Lines changed: 89 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1+
import { FormGroup, Grid, GridItem, TextInput } from "@patternfly/react-core";
2+
import { useFormContext } from "react-hook-form";
13
import { useTranslation } from "react-i18next";
2-
import { FormGroup, Grid, GridItem } from "@patternfly/react-core";
3-
44
import { FormAccess } from "../../../components/form/FormAccess";
55
import { KeyValueInput } from "../../../components/key-value-form/KeyValueInput";
6+
import { KeySelect } from "./KeySelect";
7+
import { ValueSelect } from "./ValueSelect";
68

79
import "../../realm-settings-section.css";
810

911
export const AttributeAnnotations = () => {
1012
const { t } = useTranslation();
13+
const { register } = useFormContext();
1114

1215
return (
1316
<FormAccess role="manage-realm" isHorizontal>
@@ -22,70 +25,90 @@ export const AttributeAnnotations = () => {
2225
<KeyValueInput
2326
name="annotations"
2427
label={t("annotations")}
25-
defaultKeyValue={[
26-
{
27-
key: "inputType",
28-
label: t("inputType"),
29-
values: [
30-
"text",
31-
"textarea",
32-
"select",
33-
"select-radiobuttons",
34-
"multiselect",
35-
"multiselect-checkboxes",
36-
"html5-email",
37-
"html5-tel",
38-
"html5-url",
39-
"html5-number",
40-
"html5-range",
41-
"html5-datetime-local",
42-
"html5-date",
43-
"html5-month",
44-
"html5-week",
45-
"html5-time",
46-
],
47-
},
48-
{
49-
key: "inputHelperTextBefore",
50-
label: t("inputHelperTextBefore"),
51-
},
52-
{
53-
key: "inputHelperTextAfter",
54-
label: t("inputHelperTextAfter"),
55-
},
56-
{
57-
key: "inputOptionLabelsI18nPrefix",
58-
label: t("inputOptionLabelsI18nPrefix"),
59-
},
60-
{
61-
key: "inputTypePlaceholder",
62-
label: t("inputTypePlaceholder"),
63-
},
64-
{
65-
key: "inputTypeSize",
66-
label: t("inputTypeSize"),
67-
},
68-
{
69-
key: "inputTypeCols",
70-
label: t("inputTypeCols"),
71-
},
72-
{
73-
key: "inputTypeRows",
74-
label: t("inputTypeRows"),
75-
},
76-
{
77-
key: "inputTypeStep",
78-
label: t("inputTypeStep"),
79-
},
80-
{
81-
key: "kcNumberFormat",
82-
label: t("kcNumberFormat"),
83-
},
84-
{
85-
key: "kcNumberUnFormat",
86-
label: t("kcNumberUnFormat"),
87-
},
88-
]}
28+
KeyComponent={(props) => (
29+
<KeySelect
30+
{...props}
31+
selectItems={[
32+
{
33+
key: "inputType",
34+
value: t("inputType"),
35+
},
36+
{
37+
key: "inputHelperTextBefore",
38+
value: t("inputHelperTextBefore"),
39+
},
40+
{
41+
key: "inputHelperTextAfter",
42+
value: t("inputHelperTextAfter"),
43+
},
44+
{
45+
key: "inputOptionLabelsI18nPrefix",
46+
value: t("inputOptionLabelsI18nPrefix"),
47+
},
48+
{
49+
key: "inputTypePlaceholder",
50+
value: t("inputTypePlaceholder"),
51+
},
52+
{
53+
key: "inputTypeSize",
54+
value: t("inputTypeSize"),
55+
},
56+
{
57+
key: "inputTypeCols",
58+
value: t("inputTypeCols"),
59+
},
60+
{
61+
key: "inputTypeRows",
62+
value: t("inputTypeRows"),
63+
},
64+
{
65+
key: "inputTypeStep",
66+
value: t("inputTypeStep"),
67+
},
68+
{
69+
key: "kcNumberFormat",
70+
value: t("kcNumberFormat"),
71+
},
72+
{
73+
key: "kcNumberUnFormat",
74+
value: t("kcNumberUnFormat"),
75+
},
76+
]}
77+
/>
78+
)}
79+
ValueComponent={(props) =>
80+
props.keyValue === "inputType" ? (
81+
<ValueSelect
82+
selectItems={[
83+
"text",
84+
"textarea",
85+
"select",
86+
"select-radiobuttons",
87+
"multiselect",
88+
"multiselect-checkboxes",
89+
"html5-email",
90+
"html5-tel",
91+
"html5-url",
92+
"html5-number",
93+
"html5-range",
94+
"html5-datetime-local",
95+
"html5-date",
96+
"html5-month",
97+
"html5-week",
98+
"html5-time",
99+
]}
100+
rules={{ required: true }}
101+
{...props}
102+
/>
103+
) : (
104+
<TextInput
105+
aria-label={t("customValue")}
106+
data-testid={props.name}
107+
{...props}
108+
{...register(props.name)}
109+
/>
110+
)
111+
}
89112
/>
90113
</GridItem>
91114
</Grid>

js/apps/admin-ui/src/components/key-value-form/KeySelect.tsx renamed to js/apps/admin-ui/src/realm-settings/user-profile/attribute/KeySelect.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { KeycloakSelect } from "@keycloak/keycloak-ui-shared";
1+
import {
2+
KeycloakSelect,
3+
SelectControlOption,
4+
} from "@keycloak/keycloak-ui-shared";
25
import {
36
Grid,
47
GridItem,
@@ -8,11 +11,10 @@ import {
811
import { useState } from "react";
912
import { UseControllerProps, useController } from "react-hook-form";
1013
import { useTranslation } from "react-i18next";
11-
import useToggle from "../../utils/useToggle";
12-
import { DefaultValue } from "./KeyValueInput";
14+
import useToggle from "../../../utils/useToggle";
1315

1416
type KeySelectProp = UseControllerProps & {
15-
selectItems: DefaultValue[];
17+
selectItems: SelectControlOption[];
1618
};
1719

1820
export const KeySelect = ({ selectItems, ...rest }: KeySelectProp) => {
@@ -44,7 +46,7 @@ export const KeySelect = ({ selectItems, ...rest }: KeySelectProp) => {
4446
</SelectOption>,
4547
...selectItems.map((item) => (
4648
<SelectOption key={item.key} value={item.key}>
47-
{item.label}
49+
{item.value}
4850
</SelectOption>
4951
)),
5052
]}

js/apps/admin-ui/src/components/key-value-form/ValueSelect.tsx renamed to js/apps/admin-ui/src/realm-settings/user-profile/attribute/ValueSelect.tsx

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,19 @@
11
import { KeycloakSelect } from "@keycloak/keycloak-ui-shared";
2-
import { SelectOption, TextInput } from "@patternfly/react-core";
3-
import { useMemo, useState } from "react";
2+
import { SelectOption } from "@patternfly/react-core";
3+
import { useState } from "react";
44
import { UseControllerProps, useController } from "react-hook-form";
55
import { useTranslation } from "react-i18next";
6-
import { DefaultValue } from "./KeyValueInput";
76

87
type ValueSelectProps = UseControllerProps & {
9-
selectItems: DefaultValue[];
10-
keyValue: string;
8+
selectItems: string[];
119
};
1210

13-
export const ValueSelect = ({
14-
selectItems,
15-
keyValue,
16-
...rest
17-
}: ValueSelectProps) => {
11+
export const ValueSelect = ({ selectItems, ...rest }: ValueSelectProps) => {
1812
const { t } = useTranslation();
1913
const { field } = useController(rest);
2014
const [open, setOpen] = useState(false);
2115

22-
const defaultItem = useMemo(
23-
() => selectItems.find((v) => v.key === keyValue),
24-
[selectItems, keyValue],
25-
);
26-
27-
return defaultItem?.values ? (
16+
return (
2817
<KeycloakSelect
2918
onToggle={(isOpen) => setOpen(isOpen)}
3019
isOpen={open}
@@ -35,17 +24,11 @@ export const ValueSelect = ({
3524
selections={field.value ? [field.value] : t("choose")}
3625
placeholderText={t("valuePlaceholder")}
3726
>
38-
{defaultItem.values.map((item) => (
27+
{selectItems.map((item) => (
3928
<SelectOption key={item} value={item}>
4029
{item}
4130
</SelectOption>
4231
))}
4332
</KeycloakSelect>
44-
) : (
45-
<TextInput
46-
aria-label={t("customValue")}
47-
data-testid={rest.name}
48-
{...field}
49-
/>
5033
);
5134
};

0 commit comments

Comments
 (0)