Просмотр исходного кода

refactor field ids, inital work for required fields

Ivan Galakhov 4 лет назад
Родитель
Сommit
bb9d9bd0fa

+ 5 - 6
dashboard/src/components/form-refactor/PorterForm.tsx

@@ -26,7 +26,7 @@ const PorterForm: React.FC<Props> = (props) => {
     formData.tabs.length > 0 ? formData.tabs[0].name : ""
   );
 
-  const renderSectionField = (field: FormField, id: string): JSX.Element => {
+  const renderSectionField = (field: FormField): JSX.Element => {
     const bundledProps = {
       ...field,
       isReadOnly,
@@ -37,9 +37,9 @@ const PorterForm: React.FC<Props> = (props) => {
       case "subtitle":
         return <Helper>{field.label}</Helper>;
       case "string-input":
-        return <StringInput id={id} {...(bundledProps as StringInputField)} />;
+        return <StringInput {...(bundledProps as StringInputField)} />;
       case "checkbox":
-        return <Checkbox id={id} {...(bundledProps as CheckboxField)} />;
+        return <Checkbox {...(bundledProps as CheckboxField)} />;
     }
     return <p>Not Implemented: {(field as any).type}</p>;
   };
@@ -48,10 +48,9 @@ const PorterForm: React.FC<Props> = (props) => {
     return (
       <>
         {section.contents.map((field, i) => {
-          const id = `${section.name}-${field.type}-${i}`;
           return (
-            <React.Fragment key={id}>
-              {renderSectionField(field, id)}
+            <React.Fragment key={field.id}>
+              {renderSectionField(field)}
             </React.Fragment>
           );
         })}

+ 44 - 4
dashboard/src/components/form-refactor/PorterFormContextProvider.tsx

@@ -4,6 +4,7 @@ import {
   PorterFormState,
   PorterFormAction,
   PorterFormVariableList,
+  GenericInputField,
 } from "./types";
 import { ShowIf, ShowIfAnd, ShowIfNot, ShowIfOr } from "../../shared/types";
 
@@ -121,6 +122,7 @@ export const PorterFormContextProvider: React.FC<Props> = (props) => {
   /*
   We don't want to have the actual <PorterForm> component to do as little form
   logic as possible, so this structures the form object based on show_if statements
+  and assigns a unique id to each field
 
   This computed structure also later lets us figure out which fields should be required
   */
@@ -130,18 +132,56 @@ export const PorterFormContextProvider: React.FC<Props> = (props) => {
   ) => {
     return {
       ...data,
-      tabs: data.tabs.map((tab) => {
+      tabs: data.tabs.map((tab, i) => {
         return {
           ...tab,
-          sections: tab.sections.filter((section) => {
-            return !section.show_if || evalShowIf(section.show_if, variables);
-          }),
+          sections: tab.sections
+            .map((section, j) => {
+              return {
+                ...section,
+                contents: section.contents.map((field, k) => {
+                  return {
+                    ...field,
+                    id: `${i}-${j}-${k}`,
+                  };
+                }),
+              };
+            })
+            .filter((section) => {
+              return !section.show_if || evalShowIf(section.show_if, variables);
+            }),
         };
       }),
     };
   };
+  /*
+    compute a list of field ids who's input is required and a map from a variable value
+    to a list of fields that set it
+  */
+  const computeRequiredVariables = (
+    data: PorterFormData
+  ): [string[], Record<string, string[]>] => {
+    const requiredIds: string[] = [];
+    const mapping: Record<string, string[]> = {};
+    data.tabs.map((tab) =>
+      tab.sections.map((section) =>
+        section.contents.map((field) => {
+          if (field.type == "heading" || field.type == "subtitle") return;
+          if (field.required) {
+            requiredIds.push(field.id);
+            if (!mapping[field.variable]) {
+              mapping[field.variable] = [];
+            }
+            mapping[field.variable].push(field.id);
+          }
+        })
+      )
+    );
+    return [requiredIds, mapping];
+  };
 
   const formData = computeFormStructure(props.rawFormData, state.variables);
+  const [requiredIds, varMapping] = computeRequiredVariables(formData);
 
   return (
     <Provider

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

@@ -2,7 +2,7 @@ import React from "react";
 import InputRow from "../../values-form/InputRow";
 import useFormField from "../hooks/useFormField";
 import {
-  GenericFieldProps,
+  GenericInputField,
   StringInputField,
   StringInputFieldState,
 } from "../types";

+ 10 - 7
dashboard/src/components/form-refactor/types.ts

@@ -5,17 +5,22 @@
 
 // YAML Field interfaces
 
-export interface GenericFieldProps {
+export interface GenericField {
+  id: string;
+}
+
+export interface GenericInputField extends GenericField {
   isReadOnly?: boolean;
   required?: boolean;
+  variable: string;
 }
 
-export interface HeadingField {
+export interface HeadingField extends GenericField{
   type: "heading";
   label: string;
 }
 
-export interface SubtitleField {
+export interface SubtitleField extends GenericField{
   type: "subtitle";
   label: string;
 }
@@ -26,19 +31,17 @@ export interface StringInputFieldSettings {
   omitUnitFromValue?: boolean;
 }
 
-export interface StringInputField extends GenericFieldProps {
+export interface StringInputField extends GenericInputField {
   type: "string-input";
-  variable: string;
   label?: string;
   placeholder?: string;
   info?: string;
   settings?: StringInputFieldSettings;
 }
 
-export interface CheckboxField extends GenericFieldProps {
+export interface CheckboxField extends GenericInputField {
   type: "checkbox";
   label?: string;
-  variable: string;
 }
 
 export type FormField = HeadingField|SubtitleField|StringInputField|CheckboxField;