Refactor SX templates: shared components, Python migration, cleanup
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 6m0s

- Extract shared components (empty-state, delete-btn, sentinel, crud-*,
  view-toggle, img-or-placeholder, avatar, sumup-settings-form, auth
  forms, order tables/detail/checkout)
- Migrate all Python sx_call() callers to use shared components directly
- Remove 55+ thin wrapper defcomps from domain .sx files
- Remove trivial passthrough wrappers (blog-header-label, market-card-text, etc)
- Unify duplicate auth flows (account + federation) into shared/sx/templates/auth.sx
- Unify duplicate order views (cart + orders) into shared/sx/templates/orders.sx
- Disable static file caching in dev (SEND_FILE_MAX_AGE_DEFAULT=0)
- Add SX response validation and debug headers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 20:34:34 +00:00
parent 755313bd29
commit c0d369eb8e
58 changed files with 3473 additions and 1210 deletions

View File

@@ -127,7 +127,7 @@ def post_header_sx(ctx: dict, *, oob: bool = False) -> str:
if has_admin and slug:
from quart import request
admin_href = call_url(ctx, "blog_url", f"/{slug}/admin/")
is_admin_page = "/admin" in request.path
is_admin_page = ctx.get("is_admin_section") or "/admin" in request.path
sel_cls = "!bg-stone-500 !text-white" if is_admin_page else ""
base_cls = ("justify-center cursor-pointer flex flex-row"
" items-center gap-2 rounded bg-stone-200 text-black p-3")
@@ -223,7 +223,7 @@ def oob_header_sx(parent_id: str, child_id: str, row_sx: str) -> str:
def header_child_sx(inner_sx: str, *, id: str = "root-header-child") -> str:
"""Wrap inner sx in a header-child div."""
return sx_call("header-child-sx",
id=id, inner=SxExpr(inner_sx),
id=id, inner=SxExpr(f"(<> {inner_sx})"),
)
@@ -231,7 +231,7 @@ def oob_page_sx(*, oobs: str = "", filter: str = "", aside: str = "",
content: str = "", menu: str = "") -> str:
"""Build OOB response as sx call string."""
return sx_call("oob-sx",
oobs=SxExpr(oobs) if oobs else None,
oobs=SxExpr(f"(<> {oobs})") if oobs else None,
filter=SxExpr(filter) if filter else None,
aside=SxExpr(aside) if aside else None,
menu=SxExpr(menu) if menu else None,
@@ -249,7 +249,7 @@ def full_page_sx(ctx: dict, *, header_rows: str,
meta: sx source for meta tags — auto-hoisted to <head> by sx.js.
"""
body_sx = sx_call("app-body",
header_rows=SxExpr(header_rows) if header_rows else None,
header_rows=SxExpr(f"(<> {header_rows})") if header_rows else None,
filter=SxExpr(filter) if filter else None,
aside=SxExpr(aside) if aside else None,
menu=SxExpr(menu) if menu else None,
@@ -345,6 +345,14 @@ def sx_response(source_or_component: str, status: int = 200,
source = source_or_component
body = source
# Validate the sx source parses as a single expression
try:
from .parser import parse as _parse_check
_parse_check(source)
except Exception as _e:
import logging
logging.getLogger("sx").error("sx_response parse error: %s\nSource (first 500): %s", _e, source[:500])
# For SX requests, prepend missing component definitions
if request.headers.get("SX-Request"):
comp_defs = components_for_request()
@@ -353,6 +361,9 @@ def sx_response(source_or_component: str, status: int = 200,
f'{comp_defs}</script>\n{body}')
resp = Response(body, status=status, content_type="text/sx")
resp.headers["X-SX-Body-Len"] = str(len(body))
resp.headers["X-SX-Source-Len"] = str(len(source))
resp.headers["X-SX-Has-Defs"] = "1" if "<script" in body else "0"
if headers:
for k, v in headers.items():
resp.headers[k] = v
@@ -379,7 +390,7 @@ _SX_PAGE_TEMPLATE = """\
<link rel="stylesheet" type="text/css" href="{asset_url}/styles/cards.css">
<link rel="stylesheet" type="text/css" href="{asset_url}/styles/blog-content.css">
<meta name="csrf-token" content="{csrf}">
<link rel="stylesheet" type="text/css" href="{asset_url}/styles/tw.css">
<script src="https://cdn.tailwindcss.com?plugins=typography"></script>
<link rel="stylesheet" href="{asset_url}/fontawesome/css/all.min.css">
<link rel="stylesheet" href="{asset_url}/fontawesome/css/v4-shims.min.css">
<link href="https://unpkg.com/prismjs/themes/prism.css" rel="stylesheet">