Migrate all apps to defpage declarative page routes
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m41s

Replace Python GET page handlers with declarative defpage definitions in .sx
files across all 8 apps (sx docs, orders, account, market, cart, federation,
events, blog). Each app now has sxc/pages/ with setup functions, layout
registrations, page helpers, and .sx defpage declarations.

Core infrastructure: add g I/O primitive, PageDef support for auth/layout/
data/content/filter/aside/menu slots, post_author auth level, and custom
layout registration. Remove ~1400 lines of render_*_page/render_*_oob
boilerplate. Update all endpoint references in routes, sx_components, and
templates to defpage_* naming.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-03 14:52:34 +00:00
parent 5b4cacaf19
commit c243d17eeb
108 changed files with 3598 additions and 2851 deletions

View File

@@ -111,7 +111,7 @@ def _market_header_sx(ctx: dict, *, oob: bool = False) -> str:
sub_div=SxExpr(sub_div) if sub_div else None,
)
link_href = url_for("market.browse.home")
link_href = url_for("market.browse.defpage_market_home")
# Build desktop nav from categories
categories = ctx.get("categories", {})
@@ -159,7 +159,7 @@ def _desktop_category_nav_sx(ctx: dict, categories: dict, qs: str,
admin_sx = ""
if rights and rights.get("admin"):
admin_href = prefix + url_for("market.admin.admin")
admin_href = prefix + url_for("market.admin.defpage_market_admin")
admin_sx = sx_call("market-admin-link", href=admin_href, hx_select=hx_select)
return sx_call("market-desktop-category-nav",
@@ -1203,46 +1203,6 @@ def _no_markets_sx(message: str = "No markets available") -> str:
cls="px-3 py-12 text-center text-stone-400")
async def render_all_markets_page(ctx: dict, markets: list, has_more: bool,
page_info: dict, page: int) -> str:
"""Full page: all markets listing."""
from quart import url_for
from shared.utils import route_prefix
prefix = route_prefix()
next_url = prefix + url_for("all_markets.markets_fragment", page=page + 1)
if markets:
cards = _market_cards_sx(markets, page_info, page, has_more, next_url)
content = _markets_grid(cards)
else:
content = _no_markets_sx()
content = "(<> " + content + " " + '(div :class "pb-8")' + ")"
hdr = root_header_sx(ctx)
return full_page_sx(ctx, header_rows=hdr, content=content)
async def render_all_markets_oob(ctx: dict, markets: list, has_more: bool,
page_info: dict, page: int) -> str:
"""OOB response: all markets listing."""
from quart import url_for
from shared.utils import route_prefix
prefix = route_prefix()
next_url = prefix + url_for("all_markets.markets_fragment", page=page + 1)
if markets:
cards = _market_cards_sx(markets, page_info, page, has_more, next_url)
content = _markets_grid(cards)
else:
content = _no_markets_sx()
content = "(<> " + content + " " + '(div :class "pb-8")' + ")"
oobs = root_header_sx(ctx, oob=True)
return oob_page_sx(oobs=oobs, content=content)
async def render_all_markets_cards(markets: list, has_more: bool,
page_info: dict, page: int) -> str:
"""Pagination fragment: all markets cards."""
@@ -1258,54 +1218,6 @@ async def render_all_markets_cards(markets: list, has_more: bool,
# Page markets
# ---------------------------------------------------------------------------
async def render_page_markets_page(ctx: dict, markets: list, has_more: bool,
page: int) -> str:
"""Full page: page-scoped markets listing."""
from quart import url_for
from shared.utils import route_prefix
prefix = route_prefix()
post = ctx.get("post", {})
post_slug = post.get("slug", "")
next_url = prefix + url_for("page_markets.markets_fragment", page=page + 1)
if markets:
cards = _market_cards_sx(markets, {}, page, has_more, next_url,
show_page_badge=False, post_slug=post_slug)
content = _markets_grid(cards)
else:
content = _no_markets_sx("No markets for this page")
content = "(<> " + content + " " + '(div :class "pb-8")' + ")"
hdr = root_header_sx(ctx)
hdr = "(<> " + hdr + " " + header_child_sx(_post_header_sx(ctx)) + ")"
return full_page_sx(ctx, header_rows=hdr, content=content)
async def render_page_markets_oob(ctx: dict, markets: list, has_more: bool,
page: int) -> str:
"""OOB response: page-scoped markets."""
from quart import url_for
from shared.utils import route_prefix
prefix = route_prefix()
post = ctx.get("post", {})
post_slug = post.get("slug", "")
next_url = prefix + url_for("page_markets.markets_fragment", page=page + 1)
if markets:
cards = _market_cards_sx(markets, {}, page, has_more, next_url,
show_page_badge=False, post_slug=post_slug)
content = _markets_grid(cards)
else:
content = _no_markets_sx("No markets for this page")
content = "(<> " + content + " " + '(div :class "pb-8")' + ")"
oobs = _oob_header_sx("post-header-child", "market-header-child", "")
oobs = "(<> " + oobs + " " + _post_header_sx(ctx, oob=True) + ")"
return oob_page_sx(oobs=oobs, content=content)
async def render_page_markets_cards(markets: list, has_more: bool,
page: int, post_slug: str) -> str:
"""Pagination fragment: page-scoped markets cards."""
@@ -1322,31 +1234,6 @@ async def render_page_markets_cards(markets: list, has_more: bool,
# Market landing page
# ---------------------------------------------------------------------------
async def render_market_home_page(ctx: dict) -> str:
"""Full page: market landing page (post content)."""
post = ctx.get("post") or {}
content = _market_landing_content_sx(post)
hdr = root_header_sx(ctx)
child = "(<> " + _post_header_sx(ctx) + " " + _market_header_sx(ctx) + ")"
hdr = "(<> " + hdr + " " + header_child_sx(child) + ")"
menu = _mobile_nav_panel_sx(ctx)
return full_page_sx(ctx, header_rows=hdr, content=content, menu=menu)
async def render_market_home_oob(ctx: dict) -> str:
"""OOB response: market landing page."""
post = ctx.get("post") or {}
content = _market_landing_content_sx(post)
oobs = _oob_header_sx("post-header-child", "market-header-child",
_market_header_sx(ctx))
oobs = "(<> " + oobs + " " + _post_header_sx(ctx, oob=True) + " "
oobs += _clear_deeper_oob("post-row", "post-header-child",
"market-row", "market-header-child") + ")"
menu = _mobile_nav_panel_sx(ctx)
return oob_page_sx(oobs=oobs, content=content, menu=menu)
def _market_landing_content_sx(post: dict) -> str:
"""Build market landing page content as sx."""
@@ -1485,29 +1372,6 @@ def _product_admin_header_sx(ctx: dict, d: dict, *, oob: bool = False) -> str:
# Market admin
# ---------------------------------------------------------------------------
async def render_market_admin_page(ctx: dict) -> str:
"""Full page: market admin."""
content = '"market admin"'
hdr = root_header_sx(ctx)
child = "(<> " + _post_header_sx(ctx) + " " + _market_header_sx(ctx) + " "
child += _market_admin_header_sx(ctx, selected="markets") + ")"
hdr = "(<> " + hdr + " " + header_child_sx(child) + ")"
return full_page_sx(ctx, header_rows=hdr, content=content)
async def render_market_admin_oob(ctx: dict) -> str:
"""OOB response: market admin."""
content = '"market admin"'
oobs = "(<> " + _market_header_sx(ctx, oob=True) + " "
oobs += _oob_header_sx("market-header-child", "market-admin-header-child",
_market_admin_header_sx(ctx, selected="markets")) + " "
oobs += _clear_deeper_oob("post-row", "post-header-child",
"market-row", "market-header-child",
"market-admin-row", "market-admin-header-child") + ")"
return oob_page_sx(oobs=oobs, content=content)
def _market_admin_header_sx(ctx: dict, *, oob: bool = False, selected: str = "") -> str:
"""Build market admin header row — delegates to shared helper."""
@@ -1586,28 +1450,6 @@ async def render_markets_admin_list_panel(ctx: dict) -> str:
return await _markets_admin_panel_sx(ctx)
async def render_page_admin_page(ctx: dict) -> str:
"""Full page: page-level market admin."""
slug = (ctx.get("post") or {}).get("slug", "")
admin_hdr = post_admin_header_sx(ctx, slug, selected="markets")
hdr = root_header_sx(ctx)
child = "(<> " + _post_header_sx(ctx) + " " + admin_hdr + ")"
hdr = "(<> " + hdr + " " + header_child_sx(child) + ")"
content = await _markets_admin_panel_sx(ctx)
content = '(div :id "main-panel" ' + content + ')'
return full_page_sx(ctx, header_rows=hdr, content=content)
async def render_page_admin_oob(ctx: dict) -> str:
"""OOB response: page-level market admin."""
slug = (ctx.get("post") or {}).get("slug", "")
oobs = "(<> " + post_admin_header_sx(ctx, slug, oob=True, selected="markets") + " "
oobs += _clear_deeper_oob("post-row", "post-header-child",
"post-admin-row", "post-admin-header-child") + ")"
content = await _markets_admin_panel_sx(ctx)
content = '(div :id "main-panel" ' + content + ')'
return oob_page_sx(oobs=oobs, content=content)
# ---------------------------------------------------------------------------
# Public API: POST handler fragment renderers