Add s-expression wire format support and test detail view
- HTMX beforeSwap hook intercepts text/sexp responses and renders them client-side via sexp.js before HTMX swaps the result in - sexp_response() helper for returning text/sexp from route handlers - Test detail page (/test/<nodeid>) with clickable test names - HTMX navigation to detail returns sexp wire format (4x smaller than pre-rendered HTML), full page loads render server-side - ~test-detail component with back link, outcome badge, and error traceback display Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ from __future__ import annotations
|
||||
from typing import Any
|
||||
|
||||
from markupsafe import escape
|
||||
from quart import Response
|
||||
|
||||
from .jinja_bridge import render
|
||||
from .page import SEARCH_HEADERS_MOBILE, SEARCH_HEADERS_DESKTOP
|
||||
@@ -225,6 +226,24 @@ def full_page(ctx: dict, *, header_rows_html: str,
|
||||
)
|
||||
|
||||
|
||||
def sexp_response(sexp_source: str, status: int = 200,
|
||||
headers: dict | None = None) -> Response:
|
||||
"""Return an s-expression wire-format response.
|
||||
|
||||
The client-side sexp.js will intercept responses with Content-Type
|
||||
text/sexp and render them before HTMX swaps the result in.
|
||||
|
||||
Usage in a route handler::
|
||||
|
||||
return sexp_response('(~test-row :nodeid "test_foo" :outcome "passed")')
|
||||
"""
|
||||
resp = Response(sexp_source, status=status, content_type="text/sexp")
|
||||
if headers:
|
||||
for k, v in headers.items():
|
||||
resp.headers[k] = v
|
||||
return resp
|
||||
|
||||
|
||||
def oob_page(ctx: dict, *, oobs_html: str = "",
|
||||
filter_html: str = "", aside_html: str = "",
|
||||
content_html: str = "", menu_html: str = "") -> str:
|
||||
|
||||
@@ -1261,6 +1261,18 @@
|
||||
Sexp.processScripts(e.detail.target);
|
||||
Sexp.hydrate(e.detail.target);
|
||||
});
|
||||
|
||||
// S-expression wire format: intercept text/sexp responses and render to HTML
|
||||
// before HTMX swaps them in. Server sends Content-Type: text/sexp with
|
||||
// s-expression body; sexp.js renders to HTML string for HTMX to swap.
|
||||
document.addEventListener("htmx:beforeSwap", function (e) {
|
||||
var xhr = e.detail.xhr;
|
||||
var ct = xhr.getResponseHeader("Content-Type") || "";
|
||||
if (ct.indexOf("text/sexp") === -1) return;
|
||||
// Render s-expression response to HTML string
|
||||
var html = Sexp.renderToString(xhr.responseText);
|
||||
e.detail.serverResponse = html;
|
||||
});
|
||||
}
|
||||
|
||||
})(typeof window !== "undefined" ? window : this);
|
||||
|
||||
Reference in New Issue
Block a user