- Backend: instruction_service.clear_consumed() bulk-deletes consumed rows - Backend: DELETE /api/instructions/consumed route (preserves pending) - Frontend: Clear button in consumed panel header (hidden when empty) - Frontend: SSE handler for history.cleared event - instant UI update - Frontend: api.clearConsumed() fetch wrapper
81 lines
2.5 KiB
Python
81 lines
2.5 KiB
Python
"""
|
|
app/api/routes_instructions.py
|
|
HTTP endpoints for instruction CRUD.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from fastapi import APIRouter, HTTPException, Query
|
|
from fastapi.responses import Response
|
|
|
|
from app.models import (
|
|
CreateInstructionRequest,
|
|
InstructionCreateResponse,
|
|
InstructionListResponse,
|
|
UpdateInstructionRequest,
|
|
)
|
|
from app.services import event_service, instruction_service
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/api/instructions", tags=["instructions"])
|
|
|
|
|
|
@router.get("", response_model=InstructionListResponse)
|
|
def list_instructions(
|
|
status: str = Query(default="all", pattern="^(pending|consumed|all)$")
|
|
):
|
|
items = instruction_service.list_instructions(status_filter=status)
|
|
return InstructionListResponse(items=items)
|
|
|
|
|
|
@router.post("", response_model=InstructionCreateResponse, status_code=201)
|
|
def create_instruction(body: CreateInstructionRequest):
|
|
item = instruction_service.create_instruction(body.content)
|
|
event_service.broadcast(
|
|
"instruction.created",
|
|
{"item": item.model_dump(mode="json")},
|
|
)
|
|
return InstructionCreateResponse(item=item)
|
|
|
|
|
|
@router.patch("/{instruction_id}", response_model=InstructionCreateResponse)
|
|
def update_instruction(instruction_id: str, body: UpdateInstructionRequest):
|
|
try:
|
|
item = instruction_service.update_instruction(instruction_id, body.content)
|
|
except KeyError:
|
|
raise HTTPException(status_code=404, detail="Instruction not found")
|
|
except PermissionError as exc:
|
|
raise HTTPException(status_code=409, detail=str(exc))
|
|
|
|
event_service.broadcast(
|
|
"instruction.updated",
|
|
{"item": item.model_dump(mode="json")},
|
|
)
|
|
return InstructionCreateResponse(item=item)
|
|
|
|
|
|
@router.delete("/consumed", status_code=200)
|
|
def clear_consumed_instructions():
|
|
"""Delete all consumed instructions. Pending instructions are never affected."""
|
|
count = instruction_service.clear_consumed()
|
|
event_service.broadcast("history.cleared", {"count": count})
|
|
return {"cleared": count}
|
|
|
|
|
|
@router.delete("/{instruction_id}", status_code=204)
|
|
def delete_instruction(instruction_id: str):
|
|
try:
|
|
instruction_service.delete_instruction(instruction_id)
|
|
except KeyError:
|
|
raise HTTPException(status_code=404, detail="Instruction not found")
|
|
except PermissionError as exc:
|
|
raise HTTPException(status_code=409, detail=str(exc))
|
|
|
|
event_service.broadcast("instruction.deleted", {"id": instruction_id})
|
|
return Response(status_code=204)
|
|
|
|
|