diff --git a/packages/db/prisma/seed.ts b/packages/db/prisma/seed.ts index d954f10..ec2ca52 100644 --- a/packages/db/prisma/seed.ts +++ b/packages/db/prisma/seed.ts @@ -66,9 +66,39 @@ const TEMPLATES: { ] const TEMPLATE_FIELDS = [ + // Nachgebaut nach dem Vorfallsbericht der Abteilung. Die Foundation-Freigabe + // steht im Kopf des Dokuments, steuert aber keinen Zugriff — das tut allein + // die interne Freigabe. Siehe docs/13-entscheidungen.md. + { + key: 'foundation_freigabe', + label: 'Foundation-Freigabe', + type: 'select', + options: ['0', '1', '2', '3', '4', '5'], + }, + { + key: 'berichtsart', + label: 'Berichtsart', + type: 'multiselect', + options: [ + 'Vorfallsbericht', + 'Sicherheitsanalyse', + 'Interne Untersuchung', + 'Allg. Bericht', + 'Sonstiges', + ], + }, + { + key: 'gefahreneinschaetzung', + label: 'Gefahreneinschätzung', + type: 'select', + options: ['Keine', 'Leichte', 'Mittlere', 'Erhöhte', 'Kritische'], + }, + { key: 'vorfallsdatum', label: 'Datum des Vorfalls', type: 'date' }, { key: 'sachverhalt', label: 'Sachverhalt', type: 'longtext', required: true }, { key: 'beteiligte', label: 'Beteiligte Personen', type: 'longtext' }, { key: 'feststellungen', label: 'Feststellungen', type: 'longtext' }, + { key: 'anmerkungen', label: 'Anmerkungen', type: 'longtext' }, + { key: 'massnahmen', label: 'Maßnahmen', type: 'longtext' }, { key: 'bewertung', label: 'Abschließende Bewertung', @@ -110,9 +140,14 @@ async function main(): Promise { fields: TEMPLATE_FIELDS, isActive: true, }, - // Muster und Felder bleiben unangetastet: was der Leiter im - // Vorlagen-Editor eingestellt hat, überschreibt der Seed nicht. - update: { name: template.name, description: template.description }, + // Version 1 gehört dem Seed und wird von ihm aktuell gehalten. Ändert + // der Leiter eine Vorlage im Editor, entsteht Version 2 — die fasst der + // Seed nie an, und bestehende Akten behalten ohnehin ihre Version. + update: { + name: template.name, + description: template.description, + fields: TEMPLATE_FIELDS, + }, }) } console.log(`[seed] ${TEMPLATES.length} Startvorlagen`) diff --git a/web/app/(app)/admin/vorlagen/TemplateEditor.tsx b/web/app/(app)/admin/vorlagen/TemplateEditor.tsx new file mode 100644 index 0000000..1eb7a6c --- /dev/null +++ b/web/app/(app)/admin/vorlagen/TemplateEditor.tsx @@ -0,0 +1,200 @@ +'use client' + +import { useMemo, useState, useTransition } from 'react' +import { de } from '@/lib/i18n/de' +import { isInputField, looksLikeFields, type TemplateField } from '@/lib/templates/fields' +import { saveTemplate } from './actions' + +type Vorlage = { + key: string + name: string + description: string | null + version: number + numberPrefix: string + numberPadding: number + fields: unknown +} + +/** + * Vorlagen-Editor. + * + * Die Bausteine werden als JSON bearbeitet. Das ist bewusst: ein + * Baukasten-Editor mit Ziehen und Ablegen wäre eine eigene Phase, und die + * Vorlagen ändern sich selten. Geprüft wird gegen dasselbe Schema wie + * serverseitig, und die Vorschau zeigt sofort, was dabei herauskommt. + * + * Nicht optimistisch: eine neue Version wirkt auf alle künftigen Akten. + */ +export function TemplateEditor({ vorlage }: { vorlage: Vorlage }) { + const [name, setName] = useState(vorlage.name) + const [description, setDescription] = useState(vorlage.description ?? '') + const [numberPrefix, setNumberPrefix] = useState(vorlage.numberPrefix) + const [numberPadding, setNumberPadding] = useState(vorlage.numberPadding) + const [json, setJson] = useState(() => JSON.stringify(vorlage.fields, null, 2)) + const [result, setResult] = useState(null) + const [error, setError] = useState(null) + const [pending, startTransition] = useTransition() + + const geparst = useMemo(() => { + try { + const roh = JSON.parse(json) as unknown + // Nur eine grobe Formprüfung für die Vorschau. Ob die Vorlage + // gespeichert werden darf, entscheidet allein der Server. + if (!looksLikeFields(roh)) { + return { ok: false as const, fehler: de.templateAdmin.fieldsInvalid } + } + return { ok: true as const, fields: roh } + } catch { + return { ok: false as const, fehler: de.templateAdmin.invalid } + } + }, [json]) + + function submit() { + if (!geparst.ok) return + setError(null) + setResult(null) + startTransition(async () => { + const antwort = await saveTemplate({ + key: vorlage.key, + name, + description: description || undefined, + numberPrefix, + numberPadding, + fields: geparst.fields, + }) + if (antwort.ok) setResult(de.templateAdmin.saved(antwort.version)) + else setError(antwort.error) + }) + } + + return ( +
+
+

{vorlage.name}

+ {vorlage.key} + + {de.templateAdmin.version(vorlage.version)} + +
+ +
+
+ + + + +
+ + +
+ +