diff --git a/pyproject.toml b/pyproject.toml index 9b1b87f..e465e86 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "plba" -version = "0.3.5" +version = "0.3.6" description = "Platform runtime for business applications" readme = "README.md" requires-python = ">=3.11" diff --git a/src/app_runtime/control/trace_presenter.py b/src/app_runtime/control/trace_presenter.py index cbc6dd3..ec0576d 100644 --- a/src/app_runtime/control/trace_presenter.py +++ b/src/app_runtime/control/trace_presenter.py @@ -95,7 +95,7 @@ class TraceResponseRenderer: def _render_html(self, trace_view: TraceLogView, request: TraceQueryRequest) -> HTMLResponse: title = escape(f"Trace {trace_view.trace_id}") header_links = self._related_trace_links(trace_view, request) - rows = self._step_rows(trace_view, request) + sections = self._step_sections(trace_view, request) html = f""" @@ -166,26 +166,16 @@ class TraceResponseRenderer: a:hover {{ text-decoration: underline; }} - table {{ - width: 100%; - border-collapse: collapse; - }} - th, td {{ - vertical-align: top; - padding: 14px 12px; + .step-section + .step-section {{ + margin-top: 24px; + padding-top: 24px; border-top: 1px solid var(--line); }} - th {{ - text-align: left; - color: var(--muted); - font-size: 13px; - text-transform: uppercase; - letter-spacing: 0.06em; - }} - td.step {{ - width: 240px; + .step-title {{ + margin: 0 0 14px; + font-size: 22px; + line-height: 1.2; font-weight: 700; - white-space: nowrap; }} .log-entry + .log-entry {{ margin-top: 14px; @@ -222,6 +212,21 @@ class TraceResponseRenderer: .level-DEBUG {{ color: var(--debug); }} + @media (max-width: 640px) {{ + .page {{ + padding: 14px; + }} + .card {{ + padding: 16px 14px; + border-radius: 12px; + }} + h1 {{ + font-size: 22px; + }} + .step-title {{ + font-size: 20px; + }} + }} @@ -237,14 +242,7 @@ class TraceResponseRenderer:

Logs By Step

- - - - - - {rows} - -
StepLog
+ {sections}
@@ -283,11 +281,11 @@ class TraceResponseRenderer: ) return f"/traces/{trace_id}?{params}" - def _step_rows(self, trace_view: TraceLogView, request: TraceQueryRequest) -> str: + def _step_sections(self, trace_view: TraceLogView, request: TraceQueryRequest) -> str: groups = self._step_groups(trace_view.records) if not groups: - return " No log records for selected filters." - return "".join(self._step_row(group, request.include_attrs_json) for group in groups) + return "

No step

No log records for selected filters.
" + return "".join(self._step_section(group, request.include_attrs_json) for group in groups) def _step_groups(self, records: tuple[TraceLogRecord, ...]) -> tuple[TraceStepGroup, ...]: grouped: dict[str, list[TraceLogRecord]] = {} @@ -300,10 +298,10 @@ class TraceResponseRenderer: grouped[step].append(record) return tuple(TraceStepGroup(step=step, records=tuple(grouped[step])) for step in order) - def _step_row(self, group: TraceStepGroup, include_attrs_json: bool) -> str: - step_label = escape(group.step) if group.step else " " + def _step_section(self, group: TraceStepGroup, include_attrs_json: bool) -> str: + step_label = escape(group.step) if group.step else "No step" entries = "".join(self._log_entry(record, include_attrs_json) for record in group.records) - return f"{step_label}{entries}" + return f"

{step_label}

{entries}
" def _log_entry(self, record: TraceLogRecord, include_attrs_json: bool) -> str: level = escape(record.level) diff --git a/tests/test_trace_endpoint.py b/tests/test_trace_endpoint.py index e791d6e..5b8fd6d 100644 --- a/tests/test_trace_endpoint.py +++ b/tests/test_trace_endpoint.py @@ -201,11 +201,13 @@ def test_trace_endpoint_returns_html_page_with_related_links() -> None: assert response.status_code == 200 assert response.headers["content-type"].startswith("text/html") - assert "StepLog" in response.text - assert ">load_stocks<" in response.text - assert ">filter_stocks<" in response.text + assert "

Logs By Step

" in response.text + assert '

load_stocks

' in response.text + assert '

filter_stocks

' in response.text assert "loaded prices" in response.text assert "filtered suspicious ticker" in response.text + assert "2026-04-28T10:11:12+00:00 | INFO | ok" in response.text + assert "2026-04-28T10:11:12+00:00 | WARNING | degraded" in response.text assert 'href="/traces/trace-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true"' in response.text assert 'href="/traces/parent-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true"' in response.text assert 'href="/traces/child-1?format=html&levels=ERROR%2CWARNING%2CINFO&attrs_json=true"' in response.text