Kanban: Voraussetzung gibt schon bei "Wartet" frei

- Eine abhängige Aufgabe bleibt gesperrt (in "Offen"), bis jede
  Voraussetzung in "Wartet" oder "Erledigt" steht – vorher erst bei
  "Erledigt"
- Server (UNLOCKING), Karte, Dialog und Meldungen angepasst; Test prüft
  "In Arbeit" (gesperrt) und "Wartet" (frei)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
guyg1474andClaude Opus 5.5 committed 2026-10-15 20:12:59 +02:00
1 parent fef9c8f16e
commit fdbb31065f
8 files changed
+33 -24

No files matched your search

+1 -1
View File
@@ -273,7 +273,7 @@ CREATE TABLE IF NOT EXISTS kanban_checklist (
position INTEGER NOT NULL
);
-- Abhängigkeiten: task_id ist gesperrt, bis requires_id erledigt ist (nur innerhalb eines Projekts)
-- Abhängigkeiten: task_id ist gesperrt, bis requires_id in "Wartet" oder "Erledigt" steht (nur innerhalb eines Projekts)
CREATE TABLE IF NOT EXISTS kanban_dependencies (
task_id INTEGER NOT NULL REFERENCES kanban_tasks(id) ON DELETE CASCADE,
requires_id INTEGER NOT NULL REFERENCES kanban_tasks(id) ON DELETE CASCADE,
+9 -7
View File
@@ -28,6 +28,8 @@ MAX_LINKS = 20
MAX_CHECKLIST = 100
MAX_CHECK_TEXT = 200
MAX_REQUIRES = 30
# Eine Voraussetzung gibt ihre abhängigen Aufgaben frei, sobald sie so weit ist
UNLOCKING = ("wartet", "erledigt")
ARCHIVE_AFTER = timedelta(days=2)
DELETE_AFTER = timedelta(days=14)
CLEANUP_SECONDS = 3600
@@ -226,16 +228,16 @@ def _task_extras(conn, project_id: int) -> dict:
):
e = extras.setdefault(r["task_id"], {"checklist": [], "requires": [], "blocked": False})
e["requires"].append(r["requires_id"])
e["blocked"] = e["blocked"] or r["status"] != "erledigt"
e["blocked"] = e["blocked"] or r["status"] not in UNLOCKING
return extras
def _open_requirements(conn, task_id: int) -> list:
"""Titel der noch nicht erledigten Voraussetzungen einer Aufgabe."""
"""Titel der Voraussetzungen, die noch nicht in "Wartet" oder "Erledigt" stehen."""
return [r["title"] for r in conn.execute(
"""SELECT t.title FROM kanban_dependencies d JOIN kanban_tasks t ON t.id = d.requires_id
WHERE d.task_id = ? AND t.status != 'erledigt' ORDER BY t.title""",
(task_id,),
f"""SELECT t.title FROM kanban_dependencies d JOIN kanban_tasks t ON t.id = d.requires_id
WHERE d.task_id = ? AND t.status NOT IN ({','.join('?' * len(UNLOCKING))}) ORDER BY t.title""",
(task_id, *UNLOCKING),
)]
@@ -291,9 +293,9 @@ def _save_requires(conn, task_id: int, ids: list) -> None:
def _ensure_unlocked(conn, task_id: int, status: str) -> None:
"""Gesperrte Aufgaben bleiben in "Offen", bis alle Voraussetzungen erledigt sind."""
"""Gesperrte Aufgaben bleiben in "Offen", bis alle Voraussetzungen in "Wartet" oder "Erledigt" stehen."""
if status != "offen" and (missing := _open_requirements(conn, task_id)):
raise ValidationError("Gesperrt – erst erledigen: " + ", ".join(f"„{t}“" for t in missing))
raise ValidationError("Gesperrt – erst auf „Wartet“ oder „Erledigt“ setzen: " + ", ".join(f"„{t}“" for t in missing))
def _board(conn, project_id: int) -> dict: