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

form overhaul w/ initial cases handled

jusrhee 5 лет назад
Родитель
Сommit
7fe5ee37ff

+ 0 - 1
dashboard/src/components/repo-selector/ContentsList.tsx

@@ -213,7 +213,6 @@ export default class ContentsList extends Component<PropsType, StateType> {
   };
 
   renderOverlay = () => {
-    console.log(this.props.procfilePath);
     if (this.props.procfilePath) {
       let processes = this.state.processes
         ? Object.keys(this.state.processes)

+ 98 - 2
dashboard/src/components/values-form/FormDebugger.tsx

@@ -19,6 +19,9 @@ type StateType = {
   rawYaml: string;
   showBonusTabs: boolean;
   showStateDebugger: boolean;
+  valuesToOverride: any;
+  checkbox_a: boolean;
+  isReadOnly: boolean;
 };
 
 const tabOptions = [
@@ -26,15 +29,18 @@ const tabOptions = [
   { value: "b", label: "Bonus Tab B" },
 ];
 
+// TODO: handle checkbox_a true (pass in initialized state)
 export default class FormDebugger extends Component<PropsType, StateType> {
   state = {
-    rawYaml: "",
+    rawYaml: initYaml,
     showBonusTabs: false,
     showStateDebugger: true,
+    valuesToOverride: null as any,
+    checkbox_a: false,
+    isReadOnly: false,
   };
 
   renderTabContents = (currentTab: string) => {
-    console.log("oofok");
     return (
       <TabWrapper>
         {this.state.rawYaml.toString().slice(0, 300) || "No raw YAML inputted."}
@@ -89,6 +95,13 @@ export default class FormDebugger extends Component<PropsType, StateType> {
             this.setState({ showStateDebugger: !this.state.showStateDebugger })
           }
         />
+        <CheckboxRow
+          label="Read-only"
+          checked={this.state.isReadOnly}
+          toggle={() => this.setState({
+            isReadOnly: !this.state.isReadOnly,
+          })}
+        />
         <CheckboxRow
           label="Include non-form dummy tabs"
           checked={this.state.showBonusTabs}
@@ -96,12 +109,31 @@ export default class FormDebugger extends Component<PropsType, StateType> {
             this.setState({ showBonusTabs: !this.state.showBonusTabs })
           }
         />
+        <CheckboxRow
+          label="checkbox_a"
+          checked={this.state.checkbox_a}
+          toggle={() =>
+            this.setState({
+              checkbox_a: !this.state.checkbox_a,
+
+              // Override the form value for checkbox_a
+              valuesToOverride: {
+                checkbox_a: {
+                  value: !this.state.checkbox_a
+                }
+              }
+            })
+          }
+        />
 
         <Heading>🎨 Rendered Form</Heading>
         <Br />
         <FormWrapper
+          valuesToOverride={this.state.valuesToOverride}
+          clearValuesToOverride={() => this.setState({ valuesToOverride: null })}
           showStateDebugger={this.state.showStateDebugger}
           formData={formData}
+          isReadOnly={this.state.isReadOnly}
           tabOptions={this.state.showBonusTabs ? tabOptions : []}
           renderTabContents={
             this.state.showBonusTabs ? this.renderTabContents : null
@@ -191,3 +223,67 @@ const Button = styled.div`
     justify-content: center;
   }
 `;
+
+const initYaml = `name: Porter Example
+hasSource: true
+tabs:
+- name: main
+  label: Main
+  sections:
+  - name: header
+    contents: 
+    - type: heading
+      label: 🍺 Porter Demo Form
+    - type: subtitle
+      name: command_description
+      label: Basic form demonstrating some of the features of form.yaml
+    - type: string-input
+      placeholder: "ex: pilsner"
+      label: Required Field A
+      required: true
+      variable: field_a
+    - type: string-input
+      placeholder: "ex: sapporo"
+      required: true
+      label: Required Field B
+      variable: field_b
+    - type: subtitle
+      label: "Note: Hidden required fields aren't supported yet (global only)"
+  - name: controlled-by-external
+    show_if: checkbox_a
+    contents:
+    - type: heading
+      label: Conditional Display (A)
+    - type: subtitle
+      label: This section can be externally controlled by the value of checkbox_a
+    - type: string-input
+      variable: input_a
+      placeholder: "Override w/ input_a"
+  - name: domain_name
+    show_if: ingress.custom_domain
+    contents:
+    - type: array-input
+      variable: ingress.hosts
+      label: Domain Name
+- name: env
+  label: Environment
+  sections:
+  - name: env_vars
+    contents:
+    - type: heading
+      label: Environment Variables
+    - type: subtitle
+      label: Set environment variables for your secrets and environment-specific configuration.
+    - type: env-key-value-array
+      label: 
+      variable: container.env.normal
+- name: advanced
+  label: Advanced
+  sections:
+  - name: advanced
+    contents:
+    - type: heading
+      label: Some Header
+    - type: subtitle
+      label: Some helper text
+`;

+ 56 - 16
dashboard/src/components/values-form/FormWrapper.tsx

@@ -1,42 +1,59 @@
 import React, { Component } from "react";
 import styled from "styled-components";
+import _ from "lodash";
 
 import { Section, FormElement } from "shared/types";
 import { Context } from "shared/Context";
 import TabRegion from "components/TabRegion";
 import ValuesForm from "components/values-form/ValuesForm";
-import _ from "lodash";
-
 import SaveButton from "../SaveButton";
 
 type PropsType = {
-  showStateDebugger?: boolean;
   formData: any;
   onSubmit?: (formValues: any) => void;
   saveValuesStatus?: string | null;
-  isInModal?: boolean;
+
+  // Handle additional non-form tabs
   renderTabContents?: (currentTab: string) => any;
   tabOptions?: any[];
+  tabOptionsOnly?: boolean;
+
+  // Allow external control of state
+  valuesToOverride?: any;
+  clearValuesToOverride?: () => void;
+
+  // External values made available to all child components
+  externalValues?: any;
+
+  // Display and debugger settings
+  isInModal?: boolean;
+  isReadOnly?: boolean;
+  showStateDebugger?: boolean;
 
   // TabRegion props to pass through
   color?: string;
   addendum?: any;
-  // overrideValues?: any;
 };
 
 type StateType = {
-  currentTab: string;
-  tabOptions: { value: string; label: string }[];
   metaState: any;
   requiredFields: string[];
+  currentTab: string;
+  tabOptions: { value: string; label: string }[];
 };
 
+/**
+ * Renders from raw JSON form data and manages form state.
+ * 
+ * To control values using external state prop in "valuesToOverride" (refer to
+ * FormDebugger or LaunchTemplate for example usage).
+ */
 export default class FormWrapper extends Component<PropsType, StateType> {
   state = {
-    currentTab: "",
-    tabOptions: [] as { value: string; label: string }[],
     metaState: {} as any,
     requiredFields: [] as string[],
+    currentTab: "",
+    tabOptions: [] as { value: string; label: string }[],
   };
 
   updateTabs = (resetState?: boolean) => {
@@ -45,12 +62,16 @@ export default class FormWrapper extends Component<PropsType, StateType> {
       let tabs = this.props.formData?.tabs;
       let requiredFields = [] as string[];
       let metaState: any = {};
-      if (tabs) {
+      if (tabs && !this.props.tabOptionsOnly) {
         tabs.forEach((tab: any, i: number) => {
-          if (tab.name && tab.label) {
-            // If a tab is valid, first extract state
+          if (tab?.name && tab.label) {
+            // If a tab is valid, extract state
             tab.sections.forEach((section: Section, i: number) => {
-              section.contents.forEach((item: FormElement, i: number) => {
+              section?.contents.forEach((item: FormElement, i: number) => {
+                if (item === null || item === undefined) {
+                  return;
+                }
+
                 // If no name is assigned use values.yaml variable as identifier
                 let key = item.name || item.variable;
 
@@ -124,7 +145,7 @@ export default class FormWrapper extends Component<PropsType, StateType> {
       if (tabOptions.length > 0) {
         this.setState({
           tabOptions: tabOptions,
-          currentTab: tabOptions[0].value,
+          currentTab: this.state.currentTab === "" ? tabOptions[0].value : this.state.currentTab,
           metaState,
           requiredFields: requiredFields,
         });
@@ -138,7 +159,7 @@ export default class FormWrapper extends Component<PropsType, StateType> {
       let tabs = this.props.formData?.tabs;
       if (tabs) {
         tabs.forEach((tab: any, i: number) => {
-          if (tab.name && tab.label) {
+          if (tab?.name && tab.label) {
             tabOptions.push({ value: tab.name, label: tab.label });
           }
         });
@@ -162,6 +183,19 @@ export default class FormWrapper extends Component<PropsType, StateType> {
       let formHasChanged = !_.isEqual(prevProps.formData, this.props.formData);
       this.updateTabs(formHasChanged);
     }
+
+    // Override metaState values set from outside FormWrapper
+    if (
+      this.props.valuesToOverride &&
+      !_.isEqual(prevProps.valuesToOverride, this.props.valuesToOverride)
+    ) {
+      this.setState({ metaState: {
+        ...this.state.metaState,
+        ...this.props.valuesToOverride,
+      }}, () => {
+        this.props.clearValuesToOverride && this.props.clearValuesToOverride();
+      });
+    }
   }
 
   isSet = (value: any) => {
@@ -191,13 +225,15 @@ export default class FormWrapper extends Component<PropsType, StateType> {
     if (tabs) {
       let matchedTab = null as any;
       tabs.forEach((tab: any, i: number) => {
-        if (tab.name === this.state.currentTab) {
+        if (tab?.name === this.state.currentTab) {
           matchedTab = tab;
         }
       });
       if (matchedTab) {
         return (
           <ValuesForm
+            externalValues={this.props.externalValues}
+            disabled={this.props.isReadOnly}
             metaState={this.state.metaState}
             setMetaState={(key: string, value: any) => {
               let metaState: any = this.state.metaState;
@@ -243,6 +279,10 @@ export default class FormWrapper extends Component<PropsType, StateType> {
   };
 
   showSaveButton = (): boolean => {
+    if (this.props.isReadOnly || this.state.tabOptions?.length === 0) {
+      return false;
+    }
+
     // Check if current tab is among non-form tab options{
     let nonFormTabValues = this.props.tabOptions?.map((tab: any, i: number) => {
       return tab.value;

+ 5 - 3
dashboard/src/components/values-form/InputRow.tsx

@@ -34,9 +34,11 @@ export default class InputRow extends Component<PropsType, StateType> {
     let { label, value, type, unit, placeholder, width } = this.props;
     return (
       <StyledInputRow>
-        <Label>
-          {label} <Required>{this.props.isRequired ? " *" : null}</Required>
-        </Label>
+        { label && (
+          <Label>
+            {label} <Required>{this.props.isRequired ? " *" : null}</Required>
+          </Label>
+        )}
         <InputWrapper>
           <Input
             readOnly={this.state.readOnly}

+ 5 - 5
dashboard/src/components/values-form/KeyValueArray.tsx

@@ -14,8 +14,7 @@ type PropsType = {
   setValues: (x: any) => void;
   width?: string;
   disabled?: boolean;
-  namespace?: string;
-  clusterId?: number;
+  externalValues?: any;
   envLoader?: boolean;
   fileUpload?: boolean;
   secretOption?: boolean;
@@ -25,6 +24,7 @@ type StateType = {
   values: any[];
   showEnvModal: boolean;
   showEditorModal: boolean;
+  
 };
 
 export default class KeyValueArray extends Component<PropsType, StateType> {
@@ -153,8 +153,8 @@ export default class KeyValueArray extends Component<PropsType, StateType> {
           height="342px"
         >
           <LoadEnvGroupModal
-            namespace={this.props.namespace}
-            clusterId={this.props.clusterId}
+            namespace={this.props.externalValues?.namespace}
+            clusterId={this.props.externalValues?.clusterId}
             closeModal={() => this.setState({ showEnvModal: false })}
             setValues={(values: any) => {
               this.props.setValues(values);
@@ -275,7 +275,7 @@ export default class KeyValueArray extends Component<PropsType, StateType> {
                 <i className="material-icons">add</i> Add Row
               </AddRowButton>
               <Spacer />
-              {this.props.namespace && this.props.envLoader && (
+              {this.props.externalValues?.namespace && this.props.envLoader && (
                 <LoadButton
                   onClick={() =>
                     this.setState({ showEnvModal: !this.state.showEnvModal })

+ 21 - 24
dashboard/src/components/values-form/ValuesForm.tsx

@@ -21,9 +21,7 @@ type PropsType = {
   setMetaState?: (key: string, value: any) => void;
   handleEnvChange?: (x: any) => void;
   disabled?: boolean;
-  namespace?: string;
-  clusterId?: number;
-  procfileProcess?: string;
+  externalValues?: any;
 };
 
 type StateType = any;
@@ -31,17 +29,23 @@ type StateType = any;
 // Requires an internal representation unlike other values components because metaState value underdetermines input order
 export default class ValuesForm extends Component<PropsType, StateType> {
   getInputValue = (item: FormElement) => {
-    let key = item.name || item.variable;
-    let value = this.props.metaState[key]?.value;
+    if (item) {
+      let key = item.name || item.variable;
+      let value = this.props.metaState[key]?.value;
 
-    if (item.settings && item.settings.unit && value && value.includes) {
-      value = value.split(item.settings.unit)[0];
+      if (item.settings && item.settings.unit && value && value.includes) {
+        value = value.split(item.settings.unit)[0];
+      }
+      return value;
     }
-    return value;
   };
 
   renderSection = (section: Section) => {
     return section.contents.map((item: FormElement, i: number) => {
+      if (!item) {
+        return;
+      }
+
       // If no name is assigned use values.yaml variable as identifier
       let key = item.name || item.variable;
 
@@ -84,8 +88,7 @@ export default class ValuesForm extends Component<PropsType, StateType> {
             <KeyValueArray
               key={key}
               envLoader={true}
-              namespace={this.props.namespace}
-              clusterId={this.props.clusterId}
+              externalValues={this.props.externalValues}
               values={this.props.metaState[key]?.value}
               setValues={(x: any) => {
                 this.props.setMetaState(key, x);
@@ -107,20 +110,9 @@ export default class ValuesForm extends Component<PropsType, StateType> {
           return (
             <KeyValueArray
               key={key}
-              namespace={this.props.namespace}
-              clusterId={this.props.clusterId}
+              externalValues={this.props.externalValues}
               values={this.props.metaState[key]?.value}
-              setValues={(x: any) => {
-                this.props.setMetaState(key, x);
-
-                // Need to pull env vars out of form.yaml for createGHA build env vars
-                if (
-                  this.props.handleEnvChange &&
-                  key === "container.env.normal"
-                ) {
-                  //this.props.handleEnvChange(x);
-                }
-              }}
+              setValues={(x: any) => this.props.setMetaState(key, x)}
               label={item.label}
               disabled={this.props.disabled}
             />
@@ -141,6 +133,7 @@ export default class ValuesForm extends Component<PropsType, StateType> {
           return (
             <InputRow
               key={key}
+              placeholder={item.placeholder}
               isRequired={item.required}
               type="text"
               value={this.getInputValue(item)}
@@ -178,6 +171,7 @@ export default class ValuesForm extends Component<PropsType, StateType> {
             <InputRow
               key={key}
               isRequired={item.required}
+              placeholder={item.placeholder}
               type="number"
               value={this.getInputValue(item)}
               setValue={(x: number) => {
@@ -273,7 +267,10 @@ export default class ValuesForm extends Component<PropsType, StateType> {
       return this.props.sections.map((section: Section, i: number) => {
         // Hide collapsible section if deciding field is false
         if (section.show_if) {
-          if (this.props.metaState[section.show_if]?.value === false) {
+          if (
+            !this.props.metaState[section.show_if] || 
+            this.props.metaState[section.show_if].value === false
+          ) {
             return null;
           }
         }

+ 0 - 181
dashboard/src/components/values-form/ValuesWrapper.tsx

@@ -1,181 +0,0 @@
-import React, { Component } from "react";
-import styled from "styled-components";
-
-import { Section, FormElement } from "../../shared/types";
-import { Context } from "../../shared/Context";
-
-import SaveButton from "../SaveButton";
-
-type PropsType = {
-  formTabs: any;
-  onSubmit: (formValues: any) => void;
-  disabled?: boolean;
-  saveValuesStatus?: string | null;
-  isInModal?: boolean;
-  currentTab?: string; // For resetting state when flipping b/w tabs in ExpandedChart
-  renderSaveButton?: boolean;
-  overrideValues?: any;
-};
-
-type StateType = any;
-
-const providerMap: any = {
-  gke: "gcp",
-  eks: "aws",
-  doks: "do",
-};
-
-// Manages the consolidated state of all form tabs ("metastate")
-export default class ValuesWrapper extends Component<PropsType, StateType> {
-  // No need to render, so OK to set as class variable outside of state
-  requiredFields: string[] = [];
-
-  updateFormState() {
-    let metaState: any = {};
-    this.props.formTabs.forEach((tab: any, i: number) => {
-      // TODO: reconcile tab.name and tab.value
-      if (tab.name || (tab.value && tab.value.includes("@"))) {
-        tab.sections.forEach((section: Section, i: number) => {
-          section.contents.forEach((item: FormElement, i: number) => {
-            // If no name is assigned use values.yaml variable as identifier
-            let key = item.name || item.variable;
-
-            let def =
-              item.settings && item.settings.unit
-                ? `${item.settings.default}${item.settings.unit}`
-                : item.settings.default;
-            def = (item.value && item.value[0]) || def;
-
-            if (item.type === "checkbox") {
-              def = item.value[0];
-            }
-
-            // Handle add to list of required fields
-            if (item.required) {
-              key && this.requiredFields.push(key);
-            }
-
-            switch (item.type) {
-              case "checkbox":
-                metaState[key] = def ? def : false;
-                break;
-              case "string-input":
-                metaState[key] = def ? def : "";
-                break;
-              case "string-input-password":
-                metaState[key] = def ? def : item.settings.default;
-              case "array-input":
-                metaState[key] = def ? def : [];
-                break;
-              case "env-key-value-array":
-                metaState[key] = def ? def : {};
-                break;
-              case "key-value-array":
-                metaState[key] = def ? def : {};
-                break;
-              case "number-input":
-                metaState[key] = def.toString() ? def : "";
-                break;
-              case "select":
-                metaState[key] = def ? def : item.settings.options[0].value;
-                break;
-              case "provider-select":
-                def = providerMap[this.context.currentCluster.service];
-                metaState[key] = def ? def : "aws";
-                break;
-              case "base-64":
-                metaState[key] = def ? def : "";
-              case "base-64-password":
-                metaState[key] = def ? def : "";
-              default:
-            }
-          });
-        });
-      }
-    });
-    this.setState(metaState);
-  }
-
-  // Initialize corresponding state fields for form blocks
-  componentDidMount() {
-    this.updateFormState();
-  }
-
-  componentDidUpdate(prevProps: PropsType) {
-    if (
-      this.props.formTabs !== prevProps.formTabs ||
-      this.props.currentTab !== prevProps.currentTab
-    ) {
-      this.updateFormState();
-    }
-    if (this.props.overrideValues !== prevProps.overrideValues) {
-      this.setState({ ...this.props.overrideValues });
-    }
-  }
-
-  // Checks if all required fields are set
-  isDisabled = (): boolean => {
-    let valueIndicators: any[] = [];
-    this.requiredFields.forEach((field: string, i: number) => {
-      valueIndicators.push(this.state[field] && true);
-    });
-    return valueIndicators.includes(false) || valueIndicators.includes("");
-  };
-
-  renderButton = () => {
-    if (this.props.renderSaveButton) {
-      let { formTabs, currentTab } = this.props;
-      let tab = formTabs.find(
-        (t: any) => t.name === currentTab || t.value === currentTab
-      );
-      if (tab && tab.context && tab.context.type === "helm/values") {
-        return (
-          <SaveButton
-            disabled={this.isDisabled() || this.props.disabled}
-            text="Deploy"
-            onClick={() => this.props.onSubmit(this.state)}
-            status={
-              this.isDisabled()
-                ? "Missing required fields"
-                : this.props.saveValuesStatus
-            }
-            makeFlush={true}
-          />
-        );
-      }
-    }
-  };
-
-  render() {
-    let renderFunc: any = this.props.children;
-    if (this.props.isInModal) {
-      return (
-        <StyledValuesWrapper>
-          {renderFunc(this.state, (x: any) => this.setState(x))}
-          {this.renderButton()}
-        </StyledValuesWrapper>
-      );
-    }
-    return (
-      <PaddedWrapper>
-        <StyledValuesWrapper>
-          {renderFunc(this.state, (x: any) => this.setState(x))}
-          {this.renderButton()}
-        </StyledValuesWrapper>
-      </PaddedWrapper>
-    );
-  }
-}
-
-ValuesWrapper.contextType = Context;
-
-const StyledValuesWrapper = styled.div`
-  width: 100%;
-  padding: 0;
-  height: calc(100% - 65px);
-`;
-
-const PaddedWrapper = styled.div`
-  padding-bottom: 65px;
-  position: relative;
-`;

+ 5 - 4
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -662,10 +662,11 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
               tabOptions={this.state.tabOptions}
               isInModal={true}
               renderTabContents={this.renderTabContents}
-              onSubmit={(values: any) => {
-                alert("Check console output.");
-                console.log("Raw submission values:");
-                console.log(values);
+              onSubmit={this.onSubmit}
+              saveValuesStatus={this.state.saveValuesStatus}
+              externalValues={{
+                namespace: this.props.namespace,
+                clusterId: this.context.currentCluster.id,
               }}
               color={this.state.isPreview ? "#f5cb42" : null}
               addendum={

+ 29 - 51
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedJobChart.tsx

@@ -14,8 +14,7 @@ import Loading from "components/Loading";
 import TabRegion from "components/TabRegion";
 import JobList from "./jobs/JobList";
 import SettingsSection from "./SettingsSection";
-import ValuesWrapper from "components/values-form/ValuesWrapper";
-import ValuesForm from "components/values-form/ValuesForm";
+import FormWrapper from "components/values-form/FormWrapper";
 
 type PropsType = {
   namespace: string;
@@ -36,6 +35,7 @@ type StateType = {
   showDeleteOverlay: boolean;
   deleting: boolean;
   saveValuesStatus: string | null;
+  formData: any;
 };
 
 export default class ExpandedJobChart extends Component<PropsType, StateType> {
@@ -50,6 +50,7 @@ export default class ExpandedJobChart extends Component<PropsType, StateType> {
     showDeleteOverlay: false,
     deleting: false,
     saveValuesStatus: null as string | null,
+    formData: {} as any,
   };
 
   // Retrieve full chart data (includes form and values)
@@ -235,9 +236,7 @@ export default class ExpandedJobChart extends Component<PropsType, StateType> {
     this.setState({ jobs });
   };
 
-  renderTabContents = () => {
-    let currentTab = this.state.currentTab;
-
+  renderTabContents = (currentTab: string) => {
     switch (currentTab) {
       case "jobs":
         return (
@@ -262,48 +261,14 @@ export default class ExpandedJobChart extends Component<PropsType, StateType> {
           />
         );
       default:
-        if (this.state.tabOptions && currentTab && currentTab.includes("@")) {
-          return (
-            <TabWrapper>
-              <ValuesWrapper
-                formTabs={this.state.tabOptions}
-                onSubmit={this.handleSaveValues}
-                saveValuesStatus={this.state.saveValuesStatus}
-                isInModal={true}
-                currentTab={currentTab}
-                renderSaveButton={false}
-              >
-                {(metaState: any, setMetaState: any) => {
-                  return this.state.tabOptions.map((tab: any, i: number) => {
-                    // If tab is current, render
-                    if (tab.value === currentTab) {
-                      return (
-                        <ValuesForm
-                          key={i}
-                          metaState={metaState}
-                          setMetaState={setMetaState}
-                          sections={tab.sections}
-                          disabled={true}
-                        />
-                      );
-                    }
-                  });
-                }}
-              </ValuesWrapper>
-              <SaveButton
-                text="Rerun Job"
-                onClick={() => this.handleSaveValues()}
-                status={this.state.saveValuesStatus}
-                makeFlush={true}
-              />
-            </TabWrapper>
-          );
-        }
     }
   };
 
   updateTabs() {
     let formData = this.state.currentChart.form;
+    if (formData) {
+      this.setState({ formData });
+    }
     let tabOptions = [] as any[];
 
     // Append universal tabs
@@ -312,7 +277,7 @@ export default class ExpandedJobChart extends Component<PropsType, StateType> {
     if (formData) {
       formData.tabs.map((tab: any, i: number) => {
         tabOptions.push({
-          value: "@" + tab.name,
+          value: tab.name,
           label: tab.label,
           sections: tab.sections,
           context: tab.context,
@@ -435,14 +400,21 @@ export default class ExpandedJobChart extends Component<PropsType, StateType> {
             </CloseButton>
           </HeaderWrapper>
 
-          <TabRegion
-            currentTab={this.state.currentTab}
-            setCurrentTab={(x: string) => this.setState({ currentTab: x })}
-            options={this.state.tabOptions}
-            color={null}
-          >
-            {this.renderTabContents()}
-          </TabRegion>
+          <BodyWrapper>
+            <FormWrapper
+              formData={this.state.formData}
+              isReadOnly={true}
+              tabOptions={this.state.tabOptions}
+              isInModal={true}
+              renderTabContents={this.renderTabContents}
+              tabOptionsOnly={true}
+              onSubmit={(values: any) => {
+                alert("Check console output.");
+                console.log("Raw submission values:");
+                console.log(values);
+              }}
+            />
+          </BodyWrapper>
         </StyledExpandedChart>
       </>
     );
@@ -451,6 +423,12 @@ export default class ExpandedJobChart extends Component<PropsType, StateType> {
 
 ExpandedJobChart.contextType = Context;
 
+const BodyWrapper = styled.div`
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+`;
+
 const TabWrapper = styled.div`
   height: 100%;
   width: 100%;

+ 0 - 1
dashboard/src/main/home/launch/expanded-template/ExpandedTemplate.tsx

@@ -55,7 +55,6 @@ export default class ExpandedTemplate extends Component<PropsType, StateType> {
       .then((res) => {
         let { form, values, markdown, metadata } = res.data;
         let keywords = metadata.keywords;
-        console.log(form);
         this.setState({
           form,
           values,

+ 20 - 21
dashboard/src/main/home/launch/expanded-template/LaunchTemplate.tsx

@@ -57,7 +57,7 @@ type StateType = {
   folderPath: string | null;
   selectedRegistry: any | null;
   env: any;
-  overrideValues: any;
+  valuesToOverride: any | null;
 };
 
 const defaultActionConfig: ActionConfigType = {
@@ -93,10 +93,7 @@ class LaunchTemplate extends Component<PropsType, StateType> {
     folderPath: null as string | null,
     selectedRegistry: null as any | null,
     env: {},
-    overrideValues: {
-      abba: false,
-      tracy: "mcgrady",
-    },
+    valuesToOverride: null as any | null,
   };
 
   createGHAction = (chartName: string, chartNamespace: string) => {
@@ -386,15 +383,6 @@ class LaunchTemplate extends Component<PropsType, StateType> {
       procfilePath,
     } = this.state;
 
-    // if (
-    //   sourceType === "repo" &&
-    //   !dockerfilePath &&
-    //   folderPath &&
-    //   !procfilePath
-    // ) {
-    //   return "Procfile not detected.";
-    // }
-
     if (!this.submitIsDisabled()) {
       return this.state.saveValuesStatus;
     }
@@ -505,11 +493,18 @@ class LaunchTemplate extends Component<PropsType, StateType> {
           </Subtitle>
           <FormWrapper
             formData={this.props.form}
-            onSubmit={(values: any) => {
-              alert("Check console output.");
-              console.log("Raw submission values:");
-              console.log(values);
+            saveValuesStatus={this.state.saveValuesStatus}
+            valuesToOverride={this.state.valuesToOverride}
+            clearValuesToOverride={() => this.setState({ valuesToOverride: null })}
+            externalValues={{
+              namespace: this.state.selectedNamespace,
+              clusterId: this.context.currentCluster.id,
             }}
+            onSubmit={
+              this.props.currentTab === "docker"
+                ? this.onSubmit
+                : this.onSubmitAddon
+            }
           />
         </>
       );
@@ -631,9 +626,13 @@ class LaunchTemplate extends Component<PropsType, StateType> {
             setProcfileProcess={(procfileProcess: string) =>
               this.setState({
                 procfileProcess,
-                overrideValues: {
-                  "container.command": procfileProcess || "",
-                  showStartCommand: !procfileProcess,
+                valuesToOverride: {
+                  "container.command": {
+                    value: procfileProcess || "",
+                  },
+                  showStartCommand: {
+                    value: !procfileProcess,
+                  }
                 },
               })
             }

+ 1 - 0
dashboard/src/shared/types.tsx

@@ -104,6 +104,7 @@ export interface FormElement {
   required?: boolean;
   name?: string;
   variable?: string;
+  placeholder?: string;
   value?: any;
   settings?: {
     default?: number | string | boolean;