Browse Source

array input

Ivan Galakhov 4 years ago
parent
commit
0620a09843

+ 4 - 0
dashboard/src/components/form-refactor/PorterForm.tsx

@@ -5,6 +5,7 @@ import {
   InputField,
   CheckboxField,
   KeyValueArrayField,
+  ArrayInputField,
 } from "./types";
 import TabRegion, { TabOption } from "../TabRegion";
 import Heading from "../values-form/Heading";
@@ -15,6 +16,7 @@ import Checkbox from "./field-components/Checkbox";
 import KeyValueArray from "./field-components/KeyValueArray";
 import styled from "styled-components";
 import SaveButton from "../SaveButton";
+import ArrayInput from "./field-components/ArrayInput";
 
 interface Props {
   leftTabOptions?: TabOption[];
@@ -51,6 +53,8 @@ const PorterForm: React.FC<Props> = (props) => {
         return <Checkbox {...(bundledProps as CheckboxField)} />;
       case "key-value-array":
         return <KeyValueArray {...(bundledProps as KeyValueArrayField)} />;
+      case "array-input":
+        return <ArrayInput {...(bundledProps as ArrayInputField)} />;
     }
     return <p>Not Implemented: {(field as any).type}</p>;
   };

+ 1 - 0
dashboard/src/components/form-refactor/PorterFormContextProvider.tsx

