ValuesForm.tsx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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 CheckboxRow from "./CheckboxRow";
  6. import InputRow from "./InputRow";
  7. import Base64InputRow from "./Base64InputRow";
  8. import SelectRow from "./SelectRow";
  9. import Helper from "./Helper";
  10. import Heading from "./Heading";
  11. import ExpandableResource from "../ExpandableResource";
  12. import VeleroForm from "../forms/VeleroForm";
  13. import InputArray from "./InputArray";
  14. import KeyValueArray from "./KeyValueArray";
  15. type PropsType = {
  16. sections?: Section[];
  17. metaState?: any;
  18. setMetaState?: (key: string, value: any) => void;
  19. handleEnvChange?: (x: any) => void;
  20. disabled?: boolean;
  21. externalValues?: any;
  22. };
  23. type StateType = any;
  24. // Requires an internal representation unlike other values components because metaState value underdetermines input order
  25. export default class ValuesForm extends Component<PropsType, StateType> {
  26. getInputValue = (item: FormElement) => {
  27. if (item) {
  28. let key = item.name || item.variable;
  29. let value = this.props.metaState[key]?.value;
  30. if (
  31. item.settings &&
  32. item.settings.unit &&
  33. value &&
  34. value.includes &&
  35. !item.settings.omitUnitFromValue
  36. ) {
  37. value = value.split(item.settings.unit)[0];
  38. }
  39. return value;
  40. }
  41. };
  42. renderSection = (section: Section) => {
  43. return section.contents?.map((item: FormElement, i: number) => {
  44. if (!item) {
  45. return;
  46. }
  47. // If no name is assigned use values.yaml variable as identifier
  48. let key = item.name || item.variable;
  49. let isDisabled =
  50. item.settings?.disableAfterLaunch &&
  51. !this.props.externalValues?.isLaunch;
  52. isDisabled = isDisabled || this.props.disabled;
  53. switch (item.type) {
  54. case "heading":
  55. return <Heading key={i}>{item.label}</Heading>;
  56. case "subtitle":
  57. return <Helper key={i}>{item.label}</Helper>;
  58. case "resource-list":
  59. if (Array.isArray(item.value)) {
  60. return (
  61. <ResourceList key={key}>
  62. {item.value?.map((resource: any, i: number) => {
  63. return (
  64. <ExpandableResource
  65. key={i}
  66. resource={resource}
  67. isLast={i === item.value.length - 1}
  68. roundAllCorners={true}
  69. />
  70. );
  71. })}
  72. </ResourceList>
  73. );
  74. }
  75. case "checkbox":
  76. return (
  77. <CheckboxRow
  78. key={key}
  79. disabled={isDisabled}
  80. isRequired={item.required}
  81. checked={this.props.metaState[key]?.value}
  82. toggle={() =>
  83. this.props.setMetaState(key, !this.props.metaState[key]?.value)
  84. }
  85. label={item.label}
  86. />
  87. );
  88. case "env-key-value-array":
  89. return (
  90. <KeyValueArray
  91. key={key}
  92. width="100%"
  93. envLoader={true}
  94. externalValues={this.props.externalValues}
  95. values={this.props.metaState[key]?.value}
  96. setValues={(x: any) => {
  97. this.props.setMetaState(key, x);
  98. // Need to pull env vars out of form.yaml for createGHA build env vars
  99. if (
  100. this.props.handleEnvChange &&
  101. key === "container.env.normal"
  102. ) {
  103. // this.props.handleEnvChange(x);
  104. }
  105. }}
  106. label={item.label}
  107. disabled={isDisabled}
  108. secretOption={true}
  109. />
  110. );
  111. case "key-value-array":
  112. return (
  113. <KeyValueArray
  114. key={key}
  115. width="100%"
  116. externalValues={this.props.externalValues}
  117. values={this.props.metaState[key]?.value}
  118. setValues={(x: any) => this.props.setMetaState(key, x)}
  119. label={item.label}
  120. disabled={isDisabled}
  121. />
  122. );
  123. case "array-input":
  124. return (
  125. <InputArray
  126. key={key}
  127. width="100%"
  128. values={this.props.metaState[key]?.value}
  129. setValues={(x: string[]) => {
  130. this.props.setMetaState(key, x);
  131. }}
  132. label={item.label}
  133. disabled={isDisabled}
  134. />
  135. );
  136. case "string-input":
  137. console.log(item);
  138. return (
  139. <InputRow
  140. key={key}
  141. width="100%"
  142. placeholder={item.placeholder}
  143. isRequired={item.required}
  144. type="text"
  145. value={this.getInputValue(item)}
  146. setValue={(x: string) => {
  147. if (
  148. item.settings &&
  149. item.settings.unit &&
  150. x !== "" &&
  151. !item.settings.omitUnitFromValue
  152. ) {
  153. x = x + item.settings.unit;
  154. }
  155. this.props.setMetaState(key, x);
  156. }}
  157. label={item.label}
  158. info={item.info}
  159. unit={item.settings ? item.settings.unit : null}
  160. disabled={isDisabled}
  161. />
  162. );
  163. case "string-input-password":
  164. return (
  165. <InputRow
  166. key={key}
  167. width="100%"
  168. isRequired={item.required}
  169. type="password"
  170. value={this.getInputValue(item)}
  171. setValue={(x: string) => {
  172. if (
  173. item.settings &&
  174. item.settings.unit &&
  175. x !== "" &&
  176. !item.settings.omitUnitFromValue
  177. ) {
  178. x = x + item.settings.unit;
  179. }
  180. this.props.setMetaState(key, x);
  181. }}
  182. label={item.label}
  183. unit={item.settings ? item.settings.unit : null}
  184. disabled={isDisabled}
  185. />
  186. );
  187. case "number-input":
  188. return (
  189. <InputRow
  190. key={key}
  191. width="100%"
  192. isRequired={item.required}
  193. placeholder={item.placeholder}
  194. type="number"
  195. value={this.getInputValue(item)}
  196. setValue={(x: number) => {
  197. let val: string | number = x;
  198. if (Number.isNaN(x)) {
  199. val = "";
  200. }
  201. // Convert to string if unit is set
  202. if (
  203. item.settings &&
  204. item.settings.unit &&
  205. !item.settings.omitUnitFromValue
  206. ) {
  207. val = x.toString();
  208. val = val + item.settings.unit;
  209. }
  210. this.props.setMetaState(key, val);
  211. }}
  212. label={item.label}
  213. unit={item.settings ? item.settings.unit : null}
  214. disabled={isDisabled}
  215. />
  216. );
  217. case "select":
  218. return (
  219. <SelectRow
  220. key={key}
  221. value={this.props.metaState[key]?.value}
  222. setActiveValue={(val) => this.props.setMetaState(key, val)}
  223. options={item.settings.options}
  224. dropdownLabel=""
  225. label={item.label}
  226. />
  227. );
  228. case "provider-select":
  229. return (
  230. <SelectRow
  231. key={key}
  232. value={this.props.metaState[key]?.value}
  233. setActiveValue={(val) => this.props.setMetaState(key, val)}
  234. options={[
  235. { value: "aws", label: "Amazon Web Services (AWS)" },
  236. { value: "gcp", label: "Google Cloud Platform (GCP)" },
  237. { value: "do", label: "DigitalOcean" },
  238. ]}
  239. dropdownLabel=""
  240. label={item.label}
  241. />
  242. );
  243. case "velero-create-backup":
  244. return <VeleroForm />;
  245. case "base-64":
  246. return (
  247. <Base64InputRow
  248. key={key}
  249. width="100%"
  250. isRequired={item.required}
  251. type="text"
  252. value={this.getInputValue(item)}
  253. setValue={(x: string) => {
  254. if (
  255. item.settings &&
  256. item.settings.unit &&
  257. x !== "" &&
  258. !item.settings.omitUnitFromValue
  259. ) {
  260. x = x + item.settings.unit;
  261. }
  262. this.props.setMetaState(key, btoa(x));
  263. }}
  264. label={item.label}
  265. unit={item.settings ? item.settings.unit : null}
  266. disabled={isDisabled}
  267. />
  268. );
  269. case "base-64-password":
  270. return (
  271. <Base64InputRow
  272. key={key}
  273. isRequired={item.required}
  274. type="password"
  275. value={this.getInputValue(item)}
  276. setValue={(x: string) => {
  277. if (
  278. item.settings &&
  279. item.settings.unit &&
  280. x !== "" &&
  281. !item.settings.omitUnitFromValue
  282. ) {
  283. x = x + item.settings.unit;
  284. }
  285. this.props.setMetaState(key, btoa(x));
  286. }}
  287. label={item.label}
  288. unit={item.settings ? item.settings.unit : null}
  289. disabled={isDisabled}
  290. />
  291. );
  292. default:
  293. }
  294. });
  295. };
  296. renderFormContents = () => {
  297. if (this.props.metaState) {
  298. return this.props.sections?.map((section: Section, i: number) => {
  299. // Hide collapsible section if deciding field is false
  300. if (section.show_if) {
  301. if (
  302. !this.props.metaState[section.show_if] ||
  303. this.props.metaState[section.show_if].value === false
  304. ) {
  305. return null;
  306. }
  307. }
  308. return <div key={i}>{this.renderSection(section)}</div>;
  309. });
  310. }
  311. };
  312. render() {
  313. return (
  314. <StyledValuesForm>
  315. <DarkMatter />
  316. {this.renderFormContents()}
  317. </StyledValuesForm>
  318. );
  319. }
  320. }
  321. ValuesForm.contextType = Context;
  322. const ResourceList = styled.div`
  323. margin-bottom: 15px;
  324. margin-top: 20px;
  325. border-radius: 5px;
  326. overflow: hidden;
  327. `;
  328. const DarkMatter = styled.div`
  329. margin-top: 0px;
  330. `;
  331. const StyledValuesForm = styled.div`
  332. width: 100%;
  333. height: 100%;
  334. background: #ffffff11;
  335. color: #ffffff;
  336. padding: 0px 35px 25px;
  337. position: relative;
  338. border-radius: 5px;
  339. font-size: 13px;
  340. overflow: auto;
  341. `;