Issue 3604 (#3739)

This commit is contained in:
Erik Jan de Wit 2022-11-10 11:17:49 -05:00 committed by GitHub
parent 334ca1dddf
commit 0ab33d552b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 122 additions and 12 deletions

View file

@ -1,14 +1,66 @@
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FormGroup } from "@patternfly/react-core"; import { useFormContext } from "react-hook-form";
import {
ActionList,
ActionListItem,
Button,
Flex,
FlexItem,
FormGroup,
TextInput,
} from "@patternfly/react-core";
import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons";
import type { ComponentProps } from "./components"; import type { ComponentProps } from "./components";
import { HelpItem } from "../help-enabler/HelpItem"; import { HelpItem } from "../help-enabler/HelpItem";
import { KeyValueInput } from "../key-value-form/KeyValueInput";
import { convertToName } from "./DynamicComponents"; import { convertToName } from "./DynamicComponents";
import { KeyValueType } from "../key-value-form/key-value-convert";
type IdKeyValueType = KeyValueType & {
id: number;
};
const generateId = () => Math.floor(Math.random() * 100);
export const MapComponent = ({ name, label, helpText }: ComponentProps) => { export const MapComponent = ({ name, label, helpText }: ComponentProps) => {
const { t } = useTranslation("dynamic"); const { t } = useTranslation("dynamic");
const { getValues, setValue, register } = useFormContext();
const [map, setMap] = useState<IdKeyValueType[]>([]);
const fieldName = convertToName(name!);
useEffect(() => {
register(fieldName);
const values: KeyValueType[] = JSON.parse(getValues(fieldName) || "[]");
if (!values.length) {
values.push({ key: "", value: "" });
}
setMap(values.map((value) => ({ ...value, id: generateId() })));
}, [register, getValues]);
const update = (val = map) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
setValue(fieldName, JSON.stringify(val.map(({ id, ...entry }) => entry)));
};
const updateKey = (index: number, key: string) => {
updateEntry(index, { ...map[index], key });
};
const updateValue = (index: number, value: string) => {
updateEntry(index, { ...map[index], value });
};
const updateEntry = (index: number, entry: IdKeyValueType) =>
setMap([...map.slice(0, index), entry, ...map.slice(index + 1)]);
const remove = (index: number) => {
const value = [...map.slice(0, index), ...map.slice(index + 1)];
setMap(value);
update(value);
};
return ( return (
<FormGroup <FormGroup
label={t(label!)} label={t(label!)}
@ -17,7 +69,74 @@ export const MapComponent = ({ name, label, helpText }: ComponentProps) => {
} }
fieldId={name!} fieldId={name!}
> >
<KeyValueInput name={convertToName(name!)} /> <Flex direction={{ default: "column" }}>
<Flex>
<FlexItem
grow={{ default: "grow" }}
spacer={{ default: "spacerNone" }}
>
<strong>{t("common:key")}</strong>
</FlexItem>
<FlexItem grow={{ default: "grow" }}>
<strong>{t("common:value")}</strong>
</FlexItem>
</Flex>
{map.map((attribute, index) => (
<Flex key={attribute.id} data-testid="row">
<FlexItem grow={{ default: "grow" }}>
<TextInput
name={`${fieldName}[${index}].key`}
placeholder={t("common:keyPlaceholder")}
aria-label={t("key")}
defaultValue={attribute.key}
data-testid={`${fieldName}[${index}].key`}
onChange={(value) => updateKey(index, value)}
onBlur={() => update()}
/>
</FlexItem>
<FlexItem
grow={{ default: "grow" }}
spacer={{ default: "spacerNone" }}
>
<TextInput
name={`${fieldName}[${index}].value`}
placeholder={t("common:valuePlaceholder")}
aria-label={t("common:value")}
defaultValue={attribute.value}
data-testid={`${fieldName}[${index}].value`}
onChange={(value) => updateValue(index, value)}
onBlur={() => update()}
/>
</FlexItem>
<FlexItem>
<Button
variant="link"
title={t("common:removeAttribute")}
isDisabled={map.length === 1}
onClick={() => remove(index)}
data-testid={`${fieldName}[${index}].remove`}
>
<MinusCircleIcon />
</Button>
</FlexItem>
</Flex>
))}
</Flex>
<ActionList>
<ActionListItem>
<Button
data-testid={`${fieldName}-add-row`}
className="pf-u-px-0 pf-u-mt-sm"
variant="link"
icon={<PlusCircleIcon />}
onClick={() =>
setMap([...map, { key: "", value: "", id: generateId() }])
}
>
{t("common:addAttribute")}
</Button>
</ActionListItem>
</ActionList>
</FormGroup> </FormGroup>
); );
}; };

View file

@ -70,15 +70,11 @@ export default function AddMapper() {
const save = async (idpMapper: IdentityProviderMapperRepresentation) => { const save = async (idpMapper: IdentityProviderMapperRepresentation) => {
const mapper = convertFormValuesToObject(idpMapper); const mapper = convertFormValuesToObject(idpMapper);
const attributes = JSON.stringify(idpMapper.config.attributes ?? []);
const claims = JSON.stringify(idpMapper.config.claims ?? []);
const identityProviderMapper = { const identityProviderMapper = {
...mapper, ...mapper,
config: { config: {
...mapper.config, ...mapper.config,
attributes,
claims,
}, },
identityProviderAlias: alias!, identityProviderAlias: alias!,
}; };
@ -165,11 +161,6 @@ export default function AddMapper() {
const setupForm = (mapper: IdentityProviderMapperRepresentation) => { const setupForm = (mapper: IdentityProviderMapperRepresentation) => {
convertToFormValues(mapper, form.setValue); convertToFormValues(mapper, form.setValue);
form.setValue(
"config.attributes",
JSON.parse(mapper.config.attributes || "{}")
);
form.setValue("config.claims", JSON.parse(mapper.config.claims || "{}"));
}; };
if (!mapperTypes || !currentMapper) { if (!mapperTypes || !currentMapper) {