Skip to main content

Structured shared resources (PVC example)

This guide shows how to replace a single YAML textarea with structured fields (select, text, etc.) for shared resources, using PVCs as a worked example.

The pattern is generic and can be reused for other resources like Secrets or ConfigMaps.

You should already be familiar with the high‑level architecture from docs/ui/maintainers-guide.md. This page focuses only on shared resources.


Goal

For PersistentVolumeClaims (PVCs), instead of a single YAML textarea, we want:

  • a Name text input
  • a Size text input (e.g. 1Gi)
  • a Storage class text input (e.g. standard)
  • an Access mode dropdown (ReadWriteOnce, ReadOnlyMany, ReadWriteMany)

…and we still want values.persistentVolumeClaims to look like this:

persistentVolumeClaims:
- name: my-data
size: 1Gi
storageClassName: standard
accessModes:
- ReadWriteOnce

Step 1 — Describe the fields in resources-config.js

File: src/app/resources-config.js

Each shared resource has a section in RESOURCE_SECTIONS. For PVCs we change:

{
key: 'pvcs',
label: '💾 Persistent Volume Claims',
tip: 'Attach persistent storage to your workload (survives Pod restarts)',
addLabel: 'PVC',
stateKey: 'pvcs',
nextIdKey: 'pvcNext',
createItem: (id) => ({
id,
name: '',
size: '',
storageClassName: '',
accessMode: 'ReadWriteOnce',
}),
fields: [
{
key: 'name',
label: 'Name',
type: 'text',
placeholder: 'my-data',
},
{
key: 'size',
label: 'Size',
type: 'text',
placeholder: '1Gi',
},
{
key: 'storageClassName',
label: 'Storage class',
type: 'text',
placeholder: 'standard',
},
{
key: 'accessMode',
label: 'Access mode',
type: 'select',
options: ['ReadWriteOnce', 'ReadOnlyMany', 'ReadWriteMany'],
},
],
},

What this does:

  • createItem defines the shape of each PVC item in React state.
  • fields describes how to render the form for one PVC entry.
  • ResourceList + FieldRenderer take care of rendering and wiring without any extra JSX.

You do not touch App.jsx UI code for this — only the config.


Step 2 — Map React state → values.yaml in toValues.js

File: src/app/toValues.js

Previously PVCs were driven by a YAML textarea (p.yaml); now they are structured fields. Update the PVC mapping like this:

// PVCs
const pvcList = pvcs
.filter(p => p.name.trim())
.map(p => clean({
name: p.name,
size: p.size || null,
storageClassName: p.storageClassName || null,
accessModes: p.accessMode ? [p.accessMode] : null,
}))
.filter(Boolean)
if (pvcList.length) values.persistentVolumeClaims = pvcList

Key points:

  • pvcList is built only from the structured fields.
  • accessModes is always an array; we store a single selected mode as a one‑element array.
  • clean() removes null / empty values, so only filled properties appear in the final YAML.

If you later add more structured fields (e.g. volumeMode, selector), extend this object in the same way.


Step 3 — Map values.yaml back to state in prefillFromValues()

File: src/app/App.jsx

Inside prefillFromValues(v), PVCs were previously mapped into {id, name, yaml}. Now we want to fill the structured fields instead:

return {
// ...
pvcs: (v.persistentVolumeClaims || []).map((p, i) => ({
id: i,
name: p.name || '',
size: p.size || '',
storageClassName: p.storageClassName || '',
accessMode: Array.isArray(p.accessModes) && p.accessModes[0] ? p.accessModes[0] : '',
})),
// ...
}

What this does:

  • Reads each PVC from values.persistentVolumeClaims.
  • Copies simple fields (name, size, storageClassName) straight through.
  • For accessModes, takes the first item as the selected accessMode.

Any additional keys on the PVC object that you don’t map here will simply not round‑trip through the UI (they will still work in values.yaml, but won’t show up in the configurator).


Step 4 — (Optional) Update the PVC default factory

File: src/app/App.jsx

At the top of App.jsx we keep factories for new items. For PVCs:

const newPvc = (id) => ({
id,
name: '',
size: '',
storageClassName: '',
accessMode: 'ReadWriteOnce',
})

This is mainly used when you add a PVC programmatically (e.g. in future features); the actual UI list uses createItem from resources-config.js.


Reusing this pattern for other resources

To add structured fields for another shared resource (for example, adding a type dropdown to Secrets), repeat the same three steps:

  1. Describe fields in resources-config.js:
    • Extend createItem with new keys.
    • Add new fields entries with type: 'text' | 'select' | 'number' | 'checkbox'.
  2. Update toValues.js:
    • Build the output object from the structured keys.
    • Wrap single options in arrays where the chart expects lists.
  3. Update prefillFromValues() in App.jsx:
    • Read from the chart values and populate the structured fields.

Because all shared resources go through the same ResourceList + FieldRenderer pipeline, no JSX changes are required — only config and mapping logic.