import { useState } from 'react' type Property = { type?: string; enum?: unknown[]; description?: string; title?: string } type Schema = { properties?: Record } export type SchemaFormProps = { schema: Schema values: Record secretFields: string[] secretsSet: string[] onSubmit: (values: Record) => void } /** A form for a plugin's settings, generated from its JSON schema. */ export function SchemaForm({ schema, values, secretFields, secretsSet, onSubmit, }: SchemaFormProps) { const [draft, setDraft] = useState>(values) const set = (key: string, value: unknown) => setDraft((current) => ({ ...current, [key]: value })) return (
{ event.preventDefault() onSubmit(draft) }} > {Object.entries(schema.properties ?? {}).map(([key, property]) => { const label = property.title ?? key const value = draft[key] let input: React.ReactNode if (property.enum) { input = ( ) } else if (property.type === 'boolean') { input = ( set(key, e.target.checked)} /> ) } else if (property.type === 'number' || property.type === 'integer') { input = ( set(key, e.target.valueAsNumber)} /> ) } else if (property.type === 'string') { const secret = secretFields.includes(key) input = ( set(key, e.target.value)} /> ) } else { return (

{label}: Unsupported setting type

) } return ( // biome-ignore lint/a11y/noLabelWithoutControl: every branch above sets input to a control ) })}
) }