Skip to main content

UI maintainer guide

Architecture

The form is entirely config-driven. A chart config file describes what sections and fields to show; React renders them automatically.

charts/baseline.js        App.jsx state             toValues.js
workloadSections[] → newWorkload() → buildWorkload()
type: 'section' prefillFromValues() → values.yaml dict
fields: [...]

Key files

FileRole
src/app/charts/baseline.jsAll section + field config (shared by all chart versions)
src/app/charts/base-chart-1.0.0.jsVersion-specific config: name, OCI ref, version
src/app/charts/index.jsRegistry — CHARTS map and DEFAULT_CHART
src/app/App.jsxState, newWorkload(), prefillFromValues(), shared resources
src/app/WorkloadForm.jsxRenders workload sections via SectionPanel
src/app/components/SectionPanel.jsxRenders one section (accordion + fields)
src/app/components/FieldRenderer.jsxRenders one field; exports getPath / setPath
src/app/toValues.jsConverts React state → plain JS object (written as YAML)
src/app/Sidebar.jsxYAML preview, copy/download, generate manifests

Field descriptor properties

{
key: 'hpa.yaml', // dot-notation path into workload state
label: 'HPA spec', // label shown above the input
type: 'yaml', // text | number | select | checkbox | yaml | list
rows: 6, // textarea height (yaml type only, default 3)
placeholder: '...',
tip: 'tooltip text', // shown as a ? icon
options: ['a', 'b'], // required for select type
min: 0, // minimum value (number type only)
advanced: true, // hide behind "Show advanced"
fullWidth: true, // always render on its own row (don't group with others)
showFor: ['Deployment'], // only show for these workload types
visibleWhen: { path: 'hpa.enabled', equals: true }, // conditional visibility
required: true, // show a * indicator
}

Adding a field to an existing section

1. Add to baseline.js:

// inside the section's fields[]
{ key: 'podAnnotations', label: 'Pod annotations', type: 'yaml', rows: 3 }

2. Add initial value to newWorkload() in App.jsx:

podAnnotations: '',

3. Emit in buildWorkload() in toValues.js:

const podAnnotations = parseYaml(wl.podAnnotations)
if (podAnnotations) w.podAnnotations = podAnnotations

4. Add prefill in prefillFromValues() in App.jsx:

podAnnotations: w.podAnnotations ? dumpOrEmpty(w.podAnnotations) : '',

Removing a field

  1. Delete the field descriptor from fields[] in the config.
  2. Remove its key from newWorkload().
  3. Remove its emit from toValues.js.
  4. Remove its prefill from prefillFromValues().

Adding a new section

1. Add to baseline.js workloadSections[]:

{
key: 'networkPolicy', type: 'section',
label: '🔒 Network Policy',
showFor: ['Deployment', 'StatefulSet'],
enabledField: 'networkPolicy.enabled', // drives the Enable checkbox
advanced: true,
fields: [
{ key: 'networkPolicy.yaml', label: 'Spec (YAML)', type: 'yaml', rows: 5,
placeholder: 'podSelector: {}\ningress:\n - from:\n - podSelector: {}' },
],
},

2–4. Follow the same steps as adding a field: initial state → emit → prefill.

// newWorkload() in App.jsx
networkPolicy: { enabled: false, yaml: '' },

// buildWorkload() in toValues.js
if (wl.type !== 'CronJob' && wl.networkPolicy?.enabled) {
const spec = parseYaml(wl.networkPolicy.yaml) || {}
w.networkPolicy = clean({ enabled: true, ...spec })
}

// prefillFromValues() in App.jsx
networkPolicy: {
enabled: !!w.networkPolicy?.enabled,
yaml: w.networkPolicy ? dumpSpec(w.networkPolicy) : '',
},

Removing a section

Delete the section entry from workloadSections[] in the config. The section disappears from the UI immediately. Optionally clean up newWorkload(), toValues.js, and prefillFromValues().


Chart variants

Create a new file that extends baseline.js:

// src/app/charts/base-chart-2.0.0.js
import baseline from './baseline.js'

export default {
...baseline,
name: 'base-chart v2.0.0',
ociChartRef: 'oci://ghcr.io/my-github-repo/helm/base-chart',
ociChartVersion: '2.0.0',
// override workloadSections, resourceSections, etc. as needed
}

Register it in src/app/charts/index.js:

import v100 from './base-chart-1.0.0.js'
import v200 from './base-chart-2.0.0.js'

export const CHARTS = {
'base-chart-1.0.0': v100,
'base-chart-2.0.0': v200,
}
export const DEFAULT_CHART = 'base-chart-1.0.0'

The chart selector dropdown in the sidebar appears automatically when CHARTS has more than one entry.


Per-version behavioral differences (valuesOptions)

When a chart version differs from the current baseline behaviour, declare the difference in that version's config using valuesOptions. toValues.js reads these flags and adjusts its output — newer configs that match the baseline need no valuesOptions at all.

Available flags

FlagTypeDefaultWhat it controls
serviceEnabledDefaultbooltrueWhen false, emits service.enabled: true explicitly (required by v1.0.0 template)
defaultServicePortnumber80Port considered the chart default — omitted from output when the user's value matches
terminationGracePeriodDefaultnumber30Grace period (seconds) considered the chart default — omitted when value matches
probeEnabledRequiredbooltrueWhen true, injects enabled: true into each probe object (required by the template guard)

Example

// base-chart-1.0.0.js
valuesOptions: {
serviceEnabledDefault: false, // v1.0.0 requires service.enabled: true explicitly
},

Adding a new flag

  1. Add the flag to valuesOptions in the affected chart config file(s).
  2. toValues.js already passes opts = chart?.valuesOptions || {} into buildWorkload(wl, opts).
  3. Use it inside buildWorkload:
    // example: a future version changes the default grace period to 60s
    terminationGracePeriodSeconds: Number(wl.grace) !== (opts.terminationGracePeriodDefault ?? 30) ? Number(wl.grace) : null,

Running locally

# Docusaurus (configurator embedded in docs site)
cd ui/docs
npm install
npm start # http://localhost:3000

# Standalone frontend (without Docusaurus)
cd ui/frontend
npm install
npm run dev # http://localhost:5173

Both dev servers proxy /generate to http://localhost:8000 — start the backend too (see Backend guide).