Extract HTML5 operations controller
CI / python (push) Has been cancelled
CI / rust (push) Has been cancelled

This commit is contained in:
2026-05-17 19:16:26 +03:00
parent 07d23d2ba9
commit f6679d1694
2 changed files with 129 additions and 36 deletions
@@ -0,0 +1,94 @@
from __future__ import annotations
import time
from collections.abc import Callable, Iterable, Iterator
from fastapi import HTTPException
from api_server.html5_operations import (
filter_html5_operation_jobs,
render_html5_operation_detail,
render_html5_operation_rows,
render_html5_operation_summary,
render_html5_operations,
)
from api_server.html5_sse import html5_sse_comment, html5_sse_if_changed
def html5_operations_page(
*,
jobs: Iterable[object],
project_id: str = "",
status: str = "",
kind: str = "",
) -> str:
return render_html5_operations(
_filtered_jobs(jobs, project_id=project_id, status=status, kind=kind),
project_id=project_id,
status=status,
kind=kind,
)
def html5_operation_rows(
*,
jobs: Iterable[object],
project_id: str = "",
status: str = "",
kind: str = "",
) -> str:
return render_html5_operation_rows(_filtered_jobs(jobs, project_id=project_id, status=status, kind=kind))
def html5_operation_detail(*, jobs_by_id: dict[str, object], job_id: str) -> str:
job = jobs_by_id.get(job_id)
if job is None:
raise HTTPException(status_code=404, detail=f"Unknown operation job: {job_id}")
return render_html5_operation_detail(job)
def html5_operation_summary(
*,
jobs: Iterable[object],
project_id: str = "",
status: str = "",
kind: str = "",
) -> str:
return render_html5_operation_summary(_filtered_jobs(jobs, project_id=project_id, status=status, kind=kind))
def html5_operations_event_stream(
*,
jobs: Callable[[], Iterable[object]],
once: bool = False,
project_id: str = "",
status: str = "",
kind: str = "",
) -> Iterator[str]:
last_fragments: dict[str, str] = {}
while True:
yield html5_sse_comment("operations heartbeat")
filtered = _filtered_jobs(jobs(), project_id=project_id, status=status, kind=kind)
yield from html5_sse_if_changed(
last_fragments,
"operations-summary",
render_html5_operation_summary(filtered),
)
yield from html5_sse_if_changed(
last_fragments,
"operations-jobs",
render_html5_operation_rows(filtered),
)
if once:
break
time.sleep(3)
def _filtered_jobs(
jobs: Iterable[object],
*,
project_id: str = "",
status: str = "",
kind: str = "",
) -> list[object]:
return filter_html5_operation_jobs(jobs, project_id=project_id, status=status, kind=kind)
+35 -36
View File
@@ -81,12 +81,14 @@ from api_server.html5_editor import (
render_html5_symbols, render_html5_symbols,
) )
from api_server.html5_operations import ( from api_server.html5_operations import (
filter_html5_operation_jobs,
latest_html5_import_job, latest_html5_import_job,
render_html5_operation_detail, )
render_html5_operation_rows, from api_server.html5_operations_controller import (
render_html5_operation_summary, html5_operation_detail as _html5_operation_detail,
render_html5_operations, html5_operation_rows as _html5_operation_rows,
html5_operation_summary as _html5_operation_summary,
html5_operations_event_stream as _html5_operations_event_stream,
html5_operations_page as _html5_operations_page,
) )
from api_server.html5_setup import ( from api_server.html5_setup import (
render_html5_import_check, render_html5_import_check,
@@ -1663,8 +1665,8 @@ async def html5_delete_project(project_id: str, request: Request) -> Response:
@app.get("/html5/operations") @app.get("/html5/operations")
async def html5_operations(project_id: str = "", status: str = "", kind: str = "") -> Response: async def html5_operations(project_id: str = "", status: str = "", kind: str = "") -> Response:
return _html5_response( return _html5_response(
render_html5_operations( _html5_operations_page(
_html5_operation_jobs(project_id=project_id, status=status, kind=kind), jobs=_operations.jobs.values(),
project_id=project_id, project_id=project_id,
status=status, status=status,
kind=kind, kind=kind,
@@ -1674,22 +1676,31 @@ async def html5_operations(project_id: str = "", status: str = "", kind: str = "
@app.get("/html5/operations/jobs") @app.get("/html5/operations/jobs")
async def html5_operation_jobs(project_id: str = "", status: str = "", kind: str = "") -> Response: async def html5_operation_jobs(project_id: str = "", status: str = "", kind: str = "") -> Response:
jobs = _html5_operation_jobs(project_id=project_id, status=status, kind=kind) return _html5_response(
return _html5_response(render_html5_operation_rows(jobs)) _html5_operation_rows(
jobs=_operations.jobs.values(),
project_id=project_id,
status=status,
kind=kind,
)
)
@app.get("/html5/operations/jobs/{job_id}/detail") @app.get("/html5/operations/jobs/{job_id}/detail")
async def html5_operation_job_detail(job_id: str) -> Response: async def html5_operation_job_detail(job_id: str) -> Response:
job = _operations.jobs.get(job_id) return _html5_response(_html5_operation_detail(jobs_by_id=_operations.jobs, job_id=job_id))
if job is None:
raise HTTPException(status_code=404, detail=f"Unknown operation job: {job_id}")
return _html5_response(render_html5_operation_detail(job))
@app.get("/html5/operations/summary") @app.get("/html5/operations/summary")
async def html5_operation_summary(project_id: str = "", status: str = "", kind: str = "") -> Response: async def html5_operation_summary(project_id: str = "", status: str = "", kind: str = "") -> Response:
jobs = _html5_operation_jobs(project_id=project_id, status=status, kind=kind) return _html5_response(
return _html5_response(render_html5_operation_summary(jobs)) _html5_operation_summary(
jobs=_operations.jobs.values(),
project_id=project_id,
status=status,
kind=kind,
)
)
@app.get("/html5/operations/events") @app.get("/html5/operations/events")
@@ -1699,18 +1710,15 @@ async def html5_operations_events(
status: str = "", status: str = "",
kind: str = "", kind: str = "",
) -> StreamingResponse: ) -> StreamingResponse:
def stream_operations(): return _html5_sse_response(
last_fragments: dict[str, str] = {} _html5_operations_event_stream(
while True: jobs=lambda: _operations.jobs.values(),
yield _html5_sse_comment("operations heartbeat") once=once,
jobs = _html5_operation_jobs(project_id=project_id, status=status, kind=kind) project_id=project_id,
yield from _html5_sse_if_changed(last_fragments, "operations-summary", render_html5_operation_summary(jobs)) status=status,
yield from _html5_sse_if_changed(last_fragments, "operations-jobs", render_html5_operation_rows(jobs)) kind=kind,
if once: )
break )
time.sleep(3)
return _html5_sse_response(stream_operations())
@app.get("/html5/projects/{project_id}/editor") @app.get("/html5/projects/{project_id}/editor")
@@ -8333,15 +8341,6 @@ def _current_import_source(project_id: str) -> ImportSourceKind:
return ImportSourceKind.XML_DUMP return ImportSourceKind.XML_DUMP
def _html5_operation_jobs(project_id: str = "", status: str = "", kind: str = "") -> list[OperationJob]:
return filter_html5_operation_jobs(
_operations.jobs.values(),
project_id=project_id,
status=status,
kind=kind,
)
def _html5_latest_import_job(project_id: str) -> OperationJob | None: def _html5_latest_import_job(project_id: str) -> OperationJob | None:
return latest_html5_import_job(_operations.jobs.values(), project_id) return latest_html5_import_job(_operations.jobs.values(), project_id)