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
| File | Role |
|---|---|
src/app/charts/baseline.js | All section + field config (shared by all chart versions) |
src/app/charts/base-chart-1.0.0.js | Version-specific config: name, OCI ref, version |
src/app/charts/index.js | Registry — CHARTS map and DEFAULT_CHART |
src/app/App.jsx | State, newWorkload(), prefillFromValues(), shared resources |
src/app/WorkloadForm.jsx | Renders workload sections via SectionPanel |
src/app/components/SectionPanel.jsx | Renders one section (accordion + fields) |
src/app/components/FieldRenderer.jsx | Renders one field; exports getPath / setPath |
src/app/toValues.js | Converts React state → plain JS object (written as YAML) |
src/app/Sidebar.jsx | YAML 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
- Delete the field descriptor from
fields[]in the config. - Remove its key from
newWorkload(). - Remove its emit from
toValues.js. - 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
| Flag | Type | Default | What it controls |
|---|---|---|---|
serviceEnabledDefault | bool | true | When false, emits service.enabled: true explicitly (required by v1.0.0 template) |
defaultServicePort | number | 80 | Port considered the chart default — omitted from output when the user's value matches |
terminationGracePeriodDefault | number | 30 | Grace period (seconds) considered the chart default — omitted when value matches |
probeEnabledRequired | bool | true | When 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
- Add the flag to
valuesOptionsin the affected chart config file(s). toValues.jsalready passesopts = chart?.valuesOptions || {}intobuildWorkload(wl, opts).- 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).