All checks were successful
Deploy Development / deploy (push) Successful in 45s
Test Suite / pytest-backend (push) Successful in 2m13s
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
Test Suite / k6 /api/health Baseline (push) Successful in 18s
Test Suite / playwright-smoke (push) Successful in 12s
InitiativeForm laedt Felder nach gewaehltem Archetyp; Plan-Profil zeigt Standardfelder und Zusatzfelder; actor_ref und Owner-Auswahl. Co-authored-by: Cursor <cursoragent@cursor.com>
130 lines
3.2 KiB
JavaScript
130 lines
3.2 KiB
JavaScript
export function FieldRenderer({ definitions, values, onChange, disabled = false, actors = [] }) {
|
|
if (!definitions?.length) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<fieldset className="field-renderer">
|
|
<legend className="field-renderer__legend">Zusatzfelder (Archetyp)</legend>
|
|
{definitions.map((def) => (
|
|
<DynamicField
|
|
key={def.field_key}
|
|
definition={def}
|
|
value={values?.[def.field_key]}
|
|
onChange={(next) => onChange(def.field_key, next)}
|
|
disabled={disabled}
|
|
actors={actors}
|
|
/>
|
|
))}
|
|
</fieldset>
|
|
)
|
|
}
|
|
|
|
function DynamicField({ definition, value, onChange, disabled, actors = [] }) {
|
|
const { field_key, field_type, label, required, validation_json: validation } = definition
|
|
const inputId = `field-${field_key}`
|
|
|
|
if (field_type === 'longtext') {
|
|
return (
|
|
<label htmlFor={inputId}>
|
|
{label}
|
|
{required && ' *'}
|
|
<textarea
|
|
id={inputId}
|
|
name={field_key}
|
|
rows={4}
|
|
value={value ?? ''}
|
|
onChange={(e) => onChange(e.target.value)}
|
|
required={required}
|
|
disabled={disabled}
|
|
/>
|
|
</label>
|
|
)
|
|
}
|
|
|
|
if (field_type === 'boolean') {
|
|
return (
|
|
<label className="checkbox-label" htmlFor={inputId}>
|
|
<input
|
|
id={inputId}
|
|
name={field_key}
|
|
type="checkbox"
|
|
checked={Boolean(value)}
|
|
onChange={(e) => onChange(e.target.checked)}
|
|
disabled={disabled}
|
|
/>
|
|
{label}
|
|
{required && ' *'}
|
|
</label>
|
|
)
|
|
}
|
|
|
|
if (field_type === 'enum') {
|
|
const options = validation?.options || []
|
|
return (
|
|
<label htmlFor={inputId}>
|
|
{label}
|
|
{required && ' *'}
|
|
<select
|
|
id={inputId}
|
|
name={field_key}
|
|
value={value ?? ''}
|
|
onChange={(e) => onChange(e.target.value)}
|
|
required={required}
|
|
disabled={disabled}
|
|
>
|
|
<option value="">—</option>
|
|
{options.map((opt) => (
|
|
<option key={opt} value={opt}>
|
|
{opt}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
)
|
|
}
|
|
|
|
if (field_type === 'actor_ref') {
|
|
return (
|
|
<label htmlFor={inputId}>
|
|
{label}
|
|
{required && ' *'}
|
|
<select
|
|
id={inputId}
|
|
name={field_key}
|
|
value={value ?? ''}
|
|
onChange={(e) => onChange(e.target.value || null)}
|
|
required={required}
|
|
disabled={disabled}
|
|
>
|
|
<option value="">—</option>
|
|
{actors.map((actor) => (
|
|
<option key={actor.id} value={actor.id}>
|
|
{actor.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
)
|
|
}
|
|
|
|
const inputType =
|
|
field_type === 'number' ? 'number' : field_type === 'date' ? 'date' : field_type === 'url' ? 'url' : 'text'
|
|
|
|
return (
|
|
<label htmlFor={inputId}>
|
|
{label}
|
|
{required && ' *'}
|
|
<input
|
|
id={inputId}
|
|
name={field_key}
|
|
type={inputType}
|
|
value={value ?? ''}
|
|
onChange={(e) => onChange(field_type === 'number' ? e.target.value : e.target.value)}
|
|
required={required}
|
|
disabled={disabled}
|
|
/>
|
|
</label>
|
|
)
|
|
}
|