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

278
blog/sxc/pages/__init__.py Normal file
View File

@@ -0,0 +1,278 @@
"""Blog defpage setup — registers layouts, page helpers, and loads .sx pages."""
from __future__ import annotations
from typing import Any
def setup_blog_pages() -> None:
"""Register blog-specific layouts, page helpers, and load page definitions."""
_register_blog_layouts()
_register_blog_helpers()
_load_blog_page_files()
def _load_blog_page_files() -> None:
import os
from shared.sx.pages import load_page_dir
load_page_dir(os.path.dirname(__file__), "blog")
# ---------------------------------------------------------------------------
# Layouts
# ---------------------------------------------------------------------------
def _register_blog_layouts() -> None:
from shared.sx.layouts import register_custom_layout
# :blog — root + blog header (for new-post, new-page)
register_custom_layout("blog", _blog_full, _blog_oob)
# :blog-settings — root + settings header (with settings nav menu)
register_custom_layout("blog-settings", _settings_full, _settings_oob,
mobile_fn=_settings_mobile)
# Sub-settings layouts (root + settings + sub header)
register_custom_layout("blog-cache", _cache_full, _cache_oob)
register_custom_layout("blog-snippets", _snippets_full, _snippets_oob)
register_custom_layout("blog-menu-items", _menu_items_full, _menu_items_oob)
register_custom_layout("blog-tag-groups", _tag_groups_full, _tag_groups_oob)
register_custom_layout("blog-tag-group-edit",
_tag_group_edit_full, _tag_group_edit_oob)
# --- Blog layout (root + blog header) ---
def _blog_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import root_header_sx
from sx.sx_components import _blog_header_sx
root_hdr = root_header_sx(ctx)
blog_hdr = _blog_header_sx(ctx)
return "(<> " + root_hdr + " " + blog_hdr + ")"
def _blog_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import root_header_sx, oob_header_sx
from sx.sx_components import _blog_header_sx
root_hdr = root_header_sx(ctx)
blog_hdr = _blog_header_sx(ctx)
rows = "(<> " + root_hdr + " " + blog_hdr + ")"
return oob_header_sx("root-header-child", "blog-header-child", rows)
# --- Settings layout (root + settings header) ---
def _settings_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import root_header_sx
from sx.sx_components import _settings_header_sx
root_hdr = root_header_sx(ctx)
settings_hdr = _settings_header_sx(ctx)
return "(<> " + root_hdr + " " + settings_hdr + ")"
def _settings_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import root_header_sx, oob_header_sx
from sx.sx_components import _settings_header_sx
root_hdr = root_header_sx(ctx)
settings_hdr = _settings_header_sx(ctx)
rows = "(<> " + root_hdr + " " + settings_hdr + ")"
return oob_header_sx("root-header-child", "root-settings-header-child", rows)
def _settings_mobile(ctx: dict, **kw: Any) -> str:
from sx.sx_components import _settings_nav_sx
return _settings_nav_sx(ctx)
# --- Sub-settings helpers ---
def _sub_settings_full(ctx: dict, row_id: str, child_id: str,
endpoint: str, icon: str, label: str) -> str:
from shared.sx.helpers import root_header_sx
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
from quart import url_for as qurl
root_hdr = root_header_sx(ctx)
settings_hdr = _settings_header_sx(ctx)
sub_hdr = _sub_settings_header_sx(row_id, child_id,
qurl(endpoint), icon, label, ctx)
return "(<> " + root_hdr + " " + settings_hdr + " " + sub_hdr + ")"
def _sub_settings_oob(ctx: dict, row_id: str, child_id: str,
endpoint: str, icon: str, label: str) -> str:
from shared.sx.helpers import oob_header_sx
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
from quart import url_for as qurl
settings_hdr_oob = _settings_header_sx(ctx, oob=True)
sub_hdr = _sub_settings_header_sx(row_id, child_id,
qurl(endpoint), icon, label, ctx)
sub_oob = oob_header_sx("root-settings-header-child", child_id, sub_hdr)
return "(<> " + settings_hdr_oob + " " + sub_oob + ")"
# --- Cache ---
def _cache_full(ctx: dict, **kw: Any) -> str:
return _sub_settings_full(ctx, "cache-row", "cache-header-child",
"settings.defpage_cache_page", "refresh", "Cache")
def _cache_oob(ctx: dict, **kw: Any) -> str:
return _sub_settings_oob(ctx, "cache-row", "cache-header-child",
"settings.defpage_cache_page", "refresh", "Cache")
# --- Snippets ---
def _snippets_full(ctx: dict, **kw: Any) -> str:
return _sub_settings_full(ctx, "snippets-row", "snippets-header-child",
"snippets.defpage_snippets_page", "puzzle-piece", "Snippets")
def _snippets_oob(ctx: dict, **kw: Any) -> str:
return _sub_settings_oob(ctx, "snippets-row", "snippets-header-child",
"snippets.defpage_snippets_page", "puzzle-piece", "Snippets")
# --- Menu Items ---
def _menu_items_full(ctx: dict, **kw: Any) -> str:
return _sub_settings_full(ctx, "menu_items-row", "menu_items-header-child",
"menu_items.defpage_menu_items_page", "bars", "Menu Items")
def _menu_items_oob(ctx: dict, **kw: Any) -> str:
return _sub_settings_oob(ctx, "menu_items-row", "menu_items-header-child",
"menu_items.defpage_menu_items_page", "bars", "Menu Items")
# --- Tag Groups ---
def _tag_groups_full(ctx: dict, **kw: Any) -> str:
return _sub_settings_full(ctx, "tag-groups-row", "tag-groups-header-child",
"blog.tag_groups_admin.defpage_tag_groups_page", "tags", "Tag Groups")
def _tag_groups_oob(ctx: dict, **kw: Any) -> str:
return _sub_settings_oob(ctx, "tag-groups-row", "tag-groups-header-child",
"blog.tag_groups_admin.defpage_tag_groups_page", "tags", "Tag Groups")
# --- Tag Group Edit ---
def _tag_group_edit_full(ctx: dict, **kw: Any) -> str:
from quart import request
g_id = (request.view_args or {}).get("id")
from quart import url_for as qurl
from shared.sx.helpers import root_header_sx
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
root_hdr = root_header_sx(ctx)
settings_hdr = _settings_header_sx(ctx)
sub_hdr = _sub_settings_header_sx("tag-groups-row", "tag-groups-header-child",
qurl("blog.tag_groups_admin.defpage_tag_group_edit", id=g_id),
"tags", "Tag Groups", ctx)
return "(<> " + root_hdr + " " + settings_hdr + " " + sub_hdr + ")"
def _tag_group_edit_oob(ctx: dict, **kw: Any) -> str:
from quart import request
g_id = (request.view_args or {}).get("id")
from quart import url_for as qurl
from shared.sx.helpers import oob_header_sx
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
settings_hdr_oob = _settings_header_sx(ctx, oob=True)
sub_hdr = _sub_settings_header_sx("tag-groups-row", "tag-groups-header-child",
qurl("blog.tag_groups_admin.defpage_tag_group_edit", id=g_id),
"tags", "Tag Groups", ctx)
sub_oob = oob_header_sx("root-settings-header-child", "tag-groups-header-child", sub_hdr)
return "(<> " + settings_hdr_oob + " " + sub_oob + ")"
# ---------------------------------------------------------------------------
# Page helpers (sync functions available in .sx defpage expressions)
# ---------------------------------------------------------------------------
def _register_blog_helpers() -> None:
from shared.sx.pages import register_page_helpers
register_page_helpers("blog", {
"editor-content": _h_editor_content,
"editor-page-content": _h_editor_page_content,
"post-admin-content": _h_post_admin_content,
"post-data-content": _h_post_data_content,
"post-preview-content": _h_post_preview_content,
"post-entries-content": _h_post_entries_content,
"post-settings-content": _h_post_settings_content,
"post-edit-content": _h_post_edit_content,
"settings-content": _h_settings_content,
"cache-content": _h_cache_content,
"snippets-content": _h_snippets_content,
"menu-items-content": _h_menu_items_content,
"tag-groups-content": _h_tag_groups_content,
"tag-group-edit-content": _h_tag_group_edit_content,
})
def _h_editor_content():
from quart import g
return getattr(g, "editor_content", "")
def _h_editor_page_content():
from quart import g
return getattr(g, "editor_page_content", "")
def _h_post_admin_content():
from quart import g
return getattr(g, "post_admin_content", "")
def _h_post_data_content():
from quart import g
return getattr(g, "post_data_content", "")
def _h_post_preview_content():
from quart import g
return getattr(g, "post_preview_content", "")
def _h_post_entries_content():
from quart import g
return getattr(g, "post_entries_content", "")
def _h_post_settings_content():
from quart import g
return getattr(g, "post_settings_content", "")
def _h_post_edit_content():
from quart import g
return getattr(g, "post_edit_content", "")
def _h_settings_content():
from quart import g
return getattr(g, "settings_content", "")
def _h_cache_content():
from quart import g
return getattr(g, "cache_content", "")
def _h_snippets_content():
from quart import g
return getattr(g, "snippets_content", "")
def _h_menu_items_content():
from quart import g
return getattr(g, "menu_items_content", "")
def _h_tag_groups_content():
from quart import g
return getattr(g, "tag_groups_content", "")
def _h_tag_group_edit_content():
from quart import g
return getattr(g, "tag_group_edit_content", "")

