feat: Phase 2 triage with keyboard shortcuts J/S/X
Implement /triage GET/POST routes in triage.py blueprint; render phase2.html with day-grouped photo grid, Alpine.js keyboard tagging (J=journal, S=story, X/Space=skip), and done-button gated on all-tagged. Remove stub from albums.py; register triage.bp in __init__.py. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -70,22 +70,3 @@ def select():
|
||||
save_state(state, current_app)
|
||||
return redirect(f"/triage?album_id={primary_id}")
|
||||
|
||||
|
||||
# TODO(task-6): replace this stub with the real triage route
|
||||
@bp.get("/triage")
|
||||
def triage():
|
||||
album_id = request.args.get("album_id", "")
|
||||
notes_content = ""
|
||||
phase_stale = []
|
||||
if album_id:
|
||||
state = load_state(album_id, current_app)
|
||||
if state:
|
||||
notes_content = state.notes
|
||||
phase_stale = state.phase_stale
|
||||
return render_template(
|
||||
"base.html",
|
||||
current_phase="triage",
|
||||
album_id=album_id,
|
||||
notes_content=notes_content,
|
||||
phase_stale=phase_stale,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
from flask import Blueprint, current_app, jsonify, redirect, render_template, request
|
||||
from app.state import load_state, save_state
|
||||
|
||||
bp = Blueprint("triage", __name__)
|
||||
|
||||
|
||||
@bp.get("/triage")
|
||||
def triage():
|
||||
album_id = request.args["album_id"]
|
||||
state = load_state(album_id, current_app)
|
||||
photos_by_day = {}
|
||||
for p in state.photos:
|
||||
day = p.local_datetime[:10]
|
||||
photos_by_day.setdefault(day, []).append(p)
|
||||
all_tagged = all(p.tag != "untagged" for p in state.photos)
|
||||
return render_template(
|
||||
"phase2.html",
|
||||
state=state,
|
||||
photos_by_day=photos_by_day,
|
||||
all_tagged=all_tagged,
|
||||
current_phase="triage",
|
||||
album_id=album_id,
|
||||
phase_stale=state.phase_stale,
|
||||
notes_content=state.notes,
|
||||
)
|
||||
|
||||
|
||||
@bp.post("/triage/tag")
|
||||
def tag():
|
||||
body = request.get_json()
|
||||
state = load_state(body["album_id"], current_app)
|
||||
for p in state.photos:
|
||||
if p.id == body["asset_id"]:
|
||||
p.tag = body["tag"]
|
||||
break
|
||||
save_state(state, current_app)
|
||||
tagged_count = sum(1 for p in state.photos if p.tag != "untagged")
|
||||
return jsonify({"ok": True, "tagged_count": tagged_count, "total": len(state.photos)})
|
||||
|
||||
|
||||
@bp.post("/triage/done")
|
||||
def done():
|
||||
body = request.get_json()
|
||||
state = load_state(body["album_id"], current_app)
|
||||
if not all(p.tag != "untagged" for p in state.photos):
|
||||
return jsonify({"error": "not all tagged"}), 400
|
||||
if "triage" not in state.phases_completed:
|
||||
state.phases_completed.append("triage")
|
||||
state.phase = "curate"
|
||||
save_state(state, current_app)
|
||||
return jsonify({"ok": True, "redirect": f"/curate?album_id={body['album_id']}"})
|
||||
Reference in New Issue
Block a user