FormDebugger.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. import React, { Component } from "react";
  2. import styled from "styled-components";
  3. import AceEditor from "react-ace";
  4. import PorterFormWrapper from "../form-refactor/PorterFormWrapper";
  5. import CheckboxRow from "components/values-form/CheckboxRow";
  6. import InputRow from "components/values-form/InputRow";
  7. import yaml from "js-yaml";
  8. import "shared/ace-porter-theme";
  9. import "ace-builds/src-noconflict/mode-text";
  10. import Heading from "./Heading";
  11. import Helper from "./Helper";
  12. type PropsType = {
  13. goBack: () => void;
  14. };
  15. type StateType = {
  16. rawYaml: string;
  17. showBonusTabs: boolean;
  18. showStateDebugger: boolean;
  19. valuesToOverride: any;
  20. checkbox_a: boolean;
  21. input_a: string;
  22. isReadOnly: boolean;
  23. };
  24. const tabOptions = [
  25. { value: "a", label: "Bonus Tab A" },
  26. { value: "b", label: "Bonus Tab B" },
  27. ];
  28. export default class FormDebugger extends Component<PropsType, StateType> {
  29. state = {
  30. rawYaml: initYaml,
  31. showBonusTabs: false,
  32. showStateDebugger: true,
  33. valuesToOverride: {
  34. checkbox_a: {
  35. value: true,
  36. },
  37. } as any,
  38. checkbox_a: true,
  39. input_a: "",
  40. isReadOnly: false,
  41. };
  42. renderTabContents = (currentTab: string) => {
  43. return (
  44. <TabWrapper>
  45. {this.state.rawYaml.toString().slice(0, 300) || "No raw YAML inputted."}
  46. </TabWrapper>
  47. );
  48. };
  49. aceEditorRef = React.createRef<AceEditor>();
  50. render() {
  51. let formData = {};
  52. try {
  53. formData = yaml.load(this.state.rawYaml);
  54. } catch (err: any) {
  55. console.log("YAML parsing error.");
  56. }
  57. return (
  58. <StyledFormDebugger>
  59. <Button onClick={this.props.goBack}>
  60. <i className="material-icons">keyboard_backspace</i>
  61. Back
  62. </Button>
  63. <Heading>✨ Form.yaml Editor</Heading>
  64. <Helper>Write and test form.yaml free of consequence.</Helper>
  65. <EditorWrapper>
  66. <AceEditor
  67. ref={this.aceEditorRef}
  68. mode="yaml"
  69. value={this.state.rawYaml}
  70. theme="porter"
  71. onChange={(e: string) => this.setState({ rawYaml: e })}
  72. name="codeEditor"
  73. editorProps={{ $blockScrolling: true }}
  74. height="450px"
  75. width="100%"
  76. style={{
  77. borderRadius: "5px",
  78. border: "1px solid #ffffff22",
  79. marginTop: "27px",
  80. marginBottom: "27px",
  81. }}
  82. showPrintMargin={false}
  83. showGutter={true}
  84. highlightActiveLine={true}
  85. />
  86. </EditorWrapper>
  87. <CheckboxRow
  88. label="Show form state debugger"
  89. checked={this.state.showStateDebugger}
  90. toggle={() =>
  91. this.setState({ showStateDebugger: !this.state.showStateDebugger })
  92. }
  93. />
  94. <CheckboxRow
  95. label="Read-only"
  96. checked={this.state.isReadOnly}
  97. toggle={() =>
  98. this.setState({
  99. isReadOnly: !this.state.isReadOnly,
  100. })
  101. }
  102. />
  103. <CheckboxRow
  104. label="Include non-form dummy tabs"
  105. checked={this.state.showBonusTabs}
  106. toggle={() =>
  107. this.setState({ showBonusTabs: !this.state.showBonusTabs })
  108. }
  109. />
  110. <CheckboxRow
  111. label="checkbox_a"
  112. checked={this.state.checkbox_a}
  113. toggle={() =>
  114. this.setState({
  115. checkbox_a: !this.state.checkbox_a,
  116. // Override the form value for checkbox_a
  117. valuesToOverride: {
  118. ...this.state.valuesToOverride,
  119. checkbox_a: {
  120. value: !this.state.checkbox_a,
  121. },
  122. },
  123. })
  124. }
  125. />
  126. <InputRow
  127. type="string"
  128. value={this.state.input_a}
  129. setValue={(x: string) =>
  130. this.setState({
  131. input_a: x,
  132. // Override the form value for input_a
  133. valuesToOverride: {
  134. ...this.state.valuesToOverride,
  135. input_a: {
  136. value: x,
  137. },
  138. },
  139. })
  140. }
  141. label={"input_a"}
  142. placeholder="ex: override text"
  143. />
  144. <Heading>🎨 Rendered Form</Heading>
  145. <Br />
  146. <PorterFormWrapper
  147. formData={formData}
  148. valuesToOverride={{
  149. input_a: this.state.valuesToOverride?.input_a?.value,
  150. }}
  151. isReadOnly={this.state.isReadOnly}
  152. onSubmit={(vars) => {
  153. alert("check console output");
  154. console.log(vars);
  155. }}
  156. rightTabOptions={this.state.showBonusTabs ? tabOptions : []}
  157. renderTabContents={this.renderTabContents}
  158. saveButtonText={"Test Submit"}
  159. />
  160. </StyledFormDebugger>
  161. );
  162. }
  163. }
  164. const Br = styled.div`
  165. width: 100%;
  166. height: 12px;
  167. `;
  168. const TabWrapper = styled.div`
  169. background: #ffffff11;
  170. height: 200px;
  171. width: 100%;
  172. border-radius: 5px;
  173. display: flex;
  174. align-items: center;
  175. justify-content: center;
  176. font-size: 13px;
  177. overflow: auto;
  178. padding: 50px;
  179. `;
  180. const EditorWrapper = styled.div`
  181. .ace_editor,
  182. .ace_editor * {
  183. font-family: "Monaco", "Menlo", "Ubuntu Mono", "Droid Sans Mono", "Consolas",
  184. monospace !important;
  185. font-size: 12px !important;
  186. font-weight: 400 !important;
  187. letter-spacing: 0 !important;
  188. }
  189. `;
  190. const StyledFormDebugger = styled.div`
  191. position: relative;
  192. `;
  193. const Button = styled.div`
  194. display: flex;
  195. flex-direction: row;
  196. align-items: center;
  197. justify-content: space-between;
  198. font-size: 13px;
  199. cursor: pointer;
  200. font-family: "Work Sans", sans-serif;
  201. border-radius: 20px;
  202. color: white;
  203. height: 35px;
  204. margin-left: -2px;
  205. padding: 0px 8px;
  206. width: 85px;
  207. float: right;
  208. padding-bottom: 1px;
  209. font-weight: 500;
  210. padding-right: 15px;
  211. overflow: hidden;
  212. white-space: nowrap;
  213. text-overflow: ellipsis;
  214. cursor: pointer;
  215. border: 2px solid #969fbbaa;
  216. :hover {
  217. background: #ffffff11;
  218. }
  219. > i {
  220. color: white;
  221. width: 18px;
  222. height: 18px;
  223. color: #969fbbaa;
  224. font-weight: 600;
  225. font-size: 14px;
  226. border-radius: 20px;
  227. display: flex;
  228. align-items: center;
  229. margin-right: 5px;
  230. justify-content: center;
  231. }
  232. `;
  233. const initYaml = `name: Web
  234. hasSource: true
  235. includeHiddenFields: true
  236. tabs:
  237. - name: main
  238. label: Main
  239. sections:
  240. - name: section_one
  241. contents:
  242. - type: heading
  243. label: Container Settings
  244. - type: variable
  245. variable: showStartCommand
  246. settings:
  247. default: true
  248. - name: command
  249. show_if: showStartCommand
  250. contents:
  251. - type: subtitle
  252. name: command_description
  253. label: (Optional) Set a start command for this service.
  254. - type: string-input
  255. label: Start Command
  256. placeholder: "ex: sh ./script.sh"
  257. variable: container.command
  258. - name: section_one_cont
  259. contents:
  260. - type: subtitle
  261. label: Specify the port your application is running on.
  262. - type: number-input
  263. variable: container.port
  264. label: Container Port
  265. placeholder: "ex: 80"
  266. settings:
  267. default: 80
  268. - type: heading
  269. label: Deploy Webhook
  270. - type: checkbox
  271. variable: auto_deploy
  272. label: Auto-deploy when webhook is called.
  273. settings:
  274. default: true
  275. - name: network
  276. contents:
  277. - type: heading
  278. label: Network Settings
  279. - type: subtitle
  280. label: For containers that you do not want to expose to external traffic (e.g. databases and add-ons), you may make them accessible only to other internal services running within the same cluster.
  281. - type: checkbox
  282. variable: ingress.enabled
  283. label: Expose to external traffic
  284. settings:
  285. default: true
  286. - name: domain_toggle
  287. show_if: ingress.enabled
  288. contents:
  289. - type: subtitle
  290. label: Assign custom domain to your deployment. You must first create an A record in your domain provider that points to your cluster load balancer's IP address for this.
  291. - type: checkbox
  292. variable: ingress.custom_domain
  293. label: Configure Custom Domain
  294. settings:
  295. default: false
  296. - name: domain_name
  297. show_if: ingress.custom_domain
  298. contents:
  299. - type: array-input
  300. variable: ingress.hosts
  301. label: Domain Name
  302. - name: do_wildcard
  303. show_if:
  304. and:
  305. - ingress.custom_domain
  306. - currentCluster.service.is_do
  307. contents:
  308. - type: subtitle
  309. label: If you're hosting on Digital Ocean and have enabled the wildcard domains from the 'HTTPS Issuer', you can use a wildcard certificate.
  310. - type: checkbox
  311. variable: ingress.wildcard
  312. label: Use Wildcard Certificate
  313. - name: resources
  314. label: Resources
  315. sections:
  316. - name: main_section
  317. contents:
  318. - type: heading
  319. label: Resources
  320. - type: subtitle
  321. label: Configure resources assigned to this container.
  322. - type: number-input
  323. label: RAM
  324. variable: resources.requests.memory
  325. placeholder: "ex: 256"
  326. settings:
  327. unit: Mi
  328. default: 256
  329. - type: number-input
  330. label: CPU
  331. variable: resources.requests.cpu
  332. placeholder: "ex: 100"
  333. settings:
  334. unit: m
  335. default: 100
  336. - type: number-input
  337. label: Replicas
  338. variable: replicaCount
  339. placeholder: "ex: 1"
  340. settings:
  341. default: 1
  342. - type: checkbox
  343. variable: autoscaling.enabled
  344. label: Enable autoscaling
  345. settings:
  346. default: false
  347. - name: autoscaler
  348. show_if: autoscaling.enabled
  349. contents:
  350. - type: number-input
  351. label: Minimum Replicas
  352. variable: autoscaling.minReplicas
  353. placeholder: "ex: 1"
  354. settings:
  355. default: 1
  356. - type: number-input
  357. label: Maximum Replicas
  358. variable: autoscaling.maxReplicas
  359. placeholder: "ex: 10"
  360. settings:
  361. default: 10
  362. - type: number-input
  363. label: Target CPU Utilization
  364. variable: autoscaling.targetCPUUtilizationPercentage
  365. placeholder: "ex: 50"
  366. settings:
  367. omitUnitFromValue: true
  368. unit: "%"
  369. default: 50
  370. - type: number-input
  371. label: Target RAM Utilization
  372. variable: autoscaling.targetMemoryUtilizationPercentage
  373. placeholder: "ex: 50"
  374. settings:
  375. omitUnitFromValue: true
  376. unit: "%"
  377. default: 50
  378. - name: env
  379. label: Environment
  380. sections:
  381. - name: env_vars
  382. contents:
  383. - type: heading
  384. label: Environment Variables
  385. - type: subtitle
  386. label: Set environment variables for your secrets and environment-specific configuration.
  387. - type: env-key-value-array
  388. label:
  389. variable: container.env.normal
  390. - name: advanced
  391. label: Advanced
  392. sections:
  393. - name: ingress_annotations
  394. contents:
  395. - type: heading
  396. label: Ingress Custom Annotations
  397. - type: subtitle
  398. label: Assign custom annotations to Ingress. These annotations will overwrite the annotations Porter assigns by default.
  399. - type: key-value-array
  400. variable: ingress.annotations
  401. settings:
  402. default: {}
  403. - name: health_check
  404. contents:
  405. - type: heading
  406. label: Custom Health Checks
  407. - type: subtitle
  408. label: Define custom health check endpoints to ensure zero down-time deployments.
  409. - type: checkbox
  410. variable: health.enabled
  411. label: Enable Custom Health Checks
  412. settings:
  413. default: false
  414. - name: health_check_endpoint
  415. show_if: health.enabled
  416. contents:
  417. - type: string-input
  418. label: Health Check Endpoint
  419. variable: health.path
  420. placeholder: "ex: /healthz"
  421. settings:
  422. default: /healthz
  423. - type: heading
  424. label: Custom Health Check Rules
  425. - type: subtitle
  426. label: Configure how many times a health check will be performed before deeming the container as failed.
  427. - type: number-input
  428. label: Failure Threshold
  429. variable: health.failureThreshold
  430. placeholder: "ex: 3"
  431. - type: subtitle
  432. label: Configure the interval at which health check is repeated in the case of failure.
  433. - type: number-input
  434. label: Repeat Interval
  435. variable: health.periodSeconds
  436. placeholder: "ex: 30"
  437. - name: persistence_toggle
  438. contents:
  439. - type: heading
  440. label: Persistent Disks
  441. - type: subtitle
  442. label: Attach persistent disks to your deployment to retain data across releases.
  443. - type: checkbox
  444. label: Enable Persistence
  445. variable: pvc.enabled
  446. - name: persistent_storage
  447. show_if: pvc.enabled
  448. contents:
  449. - type: number-input
  450. label: Persistent Storage
  451. variable: pvc.storage
  452. placeholder: "ex: 20"
  453. settings:
  454. unit: Gi
  455. default: 20
  456. - type: string-input
  457. label: Mount Path
  458. variable: pvc.mountPath
  459. placeholder: "ex: /mypath"
  460. settings:
  461. default: /mypath
  462. - name: termination_grace_period
  463. contents:
  464. - type: heading
  465. label: Termination Grace Period
  466. - type: subtitle
  467. label: Specify how much time app processes have to gracefully shut down on SIGTERM.
  468. - type: number-input
  469. label: Termination Grace Period (seconds)
  470. variable: terminationGracePeriodSeconds
  471. placeholder: "ex: 30"
  472. settings:
  473. default: 30
  474. - name: container_hooks
  475. contents:
  476. - type: heading
  477. label: Container hooks
  478. - type: subtitle
  479. label: (Optional) Set post start or pre stop commands for this service.
  480. - type: string-input
  481. label: Post start command
  482. placeholder: "ex: /bin/sh ./myscript.sh"
  483. variable: container.lifecycle.postStart
  484. - type: string-input
  485. label: Pre stop command
  486. placeholder: "ex: /bin/sh ./myscript.sh"
  487. variable: container.lifecycle.preStop
  488. - name: cloud_sql_toggle
  489. show_if: currentCluster.service.is_gcp
  490. contents:
  491. - type: heading
  492. label: Google Cloud SQL
  493. - type: subtitle
  494. label: Securely connect to Google Cloud SQL (GKE only).
  495. - type: checkbox
  496. variable: cloudsql.enabled
  497. label: Enable Google Cloud SQL Proxy
  498. settings:
  499. default: false
  500. - name: cloud_sql_contents
  501. show_if: cloudsql.enabled
  502. contents:
  503. - type: string-input
  504. label: Instance Connection Name
  505. variable: cloudsql.connectionName
  506. placeholder: "ex: project-123:us-east1:pachyderm"
  507. - type: number-input
  508. label: DB Port
  509. variable: cloudsql.dbPort
  510. placeholder: "ex: 5432"
  511. settings:
  512. default: 5432
  513. - type: string-input
  514. label: Service Account JSON
  515. variable: cloudsql.serviceAccountJSON
  516. placeholder: "ex: { <SERVICE_ACCOUNT_JSON> }"`;