PromucFlow_constructor/app/client/src/components/formControls/KeyValueArrayControl.tsx

258 lines
7.8 KiB
TypeScript
Raw Normal View History

import React, { useEffect, useCallback } from "react";
import {
Field,
FieldArray,
WrappedFieldArrayProps,
WrappedFieldMetaProps,
WrappedFieldInputProps,
} from "redux-form";
import styled from "styled-components";
import { Icon } from "@blueprintjs/core";
import { FormIcons } from "icons/FormIcons";
import BaseControl, { ControlProps, ControlData } from "./BaseControl";
import { ControlType } from "constants/PropertyControlConstants";
import DynamicTextField from "components/editorComponents/form/fields/DynamicTextField";
import { Colors } from "constants/Colors";
import TextInput, { TextInputProps } from "components/ads/TextInput";
export interface KeyValueArrayControlProps extends ControlProps {
name: string;
label: string;
maxLen?: number;
description?: string;
actionConfig?: any;
extraData?: ControlData[];
isRequired?: boolean;
}
const FormRowWithLabel = styled.div`
display: flex;
flex: 1;
flex-direction: row;
& svg {
cursor: pointer;
}
`;
const StyledTextInput = styled(TextInput)`
min-width: 66px;
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0px;
}
`;
function KeyValueRow(
props: KeyValueArrayControlProps & WrappedFieldArrayProps,
) {
const { extraData = [] } = props;
const keyName = getFieldName(extraData[0]?.configProperty);
const valueName = getFieldName(extraData[1]?.configProperty);
const keyFieldProps = extraData[0];
useEffect(() => {
// Always maintain 1 row
if (props.fields.length < 1) {
for (let i = props.fields.length; i < 1; i += 1) {
if (keyName && valueName) {
props.fields.push({ [keyName[1]]: "", [valueName[1]]: "" });
} else {
props.fields.push({ key: "", value: "" });
}
}
}
2020-06-04 13:49:22 +00:00
}, [props.fields, keyName, valueName]);
useEffect(() => {
if (typeof props.fields.getAll() === "string") {
const fieldsValue: any[] = JSON.parse(`${props.fields.getAll()}`);
props.fields.removeAll();
fieldsValue.forEach((value, index) => {
props.fields.insert(index, value);
});
}
}, [props.fields]);
const keyFieldValidate = useCallback(
(value: string) => {
if (value && keyFieldProps?.validationRegex) {
const regex = new RegExp(keyFieldProps?.validationRegex);
return regex.test(value) ? undefined : keyFieldProps.validationMessage;
}
return undefined;
},
[keyFieldProps?.validationRegex, keyFieldProps?.validationMessage],
);
const maxLen = props.maxLen;
//if maxLen exists apply a check on the length
const showAddIcon = (index: number): boolean =>
maxLen
? index === props.fields.length - 1 && props.fields.length < maxLen
: index === props.fields.length - 1;
return typeof props.fields.getAll() === "object" ? (
<>
{props.fields.map((field: any, index: number) => {
let keyTextFieldName = `${field}.key`;
let valueTextFieldName = `${field}.value`;
if (keyName && Array.isArray(keyName) && keyName?.length)
keyTextFieldName = `${field}.${keyName[1]}`;
if (valueName && Array.isArray(valueName) && valueName?.length)
valueTextFieldName = `${field}.${valueName[1]}`;
return (
<FormRowWithLabel
key={index}
style={{ marginTop: index > 0 ? "16px" : "0px" }}
>
2021-12-07 09:45:18 +00:00
<div
data-replay-id={btoa(keyTextFieldName)}
style={{ width: "20vw" }}
2021-12-07 09:45:18 +00:00
>
<Field
component={renderTextInput}
name={keyTextFieldName}
props={{
dataType: getType(extraData[0]?.dataType),
defaultValue: extraData[0]?.initialValue,
keyFieldValidate,
placeholder: props.extraData
? props.extraData[1]?.placeholderText
: "",
isRequired: extraData[0]?.isRequired,
name: keyTextFieldName,
}}
/>
</div>
{!props.actionConfig && (
<div style={{ marginLeft: "16px", width: "20vw" }}>
<div
data-replay-id={valueTextFieldName}
style={{ display: "flex", flexDirection: "row" }}
>
<Field
component={renderTextInput}
name={valueTextFieldName}
props={{
dataType: getType(extraData[1]?.dataType),
defaultValue: extraData[1]?.initialValue,
placeholder: props.extraData
? props.extraData[1]?.placeholderText
: "",
name: valueTextFieldName,
isRequired: extraData[1]?.isRequired,
}}
/>
{showAddIcon(index) ? (
<Icon
className="t--add-field"
color={Colors["CADET_BLUE"]}
icon="plus"
iconSize={20}
onClick={() => {
props.fields.push({ key: "", value: "" });
}}
style={{ marginLeft: "16px", alignSelf: "center" }}
/>
) : (
<FormIcons.DELETE_ICON
className="t--delete-field"
color={Colors["CADET_BLUE"]}
height={20}
onClick={() => props.fields.remove(index)}
style={{ marginLeft: "16px", alignSelf: "center" }}
width={20}
/>
)}
</div>
</div>
)}
{props.actionConfig && (
<DynamicTextField
name={`${field}.value`}
placeholder={
props.actionConfig[index].mandatory &&
props.actionConfig[index].type
? `Value (Type: ${props.actionConfig[index].type})`
: `Value (optional)`
}
/>
)}
</FormRowWithLabel>
);
})}
</>
) : null;
}
class KeyValueArrayControl extends BaseControl<KeyValueArrayControlProps> {
render() {
const name = getFieldName(this.props.configProperty);
return (
<FieldArray
component={KeyValueRow}
rerenderOnEveryChange={false}
{...this.props}
name={name ? name[0] : ""}
/>
);
}
getControlType(): ControlType {
return "KEYVALUE_ARRAY";
}
}
const getFieldName = (configProperty: string): string[] | undefined => {
if (configProperty) return configProperty.split("[*].");
};
const getType = (dataType: string | undefined) => {
switch (dataType) {
case "PASSWORD":
return "password";
case "NUMBER":
return "number";
default:
return "text";
}
};
function renderTextInput(
props: TextInputProps & {
dataType?: "text" | "number" | "password";
placeholder?: string;
defaultValue: string | number;
isRequired: boolean;
keyFieldValidate?: (value: string) => { isValid: boolean; message: string };
errorMsg?: string;
helperText?: string;
} & {
meta: Partial<WrappedFieldMetaProps>;
input: Partial<WrappedFieldInputProps>;
},
): JSX.Element {
return (
<StyledTextInput
dataType={props.dataType}
defaultValue={props.defaultValue}
errorMsg={props.errorMsg}
helperText={props.helperText}
name={props.input?.name}
onChange={props.input.onChange}
placeholder={props.placeholder}
validator={props.keyFieldValidate}
value={props.input.value}
width="100%"
/>
);
}
export default KeyValueArrayControl;