2021-03-31 19:07:04 +00:00
|
|
|
import React, { useEffect } from "react";
|
2020-12-04 20:37:29 +00:00
|
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import { ArrayField, UseFormMethods } from "react-hook-form";
|
2020-12-02 14:48:06 +00:00
|
|
|
import { ActionGroup, Button, TextInput } from "@patternfly/react-core";
|
2020-12-15 07:21:17 +00:00
|
|
|
import {
|
|
|
|
TableComposable,
|
|
|
|
Tbody,
|
|
|
|
Td,
|
|
|
|
Th,
|
|
|
|
Thead,
|
|
|
|
Tr,
|
|
|
|
} from "@patternfly/react-table";
|
2020-12-02 14:48:06 +00:00
|
|
|
import { MinusCircleIcon, PlusCircleIcon } from "@patternfly/react-icons";
|
2020-12-04 20:37:29 +00:00
|
|
|
|
2021-03-16 12:37:57 +00:00
|
|
|
import { FormAccess } from "../form-access/FormAccess";
|
2020-12-04 20:37:29 +00:00
|
|
|
|
2021-03-16 12:37:57 +00:00
|
|
|
import "./attribute-form.css";
|
2020-12-15 07:21:17 +00:00
|
|
|
|
2020-12-02 14:48:06 +00:00
|
|
|
export type KeyValueType = { key: string; value: string };
|
2020-12-15 07:21:17 +00:00
|
|
|
|
2021-03-16 12:37:57 +00:00
|
|
|
export type AttributeForm = {
|
|
|
|
attributes: KeyValueType[];
|
|
|
|
};
|
|
|
|
|
|
|
|
export type AttributesFormProps = {
|
|
|
|
form: UseFormMethods<AttributeForm>;
|
|
|
|
save: (model: AttributeForm) => void;
|
2021-01-26 20:06:16 +00:00
|
|
|
reset: () => void;
|
2020-12-04 20:37:29 +00:00
|
|
|
array: {
|
|
|
|
fields: Partial<ArrayField<Record<string, any>, "id">>[];
|
|
|
|
append: (
|
|
|
|
value: Partial<Record<string, any>> | Partial<Record<string, any>>[],
|
|
|
|
shouldFocus?: boolean | undefined
|
|
|
|
) => void;
|
|
|
|
remove: (index?: number | number[] | undefined) => void;
|
|
|
|
};
|
2020-12-02 14:48:06 +00:00
|
|
|
};
|
2020-12-15 07:21:17 +00:00
|
|
|
|
2021-03-16 12:37:57 +00:00
|
|
|
export const arrayToAttributes = (attributeArray: KeyValueType[]) => {
|
|
|
|
const initValue: { [index: string]: string[] } = {};
|
|
|
|
return attributeArray.reduce((acc, attribute) => {
|
|
|
|
acc[attribute.key] = [attribute.value];
|
|
|
|
return acc;
|
|
|
|
}, initValue);
|
|
|
|
};
|
|
|
|
|
|
|
|
export const attributesToArray = (attributes?: {
|
|
|
|
[key: string]: string[];
|
|
|
|
}): KeyValueType[] => {
|
|
|
|
if (!attributes || Object.keys(attributes).length == 0) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
return Object.keys(attributes).map((key) => ({
|
|
|
|
key: key,
|
|
|
|
value: attributes[key][0],
|
|
|
|
}));
|
|
|
|
};
|
|
|
|
|
|
|
|
export const AttributesForm = ({
|
2021-01-28 19:16:11 +00:00
|
|
|
form: { handleSubmit, register, formState, errors, watch },
|
2020-12-04 20:37:29 +00:00
|
|
|
array: { fields, append, remove },
|
2021-01-26 20:06:16 +00:00
|
|
|
reset,
|
2021-03-22 08:14:24 +00:00
|
|
|
save,
|
2021-03-16 12:37:57 +00:00
|
|
|
}: AttributesFormProps) => {
|
2020-12-02 14:48:06 +00:00
|
|
|
const { t } = useTranslation("roles");
|
2020-12-15 07:21:17 +00:00
|
|
|
|
2020-12-02 14:48:06 +00:00
|
|
|
const columns = ["Key", "Value"];
|
2021-03-29 11:35:13 +00:00
|
|
|
|
|
|
|
const watchLast = watch(`attributes[${fields.length - 1}].key`, "");
|
|
|
|
|
2021-03-31 19:07:04 +00:00
|
|
|
useEffect(() => {
|
|
|
|
if (fields.length === 0) {
|
|
|
|
append({ key: "", value: "" });
|
|
|
|
}
|
|
|
|
}, [fields]);
|
2020-12-15 07:21:17 +00:00
|
|
|
|
|
|
|
return (
|
2020-12-02 14:48:06 +00:00
|
|
|
<>
|
2020-12-04 20:37:29 +00:00
|
|
|
<FormAccess role="manage-realm" onSubmit={handleSubmit(save)}>
|
2020-12-02 14:48:06 +00:00
|
|
|
<TableComposable
|
2021-03-16 12:37:57 +00:00
|
|
|
className="kc-attributes__table"
|
2020-12-02 14:48:06 +00:00
|
|
|
aria-label="Role attribute keys and values"
|
|
|
|
variant="compact"
|
|
|
|
borders={false}
|
|
|
|
>
|
|
|
|
<Thead>
|
|
|
|
<Tr>
|
|
|
|
<Th id="key" width={40}>
|
|
|
|
{columns[0]}
|
|
|
|
</Th>
|
|
|
|
<Th id="value" width={40}>
|
|
|
|
{columns[1]}
|
|
|
|
</Th>
|
|
|
|
</Tr>
|
|
|
|
</Thead>
|
|
|
|
<Tbody>
|
|
|
|
{fields.map((attribute, rowIndex) => (
|
|
|
|
<Tr key={attribute.id}>
|
|
|
|
<Td
|
|
|
|
key={`${attribute.id}-key`}
|
|
|
|
id={`text-input-${rowIndex}-key`}
|
|
|
|
dataLabel={columns[0]}
|
|
|
|
>
|
|
|
|
<TextInput
|
|
|
|
name={`attributes[${rowIndex}].key`}
|
2021-03-22 08:14:24 +00:00
|
|
|
ref={register()}
|
2020-12-02 14:48:06 +00:00
|
|
|
aria-label="key-input"
|
|
|
|
defaultValue={attribute.key}
|
2020-12-04 20:37:29 +00:00
|
|
|
validated={
|
|
|
|
errors.attributes && errors.attributes[rowIndex]
|
|
|
|
? "error"
|
|
|
|
: "default"
|
|
|
|
}
|
2020-12-02 14:48:06 +00:00
|
|
|
/>
|
|
|
|
</Td>
|
|
|
|
<Td
|
|
|
|
key={`${attribute}-value`}
|
|
|
|
id={`text-input-${rowIndex}-value`}
|
|
|
|
dataLabel={columns[1]}
|
|
|
|
>
|
|
|
|
<TextInput
|
|
|
|
name={`attributes[${rowIndex}].value`}
|
2020-12-04 20:37:29 +00:00
|
|
|
ref={register()}
|
2020-12-02 14:48:06 +00:00
|
|
|
aria-label="value-input"
|
|
|
|
defaultValue={attribute.value}
|
|
|
|
/>
|
|
|
|
</Td>
|
|
|
|
{rowIndex !== fields.length - 1 && fields.length - 1 !== 0 && (
|
|
|
|
<Td
|
|
|
|
key="minus-button"
|
|
|
|
id={`kc-minus-button-${rowIndex}`}
|
|
|
|
dataLabel={columns[2]}
|
|
|
|
>
|
|
|
|
<Button
|
|
|
|
id={`minus-button-${rowIndex}`}
|
|
|
|
aria-label={`remove ${attribute.key} with value ${attribute.value} `}
|
|
|
|
variant="link"
|
2021-03-16 12:37:57 +00:00
|
|
|
className="kc-attributes__minus-icon"
|
2020-12-02 14:48:06 +00:00
|
|
|
onClick={() => remove(rowIndex)}
|
|
|
|
>
|
|
|
|
<MinusCircleIcon />
|
|
|
|
</Button>
|
|
|
|
</Td>
|
|
|
|
)}
|
|
|
|
{rowIndex === fields.length - 1 && (
|
|
|
|
<Td key="add-button" id="add-button" dataLabel={columns[2]}>
|
2021-03-29 11:35:13 +00:00
|
|
|
{fields.length !== 1 && (
|
2020-12-04 20:37:29 +00:00
|
|
|
<Button
|
|
|
|
id={`minus-button-${rowIndex}`}
|
|
|
|
aria-label={`remove ${attribute.key} with value ${attribute.value} `}
|
|
|
|
variant="link"
|
2021-03-16 12:37:57 +00:00
|
|
|
className="kc-attributes__minus-icon"
|
2020-12-04 20:37:29 +00:00
|
|
|
onClick={() => remove(rowIndex)}
|
|
|
|
>
|
|
|
|
<MinusCircleIcon />
|
|
|
|
</Button>
|
|
|
|
)}
|
2020-12-02 14:48:06 +00:00
|
|
|
</Td>
|
|
|
|
)}
|
|
|
|
</Tr>
|
2020-12-15 07:21:17 +00:00
|
|
|
))}
|
2021-04-01 13:41:21 +00:00
|
|
|
<Tr>
|
|
|
|
<Td>
|
|
|
|
<Button
|
|
|
|
aria-label={t("roles:addAttributeText")}
|
|
|
|
id="plus-icon"
|
|
|
|
variant="link"
|
|
|
|
className="kc-attributes__plus-icon"
|
|
|
|
onClick={() => append({ key: "", value: "" })}
|
|
|
|
icon={<PlusCircleIcon />}
|
|
|
|
isDisabled={!watchLast}
|
|
|
|
>
|
|
|
|
{t("roles:addAttributeText")}
|
|
|
|
</Button>
|
|
|
|
</Td>
|
|
|
|
</Tr>
|
2020-12-02 14:48:06 +00:00
|
|
|
</Tbody>
|
|
|
|
</TableComposable>
|
2021-03-16 12:37:57 +00:00
|
|
|
<ActionGroup className="kc-attributes__action-group">
|
2021-03-29 11:35:13 +00:00
|
|
|
<Button
|
|
|
|
variant="primary"
|
|
|
|
type="submit"
|
|
|
|
isDisabled={!formState.isDirty}
|
|
|
|
>
|
2020-12-02 14:48:06 +00:00
|
|
|
{t("common:save")}
|
|
|
|
</Button>
|
2021-03-29 11:35:13 +00:00
|
|
|
<Button
|
|
|
|
onClick={reset}
|
|
|
|
variant="link"
|
|
|
|
isDisabled={!formState.isDirty}
|
|
|
|
>
|
2021-03-12 16:30:14 +00:00
|
|
|
{t("common:revert")}
|
2021-01-19 19:30:52 +00:00
|
|
|
</Button>
|
2020-12-02 14:48:06 +00:00
|
|
|
</ActionGroup>
|
|
|
|
</FormAccess>
|
|
|
|
</>
|
2020-12-15 07:21:17 +00:00
|
|
|
);
|
2021-01-26 20:06:16 +00:00
|
|
|
};
|