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:
1 parent
fef9c8f16e
commit
fdbb31065f
8 files changed
+33
-24
No files matched your search
+1
-1
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in new issue
Block a user