FormWrapper.tsx 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import React, { Component } from "react";
  2. import styled from "styled-components";
  3. import { Section, FormElement } from "../../shared/types";
  4. import { Context } from "../../shared/Context";
  5. import SaveButton from "../SaveButton";
  6. type PropsType = {
  7. formTabs: any;
  8. onSubmit: (formValues: any) => void;
  9. disabled?: boolean;
  10. saveValuesStatus?: string | null;
  11. isInModal?: boolean;
  12. currentTab?: string; // For resetting state when flipping b/w tabs in ExpandedChart
  13. renderSaveButton?: boolean;
  14. overrideValues?: any;
  15. };
  16. type StateType = any;
  17. const providerMap: any = {
  18. gke: "gcp",
  19. eks: "aws",
  20. doks: "do",
  21. };
  22. // Manages the consolidated state of all form tabs ("metastate")
  23. export default class ValuesWrapper extends Component<PropsType, StateType> {
  24. // No need to render, so OK to set as class variable outside of state
  25. requiredFields: string[] = [];
  26. updateFormState() {
  27. let metaState: any = {};
  28. this.props.formTabs.forEach((tab: any, i: number) => {
  29. // TODO: reconcile tab.name and tab.value
  30. if (tab.name || (tab.value && tab.value.includes("@"))) {
  31. tab.sections.forEach((section: Section, i: number) => {
  32. section.contents.forEach((item: FormElement, i: number) => {
  33. // If no name is assigned use values.yaml variable as identifier
  34. let key = item.name || item.variable;
  35. let def =
  36. item.settings && item.settings.unit
  37. ? `${item.settings.default}${item.settings.unit}`
  38. : item.settings.default;
  39. def = (item.value && item.value[0]) || def;
  40. if (item.type === "checkbox") {
  41. def = item.value[0];
  42. }
  43. // Handle add to list of required fields
  44. if (item.required) {
  45. key && this.requiredFields.push(key);
  46. }
  47. switch (item.type) {
  48. case "checkbox":
  49. metaState[key] = def ? def : false;
  50. break;
  51. case "string-input":
  52. metaState[key] = def ? def : "";
  53. break;
  54. case "string-input-password":
  55. metaState[key] = def ? def : item.settings.default;
  56. case "array-input":
  57. metaState[key] = def ? def : [];
  58. break;
  59. case "env-key-value-array":
  60. metaState[key] = def ? def : {};
  61. break;
  62. case "key-value-array":
  63. metaState[key] = def ? def : {};
  64. break;
  65. case "number-input":
  66. metaState[key] = def.toString() ? def : "";
  67. break;
  68. case "select":
  69. metaState[key] = def ? def : item.settings.options[0].value;
  70. break;
  71. case "provider-select":
  72. def = providerMap[this.context.currentCluster.service];
  73. metaState[key] = def ? def : "aws";
  74. break;
  75. case "base-64":
  76. metaState[key] = def ? def : "";
  77. case "base-64-password":
  78. metaState[key] = def ? def : "";
  79. default:
  80. }
  81. });
  82. });
  83. }
  84. });
  85. this.setState(metaState);
  86. }
  87. // Initialize corresponding state fields for form blocks
  88. componentDidMount() {
  89. this.updateFormState();
  90. }
  91. componentDidUpdate(prevProps: PropsType) {
  92. if (
  93. this.props.formTabs !== prevProps.formTabs ||
  94. this.props.currentTab !== prevProps.currentTab
  95. ) {
  96. this.updateFormState();
  97. }
  98. if (this.props.overrideValues !== prevProps.overrideValues) {
  99. this.setState({ ...this.props.overrideValues });
  100. }
  101. }
  102. // Checks if all required fields are set
  103. isDisabled = (): boolean => {
  104. let valueIndicators: any[] = [];
  105. this.requiredFields.forEach((field: string, i: number) => {
  106. valueIndicators.push(this.state[field] && true);
  107. });
  108. return valueIndicators.includes(false) || valueIndicators.includes("");
  109. };
  110. renderButton = () => {
  111. if (this.props.renderSaveButton) {
  112. let { formTabs, currentTab } = this.props;
  113. let tab = formTabs.find(
  114. (t: any) => t.name === currentTab || t.value === currentTab
  115. );
  116. if (tab && tab.context && tab.context.type === "helm/values") {
  117. return (
  118. <SaveButton
  119. disabled={this.isDisabled() || this.props.disabled}
  120. text="Deploy"
  121. onClick={() => this.props.onSubmit(this.state)}
  122. status={
  123. this.isDisabled()
  124. ? "Missing required fields"
  125. : this.props.saveValuesStatus
  126. }
  127. makeFlush={true}
  128. />
  129. );
  130. }
  131. }
  132. };
  133. render() {
  134. let renderFunc: any = this.props.children;
  135. if (this.props.isInModal) {
  136. return (
  137. <StyledValuesWrapper>
  138. {renderFunc(this.state, (x: any) => this.setState(x))}
  139. {this.renderButton()}
  140. </StyledValuesWrapper>
  141. );
  142. }
  143. return (
  144. <PaddedWrapper>
  145. <StyledValuesWrapper>
  146. {renderFunc(this.state, (x: any) => this.setState(x))}
  147. {this.renderButton()}
  148. </StyledValuesWrapper>
  149. </PaddedWrapper>
  150. );
  151. }
  152. }
  153. ValuesWrapper.contextType = Context;
  154. const StyledValuesWrapper = styled.div`
  155. width: 100%;
  156. padding: 0;
  157. height: calc(100% - 65px);
  158. `;
  159. const PaddedWrapper = styled.div`
  160. padding-bottom: 65px;
  161. position: relative;
  162. `;