All checks were successful
Build and Deploy DevOpsDash / build-image (push) Successful in 8s
- Add projects router (Redis projects + workcontexts merged)
- Register projects router in main.py
- Extend knowledge router: howtos, agents, skills via MCP proxy
- Extend mcp_client: list/get howtos, agents, skills
- Rewrite dashboard.html: 4 tabs (Taskz/Worklog/Projects/Knowledge)
- Taskz: sidebar board list + Kanban columns with task modal
- Worklog: context/days picker + standup button
- Projects: context filter sidebar + work context display
- Knowledge: 6 sub-tabs (docs/howtos/agents/skills/adrs/memories)
with markdown rendering via marked.js
62 lines
1.8 KiB
Python
62 lines
1.8 KiB
Python
"""Projects router — registered git repos + work contexts from Redis."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter
|
|
|
|
from app.redis_client import get_redis, list_projects, list_workcontexts, PROJECT_KEY_PREFIX, WORKCONTEXT_KEY_PREFIX
|
|
|
|
router = APIRouter(prefix="/api/v1", tags=["projects"])
|
|
|
|
|
|
@router.get("/projects")
|
|
def api_list_projects(context: Optional[str] = None, q: Optional[str] = None):
|
|
r = get_redis()
|
|
projects = list_projects(r, context=context)
|
|
|
|
# Merge in work contexts (keyed by path)
|
|
wc_keys = r.keys(f"{WORKCONTEXT_KEY_PREFIX}*")
|
|
import json
|
|
work_contexts: dict = {}
|
|
for key in wc_keys:
|
|
raw = r.get(key)
|
|
if raw:
|
|
try:
|
|
path = key[len(WORKCONTEXT_KEY_PREFIX):]
|
|
work_contexts[path] = json.loads(raw)
|
|
except Exception:
|
|
pass
|
|
|
|
# Attach work context and apply search filter
|
|
result = []
|
|
for p in projects:
|
|
path = p.get("path", "")
|
|
p["work_context"] = work_contexts.get(path)
|
|
if q and q.lower() not in (p.get("name", "") + p.get("path", "") + " ".join(p.get("tags", []))).lower():
|
|
continue
|
|
result.append(p)
|
|
|
|
# Sort: projects with recent work context first
|
|
result.sort(
|
|
key=lambda p: (
|
|
p["work_context"]["saved_at"] if p.get("work_context") else "",
|
|
),
|
|
reverse=True,
|
|
)
|
|
|
|
# Context breakdown
|
|
contexts = {}
|
|
for p in result:
|
|
c = p.get("context", "unknown")
|
|
contexts[c] = contexts.get(c, 0) + 1
|
|
|
|
return {"projects": result, "total": len(result), "contexts": contexts}
|
|
|
|
|
|
@router.get("/workcontexts")
|
|
def api_list_workcontexts():
|
|
r = get_redis()
|
|
return {"contexts": list_workcontexts(r)}
|