bcfee45bd7
Implements Task 4: base.html DaisyUI/Alpine shell, notes autosave panel, nav.py phase switching with downstream stale marking, notes.py save/get endpoints, state debug endpoint, and stub /triage route for test support. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
52 lines
1.6 KiB
Python
52 lines
1.6 KiB
Python
from flask import Blueprint, current_app, jsonify, redirect, request
|
|
from app.state import load_state, save_state
|
|
|
|
bp = Blueprint("nav", __name__)
|
|
|
|
STALE_DOWNSTREAM = {
|
|
"triage": ["curate", "group", "write"],
|
|
"curate": ["group", "write"],
|
|
"group": ["write"],
|
|
"write": [],
|
|
"export": [],
|
|
}
|
|
|
|
|
|
@bp.post("/nav/phase")
|
|
def goto_phase():
|
|
body = request.get_json()
|
|
target = body["target_phase"]
|
|
state = load_state(body["album_id"], current_app)
|
|
if state is None:
|
|
return jsonify({"error": "no state"}), 404
|
|
|
|
# Mark downstream completed phases and the current phase as stale
|
|
downstream = STALE_DOWNSTREAM.get(target, [])
|
|
candidates = set(downstream) & (set(state.phases_completed) | {state.phase})
|
|
newly_stale = [p for p in candidates if p not in state.phase_stale]
|
|
state.phase_stale = list(set(state.phase_stale + newly_stale))
|
|
state.phase = target
|
|
save_state(state, current_app)
|
|
return jsonify({"ok": True, "phase": target})
|
|
|
|
|
|
@bp.post("/nav/dismiss-stale")
|
|
def dismiss_stale():
|
|
album_id = request.form["album_id"]
|
|
phase = request.form["phase"]
|
|
state = load_state(album_id, current_app)
|
|
if state:
|
|
state.phase_stale = [p for p in state.phase_stale if p != phase]
|
|
save_state(state, current_app)
|
|
return redirect(f"/{phase}?album_id={album_id}")
|
|
|
|
|
|
@bp.get("/state/<album_id>")
|
|
def get_state(album_id):
|
|
"""Debug/test endpoint — returns full state JSON."""
|
|
state = load_state(album_id, current_app)
|
|
if state is None:
|
|
return jsonify({"error": "no state"}), 404
|
|
from dataclasses import asdict
|
|
return jsonify(asdict(state))
|