From 5fb4b3cbf40c4e6667503456c368c2ea04607a6e Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 2 Jul 2026 19:46:37 +0200 Subject: [PATCH] =?UTF-8?q?Risiko-Bearbeiten:=20Ma=C3=9Fnahmen=20in=20voll?= =?UTF-8?q?er=20Breite,=20Brutto=E2=86=92Rest=20visualisiert?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Maßnahmen-Bereich unterhalb der Stammdaten über die komplette Breite (Tabelle mit ID, Titel, editierbarer Minderung je Dimension) - Zwei Aktionen als aufklappbare Buttons: "Maßnahme hinzufügen" (bestehende auswählen) und "Neue Maßnahme erstellen" (legt an und verknüpft direkt mit dem Risiko, Rest-Risiko wird neu berechnet) - Risiko-Detail: Brutto→Rest als zwei farbig abgesetzte Karten (rot/ orange) mit Pfeil, großer Score-Zahl und Level-Chip; darunter Farbskala (grün→rot) mit Markern für Brutto und Rest (Referenz: docs/ISMS-GUI-Verbesserungen-GEFIM.html) Verifiziert: neue Maßnahme -0,75 → Rest 1,75 × 4 = 7; Skala/Karten korrekt gerendert. Co-Authored-By: Claude Opus 4.8 --- docs/ISMS-GUI-Verbesserungen-GEFIM.html | 382 ++++++++++++++++++++++++ messages/de.json | 6 +- messages/en.json | 6 +- src/components/risk-modals.tsx | 291 +++++++++++------- 4 files changed, 578 insertions(+), 107 deletions(-) create mode 100644 docs/ISMS-GUI-Verbesserungen-GEFIM.html diff --git a/docs/ISMS-GUI-Verbesserungen-GEFIM.html b/docs/ISMS-GUI-Verbesserungen-GEFIM.html new file mode 100644 index 0000000..dd8a128 --- /dev/null +++ b/docs/ISMS-GUI-Verbesserungen-GEFIM.html @@ -0,0 +1,382 @@ + + + + + +GEFIM ISMS – GUI-Verbesserungen + + + + + + +
+
GEFIMGUI-Verbesserungen · Vorschlag
+
+

Vorschläge für Detailansicht & Bearbeiten

+

Zwei überarbeitete Screens auf Basis eurer aktuellen Umsetzung: klarere Hierarchie, visuelle Risikodarstellung, Bearbeiten als Slide-over mit einem sticky Speichern. Öffne die Screens und probiere sie aus.

+
+ +
+
+
+

Risiko-Detail · R-001 (neu)

+

Visueller Brutto→Rest-Verlauf, Maßnahmen als Karten mit Fortschritt, einheitliche C/I/A-Gauges.

+
Ansicht öffnen →
+
+
+
+

Prozess bearbeiten (neu)

+

Slide-over mit Sprungnavigation, Typeahead-Asset-Zuordnung, farbige Schadenshöhe, ein Speichern, Löschen im ⋯-Menü.

+
Formular öffnen →
+
+
+ +
+

Was konkret verbessert wurde

