Add HTML5 operations monitor
This commit is contained in:
@@ -70,6 +70,54 @@ def render_html5_project_rows(projects: Iterable[object]) -> str:
|
||||
return project_rows
|
||||
|
||||
|
||||
def render_html5_operations(jobs: Iterable[object]) -> str:
|
||||
job_list = list(jobs)
|
||||
return _page(
|
||||
"SFERA HTML5 operations",
|
||||
f"""
|
||||
<main class="shell" data-html5-page="operations">
|
||||
<section class="hero">
|
||||
<div>
|
||||
<p class="eyebrow">SFERA HTML5</p>
|
||||
<h1>Операции сервера</h1>
|
||||
<p class="lead">Очередь фоновых задач отрисовывается API-сервером и обновляется htmx polling без React runtime.</p>
|
||||
</div>
|
||||
<div class="hero-metrics">
|
||||
<strong>{len(job_list)}</strong>
|
||||
<span>jobs</span>
|
||||
</div>
|
||||
</section>
|
||||
<section class="band">
|
||||
<div class="section-title">
|
||||
<h2>Очередь</h2>
|
||||
<a class="button" href="/html5">Проекты</a>
|
||||
</div>
|
||||
<div class="table-wrap">
|
||||
<table data-html5-operations>
|
||||
<thead>
|
||||
<tr><th>Job</th><th>Проект</th><th>Статус</th><th>Stage</th><th>Сообщение</th></tr>
|
||||
</thead>
|
||||
<tbody
|
||||
data-html5-operations-body
|
||||
hx-get="/html5/operations/jobs"
|
||||
hx-trigger="every 3s"
|
||||
hx-swap="innerHTML"
|
||||
>{render_html5_operation_rows(job_list)}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
def render_html5_operation_rows(jobs: Iterable[object]) -> str:
|
||||
rows = "\n".join(_operation_row(job) for job in jobs)
|
||||
if not rows:
|
||||
return '<tr><td colspan="5" class="muted">Фоновые операции пока не запускались</td></tr>'
|
||||
return rows
|
||||
|
||||
|
||||
def render_html5_editor(
|
||||
*,
|
||||
project_id: str,
|
||||
@@ -474,6 +522,29 @@ def _project_link(project: object, active_project_id: str) -> str:
|
||||
return f'<a class="project-link{active}" href="/html5/projects/{quote(project_id)}/editor">{escape(name)}</a>'
|
||||
|
||||
|
||||
def _operation_row(job: object) -> str:
|
||||
job_id = str(getattr(job, "job_id", ""))
|
||||
kind = str(getattr(job, "kind", ""))
|
||||
status = _enum_text(getattr(job, "status", ""))
|
||||
payload = getattr(job, "payload", {}) or {}
|
||||
project_id = str(payload.get("project_id") or "")
|
||||
stage = str(payload.get("stage") or "")
|
||||
message = str(payload.get("message") or getattr(job, "error", "") or "")
|
||||
project_link = (
|
||||
f'<a href="/html5/projects/{quote(project_id)}/setup">{escape(project_id)}</a>'
|
||||
if project_id
|
||||
else '<span class="muted">-</span>'
|
||||
)
|
||||
return f"""
|
||||
<tr data-html5-operation="{escape(job_id)}">
|
||||
<td><strong>{escape(kind)}</strong><small>{escape(job_id)}</small></td>
|
||||
<td>{project_link}</td>
|
||||
<td>{escape(status)}</td>
|
||||
<td>{escape(stage or "-")}</td>
|
||||
<td>{escape(message or "-")}</td>
|
||||
</tr>"""
|
||||
|
||||
|
||||
def _topbar(project_id: str, project_nav: str) -> str:
|
||||
return f"""
|
||||
<header class="topbar" data-html5-topbar>
|
||||
|
||||
Reference in New Issue
Block a user