from __future__ import annotations
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from ..layout.page import page
def register(app: FastAPI) -> None:
@app.get("/ui/tasks")
async def ui_tasks() -> HTMLResponse:
body = """
Tasks
""".strip()
script = """
const out = document.getElementById("out");
async function refresh() {
out.textContent = "Loading...";
try {
const q = await apiJson("/api/v2/queue");
const completedLimit = 25;
const completedOffset = Number(localStorage.getItem("mvp_completed_offset") || "0") || 0;
const done = await apiJson("/api/v2/tasks?limit=" + completedLimit + "&offset=" + completedOffset + "&states=SUCCEEDED,FAILED,CANCELED");
function pill(state) {
const s = String(state || "");
if (s === "SUCCEEDED") return `${s}`;
if (s === "FAILED") return `${s}`;
if (s === "CANCELED") return `${s}`;
if (s === "RUNNING") return `${s}`;
if (s === "QUEUED" || s === "PENDING_RESOURCES" || s === "SUBMITTING" || s === "SUBMITTED") return `${s}`;
return `${s}`;
}
function row(t) {
const id = t.task_id;
return `
| ${id} |
${t.workload} |
${pill(t.state)} |
${t.nnodes} x ${t.n_gpus_per_node} GPU |
${t.updated_at || ""} |
`;
}
const running = (q.running || []).map(row).join("");
const pending = (q.pending || []).map(row).join("");
const doneRows = (done.tasks || []).map(row).join("");
const pageNo = Math.floor(completedOffset / completedLimit) + 1;
const prevDisabled = completedOffset <= 0;
const nextDisabled = !done.has_more;
out.innerHTML = `
Tip: configure token in
Login.
Running
| Task | Workload | State | Resources | Updated |
${running || "| (none) |
"}
Pending
| Task | Workload | State | Resources | Updated |
${pending || "| (none) |
"}
Completed
| Task | Workload | State | Resources | Updated |
${doneRows || "| (none) |
"}
`;
const prevBtn = document.getElementById("done-prev");
const nextBtn = document.getElementById("done-next");
if (prevBtn) prevBtn.onclick = () => {
const cur = Number(localStorage.getItem("mvp_completed_offset") || "0") || 0;
const next = Math.max(0, cur - completedLimit);
localStorage.setItem("mvp_completed_offset", String(next));
refresh();
};
if (nextBtn) nextBtn.onclick = () => {
const cur = Number(localStorage.getItem("mvp_completed_offset") || "0") || 0;
const next = cur + completedLimit;
localStorage.setItem("mvp_completed_offset", String(next));
refresh();
};
} catch (e) {
out.textContent = "Error: " + (e.status || "") + "\\n" + (e.body || String(e));
}
}
document.getElementById("refresh").onclick = refresh;
refresh();
""".strip()
return HTMLResponse(content=page("Tasks", "tasks", body, script))