98
blog/sxc/pages/blog.sx Normal file
View File

@@ -0,0 +1,98 @@
; Blog app defpage declarations
; Pages kept as Python: home, index, post-detail (cache_page / complex branching)
; --- New post/page editors ---
(defpage new-post
:path "/new/"
:auth :admin
:layout :blog
:content (editor-content))
(defpage new-page
:path "/new-page/"
:auth :admin
:layout :blog
:content (editor-page-content))
; --- Post admin pages (nested under /<slug>/admin/) ---
(defpage post-admin
:path "/"
:auth :admin
:layout (:post-admin :selected "admin")
:content (post-admin-content))
(defpage post-data
:path "/data/"
:auth :admin
:layout (:post-admin :selected "data")
:content (post-data-content))
(defpage post-preview
:path "/preview/"
:auth :admin
:layout (:post-admin :selected "preview")
:content (post-preview-content))
(defpage post-entries
:path "/entries/"
:auth :admin
:layout (:post-admin :selected "entries")
:content (post-entries-content))
(defpage post-settings
:path "/settings/"
:auth :post_author
:layout (:post-admin :selected "settings")
:content (post-settings-content))
(defpage post-edit
:path "/edit/"
:auth :post_author
:layout (:post-admin :selected "edit")
:content (post-edit-content))
; --- Settings pages ---
(defpage settings-home
:path "/"
:auth :admin
:layout :blog-settings
:content (settings-content))
(defpage cache-page
:path "/cache/"
:auth :admin
:layout :blog-cache
:content (cache-content))
; --- Snippets ---
(defpage snippets-page
:path "/"
:auth :login
:layout :blog-snippets
:content (snippets-content))
; --- Menu Items ---
(defpage menu-items-page
:path "/"
:auth :admin
:layout :blog-menu-items
:content (menu-items-content))
; --- Tag Groups ---
(defpage tag-groups-page
:path "/"
:auth :admin
:layout :blog-tag-groups
:content (tag-groups-content))
(defpage tag-group-edit
:path "/<int:id>/"
:auth :admin
:layout :blog-tag-group-edit
:content (tag-group-edit-content))