+
+
1
Ein sticky Speichern statt zwei getrennter Buttons — inkl. Autosave-Indikator.
+
2
Risikowert visualisiert: Brutto→Rest mit Pfeil und Position auf einer Farbskala.
+
3
Slide-over statt hohem Modal — Kontext bleibt erhalten, Sprungnavigation oben.
+
4
Einheitliches C/I/A-Gauge mit fester Farblogik (1→4) statt loser Zahlen.
+
5
Maßnahmen als Karten mit Status, Fortschritt und Minderungseffekt.
+
6
Löschen entschärft — im ⋯-Überlaufmenü statt neben Speichern.
+
7
Typeahead-Suche für Asset-Zuordnung mit Chips statt zwei Dropdowns.
+
8
Einheiten & Inline-Hilfe an Feldern, Fokus-Zustände, Live-Validierung.
+
+
Tipp für Power-User: Command-Palette mit K für schnelle Navigation und Aktionen.
+
+
+ + +
+
+
+
+ + + + diff --git a/messages/de.json b/messages/de.json index d3157a0..7c574e5 100644 --- a/messages/de.json +++ b/messages/de.json @@ -256,7 +256,11 @@ "reductionI": "Minderung Schaden (0,00–4,00)", "reduction": "Minderung", "createFromAsset": "Risiko erstellen", - "catalogHint": "Aus Katalog wählen oder frei eingeben …" + "catalogHint": "Aus Katalog wählen oder frei eingeben …", + "addExistingBtn": "Maßnahme hinzufügen", + "createNewBtn": "Neue Maßnahme erstellen", + "measureCol": "Maßnahme", + "statusCol": "Status" }, "riskTreatment": { "AVOID": "Vermeiden", diff --git a/messages/en.json b/messages/en.json index 9d08def..0494dfb 100644 --- a/messages/en.json +++ b/messages/en.json @@ -256,7 +256,11 @@ "reductionI": "Reduction damage (0.00–4.00)", "reduction": "Reduction", "createFromAsset": "Create risk", - "catalogHint": "Pick from catalog or type freely …" + "catalogHint": "Pick from catalog or type freely …", + "addExistingBtn": "Add measure", + "createNewBtn": "Create new measure", + "measureCol": "Measure", + "statusCol": "Status" }, "riskTreatment": { "AVOID": "Avoid", diff --git a/src/components/risk-modals.tsx b/src/components/risk-modals.tsx index 16ff2e8..2640951 100644 --- a/src/components/risk-modals.tsx +++ b/src/components/risk-modals.tsx @@ -1,6 +1,6 @@ import Link from "next/link"; import { getFormatter, getTranslations } from "next-intl/server"; -import { Check, Pencil, Trash2, X } from "lucide-react"; +import { ArrowRight, Check, Pencil, Plus, Trash2, X } from "lucide-react"; import type { Prisma } from "@prisma/client"; import { addRiskAsset, @@ -71,50 +71,87 @@ async function ScorePill({ score }: { score: number }) { ); } -/** Bewertungs-Block: Wahrscheinlichkeit & Schaden mit Beschriftung + Score. */ -async function RatingBlock({ +/** Bewertungs-Karte: große Score-Zahl, darunter Wahrscheinlichkeit × Schaden + Level-Chip. */ +async function RatingCard({ title, likelihood, impact, score, - hint, + accent, }: { title: string; likelihood: number | null; impact: number | null; score: number | null; - hint?: string; + accent: "gross" | "residual"; }) { const t = await getTranslations("risks"); const format = await getFormatter(); const num = (v: number) => format.number(v, { maximumFractionDigits: 2 }); + + const border = accent === "gross" ? "border-l-[#d64c4c]" : "border-l-[#e0982e]"; + return ( -
- {title} +
+
+ {title} +
{score != null && likelihood != null && impact != null ? ( -
-
-
- {t("likelihoodShort")} -
-
{num(likelihood)}
-
-
×
-
-
- {t("damageShort")} -
-
{num(impact)}
-
-
=
-
+ <> +
+ + {num(score)} +
-
+
+ {t("likelihoodShort")} {num(likelihood)} × {t("damageShort")} {num(impact)} +
+ ) : ( -

{t("noMeasures")}

+

{t("noMeasures")}

)} - {hint &&

{hint}

} + {accent === "residual" && ( +

{t("residualAuto")}

+ )} +
+ ); +} + +/** Farbskala grün→rot mit Markern für Brutto (dunkel) und Rest (orange). SPEC §4.2. */ +function RiskScoreScale({ gross, residual }: { gross: number; residual: number | null }) { + // 5×5 → Score 1..25; Position linear auf der Skala + const pos = (v: number) => `${((Math.min(25, Math.max(1, v)) - 1) / 24) * 100}%`; + return ( +
+
+ + {residual != null && ( + + )} +
+
+ + Brutto + + + Rest + +
); } @@ -229,23 +266,26 @@ export async function RiskDetailModal({
- {/* Brutto- vs. Rest-Risiko — mit beschrifteten Werten */} -
-
- +
+ - +
+
{/* Notwendige Maßnahmen — echt verknüpft */} @@ -362,89 +402,130 @@ export async function RiskEditModal({ )}
- {/* Maßnahmen → bestimmen das Rest-Risiko */} -
-

{t("measures")}

-

{t("residualAuto")}

- {risk.riskMeasures.length === 0 &&

{tc("none")}

} -
    - {risk.riskMeasures.map((rm) => ( -
  • -
    - {measureRef(rm.measure.refNo)} - {rm.measure.title} -
    - -
    -
    - {/* Minderung nachträglich anpassen (upsert über linkMeasureToRisk) */} -
    - -
    - -
    - -
    -
  • - ))} -
+
+ + {/* Maßnahmen → bestimmen das Rest-Risiko (volle Breite unter den Stammdaten) */} +
+
+
+

{t("measures")}

+

{t("residualAuto")}

+
+
+ {/* Aufklappbare Formulare per
— serverseitig, kein Client-State */} {availableMeasures.length > 0 && ( +
+ + {t("addExistingBtn")} + +
+

{t("linkMeasure")}

+ + + + +
+ )} +
+ + {t("createNewBtn")} +
-

{t("linkMeasure")}

- +

{t("newMeasure")}

+ - )} - -
-

{t("newMeasure")}

- - - - -
- -
-
- -
+
+ + {risk.riskMeasures.length === 0 && ( +

{tc("none")}

+ )} + {risk.riskMeasures.length > 0 && ( +
+
+ {t("id")} + {t("measureCol")} + {t("reductionL")} + {t("reductionI")} + + +
+ {risk.riskMeasures.map((rm) => ( +
+ + {measureRef(rm.measure.refNo)} + + {rm.measure.title} + + + + + +
+ ))} +
+ )} +
+ +
+
+ +
);