Ablaufkarten trennen: "Bald ablaufend" zeigt kein Abgelaufenes mehr

Eine Karte mit dieser Ueberschrift, in der bereits Ueberfaelliges steht,
ist irrefuehrend. KarteAblauf bekommt daher einen Modus soon/expired/alle
statt des bisherigen Schalters "nurAbgelaufen".

Neu ist die Karte "Ablauf-Uebersicht" (alle), die beides zusammen zeigt.
Sie steht auch in der eingebauten Vorgabe, damit dort ohne Zutun weiterhin
Ueberfaelliges sichtbar ist.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-07-23 12:24:30 +02:00
parent 1fd1e89872
commit d6a717e39c
3 changed files with 34 additions and 10 deletions

View File

@@ -54,7 +54,9 @@ ENFORCED_KEY = "dashboard_enforced"
BUILTIN_LAYOUT: list[dict] = [
{"i": "actions", "x": 0, "y": 0, "w": 4, "h": 3},
{"i": "status", "x": 4, "y": 0, "w": 8, "h": 3},
{"i": "expiring", "x": 0, "y": 3, "w": 6, "h": 6},
# Bewusst die kombinierte Karte: "expiring" zeigt nur noch Laufendes, in der
# Vorgabe soll aber auch Ueberfaelliges ohne Zutun sichtbar sein.
{"i": "expiry-all", "x": 0, "y": 3, "w": 6, "h": 6},
{"i": "shopping", "x": 6, "y": 3, "w": 6, "h": 6},
{"i": "expiry-donut", "x": 0, "y": 9, "w": 4, "h": 6},
{"i": "category-donut", "x": 4, "y": 9, "w": 4, "h": 6},

View File

@@ -155,7 +155,7 @@ def test_layout_faellt_auf_die_eingebaute_zurueck(db, user):
assert antwort.source == "builtin"
assert antwort.enforced is False
assert antwort.has_default is False
assert any(k["i"] == "expiring" for k in antwort.layout)
assert any(k["i"] == "expiry-all" for k in antwort.layout)
def test_eigene_anordnung_wird_gespeichert(db, user):

View File

@@ -109,16 +109,32 @@ function KarteEinheiten() {
}
// ---------------------------------------------------------------- Listen
function KarteAblauf({ nurAbgelaufen = false }) {
/**
* Ablaufliste in drei Ausprägungen.
*
* "soon" zeigt bewusst NUR das, was noch läuft: Eine Karte mit der Überschrift
* „Bald ablaufend“, in der bereits Abgelaufenes steht, führt in die Irre.
* Wer beides zusammen sehen will, nimmt "alle".
*/
const ABLAUF_LEER = {
soon: "Nichts läuft demnächst ab.",
expired: "Nichts ist abgelaufen.",
alle: "Nichts läuft demnächst ab und nichts ist abgelaufen.",
};
function KarteAblauf({ modus = "alle" }) {
const { formatBestBefore } = useSettings();
const { daten, fehler } = useDaten(() => api.expiring());
const zeilen = (daten || []).filter((e) => (nurAbgelaufen ? e.days_left < 0 : true));
const zeilen = (daten || []).filter((e) => {
if (modus === "expired") return e.days_left < 0;
if (modus === "soon") return e.days_left >= 0;
return true;
});
return (
<Zustand fehler={fehler} daten={daten}
leer={nurAbgelaufen ? "Nichts ist abgelaufen." : "Nichts läuft demnächst ab."}>
<Zustand fehler={fehler} daten={daten} leer={ABLAUF_LEER[modus]}>
{zeilen.length === 0 ? (
<div className="empty">{nurAbgelaufen ? "Nichts ist abgelaufen." : "Nichts läuft demnächst ab."}</div>
<div className="empty">{ABLAUF_LEER[modus]}</div>
) : (
<div className="table-wrap">
<table className="table">
@@ -407,15 +423,21 @@ export const KARTEN = {
},
expiring: {
titel: "Bald ablaufend", icon: "clock", vorschau: "tabelle",
beschreibung: "Chargen innerhalb der Warnfrist",
beschreibung: "Nur Chargen innerhalb der Warnfrist ohne bereits abgelaufene",
standard: { w: 6, h: 6 }, min: { w: 4, h: 4 },
komponente: () => <KarteAblauf />,
komponente: () => <KarteAblauf modus="soon" />,
},
expired: {
titel: "Abgelaufen", icon: "alert", vorschau: "tabelle",
beschreibung: "Nur überfällige Chargen",
standard: { w: 6, h: 5 }, min: { w: 4, h: 4 },
komponente: () => <KarteAblauf nurAbgelaufen />,
komponente: () => <KarteAblauf modus="expired" />,
},
"expiry-all": {
titel: "Ablauf-Übersicht", icon: "clock", vorschau: "tabelle",
beschreibung: "Abgelaufen und bald ablaufend in einer Liste",
standard: { w: 6, h: 6 }, min: { w: 4, h: 4 },
komponente: () => <KarteAblauf modus="alle" />,
},
shopping: {
titel: "Einkaufsliste", icon: "cart", vorschau: "tabelle",