Show Git ingestion job status

This commit is contained in:
george
2026-06-06 12:13:40 +01:00
parent ff4da0cb9e
commit 6fe4d1b9fc
2 changed files with 106 additions and 8 deletions
+55 -8
View File
@@ -1,8 +1,11 @@
"""WebUI FastAPI application."""
import asyncio
import html
import os
import uuid
from datetime import datetime, timezone
from pathlib import Path
from typing import List, Optional
from typing import Any, Dict, List, Optional
from fastapi import FastAPI, File, Form, Request, UploadFile
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse
@@ -23,6 +26,8 @@ templates.env.globals["escapeHtml"] = lambda value: html.escape(str(value or "")
app.mount("/static", StaticFiles(directory=os.path.join(os.path.dirname(__file__), "static")), name="static")
_client: Optional[DocsAPIClient] = None
_sync_jobs: Dict[str, Dict[str, Any]] = {}
_sync_tasks: set[asyncio.Task] = set()
def get_client() -> DocsAPIClient:
@@ -35,6 +40,25 @@ def get_client() -> DocsAPIClient:
return _client
def utc_now() -> str:
return datetime.now(timezone.utc).isoformat()
async def run_sync_job(job_id: str, override: bool) -> None:
job = _sync_jobs[job_id]
job["status"] = "running"
job["started_at"] = utc_now()
try:
result = await get_client().post("/sources/sync", json={"override": override})
job["result"] = result
job["status"] = "succeeded" if result.get("success") else "failed"
except Exception as exc:
job["status"] = "failed"
job["error"] = str(exc)
finally:
job["finished_at"] = utc_now()
@app.on_event("shutdown")
async def shutdown() -> None:
if _client is not None:
@@ -300,10 +324,33 @@ async def add_source(
@app.post("/sources/sync")
async def sync_sources(override: bool = Form(False)):
client = get_client()
try:
result = await client.post("/sources/sync", json={"override": override})
body = f"<h1>Git Sync Complete</h1><pre>{html.escape(str(result))}</pre><a href='/sources'>Back</a>"
except Exception as e:
body = f"<h1>Git Sync Failed</h1><pre>{html.escape(str(e))}</pre><a href='/sources'>Back</a>"
return page("Git Sync", body)
job_id = uuid.uuid4().hex
_sync_jobs[job_id] = {
"id": job_id,
"status": "queued",
"created_at": utc_now(),
"started_at": None,
"finished_at": None,
"result": None,
"error": None,
}
task = asyncio.create_task(run_sync_job(job_id, override))
_sync_tasks.add(task)
task.add_done_callback(_sync_tasks.discard)
return RedirectResponse(url=f"/sources/jobs/{job_id}", status_code=303)
@app.get("/sources/jobs/{job_id}")
async def sync_job_page(request: Request, job_id: str):
job = _sync_jobs.get(job_id)
if job is None:
return page("Git Sync Not Found", "<h1>Git Sync Not Found</h1><a href='/sources'>Back</a>")
return templates.TemplateResponse("sync_job.html", {"request": request, "job": job})
@app.get("/sources/jobs/{job_id}/status")
async def sync_job_status(job_id: str):
job = _sync_jobs.get(job_id)
if job is None:
return JSONResponse(status_code=404, content={"error": "Sync job not found"})
return job