import json from pathlib import Path from fastapi import APIRouter, Form, Request from fastapi.responses import HTMLResponse, StreamingResponse from gui.state import runner, templates router = APIRouter(prefix="/compose") @router.get("", response_class=HTMLResponse) async def compose_page(request: Request): services = runner.list_services() deployed = runner.list_deployed() return templates.TemplateResponse( "compose/index.html", { "request": request, "active": "compose", "services": services, "deployed": deployed, }, ) @router.get("/{service}", response_class=HTMLResponse) async def service_detail(request: Request, service: str): deployed = (Path("/srv") / service).is_dir() return templates.TemplateResponse( "compose/detail.html", { "request": request, "active": "compose", "service": service, "deployed": deployed, }, ) @router.get("/{service}/stream/{action}") async def service_stream(service: str, action: str): async def generate(): cmd_map = { "up": f"pos docker compose up {service}", "down": f"pos docker compose down {service}", "restart": f"pos docker compose restart {service}", "logs": f"pos docker compose logs {service}", } cmd = cmd_map.get(action) if not cmd: yield f"event: error\ndata: Unknown action: {action}\n\n" return async for event in runner.stream(cmd): yield f"event: {event['event']}\ndata: {event['data']}\n\n" return StreamingResponse(generate(), media_type="text/event-stream") @router.post("/config/set") async def config_set(key: str = Form(...), value: str = Form(...)): code, out, err = await runner.run(f"pos docker compose config set {key}={value}") return {"ok": code == 0, "output": out or err} @router.get("/config", response_class=HTMLResponse) async def config_page(request: Request): code, out, _ = await runner.run("pos docker compose config") config_file = Path.home() / ".config" / "linux_post_install" / "compose.env" current = "" if config_file.is_file(): current = config_file.read_text() return templates.TemplateResponse( "compose/config.html", { "request": request, "active": "compose", "current": current, "status": out, }, )