GUI-Bausteine: CiaGauge, SegmentedRating, Prozess-Dialog aufgeräumt
Referenz: docs/ISMS-GUI-Verbesserungen-GEFIM.html - CiaGauge: Schutzbedarf/Schadenshöhe als 4er-Segmentbalken (Farblogik 1–4) statt Zahlen-Quadrate — einheitlich in allen Tabellen/Karten; in Detailkarten mit VER/INT/VFB-Labels - SegmentedRating: 1–4 anklickbare, farbige Stufen-Buttons (Client- Komponente mit Hidden-Input + HTML-form-Association) für Asset- Schutzbedarf und BIA-Schadenshöhe statt Dropdowns - Prozess-Bearbeiten aufgeräumt: Sprungnavigation (Grunddaten/Assets/ BIA), genau EIN Speichern-Button (Stammdaten + BIA in einer Action saveProcessAll, Felder per form-Attribut verbunden), Löschen ins ⋯-Überlaufmenü verschoben; Asset-Zuordnung als entfernbare Chips mit Segmentbalken Verifiziert: kombiniertes Speichern (Name + BIA-Schadenshöhe in einem Vorgang, Kritikalität neu berechnet), SegmentedRating-Wert korrekt übernommen, ⋯-Menü mit Löschen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
5fb4b3cbf4
commit
430aaab024
@@ -190,3 +190,52 @@ export async function saveBia(processId: string, formData: FormData) {
|
||||
});
|
||||
revalidatePath("/processes");
|
||||
}
|
||||
|
||||
/**
|
||||
* Kombiniertes Speichern für den aufgeräumten Bearbeiten-Dialog: Stammdaten
|
||||
* und BIA in einem Vorgang (ein Speichern-Button). Asset-Zuordnung läuft
|
||||
* weiter über die inkrementellen Aktionen assignAsset/unassignAsset.
|
||||
*/
|
||||
export async function saveProcessAll(processId: string, formData: FormData) {
|
||||
const session = await requireSession();
|
||||
requirePermission(session, "bia:write");
|
||||
const db = dbForTenant(session.user.tenantId);
|
||||
|
||||
const before = await db.process.findUnique({
|
||||
where: { id: processId },
|
||||
include: { bia: true },
|
||||
});
|
||||
if (!before) throw new Error("Prozess nicht gefunden");
|
||||
|
||||
const master = parseProcessForm(formData);
|
||||
await db.process.update({ where: { id: processId }, data: master });
|
||||
|
||||
const level = z.coerce.number().int().min(1).max(4);
|
||||
const biaData = {
|
||||
rtoHours: hours.parse(formData.get("rtoHours") ?? ""),
|
||||
rpoHours: hours.parse(formData.get("rpoHours") ?? ""),
|
||||
mtdHours: hours.parse(formData.get("mtdHours") ?? ""),
|
||||
impactC: level.parse(formData.get("impactC")),
|
||||
impactI: level.parse(formData.get("impactI")),
|
||||
impactA: level.parse(formData.get("impactA")),
|
||||
notes: (formData.get("notes") as string)?.trim() || null,
|
||||
};
|
||||
const criticality = Math.max(biaData.impactC, biaData.impactI, biaData.impactA);
|
||||
await db.biaEntry.upsert({
|
||||
where: { processId },
|
||||
update: { ...biaData, criticality },
|
||||
create: { ...biaData, criticality, processId, tenantId: session.user.tenantId },
|
||||
});
|
||||
|
||||
await writeAuditLog({
|
||||
tenantId: session.user.tenantId,
|
||||
actorId: session.user.id,
|
||||
action: "update",
|
||||
entity: "process",
|
||||
entityId: processId,
|
||||
before,
|
||||
after: { ...master, bia: { ...biaData, criticality } },
|
||||
});
|
||||
revalidatePath("/processes");
|
||||
redirect(`/processes?detail=${processId}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user