@@ -93,6 +93,7 @@ export const PorterFormContextProvider: React.FC<Props> = (props) => {
         return {
           ...state,
           variables: {
+            ...state.variables,
             ...action.mutateFunc(state.variables),
             ...props.overrideVariables,
           },

+ 172 - 0
dashboard/src/components/form-refactor/field-components/ArrayInput.tsx

@@ -0,0 +1,172 @@
+import React from "react";
+import styled from "styled-components";
+import { ArrayInputField, ArrayInputFieldState } from "../types";
+import useFormField from "../hooks/useFormField";
+
+const ArrayInput: React.FC<ArrayInputField> = (props) => {
+  const { state, variables, setVars } = useFormField<ArrayInputFieldState>(
+    props.id,
+    {
+      initVars: {
+        [props.variable]: [],
+      },
+    }
+  );
+
+  if (state == undefined) return <></>;
+
+  const renderDeleteButton = (values: string[], i: number) => {
+    if (!props.isReadOnly) {
+      return (
+        <DeleteButton
+          onClick={() => {
+            setVars((prev) => {
+              return {
+                [props.variable]: prev[props.variable]
+                  .slice(0, i)
+                  .concat(prev[props.variable].slice(i + 1)),
+              };
+            });
+          }}
+        >
+          <i className="material-icons">cancel</i>
+        </DeleteButton>
+      );
+    }
+  };
+
+  const renderInputList = (values: string[]) => {
+    return (
+      <>
+        {values.map((value: string, i: number) => {
+          return (
+            <InputWrapper>
+              <Input
+                placeholder=""
+                width="270px"
+                value={value}
+                onChange={(e: any) => {
+                  e.persist();
+                  setVars((prev) => {
+                    return {
+                      [props.variable]: prev[props.variable].map(
+                        (t: string, j: number) => {
+                          return i == j ? e.target.value : t;
+                        }
+                      ),
+                    };
+                  });
+                }}
+                disabled={props.isReadOnly}
+              />
+              {renderDeleteButton(values, i)}
+            </InputWrapper>
+          );
+        })}
+      </>
+    );
+  };
+
+  return (
+    <StyledInputArray>
+      <Label>{props.label}</Label>
+      {variables[props.variable] === 0 ? (
+        <></>
+      ) : (
+        renderInputList(variables[props.variable])
+      )}
+      <AddRowButton
+        onClick={() => {
+          setVars((prev) => {
+            return {
+              [props.variable]: [...prev[props.variable], ""],
+            };
+          });
+        }}
+      >
+        <i className="material-icons">add</i> Add Row
+      </AddRowButton>
+    </StyledInputArray>
+  );
+};
+
+export default ArrayInput;
+
+const AddRowButton = styled.div`
+  display: flex;
+  align-items: center;
+  margin-top: 5px;
+  width: 270px;
+  font-size: 13px;
+  color: #aaaabb;
+  height: 30px;
+  border-radius: 3px;
+  cursor: pointer;
+  background: #ffffff11;
+  :hover {
+    background: #ffffff22;
+  }
+
+  > i {
+    color: #ffffff44;
+    font-size: 16px;
+    margin-left: 8px;
+    margin-right: 10px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+  }
+`;
+
+const DeleteButton = styled.div`
+  width: 15px;
+  height: 15px;
+  display: flex;
+  align-items: center;
+  margin-left: 8px;
+  margin-top: -3px;
+  justify-content: center;
+
+  > i {
+    font-size: 17px;
+    color: #ffffff44;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+    :hover {
+      color: #ffffff88;
+    }
+  }
+`;
+
+const InputWrapper = styled.div`
+  display: flex;
+  align-items: center;
+`;
+
+const Input = styled.input`
+  outline: none;
+  border: none;
+  margin-bottom: 5px;
+  font-size: 13px;
+  background: #ffffff11;
+  border: 1px solid #ffffff55;
+  border-radius: 3px;
+  width: ${(props: { disabled?: boolean; width: string }) =>
+    props.width ? props.width : "270px"};
+  color: ${(props: { disabled?: boolean; width: string }) =>
+    props.disabled ? "#ffffff44" : "white"};
+  padding: 5px 10px;
+  height: 35px;
+`;
+
+const Label = styled.div`
+  color: #ffffff;
+  margin-bottom: 10px;
+`;
+
+const StyledInputArray = styled.div`
+  margin-bottom: 15px;
+  margin-top: 22px;
+`;

+ 1 - 5
dashboard/src/components/form-refactor/field-components/Input.tsx

@@ -8,11 +8,7 @@ import {
   StringInputFieldState,
 } from "../types";
 
-interface Props extends InputField {
-  id: string;
-}
-
-const Input: React.FC<Props> = ({
+const Input: React.FC<InputField> = ({
   id,
   variable,
   label,

+ 8 - 2
dashboard/src/components/form-refactor/types.ts

@@ -54,7 +54,12 @@ export interface KeyValueArrayField extends GenericInputField {
   fileUpload?: boolean;
 }
 
-export type FormField = HeadingField|SubtitleField|InputField|CheckboxField|KeyValueArrayField;
+export interface ArrayInputField extends GenericInputField {
+  type: "array-input"
+  label?: string
+}
+
+export type FormField = HeadingField|SubtitleField|InputField|CheckboxField|KeyValueArrayField|ArrayInputField;
 
 export interface ShowIfAnd {
   and: ShowIf[];
@@ -104,8 +109,9 @@ export interface KeyValueArrayFieldState {
   showEnvModal: boolean;
   showEditorModal: boolean;
 }
+export interface ArrayInputFieldState {}
 
-export type PorterFormFieldFieldState = StringInputFieldState|CheckboxFieldState|KeyValueArrayField;
+export type PorterFormFieldFieldState = StringInputFieldState|CheckboxFieldState|KeyValueArrayField|ArrayInputFieldState;
 
 // reducer interfaces
 

+ 9 - 1
dashboard/src/components/values-form/FormDebugger.tsx

@@ -276,8 +276,16 @@ const Button = styled.div`
 const initYaml = `name: Porter Example
 hasSource: true
 tabs:
+- name: complex
+  label: Complex Inputs
+  sections:
+  - name: only-section
+    contents:
+      - type: array-input
+        label: testing array-input
+        variable: array-input-variable
 - name: main
-  label: Main
+  label: Basic Inputs
   sections:
   - name: header
     contents: