Global labels: remove project_id, endpoints at /labels
Some checks failed
Deploy Tracker / deploy (push) Failing after 3s

Labels are now app-wide, not project-scoped.
GET/POST /labels, PATCH/DELETE /labels/{id}
This commit is contained in:
markov 2026-02-28 00:42:03 +01:00
parent 1f57f869ba
commit 009789ad8b
2 changed files with 11 additions and 20 deletions

View File

@ -1,4 +1,4 @@
"""Labels API — CRUD for project-scoped labels."""
"""Labels API — CRUD for global labels."""
import uuid
@ -26,31 +26,27 @@ class LabelUpdate(BaseModel):
class LabelOut(BaseModel):
id: str
project_id: str
name: str
color: str
@router.get("/projects/{project_id}/labels", response_model=list[LabelOut])
async def list_labels(project_id: str, db: AsyncSession = Depends(get_db)):
result = await db.execute(
select(Label).where(Label.project_id == uuid.UUID(project_id)).order_by(Label.name)
)
return [LabelOut(id=str(l.id), project_id=str(l.project_id), name=l.name, color=l.color) for l in result.scalars()]
@router.get("/labels", response_model=list[LabelOut])
async def list_labels(db: AsyncSession = Depends(get_db)):
result = await db.execute(select(Label).order_by(Label.name))
return [LabelOut(id=str(l.id), name=l.name, color=l.color) for l in result.scalars()]
@router.post("/projects/{project_id}/labels", response_model=LabelOut)
@router.post("/labels", response_model=LabelOut)
async def create_label(
project_id: str,
req: LabelCreate,
current_member: Member = Depends(get_current_member),
db: AsyncSession = Depends(get_db),
):
label = Label(project_id=uuid.UUID(project_id), name=req.name, color=req.color)
label = Label(name=req.name, color=req.color)
db.add(label)
await db.commit()
await db.refresh(label)
return LabelOut(id=str(label.id), project_id=str(label.project_id), name=label.name, color=label.color)
return LabelOut(id=str(label.id), name=label.name, color=label.color)
@router.patch("/labels/{label_id}", response_model=LabelOut)
@ -70,7 +66,7 @@ async def update_label(
label.color = req.color
await db.commit()
await db.refresh(label)
return LabelOut(id=str(label.id), project_id=str(label.project_id), name=label.name, color=label.color)
return LabelOut(id=str(label.id), name=label.name, color=label.color)
@router.delete("/labels/{label_id}")
@ -83,8 +79,6 @@ async def delete_label(
label = result.scalar_one_or_none()
if not label:
raise HTTPException(404, "Label not found")
# Remove task associations
await db.execute(select(TaskLabel).where(TaskLabel.label_id == label.id))
await db.delete(label)
await db.commit()
return {"ok": True}

View File

@ -54,15 +54,12 @@ class Step(Base):
class Label(Base):
"""Project-scoped labels (like Jira)."""
"""Global labels (app-wide)."""
__tablename__ = "labels"
project_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("projects.id"), nullable=False)
name: Mapped[str] = mapped_column(String(100), nullable=False)
name: Mapped[str] = mapped_column(String(100), unique=True, nullable=False)
color: Mapped[str] = mapped_column(String(7), default="#6366f1") # hex color
project: Mapped["Project"] = relationship()
class TaskLabel(Base):
"""Many-to-many: tasks ↔ labels."""