Replace sx_call() with render_to_sx() across all services
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m6s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m6s
Python no longer generates s-expression strings. All SX rendering now goes through render_to_sx() which builds AST from native Python values and evaluates via async_eval_to_sx() — no SX string literals in Python. - Add render_to_sx()/render_to_html() infrastructure in shared/sx/helpers.py - Add (abort status msg) IO primitive in shared/sx/primitives_io.py - Convert all 9 services: ~650 sx_call() invocations replaced - Convert shared helpers (root_header_sx, full_page_sx, etc.) to async - Fix likes service import bug (likes.models → models) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -56,6 +56,6 @@ def register(url_prefix="/"):
|
|||||||
await g.s.flush()
|
await g.s.flush()
|
||||||
|
|
||||||
from sx.sx_components import render_newsletter_toggle
|
from sx.sx_components import render_newsletter_toggle
|
||||||
return sx_response(render_newsletter_toggle(un))
|
return sx_response(await render_newsletter_toggle(un))
|
||||||
|
|
||||||
return account_bp
|
return account_bp
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from typing import Any
|
|||||||
|
|
||||||
from shared.sx.jinja_bridge import load_service_components
|
from shared.sx.jinja_bridge import load_service_components
|
||||||
from shared.sx.helpers import (
|
from shared.sx.helpers import (
|
||||||
sx_call, SxExpr,
|
render_to_sx,
|
||||||
root_header_sx, full_page_sx,
|
root_header_sx, full_page_sx,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,9 +28,10 @@ async def render_login_page(ctx: dict) -> str:
|
|||||||
"""Full page: login form."""
|
"""Full page: login form."""
|
||||||
error = ctx.get("error", "")
|
error = ctx.get("error", "")
|
||||||
email = ctx.get("email", "")
|
email = ctx.get("email", "")
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
content = sx_call("account-login-content", error=error or None, email=email)
|
content = await render_to_sx("account-login-content",
|
||||||
return full_page_sx(ctx, header_rows=hdr,
|
error=error or None, email=email)
|
||||||
|
return await full_page_sx(ctx, header_rows=hdr,
|
||||||
content=content,
|
content=content,
|
||||||
meta_html='<title>Login \u2014 Rose Ash</title>')
|
meta_html='<title>Login \u2014 Rose Ash</title>')
|
||||||
|
|
||||||
@@ -39,18 +40,19 @@ async def render_device_page(ctx: dict) -> str:
|
|||||||
"""Full page: device authorization form."""
|
"""Full page: device authorization form."""
|
||||||
error = ctx.get("error", "")
|
error = ctx.get("error", "")
|
||||||
code = ctx.get("code", "")
|
code = ctx.get("code", "")
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
content = sx_call("account-device-content", error=error or None, code=code)
|
content = await render_to_sx("account-device-content",
|
||||||
return full_page_sx(ctx, header_rows=hdr,
|
error=error or None, code=code)
|
||||||
|
return await full_page_sx(ctx, header_rows=hdr,
|
||||||
content=content,
|
content=content,
|
||||||
meta_html='<title>Authorize Device \u2014 Rose Ash</title>')
|
meta_html='<title>Authorize Device \u2014 Rose Ash</title>')
|
||||||
|
|
||||||
|
|
||||||
async def render_device_approved_page(ctx: dict) -> str:
|
async def render_device_approved_page(ctx: dict) -> str:
|
||||||
"""Full page: device approved."""
|
"""Full page: device approved."""
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
content = sx_call("account-device-approved")
|
content = await render_to_sx("account-device-approved")
|
||||||
return full_page_sx(ctx, header_rows=hdr,
|
return await full_page_sx(ctx, header_rows=hdr,
|
||||||
content=content,
|
content=content,
|
||||||
meta_html='<title>Device Authorized \u2014 Rose Ash</title>')
|
meta_html='<title>Device Authorized \u2014 Rose Ash</title>')
|
||||||
|
|
||||||
@@ -59,10 +61,10 @@ async def render_check_email_page(ctx: dict) -> str:
|
|||||||
"""Full page: check email after magic link sent."""
|
"""Full page: check email after magic link sent."""
|
||||||
email = ctx.get("email", "")
|
email = ctx.get("email", "")
|
||||||
email_error = ctx.get("email_error")
|
email_error = ctx.get("email_error")
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
content = sx_call("account-check-email-content",
|
content = await render_to_sx("account-check-email-content",
|
||||||
email=email, email_error=email_error)
|
email=email, email_error=email_error)
|
||||||
return full_page_sx(ctx, header_rows=hdr,
|
return await full_page_sx(ctx, header_rows=hdr,
|
||||||
content=content,
|
content=content,
|
||||||
meta_html='<title>Check your email \u2014 Rose Ash</title>')
|
meta_html='<title>Check your email \u2014 Rose Ash</title>')
|
||||||
|
|
||||||
@@ -71,7 +73,7 @@ async def render_check_email_page(ctx: dict) -> str:
|
|||||||
# Public API: Fragment renderers for POST handlers
|
# Public API: Fragment renderers for POST handlers
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def render_newsletter_toggle(un) -> str:
|
async def render_newsletter_toggle(un) -> str:
|
||||||
"""Render a newsletter toggle switch for POST response."""
|
"""Render a newsletter toggle switch for POST response."""
|
||||||
from shared.browser.app.csrf import generate_csrf_token
|
from shared.browser.app.csrf import generate_csrf_token
|
||||||
|
|
||||||
@@ -94,7 +96,7 @@ def render_newsletter_toggle(un) -> str:
|
|||||||
translate = "translate-x-1"
|
translate = "translate-x-1"
|
||||||
checked = "false"
|
checked = "false"
|
||||||
|
|
||||||
return sx_call(
|
return await render_to_sx(
|
||||||
"account-newsletter-toggle",
|
"account-newsletter-toggle",
|
||||||
id=f"nl-{nid}", url=toggle_url,
|
id=f"nl-{nid}", url=toggle_url,
|
||||||
hdrs=f'{{"X-CSRFToken": "{csrf}"}}',
|
hdrs=f'{{"X-CSRFToken": "{csrf}"}}',
|
||||||
@@ -103,27 +105,3 @@ def render_newsletter_toggle(un) -> str:
|
|||||||
checked=checked,
|
checked=checked,
|
||||||
knob_cls=f"inline-block h-4 w-4 rounded-full bg-white shadow transform transition-transform {translate}",
|
knob_cls=f"inline-block h-4 w-4 rounded-full bg-white shadow transform transition-transform {translate}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
# Internal helpers
|
|
||||||
# ---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def _fragment_content(frag: object) -> str:
|
|
||||||
"""Convert a fragment response to sx content string.
|
|
||||||
|
|
||||||
SxExpr (from text/sx responses) is embedded as-is; plain strings
|
|
||||||
(from text/html) are wrapped in ``~rich-text``.
|
|
||||||
"""
|
|
||||||
from shared.sx.parser import SxExpr
|
|
||||||
if isinstance(frag, SxExpr):
|
|
||||||
return frag.source
|
|
||||||
s = str(frag) if frag else ""
|
|
||||||
if not s:
|
|
||||||
return ""
|
|
||||||
return f'(~rich-text :html "{_sx_escape(s)}")'
|
|
||||||
|
|
||||||
|
|
||||||
def _sx_escape(s: str) -> str:
|
|
||||||
"""Escape a string for embedding in sx string literals."""
|
|
||||||
return s.replace("\\", "\\\\").replace('"', '\\"')
|
|
||||||
|
|||||||
@@ -26,43 +26,51 @@ def _register_account_layouts() -> None:
|
|||||||
register_custom_layout("account", _account_full, _account_oob, _account_mobile)
|
register_custom_layout("account", _account_full, _account_oob, _account_mobile)
|
||||||
|
|
||||||
|
|
||||||
def _account_full(ctx: dict, **kw: Any) -> str:
|
async def _account_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, header_child_sx, call_url, sx_call, SxExpr
|
from shared.sx.helpers import root_header_sx, header_child_sx, render_to_sx
|
||||||
|
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
auth_hdr = sx_call("auth-header-row",
|
auth_hdr = await render_to_sx("auth-header-row",
|
||||||
account_url=call_url(ctx, "account_url", ""),
|
account_url=_call_url(ctx, "account_url", ""),
|
||||||
select_colours=ctx.get("select_colours", ""),
|
select_colours=ctx.get("select_colours", ""),
|
||||||
account_nav=_as_sx_nav(ctx),
|
account_nav=_as_sx_nav(ctx),
|
||||||
)
|
)
|
||||||
hdr_child = header_child_sx(auth_hdr)
|
hdr_child = await header_child_sx(auth_hdr)
|
||||||
return "(<> " + root_hdr + " " + hdr_child + ")"
|
return "(<> " + root_hdr + " " + hdr_child + ")"
|
||||||
|
|
||||||
|
|
||||||
def _account_oob(ctx: dict, **kw: Any) -> str:
|
async def _account_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, call_url, sx_call
|
from shared.sx.helpers import root_header_sx, render_to_sx
|
||||||
|
|
||||||
auth_hdr = sx_call("auth-header-row",
|
auth_hdr = await render_to_sx("auth-header-row",
|
||||||
account_url=call_url(ctx, "account_url", ""),
|
account_url=_call_url(ctx, "account_url", ""),
|
||||||
select_colours=ctx.get("select_colours", ""),
|
select_colours=ctx.get("select_colours", ""),
|
||||||
account_nav=_as_sx_nav(ctx),
|
account_nav=_as_sx_nav(ctx),
|
||||||
oob=True,
|
oob=True,
|
||||||
)
|
)
|
||||||
return "(<> " + auth_hdr + " " + root_header_sx(ctx, oob=True) + ")"
|
return "(<> " + auth_hdr + " " + await root_header_sx(ctx, oob=True) + ")"
|
||||||
|
|
||||||
|
|
||||||
def _account_mobile(ctx: dict, **kw: Any) -> str:
|
async def _account_mobile(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import mobile_menu_sx, mobile_root_nav_sx, sx_call, SxExpr, call_url
|
from shared.sx.helpers import mobile_menu_sx, mobile_root_nav_sx, render_to_sx
|
||||||
|
from shared.sx.parser import SxExpr
|
||||||
ctx = _inject_account_nav(ctx)
|
ctx = _inject_account_nav(ctx)
|
||||||
nav_items = sx_call("auth-nav-items",
|
nav_items = await render_to_sx("auth-nav-items",
|
||||||
account_url=call_url(ctx, "account_url", ""),
|
account_url=_call_url(ctx, "account_url", ""),
|
||||||
select_colours=ctx.get("select_colours", ""),
|
select_colours=ctx.get("select_colours", ""),
|
||||||
account_nav=_as_sx_nav(ctx),
|
account_nav=_as_sx_nav(ctx),
|
||||||
)
|
)
|
||||||
auth_section = sx_call("mobile-menu-section",
|
auth_section = await render_to_sx("mobile-menu-section",
|
||||||
label="account", href="/", level=1, colour="sky",
|
label="account", href="/", level=1, colour="sky",
|
||||||
items=SxExpr(nav_items))
|
items=SxExpr(nav_items))
|
||||||
return mobile_menu_sx(auth_section, mobile_root_nav_sx(ctx))
|
return mobile_menu_sx(auth_section, await mobile_root_nav_sx(ctx))
|
||||||
|
|
||||||
|
|
||||||
|
def _call_url(ctx: dict, key: str, path: str = "/") -> str:
|
||||||
|
fn = ctx.get(key)
|
||||||
|
if callable(fn):
|
||||||
|
return fn(path)
|
||||||
|
return str(fn or "") + path
|
||||||
|
|
||||||
|
|
||||||
def _inject_account_nav(ctx: dict) -> dict:
|
def _inject_account_nav(ctx: dict) -> dict:
|
||||||
@@ -75,7 +83,7 @@ def _inject_account_nav(ctx: dict) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
def _as_sx_nav(ctx: dict) -> Any:
|
def _as_sx_nav(ctx: dict) -> Any:
|
||||||
"""Convert account_nav fragment to SxExpr for use in sx_call."""
|
"""Convert account_nav fragment to SxExpr for use in component calls."""
|
||||||
from shared.sx.helpers import _as_sx
|
from shared.sx.helpers import _as_sx
|
||||||
ctx = _inject_account_nav(ctx)
|
ctx = _inject_account_nav(ctx)
|
||||||
return _as_sx(ctx.get("account_nav"))
|
return _as_sx(ctx.get("account_nav"))
|
||||||
@@ -100,8 +108,7 @@ async def _h_newsletters_content(**kw):
|
|||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from shared.models import UserNewsletter
|
from shared.models import UserNewsletter
|
||||||
from shared.models.ghost_membership_entities import GhostNewsletter
|
from shared.models.ghost_membership_entities import GhostNewsletter
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
|
|
||||||
result = await g.s.execute(
|
result = await g.s.execute(
|
||||||
select(GhostNewsletter).order_by(GhostNewsletter.name)
|
select(GhostNewsletter).order_by(GhostNewsletter.name)
|
||||||
@@ -131,8 +138,8 @@ async def _h_newsletters_content(**kw):
|
|||||||
# Call account_url to get the base URL string
|
# Call account_url to get the base URL string
|
||||||
account_url_str = account_url("") if callable(account_url) else str(account_url or "")
|
account_url_str = account_url("") if callable(account_url) else str(account_url or "")
|
||||||
|
|
||||||
return sx_call("account-newsletters-content",
|
return await render_to_sx("account-newsletters-content",
|
||||||
newsletter_list=SxExpr(serialize(newsletter_list)),
|
newsletter_list=newsletter_list,
|
||||||
account_url=account_url_str)
|
account_url=account_url_str)
|
||||||
|
|
||||||
|
|
||||||
@@ -148,5 +155,11 @@ async def _h_fragment_content(slug=None, **kw):
|
|||||||
)
|
)
|
||||||
if not fragment_html:
|
if not fragment_html:
|
||||||
abort(404)
|
abort(404)
|
||||||
from sx.sx_components import _fragment_content
|
from shared.sx.parser import SxExpr
|
||||||
return _fragment_content(fragment_html)
|
if isinstance(fragment_html, SxExpr):
|
||||||
|
return fragment_html.source
|
||||||
|
s = str(fragment_html) if fragment_html else ""
|
||||||
|
if not s:
|
||||||
|
return ""
|
||||||
|
from shared.sx.helpers import render_to_sx
|
||||||
|
return await render_to_sx("rich-text", html=s)
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ def register(url_prefix, title):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import render_new_post_page, render_editor_panel
|
from sx.sx_components import render_new_post_page, render_editor_panel
|
||||||
tctx = await get_template_context()
|
tctx = await get_template_context()
|
||||||
tctx["editor_html"] = render_editor_panel(save_error="Invalid JSON in editor content.")
|
tctx["editor_html"] = await render_editor_panel(save_error="Invalid JSON in editor content.")
|
||||||
html = await render_new_post_page(tctx)
|
html = await render_new_post_page(tctx)
|
||||||
return await make_response(html, 400)
|
return await make_response(html, 400)
|
||||||
|
|
||||||
@@ -244,7 +244,7 @@ def register(url_prefix, title):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import render_new_post_page, render_editor_panel
|
from sx.sx_components import render_new_post_page, render_editor_panel
|
||||||
tctx = await get_template_context()
|
tctx = await get_template_context()
|
||||||
tctx["editor_html"] = render_editor_panel(save_error=reason)
|
tctx["editor_html"] = await render_editor_panel(save_error=reason)
|
||||||
html = await render_new_post_page(tctx)
|
html = await render_new_post_page(tctx)
|
||||||
return await make_response(html, 400)
|
return await make_response(html, 400)
|
||||||
|
|
||||||
@@ -291,7 +291,7 @@ def register(url_prefix, title):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import render_new_post_page, render_editor_panel
|
from sx.sx_components import render_new_post_page, render_editor_panel
|
||||||
tctx = await get_template_context()
|
tctx = await get_template_context()
|
||||||
tctx["editor_html"] = render_editor_panel(save_error="Invalid JSON in editor content.", is_page=True)
|
tctx["editor_html"] = await render_editor_panel(save_error="Invalid JSON in editor content.", is_page=True)
|
||||||
tctx["is_page"] = True
|
tctx["is_page"] = True
|
||||||
html = await render_new_post_page(tctx)
|
html = await render_new_post_page(tctx)
|
||||||
return await make_response(html, 400)
|
return await make_response(html, 400)
|
||||||
@@ -301,7 +301,7 @@ def register(url_prefix, title):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import render_new_post_page, render_editor_panel
|
from sx.sx_components import render_new_post_page, render_editor_panel
|
||||||
tctx = await get_template_context()
|
tctx = await get_template_context()
|
||||||
tctx["editor_html"] = render_editor_panel(save_error=reason, is_page=True)
|
tctx["editor_html"] = await render_editor_panel(save_error=reason, is_page=True)
|
||||||
tctx["is_page"] = True
|
tctx["is_page"] = True
|
||||||
html = await render_new_post_page(tctx)
|
html = await render_new_post_page(tctx)
|
||||||
return await make_response(html, 400)
|
return await make_response(html, 400)
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ from shared.sx.helpers import sx_response
|
|||||||
def register():
|
def register():
|
||||||
bp = Blueprint("menu_items", __name__, url_prefix='/settings/menu_items')
|
bp = Blueprint("menu_items", __name__, url_prefix='/settings/menu_items')
|
||||||
|
|
||||||
def get_menu_items_nav_oob_sync(menu_items):
|
async def get_menu_items_nav_oob_async(menu_items):
|
||||||
"""Helper to generate OOB update for root nav menu items"""
|
"""Helper to generate OOB update for root nav menu items"""
|
||||||
from sx.sx_components import render_menu_items_nav_oob
|
from sx.sx_components import render_menu_items_nav_oob
|
||||||
return render_menu_items_nav_oob(menu_items)
|
return await render_menu_items_nav_oob(menu_items)
|
||||||
|
|
||||||
@bp.get("/new/")
|
@bp.get("/new/")
|
||||||
@require_admin
|
@require_admin
|
||||||
@@ -51,8 +51,8 @@ def register():
|
|||||||
# Get updated list and nav OOB
|
# Get updated list and nav OOB
|
||||||
menu_items = await get_all_menu_items(g.s)
|
menu_items = await get_all_menu_items(g.s)
|
||||||
from sx.sx_components import render_menu_items_list
|
from sx.sx_components import render_menu_items_list
|
||||||
html = render_menu_items_list(menu_items)
|
html = await render_menu_items_list(menu_items)
|
||||||
nav_oob = get_menu_items_nav_oob_sync(menu_items)
|
nav_oob = await get_menu_items_nav_oob_async(menu_items)
|
||||||
return sx_response(html + nav_oob)
|
return sx_response(html + nav_oob)
|
||||||
|
|
||||||
except MenuItemError as e:
|
except MenuItemError as e:
|
||||||
@@ -91,8 +91,8 @@ def register():
|
|||||||
# Get updated list and nav OOB
|
# Get updated list and nav OOB
|
||||||
menu_items = await get_all_menu_items(g.s)
|
menu_items = await get_all_menu_items(g.s)
|
||||||
from sx.sx_components import render_menu_items_list
|
from sx.sx_components import render_menu_items_list
|
||||||
html = render_menu_items_list(menu_items)
|
html = await render_menu_items_list(menu_items)
|
||||||
nav_oob = get_menu_items_nav_oob_sync(menu_items)
|
nav_oob = await get_menu_items_nav_oob_async(menu_items)
|
||||||
return sx_response(html + nav_oob)
|
return sx_response(html + nav_oob)
|
||||||
|
|
||||||
except MenuItemError as e:
|
except MenuItemError as e:
|
||||||
@@ -112,8 +112,8 @@ def register():
|
|||||||
# Get updated list and nav OOB
|
# Get updated list and nav OOB
|
||||||
menu_items = await get_all_menu_items(g.s)
|
menu_items = await get_all_menu_items(g.s)
|
||||||
from sx.sx_components import render_menu_items_list
|
from sx.sx_components import render_menu_items_list
|
||||||
html = render_menu_items_list(menu_items)
|
html = await render_menu_items_list(menu_items)
|
||||||
nav_oob = get_menu_items_nav_oob_sync(menu_items)
|
nav_oob = await get_menu_items_nav_oob_async(menu_items)
|
||||||
return sx_response(html + nav_oob)
|
return sx_response(html + nav_oob)
|
||||||
|
|
||||||
@bp.get("/pages/search/")
|
@bp.get("/pages/search/")
|
||||||
@@ -128,7 +128,7 @@ def register():
|
|||||||
has_more = (page * per_page) < total
|
has_more = (page * per_page) < total
|
||||||
|
|
||||||
from sx.sx_components import render_page_search_results
|
from sx.sx_components import render_page_search_results
|
||||||
return sx_response(render_page_search_results(pages, query, page, has_more))
|
return sx_response(await render_page_search_results(pages, query, page, has_more))
|
||||||
|
|
||||||
@bp.post("/reorder/")
|
@bp.post("/reorder/")
|
||||||
@require_admin
|
@require_admin
|
||||||
@@ -153,8 +153,8 @@ def register():
|
|||||||
# Get updated list and nav OOB
|
# Get updated list and nav OOB
|
||||||
menu_items = await get_all_menu_items(g.s)
|
menu_items = await get_all_menu_items(g.s)
|
||||||
from sx.sx_components import render_menu_items_list
|
from sx.sx_components import render_menu_items_list
|
||||||
html = render_menu_items_list(menu_items)
|
html = await render_menu_items_list(menu_items)
|
||||||
nav_oob = get_menu_items_nav_oob_sync(menu_items)
|
nav_oob = await get_menu_items_nav_oob_async(menu_items)
|
||||||
return sx_response(html + nav_oob)
|
return sx_response(html + nav_oob)
|
||||||
|
|
||||||
return bp
|
return bp
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ def register():
|
|||||||
features = result.get("features", {})
|
features = result.get("features", {})
|
||||||
|
|
||||||
from sx.sx_components import render_features_panel
|
from sx.sx_components import render_features_panel
|
||||||
html = render_features_panel(
|
html = await render_features_panel(
|
||||||
features, post,
|
features, post,
|
||||||
sumup_configured=result.get("sumup_configured", False),
|
sumup_configured=result.get("sumup_configured", False),
|
||||||
sumup_merchant_code=result.get("sumup_merchant_code") or "",
|
sumup_merchant_code=result.get("sumup_merchant_code") or "",
|
||||||
@@ -129,7 +129,7 @@ def register():
|
|||||||
|
|
||||||
features = result.get("features", {})
|
features = result.get("features", {})
|
||||||
from sx.sx_components import render_features_panel
|
from sx.sx_components import render_features_panel
|
||||||
html = render_features_panel(
|
html = await render_features_panel(
|
||||||
features, post,
|
features, post,
|
||||||
sumup_configured=result.get("sumup_configured", False),
|
sumup_configured=result.get("sumup_configured", False),
|
||||||
sumup_merchant_code=result.get("sumup_merchant_code") or "",
|
sumup_merchant_code=result.get("sumup_merchant_code") or "",
|
||||||
@@ -259,8 +259,8 @@ def register():
|
|||||||
from sx.sx_components import render_associated_entries, render_nav_entries_oob
|
from sx.sx_components import render_associated_entries, render_nav_entries_oob
|
||||||
|
|
||||||
post = g.post_data["post"]
|
post = g.post_data["post"]
|
||||||
admin_list = render_associated_entries(all_calendars, associated_entry_ids, post["slug"])
|
admin_list = await render_associated_entries(all_calendars, associated_entry_ids, post["slug"])
|
||||||
nav_entries_html = render_nav_entries_oob(associated_entries, calendars, post)
|
nav_entries_html = await render_nav_entries_oob(associated_entries, calendars, post)
|
||||||
|
|
||||||
return sx_response(admin_list + nav_entries_html)
|
return sx_response(admin_list + nav_entries_html)
|
||||||
|
|
||||||
@@ -436,7 +436,7 @@ def register():
|
|||||||
page_markets = await _fetch_page_markets(post_id)
|
page_markets = await _fetch_page_markets(post_id)
|
||||||
|
|
||||||
from sx.sx_components import render_markets_panel
|
from sx.sx_components import render_markets_panel
|
||||||
return sx_response(render_markets_panel(page_markets, post))
|
return sx_response(await render_markets_panel(page_markets, post))
|
||||||
|
|
||||||
@bp.post("/markets/new/")
|
@bp.post("/markets/new/")
|
||||||
@require_admin
|
@require_admin
|
||||||
@@ -462,7 +462,7 @@ def register():
|
|||||||
page_markets = await _fetch_page_markets(post_id)
|
page_markets = await _fetch_page_markets(post_id)
|
||||||
|
|
||||||
from sx.sx_components import render_markets_panel
|
from sx.sx_components import render_markets_panel
|
||||||
return sx_response(render_markets_panel(page_markets, post))
|
return sx_response(await render_markets_panel(page_markets, post))
|
||||||
|
|
||||||
@bp.delete("/markets/<market_slug>/")
|
@bp.delete("/markets/<market_slug>/")
|
||||||
@require_admin
|
@require_admin
|
||||||
@@ -482,6 +482,6 @@ def register():
|
|||||||
page_markets = await _fetch_page_markets(post_id)
|
page_markets = await _fetch_page_markets(post_id)
|
||||||
|
|
||||||
from sx.sx_components import render_markets_panel
|
from sx.sx_components import render_markets_panel
|
||||||
return sx_response(render_markets_panel(page_markets, post))
|
return sx_response(await render_markets_panel(page_markets, post))
|
||||||
|
|
||||||
return bp
|
return bp
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ def register():
|
|||||||
|
|
||||||
# Get post_id from g.post_data
|
# Get post_id from g.post_data
|
||||||
if not g.user:
|
if not g.user:
|
||||||
return sx_response(render_like_toggle_button(slug, False, like_url), status=403)
|
return sx_response(await render_like_toggle_button(slug, False, like_url), status=403)
|
||||||
|
|
||||||
post_id = g.post_data["post"]["id"]
|
post_id = g.post_data["post"]["id"]
|
||||||
user_id = g.user.id
|
user_id = g.user.id
|
||||||
@@ -135,7 +135,7 @@ def register():
|
|||||||
})
|
})
|
||||||
liked = result["liked"]
|
liked = result["liked"]
|
||||||
|
|
||||||
return sx_response(render_like_toggle_button(slug, liked, like_url))
|
return sx_response(await render_like_toggle_button(slug, liked, like_url))
|
||||||
|
|
||||||
@bp.get("/w/<widget_domain>/")
|
@bp.get("/w/<widget_domain>/")
|
||||||
async def widget_paginate(slug: str, widget_domain: str):
|
async def widget_paginate(slug: str, widget_domain: str):
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ def register():
|
|||||||
|
|
||||||
snippets = await _visible_snippets(g.s)
|
snippets = await _visible_snippets(g.s)
|
||||||
from sx.sx_components import render_snippets_list
|
from sx.sx_components import render_snippets_list
|
||||||
return sx_response(render_snippets_list(snippets, is_admin))
|
return sx_response(await render_snippets_list(snippets, is_admin))
|
||||||
|
|
||||||
@bp.patch("/<int:snippet_id>/visibility/")
|
@bp.patch("/<int:snippet_id>/visibility/")
|
||||||
@require_login
|
@require_login
|
||||||
@@ -71,6 +71,6 @@ def register():
|
|||||||
|
|
||||||
snippets = await _visible_snippets(g.s)
|
snippets = await _visible_snippets(g.s)
|
||||||
from sx.sx_components import render_snippets_list
|
from sx.sx_components import render_snippets_list
|
||||||
return sx_response(render_snippets_list(snippets, True))
|
return sx_response(await render_snippets_list(snippets, True))
|
||||||
|
|
||||||
return bp
|
return bp
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -129,148 +129,148 @@ def _register_blog_layouts() -> None:
|
|||||||
|
|
||||||
# --- Blog layout (root + blog header) ---
|
# --- Blog layout (root + blog header) ---
|
||||||
|
|
||||||
def _blog_full(ctx: dict, **kw: Any) -> str:
|
async def _blog_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx
|
from shared.sx.helpers import root_header_sx
|
||||||
from sx.sx_components import _blog_header_sx
|
from sx.sx_components import _blog_header_sx
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
blog_hdr = _blog_header_sx(ctx)
|
blog_hdr = await _blog_header_sx(ctx)
|
||||||
return "(<> " + root_hdr + " " + blog_hdr + ")"
|
return "(<> " + root_hdr + " " + blog_hdr + ")"
|
||||||
|
|
||||||
|
|
||||||
def _blog_oob(ctx: dict, **kw: Any) -> str:
|
async def _blog_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, oob_header_sx
|
from shared.sx.helpers import root_header_sx, oob_header_sx
|
||||||
from sx.sx_components import _blog_header_sx
|
from sx.sx_components import _blog_header_sx
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
blog_hdr = _blog_header_sx(ctx)
|
blog_hdr = await _blog_header_sx(ctx)
|
||||||
rows = "(<> " + root_hdr + " " + blog_hdr + ")"
|
rows = "(<> " + root_hdr + " " + blog_hdr + ")"
|
||||||
return oob_header_sx("root-header-child", "blog-header-child", rows)
|
return await oob_header_sx("root-header-child", "blog-header-child", rows)
|
||||||
|
|
||||||
|
|
||||||
# --- Settings layout (root + settings header) ---
|
# --- Settings layout (root + settings header) ---
|
||||||
|
|
||||||
def _settings_full(ctx: dict, **kw: Any) -> str:
|
async def _settings_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx
|
from shared.sx.helpers import root_header_sx
|
||||||
from sx.sx_components import _settings_header_sx
|
from sx.sx_components import _settings_header_sx
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
settings_hdr = _settings_header_sx(ctx)
|
settings_hdr = await _settings_header_sx(ctx)
|
||||||
return "(<> " + root_hdr + " " + settings_hdr + ")"
|
return "(<> " + root_hdr + " " + settings_hdr + ")"
|
||||||
|
|
||||||
|
|
||||||
def _settings_oob(ctx: dict, **kw: Any) -> str:
|
async def _settings_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, oob_header_sx
|
from shared.sx.helpers import root_header_sx, oob_header_sx
|
||||||
from sx.sx_components import _settings_header_sx
|
from sx.sx_components import _settings_header_sx
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
settings_hdr = _settings_header_sx(ctx)
|
settings_hdr = await _settings_header_sx(ctx)
|
||||||
rows = "(<> " + root_hdr + " " + settings_hdr + ")"
|
rows = "(<> " + root_hdr + " " + settings_hdr + ")"
|
||||||
return oob_header_sx("root-header-child", "root-settings-header-child", rows)
|
return await oob_header_sx("root-header-child", "root-settings-header-child", rows)
|
||||||
|
|
||||||
|
|
||||||
def _settings_mobile(ctx: dict, **kw: Any) -> str:
|
async def _settings_mobile(ctx: dict, **kw: Any) -> str:
|
||||||
from sx.sx_components import _settings_nav_sx
|
from sx.sx_components import _settings_nav_sx
|
||||||
return _settings_nav_sx(ctx)
|
return await _settings_nav_sx(ctx)
|
||||||
|
|
||||||
|
|
||||||
# --- Sub-settings helpers ---
|
# --- Sub-settings helpers ---
|
||||||
|
|
||||||
def _sub_settings_full(ctx: dict, row_id: str, child_id: str,
|
async def _sub_settings_full(ctx: dict, row_id: str, child_id: str,
|
||||||
endpoint: str, icon: str, label: str) -> str:
|
endpoint: str, icon: str, label: str) -> str:
|
||||||
from shared.sx.helpers import root_header_sx
|
from shared.sx.helpers import root_header_sx
|
||||||
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
|
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
|
||||||
from quart import url_for as qurl
|
from quart import url_for as qurl
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
settings_hdr = _settings_header_sx(ctx)
|
settings_hdr = await _settings_header_sx(ctx)
|
||||||
sub_hdr = _sub_settings_header_sx(row_id, child_id,
|
sub_hdr = await _sub_settings_header_sx(row_id, child_id,
|
||||||
qurl(endpoint), icon, label, ctx)
|
qurl(endpoint), icon, label, ctx)
|
||||||
return "(<> " + root_hdr + " " + settings_hdr + " " + sub_hdr + ")"
|
return "(<> " + root_hdr + " " + settings_hdr + " " + sub_hdr + ")"
|
||||||
|
|
||||||
|
|
||||||
def _sub_settings_oob(ctx: dict, row_id: str, child_id: str,
|
async def _sub_settings_oob(ctx: dict, row_id: str, child_id: str,
|
||||||
endpoint: str, icon: str, label: str) -> str:
|
endpoint: str, icon: str, label: str) -> str:
|
||||||
from shared.sx.helpers import oob_header_sx
|
from shared.sx.helpers import oob_header_sx
|
||||||
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
|
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
|
||||||
from quart import url_for as qurl
|
from quart import url_for as qurl
|
||||||
settings_hdr_oob = _settings_header_sx(ctx, oob=True)
|
settings_hdr_oob = await _settings_header_sx(ctx, oob=True)
|
||||||
sub_hdr = _sub_settings_header_sx(row_id, child_id,
|
sub_hdr = await _sub_settings_header_sx(row_id, child_id,
|
||||||
qurl(endpoint), icon, label, ctx)
|
qurl(endpoint), icon, label, ctx)
|
||||||
sub_oob = oob_header_sx("root-settings-header-child", child_id, sub_hdr)
|
sub_oob = await oob_header_sx("root-settings-header-child", child_id, sub_hdr)
|
||||||
return "(<> " + settings_hdr_oob + " " + sub_oob + ")"
|
return "(<> " + settings_hdr_oob + " " + sub_oob + ")"
|
||||||
|
|
||||||
|
|
||||||
# --- Cache ---
|
# --- Cache ---
|
||||||
|
|
||||||
def _cache_full(ctx: dict, **kw: Any) -> str:
|
async def _cache_full(ctx: dict, **kw: Any) -> str:
|
||||||
return _sub_settings_full(ctx, "cache-row", "cache-header-child",
|
return await _sub_settings_full(ctx, "cache-row", "cache-header-child",
|
||||||
"defpage_cache_page", "refresh", "Cache")
|
"defpage_cache_page", "refresh", "Cache")
|
||||||
|
|
||||||
|
|
||||||
def _cache_oob(ctx: dict, **kw: Any) -> str:
|
async def _cache_oob(ctx: dict, **kw: Any) -> str:
|
||||||
return _sub_settings_oob(ctx, "cache-row", "cache-header-child",
|
return await _sub_settings_oob(ctx, "cache-row", "cache-header-child",
|
||||||
"defpage_cache_page", "refresh", "Cache")
|
"defpage_cache_page", "refresh", "Cache")
|
||||||
|
|
||||||
|
|
||||||
# --- Snippets ---
|
# --- Snippets ---
|
||||||
|
|
||||||
def _snippets_full(ctx: dict, **kw: Any) -> str:
|
async def _snippets_full(ctx: dict, **kw: Any) -> str:
|
||||||
return _sub_settings_full(ctx, "snippets-row", "snippets-header-child",
|
return await _sub_settings_full(ctx, "snippets-row", "snippets-header-child",
|
||||||
"defpage_snippets_page", "puzzle-piece", "Snippets")
|
"defpage_snippets_page", "puzzle-piece", "Snippets")
|
||||||
|
|
||||||
|
|
||||||
def _snippets_oob(ctx: dict, **kw: Any) -> str:
|
async def _snippets_oob(ctx: dict, **kw: Any) -> str:
|
||||||
return _sub_settings_oob(ctx, "snippets-row", "snippets-header-child",
|
return await _sub_settings_oob(ctx, "snippets-row", "snippets-header-child",
|
||||||
"defpage_snippets_page", "puzzle-piece", "Snippets")
|
"defpage_snippets_page", "puzzle-piece", "Snippets")
|
||||||
|
|
||||||
|
|
||||||
# --- Menu Items ---
|
# --- Menu Items ---
|
||||||
|
|
||||||
def _menu_items_full(ctx: dict, **kw: Any) -> str:
|
async def _menu_items_full(ctx: dict, **kw: Any) -> str:
|
||||||
return _sub_settings_full(ctx, "menu_items-row", "menu_items-header-child",
|
return await _sub_settings_full(ctx, "menu_items-row", "menu_items-header-child",
|
||||||
"defpage_menu_items_page", "bars", "Menu Items")
|
"defpage_menu_items_page", "bars", "Menu Items")
|
||||||
|
|
||||||
|
|
||||||
def _menu_items_oob(ctx: dict, **kw: Any) -> str:
|
async def _menu_items_oob(ctx: dict, **kw: Any) -> str:
|
||||||
return _sub_settings_oob(ctx, "menu_items-row", "menu_items-header-child",
|
return await _sub_settings_oob(ctx, "menu_items-row", "menu_items-header-child",
|
||||||
"defpage_menu_items_page", "bars", "Menu Items")
|
"defpage_menu_items_page", "bars", "Menu Items")
|
||||||
|
|
||||||
|
|
||||||
# --- Tag Groups ---
|
# --- Tag Groups ---
|
||||||
|
|
||||||
def _tag_groups_full(ctx: dict, **kw: Any) -> str:
|
async def _tag_groups_full(ctx: dict, **kw: Any) -> str:
|
||||||
return _sub_settings_full(ctx, "tag-groups-row", "tag-groups-header-child",
|
return await _sub_settings_full(ctx, "tag-groups-row", "tag-groups-header-child",
|
||||||
"defpage_tag_groups_page", "tags", "Tag Groups")
|
"defpage_tag_groups_page", "tags", "Tag Groups")
|
||||||
|
|
||||||
|
|
||||||
def _tag_groups_oob(ctx: dict, **kw: Any) -> str:
|
async def _tag_groups_oob(ctx: dict, **kw: Any) -> str:
|
||||||
return _sub_settings_oob(ctx, "tag-groups-row", "tag-groups-header-child",
|
return await _sub_settings_oob(ctx, "tag-groups-row", "tag-groups-header-child",
|
||||||
"defpage_tag_groups_page", "tags", "Tag Groups")
|
"defpage_tag_groups_page", "tags", "Tag Groups")
|
||||||
|
|
||||||
|
|
||||||
# --- Tag Group Edit ---
|
# --- Tag Group Edit ---
|
||||||
|
|
||||||
def _tag_group_edit_full(ctx: dict, **kw: Any) -> str:
|
async def _tag_group_edit_full(ctx: dict, **kw: Any) -> str:
|
||||||
from quart import request
|
from quart import request
|
||||||
g_id = (request.view_args or {}).get("id")
|
g_id = (request.view_args or {}).get("id")
|
||||||
from quart import url_for as qurl
|
from quart import url_for as qurl
|
||||||
from shared.sx.helpers import root_header_sx
|
from shared.sx.helpers import root_header_sx
|
||||||
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
|
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
settings_hdr = _settings_header_sx(ctx)
|
settings_hdr = await _settings_header_sx(ctx)
|
||||||
sub_hdr = _sub_settings_header_sx("tag-groups-row", "tag-groups-header-child",
|
sub_hdr = await _sub_settings_header_sx("tag-groups-row", "tag-groups-header-child",
|
||||||
qurl("defpage_tag_group_edit", id=g_id),
|
qurl("defpage_tag_group_edit", id=g_id),
|
||||||
"tags", "Tag Groups", ctx)
|
"tags", "Tag Groups", ctx)
|
||||||
return "(<> " + root_hdr + " " + settings_hdr + " " + sub_hdr + ")"
|
return "(<> " + root_hdr + " " + settings_hdr + " " + sub_hdr + ")"
|
||||||
|
|
||||||
|
|
||||||
def _tag_group_edit_oob(ctx: dict, **kw: Any) -> str:
|
async def _tag_group_edit_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from quart import request
|
from quart import request
|
||||||
g_id = (request.view_args or {}).get("id")
|
g_id = (request.view_args or {}).get("id")
|
||||||
from quart import url_for as qurl
|
from quart import url_for as qurl
|
||||||
from shared.sx.helpers import oob_header_sx
|
from shared.sx.helpers import oob_header_sx
|
||||||
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
|
from sx.sx_components import _settings_header_sx, _sub_settings_header_sx
|
||||||
settings_hdr_oob = _settings_header_sx(ctx, oob=True)
|
settings_hdr_oob = await _settings_header_sx(ctx, oob=True)
|
||||||
sub_hdr = _sub_settings_header_sx("tag-groups-row", "tag-groups-header-child",
|
sub_hdr = await _sub_settings_header_sx("tag-groups-row", "tag-groups-header-child",
|
||||||
qurl("defpage_tag_group_edit", id=g_id),
|
qurl("defpage_tag_group_edit", id=g_id),
|
||||||
"tags", "Tag Groups", ctx)
|
"tags", "Tag Groups", ctx)
|
||||||
sub_oob = oob_header_sx("root-settings-header-child", "tag-groups-header-child", sub_hdr)
|
sub_oob = await oob_header_sx("root-settings-header-child", "tag-groups-header-child", sub_hdr)
|
||||||
return "(<> " + settings_hdr_oob + " " + sub_oob + ")"
|
return "(<> " + settings_hdr_oob + " " + sub_oob + ")"
|
||||||
|
|
||||||
|
|
||||||
@@ -302,12 +302,12 @@ def _register_blog_helpers() -> None:
|
|||||||
|
|
||||||
async def _h_editor_content(**kw):
|
async def _h_editor_content(**kw):
|
||||||
from sx.sx_components import render_editor_panel
|
from sx.sx_components import render_editor_panel
|
||||||
return render_editor_panel()
|
return await render_editor_panel()
|
||||||
|
|
||||||
|
|
||||||
async def _h_editor_page_content(**kw):
|
async def _h_editor_page_content(**kw):
|
||||||
from sx.sx_components import render_editor_panel
|
from sx.sx_components import render_editor_panel
|
||||||
return render_editor_panel(is_page=True)
|
return await render_editor_panel(is_page=True)
|
||||||
|
|
||||||
|
|
||||||
# --- Post admin helpers ---
|
# --- Post admin helpers ---
|
||||||
@@ -391,7 +391,7 @@ async def _h_post_preview_content(slug=None, **kw):
|
|||||||
from sx.sx_components import _preview_main_panel_sx
|
from sx.sx_components import _preview_main_panel_sx
|
||||||
tctx = await get_template_context()
|
tctx = await get_template_context()
|
||||||
tctx.update(preview_ctx)
|
tctx.update(preview_ctx)
|
||||||
return _preview_main_panel_sx(tctx)
|
return await _preview_main_panel_sx(tctx)
|
||||||
|
|
||||||
|
|
||||||
async def _h_post_entries_content(slug=None, **kw):
|
async def _h_post_entries_content(slug=None, **kw):
|
||||||
@@ -415,7 +415,7 @@ async def _h_post_entries_content(slug=None, **kw):
|
|||||||
tctx = await get_template_context()
|
tctx = await get_template_context()
|
||||||
tctx["all_calendars"] = all_calendars
|
tctx["all_calendars"] = all_calendars
|
||||||
tctx["associated_entry_ids"] = associated_entry_ids
|
tctx["associated_entry_ids"] = associated_entry_ids
|
||||||
return _post_entries_content_sx(tctx)
|
return await _post_entries_content_sx(tctx)
|
||||||
|
|
||||||
|
|
||||||
async def _h_post_settings_content(slug=None, **kw):
|
async def _h_post_settings_content(slug=None, **kw):
|
||||||
@@ -468,7 +468,7 @@ async def _h_post_edit_content(slug=None, **kw):
|
|||||||
tctx["save_success"] = save_success
|
tctx["save_success"] = save_success
|
||||||
tctx["save_error"] = save_error
|
tctx["save_error"] = save_error
|
||||||
tctx["newsletters"] = newsletters
|
tctx["newsletters"] = newsletters
|
||||||
return _post_edit_content_sx(tctx)
|
return await _post_edit_content_sx(tctx)
|
||||||
|
|
||||||
|
|
||||||
# --- Settings helpers ---
|
# --- Settings helpers ---
|
||||||
@@ -484,7 +484,7 @@ async def _h_cache_content(**kw):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import _cache_main_panel_sx
|
from sx.sx_components import _cache_main_panel_sx
|
||||||
tctx = await get_template_context()
|
tctx = await get_template_context()
|
||||||
return _cache_main_panel_sx(tctx)
|
return await _cache_main_panel_sx(tctx)
|
||||||
|
|
||||||
|
|
||||||
# --- Snippets helper ---
|
# --- Snippets helper ---
|
||||||
@@ -506,7 +506,7 @@ async def _h_snippets_content(**kw):
|
|||||||
tctx = await get_template_context()
|
tctx = await get_template_context()
|
||||||
tctx["snippets"] = rows
|
tctx["snippets"] = rows
|
||||||
tctx["is_admin"] = is_admin
|
tctx["is_admin"] = is_admin
|
||||||
return _snippets_main_panel_sx(tctx)
|
return await _snippets_main_panel_sx(tctx)
|
||||||
|
|
||||||
|
|
||||||
# --- Menu Items helper ---
|
# --- Menu Items helper ---
|
||||||
@@ -519,7 +519,7 @@ async def _h_menu_items_content(**kw):
|
|||||||
from sx.sx_components import _menu_items_main_panel_sx
|
from sx.sx_components import _menu_items_main_panel_sx
|
||||||
tctx = await get_template_context()
|
tctx = await get_template_context()
|
||||||
tctx["menu_items"] = menu_items
|
tctx["menu_items"] = menu_items
|
||||||
return _menu_items_main_panel_sx(tctx)
|
return await _menu_items_main_panel_sx(tctx)
|
||||||
|
|
||||||
|
|
||||||
# --- Tag Groups helpers ---
|
# --- Tag Groups helpers ---
|
||||||
@@ -539,7 +539,7 @@ async def _h_tag_groups_content(**kw):
|
|||||||
from sx.sx_components import _tag_groups_main_panel_sx
|
from sx.sx_components import _tag_groups_main_panel_sx
|
||||||
tctx = await get_template_context()
|
tctx = await get_template_context()
|
||||||
tctx.update({"groups": groups, "unassigned_tags": unassigned})
|
tctx.update({"groups": groups, "unassigned_tags": unassigned})
|
||||||
return _tag_groups_main_panel_sx(tctx)
|
return await _tag_groups_main_panel_sx(tctx)
|
||||||
|
|
||||||
|
|
||||||
async def _h_tag_group_edit_content(id=None, **kw):
|
async def _h_tag_group_edit_content(id=None, **kw):
|
||||||
@@ -571,4 +571,4 @@ async def _h_tag_group_edit_content(id=None, **kw):
|
|||||||
"all_tags": all_tags,
|
"all_tags": all_tags,
|
||||||
"assigned_tag_ids": set(assigned_rows),
|
"assigned_tag_ids": set(assigned_rows),
|
||||||
})
|
})
|
||||||
return _tag_groups_edit_main_panel_sx(tctx)
|
return await _tag_groups_edit_main_panel_sx(tctx)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ def register():
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import render_cart_payments_panel
|
from sx.sx_components import render_cart_payments_panel
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
html = render_cart_payments_panel(ctx)
|
html = await render_cart_payments_panel(ctx)
|
||||||
return sx_response(html)
|
return sx_response(html)
|
||||||
|
|
||||||
return bp
|
return bp
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ from shared.sx.helpers import (
|
|||||||
post_header_sx as _shared_post_header_sx,
|
post_header_sx as _shared_post_header_sx,
|
||||||
search_desktop_sx, search_mobile_sx,
|
search_desktop_sx, search_mobile_sx,
|
||||||
full_page_sx, oob_page_sx, header_child_sx,
|
full_page_sx, oob_page_sx, header_child_sx,
|
||||||
sx_call, SxExpr,
|
render_to_sx,
|
||||||
)
|
)
|
||||||
from shared.sx.parser import serialize
|
from shared.sx.parser import SxExpr
|
||||||
from shared.infrastructure.urls import cart_url
|
from shared.infrastructure.urls import cart_url
|
||||||
|
|
||||||
# Load cart-specific .sx components + handlers at import time
|
# Load cart-specific .sx components + handlers at import time
|
||||||
@@ -69,12 +69,12 @@ async def _post_header_sx(ctx: dict, page_post: Any, *, oob: bool = False) -> st
|
|||||||
"""Build post-level header row from page_post DTO, using shared helper."""
|
"""Build post-level header row from page_post DTO, using shared helper."""
|
||||||
ctx = _ensure_post_ctx(ctx, page_post)
|
ctx = _ensure_post_ctx(ctx, page_post)
|
||||||
ctx = await _ensure_container_nav(ctx)
|
ctx = await _ensure_container_nav(ctx)
|
||||||
return _shared_post_header_sx(ctx, oob=oob)
|
return await _shared_post_header_sx(ctx, oob=oob)
|
||||||
|
|
||||||
|
|
||||||
def _cart_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
async def _cart_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
||||||
"""Build the cart section header row."""
|
"""Build the cart section header row."""
|
||||||
return sx_call(
|
return await render_to_sx(
|
||||||
"menu-row-sx",
|
"menu-row-sx",
|
||||||
id="cart-row", level=1, colour="sky",
|
id="cart-row", level=1, colour="sky",
|
||||||
link_href=call_url(ctx, "cart_url", "/"),
|
link_href=call_url(ctx, "cart_url", "/"),
|
||||||
@@ -83,17 +83,17 @@ def _cart_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _page_cart_header_sx(ctx: dict, page_post: Any, *, oob: bool = False) -> str:
|
async def _page_cart_header_sx(ctx: dict, page_post: Any, *, oob: bool = False) -> str:
|
||||||
"""Build the per-page cart header row."""
|
"""Build the per-page cart header row."""
|
||||||
slug = page_post.slug if page_post else ""
|
slug = page_post.slug if page_post else ""
|
||||||
title = ((page_post.title if page_post else None) or "")[:160]
|
title = ((page_post.title if page_post else None) or "")[:160]
|
||||||
label_parts = []
|
label_parts = []
|
||||||
if page_post and page_post.feature_image:
|
if page_post and page_post.feature_image:
|
||||||
label_parts.append(sx_call("cart-page-label-img", src=page_post.feature_image))
|
label_parts.append(await render_to_sx("cart-page-label-img", src=page_post.feature_image))
|
||||||
label_parts.append(f'(span "{escape(title)}")')
|
label_parts.append(f'(span "{escape(title)}")')
|
||||||
label_sx = "(<> " + " ".join(label_parts) + ")"
|
label_sx = "(<> " + " ".join(label_parts) + ")"
|
||||||
nav_sx = sx_call("cart-all-carts-link", href=call_url(ctx, "cart_url", "/"))
|
nav_sx = await render_to_sx("cart-all-carts-link", href=call_url(ctx, "cart_url", "/"))
|
||||||
return sx_call(
|
return await render_to_sx(
|
||||||
"menu-row-sx",
|
"menu-row-sx",
|
||||||
id="page-cart-row", level=2, colour="sky",
|
id="page-cart-row", level=2, colour="sky",
|
||||||
link_href=call_url(ctx, "cart_url", f"/{slug}/"),
|
link_href=call_url(ctx, "cart_url", f"/{slug}/"),
|
||||||
@@ -102,26 +102,26 @@ def _page_cart_header_sx(ctx: dict, page_post: Any, *, oob: bool = False) -> str
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _auth_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
async def _auth_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
||||||
"""Build the account section header row (for orders)."""
|
"""Build the account section header row (for orders)."""
|
||||||
return sx_call(
|
return await render_to_sx(
|
||||||
"auth-header-row-simple",
|
"auth-header-row-simple",
|
||||||
account_url=call_url(ctx, "account_url", ""),
|
account_url=call_url(ctx, "account_url", ""),
|
||||||
oob=oob,
|
oob=oob,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _orders_header_sx(ctx: dict, list_url: str) -> str:
|
async def _orders_header_sx(ctx: dict, list_url: str) -> str:
|
||||||
"""Build the orders section header row."""
|
"""Build the orders section header row."""
|
||||||
return sx_call("orders-header-row", list_url=list_url)
|
return await render_to_sx("orders-header-row", list_url=list_url)
|
||||||
|
|
||||||
|
|
||||||
def _cart_page_admin_header_sx(ctx: dict, page_post: Any, *, oob: bool = False,
|
async def _cart_page_admin_header_sx(ctx: dict, page_post: Any, *, oob: bool = False,
|
||||||
selected: str = "") -> str:
|
selected: str = "") -> str:
|
||||||
"""Build the page-level admin header row."""
|
"""Build the page-level admin header row."""
|
||||||
slug = page_post.slug if page_post else ""
|
slug = page_post.slug if page_post else ""
|
||||||
ctx = _ensure_post_ctx(ctx, page_post)
|
ctx = _ensure_post_ctx(ctx, page_post)
|
||||||
return post_admin_header_sx(ctx, slug, oob=oob, selected=selected)
|
return await post_admin_header_sx(ctx, slug, oob=oob, selected=selected)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -190,24 +190,25 @@ async def render_orders_page(ctx: dict, orders: list, page: int,
|
|||||||
detail_url_prefix = pfx + url_for_fn("orders.order.order_detail", order_id=0).rsplit("0/", 1)[0]
|
detail_url_prefix = pfx + url_for_fn("orders.order.order_detail", order_id=0).rsplit("0/", 1)[0]
|
||||||
|
|
||||||
order_dicts = [_serialize_order(o) for o in orders]
|
order_dicts = [_serialize_order(o) for o in orders]
|
||||||
content = sx_call("orders-list-content",
|
content = await render_to_sx("orders-list-content",
|
||||||
orders=SxExpr(serialize(order_dicts)),
|
orders=order_dicts,
|
||||||
page=page, total_pages=total_pages,
|
page=page, total_pages=total_pages,
|
||||||
rows_url=rows_url, detail_url_prefix=detail_url_prefix)
|
rows_url=rows_url, detail_url_prefix=detail_url_prefix)
|
||||||
|
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
auth = _auth_header_sx(ctx)
|
auth = await _auth_header_sx(ctx)
|
||||||
orders_hdr = _orders_header_sx(ctx, list_url)
|
orders_hdr = await _orders_header_sx(ctx, list_url)
|
||||||
auth_child = sx_call(
|
auth_child_inner = await render_to_sx("header-child-sx", id="auth-header-child", inner=SxExpr(orders_hdr))
|
||||||
|
auth_child = await render_to_sx(
|
||||||
"header-child-sx",
|
"header-child-sx",
|
||||||
inner=SxExpr("(<> " + auth + " " + sx_call("header-child-sx", id="auth-header-child", inner=SxExpr(orders_hdr)) + ")"),
|
inner=SxExpr("(<> " + auth + " " + auth_child_inner + ")"),
|
||||||
)
|
)
|
||||||
header_rows = "(<> " + hdr + " " + auth_child + ")"
|
header_rows = "(<> " + hdr + " " + auth_child + ")"
|
||||||
|
|
||||||
filt = sx_call("order-list-header", search_mobile=SxExpr(search_mobile_sx(ctx)))
|
filt = await render_to_sx("order-list-header", search_mobile=SxExpr(await search_mobile_sx(ctx)))
|
||||||
return full_page_sx(ctx, header_rows=header_rows,
|
return await full_page_sx(ctx, header_rows=header_rows,
|
||||||
filter=filt,
|
filter=filt,
|
||||||
aside=search_desktop_sx(ctx),
|
aside=await search_desktop_sx(ctx),
|
||||||
content=content)
|
content=content)
|
||||||
|
|
||||||
|
|
||||||
@@ -222,20 +223,21 @@ async def render_orders_rows(ctx: dict, orders: list, page: int,
|
|||||||
detail_url_prefix = pfx + url_for_fn("orders.order.order_detail", order_id=0).rsplit("0/", 1)[0]
|
detail_url_prefix = pfx + url_for_fn("orders.order.order_detail", order_id=0).rsplit("0/", 1)[0]
|
||||||
|
|
||||||
order_dicts = [_serialize_order(o) for o in orders]
|
order_dicts = [_serialize_order(o) for o in orders]
|
||||||
parts = [sx_call("order-row-pair",
|
parts = []
|
||||||
order=SxExpr(serialize(od)),
|
for od in order_dicts:
|
||||||
detail_url_prefix=detail_url_prefix)
|
parts.append(await render_to_sx("order-row-pair",
|
||||||
for od in order_dicts]
|
order=od,
|
||||||
|
detail_url_prefix=detail_url_prefix))
|
||||||
|
|
||||||
if page < total_pages:
|
if page < total_pages:
|
||||||
next_url = list_url + qs_fn(page=page + 1)
|
next_url = list_url + qs_fn(page=page + 1)
|
||||||
parts.append(sx_call(
|
parts.append(await render_to_sx(
|
||||||
"infinite-scroll",
|
"infinite-scroll",
|
||||||
url=next_url, page=page, total_pages=total_pages,
|
url=next_url, page=page, total_pages=total_pages,
|
||||||
id_prefix="orders", colspan=5,
|
id_prefix="orders", colspan=5,
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
parts.append(sx_call("order-end-row"))
|
parts.append(await render_to_sx("order-end-row"))
|
||||||
|
|
||||||
return "(<> " + " ".join(parts) + ")"
|
return "(<> " + " ".join(parts) + ")"
|
||||||
|
|
||||||
@@ -255,24 +257,25 @@ async def render_orders_oob(ctx: dict, orders: list, page: int,
|
|||||||
detail_url_prefix = pfx + url_for_fn("orders.order.order_detail", order_id=0).rsplit("0/", 1)[0]
|
detail_url_prefix = pfx + url_for_fn("orders.order.order_detail", order_id=0).rsplit("0/", 1)[0]
|
||||||
|
|
||||||
order_dicts = [_serialize_order(o) for o in orders]
|
order_dicts = [_serialize_order(o) for o in orders]
|
||||||
content = sx_call("orders-list-content",
|
content = await render_to_sx("orders-list-content",
|
||||||
orders=SxExpr(serialize(order_dicts)),
|
orders=order_dicts,
|
||||||
page=page, total_pages=total_pages,
|
page=page, total_pages=total_pages,
|
||||||
rows_url=rows_url, detail_url_prefix=detail_url_prefix)
|
rows_url=rows_url, detail_url_prefix=detail_url_prefix)
|
||||||
|
|
||||||
auth_oob = _auth_header_sx(ctx, oob=True)
|
auth_oob = await _auth_header_sx(ctx, oob=True)
|
||||||
auth_child_oob = sx_call(
|
orders_hdr = await _orders_header_sx(ctx, list_url)
|
||||||
|
auth_child_oob = await render_to_sx(
|
||||||
"oob-header-sx",
|
"oob-header-sx",
|
||||||
parent_id="auth-header-child",
|
parent_id="auth-header-child",
|
||||||
row=SxExpr(_orders_header_sx(ctx, list_url)),
|
row=SxExpr(orders_hdr),
|
||||||
)
|
)
|
||||||
root_oob = root_header_sx(ctx, oob=True)
|
root_oob = await root_header_sx(ctx, oob=True)
|
||||||
oobs = "(<> " + auth_oob + " " + auth_child_oob + " " + root_oob + ")"
|
oobs = "(<> " + auth_oob + " " + auth_child_oob + " " + root_oob + ")"
|
||||||
|
|
||||||
filt = sx_call("order-list-header", search_mobile=SxExpr(search_mobile_sx(ctx)))
|
filt = await render_to_sx("order-list-header", search_mobile=SxExpr(await search_mobile_sx(ctx)))
|
||||||
return oob_page_sx(oobs=oobs,
|
return await oob_page_sx(oobs=oobs,
|
||||||
filter=filt,
|
filter=filt,
|
||||||
aside=search_desktop_sx(ctx),
|
aside=await search_desktop_sx(ctx),
|
||||||
content=content)
|
content=content)
|
||||||
|
|
||||||
|
|
||||||
@@ -296,29 +299,32 @@ async def render_order_page(ctx: dict, order: Any,
|
|||||||
order_data = _serialize_order(order)
|
order_data = _serialize_order(order)
|
||||||
cal_data = [_serialize_calendar_entry(e) for e in (calendar_entries or [])]
|
cal_data = [_serialize_calendar_entry(e) for e in (calendar_entries or [])]
|
||||||
|
|
||||||
main = sx_call("order-detail-content",
|
main = await render_to_sx("order-detail-content",
|
||||||
order=SxExpr(serialize(order_data)),
|
order=order_data,
|
||||||
calendar_entries=SxExpr(serialize(cal_data)))
|
calendar_entries=cal_data)
|
||||||
filt = sx_call("order-detail-filter-content",
|
filt = await render_to_sx("order-detail-filter-content",
|
||||||
order=SxExpr(serialize(order_data)),
|
order=order_data,
|
||||||
list_url=list_url, recheck_url=recheck_url,
|
list_url=list_url, recheck_url=recheck_url,
|
||||||
pay_url=pay_url, csrf=generate_csrf_token())
|
pay_url=pay_url, csrf=generate_csrf_token())
|
||||||
|
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
order_row = sx_call(
|
order_row = await render_to_sx(
|
||||||
"menu-row-sx",
|
"menu-row-sx",
|
||||||
id="order-row", level=3, colour="sky",
|
id="order-row", level=3, colour="sky",
|
||||||
link_href=detail_url, link_label=f"Order {order.id}", icon="fa fa-gbp",
|
link_href=detail_url, link_label=f"Order {order.id}", icon="fa fa-gbp",
|
||||||
)
|
)
|
||||||
order_child = sx_call(
|
auth = await _auth_header_sx(ctx)
|
||||||
|
orders_hdr = await _orders_header_sx(ctx, list_url)
|
||||||
|
orders_child = await render_to_sx("header-child-sx", id="orders-header-child", inner=SxExpr(order_row))
|
||||||
|
auth_inner = "(<> " + orders_hdr + " " + orders_child + ")"
|
||||||
|
auth_child = await render_to_sx("header-child-sx", id="auth-header-child", inner=SxExpr(auth_inner))
|
||||||
|
order_child = await render_to_sx(
|
||||||
"header-child-sx",
|
"header-child-sx",
|
||||||
inner=SxExpr("(<> " + _auth_header_sx(ctx) + " " + sx_call("header-child-sx", id="auth-header-child", inner=SxExpr(
|
inner=SxExpr("(<> " + auth + " " + auth_child + ")"),
|
||||||
"(<> " + _orders_header_sx(ctx, list_url) + " " + sx_call("header-child-sx", id="orders-header-child", inner=SxExpr(order_row)) + ")"
|
|
||||||
)) + ")"),
|
|
||||||
)
|
)
|
||||||
header_rows = "(<> " + hdr + " " + order_child + ")"
|
header_rows = "(<> " + hdr + " " + order_child + ")"
|
||||||
|
|
||||||
return full_page_sx(ctx, header_rows=header_rows, filter=filt, content=main)
|
return await full_page_sx(ctx, header_rows=header_rows, filter=filt, content=main)
|
||||||
|
|
||||||
|
|
||||||
async def render_order_oob(ctx: dict, order: Any,
|
async def render_order_oob(ctx: dict, order: Any,
|
||||||
@@ -337,27 +343,27 @@ async def render_order_oob(ctx: dict, order: Any,
|
|||||||
order_data = _serialize_order(order)
|
order_data = _serialize_order(order)
|
||||||
cal_data = [_serialize_calendar_entry(e) for e in (calendar_entries or [])]
|
cal_data = [_serialize_calendar_entry(e) for e in (calendar_entries or [])]
|
||||||
|
|
||||||
main = sx_call("order-detail-content",
|
main = await render_to_sx("order-detail-content",
|
||||||
order=SxExpr(serialize(order_data)),
|
order=order_data,
|
||||||
calendar_entries=SxExpr(serialize(cal_data)))
|
calendar_entries=cal_data)
|
||||||
filt = sx_call("order-detail-filter-content",
|
filt = await render_to_sx("order-detail-filter-content",
|
||||||
order=SxExpr(serialize(order_data)),
|
order=order_data,
|
||||||
list_url=list_url, recheck_url=recheck_url,
|
list_url=list_url, recheck_url=recheck_url,
|
||||||
pay_url=pay_url, csrf=generate_csrf_token())
|
pay_url=pay_url, csrf=generate_csrf_token())
|
||||||
|
|
||||||
order_row_oob = sx_call(
|
order_row_oob = await render_to_sx(
|
||||||
"menu-row-sx",
|
"menu-row-sx",
|
||||||
id="order-row", level=3, colour="sky",
|
id="order-row", level=3, colour="sky",
|
||||||
link_href=detail_url, link_label=f"Order {order.id}", icon="fa fa-gbp",
|
link_href=detail_url, link_label=f"Order {order.id}", icon="fa fa-gbp",
|
||||||
oob=True,
|
oob=True,
|
||||||
)
|
)
|
||||||
orders_child_oob = sx_call("oob-header-sx",
|
orders_child_oob = await render_to_sx("oob-header-sx",
|
||||||
parent_id="orders-header-child",
|
parent_id="orders-header-child",
|
||||||
row=SxExpr(order_row_oob))
|
row=SxExpr(order_row_oob))
|
||||||
root_oob = root_header_sx(ctx, oob=True)
|
root_oob = await root_header_sx(ctx, oob=True)
|
||||||
oobs = "(<> " + orders_child_oob + " " + root_oob + ")"
|
oobs = "(<> " + orders_child_oob + " " + root_oob + ")"
|
||||||
|
|
||||||
return oob_page_sx(oobs=oobs, filter=filt, content=main)
|
return await oob_page_sx(oobs=oobs, filter=filt, content=main)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -370,25 +376,25 @@ async def render_checkout_error_page(ctx: dict, error: str | None = None,
|
|||||||
err_msg = error or "Unexpected error while creating the hosted checkout session."
|
err_msg = error or "Unexpected error while creating the hosted checkout session."
|
||||||
order_sx = None
|
order_sx = None
|
||||||
if order:
|
if order:
|
||||||
order_sx = sx_call("checkout-error-order-id", oid=f"#{order.id}")
|
order_sx = await render_to_sx("checkout-error-order-id", oid=f"#{order.id}")
|
||||||
back_url = cart_url("/")
|
back_url = cart_url("/")
|
||||||
|
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
filt = sx_call("checkout-error-header")
|
filt = await render_to_sx("checkout-error-header")
|
||||||
content = sx_call(
|
content = await render_to_sx(
|
||||||
"checkout-error-content",
|
"checkout-error-content",
|
||||||
msg=err_msg,
|
msg=err_msg,
|
||||||
order=SxExpr(order_sx) if order_sx else None,
|
order=SxExpr(order_sx) if order_sx else None,
|
||||||
back_url=back_url,
|
back_url=back_url,
|
||||||
)
|
)
|
||||||
return full_page_sx(ctx, header_rows=hdr, filter=filt, content=content)
|
return await full_page_sx(ctx, header_rows=hdr, filter=filt, content=content)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Public API: POST response renderers
|
# Public API: POST response renderers
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def render_cart_payments_panel(ctx: dict) -> str:
|
async def render_cart_payments_panel(ctx: dict) -> str:
|
||||||
"""Render the payments config panel for PUT response."""
|
"""Render the payments config panel for PUT response."""
|
||||||
page_config = ctx.get("page_config")
|
page_config = ctx.get("page_config")
|
||||||
pc_data = None
|
pc_data = None
|
||||||
@@ -398,5 +404,5 @@ def render_cart_payments_panel(ctx: dict) -> str:
|
|||||||
"sumup_merchant_code": getattr(page_config, "sumup_merchant_code", None) or "",
|
"sumup_merchant_code": getattr(page_config, "sumup_merchant_code", None) or "",
|
||||||
"sumup_checkout_prefix": getattr(page_config, "sumup_checkout_prefix", None) or "",
|
"sumup_checkout_prefix": getattr(page_config, "sumup_checkout_prefix", None) or "",
|
||||||
}
|
}
|
||||||
return sx_call("cart-payments-content",
|
return await render_to_sx("cart-payments-content",
|
||||||
page_config=SxExpr(serialize(pc_data)) if pc_data else None)
|
page_config=pc_data)
|
||||||
|
|||||||
@@ -27,31 +27,35 @@ def _register_cart_layouts() -> None:
|
|||||||
register_custom_layout("cart-admin", _cart_admin_full, _cart_admin_oob)
|
register_custom_layout("cart-admin", _cart_admin_full, _cart_admin_oob)
|
||||||
|
|
||||||
|
|
||||||
def _cart_page_full(ctx: dict, **kw: Any) -> str:
|
async def _cart_page_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, sx_call, SxExpr
|
from shared.sx.helpers import root_header_sx, render_to_sx
|
||||||
|
from shared.sx.parser import SxExpr
|
||||||
from sx.sx_components import _cart_header_sx, _page_cart_header_sx
|
from sx.sx_components import _cart_header_sx, _page_cart_header_sx
|
||||||
|
|
||||||
page_post = ctx.get("page_post")
|
page_post = ctx.get("page_post")
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
child = _cart_header_sx(ctx)
|
child = await _cart_header_sx(ctx)
|
||||||
page_hdr = _page_cart_header_sx(ctx, page_post)
|
page_hdr = await _page_cart_header_sx(ctx, page_post)
|
||||||
nested = sx_call(
|
inner_child = await render_to_sx("header-child-sx", id="cart-header-child", inner=SxExpr(page_hdr))
|
||||||
|
nested = await render_to_sx(
|
||||||
"header-child-sx",
|
"header-child-sx",
|
||||||
inner=SxExpr("(<> " + child + " " + sx_call("header-child-sx", id="cart-header-child", inner=SxExpr(page_hdr)) + ")"),
|
inner=SxExpr("(<> " + child + " " + inner_child + ")"),
|
||||||
)
|
)
|
||||||
return "(<> " + root_hdr + " " + nested + ")"
|
return "(<> " + root_hdr + " " + nested + ")"
|
||||||
|
|
||||||
|
|
||||||
def _cart_page_oob(ctx: dict, **kw: Any) -> str:
|
async def _cart_page_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, sx_call, SxExpr
|
from shared.sx.helpers import root_header_sx, render_to_sx
|
||||||
|
from shared.sx.parser import SxExpr
|
||||||
from sx.sx_components import _cart_header_sx, _page_cart_header_sx
|
from sx.sx_components import _cart_header_sx, _page_cart_header_sx
|
||||||
|
|
||||||
page_post = ctx.get("page_post")
|
page_post = ctx.get("page_post")
|
||||||
child_oob = sx_call("oob-header-sx",
|
page_hdr = await _page_cart_header_sx(ctx, page_post)
|
||||||
|
child_oob = await render_to_sx("oob-header-sx",
|
||||||
parent_id="cart-header-child",
|
parent_id="cart-header-child",
|
||||||
row=SxExpr(_page_cart_header_sx(ctx, page_post)))
|
row=SxExpr(page_hdr))
|
||||||
cart_hdr_oob = _cart_header_sx(ctx, oob=True)
|
cart_hdr_oob = await _cart_header_sx(ctx, oob=True)
|
||||||
root_hdr_oob = root_header_sx(ctx, oob=True)
|
root_hdr_oob = await root_header_sx(ctx, oob=True)
|
||||||
return "(<> " + child_oob + " " + cart_hdr_oob + " " + root_hdr_oob + ")"
|
return "(<> " + child_oob + " " + cart_hdr_oob + " " + root_hdr_oob + ")"
|
||||||
|
|
||||||
|
|
||||||
@@ -61,9 +65,9 @@ async def _cart_admin_full(ctx: dict, **kw: Any) -> str:
|
|||||||
|
|
||||||
page_post = ctx.get("page_post")
|
page_post = ctx.get("page_post")
|
||||||
selected = kw.get("selected", "")
|
selected = kw.get("selected", "")
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
post_hdr = await _post_header_sx(ctx, page_post)
|
post_hdr = await _post_header_sx(ctx, page_post)
|
||||||
admin_hdr = _cart_page_admin_header_sx(ctx, page_post, selected=selected)
|
admin_hdr = await _cart_page_admin_header_sx(ctx, page_post, selected=selected)
|
||||||
return "(<> " + root_hdr + " " + post_hdr + " " + admin_hdr + ")"
|
return "(<> " + root_hdr + " " + post_hdr + " " + admin_hdr + ")"
|
||||||
|
|
||||||
|
|
||||||
@@ -72,7 +76,7 @@ async def _cart_admin_oob(ctx: dict, **kw: Any) -> str:
|
|||||||
|
|
||||||
page_post = ctx.get("page_post")
|
page_post = ctx.get("page_post")
|
||||||
selected = kw.get("selected", "")
|
selected = kw.get("selected", "")
|
||||||
return _cart_page_admin_header_sx(ctx, page_post, oob=True, selected=selected)
|
return await _cart_page_admin_header_sx(ctx, page_post, oob=True, selected=selected)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -244,22 +248,21 @@ def _build_summary_data(ctx: dict, cart: list, cal_entries: list, tickets: list,
|
|||||||
|
|
||||||
async def _h_overview_content(**kw):
|
async def _h_overview_content(**kw):
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
from shared.infrastructure.urls import cart_url
|
from shared.infrastructure.urls import cart_url
|
||||||
from bp.cart.services import get_cart_grouped_by_page
|
from bp.cart.services import get_cart_grouped_by_page
|
||||||
|
|
||||||
page_groups = await get_cart_grouped_by_page(g.s)
|
page_groups = await get_cart_grouped_by_page(g.s)
|
||||||
grp_dicts = [d for d in (_serialize_page_group(grp) for grp in page_groups) if d]
|
grp_dicts = [d for d in (_serialize_page_group(grp) for grp in page_groups) if d]
|
||||||
return sx_call("cart-overview-content",
|
return await render_to_sx("cart-overview-content",
|
||||||
page_groups=SxExpr(serialize(grp_dicts)),
|
page_groups=grp_dicts,
|
||||||
cart_url_base=cart_url(""))
|
cart_url_base=cart_url(""))
|
||||||
|
|
||||||
|
|
||||||
async def _h_page_cart_content(page_slug=None, **kw):
|
async def _h_page_cart_content(page_slug=None, **kw):
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
from shared.sx.parser import SxExpr
|
||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from bp.cart.services import total, calendar_total, ticket_total
|
from bp.cart.services import total, calendar_total, ticket_total
|
||||||
from bp.cart.services.page_cart import (
|
from bp.cart.services.page_cart import (
|
||||||
@@ -277,7 +280,7 @@ async def _h_page_cart_content(page_slug=None, **kw):
|
|||||||
sd = _build_summary_data(ctx, cart, cal_entries, page_tickets,
|
sd = _build_summary_data(ctx, cart, cal_entries, page_tickets,
|
||||||
total, calendar_total, ticket_total)
|
total, calendar_total, ticket_total)
|
||||||
|
|
||||||
summary_sx = sx_call("cart-summary-from-data",
|
summary_sx = await render_to_sx("cart-summary-from-data",
|
||||||
item_count=sd["item_count"],
|
item_count=sd["item_count"],
|
||||||
grand_total=sd["grand_total"],
|
grand_total=sd["grand_total"],
|
||||||
symbol=sd["symbol"],
|
symbol=sd["symbol"],
|
||||||
@@ -286,10 +289,10 @@ async def _h_page_cart_content(page_slug=None, **kw):
|
|||||||
login_href=sd.get("login_href"),
|
login_href=sd.get("login_href"),
|
||||||
user_email=sd.get("user_email"))
|
user_email=sd.get("user_email"))
|
||||||
|
|
||||||
return sx_call("cart-page-cart-content",
|
return await render_to_sx("cart-page-cart-content",
|
||||||
cart_items=SxExpr(serialize([_serialize_cart_item(i) for i in cart])),
|
cart_items=[_serialize_cart_item(i) for i in cart],
|
||||||
cal_entries=SxExpr(serialize([_serialize_cal_entry(e) for e in cal_entries])),
|
cal_entries=[_serialize_cal_entry(e) for e in cal_entries],
|
||||||
ticket_groups=SxExpr(serialize([_serialize_ticket_group(tg) for tg in ticket_groups])),
|
ticket_groups=[_serialize_ticket_group(tg) for tg in ticket_groups],
|
||||||
summary=SxExpr(summary_sx))
|
summary=SxExpr(summary_sx))
|
||||||
|
|
||||||
|
|
||||||
@@ -299,8 +302,7 @@ async def _h_cart_admin_content(page_slug=None, **kw):
|
|||||||
|
|
||||||
async def _h_cart_payments_content(page_slug=None, **kw):
|
async def _h_cart_payments_content(page_slug=None, **kw):
|
||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
|
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
page_config = ctx.get("page_config")
|
page_config = ctx.get("page_config")
|
||||||
@@ -311,5 +313,5 @@ async def _h_cart_payments_content(page_slug=None, **kw):
|
|||||||
"sumup_merchant_code": getattr(page_config, "sumup_merchant_code", None) or "",
|
"sumup_merchant_code": getattr(page_config, "sumup_merchant_code", None) or "",
|
||||||
"sumup_checkout_prefix": getattr(page_config, "sumup_checkout_prefix", None) or "",
|
"sumup_checkout_prefix": getattr(page_config, "sumup_checkout_prefix", None) or "",
|
||||||
}
|
}
|
||||||
return sx_call("cart-payments-content",
|
return await render_to_sx("cart-payments-content",
|
||||||
page_config=SxExpr(serialize(pc_data)) if pc_data else None)
|
page_config=pc_data)
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ def register() -> Blueprint:
|
|||||||
frag_params["session_id"] = ident["session_id"]
|
frag_params["session_id"] = ident["session_id"]
|
||||||
|
|
||||||
from sx.sx_components import render_ticket_widget
|
from sx.sx_components import render_ticket_widget
|
||||||
widget_html = render_ticket_widget(entry, qty, "/all-tickets/adjust")
|
widget_html = await render_ticket_widget(entry, qty, "/all-tickets/adjust")
|
||||||
mini_html = await fetch_fragment("cart", "cart-mini", params=frag_params, required=False)
|
mini_html = await fetch_fragment("cart", "cart-mini", params=frag_params, required=False)
|
||||||
return sx_response(widget_html + (mini_html or ""))
|
return sx_response(widget_html + (mini_html or ""))
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ def register():
|
|||||||
@require_admin
|
@require_admin
|
||||||
async def calendar_description_edit(calendar_slug: str, **kwargs):
|
async def calendar_description_edit(calendar_slug: str, **kwargs):
|
||||||
from sx.sx_components import render_calendar_description_edit
|
from sx.sx_components import render_calendar_description_edit
|
||||||
html = render_calendar_description_edit(g.calendar)
|
html = await render_calendar_description_edit(g.calendar)
|
||||||
return sx_response(html)
|
return sx_response(html)
|
||||||
|
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ def register():
|
|||||||
await g.s.flush()
|
await g.s.flush()
|
||||||
|
|
||||||
from sx.sx_components import render_calendar_description
|
from sx.sx_components import render_calendar_description
|
||||||
html = render_calendar_description(g.calendar, oob=True)
|
html = await render_calendar_description(g.calendar, oob=True)
|
||||||
return sx_response(html)
|
return sx_response(html)
|
||||||
|
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ def register():
|
|||||||
@require_admin
|
@require_admin
|
||||||
async def calendar_description_view(calendar_slug: str, **kwargs):
|
async def calendar_description_view(calendar_slug: str, **kwargs):
|
||||||
from sx.sx_components import render_calendar_description
|
from sx.sx_components import render_calendar_description
|
||||||
html = render_calendar_description(g.calendar)
|
html = await render_calendar_description(g.calendar)
|
||||||
return sx_response(html)
|
return sx_response(html)
|
||||||
|
|
||||||
return bp
|
return bp
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ def register():
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import _calendar_admin_main_panel_html
|
from sx.sx_components import _calendar_admin_main_panel_html
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
html = _calendar_admin_main_panel_html(ctx)
|
html = await _calendar_admin_main_panel_html(ctx)
|
||||||
return sx_response(html)
|
return sx_response(html)
|
||||||
|
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ def register():
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import render_calendars_list_panel
|
from sx.sx_components import render_calendars_list_panel
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
html = render_calendars_list_panel(ctx)
|
html = await render_calendars_list_panel(ctx)
|
||||||
|
|
||||||
if post_data:
|
if post_data:
|
||||||
from shared.services.entry_associations import get_associated_entries
|
from shared.services.entry_associations import get_associated_entries
|
||||||
@@ -236,7 +236,7 @@ def register():
|
|||||||
).scalars().all()
|
).scalars().all()
|
||||||
|
|
||||||
associated_entries = await get_associated_entries(post_id)
|
associated_entries = await get_associated_entries(post_id)
|
||||||
nav_oob = render_post_nav_entries_oob(associated_entries, cals, post_data["post"])
|
nav_oob = await render_post_nav_entries_oob(associated_entries, cals, post_data["post"])
|
||||||
html = html + nav_oob
|
html = html + nav_oob
|
||||||
|
|
||||||
return sx_response(html)
|
return sx_response(html)
|
||||||
|
|||||||
@@ -259,7 +259,7 @@ def register():
|
|||||||
}
|
}
|
||||||
|
|
||||||
from sx.sx_components import render_day_main_panel
|
from sx.sx_components import render_day_main_panel
|
||||||
html = render_day_main_panel(ctx)
|
html = await render_day_main_panel(ctx)
|
||||||
mini_html = await fetch_fragment("cart", "cart-mini", params=frag_params, required=False)
|
mini_html = await fetch_fragment("cart", "cart-mini", params=frag_params, required=False)
|
||||||
return sx_response(html + (mini_html or ""))
|
return sx_response(html + (mini_html or ""))
|
||||||
|
|
||||||
@@ -280,12 +280,12 @@ def register():
|
|||||||
day_slots = list(result.scalars())
|
day_slots = list(result.scalars())
|
||||||
|
|
||||||
from sx.sx_components import render_entry_add_form
|
from sx.sx_components import render_entry_add_form
|
||||||
return sx_response(render_entry_add_form(g.calendar, day, month, year, day_slots))
|
return sx_response(await render_entry_add_form(g.calendar, day, month, year, day_slots))
|
||||||
|
|
||||||
@bp.get("/add-button/")
|
@bp.get("/add-button/")
|
||||||
async def add_button(day: int, month: int, year: int, **kwargs):
|
async def add_button(day: int, month: int, year: int, **kwargs):
|
||||||
from sx.sx_components import render_entry_add_button
|
from sx.sx_components import render_entry_add_button
|
||||||
return sx_response(render_entry_add_button(g.calendar, day, month, year))
|
return sx_response(await render_entry_add_button(g.calendar, day, month, year))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ def register():
|
|||||||
|
|
||||||
# Render OOB nav
|
# Render OOB nav
|
||||||
from sx.sx_components import render_day_entries_nav_oob
|
from sx.sx_components import render_day_entries_nav_oob
|
||||||
return render_day_entries_nav_oob(visible.confirmed_entries, calendar, day_date)
|
return await render_day_entries_nav_oob(visible.confirmed_entries, calendar, day_date)
|
||||||
|
|
||||||
async def get_post_nav_oob(entry_id: int):
|
async def get_post_nav_oob(entry_id: int):
|
||||||
"""Helper to generate OOB update for post entries nav when entry state changes"""
|
"""Helper to generate OOB update for post entries nav when entry state changes"""
|
||||||
@@ -149,7 +149,7 @@ def register():
|
|||||||
|
|
||||||
# Render OOB nav for this post
|
# Render OOB nav for this post
|
||||||
from sx.sx_components import render_post_nav_entries_oob
|
from sx.sx_components import render_post_nav_entries_oob
|
||||||
nav_oob = render_post_nav_entries_oob(associated_entries, calendars, post)
|
nav_oob = await render_post_nav_entries_oob(associated_entries, calendars, post)
|
||||||
nav_oobs.append(nav_oob)
|
nav_oobs.append(nav_oob)
|
||||||
|
|
||||||
return "".join(nav_oobs)
|
return "".join(nav_oobs)
|
||||||
@@ -257,7 +257,7 @@ def register():
|
|||||||
day_slots = list(result.scalars())
|
day_slots = list(result.scalars())
|
||||||
|
|
||||||
from sx.sx_components import render_entry_edit_form
|
from sx.sx_components import render_entry_edit_form
|
||||||
return sx_response(render_entry_edit_form(g.entry, g.calendar, day, month, year, day_slots))
|
return sx_response(await render_entry_edit_form(g.entry, g.calendar, day, month, year, day_slots))
|
||||||
|
|
||||||
@bp.put("/")
|
@bp.put("/")
|
||||||
@require_admin
|
@require_admin
|
||||||
@@ -423,7 +423,7 @@ def register():
|
|||||||
from sx.sx_components import _entry_main_panel_html
|
from sx.sx_components import _entry_main_panel_html
|
||||||
|
|
||||||
tctx = await get_template_context()
|
tctx = await get_template_context()
|
||||||
html = _entry_main_panel_html(tctx)
|
html = await _entry_main_panel_html(tctx)
|
||||||
return sx_response(html + nav_oob)
|
return sx_response(html + nav_oob)
|
||||||
|
|
||||||
|
|
||||||
@@ -449,7 +449,7 @@ def register():
|
|||||||
# Re-read entry to get updated state
|
# Re-read entry to get updated state
|
||||||
await g.s.refresh(g.entry)
|
await g.s.refresh(g.entry)
|
||||||
from sx.sx_components import render_entry_optioned
|
from sx.sx_components import render_entry_optioned
|
||||||
html = render_entry_optioned(g.entry, g.calendar, day, month, year)
|
html = await render_entry_optioned(g.entry, g.calendar, day, month, year)
|
||||||
return sx_response(html + day_nav_oob + post_nav_oob)
|
return sx_response(html + day_nav_oob + post_nav_oob)
|
||||||
|
|
||||||
@bp.post("/decline/")
|
@bp.post("/decline/")
|
||||||
@@ -474,7 +474,7 @@ def register():
|
|||||||
# Re-read entry to get updated state
|
# Re-read entry to get updated state
|
||||||
await g.s.refresh(g.entry)
|
await g.s.refresh(g.entry)
|
||||||
from sx.sx_components import render_entry_optioned
|
from sx.sx_components import render_entry_optioned
|
||||||
html = render_entry_optioned(g.entry, g.calendar, day, month, year)
|
html = await render_entry_optioned(g.entry, g.calendar, day, month, year)
|
||||||
return sx_response(html + day_nav_oob + post_nav_oob)
|
return sx_response(html + day_nav_oob + post_nav_oob)
|
||||||
|
|
||||||
@bp.post("/provisional/")
|
@bp.post("/provisional/")
|
||||||
@@ -499,7 +499,7 @@ def register():
|
|||||||
# Re-read entry to get updated state
|
# Re-read entry to get updated state
|
||||||
await g.s.refresh(g.entry)
|
await g.s.refresh(g.entry)
|
||||||
from sx.sx_components import render_entry_optioned
|
from sx.sx_components import render_entry_optioned
|
||||||
html = render_entry_optioned(g.entry, g.calendar, day, month, year)
|
html = await render_entry_optioned(g.entry, g.calendar, day, month, year)
|
||||||
return sx_response(html + day_nav_oob + post_nav_oob)
|
return sx_response(html + day_nav_oob + post_nav_oob)
|
||||||
|
|
||||||
@bp.post("/tickets/")
|
@bp.post("/tickets/")
|
||||||
@@ -543,7 +543,7 @@ def register():
|
|||||||
# Return just the tickets fragment (targeted by hx-target="#entry-tickets-...")
|
# Return just the tickets fragment (targeted by hx-target="#entry-tickets-...")
|
||||||
await g.s.refresh(g.entry)
|
await g.s.refresh(g.entry)
|
||||||
from sx.sx_components import render_entry_tickets_config
|
from sx.sx_components import render_entry_tickets_config
|
||||||
html = render_entry_tickets_config(g.entry, g.calendar, request.view_args.get("day"), request.view_args.get("month"), request.view_args.get("year"))
|
html = await render_entry_tickets_config(g.entry, g.calendar, request.view_args.get("day"), request.view_args.get("month"), request.view_args.get("year"))
|
||||||
return sx_response(html)
|
return sx_response(html)
|
||||||
|
|
||||||
@bp.get("/posts/search/")
|
@bp.get("/posts/search/")
|
||||||
@@ -559,7 +559,7 @@ def register():
|
|||||||
|
|
||||||
va = request.view_args or {}
|
va = request.view_args or {}
|
||||||
from sx.sx_components import render_post_search_results
|
from sx.sx_components import render_post_search_results
|
||||||
return sx_response(render_post_search_results(
|
return sx_response(await render_post_search_results(
|
||||||
search_posts, query, page, total_pages,
|
search_posts, query, page, total_pages,
|
||||||
g.entry, g.calendar,
|
g.entry, g.calendar,
|
||||||
va.get("day"), va.get("month"), va.get("year"),
|
va.get("day"), va.get("month"), va.get("year"),
|
||||||
@@ -594,8 +594,8 @@ def register():
|
|||||||
# Return updated posts list + OOB nav update
|
# Return updated posts list + OOB nav update
|
||||||
from sx.sx_components import render_entry_posts_panel, render_entry_posts_nav_oob
|
from sx.sx_components import render_entry_posts_panel, render_entry_posts_nav_oob
|
||||||
va = request.view_args or {}
|
va = request.view_args or {}
|
||||||
html = render_entry_posts_panel(entry_posts, g.entry, g.calendar, va.get("day"), va.get("month"), va.get("year"))
|
html = await render_entry_posts_panel(entry_posts, g.entry, g.calendar, va.get("day"), va.get("month"), va.get("year"))
|
||||||
nav_oob = render_entry_posts_nav_oob(entry_posts)
|
nav_oob = await render_entry_posts_nav_oob(entry_posts)
|
||||||
return sx_response(html + nav_oob)
|
return sx_response(html + nav_oob)
|
||||||
|
|
||||||
@bp.delete("/posts/<int:post_id>/")
|
@bp.delete("/posts/<int:post_id>/")
|
||||||
@@ -616,8 +616,8 @@ def register():
|
|||||||
# Return updated posts list + OOB nav update
|
# Return updated posts list + OOB nav update
|
||||||
from sx.sx_components import render_entry_posts_panel, render_entry_posts_nav_oob
|
from sx.sx_components import render_entry_posts_panel, render_entry_posts_nav_oob
|
||||||
va = request.view_args or {}
|
va = request.view_args or {}
|
||||||
html = render_entry_posts_panel(entry_posts, g.entry, g.calendar, va.get("day"), va.get("month"), va.get("year"))
|
html = await render_entry_posts_panel(entry_posts, g.entry, g.calendar, va.get("day"), va.get("month"), va.get("year"))
|
||||||
nav_oob = render_entry_posts_nav_oob(entry_posts)
|
nav_oob = await render_entry_posts_nav_oob(entry_posts)
|
||||||
return sx_response(html + nav_oob)
|
return sx_response(html + nav_oob)
|
||||||
|
|
||||||
return bp
|
return bp
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ def register():
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import render_calendars_list_panel
|
from sx.sx_components import render_calendars_list_panel
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
html = render_calendars_list_panel(ctx)
|
html = await render_calendars_list_panel(ctx)
|
||||||
|
|
||||||
# Blog-embedded mode: also update post nav
|
# Blog-embedded mode: also update post nav
|
||||||
if post_data:
|
if post_data:
|
||||||
@@ -85,7 +85,7 @@ def register():
|
|||||||
).scalars().all()
|
).scalars().all()
|
||||||
|
|
||||||
associated_entries = await get_associated_entries(post_id)
|
associated_entries = await get_associated_entries(post_id)
|
||||||
nav_oob = render_post_nav_entries_oob(associated_entries, cals, post_data["post"])
|
nav_oob = await render_post_nav_entries_oob(associated_entries, cals, post_data["post"])
|
||||||
html = html + nav_oob
|
html = html + nav_oob
|
||||||
|
|
||||||
return sx_response(html)
|
return sx_response(html)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ def register():
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import render_markets_list_panel
|
from sx.sx_components import render_markets_list_panel
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
return sx_response(render_markets_list_panel(ctx))
|
return sx_response(await render_markets_list_panel(ctx))
|
||||||
|
|
||||||
@bp.delete("/<market_slug>/")
|
@bp.delete("/<market_slug>/")
|
||||||
@require_admin
|
@require_admin
|
||||||
@@ -57,6 +57,6 @@ def register():
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import render_markets_list_panel
|
from sx.sx_components import render_markets_list_panel
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
return sx_response(render_markets_list_panel(ctx))
|
return sx_response(await render_markets_list_panel(ctx))
|
||||||
|
|
||||||
return bp
|
return bp
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ def register() -> Blueprint:
|
|||||||
frag_params["session_id"] = ident["session_id"]
|
frag_params["session_id"] = ident["session_id"]
|
||||||
|
|
||||||
from sx.sx_components import render_ticket_widget
|
from sx.sx_components import render_ticket_widget
|
||||||
widget_html = render_ticket_widget(entry, qty, f"/{g.post_slug}/tickets/adjust")
|
widget_html = await render_ticket_widget(entry, qty, f"/{g.post_slug}/tickets/adjust")
|
||||||
mini_html = await fetch_fragment("cart", "cart-mini", params=frag_params, required=False)
|
mini_html = await fetch_fragment("cart", "cart-mini", params=frag_params, required=False)
|
||||||
return sx_response(widget_html + (mini_html or ""))
|
return sx_response(widget_html + (mini_html or ""))
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ def register():
|
|||||||
if not slot:
|
if not slot:
|
||||||
return await make_response("Not found", 404)
|
return await make_response("Not found", 404)
|
||||||
from sx.sx_components import render_slot_edit_form
|
from sx.sx_components import render_slot_edit_form
|
||||||
return sx_response(render_slot_edit_form(slot, g.calendar))
|
return sx_response(await render_slot_edit_form(slot, g.calendar))
|
||||||
|
|
||||||
@bp.get("/view/")
|
@bp.get("/view/")
|
||||||
@require_admin
|
@require_admin
|
||||||
@@ -45,7 +45,7 @@ def register():
|
|||||||
if not slot:
|
if not slot:
|
||||||
return await make_response("Not found", 404)
|
return await make_response("Not found", 404)
|
||||||
from sx.sx_components import render_slot_main_panel
|
from sx.sx_components import render_slot_main_panel
|
||||||
return sx_response(render_slot_main_panel(slot, g.calendar))
|
return sx_response(await render_slot_main_panel(slot, g.calendar))
|
||||||
|
|
||||||
@bp.delete("/")
|
@bp.delete("/")
|
||||||
@require_admin
|
@require_admin
|
||||||
@@ -54,7 +54,7 @@ def register():
|
|||||||
await svc_delete_slot(g.s, slot_id)
|
await svc_delete_slot(g.s, slot_id)
|
||||||
slots = await svc_list_slots(g.s, g.calendar.id)
|
slots = await svc_list_slots(g.s, g.calendar.id)
|
||||||
from sx.sx_components import render_slots_table
|
from sx.sx_components import render_slots_table
|
||||||
return sx_response(render_slots_table(slots, g.calendar))
|
return sx_response(await render_slots_table(slots, g.calendar))
|
||||||
|
|
||||||
@bp.put("/")
|
@bp.put("/")
|
||||||
@require_admin
|
@require_admin
|
||||||
@@ -136,7 +136,7 @@ def register():
|
|||||||
), 422
|
), 422
|
||||||
|
|
||||||
from sx.sx_components import render_slot_main_panel
|
from sx.sx_components import render_slot_main_panel
|
||||||
return sx_response(render_slot_main_panel(slot, g.calendar, oob=True))
|
return sx_response(await render_slot_main_panel(slot, g.calendar, oob=True))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -111,19 +111,19 @@ def register():
|
|||||||
# Success → re-render the slots table
|
# Success → re-render the slots table
|
||||||
slots = await svc_list_slots(g.s, g.calendar.id)
|
slots = await svc_list_slots(g.s, g.calendar.id)
|
||||||
from sx.sx_components import render_slots_table
|
from sx.sx_components import render_slots_table
|
||||||
return sx_response(render_slots_table(slots, g.calendar))
|
return sx_response(await render_slots_table(slots, g.calendar))
|
||||||
|
|
||||||
|
|
||||||
@bp.get("/add")
|
@bp.get("/add")
|
||||||
@require_admin
|
@require_admin
|
||||||
async def add_form(**kwargs):
|
async def add_form(**kwargs):
|
||||||
from sx.sx_components import render_slot_add_form
|
from sx.sx_components import render_slot_add_form
|
||||||
return sx_response(render_slot_add_form(g.calendar))
|
return sx_response(await render_slot_add_form(g.calendar))
|
||||||
|
|
||||||
@bp.get("/add-button")
|
@bp.get("/add-button")
|
||||||
@require_admin
|
@require_admin
|
||||||
async def add_button(**kwargs):
|
async def add_button(**kwargs):
|
||||||
from sx.sx_components import render_slot_add_button
|
from sx.sx_components import render_slot_add_button
|
||||||
return sx_response(render_slot_add_button(g.calendar))
|
return sx_response(await render_slot_add_button(g.calendar))
|
||||||
|
|
||||||
return bp
|
return bp
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ def register() -> Blueprint:
|
|||||||
tickets = await get_tickets_for_entry(g.s, entry_id)
|
tickets = await get_tickets_for_entry(g.s, entry_id)
|
||||||
|
|
||||||
from sx.sx_components import render_entry_tickets_admin
|
from sx.sx_components import render_entry_tickets_admin
|
||||||
html = render_entry_tickets_admin(entry, tickets)
|
html = await render_entry_tickets_admin(entry, tickets)
|
||||||
return sx_response(html)
|
return sx_response(html)
|
||||||
|
|
||||||
@bp.get("/lookup/")
|
@bp.get("/lookup/")
|
||||||
@@ -71,9 +71,9 @@ def register() -> Blueprint:
|
|||||||
ticket = await get_ticket_by_code(g.s, code)
|
ticket = await get_ticket_by_code(g.s, code)
|
||||||
from sx.sx_components import render_lookup_result
|
from sx.sx_components import render_lookup_result
|
||||||
if not ticket:
|
if not ticket:
|
||||||
return sx_response(render_lookup_result(None, "Ticket not found"))
|
return sx_response(await render_lookup_result(None, "Ticket not found"))
|
||||||
|
|
||||||
return sx_response(render_lookup_result(ticket, None))
|
return sx_response(await render_lookup_result(ticket, None))
|
||||||
|
|
||||||
@bp.post("/<code>/checkin/")
|
@bp.post("/<code>/checkin/")
|
||||||
@require_admin
|
@require_admin
|
||||||
@@ -84,9 +84,9 @@ def register() -> Blueprint:
|
|||||||
|
|
||||||
from sx.sx_components import render_checkin_result
|
from sx.sx_components import render_checkin_result
|
||||||
if not success:
|
if not success:
|
||||||
return sx_response(render_checkin_result(False, error, None))
|
return sx_response(await render_checkin_result(False, error, None))
|
||||||
|
|
||||||
ticket = await get_ticket_by_code(g.s, code)
|
ticket = await get_ticket_by_code(g.s, code)
|
||||||
return sx_response(render_checkin_result(True, None, ticket))
|
return sx_response(await render_checkin_result(True, None, ticket))
|
||||||
|
|
||||||
return bp
|
return bp
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ def register():
|
|||||||
|
|
||||||
from sx.sx_components import render_ticket_type_edit_form
|
from sx.sx_components import render_ticket_type_edit_form
|
||||||
va = request.view_args or {}
|
va = request.view_args or {}
|
||||||
return sx_response(render_ticket_type_edit_form(
|
return sx_response(await render_ticket_type_edit_form(
|
||||||
ticket_type, g.entry, g.calendar,
|
ticket_type, g.entry, g.calendar,
|
||||||
va.get("day"), va.get("month"), va.get("year"),
|
va.get("day"), va.get("month"), va.get("year"),
|
||||||
))
|
))
|
||||||
@@ -47,7 +47,7 @@ def register():
|
|||||||
|
|
||||||
from sx.sx_components import render_ticket_type_main_panel
|
from sx.sx_components import render_ticket_type_main_panel
|
||||||
va = request.view_args or {}
|
va = request.view_args or {}
|
||||||
return sx_response(render_ticket_type_main_panel(
|
return sx_response(await render_ticket_type_main_panel(
|
||||||
ticket_type, g.entry, g.calendar,
|
ticket_type, g.entry, g.calendar,
|
||||||
va.get("day"), va.get("month"), va.get("year"),
|
va.get("day"), va.get("month"), va.get("year"),
|
||||||
))
|
))
|
||||||
@@ -114,7 +114,7 @@ def register():
|
|||||||
# Return updated view with OOB flag
|
# Return updated view with OOB flag
|
||||||
from sx.sx_components import render_ticket_type_main_panel
|
from sx.sx_components import render_ticket_type_main_panel
|
||||||
va = request.view_args or {}
|
va = request.view_args or {}
|
||||||
return sx_response(render_ticket_type_main_panel(
|
return sx_response(await render_ticket_type_main_panel(
|
||||||
ticket_type, g.entry, g.calendar,
|
ticket_type, g.entry, g.calendar,
|
||||||
va.get("day"), va.get("month"), va.get("year"),
|
va.get("day"), va.get("month"), va.get("year"),
|
||||||
oob=True,
|
oob=True,
|
||||||
@@ -133,7 +133,7 @@ def register():
|
|||||||
ticket_types = await svc_list_ticket_types(g.s, g.entry.id)
|
ticket_types = await svc_list_ticket_types(g.s, g.entry.id)
|
||||||
from sx.sx_components import render_ticket_types_table
|
from sx.sx_components import render_ticket_types_table
|
||||||
va = request.view_args or {}
|
va = request.view_args or {}
|
||||||
return sx_response(render_ticket_types_table(
|
return sx_response(await render_ticket_types_table(
|
||||||
ticket_types, g.entry, g.calendar,
|
ticket_types, g.entry, g.calendar,
|
||||||
va.get("day"), va.get("month"), va.get("year"),
|
va.get("day"), va.get("month"), va.get("year"),
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ def register():
|
|||||||
ticket_types = await svc_list_ticket_types(g.s, g.entry.id)
|
ticket_types = await svc_list_ticket_types(g.s, g.entry.id)
|
||||||
from sx.sx_components import render_ticket_types_table
|
from sx.sx_components import render_ticket_types_table
|
||||||
va = request.view_args or {}
|
va = request.view_args or {}
|
||||||
return sx_response(render_ticket_types_table(
|
return sx_response(await render_ticket_types_table(
|
||||||
ticket_types, g.entry, g.calendar,
|
ticket_types, g.entry, g.calendar,
|
||||||
va.get("day"), va.get("month"), va.get("year"),
|
va.get("day"), va.get("month"), va.get("year"),
|
||||||
))
|
))
|
||||||
@@ -106,7 +106,7 @@ def register():
|
|||||||
"""Show the add ticket type form."""
|
"""Show the add ticket type form."""
|
||||||
from sx.sx_components import render_ticket_type_add_form
|
from sx.sx_components import render_ticket_type_add_form
|
||||||
va = request.view_args or {}
|
va = request.view_args or {}
|
||||||
return sx_response(render_ticket_type_add_form(
|
return sx_response(await render_ticket_type_add_form(
|
||||||
g.entry, g.calendar,
|
g.entry, g.calendar,
|
||||||
va.get("day"), va.get("month"), va.get("year"),
|
va.get("day"), va.get("month"), va.get("year"),
|
||||||
))
|
))
|
||||||
@@ -117,7 +117,7 @@ def register():
|
|||||||
"""Show the add ticket type button."""
|
"""Show the add ticket type button."""
|
||||||
from sx.sx_components import render_ticket_type_add_button
|
from sx.sx_components import render_ticket_type_add_button
|
||||||
va = request.view_args or {}
|
va = request.view_args or {}
|
||||||
return sx_response(render_ticket_type_add_button(
|
return sx_response(await render_ticket_type_add_button(
|
||||||
g.entry, g.calendar,
|
g.entry, g.calendar,
|
||||||
va.get("day"), va.get("month"), va.get("year"),
|
va.get("day"), va.get("month"), va.get("year"),
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ def register() -> Blueprint:
|
|||||||
cart_count = summary.count + summary.calendar_count + summary.ticket_count
|
cart_count = summary.count + summary.calendar_count + summary.ticket_count
|
||||||
|
|
||||||
from sx.sx_components import render_buy_result
|
from sx.sx_components import render_buy_result
|
||||||
return sx_response(render_buy_result(entry, created, remaining, cart_count))
|
return sx_response(await render_buy_result(entry, created, remaining, cart_count))
|
||||||
|
|
||||||
@bp.post("/adjust/")
|
@bp.post("/adjust/")
|
||||||
@clear_cache(tag="calendars", tag_scope="all")
|
@clear_cache(tag="calendars", tag_scope="all")
|
||||||
@@ -250,7 +250,7 @@ def register() -> Blueprint:
|
|||||||
cart_count = summary.count + summary.calendar_count + summary.ticket_count
|
cart_count = summary.count + summary.calendar_count + summary.ticket_count
|
||||||
|
|
||||||
from sx.sx_components import render_adjust_response
|
from sx.sx_components import render_adjust_response
|
||||||
return sx_response(render_adjust_response(
|
return sx_response(await render_adjust_response(
|
||||||
entry, ticket_remaining, ticket_sold_count,
|
entry, ticket_remaining, ticket_sold_count,
|
||||||
user_ticket_count, user_ticket_counts_by_type, cart_count,
|
user_ticket_count, user_ticket_counts_by_type, cart_count,
|
||||||
))
|
))
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -44,11 +44,11 @@ async def _cal_admin_full(ctx: dict, **kw: Any) -> str:
|
|||||||
)
|
)
|
||||||
ctx = await _ensure_container_nav(ctx)
|
ctx = await _ensure_container_nav(ctx)
|
||||||
slug = (ctx.get("post") or {}).get("slug", "")
|
slug = (ctx.get("post") or {}).get("slug", "")
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
post_hdr = _post_header_sx(ctx)
|
post_hdr = await _post_header_sx(ctx)
|
||||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
admin_hdr = await post_admin_header_sx(ctx, slug, selected="calendars")
|
||||||
child = admin_hdr + _calendar_header_sx(ctx) + _calendar_admin_header_sx(ctx)
|
child = admin_hdr + await _calendar_header_sx(ctx) + await _calendar_admin_header_sx(ctx)
|
||||||
return root_hdr + post_hdr + header_child_sx(child)
|
return root_hdr + post_hdr + await header_child_sx(child)
|
||||||
|
|
||||||
|
|
||||||
async def _cal_admin_oob(ctx: dict, **kw: Any) -> str:
|
async def _cal_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||||
@@ -59,10 +59,10 @@ async def _cal_admin_oob(ctx: dict, **kw: Any) -> str:
|
|||||||
)
|
)
|
||||||
ctx = await _ensure_container_nav(ctx)
|
ctx = await _ensure_container_nav(ctx)
|
||||||
slug = (ctx.get("post") or {}).get("slug", "")
|
slug = (ctx.get("post") or {}).get("slug", "")
|
||||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
oobs = (await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||||
+ _calendar_header_sx(ctx, oob=True))
|
+ await _calendar_header_sx(ctx, oob=True))
|
||||||
oobs += oob_header_sx("calendar-header-child", "calendar-admin-header-child",
|
oobs += await oob_header_sx("calendar-header-child", "calendar-admin-header-child",
|
||||||
_calendar_admin_header_sx(ctx))
|
await _calendar_admin_header_sx(ctx))
|
||||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||||
"post-admin-row", "post-admin-header-child",
|
"post-admin-row", "post-admin-header-child",
|
||||||
"calendar-row", "calendar-header-child",
|
"calendar-row", "calendar-header-child",
|
||||||
@@ -83,8 +83,8 @@ async def _slots_oob(ctx: dict, **kw: Any) -> str:
|
|||||||
)
|
)
|
||||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||||
slug = (ctx.get("post") or {}).get("slug", "")
|
slug = (ctx.get("post") or {}).get("slug", "")
|
||||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
oobs = (await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||||
+ _calendar_admin_header_sx(ctx, oob=True))
|
+ await _calendar_admin_header_sx(ctx, oob=True))
|
||||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||||
"post-admin-row", "post-admin-header-child",
|
"post-admin-row", "post-admin-header-child",
|
||||||
"calendar-row", "calendar-header-child",
|
"calendar-row", "calendar-header-child",
|
||||||
@@ -102,12 +102,12 @@ async def _slot_full(ctx: dict, **kw: Any) -> str:
|
|||||||
)
|
)
|
||||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||||
slug = (ctx.get("post") or {}).get("slug", "")
|
slug = (ctx.get("post") or {}).get("slug", "")
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
post_hdr = _post_header_sx(ctx)
|
post_hdr = await _post_header_sx(ctx)
|
||||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
admin_hdr = await post_admin_header_sx(ctx, slug, selected="calendars")
|
||||||
child = (admin_hdr + _calendar_header_sx(ctx)
|
child = (admin_hdr + await _calendar_header_sx(ctx)
|
||||||
+ _calendar_admin_header_sx(ctx) + _slot_header_html(ctx))
|
+ await _calendar_admin_header_sx(ctx) + await _slot_header_html(ctx))
|
||||||
return root_hdr + post_hdr + header_child_sx(child)
|
return root_hdr + post_hdr + await header_child_sx(child)
|
||||||
|
|
||||||
|
|
||||||
async def _slot_oob(ctx: dict, **kw: Any) -> str:
|
async def _slot_oob(ctx: dict, **kw: Any) -> str:
|
||||||
@@ -118,10 +118,10 @@ async def _slot_oob(ctx: dict, **kw: Any) -> str:
|
|||||||
)
|
)
|
||||||
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
|
||||||
slug = (ctx.get("post") or {}).get("slug", "")
|
slug = (ctx.get("post") or {}).get("slug", "")
|
||||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
oobs = (await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||||
+ _calendar_admin_header_sx(ctx, oob=True))
|
+ await _calendar_admin_header_sx(ctx, oob=True))
|
||||||
oobs += oob_header_sx("calendar-admin-header-child", "slot-header-child",
|
oobs += await oob_header_sx("calendar-admin-header-child", "slot-header-child",
|
||||||
_slot_header_html(ctx))
|
await _slot_header_html(ctx))
|
||||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||||
"post-admin-row", "post-admin-header-child",
|
"post-admin-row", "post-admin-header-child",
|
||||||
"calendar-row", "calendar-header-child",
|
"calendar-row", "calendar-header-child",
|
||||||
@@ -140,12 +140,12 @@ async def _day_admin_full(ctx: dict, **kw: Any) -> str:
|
|||||||
)
|
)
|
||||||
ctx = await _ensure_container_nav(ctx)
|
ctx = await _ensure_container_nav(ctx)
|
||||||
slug = (ctx.get("post") or {}).get("slug", "")
|
slug = (ctx.get("post") or {}).get("slug", "")
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
post_hdr = _post_header_sx(ctx)
|
post_hdr = await _post_header_sx(ctx)
|
||||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
admin_hdr = await post_admin_header_sx(ctx, slug, selected="calendars")
|
||||||
child = (admin_hdr + _calendar_header_sx(ctx) + _day_header_sx(ctx)
|
child = (admin_hdr + await _calendar_header_sx(ctx) + await _day_header_sx(ctx)
|
||||||
+ _day_admin_header_sx(ctx))
|
+ await _day_admin_header_sx(ctx))
|
||||||
return root_hdr + post_hdr + header_child_sx(child)
|
return root_hdr + post_hdr + await header_child_sx(child)
|
||||||
|
|
||||||
|
|
||||||
async def _day_admin_oob(ctx: dict, **kw: Any) -> str:
|
async def _day_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||||
@@ -156,10 +156,10 @@ async def _day_admin_oob(ctx: dict, **kw: Any) -> str:
|
|||||||
)
|
)
|
||||||
ctx = await _ensure_container_nav(ctx)
|
ctx = await _ensure_container_nav(ctx)
|
||||||
slug = (ctx.get("post") or {}).get("slug", "")
|
slug = (ctx.get("post") or {}).get("slug", "")
|
||||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
oobs = (await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||||
+ _calendar_header_sx(ctx, oob=True))
|
+ await _calendar_header_sx(ctx, oob=True))
|
||||||
oobs += oob_header_sx("day-header-child", "day-admin-header-child",
|
oobs += await oob_header_sx("day-header-child", "day-admin-header-child",
|
||||||
_day_admin_header_sx(ctx))
|
await _day_admin_header_sx(ctx))
|
||||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||||
"post-admin-row", "post-admin-header-child",
|
"post-admin-row", "post-admin-header-child",
|
||||||
"calendar-row", "calendar-header-child",
|
"calendar-row", "calendar-header-child",
|
||||||
@@ -170,26 +170,26 @@ async def _day_admin_oob(ctx: dict, **kw: Any) -> str:
|
|||||||
|
|
||||||
# --- Entry layout (root + child(post + cal + day + entry), + menu) ---
|
# --- Entry layout (root + child(post + cal + day + entry), + menu) ---
|
||||||
|
|
||||||
def _entry_full(ctx: dict, **kw: Any) -> str:
|
async def _entry_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, header_child_sx
|
from shared.sx.helpers import root_header_sx, header_child_sx
|
||||||
from sx.sx_components import (
|
from sx.sx_components import (
|
||||||
_post_header_sx, _calendar_header_sx,
|
_post_header_sx, _calendar_header_sx,
|
||||||
_day_header_sx, _entry_header_html,
|
_day_header_sx, _entry_header_html,
|
||||||
)
|
)
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
child = (_post_header_sx(ctx) + _calendar_header_sx(ctx)
|
child = (await _post_header_sx(ctx) + await _calendar_header_sx(ctx)
|
||||||
+ _day_header_sx(ctx) + _entry_header_html(ctx))
|
+ await _day_header_sx(ctx) + await _entry_header_html(ctx))
|
||||||
return root_hdr + header_child_sx(child)
|
return root_hdr + await header_child_sx(child)
|
||||||
|
|
||||||
|
|
||||||
def _entry_oob(ctx: dict, **kw: Any) -> str:
|
async def _entry_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import oob_header_sx
|
from shared.sx.helpers import oob_header_sx
|
||||||
from sx.sx_components import (
|
from sx.sx_components import (
|
||||||
_day_header_sx, _entry_header_html, _clear_deeper_oob,
|
_day_header_sx, _entry_header_html, _clear_deeper_oob,
|
||||||
)
|
)
|
||||||
oobs = _day_header_sx(ctx, oob=True)
|
oobs = await _day_header_sx(ctx, oob=True)
|
||||||
oobs += oob_header_sx("day-header-child", "entry-header-child",
|
oobs += await oob_header_sx("day-header-child", "entry-header-child",
|
||||||
_entry_header_html(ctx))
|
await _entry_header_html(ctx))
|
||||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||||
"calendar-row", "calendar-header-child",
|
"calendar-row", "calendar-header-child",
|
||||||
"day-row", "day-header-child",
|
"day-row", "day-header-child",
|
||||||
@@ -208,12 +208,12 @@ async def _entry_admin_full(ctx: dict, **kw: Any) -> str:
|
|||||||
)
|
)
|
||||||
ctx = await _ensure_container_nav(ctx)
|
ctx = await _ensure_container_nav(ctx)
|
||||||
slug = (ctx.get("post") or {}).get("slug", "")
|
slug = (ctx.get("post") or {}).get("slug", "")
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
post_hdr = _post_header_sx(ctx)
|
post_hdr = await _post_header_sx(ctx)
|
||||||
admin_hdr = post_admin_header_sx(ctx, slug, selected="calendars")
|
admin_hdr = await post_admin_header_sx(ctx, slug, selected="calendars")
|
||||||
child = (admin_hdr + _calendar_header_sx(ctx) + _day_header_sx(ctx)
|
child = (admin_hdr + await _calendar_header_sx(ctx) + await _day_header_sx(ctx)
|
||||||
+ _entry_header_html(ctx) + _entry_admin_header_html(ctx))
|
+ await _entry_header_html(ctx) + await _entry_admin_header_html(ctx))
|
||||||
return root_hdr + post_hdr + header_child_sx(child)
|
return root_hdr + post_hdr + await header_child_sx(child)
|
||||||
|
|
||||||
|
|
||||||
async def _entry_admin_oob(ctx: dict, **kw: Any) -> str:
|
async def _entry_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||||
@@ -224,10 +224,10 @@ async def _entry_admin_oob(ctx: dict, **kw: Any) -> str:
|
|||||||
)
|
)
|
||||||
ctx = await _ensure_container_nav(ctx)
|
ctx = await _ensure_container_nav(ctx)
|
||||||
slug = (ctx.get("post") or {}).get("slug", "")
|
slug = (ctx.get("post") or {}).get("slug", "")
|
||||||
oobs = (post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
oobs = (await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")
|
||||||
+ _entry_header_html(ctx, oob=True))
|
+ await _entry_header_html(ctx, oob=True))
|
||||||
oobs += oob_header_sx("entry-header-child", "entry-admin-header-child",
|
oobs += await oob_header_sx("entry-header-child", "entry-admin-header-child",
|
||||||
_entry_admin_header_html(ctx))
|
await _entry_admin_header_html(ctx))
|
||||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||||
"post-admin-row", "post-admin-header-child",
|
"post-admin-row", "post-admin-header-child",
|
||||||
"calendar-row", "calendar-header-child",
|
"calendar-row", "calendar-header-child",
|
||||||
@@ -239,75 +239,75 @@ async def _entry_admin_oob(ctx: dict, **kw: Any) -> str:
|
|||||||
|
|
||||||
# --- Ticket types layout (extends entry admin with ticket-types header, + menu) ---
|
# --- Ticket types layout (extends entry admin with ticket-types header, + menu) ---
|
||||||
|
|
||||||
def _ticket_types_full(ctx: dict, **kw: Any) -> str:
|
async def _ticket_types_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, header_child_sx
|
from shared.sx.helpers import root_header_sx, header_child_sx
|
||||||
from sx.sx_components import (
|
from sx.sx_components import (
|
||||||
_post_header_sx, _calendar_header_sx, _day_header_sx,
|
_post_header_sx, _calendar_header_sx, _day_header_sx,
|
||||||
_entry_header_html, _entry_admin_header_html,
|
_entry_header_html, _entry_admin_header_html,
|
||||||
_ticket_types_header_html,
|
_ticket_types_header_html,
|
||||||
)
|
)
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
child = (_post_header_sx(ctx) + _calendar_header_sx(ctx)
|
child = (await _post_header_sx(ctx) + await _calendar_header_sx(ctx)
|
||||||
+ _day_header_sx(ctx) + _entry_header_html(ctx)
|
+ await _day_header_sx(ctx) + await _entry_header_html(ctx)
|
||||||
+ _entry_admin_header_html(ctx) + _ticket_types_header_html(ctx))
|
+ await _entry_admin_header_html(ctx) + await _ticket_types_header_html(ctx))
|
||||||
return root_hdr + header_child_sx(child)
|
return root_hdr + await header_child_sx(child)
|
||||||
|
|
||||||
|
|
||||||
def _ticket_types_oob(ctx: dict, **kw: Any) -> str:
|
async def _ticket_types_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import oob_header_sx
|
from shared.sx.helpers import oob_header_sx
|
||||||
from sx.sx_components import (
|
from sx.sx_components import (
|
||||||
_entry_admin_header_html, _ticket_types_header_html, _clear_deeper_oob,
|
_entry_admin_header_html, _ticket_types_header_html, _clear_deeper_oob,
|
||||||
)
|
)
|
||||||
oobs = _entry_admin_header_html(ctx, oob=True)
|
oobs = await _entry_admin_header_html(ctx, oob=True)
|
||||||
oobs += oob_header_sx("entry-admin-header-child", "ticket_types-header-child",
|
oobs += await oob_header_sx("entry-admin-header-child", "ticket_types-header-child",
|
||||||
_ticket_types_header_html(ctx))
|
await _ticket_types_header_html(ctx))
|
||||||
return oobs
|
return oobs
|
||||||
|
|
||||||
|
|
||||||
# --- Ticket type detail layout (extends ticket types with ticket-type header, + menu) ---
|
# --- Ticket type detail layout (extends ticket types with ticket-type header, + menu) ---
|
||||||
|
|
||||||
def _ticket_type_full(ctx: dict, **kw: Any) -> str:
|
async def _ticket_type_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, header_child_sx
|
from shared.sx.helpers import root_header_sx, header_child_sx
|
||||||
from sx.sx_components import (
|
from sx.sx_components import (
|
||||||
_post_header_sx, _calendar_header_sx, _day_header_sx,
|
_post_header_sx, _calendar_header_sx, _day_header_sx,
|
||||||
_entry_header_html, _entry_admin_header_html,
|
_entry_header_html, _entry_admin_header_html,
|
||||||
_ticket_types_header_html, _ticket_type_header_html,
|
_ticket_types_header_html, _ticket_type_header_html,
|
||||||
)
|
)
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
child = (_post_header_sx(ctx) + _calendar_header_sx(ctx)
|
child = (await _post_header_sx(ctx) + await _calendar_header_sx(ctx)
|
||||||
+ _day_header_sx(ctx) + _entry_header_html(ctx)
|
+ await _day_header_sx(ctx) + await _entry_header_html(ctx)
|
||||||
+ _entry_admin_header_html(ctx) + _ticket_types_header_html(ctx)
|
+ await _entry_admin_header_html(ctx) + await _ticket_types_header_html(ctx)
|
||||||
+ _ticket_type_header_html(ctx))
|
+ await _ticket_type_header_html(ctx))
|
||||||
return root_hdr + header_child_sx(child)
|
return root_hdr + await header_child_sx(child)
|
||||||
|
|
||||||
|
|
||||||
def _ticket_type_oob(ctx: dict, **kw: Any) -> str:
|
async def _ticket_type_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import oob_header_sx
|
from shared.sx.helpers import oob_header_sx
|
||||||
from sx.sx_components import (
|
from sx.sx_components import (
|
||||||
_ticket_types_header_html, _ticket_type_header_html,
|
_ticket_types_header_html, _ticket_type_header_html,
|
||||||
)
|
)
|
||||||
oobs = _ticket_types_header_html(ctx, oob=True)
|
oobs = await _ticket_types_header_html(ctx, oob=True)
|
||||||
oobs += oob_header_sx("ticket_types-header-child", "ticket_type-header-child",
|
oobs += await oob_header_sx("ticket_types-header-child", "ticket_type-header-child",
|
||||||
_ticket_type_header_html(ctx))
|
await _ticket_type_header_html(ctx))
|
||||||
return oobs
|
return oobs
|
||||||
|
|
||||||
|
|
||||||
# --- Markets layout (root + child(post + markets)) ---
|
# --- Markets layout (root + child(post + markets)) ---
|
||||||
|
|
||||||
def _markets_full(ctx: dict, **kw: Any) -> str:
|
async def _markets_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, header_child_sx
|
from shared.sx.helpers import root_header_sx, header_child_sx
|
||||||
from sx.sx_components import _post_header_sx, _markets_header_sx
|
from sx.sx_components import _post_header_sx, _markets_header_sx
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
child = _post_header_sx(ctx) + _markets_header_sx(ctx)
|
child = await _post_header_sx(ctx) + await _markets_header_sx(ctx)
|
||||||
return root_hdr + header_child_sx(child)
|
return root_hdr + await header_child_sx(child)
|
||||||
|
|
||||||
|
|
||||||
def _markets_oob(ctx: dict, **kw: Any) -> str:
|
async def _markets_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import oob_header_sx
|
from shared.sx.helpers import oob_header_sx
|
||||||
from sx.sx_components import _post_header_sx, _markets_header_sx
|
from sx.sx_components import _post_header_sx, _markets_header_sx
|
||||||
oobs = _post_header_sx(ctx, oob=True)
|
oobs = await _post_header_sx(ctx, oob=True)
|
||||||
oobs += oob_header_sx("post-header-child", "markets-header-child",
|
oobs += await oob_header_sx("post-header-child", "markets-header-child",
|
||||||
_markets_header_sx(ctx))
|
await _markets_header_sx(ctx))
|
||||||
return oobs
|
return oobs
|
||||||
|
|
||||||
|
|
||||||
@@ -518,7 +518,7 @@ async def _h_calendar_admin_content(calendar_slug=None, **kw):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import _calendar_admin_main_panel_html
|
from sx.sx_components import _calendar_admin_main_panel_html
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
return _calendar_admin_main_panel_html(ctx)
|
return await _calendar_admin_main_panel_html(ctx)
|
||||||
|
|
||||||
|
|
||||||
async def _h_day_admin_content(calendar_slug=None, year=None, month=None, day=None, **kw):
|
async def _h_day_admin_content(calendar_slug=None, year=None, month=None, day=None, **kw):
|
||||||
@@ -526,7 +526,7 @@ async def _h_day_admin_content(calendar_slug=None, year=None, month=None, day=No
|
|||||||
if year is not None:
|
if year is not None:
|
||||||
await _ensure_day_data(int(year), int(month), int(day))
|
await _ensure_day_data(int(year), int(month), int(day))
|
||||||
from sx.sx_components import _day_admin_main_panel_html
|
from sx.sx_components import _day_admin_main_panel_html
|
||||||
return _day_admin_main_panel_html({})
|
return await _day_admin_main_panel_html({})
|
||||||
|
|
||||||
|
|
||||||
async def _h_slots_content(calendar_slug=None, **kw):
|
async def _h_slots_content(calendar_slug=None, **kw):
|
||||||
@@ -537,7 +537,7 @@ async def _h_slots_content(calendar_slug=None, **kw):
|
|||||||
slots = await svc_list_slots(g.s, calendar.id) if calendar else []
|
slots = await svc_list_slots(g.s, calendar.id) if calendar else []
|
||||||
_add_to_defpage_ctx(slots=slots)
|
_add_to_defpage_ctx(slots=slots)
|
||||||
from sx.sx_components import render_slots_table
|
from sx.sx_components import render_slots_table
|
||||||
return render_slots_table(slots, calendar)
|
return await render_slots_table(slots, calendar)
|
||||||
|
|
||||||
|
|
||||||
async def _h_slot_content(calendar_slug=None, slot_id=None, **kw):
|
async def _h_slot_content(calendar_slug=None, slot_id=None, **kw):
|
||||||
@@ -551,7 +551,7 @@ async def _h_slot_content(calendar_slug=None, slot_id=None, **kw):
|
|||||||
_add_to_defpage_ctx(slot=slot)
|
_add_to_defpage_ctx(slot=slot)
|
||||||
calendar = getattr(g, "calendar", None)
|
calendar = getattr(g, "calendar", None)
|
||||||
from sx.sx_components import render_slot_main_panel
|
from sx.sx_components import render_slot_main_panel
|
||||||
return render_slot_main_panel(slot, calendar)
|
return await render_slot_main_panel(slot, calendar)
|
||||||
|
|
||||||
|
|
||||||
async def _h_entry_content(calendar_slug=None, entry_id=None, **kw):
|
async def _h_entry_content(calendar_slug=None, entry_id=None, **kw):
|
||||||
@@ -560,7 +560,7 @@ async def _h_entry_content(calendar_slug=None, entry_id=None, **kw):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import _entry_main_panel_html
|
from sx.sx_components import _entry_main_panel_html
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
return _entry_main_panel_html(ctx)
|
return await _entry_main_panel_html(ctx)
|
||||||
|
|
||||||
|
|
||||||
async def _h_entry_menu(calendar_slug=None, entry_id=None, **kw):
|
async def _h_entry_menu(calendar_slug=None, entry_id=None, **kw):
|
||||||
@@ -569,7 +569,7 @@ async def _h_entry_menu(calendar_slug=None, entry_id=None, **kw):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import _entry_nav_html
|
from sx.sx_components import _entry_nav_html
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
return _entry_nav_html(ctx)
|
return await _entry_nav_html(ctx)
|
||||||
|
|
||||||
|
|
||||||
async def _h_entry_admin_content(calendar_slug=None, entry_id=None, **kw):
|
async def _h_entry_admin_content(calendar_slug=None, entry_id=None, **kw):
|
||||||
@@ -578,12 +578,12 @@ async def _h_entry_admin_content(calendar_slug=None, entry_id=None, **kw):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import _entry_admin_main_panel_html
|
from sx.sx_components import _entry_admin_main_panel_html
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
return _entry_admin_main_panel_html(ctx)
|
return await _entry_admin_main_panel_html(ctx)
|
||||||
|
|
||||||
|
|
||||||
def _h_admin_menu():
|
async def _h_admin_menu():
|
||||||
from shared.sx.helpers import sx_call
|
from shared.sx.helpers import render_to_sx
|
||||||
return sx_call("events-admin-placeholder-nav")
|
return await render_to_sx("events-admin-placeholder-nav")
|
||||||
|
|
||||||
|
|
||||||
async def _h_ticket_types_content(calendar_slug=None, entry_id=None,
|
async def _h_ticket_types_content(calendar_slug=None, entry_id=None,
|
||||||
@@ -597,7 +597,7 @@ async def _h_ticket_types_content(calendar_slug=None, entry_id=None,
|
|||||||
ticket_types = await svc_list_ticket_types(g.s, entry.id) if entry else []
|
ticket_types = await svc_list_ticket_types(g.s, entry.id) if entry else []
|
||||||
_add_to_defpage_ctx(ticket_types=ticket_types)
|
_add_to_defpage_ctx(ticket_types=ticket_types)
|
||||||
from sx.sx_components import render_ticket_types_table
|
from sx.sx_components import render_ticket_types_table
|
||||||
return render_ticket_types_table(ticket_types, entry, calendar, day, month, year)
|
return await render_ticket_types_table(ticket_types, entry, calendar, day, month, year)
|
||||||
|
|
||||||
|
|
||||||
async def _h_ticket_type_content(calendar_slug=None, entry_id=None,
|
async def _h_ticket_type_content(calendar_slug=None, entry_id=None,
|
||||||
@@ -614,7 +614,7 @@ async def _h_ticket_type_content(calendar_slug=None, entry_id=None,
|
|||||||
entry = getattr(g, "entry", None)
|
entry = getattr(g, "entry", None)
|
||||||
calendar = getattr(g, "calendar", None)
|
calendar = getattr(g, "calendar", None)
|
||||||
from sx.sx_components import render_ticket_type_main_panel
|
from sx.sx_components import render_ticket_type_main_panel
|
||||||
return render_ticket_type_main_panel(ticket_type, entry, calendar, day, month, year)
|
return await render_ticket_type_main_panel(ticket_type, entry, calendar, day, month, year)
|
||||||
|
|
||||||
|
|
||||||
async def _h_tickets_content(**kw):
|
async def _h_tickets_content(**kw):
|
||||||
@@ -630,7 +630,7 @@ async def _h_tickets_content(**kw):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import _tickets_main_panel_html
|
from sx.sx_components import _tickets_main_panel_html
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
return _tickets_main_panel_html(ctx, tickets)
|
return await _tickets_main_panel_html(ctx, tickets)
|
||||||
|
|
||||||
|
|
||||||
async def _h_ticket_detail_content(code=None, **kw):
|
async def _h_ticket_detail_content(code=None, **kw):
|
||||||
@@ -653,7 +653,7 @@ async def _h_ticket_detail_content(code=None, **kw):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import _ticket_detail_panel_html
|
from sx.sx_components import _ticket_detail_panel_html
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
return _ticket_detail_panel_html(ctx, ticket)
|
return await _ticket_detail_panel_html(ctx, ticket)
|
||||||
|
|
||||||
|
|
||||||
async def _h_ticket_admin_content(**kw):
|
async def _h_ticket_admin_content(**kw):
|
||||||
@@ -693,11 +693,11 @@ async def _h_ticket_admin_content(**kw):
|
|||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import _ticket_admin_main_panel_html
|
from sx.sx_components import _ticket_admin_main_panel_html
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
return _ticket_admin_main_panel_html(ctx, tickets, stats)
|
return await _ticket_admin_main_panel_html(ctx, tickets, stats)
|
||||||
|
|
||||||
|
|
||||||
async def _h_markets_content(**kw):
|
async def _h_markets_content(**kw):
|
||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
from sx.sx_components import _markets_main_panel_html
|
from sx.sx_components import _markets_main_panel_html
|
||||||
ctx = await get_template_context()
|
ctx = await get_template_context()
|
||||||
return _markets_main_panel_html(ctx)
|
return await _markets_main_panel_html(ctx)
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ def register(url_prefix="/social"):
|
|||||||
else:
|
else:
|
||||||
list_type = "following"
|
list_type = "following"
|
||||||
from sx.sx_components import render_actor_card
|
from sx.sx_components import render_actor_card
|
||||||
return sx_response(render_actor_card(remote_dto, actor, followed_urls, list_type=list_type))
|
return sx_response(await render_actor_card(remote_dto, actor, followed_urls, list_type=list_type))
|
||||||
|
|
||||||
# -- Interactions ----------------------------------------------------------
|
# -- Interactions ----------------------------------------------------------
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ def register(url_prefix="/social"):
|
|||||||
)).scalar())
|
)).scalar())
|
||||||
|
|
||||||
from sx.sx_components import render_interaction_buttons
|
from sx.sx_components import render_interaction_buttons
|
||||||
return sx_response(render_interaction_buttons(
|
return sx_response(await render_interaction_buttons(
|
||||||
object_id=object_id,
|
object_id=object_id,
|
||||||
author_inbox=author_inbox,
|
author_inbox=author_inbox,
|
||||||
like_count=like_count,
|
like_count=like_count,
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ from typing import Any
|
|||||||
from markupsafe import escape
|
from markupsafe import escape
|
||||||
|
|
||||||
from shared.sx.jinja_bridge import load_service_components
|
from shared.sx.jinja_bridge import load_service_components
|
||||||
from shared.sx.parser import serialize
|
|
||||||
from shared.sx.helpers import (
|
from shared.sx.helpers import (
|
||||||
sx_call, SxExpr,
|
render_to_sx,
|
||||||
root_header_sx, full_page_sx, header_child_sx,
|
root_header_sx, full_page_sx, header_child_sx,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -81,16 +80,16 @@ def _serialize_remote_actor(a) -> dict:
|
|||||||
# Social page shell
|
# Social page shell
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _social_page(ctx: dict, actor: Any, *, content: str,
|
async def _social_page(ctx: dict, actor: Any, *, content: str,
|
||||||
title: str = "Rose Ash", meta_html: str = "") -> str:
|
title: str = "Rose Ash", meta_html: str = "") -> str:
|
||||||
|
from shared.sx.parser import SxExpr
|
||||||
actor_data = _serialize_actor(actor)
|
actor_data = _serialize_actor(actor)
|
||||||
nav = sx_call("federation-social-nav",
|
nav = await render_to_sx("federation-social-nav", actor=actor_data)
|
||||||
actor=SxExpr(serialize(actor_data)) if actor_data else None)
|
social_hdr = await render_to_sx("federation-social-header", nav=SxExpr(nav))
|
||||||
social_hdr = sx_call("federation-social-header", nav=SxExpr(nav))
|
hdr = await root_header_sx(ctx)
|
||||||
hdr = root_header_sx(ctx)
|
child = await header_child_sx(social_hdr)
|
||||||
child = header_child_sx(social_hdr)
|
|
||||||
header_rows = "(<> " + hdr + " " + child + ")"
|
header_rows = "(<> " + hdr + " " + child + ")"
|
||||||
return full_page_sx(ctx, header_rows=header_rows, content=content,
|
return await full_page_sx(ctx, header_rows=header_rows, content=content,
|
||||||
meta_html=meta_html or f'<title>{escape(title)}</title>')
|
meta_html=meta_html or f'<title>{escape(title)}</title>')
|
||||||
|
|
||||||
|
|
||||||
@@ -99,24 +98,24 @@ def _social_page(ctx: dict, actor: Any, *, content: str,
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
async def render_federation_home(ctx: dict) -> str:
|
async def render_federation_home(ctx: dict) -> str:
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
return full_page_sx(ctx, header_rows=hdr)
|
return await full_page_sx(ctx, header_rows=hdr)
|
||||||
|
|
||||||
|
|
||||||
async def render_login_page(ctx: dict) -> str:
|
async def render_login_page(ctx: dict) -> str:
|
||||||
error = ctx.get("error", "")
|
error = ctx.get("error", "")
|
||||||
email = ctx.get("email", "")
|
email = ctx.get("email", "")
|
||||||
content = sx_call("account-login-content",
|
content = await render_to_sx("account-login-content",
|
||||||
error=error or None, email=str(escape(email)))
|
error=error or None, email=str(escape(email)))
|
||||||
return _social_page(ctx, None, content=content, title="Login \u2014 Rose Ash")
|
return await _social_page(ctx, None, content=content, title="Login \u2014 Rose Ash")
|
||||||
|
|
||||||
|
|
||||||
async def render_check_email_page(ctx: dict) -> str:
|
async def render_check_email_page(ctx: dict) -> str:
|
||||||
email = ctx.get("email", "")
|
email = ctx.get("email", "")
|
||||||
email_error = ctx.get("email_error")
|
email_error = ctx.get("email_error")
|
||||||
content = sx_call("account-check-email-content",
|
content = await render_to_sx("account-check-email-content",
|
||||||
email=str(escape(email)), email_error=email_error)
|
email=str(escape(email)), email_error=email_error)
|
||||||
return _social_page(ctx, None, content=content,
|
return await _social_page(ctx, None, content=content,
|
||||||
title="Check your email \u2014 Rose Ash")
|
title="Check your email \u2014 Rose Ash")
|
||||||
|
|
||||||
|
|
||||||
@@ -124,6 +123,7 @@ async def render_choose_username_page(ctx: dict) -> str:
|
|||||||
from shared.browser.app.csrf import generate_csrf_token
|
from shared.browser.app.csrf import generate_csrf_token
|
||||||
from quart import url_for
|
from quart import url_for
|
||||||
from shared.config import config
|
from shared.config import config
|
||||||
|
from shared.sx.parser import SxExpr
|
||||||
|
|
||||||
csrf = generate_csrf_token()
|
csrf = generate_csrf_token()
|
||||||
error = ctx.get("error", "")
|
error = ctx.get("error", "")
|
||||||
@@ -132,15 +132,15 @@ async def render_choose_username_page(ctx: dict) -> str:
|
|||||||
check_url = url_for("identity.check_username")
|
check_url = url_for("identity.check_username")
|
||||||
actor = ctx.get("actor")
|
actor = ctx.get("actor")
|
||||||
|
|
||||||
error_sx = sx_call("auth-error-banner", error=error) if error else ""
|
error_sx = await render_to_sx("auth-error-banner", error=error) if error else ""
|
||||||
content = sx_call(
|
content = await render_to_sx(
|
||||||
"federation-choose-username",
|
"federation-choose-username",
|
||||||
domain=str(escape(ap_domain)),
|
domain=str(escape(ap_domain)),
|
||||||
error=SxExpr(error_sx) if error_sx else None,
|
error=SxExpr(error_sx) if error_sx else None,
|
||||||
csrf=csrf, username=str(escape(username)),
|
csrf=csrf, username=str(escape(username)),
|
||||||
check_url=check_url,
|
check_url=check_url,
|
||||||
)
|
)
|
||||||
return _social_page(ctx, actor, content=content,
|
return await _social_page(ctx, actor, content=content,
|
||||||
title="Choose Username \u2014 Rose Ash")
|
title="Choose Username \u2014 Rose Ash")
|
||||||
|
|
||||||
|
|
||||||
@@ -164,10 +164,10 @@ async def render_timeline_items(items: list, timeline_type: str,
|
|||||||
else:
|
else:
|
||||||
next_url = url_for(f"social.{timeline_type}_timeline_page", before=before)
|
next_url = url_for(f"social.{timeline_type}_timeline_page", before=before)
|
||||||
|
|
||||||
return sx_call("federation-timeline-items",
|
return await render_to_sx("federation-timeline-items",
|
||||||
items=SxExpr(serialize(item_dicts)),
|
items=item_dicts,
|
||||||
timeline_type=timeline_type,
|
timeline_type=timeline_type,
|
||||||
actor=SxExpr(serialize(actor_data)) if actor_data else None,
|
actor=actor_data,
|
||||||
next_url=next_url)
|
next_url=next_url)
|
||||||
|
|
||||||
|
|
||||||
@@ -178,14 +178,14 @@ async def render_search_results(actors: list, query: str, page: int,
|
|||||||
actor_data = _serialize_actor(actor)
|
actor_data = _serialize_actor(actor)
|
||||||
parts = []
|
parts = []
|
||||||
for ad in actor_dicts:
|
for ad in actor_dicts:
|
||||||
parts.append(sx_call("federation-actor-card-from-data",
|
parts.append(await render_to_sx("federation-actor-card-from-data",
|
||||||
a=SxExpr(serialize(ad)),
|
a=ad,
|
||||||
actor=SxExpr(serialize(actor_data)) if actor_data else None,
|
actor=actor_data,
|
||||||
followed_urls=SxExpr(serialize(list(followed_urls))),
|
followed_urls=list(followed_urls),
|
||||||
list_type="search"))
|
list_type="search"))
|
||||||
if len(actors) >= 20:
|
if len(actors) >= 20:
|
||||||
next_url = url_for("social.search_page", q=query, page=page + 1)
|
next_url = url_for("social.search_page", q=query, page=page + 1)
|
||||||
parts.append(sx_call("federation-scroll-sentinel", url=next_url))
|
parts.append(await render_to_sx("federation-scroll-sentinel", url=next_url))
|
||||||
return "(<> " + " ".join(parts) + ")" if parts else ""
|
return "(<> " + " ".join(parts) + ")" if parts else ""
|
||||||
|
|
||||||
|
|
||||||
@@ -195,14 +195,14 @@ async def render_following_items(actors: list, page: int, actor: Any) -> str:
|
|||||||
actor_data = _serialize_actor(actor)
|
actor_data = _serialize_actor(actor)
|
||||||
parts = []
|
parts = []
|
||||||
for ad in actor_dicts:
|
for ad in actor_dicts:
|
||||||
parts.append(sx_call("federation-actor-card-from-data",
|
parts.append(await render_to_sx("federation-actor-card-from-data",
|
||||||
a=SxExpr(serialize(ad)),
|
a=ad,
|
||||||
actor=SxExpr(serialize(actor_data)) if actor_data else None,
|
actor=actor_data,
|
||||||
followed_urls=SxExpr(serialize([])),
|
followed_urls=[],
|
||||||
list_type="following"))
|
list_type="following"))
|
||||||
if len(actors) >= 20:
|
if len(actors) >= 20:
|
||||||
next_url = url_for("social.following_list_page", page=page + 1)
|
next_url = url_for("social.following_list_page", page=page + 1)
|
||||||
parts.append(sx_call("federation-scroll-sentinel", url=next_url))
|
parts.append(await render_to_sx("federation-scroll-sentinel", url=next_url))
|
||||||
return "(<> " + " ".join(parts) + ")" if parts else ""
|
return "(<> " + " ".join(parts) + ")" if parts else ""
|
||||||
|
|
||||||
|
|
||||||
@@ -213,14 +213,14 @@ async def render_followers_items(actors: list, page: int,
|
|||||||
actor_data = _serialize_actor(actor)
|
actor_data = _serialize_actor(actor)
|
||||||
parts = []
|
parts = []
|
||||||
for ad in actor_dicts:
|
for ad in actor_dicts:
|
||||||
parts.append(sx_call("federation-actor-card-from-data",
|
parts.append(await render_to_sx("federation-actor-card-from-data",
|
||||||
a=SxExpr(serialize(ad)),
|
a=ad,
|
||||||
actor=SxExpr(serialize(actor_data)) if actor_data else None,
|
actor=actor_data,
|
||||||
followed_urls=SxExpr(serialize(list(followed_urls))),
|
followed_urls=list(followed_urls),
|
||||||
list_type="followers"))
|
list_type="followers"))
|
||||||
if len(actors) >= 20:
|
if len(actors) >= 20:
|
||||||
next_url = url_for("social.followers_list_page", page=page + 1)
|
next_url = url_for("social.followers_list_page", page=page + 1)
|
||||||
parts.append(sx_call("federation-scroll-sentinel", url=next_url))
|
parts.append(await render_to_sx("federation-scroll-sentinel", url=next_url))
|
||||||
return "(<> " + " ".join(parts) + ")" if parts else ""
|
return "(<> " + " ".join(parts) + ")" if parts else ""
|
||||||
|
|
||||||
|
|
||||||
@@ -233,13 +233,14 @@ async def render_actor_timeline_items(items: list, actor_id: int,
|
|||||||
# Public API: POST handler fragment renderers
|
# Public API: POST handler fragment renderers
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def render_interaction_buttons(object_id: str, author_inbox: str,
|
async def render_interaction_buttons(object_id: str, author_inbox: str,
|
||||||
like_count: int, boost_count: int,
|
like_count: int, boost_count: int,
|
||||||
liked_by_me: bool, boosted_by_me: bool,
|
liked_by_me: bool, boosted_by_me: bool,
|
||||||
actor: Any) -> str:
|
actor: Any) -> str:
|
||||||
"""Render interaction buttons fragment for POST response."""
|
"""Render interaction buttons fragment for POST response."""
|
||||||
from shared.browser.app.csrf import generate_csrf_token
|
from shared.browser.app.csrf import generate_csrf_token
|
||||||
from quart import url_for
|
from quart import url_for
|
||||||
|
from shared.sx.parser import SxExpr
|
||||||
|
|
||||||
csrf = generate_csrf_token()
|
csrf = generate_csrf_token()
|
||||||
safe_id = object_id.replace("/", "_").replace(":", "_")
|
safe_id = object_id.replace("/", "_").replace(":", "_")
|
||||||
@@ -262,31 +263,31 @@ def render_interaction_buttons(object_id: str, author_inbox: str,
|
|||||||
boost_cls = "hover:text-green-600"
|
boost_cls = "hover:text-green-600"
|
||||||
|
|
||||||
reply_url = url_for("social.defpage_compose_form", reply_to=object_id) if object_id else ""
|
reply_url = url_for("social.defpage_compose_form", reply_to=object_id) if object_id else ""
|
||||||
reply_sx = sx_call("federation-reply-link", url=reply_url) if reply_url else ""
|
reply_sx = await render_to_sx("federation-reply-link", url=reply_url) if reply_url else ""
|
||||||
|
|
||||||
like_form = sx_call("federation-like-form",
|
like_form = await render_to_sx("federation-like-form",
|
||||||
action=like_action, target=target, oid=object_id, ainbox=author_inbox,
|
action=like_action, target=target, oid=object_id, ainbox=author_inbox,
|
||||||
csrf=csrf, cls=f"flex items-center gap-1 {like_cls}",
|
csrf=csrf, cls=f"flex items-center gap-1 {like_cls}",
|
||||||
icon=like_icon, count=str(like_count))
|
icon=like_icon, count=str(like_count))
|
||||||
|
|
||||||
boost_form = sx_call("federation-boost-form",
|
boost_form = await render_to_sx("federation-boost-form",
|
||||||
action=boost_action, target=target, oid=object_id, ainbox=author_inbox,
|
action=boost_action, target=target, oid=object_id, ainbox=author_inbox,
|
||||||
csrf=csrf, cls=f"flex items-center gap-1 {boost_cls}",
|
csrf=csrf, cls=f"flex items-center gap-1 {boost_cls}",
|
||||||
count=str(boost_count))
|
count=str(boost_count))
|
||||||
|
|
||||||
return sx_call("federation-interaction-buttons",
|
return await render_to_sx("federation-interaction-buttons",
|
||||||
like=SxExpr(like_form),
|
like=SxExpr(like_form),
|
||||||
boost=SxExpr(boost_form),
|
boost=SxExpr(boost_form),
|
||||||
reply=SxExpr(reply_sx) if reply_sx else None)
|
reply=SxExpr(reply_sx) if reply_sx else None)
|
||||||
|
|
||||||
|
|
||||||
def render_actor_card(actor_dto: Any, actor: Any, followed_urls: set,
|
async def render_actor_card(actor_dto: Any, actor: Any, followed_urls: set,
|
||||||
*, list_type: str = "following") -> str:
|
*, list_type: str = "following") -> str:
|
||||||
"""Render a single actor card fragment for POST response."""
|
"""Render a single actor card fragment for POST response."""
|
||||||
actor_data = _serialize_actor(actor)
|
actor_data = _serialize_actor(actor)
|
||||||
ad = _serialize_remote_actor(actor_dto)
|
ad = _serialize_remote_actor(actor_dto)
|
||||||
return sx_call("federation-actor-card-from-data",
|
return await render_to_sx("federation-actor-card-from-data",
|
||||||
a=SxExpr(serialize(ad)),
|
a=ad,
|
||||||
actor=SxExpr(serialize(actor_data)) if actor_data else None,
|
actor=actor_data,
|
||||||
followed_urls=SxExpr(serialize(list(followed_urls))),
|
followed_urls=list(followed_urls),
|
||||||
list_type=list_type)
|
list_type=list_type)
|
||||||
|
|||||||
@@ -26,33 +26,31 @@ def _register_federation_layouts() -> None:
|
|||||||
register_custom_layout("social", _social_full, _social_oob)
|
register_custom_layout("social", _social_full, _social_oob)
|
||||||
|
|
||||||
|
|
||||||
def _social_full(ctx: dict, **kw: Any) -> str:
|
async def _social_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, header_child_sx, sx_call, SxExpr
|
from shared.sx.helpers import root_header_sx, header_child_sx, render_to_sx
|
||||||
from shared.sx.parser import serialize
|
from shared.sx.parser import SxExpr
|
||||||
|
|
||||||
actor = ctx.get("actor")
|
actor = ctx.get("actor")
|
||||||
actor_data = _serialize_actor(actor) if actor else None
|
actor_data = _serialize_actor(actor) if actor else None
|
||||||
nav = sx_call("federation-social-nav",
|
nav = await render_to_sx("federation-social-nav", actor=actor_data)
|
||||||
actor=SxExpr(serialize(actor_data)) if actor_data else None)
|
social_hdr = await render_to_sx("federation-social-header", nav=SxExpr(nav))
|
||||||
social_hdr = sx_call("federation-social-header", nav=SxExpr(nav))
|
root_hdr = await root_header_sx(ctx)
|
||||||
root_hdr = root_header_sx(ctx)
|
child = await header_child_sx(social_hdr)
|
||||||
child = header_child_sx(social_hdr)
|
|
||||||
return "(<> " + root_hdr + " " + child + ")"
|
return "(<> " + root_hdr + " " + child + ")"
|
||||||
|
|
||||||
|
|
||||||
def _social_oob(ctx: dict, **kw: Any) -> str:
|
async def _social_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, sx_call, SxExpr
|
from shared.sx.helpers import root_header_sx, render_to_sx
|
||||||
from shared.sx.parser import serialize
|
from shared.sx.parser import SxExpr
|
||||||
|
|
||||||
actor = ctx.get("actor")
|
actor = ctx.get("actor")
|
||||||
actor_data = _serialize_actor(actor) if actor else None
|
actor_data = _serialize_actor(actor) if actor else None
|
||||||
nav = sx_call("federation-social-nav",
|
nav = await render_to_sx("federation-social-nav", actor=actor_data)
|
||||||
actor=SxExpr(serialize(actor_data)) if actor_data else None)
|
social_hdr = await render_to_sx("federation-social-header", nav=SxExpr(nav))
|
||||||
social_hdr = sx_call("federation-social-header", nav=SxExpr(nav))
|
child_oob = await render_to_sx("oob-header-sx",
|
||||||
child_oob = sx_call("oob-header-sx",
|
|
||||||
parent_id="root-header-child",
|
parent_id="root-header-child",
|
||||||
row=SxExpr(social_hdr))
|
row=SxExpr(social_hdr))
|
||||||
root_hdr_oob = root_header_sx(ctx, oob=True)
|
root_hdr_oob = await root_header_sx(ctx, oob=True)
|
||||||
return "(<> " + child_oob + " " + root_hdr_oob + ")"
|
return "(<> " + child_oob + " " + root_hdr_oob + ")"
|
||||||
|
|
||||||
|
|
||||||
@@ -145,43 +143,40 @@ def _require_actor():
|
|||||||
async def _h_home_timeline_content(**kw):
|
async def _h_home_timeline_content(**kw):
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.services.registry import services
|
from shared.services.registry import services
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
actor = _require_actor()
|
actor = _require_actor()
|
||||||
items = await services.federation.get_home_timeline(g.s, actor.id)
|
items = await services.federation.get_home_timeline(g.s, actor.id)
|
||||||
return sx_call("federation-timeline-content",
|
return await render_to_sx("federation-timeline-content",
|
||||||
items=SxExpr(serialize([_serialize_timeline_item(i) for i in items])),
|
items=[_serialize_timeline_item(i) for i in items],
|
||||||
timeline_type="home",
|
timeline_type="home",
|
||||||
actor=SxExpr(serialize(_serialize_actor(actor))))
|
actor=_serialize_actor(actor))
|
||||||
|
|
||||||
|
|
||||||
async def _h_public_timeline_content(**kw):
|
async def _h_public_timeline_content(**kw):
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.services.registry import services
|
from shared.services.registry import services
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
actor = _get_actor()
|
actor = _get_actor()
|
||||||
items = await services.federation.get_public_timeline(g.s)
|
items = await services.federation.get_public_timeline(g.s)
|
||||||
return sx_call("federation-timeline-content",
|
return await render_to_sx("federation-timeline-content",
|
||||||
items=SxExpr(serialize([_serialize_timeline_item(i) for i in items])),
|
items=[_serialize_timeline_item(i) for i in items],
|
||||||
timeline_type="public",
|
timeline_type="public",
|
||||||
actor=SxExpr(serialize(_serialize_actor(actor))) if actor else None)
|
actor=_serialize_actor(actor))
|
||||||
|
|
||||||
|
|
||||||
async def _h_compose_content(**kw):
|
async def _h_compose_content(**kw):
|
||||||
from quart import request
|
from quart import request
|
||||||
from shared.sx.helpers import sx_call
|
from shared.sx.helpers import render_to_sx
|
||||||
_require_actor()
|
_require_actor()
|
||||||
reply_to = request.args.get("reply_to")
|
reply_to = request.args.get("reply_to")
|
||||||
return sx_call("federation-compose-content",
|
return await render_to_sx("federation-compose-content",
|
||||||
reply_to=reply_to or None)
|
reply_to=reply_to or None)
|
||||||
|
|
||||||
|
|
||||||
async def _h_search_content(**kw):
|
async def _h_search_content(**kw):
|
||||||
from quart import g, request
|
from quart import g, request
|
||||||
from shared.services.registry import services
|
from shared.services.registry import services
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
actor = _get_actor()
|
actor = _get_actor()
|
||||||
query = request.args.get("q", "").strip()
|
query = request.args.get("q", "").strip()
|
||||||
actors_list = []
|
actors_list = []
|
||||||
@@ -194,34 +189,32 @@ async def _h_search_content(**kw):
|
|||||||
g.s, actor.preferred_username, page=1, per_page=1000,
|
g.s, actor.preferred_username, page=1, per_page=1000,
|
||||||
)
|
)
|
||||||
followed_urls = {a.actor_url for a in following}
|
followed_urls = {a.actor_url for a in following}
|
||||||
return sx_call("federation-search-content",
|
return await render_to_sx("federation-search-content",
|
||||||
query=query,
|
query=query,
|
||||||
actors=SxExpr(serialize([_serialize_remote_actor(a) for a in actors_list])),
|
actors=[_serialize_remote_actor(a) for a in actors_list],
|
||||||
total=total,
|
total=total,
|
||||||
followed_urls=SxExpr(serialize(list(followed_urls))),
|
followed_urls=list(followed_urls),
|
||||||
actor=SxExpr(serialize(_serialize_actor(actor))) if actor else None)
|
actor=_serialize_actor(actor))
|
||||||
|
|
||||||
|
|
||||||
async def _h_following_content(**kw):
|
async def _h_following_content(**kw):
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.services.registry import services
|
from shared.services.registry import services
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
actor = _require_actor()
|
actor = _require_actor()
|
||||||
actors_list, total = await services.federation.get_following(
|
actors_list, total = await services.federation.get_following(
|
||||||
g.s, actor.preferred_username,
|
g.s, actor.preferred_username,
|
||||||
)
|
)
|
||||||
return sx_call("federation-following-content",
|
return await render_to_sx("federation-following-content",
|
||||||
actors=SxExpr(serialize([_serialize_remote_actor(a) for a in actors_list])),
|
actors=[_serialize_remote_actor(a) for a in actors_list],
|
||||||
total=total,
|
total=total,
|
||||||
actor=SxExpr(serialize(_serialize_actor(actor))))
|
actor=_serialize_actor(actor))
|
||||||
|
|
||||||
|
|
||||||
async def _h_followers_content(**kw):
|
async def _h_followers_content(**kw):
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.services.registry import services
|
from shared.services.registry import services
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
actor = _require_actor()
|
actor = _require_actor()
|
||||||
actors_list, total = await services.federation.get_followers_paginated(
|
actors_list, total = await services.federation.get_followers_paginated(
|
||||||
g.s, actor.preferred_username,
|
g.s, actor.preferred_username,
|
||||||
@@ -230,18 +223,17 @@ async def _h_followers_content(**kw):
|
|||||||
g.s, actor.preferred_username, page=1, per_page=1000,
|
g.s, actor.preferred_username, page=1, per_page=1000,
|
||||||
)
|
)
|
||||||
followed_urls = {a.actor_url for a in following}
|
followed_urls = {a.actor_url for a in following}
|
||||||
return sx_call("federation-followers-content",
|
return await render_to_sx("federation-followers-content",
|
||||||
actors=SxExpr(serialize([_serialize_remote_actor(a) for a in actors_list])),
|
actors=[_serialize_remote_actor(a) for a in actors_list],
|
||||||
total=total,
|
total=total,
|
||||||
followed_urls=SxExpr(serialize(list(followed_urls))),
|
followed_urls=list(followed_urls),
|
||||||
actor=SxExpr(serialize(_serialize_actor(actor))))
|
actor=_serialize_actor(actor))
|
||||||
|
|
||||||
|
|
||||||
async def _h_actor_timeline_content(id=None, **kw):
|
async def _h_actor_timeline_content(id=None, **kw):
|
||||||
from quart import g, abort
|
from quart import g, abort
|
||||||
from shared.services.registry import services
|
from shared.services.registry import services
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
actor = _get_actor()
|
actor = _get_actor()
|
||||||
actor_id = id
|
actor_id = id
|
||||||
from shared.models.federation import RemoteActor
|
from shared.models.federation import RemoteActor
|
||||||
@@ -268,18 +260,17 @@ async def _h_actor_timeline_content(id=None, **kw):
|
|||||||
)
|
)
|
||||||
).scalar_one_or_none()
|
).scalar_one_or_none()
|
||||||
is_following = existing is not None
|
is_following = existing is not None
|
||||||
return sx_call("federation-actor-timeline-content",
|
return await render_to_sx("federation-actor-timeline-content",
|
||||||
remote_actor=SxExpr(serialize(_serialize_remote_actor(remote_dto))),
|
remote_actor=_serialize_remote_actor(remote_dto),
|
||||||
items=SxExpr(serialize([_serialize_timeline_item(i) for i in items])),
|
items=[_serialize_timeline_item(i) for i in items],
|
||||||
is_following=is_following,
|
is_following=is_following,
|
||||||
actor=SxExpr(serialize(_serialize_actor(actor))) if actor else None)
|
actor=_serialize_actor(actor))
|
||||||
|
|
||||||
|
|
||||||
async def _h_notifications_content(**kw):
|
async def _h_notifications_content(**kw):
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.services.registry import services
|
from shared.services.registry import services
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
actor = _require_actor()
|
actor = _require_actor()
|
||||||
items = await services.federation.get_notifications(g.s, actor.id)
|
items = await services.federation.get_notifications(g.s, actor.id)
|
||||||
await services.federation.mark_notifications_read(g.s, actor.id)
|
await services.federation.mark_notifications_read(g.s, actor.id)
|
||||||
@@ -298,5 +289,5 @@ async def _h_notifications_content(**kw):
|
|||||||
"read": getattr(n, "read", True),
|
"read": getattr(n, "read", True),
|
||||||
"app_domain": getattr(n, "app_domain", ""),
|
"app_domain": getattr(n, "app_domain", ""),
|
||||||
})
|
})
|
||||||
return sx_call("federation-notifications-content",
|
return await render_to_sx("federation-notifications-content",
|
||||||
notifications=SxExpr(serialize(notif_dicts)))
|
notifications=notif_dicts)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ def register() -> Blueprint:
|
|||||||
async def _is_liked():
|
async def _is_liked():
|
||||||
"""Check if a user has liked a specific target."""
|
"""Check if a user has liked a specific target."""
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from likes.models.like import Like
|
from models.like import Like
|
||||||
|
|
||||||
user_id = request.args.get("user_id", type=int)
|
user_id = request.args.get("user_id", type=int)
|
||||||
target_type = request.args.get("target_type", "")
|
target_type = request.args.get("target_type", "")
|
||||||
@@ -62,7 +62,7 @@ def register() -> Blueprint:
|
|||||||
async def _liked_slugs():
|
async def _liked_slugs():
|
||||||
"""Return all liked target_slugs for a user + target_type."""
|
"""Return all liked target_slugs for a user + target_type."""
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from likes.models.like import Like
|
from models.like import Like
|
||||||
|
|
||||||
user_id = request.args.get("user_id", type=int)
|
user_id = request.args.get("user_id", type=int)
|
||||||
target_type = request.args.get("target_type", "")
|
target_type = request.args.get("target_type", "")
|
||||||
@@ -86,7 +86,7 @@ def register() -> Blueprint:
|
|||||||
async def _liked_ids():
|
async def _liked_ids():
|
||||||
"""Return all liked target_ids for a user + target_type."""
|
"""Return all liked target_ids for a user + target_type."""
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
from likes.models.like import Like
|
from models.like import Like
|
||||||
|
|
||||||
user_id = request.args.get("user_id", type=int)
|
user_id = request.args.get("user_id", type=int)
|
||||||
target_type = request.args.get("target_type", "")
|
target_type = request.args.get("target_type", "")
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ def register():
|
|||||||
from sx.sx_components import render_like_toggle_button
|
from sx.sx_components import render_like_toggle_button
|
||||||
|
|
||||||
if not g.user:
|
if not g.user:
|
||||||
return sx_response(render_like_toggle_button(product_slug, False), status=403)
|
return sx_response(await render_like_toggle_button(product_slug, False), status=403)
|
||||||
|
|
||||||
user_id = g.user.id
|
user_id = g.user.id
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ def register():
|
|||||||
})
|
})
|
||||||
liked = result["liked"]
|
liked = result["liked"]
|
||||||
|
|
||||||
return sx_response(render_like_toggle_button(product_slug, liked))
|
return sx_response(await render_like_toggle_button(product_slug, liked))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ def register():
|
|||||||
from sx.sx_components import render_cart_added_response
|
from sx.sx_components import render_cart_added_response
|
||||||
item_data = getattr(g, "item_data", {})
|
item_data = getattr(g, "item_data", {})
|
||||||
d = item_data.get("d", {})
|
d = item_data.get("d", {})
|
||||||
return sx_response(render_cart_added_response(g.cart, ci_ns, d))
|
return sx_response(await render_cart_added_response(g.cart, ci_ns, d))
|
||||||
|
|
||||||
# normal POST: go to cart page
|
# normal POST: go to cart page
|
||||||
from shared.infrastructure.urls import cart_url
|
from shared.infrastructure.urls import cart_url
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -27,55 +27,55 @@ def _register_market_layouts() -> None:
|
|||||||
register_custom_layout("market-admin", _market_admin_full, _market_admin_oob)
|
register_custom_layout("market-admin", _market_admin_full, _market_admin_oob)
|
||||||
|
|
||||||
|
|
||||||
def _market_full(ctx: dict, **kw: Any) -> str:
|
async def _market_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, header_child_sx
|
from shared.sx.helpers import root_header_sx, header_child_sx
|
||||||
from sx.sx_components import _post_header_sx, _market_header_sx
|
from sx.sx_components import _post_header_sx, _market_header_sx
|
||||||
|
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
child = "(<> " + _post_header_sx(ctx) + " " + _market_header_sx(ctx) + ")"
|
child = "(<> " + await _post_header_sx(ctx) + " " + await _market_header_sx(ctx) + ")"
|
||||||
return "(<> " + root_hdr + " " + header_child_sx(child) + ")"
|
return "(<> " + root_hdr + " " + await header_child_sx(child) + ")"
|
||||||
|
|
||||||
|
|
||||||
def _market_oob(ctx: dict, **kw: Any) -> str:
|
async def _market_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import oob_header_sx
|
from shared.sx.helpers import oob_header_sx
|
||||||
from sx.sx_components import _post_header_sx, _market_header_sx, _clear_deeper_oob
|
from sx.sx_components import _post_header_sx, _market_header_sx, _clear_deeper_oob
|
||||||
|
|
||||||
oobs = oob_header_sx("post-header-child", "market-header-child",
|
oobs = await oob_header_sx("post-header-child", "market-header-child",
|
||||||
_market_header_sx(ctx))
|
await _market_header_sx(ctx))
|
||||||
oobs = "(<> " + oobs + " " + _post_header_sx(ctx, oob=True) + " "
|
oobs = "(<> " + oobs + " " + await _post_header_sx(ctx, oob=True) + " "
|
||||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||||
"market-row", "market-header-child") + ")"
|
"market-row", "market-header-child") + ")"
|
||||||
return oobs
|
return oobs
|
||||||
|
|
||||||
|
|
||||||
def _market_mobile(ctx: dict, **kw: Any) -> str:
|
async def _market_mobile(ctx: dict, **kw: Any) -> str:
|
||||||
from sx.sx_components import _mobile_nav_panel_sx
|
from sx.sx_components import _mobile_nav_panel_sx
|
||||||
return _mobile_nav_panel_sx(ctx)
|
return await _mobile_nav_panel_sx(ctx)
|
||||||
|
|
||||||
|
|
||||||
def _market_admin_full(ctx: dict, **kw: Any) -> str:
|
async def _market_admin_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, header_child_sx
|
from shared.sx.helpers import root_header_sx, header_child_sx
|
||||||
from sx.sx_components import (
|
from sx.sx_components import (
|
||||||
_post_header_sx, _market_header_sx, _market_admin_header_sx,
|
_post_header_sx, _market_header_sx, _market_admin_header_sx,
|
||||||
)
|
)
|
||||||
|
|
||||||
selected = kw.get("selected", "")
|
selected = kw.get("selected", "")
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
child = "(<> " + _post_header_sx(ctx) + " " + _market_header_sx(ctx) + " "
|
child = "(<> " + await _post_header_sx(ctx) + " " + await _market_header_sx(ctx) + " "
|
||||||
child += _market_admin_header_sx(ctx, selected=selected) + ")"
|
child += await _market_admin_header_sx(ctx, selected=selected) + ")"
|
||||||
return "(<> " + root_hdr + " " + header_child_sx(child) + ")"
|
return "(<> " + root_hdr + " " + await header_child_sx(child) + ")"
|
||||||
|
|
||||||
|
|
||||||
def _market_admin_oob(ctx: dict, **kw: Any) -> str:
|
async def _market_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import oob_header_sx
|
from shared.sx.helpers import oob_header_sx
|
||||||
from sx.sx_components import (
|
from sx.sx_components import (
|
||||||
_market_header_sx, _market_admin_header_sx, _clear_deeper_oob,
|
_market_header_sx, _market_admin_header_sx, _clear_deeper_oob,
|
||||||
)
|
)
|
||||||
|
|
||||||
selected = kw.get("selected", "")
|
selected = kw.get("selected", "")
|
||||||
oobs = "(<> " + _market_header_sx(ctx, oob=True) + " "
|
oobs = "(<> " + await _market_header_sx(ctx, oob=True) + " "
|
||||||
oobs += oob_header_sx("market-header-child", "market-admin-header-child",
|
oobs += await oob_header_sx("market-header-child", "market-admin-header-child",
|
||||||
_market_admin_header_sx(ctx, selected=selected)) + " "
|
await _market_admin_header_sx(ctx, selected=selected)) + " "
|
||||||
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
||||||
"market-row", "market-header-child",
|
"market-row", "market-header-child",
|
||||||
"market-admin-row", "market-admin-header-child") + ")"
|
"market-admin-row", "market-admin-header-child") + ")"
|
||||||
@@ -123,14 +123,14 @@ async def _h_all_markets_content(**kw):
|
|||||||
|
|
||||||
if not markets:
|
if not markets:
|
||||||
from sx.sx_components import _no_markets_sx
|
from sx.sx_components import _no_markets_sx
|
||||||
return _no_markets_sx()
|
return await _no_markets_sx()
|
||||||
|
|
||||||
prefix = route_prefix()
|
prefix = route_prefix()
|
||||||
next_url = prefix + url_for("all_markets.markets_fragment", page=page + 1)
|
next_url = prefix + url_for("all_markets.markets_fragment", page=page + 1)
|
||||||
|
|
||||||
from sx.sx_components import _market_cards_sx, _markets_grid
|
from sx.sx_components import _market_cards_sx, _markets_grid
|
||||||
cards = _market_cards_sx(markets, page_info, page, has_more, next_url)
|
cards = await _market_cards_sx(markets, page_info, page, has_more, next_url)
|
||||||
content = _markets_grid(cards)
|
content = await _markets_grid(cards)
|
||||||
return "(<> " + content + " " + '(div :class "pb-8")' + ")"
|
return "(<> " + content + " " + '(div :class "pb-8")' + ")"
|
||||||
|
|
||||||
|
|
||||||
@@ -148,15 +148,15 @@ async def _h_page_markets_content(slug=None, **kw):
|
|||||||
|
|
||||||
if not markets:
|
if not markets:
|
||||||
from sx.sx_components import _no_markets_sx
|
from sx.sx_components import _no_markets_sx
|
||||||
return _no_markets_sx("No markets for this page")
|
return await _no_markets_sx("No markets for this page")
|
||||||
|
|
||||||
prefix = route_prefix()
|
prefix = route_prefix()
|
||||||
next_url = prefix + url_for("page_markets.markets_fragment", page=page + 1)
|
next_url = prefix + url_for("page_markets.markets_fragment", page=page + 1)
|
||||||
|
|
||||||
from sx.sx_components import _market_cards_sx, _markets_grid
|
from sx.sx_components import _market_cards_sx, _markets_grid
|
||||||
cards = _market_cards_sx(markets, {}, page, has_more, next_url,
|
cards = await _market_cards_sx(markets, {}, page, has_more, next_url,
|
||||||
show_page_badge=False, post_slug=post_slug)
|
show_page_badge=False, post_slug=post_slug)
|
||||||
content = _markets_grid(cards)
|
content = await _markets_grid(cards)
|
||||||
return "(<> " + content + " " + '(div :class "pb-8")' + ")"
|
return "(<> " + content + " " + '(div :class "pb-8")' + ")"
|
||||||
|
|
||||||
|
|
||||||
@@ -168,12 +168,12 @@ async def _h_page_admin_content(slug=None, **kw):
|
|||||||
return '(div :id "main-panel" ' + content + ')'
|
return '(div :id "main-panel" ' + content + ')'
|
||||||
|
|
||||||
|
|
||||||
def _h_market_home_content(page_slug=None, market_slug=None, **kw):
|
async def _h_market_home_content(page_slug=None, market_slug=None, **kw):
|
||||||
from quart import g
|
from quart import g
|
||||||
post_data = getattr(g, "post_data", {})
|
post_data = getattr(g, "post_data", {})
|
||||||
post = post_data.get("post", {})
|
post = post_data.get("post", {})
|
||||||
from sx.sx_components import _market_landing_content_sx
|
from sx.sx_components import _market_landing_content_sx
|
||||||
return _market_landing_content_sx(post)
|
return await _market_landing_content_sx(post)
|
||||||
|
|
||||||
|
|
||||||
def _h_market_admin_content(page_slug=None, market_slug=None, **kw):
|
def _h_market_admin_content(page_slug=None, market_slug=None, **kw):
|
||||||
|
|||||||
@@ -73,8 +73,7 @@ def register(url_prefix: str) -> Blueprint:
|
|||||||
result = await g.s.execute(stmt)
|
result = await g.s.execute(stmt)
|
||||||
orders = result.scalars().all()
|
orders = result.scalars().all()
|
||||||
|
|
||||||
from shared.sx.helpers import sx_response, sx_call, SxExpr
|
from shared.sx.helpers import sx_response, render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
from shared.utils import route_prefix
|
from shared.utils import route_prefix
|
||||||
|
|
||||||
pfx = route_prefix()
|
pfx = route_prefix()
|
||||||
@@ -96,16 +95,16 @@ def register(url_prefix: str) -> Blueprint:
|
|||||||
# Build just the rows fragment (not full table) for infinite scroll
|
# Build just the rows fragment (not full table) for infinite scroll
|
||||||
parts = []
|
parts = []
|
||||||
for od in order_dicts:
|
for od in order_dicts:
|
||||||
parts.append(sx_call("order-row-pair",
|
parts.append(await render_to_sx("order-row-pair",
|
||||||
order=SxExpr(serialize(od)),
|
order=od,
|
||||||
detail_url_prefix=detail_prefix))
|
detail_url_prefix=detail_prefix))
|
||||||
if page < total_pages:
|
if page < total_pages:
|
||||||
parts.append(sx_call("infinite-scroll",
|
parts.append(await render_to_sx("infinite-scroll",
|
||||||
url=rows_url + qs_fn(page=page + 1),
|
url=rows_url + qs_fn(page=page + 1),
|
||||||
page=page, total_pages=total_pages,
|
page=page, total_pages=total_pages,
|
||||||
id_prefix="orders", colspan=5))
|
id_prefix="orders", colspan=5))
|
||||||
else:
|
else:
|
||||||
parts.append(sx_call("order-end-row"))
|
parts.append(await render_to_sx("order-end-row"))
|
||||||
sx_src = "(<> " + " ".join(parts) + ")"
|
sx_src = "(<> " + " ".join(parts) + ")"
|
||||||
|
|
||||||
resp = sx_response(sx_src)
|
resp = sx_response(sx_src)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from typing import Any
|
|||||||
|
|
||||||
from shared.sx.jinja_bridge import load_service_components
|
from shared.sx.jinja_bridge import load_service_components
|
||||||
from shared.sx.helpers import (
|
from shared.sx.helpers import (
|
||||||
call_url, sx_call, SxExpr,
|
call_url, render_to_sx,
|
||||||
root_header_sx, full_page_sx, header_child_sx,
|
root_header_sx, full_page_sx, header_child_sx,
|
||||||
)
|
)
|
||||||
from shared.infrastructure.urls import market_product_url, cart_url
|
from shared.infrastructure.urls import market_product_url, cart_url
|
||||||
@@ -29,24 +29,24 @@ load_service_components(os.path.dirname(os.path.dirname(__file__)),
|
|||||||
async def render_checkout_error_page(ctx: dict, error: str | None = None, order: Any | None = None) -> str:
|
async def render_checkout_error_page(ctx: dict, error: str | None = None, order: Any | None = None) -> str:
|
||||||
"""Full page: checkout error (sx wire format)."""
|
"""Full page: checkout error (sx wire format)."""
|
||||||
account_url = call_url(ctx, "account_url", "")
|
account_url = call_url(ctx, "account_url", "")
|
||||||
auth_hdr = sx_call("auth-header-row", account_url=account_url)
|
auth_hdr = await render_to_sx("auth-header-row", account_url=account_url)
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
hdr = "(<> " + hdr + " " + header_child_sx(auth_hdr) + ")"
|
hdr = "(<> " + hdr + " " + await header_child_sx(auth_hdr) + ")"
|
||||||
filt = sx_call("checkout-error-header")
|
filt = await render_to_sx("checkout-error-header")
|
||||||
|
|
||||||
err_msg = error or "Unexpected error while creating the hosted checkout session."
|
err_msg = error or "Unexpected error while creating the hosted checkout session."
|
||||||
order_sx = ""
|
order_sx = ""
|
||||||
if order:
|
if order:
|
||||||
order_sx = sx_call("checkout-error-order-id", oid=f"#{order.id}")
|
order_sx = await render_to_sx("checkout-error-order-id", oid=f"#{order.id}")
|
||||||
back_url = cart_url("/")
|
from shared.sx.parser import SxExpr
|
||||||
content = sx_call(
|
content = await render_to_sx(
|
||||||
"checkout-error-content",
|
"checkout-error-content",
|
||||||
msg=err_msg,
|
msg=err_msg,
|
||||||
order=SxExpr(order_sx) if order_sx else None,
|
order=SxExpr(order_sx) if order_sx else None,
|
||||||
back_url=back_url,
|
back_url=cart_url("/"),
|
||||||
)
|
)
|
||||||
|
|
||||||
return full_page_sx(ctx, header_rows=hdr, filter=filt, content=content)
|
return await full_page_sx(ctx, header_rows=hdr, filter=filt, content=content)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -58,12 +58,12 @@ async def render_checkout_return_page(ctx: dict, order: Any | None,
|
|||||||
calendar_entries: list | None = None,
|
calendar_entries: list | None = None,
|
||||||
order_tickets: list | None = None) -> str:
|
order_tickets: list | None = None) -> str:
|
||||||
"""Full page: checkout return after SumUp payment (sx wire format)."""
|
"""Full page: checkout return after SumUp payment (sx wire format)."""
|
||||||
from shared.sx.parser import serialize
|
from shared.sx.parser import SxExpr
|
||||||
|
|
||||||
filt = sx_call("checkout-return-header", status=status)
|
filt = await render_to_sx("checkout-return-header", status=status)
|
||||||
|
|
||||||
if not order:
|
if not order:
|
||||||
content = sx_call("checkout-return-missing")
|
content = await render_to_sx("checkout-return-missing")
|
||||||
else:
|
else:
|
||||||
# Serialize order data for defcomp
|
# Serialize order data for defcomp
|
||||||
order_dict = {
|
order_dict = {
|
||||||
@@ -87,7 +87,7 @@ async def render_checkout_return_page(ctx: dict, order: Any | None,
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
summary = sx_call("order-summary-card",
|
summary = await render_to_sx("order-summary-card",
|
||||||
order_id=order.id,
|
order_id=order.id,
|
||||||
created_at=order_dict["created_at_formatted"],
|
created_at=order_dict["created_at_formatted"],
|
||||||
description=order.description, status=order.status,
|
description=order.description, status=order.status,
|
||||||
@@ -101,19 +101,19 @@ async def render_checkout_return_page(ctx: dict, order: Any | None,
|
|||||||
item_parts = []
|
item_parts = []
|
||||||
for item_d in order_dict["items"]:
|
for item_d in order_dict["items"]:
|
||||||
if item_d["product_image"]:
|
if item_d["product_image"]:
|
||||||
img = sx_call("order-item-image",
|
img = await render_to_sx("order-item-image",
|
||||||
src=item_d["product_image"],
|
src=item_d["product_image"],
|
||||||
alt=item_d["product_title"] or "Product image")
|
alt=item_d["product_title"] or "Product image")
|
||||||
else:
|
else:
|
||||||
img = sx_call("order-item-no-image")
|
img = await render_to_sx("order-item-no-image")
|
||||||
item_parts.append(sx_call("order-item-row",
|
item_parts.append(await render_to_sx("order-item-row",
|
||||||
href=item_d["product_url"], img=SxExpr(img),
|
href=item_d["product_url"], img=SxExpr(img),
|
||||||
title=item_d["product_title"] or "Unknown product",
|
title=item_d["product_title"] or "Unknown product",
|
||||||
pid=f"Product ID: {item_d['product_id']}",
|
pid=f"Product ID: {item_d['product_id']}",
|
||||||
qty=f"Qty: {item_d['quantity']}",
|
qty=f"Qty: {item_d['quantity']}",
|
||||||
price=f"{item_d['currency'] or order.currency or 'GBP'} {item_d['unit_price_formatted']}",
|
price=f"{item_d['currency'] or order.currency or 'GBP'} {item_d['unit_price_formatted']}",
|
||||||
))
|
))
|
||||||
items = sx_call("order-items-panel",
|
items = await render_to_sx("order-items-panel",
|
||||||
items=SxExpr("(<> " + " ".join(item_parts) + ")"))
|
items=SxExpr("(<> " + " ".join(item_parts) + ")"))
|
||||||
|
|
||||||
# Calendar entries
|
# Calendar entries
|
||||||
@@ -131,13 +131,13 @@ async def render_checkout_return_page(ctx: dict, order: Any | None,
|
|||||||
ds = e.start_at.strftime("%-d %b %Y, %H:%M") if e.start_at else ""
|
ds = e.start_at.strftime("%-d %b %Y, %H:%M") if e.start_at else ""
|
||||||
if e.end_at:
|
if e.end_at:
|
||||||
ds += f" \u2013 {e.end_at.strftime('%-d %b %Y, %H:%M')}"
|
ds += f" \u2013 {e.end_at.strftime('%-d %b %Y, %H:%M')}"
|
||||||
cal_parts.append(sx_call("order-calendar-entry",
|
cal_parts.append(await render_to_sx("order-calendar-entry",
|
||||||
name=e.name,
|
name=e.name,
|
||||||
pill=f"inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium {pill}",
|
pill=f"inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium {pill}",
|
||||||
status=st.capitalize(), date_str=ds,
|
status=st.capitalize(), date_str=ds,
|
||||||
cost=f"\u00a3{e.cost or 0:.2f}",
|
cost=f"\u00a3{e.cost or 0:.2f}",
|
||||||
))
|
))
|
||||||
calendar = sx_call("order-calendar-section",
|
calendar = await render_to_sx("order-calendar-section",
|
||||||
items=SxExpr("(<> " + " ".join(cal_parts) + ")"))
|
items=SxExpr("(<> " + " ".join(cal_parts) + ")"))
|
||||||
|
|
||||||
# Tickets
|
# Tickets
|
||||||
@@ -156,24 +156,24 @@ async def render_checkout_return_page(ctx: dict, order: Any | None,
|
|||||||
ds = tk.entry_start_at.strftime("%-d %b %Y, %H:%M") if tk.entry_start_at else ""
|
ds = tk.entry_start_at.strftime("%-d %b %Y, %H:%M") if tk.entry_start_at else ""
|
||||||
if tk.entry_end_at:
|
if tk.entry_end_at:
|
||||||
ds += f" \u2013 {tk.entry_end_at.strftime('%-d %b %Y, %H:%M')}"
|
ds += f" \u2013 {tk.entry_end_at.strftime('%-d %b %Y, %H:%M')}"
|
||||||
tk_parts.append(sx_call("checkout-return-ticket",
|
tk_parts.append(await render_to_sx("checkout-return-ticket",
|
||||||
name=tk.entry_name, pill=pill_cls,
|
name=tk.entry_name, pill=pill_cls,
|
||||||
state=st.replace("_", " ").capitalize(),
|
state=st.replace("_", " ").capitalize(),
|
||||||
type_name=tk.ticket_type_name or None,
|
type_name=tk.ticket_type_name or None,
|
||||||
date_str=ds, code=tk.code,
|
date_str=ds, code=tk.code,
|
||||||
price=f"\u00a3{tk.price or 0:.2f}",
|
price=f"\u00a3{tk.price or 0:.2f}",
|
||||||
))
|
))
|
||||||
tickets = sx_call("checkout-return-tickets",
|
tickets = await render_to_sx("checkout-return-tickets",
|
||||||
items=SxExpr("(<> " + " ".join(tk_parts) + ")"))
|
items=SxExpr("(<> " + " ".join(tk_parts) + ")"))
|
||||||
|
|
||||||
# Status message
|
# Status message
|
||||||
status_msg = ""
|
status_msg = ""
|
||||||
if order.status == "failed":
|
if order.status == "failed":
|
||||||
status_msg = sx_call("checkout-return-failed", order_id=order.id)
|
status_msg = await render_to_sx("checkout-return-failed", order_id=order.id)
|
||||||
elif order.status == "paid":
|
elif order.status == "paid":
|
||||||
status_msg = sx_call("checkout-return-paid")
|
status_msg = await render_to_sx("checkout-return-paid")
|
||||||
|
|
||||||
content = sx_call("checkout-return-content",
|
content = await render_to_sx("checkout-return-content",
|
||||||
summary=SxExpr(summary),
|
summary=SxExpr(summary),
|
||||||
items=SxExpr(items) if items else None,
|
items=SxExpr(items) if items else None,
|
||||||
calendar=SxExpr(calendar) if calendar else None,
|
calendar=SxExpr(calendar) if calendar else None,
|
||||||
@@ -182,8 +182,8 @@ async def render_checkout_return_page(ctx: dict, order: Any | None,
|
|||||||
)
|
)
|
||||||
|
|
||||||
account_url = call_url(ctx, "account_url", "")
|
account_url = call_url(ctx, "account_url", "")
|
||||||
auth_hdr = sx_call("auth-header-row", account_url=account_url)
|
auth_hdr = await render_to_sx("auth-header-row", account_url=account_url)
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
hdr = "(<> " + hdr + " " + header_child_sx(auth_hdr) + ")"
|
hdr = "(<> " + hdr + " " + await header_child_sx(auth_hdr) + ")"
|
||||||
|
|
||||||
return full_page_sx(ctx, header_rows=hdr, filter=filt, content=content)
|
return await full_page_sx(ctx, header_rows=hdr, filter=filt, content=content)
|
||||||
|
|||||||
@@ -28,94 +28,101 @@ def _register_orders_layouts() -> None:
|
|||||||
register_custom_layout("order-detail", _order_detail_full, _order_detail_oob, _order_detail_mobile)
|
register_custom_layout("order-detail", _order_detail_full, _order_detail_oob, _order_detail_mobile)
|
||||||
|
|
||||||
|
|
||||||
def _orders_full(ctx: dict, **kw: Any) -> str:
|
async def _orders_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, header_child_sx, call_url, sx_call, SxExpr
|
from shared.sx.helpers import root_header_sx, header_child_sx, call_url, render_to_sx
|
||||||
|
|
||||||
list_url = kw.get("list_url", "/")
|
list_url = kw.get("list_url", "/")
|
||||||
account_url = call_url(ctx, "account_url", "")
|
account_url = call_url(ctx, "account_url", "")
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
auth_hdr = sx_call("auth-header-row",
|
auth_hdr = await render_to_sx("auth-header-row",
|
||||||
account_url=account_url,
|
account_url=account_url,
|
||||||
select_colours=ctx.get("select_colours", ""),
|
select_colours=ctx.get("select_colours", ""),
|
||||||
account_nav=_as_sx_nav(ctx),
|
account_nav=_as_sx_nav(ctx),
|
||||||
)
|
)
|
||||||
orders_hdr = sx_call("orders-header-row", list_url=list_url)
|
orders_hdr = await render_to_sx("orders-header-row", list_url=list_url)
|
||||||
inner = "(<> " + auth_hdr + " " + orders_hdr + ")"
|
inner = "(<> " + auth_hdr + " " + orders_hdr + ")"
|
||||||
return "(<> " + root_hdr + " " + header_child_sx(inner) + ")"
|
return "(<> " + root_hdr + " " + await header_child_sx(inner) + ")"
|
||||||
|
|
||||||
|
|
||||||
def _orders_oob(ctx: dict, **kw: Any) -> str:
|
async def _orders_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, sx_call, SxExpr, call_url
|
from shared.sx.helpers import root_header_sx, render_to_sx
|
||||||
|
from shared.sx.helpers import call_url
|
||||||
|
from shared.sx.parser import SxExpr
|
||||||
|
|
||||||
list_url = kw.get("list_url", "/")
|
list_url = kw.get("list_url", "/")
|
||||||
account_url = call_url(ctx, "account_url", "")
|
account_url = call_url(ctx, "account_url", "")
|
||||||
auth_hdr = sx_call("auth-header-row",
|
auth_hdr = await render_to_sx("auth-header-row",
|
||||||
account_url=account_url,
|
account_url=account_url,
|
||||||
select_colours=ctx.get("select_colours", ""),
|
select_colours=ctx.get("select_colours", ""),
|
||||||
account_nav=_as_sx_nav(ctx),
|
account_nav=_as_sx_nav(ctx),
|
||||||
oob=True,
|
oob=True,
|
||||||
)
|
)
|
||||||
auth_child_oob = sx_call("oob-header-sx",
|
orders_hdr = await render_to_sx("orders-header-row", list_url=list_url)
|
||||||
parent_id="auth-header-child",
|
auth_child_oob = await render_to_sx("oob-header-sx",
|
||||||
row=SxExpr(sx_call("orders-header-row", list_url=list_url)))
|
parent_id="auth-header-child",
|
||||||
root_hdr = root_header_sx(ctx, oob=True)
|
row=SxExpr(orders_hdr))
|
||||||
|
root_hdr = await root_header_sx(ctx, oob=True)
|
||||||
return "(<> " + auth_hdr + " " + auth_child_oob + " " + root_hdr + ")"
|
return "(<> " + auth_hdr + " " + auth_child_oob + " " + root_hdr + ")"
|
||||||
|
|
||||||
|
|
||||||
def _orders_mobile(ctx: dict, **kw: Any) -> str:
|
async def _orders_mobile(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import mobile_menu_sx, mobile_root_nav_sx
|
from shared.sx.helpers import mobile_menu_sx, mobile_root_nav_sx
|
||||||
return mobile_menu_sx(mobile_root_nav_sx(ctx))
|
return mobile_menu_sx(await mobile_root_nav_sx(ctx))
|
||||||
|
|
||||||
|
|
||||||
def _order_detail_full(ctx: dict, **kw: Any) -> str:
|
async def _order_detail_full(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, sx_call, SxExpr, call_url
|
from shared.sx.helpers import root_header_sx, render_to_sx
|
||||||
|
from shared.sx.helpers import call_url
|
||||||
|
from shared.sx.parser import SxExpr
|
||||||
|
|
||||||
list_url = kw.get("list_url", "/")
|
list_url = kw.get("list_url", "/")
|
||||||
detail_url = kw.get("detail_url", "/")
|
detail_url = kw.get("detail_url", "/")
|
||||||
account_url = call_url(ctx, "account_url", "")
|
account_url = call_url(ctx, "account_url", "")
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
order_row = sx_call(
|
order_row = await render_to_sx(
|
||||||
"menu-row-sx",
|
"menu-row-sx",
|
||||||
id="order-row", level=3, colour="sky", link_href=detail_url,
|
id="order-row", level=3, colour="sky", link_href=detail_url,
|
||||||
link_label="Order", icon="fa fa-gbp",
|
link_label="Order", icon="fa fa-gbp",
|
||||||
)
|
)
|
||||||
auth_hdr = sx_call("auth-header-row",
|
auth_hdr = await render_to_sx("auth-header-row",
|
||||||
account_url=account_url,
|
account_url=account_url,
|
||||||
select_colours=ctx.get("select_colours", ""),
|
select_colours=ctx.get("select_colours", ""),
|
||||||
account_nav=_as_sx_nav(ctx),
|
account_nav=_as_sx_nav(ctx),
|
||||||
)
|
)
|
||||||
detail_header = sx_call(
|
orders_hdr = await render_to_sx("orders-header-row", list_url=list_url)
|
||||||
|
detail_header = await render_to_sx(
|
||||||
"order-detail-header-stack",
|
"order-detail-header-stack",
|
||||||
auth=SxExpr(auth_hdr),
|
auth=SxExpr(auth_hdr),
|
||||||
orders=SxExpr(sx_call("orders-header-row", list_url=list_url)),
|
orders=SxExpr(orders_hdr),
|
||||||
order=SxExpr(order_row),
|
order=SxExpr(order_row),
|
||||||
)
|
)
|
||||||
return "(<> " + root_hdr + " " + detail_header + ")"
|
return "(<> " + root_hdr + " " + detail_header + ")"
|
||||||
|
|
||||||
|
|
||||||
def _order_detail_oob(ctx: dict, **kw: Any) -> str:
|
async def _order_detail_oob(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import root_header_sx, sx_call, SxExpr
|
from shared.sx.helpers import root_header_sx, render_to_sx
|
||||||
|
from shared.sx.parser import SxExpr
|
||||||
|
|
||||||
detail_url = kw.get("detail_url", "/")
|
detail_url = kw.get("detail_url", "/")
|
||||||
order_row_oob = sx_call(
|
order_row_oob = await render_to_sx(
|
||||||
"menu-row-sx",
|
"menu-row-sx",
|
||||||
id="order-row", level=3, colour="sky", link_href=detail_url,
|
id="order-row", level=3, colour="sky", link_href=detail_url,
|
||||||
link_label="Order", icon="fa fa-gbp", oob=True,
|
link_label="Order", icon="fa fa-gbp", oob=True,
|
||||||
)
|
)
|
||||||
header_child_oob = sx_call("oob-header-sx",
|
header_child_oob = await render_to_sx("oob-header-sx",
|
||||||
parent_id="orders-header-child",
|
parent_id="orders-header-child",
|
||||||
row=SxExpr(order_row_oob))
|
row=SxExpr(order_row_oob))
|
||||||
root_hdr = root_header_sx(ctx, oob=True)
|
root_hdr = await root_header_sx(ctx, oob=True)
|
||||||
return "(<> " + header_child_oob + " " + root_hdr + ")"
|
return "(<> " + header_child_oob + " " + root_hdr + ")"
|
||||||
|
|
||||||
|
|
||||||
def _order_detail_mobile(ctx: dict, **kw: Any) -> str:
|
async def _order_detail_mobile(ctx: dict, **kw: Any) -> str:
|
||||||
from shared.sx.helpers import mobile_menu_sx, mobile_root_nav_sx
|
from shared.sx.helpers import mobile_menu_sx, mobile_root_nav_sx
|
||||||
return mobile_menu_sx(mobile_root_nav_sx(ctx))
|
return mobile_menu_sx(await mobile_root_nav_sx(ctx))
|
||||||
|
|
||||||
|
|
||||||
def _as_sx_nav(ctx: dict) -> Any:
|
def _as_sx_nav(ctx: dict) -> Any:
|
||||||
"""Convert account_nav fragment to SxExpr for use in sx_call."""
|
"""Convert account_nav fragment to SxExpr for use in component calls."""
|
||||||
from shared.sx.helpers import _as_sx
|
from shared.sx.helpers import _as_sx
|
||||||
return _as_sx(ctx.get("account_nav"))
|
return _as_sx(ctx.get("account_nav"))
|
||||||
|
|
||||||
@@ -279,11 +286,10 @@ async def _ensure_order_detail(order_id):
|
|||||||
async def _h_orders_list_content(**kw):
|
async def _h_orders_list_content(**kw):
|
||||||
await _ensure_orders_list()
|
await _ensure_orders_list()
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
d = getattr(g, "orders_page_data", None)
|
d = getattr(g, "orders_page_data", None)
|
||||||
if not d:
|
if not d:
|
||||||
return sx_call("order-empty-state")
|
return await render_to_sx("order-empty-state")
|
||||||
|
|
||||||
orders = d["orders"]
|
orders = d["orders"]
|
||||||
url_for_fn = d["url_for_fn"]
|
url_for_fn = d["url_for_fn"]
|
||||||
@@ -305,8 +311,8 @@ async def _h_orders_list_content(**kw):
|
|||||||
detail_prefix = rpfx + url_for_fn("orders.defpage_order_detail", order_id=0).rsplit("0/", 1)[0]
|
detail_prefix = rpfx + url_for_fn("orders.defpage_order_detail", order_id=0).rsplit("0/", 1)[0]
|
||||||
rows_url = rpfx + url_for_fn("orders.orders_rows")
|
rows_url = rpfx + url_for_fn("orders.orders_rows")
|
||||||
|
|
||||||
return sx_call("orders-list-content",
|
return await render_to_sx("orders-list-content",
|
||||||
orders=SxExpr(serialize(order_dicts)),
|
orders=order_dicts,
|
||||||
page=d["page"],
|
page=d["page"],
|
||||||
total_pages=d["total_pages"],
|
total_pages=d["total_pages"],
|
||||||
rows_url=rows_url,
|
rows_url=rows_url,
|
||||||
@@ -316,30 +322,31 @@ async def _h_orders_list_content(**kw):
|
|||||||
async def _h_orders_list_filter(**kw):
|
async def _h_orders_list_filter(**kw):
|
||||||
await _ensure_orders_list()
|
await _ensure_orders_list()
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.page import SEARCH_HEADERS_MOBILE
|
from shared.sx.page import SEARCH_HEADERS_MOBILE
|
||||||
|
from shared.sx.parser import SxExpr
|
||||||
d = getattr(g, "orders_page_data", None)
|
d = getattr(g, "orders_page_data", None)
|
||||||
search = d.get("search", "") if d else ""
|
search = d.get("search", "") if d else ""
|
||||||
search_count = d.get("search_count", "") if d else ""
|
search_count = d.get("search_count", "") if d else ""
|
||||||
search_mobile = sx_call("search-mobile",
|
search_mobile = await render_to_sx("search-mobile",
|
||||||
current_local_href="/",
|
current_local_href="/",
|
||||||
search=search or "",
|
search=search or "",
|
||||||
search_count=search_count or "",
|
search_count=search_count or "",
|
||||||
hx_select="#main-panel",
|
hx_select="#main-panel",
|
||||||
search_headers_mobile=SEARCH_HEADERS_MOBILE,
|
search_headers_mobile=SEARCH_HEADERS_MOBILE,
|
||||||
)
|
)
|
||||||
return sx_call("order-list-header", search_mobile=SxExpr(search_mobile))
|
return await render_to_sx("order-list-header", search_mobile=SxExpr(search_mobile))
|
||||||
|
|
||||||
|
|
||||||
async def _h_orders_list_aside(**kw):
|
async def _h_orders_list_aside(**kw):
|
||||||
await _ensure_orders_list()
|
await _ensure_orders_list()
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.sx.helpers import sx_call
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.page import SEARCH_HEADERS_DESKTOP
|
from shared.sx.page import SEARCH_HEADERS_DESKTOP
|
||||||
d = getattr(g, "orders_page_data", None)
|
d = getattr(g, "orders_page_data", None)
|
||||||
search = d.get("search", "") if d else ""
|
search = d.get("search", "") if d else ""
|
||||||
search_count = d.get("search_count", "") if d else ""
|
search_count = d.get("search_count", "") if d else ""
|
||||||
return sx_call("search-desktop",
|
return await render_to_sx("search-desktop",
|
||||||
current_local_href="/",
|
current_local_href="/",
|
||||||
search=search or "",
|
search=search or "",
|
||||||
search_count=search_count or "",
|
search_count=search_count or "",
|
||||||
@@ -358,8 +365,7 @@ async def _h_orders_list_url(**kw):
|
|||||||
async def _h_order_detail_content(order_id=None, **kw):
|
async def _h_order_detail_content(order_id=None, **kw):
|
||||||
await _ensure_order_detail(order_id)
|
await _ensure_order_detail(order_id)
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
from shared.infrastructure.urls import market_product_url
|
from shared.infrastructure.urls import market_product_url
|
||||||
d = getattr(g, "order_detail_data", None)
|
d = getattr(g, "order_detail_data", None)
|
||||||
if not d:
|
if not d:
|
||||||
@@ -402,16 +408,15 @@ async def _h_order_detail_content(order_id=None, **kw):
|
|||||||
"cost_formatted": f"{e.cost or 0:.2f}",
|
"cost_formatted": f"{e.cost or 0:.2f}",
|
||||||
})
|
})
|
||||||
|
|
||||||
return sx_call("order-detail-content",
|
return await render_to_sx("order-detail-content",
|
||||||
order=SxExpr(serialize(order_dict)),
|
order=order_dict,
|
||||||
calendar_entries=SxExpr(serialize(cal_dicts)) if cal_dicts else None)
|
calendar_entries=cal_dicts)
|
||||||
|
|
||||||
|
|
||||||
async def _h_order_detail_filter(order_id=None, **kw):
|
async def _h_order_detail_filter(order_id=None, **kw):
|
||||||
await _ensure_order_detail(order_id)
|
await _ensure_order_detail(order_id)
|
||||||
from quart import g
|
from quart import g
|
||||||
from shared.sx.helpers import sx_call, SxExpr
|
from shared.sx.helpers import render_to_sx
|
||||||
from shared.sx.parser import serialize
|
|
||||||
d = getattr(g, "order_detail_data", None)
|
d = getattr(g, "order_detail_data", None)
|
||||||
if not d:
|
if not d:
|
||||||
return ""
|
return ""
|
||||||
@@ -422,8 +427,8 @@ async def _h_order_detail_filter(order_id=None, **kw):
|
|||||||
"created_at_formatted": order.created_at.strftime("%-d %b %Y, %H:%M") if order.created_at else "\u2014",
|
"created_at_formatted": order.created_at.strftime("%-d %b %Y, %H:%M") if order.created_at else "\u2014",
|
||||||
}
|
}
|
||||||
|
|
||||||
return sx_call("order-detail-filter-content",
|
return await render_to_sx("order-detail-filter-content",
|
||||||
order=SxExpr(serialize(order_dict)),
|
order=order_dict,
|
||||||
list_url=d["list_url"],
|
list_url=d["list_url"],
|
||||||
recheck_url=d["recheck_url"],
|
recheck_url=d["recheck_url"],
|
||||||
pay_url=d["pay_url"],
|
pay_url=d["pay_url"],
|
||||||
|
|||||||
@@ -149,22 +149,22 @@ async def _rich_error_page(errnum: str, message: str, image: str | None = None)
|
|||||||
# Root header (site nav bar)
|
# Root header (site nav bar)
|
||||||
from shared.sx.helpers import (
|
from shared.sx.helpers import (
|
||||||
root_header_sx, post_header_sx,
|
root_header_sx, post_header_sx,
|
||||||
header_child_sx, full_page_sx, sx_call,
|
header_child_sx, full_page_sx, render_to_sx,
|
||||||
)
|
)
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
|
|
||||||
# Post breadcrumb if we resolved a post
|
# Post breadcrumb if we resolved a post
|
||||||
post = (post_data or {}).get("post") or ctx.get("post") or {}
|
post = (post_data or {}).get("post") or ctx.get("post") or {}
|
||||||
if post.get("slug"):
|
if post.get("slug"):
|
||||||
ctx["post"] = post
|
ctx["post"] = post
|
||||||
post_row = post_header_sx(ctx)
|
post_row = await post_header_sx(ctx)
|
||||||
if post_row:
|
if post_row:
|
||||||
hdr = "(<> " + hdr + " " + header_child_sx(post_row) + ")"
|
hdr = "(<> " + hdr + " " + await header_child_sx(post_row) + ")"
|
||||||
|
|
||||||
# Error content
|
# Error content
|
||||||
error_content = sx_call("error-content", errnum=errnum, message=message, image=image)
|
error_content = await render_to_sx("error-content", errnum=errnum, message=message, image=image)
|
||||||
|
|
||||||
return full_page_sx(ctx, header_rows=hdr, content=error_content)
|
return await full_page_sx(ctx, header_rows=hdr, content=error_content)
|
||||||
except Exception:
|
except Exception:
|
||||||
current_app.logger.debug("Rich error page failed, falling back", exc_info=True)
|
current_app.logger.debug("Rich error page failed, falling back", exc_info=True)
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -114,18 +114,18 @@ async def _render_profile_sx(actor, activities, total):
|
|||||||
# Import federation layout for OOB headers
|
# Import federation layout for OOB headers
|
||||||
try:
|
try:
|
||||||
from federation.sxc.pages import _social_oob
|
from federation.sxc.pages import _social_oob
|
||||||
oob_headers = _social_oob(tctx)
|
oob_headers = await _social_oob(tctx)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
oob_headers = ""
|
oob_headers = ""
|
||||||
return sx_response(oob_page_sx(oobs=oob_headers, content=content))
|
return sx_response(await oob_page_sx(oobs=oob_headers, content=content))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
from federation.sxc.pages import _social_full
|
from federation.sxc.pages import _social_full
|
||||||
header_rows = _social_full(tctx)
|
header_rows = await _social_full(tctx)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from shared.sx.helpers import root_header_sx
|
from shared.sx.helpers import root_header_sx
|
||||||
header_rows = root_header_sx(tctx)
|
header_rows = await root_header_sx(tctx)
|
||||||
return full_page_sx(tctx, header_rows=header_rows, content=content)
|
return await full_page_sx(tctx, header_rows=header_rows, content=content)
|
||||||
|
|
||||||
|
|
||||||
def create_activitypub_blueprint(app_name: str) -> Blueprint:
|
def create_activitypub_blueprint(app_name: str) -> Blueprint:
|
||||||
|
|||||||
@@ -92,14 +92,14 @@ def create_ap_social_blueprint(app_name: str) -> Blueprint:
|
|||||||
kw = {"actor": actor}
|
kw = {"actor": actor}
|
||||||
|
|
||||||
if is_htmx_request():
|
if is_htmx_request():
|
||||||
oob_headers = _social_oob_headers(tctx, **kw)
|
oob_headers = await _social_oob_headers(tctx, **kw)
|
||||||
return sx_response(oob_page_sx(
|
return sx_response(await oob_page_sx(
|
||||||
oobs=oob_headers,
|
oobs=oob_headers,
|
||||||
content=content,
|
content=content,
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
header_rows = _social_full_headers(tctx, **kw)
|
header_rows = await _social_full_headers(tctx, **kw)
|
||||||
return full_page_sx(tctx, header_rows=header_rows, content=content)
|
return await full_page_sx(tctx, header_rows=header_rows, content=content)
|
||||||
|
|
||||||
# -- Index ----------------------------------------------------------------
|
# -- Index ----------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,9 @@ from typing import Any
|
|||||||
from markupsafe import escape
|
from markupsafe import escape
|
||||||
|
|
||||||
from shared.sx.helpers import (
|
from shared.sx.helpers import (
|
||||||
sx_call, root_header_sx, oob_header_sx,
|
root_header_sx, oob_header_sx,
|
||||||
mobile_menu_sx, mobile_root_nav_sx, full_page_sx, oob_page_sx,
|
mobile_menu_sx, mobile_root_nav_sx, full_page_sx, oob_page_sx,
|
||||||
)
|
)
|
||||||
from shared.sx.parser import SxExpr
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -91,23 +90,23 @@ def _social_header_row(actor: Any) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _social_full_headers(ctx: dict, **kw: Any) -> str:
|
async def _social_full_headers(ctx: dict, **kw: Any) -> str:
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
actor = kw.get("actor")
|
actor = kw.get("actor")
|
||||||
social_row = _social_header_row(actor)
|
social_row = _social_header_row(actor)
|
||||||
return "(<> " + root_hdr + " " + social_row + ")"
|
return "(<> " + root_hdr + " " + social_row + ")"
|
||||||
|
|
||||||
|
|
||||||
def _social_oob_headers(ctx: dict, **kw: Any) -> str:
|
async def _social_oob_headers(ctx: dict, **kw: Any) -> str:
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
actor = kw.get("actor")
|
actor = kw.get("actor")
|
||||||
social_row = _social_header_row(actor)
|
social_row = _social_header_row(actor)
|
||||||
rows = "(<> " + root_hdr + " " + social_row + ")"
|
rows = "(<> " + root_hdr + " " + social_row + ")"
|
||||||
return oob_header_sx("root-header-child", "social-lite-header-child", rows)
|
return await oob_header_sx("root-header-child", "social-lite-header-child", rows)
|
||||||
|
|
||||||
|
|
||||||
def _social_mobile(ctx: dict, **kw: Any) -> str:
|
async def _social_mobile(ctx: dict, **kw: Any) -> str:
|
||||||
return mobile_menu_sx(mobile_root_nav_sx(ctx))
|
return mobile_menu_sx(await mobile_root_nav_sx(ctx))
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -83,12 +83,12 @@ def _as_sx(val: Any) -> SxExpr | None:
|
|||||||
return SxExpr(f'(~rich-text :html "{escaped}")')
|
return SxExpr(f'(~rich-text :html "{escaped}")')
|
||||||
|
|
||||||
|
|
||||||
def root_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
async def root_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
||||||
"""Build the root header row as a sx call string."""
|
"""Build the root header row as sx wire format."""
|
||||||
rights = ctx.get("rights") or {}
|
rights = ctx.get("rights") or {}
|
||||||
is_admin = rights.get("admin") if isinstance(rights, dict) else getattr(rights, "admin", False)
|
is_admin = rights.get("admin") if isinstance(rights, dict) else getattr(rights, "admin", False)
|
||||||
settings_url = call_url(ctx, "blog_url", "/settings/") if is_admin else ""
|
settings_url = call_url(ctx, "blog_url", "/settings/") if is_admin else ""
|
||||||
return sx_call("header-row-sx",
|
return await render_to_sx("header-row-sx",
|
||||||
cart_mini=_as_sx(ctx.get("cart_mini")),
|
cart_mini=_as_sx(ctx.get("cart_mini")),
|
||||||
blog_url=call_url(ctx, "blog_url", ""),
|
blog_url=call_url(ctx, "blog_url", ""),
|
||||||
site_title=ctx.get("base_title", ""),
|
site_title=ctx.get("base_title", ""),
|
||||||
@@ -108,13 +108,13 @@ def mobile_menu_sx(*sections: str) -> str:
|
|||||||
return "(<> " + " ".join(parts) + ")" if parts else ""
|
return "(<> " + " ".join(parts) + ")" if parts else ""
|
||||||
|
|
||||||
|
|
||||||
def mobile_root_nav_sx(ctx: dict) -> str:
|
async def mobile_root_nav_sx(ctx: dict) -> str:
|
||||||
"""Root-level mobile nav via ~mobile-root-nav component."""
|
"""Root-level mobile nav via ~mobile-root-nav component."""
|
||||||
nav_tree = ctx.get("nav_tree") or ""
|
nav_tree = ctx.get("nav_tree") or ""
|
||||||
auth_menu = ctx.get("auth_menu") or ""
|
auth_menu = ctx.get("auth_menu") or ""
|
||||||
if not nav_tree and not auth_menu:
|
if not nav_tree and not auth_menu:
|
||||||
return ""
|
return ""
|
||||||
return sx_call("mobile-root-nav",
|
return await render_to_sx("mobile-root-nav",
|
||||||
nav_tree=_as_sx(nav_tree),
|
nav_tree=_as_sx(nav_tree),
|
||||||
auth_menu=_as_sx(auth_menu),
|
auth_menu=_as_sx(auth_menu),
|
||||||
)
|
)
|
||||||
@@ -124,7 +124,7 @@ def mobile_root_nav_sx(ctx: dict) -> str:
|
|||||||
# Shared nav-item builders — used by BOTH desktop headers and mobile menus
|
# Shared nav-item builders — used by BOTH desktop headers and mobile menus
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _post_nav_items_sx(ctx: dict) -> str:
|
async def _post_nav_items_sx(ctx: dict) -> str:
|
||||||
"""Build post-level nav items (container_nav + admin cog). Shared by
|
"""Build post-level nav items (container_nav + admin cog). Shared by
|
||||||
``post_header_sx`` (desktop) and ``post_mobile_nav_sx`` (mobile)."""
|
``post_header_sx`` (desktop) and ``post_mobile_nav_sx`` (mobile)."""
|
||||||
post = ctx.get("post") or {}
|
post = ctx.get("post") or {}
|
||||||
@@ -135,7 +135,7 @@ def _post_nav_items_sx(ctx: dict) -> str:
|
|||||||
page_cart_count = ctx.get("page_cart_count", 0)
|
page_cart_count = ctx.get("page_cart_count", 0)
|
||||||
if page_cart_count and page_cart_count > 0:
|
if page_cart_count and page_cart_count > 0:
|
||||||
cart_href = call_url(ctx, "cart_url", f"/{slug}/")
|
cart_href = call_url(ctx, "cart_url", f"/{slug}/")
|
||||||
parts.append(sx_call("page-cart-badge", href=cart_href,
|
parts.append(await render_to_sx("page-cart-badge", href=cart_href,
|
||||||
count=str(page_cart_count)))
|
count=str(page_cart_count)))
|
||||||
|
|
||||||
container_nav = str(ctx.get("container_nav") or "").strip()
|
container_nav = str(ctx.get("container_nav") or "").strip()
|
||||||
@@ -171,7 +171,7 @@ def _post_nav_items_sx(ctx: dict) -> str:
|
|||||||
return "(<> " + " ".join(parts) + ")" if parts else ""
|
return "(<> " + " ".join(parts) + ")" if parts else ""
|
||||||
|
|
||||||
|
|
||||||
def _post_admin_nav_items_sx(ctx: dict, slug: str,
|
async def _post_admin_nav_items_sx(ctx: dict, slug: str,
|
||||||
selected: str = "") -> str:
|
selected: str = "") -> str:
|
||||||
"""Build post-admin nav items (calendars, markets, etc.). Shared by
|
"""Build post-admin nav items (calendars, markets, etc.). Shared by
|
||||||
``post_admin_header_sx`` (desktop) and mobile menu."""
|
``post_admin_header_sx`` (desktop) and mobile menu."""
|
||||||
@@ -193,7 +193,7 @@ def _post_admin_nav_items_sx(ctx: dict, slug: str,
|
|||||||
continue
|
continue
|
||||||
href = url_fn(path)
|
href = url_fn(path)
|
||||||
is_sel = label == selected
|
is_sel = label == selected
|
||||||
parts.append(sx_call("nav-link", href=href, label=label,
|
parts.append(await render_to_sx("nav-link", href=href, label=label,
|
||||||
select_colours=select_colours,
|
select_colours=select_colours,
|
||||||
is_selected=is_sel or None))
|
is_selected=is_sel or None))
|
||||||
return "(<> " + " ".join(parts) + ")" if parts else ""
|
return "(<> " + " ".join(parts) + ")" if parts else ""
|
||||||
@@ -203,15 +203,15 @@ def _post_admin_nav_items_sx(ctx: dict, slug: str,
|
|||||||
# Mobile menu section builders — wrap shared nav items for hamburger panel
|
# Mobile menu section builders — wrap shared nav items for hamburger panel
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def post_mobile_nav_sx(ctx: dict) -> str:
|
async def post_mobile_nav_sx(ctx: dict) -> str:
|
||||||
"""Post-level mobile menu section."""
|
"""Post-level mobile menu section."""
|
||||||
nav = _post_nav_items_sx(ctx)
|
nav = await _post_nav_items_sx(ctx)
|
||||||
if not nav:
|
if not nav:
|
||||||
return ""
|
return ""
|
||||||
post = ctx.get("post") or {}
|
post = ctx.get("post") or {}
|
||||||
slug = post.get("slug", "")
|
slug = post.get("slug", "")
|
||||||
title = (post.get("title") or slug)[:40]
|
title = (post.get("title") or slug)[:40]
|
||||||
return sx_call("mobile-menu-section",
|
return await render_to_sx("mobile-menu-section",
|
||||||
label=title,
|
label=title,
|
||||||
href=call_url(ctx, "blog_url", f"/{slug}/"),
|
href=call_url(ctx, "blog_url", f"/{slug}/"),
|
||||||
level=1,
|
level=1,
|
||||||
@@ -219,22 +219,22 @@ def post_mobile_nav_sx(ctx: dict) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def post_admin_mobile_nav_sx(ctx: dict, slug: str,
|
async def post_admin_mobile_nav_sx(ctx: dict, slug: str,
|
||||||
selected: str = "") -> str:
|
selected: str = "") -> str:
|
||||||
"""Post-admin mobile menu section."""
|
"""Post-admin mobile menu section."""
|
||||||
nav = _post_admin_nav_items_sx(ctx, slug, selected)
|
nav = await _post_admin_nav_items_sx(ctx, slug, selected)
|
||||||
if not nav:
|
if not nav:
|
||||||
return ""
|
return ""
|
||||||
admin_href = call_url(ctx, "blog_url", f"/{slug}/admin/")
|
admin_href = call_url(ctx, "blog_url", f"/{slug}/admin/")
|
||||||
return sx_call("mobile-menu-section",
|
return await render_to_sx("mobile-menu-section",
|
||||||
label="admin", href=admin_href, level=2,
|
label="admin", href=admin_href, level=2,
|
||||||
items=SxExpr(nav),
|
items=SxExpr(nav),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def search_mobile_sx(ctx: dict) -> str:
|
async def search_mobile_sx(ctx: dict) -> str:
|
||||||
"""Build mobile search input as sx call string."""
|
"""Build mobile search input as sx wire format."""
|
||||||
return sx_call("search-mobile",
|
return await render_to_sx("search-mobile",
|
||||||
current_local_href=ctx.get("current_local_href", "/"),
|
current_local_href=ctx.get("current_local_href", "/"),
|
||||||
search=ctx.get("search", ""),
|
search=ctx.get("search", ""),
|
||||||
search_count=ctx.get("search_count", ""),
|
search_count=ctx.get("search_count", ""),
|
||||||
@@ -243,9 +243,9 @@ def search_mobile_sx(ctx: dict) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def search_desktop_sx(ctx: dict) -> str:
|
async def search_desktop_sx(ctx: dict) -> str:
|
||||||
"""Build desktop search input as sx call string."""
|
"""Build desktop search input as sx wire format."""
|
||||||
return sx_call("search-desktop",
|
return await render_to_sx("search-desktop",
|
||||||
current_local_href=ctx.get("current_local_href", "/"),
|
current_local_href=ctx.get("current_local_href", "/"),
|
||||||
search=ctx.get("search", ""),
|
search=ctx.get("search", ""),
|
||||||
search_count=ctx.get("search_count", ""),
|
search_count=ctx.get("search_count", ""),
|
||||||
@@ -254,8 +254,8 @@ def search_desktop_sx(ctx: dict) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def post_header_sx(ctx: dict, *, oob: bool = False, child: str = "") -> str:
|
async def post_header_sx(ctx: dict, *, oob: bool = False, child: str = "") -> str:
|
||||||
"""Build the post-level header row as sx call string."""
|
"""Build the post-level header row as sx wire format."""
|
||||||
post = ctx.get("post") or {}
|
post = ctx.get("post") or {}
|
||||||
slug = post.get("slug", "")
|
slug = post.get("slug", "")
|
||||||
if not slug:
|
if not slug:
|
||||||
@@ -263,11 +263,11 @@ def post_header_sx(ctx: dict, *, oob: bool = False, child: str = "") -> str:
|
|||||||
title = (post.get("title") or "")[:160]
|
title = (post.get("title") or "")[:160]
|
||||||
feature_image = post.get("feature_image")
|
feature_image = post.get("feature_image")
|
||||||
|
|
||||||
label_sx = sx_call("post-label", feature_image=feature_image, title=title)
|
label_sx = await render_to_sx("post-label", feature_image=feature_image, title=title)
|
||||||
nav_sx = _post_nav_items_sx(ctx) or None
|
nav_sx = await _post_nav_items_sx(ctx) or None
|
||||||
link_href = call_url(ctx, "blog_url", f"/{slug}/")
|
link_href = call_url(ctx, "blog_url", f"/{slug}/")
|
||||||
|
|
||||||
return sx_call("menu-row-sx",
|
return await render_to_sx("menu-row-sx",
|
||||||
id="post-row", level=1,
|
id="post-row", level=1,
|
||||||
link_href=link_href,
|
link_href=link_href,
|
||||||
link_label_content=SxExpr(label_sx),
|
link_label_content=SxExpr(label_sx),
|
||||||
@@ -278,22 +278,22 @@ def post_header_sx(ctx: dict, *, oob: bool = False, child: str = "") -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def post_admin_header_sx(ctx: dict, slug: str, *, oob: bool = False,
|
async def post_admin_header_sx(ctx: dict, slug: str, *, oob: bool = False,
|
||||||
selected: str = "", admin_href: str = "") -> str:
|
selected: str = "", admin_href: str = "") -> str:
|
||||||
"""Post admin header row as sx call string."""
|
"""Post admin header row as sx wire format."""
|
||||||
# Label
|
# Label
|
||||||
label_parts = ['(i :class "fa fa-shield-halved" :aria-hidden "true")', '" admin"']
|
label_parts = ['(i :class "fa fa-shield-halved" :aria-hidden "true")', '" admin"']
|
||||||
if selected:
|
if selected:
|
||||||
label_parts.append(f'(span :class "text-white" "{escape(selected)}")')
|
label_parts.append(f'(span :class "text-white" "{escape(selected)}")')
|
||||||
label_sx = "(<> " + " ".join(label_parts) + ")"
|
label_sx = "(<> " + " ".join(label_parts) + ")"
|
||||||
|
|
||||||
nav_sx = _post_admin_nav_items_sx(ctx, slug, selected) or None
|
nav_sx = await _post_admin_nav_items_sx(ctx, slug, selected) or None
|
||||||
|
|
||||||
if not admin_href:
|
if not admin_href:
|
||||||
blog_fn = ctx.get("blog_url")
|
blog_fn = ctx.get("blog_url")
|
||||||
admin_href = blog_fn(f"/{slug}/admin/") if callable(blog_fn) else f"/{slug}/admin/"
|
admin_href = blog_fn(f"/{slug}/admin/") if callable(blog_fn) else f"/{slug}/admin/"
|
||||||
|
|
||||||
return sx_call("menu-row-sx",
|
return await render_to_sx("menu-row-sx",
|
||||||
id="post-admin-row", level=2,
|
id="post-admin-row", level=2,
|
||||||
link_href=admin_href,
|
link_href=admin_href,
|
||||||
link_label_content=SxExpr(label_sx),
|
link_label_content=SxExpr(label_sx),
|
||||||
@@ -302,29 +302,29 @@ def post_admin_header_sx(ctx: dict, slug: str, *, oob: bool = False,
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def oob_header_sx(parent_id: str, child_id: str, row_sx: str) -> str:
|
async def oob_header_sx(parent_id: str, child_id: str, row_sx: str) -> str:
|
||||||
"""Wrap a header row sx in an OOB swap.
|
"""Wrap a header row sx in an OOB swap.
|
||||||
|
|
||||||
child_id is accepted for call-site compatibility but no longer used —
|
child_id is accepted for call-site compatibility but no longer used —
|
||||||
the child placeholder is created by ~menu-row-sx itself.
|
the child placeholder is created by ~menu-row-sx itself.
|
||||||
"""
|
"""
|
||||||
return sx_call("oob-header-sx",
|
return await render_to_sx("oob-header-sx",
|
||||||
parent_id=parent_id,
|
parent_id=parent_id,
|
||||||
row=SxExpr(row_sx),
|
row=SxExpr(row_sx),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def header_child_sx(inner_sx: str, *, id: str = "root-header-child") -> str:
|
async def header_child_sx(inner_sx: str, *, id: str = "root-header-child") -> str:
|
||||||
"""Wrap inner sx in a header-child div."""
|
"""Wrap inner sx in a header-child div."""
|
||||||
return sx_call("header-child-sx",
|
return await render_to_sx("header-child-sx",
|
||||||
id=id, inner=SxExpr(f"(<> {inner_sx})"),
|
id=id, inner=SxExpr(f"(<> {inner_sx})"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def oob_page_sx(*, oobs: str = "", filter: str = "", aside: str = "",
|
async def oob_page_sx(*, oobs: str = "", filter: str = "", aside: str = "",
|
||||||
content: str = "", menu: str = "") -> str:
|
content: str = "", menu: str = "") -> str:
|
||||||
"""Build OOB response as sx call string."""
|
"""Build OOB response as sx wire format."""
|
||||||
return sx_call("oob-sx",
|
return await render_to_sx("oob-sx",
|
||||||
oobs=SxExpr(f"(<> {oobs})") if oobs else None,
|
oobs=SxExpr(f"(<> {oobs})") if oobs else None,
|
||||||
filter=SxExpr(filter) if filter else None,
|
filter=SxExpr(filter) if filter else None,
|
||||||
aside=SxExpr(aside) if aside else None,
|
aside=SxExpr(aside) if aside else None,
|
||||||
@@ -333,7 +333,7 @@ def oob_page_sx(*, oobs: str = "", filter: str = "", aside: str = "",
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def full_page_sx(ctx: dict, *, header_rows: str,
|
async def full_page_sx(ctx: dict, *, header_rows: str,
|
||||||
filter: str = "", aside: str = "",
|
filter: str = "", aside: str = "",
|
||||||
content: str = "", menu: str = "",
|
content: str = "", menu: str = "",
|
||||||
meta_html: str = "", meta: str = "") -> str:
|
meta_html: str = "", meta: str = "") -> str:
|
||||||
@@ -344,8 +344,8 @@ def full_page_sx(ctx: dict, *, header_rows: str,
|
|||||||
"""
|
"""
|
||||||
# Auto-generate mobile nav from context when no menu provided
|
# Auto-generate mobile nav from context when no menu provided
|
||||||
if not menu:
|
if not menu:
|
||||||
menu = mobile_root_nav_sx(ctx)
|
menu = await mobile_root_nav_sx(ctx)
|
||||||
body_sx = sx_call("app-body",
|
body_sx = await render_to_sx("app-body",
|
||||||
header_rows=SxExpr(f"(<> {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,
|
filter=SxExpr(filter) if filter else None,
|
||||||
aside=SxExpr(aside) if aside else None,
|
aside=SxExpr(aside) if aside else None,
|
||||||
@@ -359,6 +359,64 @@ def full_page_sx(ctx: dict, *, header_rows: str,
|
|||||||
return sx_page(ctx, body_sx, meta_html=meta_html)
|
return sx_page(ctx, body_sx, meta_html=meta_html)
|
||||||
|
|
||||||
|
|
||||||
|
def _build_component_ast(__name: str, **kwargs: Any) -> list:
|
||||||
|
"""Build an AST list for a component call from Python kwargs.
|
||||||
|
|
||||||
|
Returns e.g. [Symbol("~card"), Keyword("title"), "hello", Keyword("count"), 3]
|
||||||
|
No SX string generation — values stay as native Python objects.
|
||||||
|
"""
|
||||||
|
from .types import Symbol, Keyword, NIL
|
||||||
|
comp_sym = Symbol(__name if __name.startswith("~") else f"~{__name}")
|
||||||
|
ast: list = [comp_sym]
|
||||||
|
for key, val in kwargs.items():
|
||||||
|
kebab = key.replace("_", "-")
|
||||||
|
ast.append(Keyword(kebab))
|
||||||
|
if val is None:
|
||||||
|
ast.append(NIL)
|
||||||
|
elif isinstance(val, SxExpr):
|
||||||
|
# SxExpr values need to be parsed into AST
|
||||||
|
from .parser import parse
|
||||||
|
ast.append(parse(val.source))
|
||||||
|
else:
|
||||||
|
ast.append(val)
|
||||||
|
return ast
|
||||||
|
|
||||||
|
|
||||||
|
async def render_to_sx(__name: str, **kwargs: Any) -> str:
|
||||||
|
"""Call a defcomp and get SX wire format back. No SX string literals.
|
||||||
|
|
||||||
|
Builds an AST from Python values and evaluates it through the SX
|
||||||
|
evaluator, which resolves IO primitives and serializes component/tag
|
||||||
|
calls as SX wire format.
|
||||||
|
|
||||||
|
await render_to_sx("card", title="hello", count=3)
|
||||||
|
# equivalent to old: sx_call("card", title="hello", count=3)
|
||||||
|
# but values flow as native objects, not serialized strings
|
||||||
|
"""
|
||||||
|
from .jinja_bridge import get_component_env, _get_request_context
|
||||||
|
from .async_eval import async_eval_to_sx
|
||||||
|
|
||||||
|
ast = _build_component_ast(__name, **kwargs)
|
||||||
|
env = dict(get_component_env())
|
||||||
|
ctx = _get_request_context()
|
||||||
|
return await async_eval_to_sx(ast, env, ctx)
|
||||||
|
|
||||||
|
|
||||||
|
async def render_to_html(__name: str, **kwargs: Any) -> str:
|
||||||
|
"""Call a defcomp and get HTML back. No SX string literals.
|
||||||
|
|
||||||
|
Same as render_to_sx() but produces HTML output instead of SX wire
|
||||||
|
format. Used by route renders that need HTML (full pages, fragments).
|
||||||
|
"""
|
||||||
|
from .jinja_bridge import get_component_env, _get_request_context
|
||||||
|
from .async_eval import async_render
|
||||||
|
|
||||||
|
ast = _build_component_ast(__name, **kwargs)
|
||||||
|
env = dict(get_component_env())
|
||||||
|
ctx = _get_request_context()
|
||||||
|
return await async_render(ast, env, ctx)
|
||||||
|
|
||||||
|
|
||||||
def sx_call(component_name: str, **kwargs: Any) -> str:
|
def sx_call(component_name: str, **kwargs: Any) -> str:
|
||||||
"""Build an s-expression component call string from Python kwargs.
|
"""Build an s-expression component call string from Python kwargs.
|
||||||
|
|
||||||
@@ -428,27 +486,19 @@ def components_for_request() -> str:
|
|||||||
return "\n".join(parts)
|
return "\n".join(parts)
|
||||||
|
|
||||||
|
|
||||||
def sx_response(source_or_component: str, status: int = 200,
|
def sx_response(source: str, status: int = 200,
|
||||||
headers: dict | None = None, **kwargs: Any):
|
headers: dict | None = None):
|
||||||
"""Return an s-expression wire-format response.
|
"""Return an s-expression wire-format response.
|
||||||
|
|
||||||
Can be called with a raw sx string::
|
Takes a raw sx string::
|
||||||
|
|
||||||
return sx_response('(~test-row :nodeid "foo")')
|
return sx_response('(~test-row :nodeid "foo")')
|
||||||
|
|
||||||
Or with a component name + kwargs (builds the sx call)::
|
|
||||||
|
|
||||||
return sx_response("test-row", nodeid="foo", outcome="passed")
|
|
||||||
|
|
||||||
For SX requests, missing component definitions are prepended as a
|
For SX requests, missing component definitions are prepended as a
|
||||||
``<script type="text/sx" data-components>`` block so the client
|
``<script type="text/sx" data-components>`` block so the client
|
||||||
can process them before rendering OOB content.
|
can process them before rendering OOB content.
|
||||||
"""
|
"""
|
||||||
from quart import request, Response
|
from quart import request, Response
|
||||||
if kwargs:
|
|
||||||
source = sx_call(source_or_component, **kwargs)
|
|
||||||
else:
|
|
||||||
source = source_or_component
|
|
||||||
|
|
||||||
body = source
|
body = source
|
||||||
# Validate the sx source parses as a single expression
|
# Validate the sx source parses as a single expression
|
||||||
|
|||||||
@@ -87,61 +87,61 @@ def get_layout(name: str) -> Layout | None:
|
|||||||
# Built-in layouts
|
# Built-in layouts
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _root_full(ctx: dict, **kw: Any) -> str:
|
async def _root_full(ctx: dict, **kw: Any) -> str:
|
||||||
return root_header_sx(ctx)
|
return await root_header_sx(ctx)
|
||||||
|
|
||||||
|
|
||||||
def _root_oob(ctx: dict, **kw: Any) -> str:
|
async def _root_oob(ctx: dict, **kw: Any) -> str:
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
return oob_header_sx("root-header-child", "root-header-child", root_hdr)
|
return await oob_header_sx("root-header-child", "root-header-child", root_hdr)
|
||||||
|
|
||||||
|
|
||||||
def _post_full(ctx: dict, **kw: Any) -> str:
|
async def _post_full(ctx: dict, **kw: Any) -> str:
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
post_hdr = post_header_sx(ctx)
|
post_hdr = await post_header_sx(ctx)
|
||||||
return "(<> " + root_hdr + " " + post_hdr + ")"
|
return "(<> " + root_hdr + " " + post_hdr + ")"
|
||||||
|
|
||||||
|
|
||||||
def _post_oob(ctx: dict, **kw: Any) -> str:
|
async def _post_oob(ctx: dict, **kw: Any) -> str:
|
||||||
post_hdr = post_header_sx(ctx, oob=True)
|
post_hdr = await post_header_sx(ctx, oob=True)
|
||||||
# Also replace #post-header-child (empty — clears any nested admin rows)
|
# Also replace #post-header-child (empty — clears any nested admin rows)
|
||||||
child_oob = oob_header_sx("post-header-child", "", "")
|
child_oob = await oob_header_sx("post-header-child", "", "")
|
||||||
return "(<> " + post_hdr + " " + child_oob + ")"
|
return "(<> " + post_hdr + " " + child_oob + ")"
|
||||||
|
|
||||||
|
|
||||||
def _post_admin_full(ctx: dict, **kw: Any) -> str:
|
async def _post_admin_full(ctx: dict, **kw: Any) -> str:
|
||||||
slug = ctx.get("post", {}).get("slug", "")
|
slug = ctx.get("post", {}).get("slug", "")
|
||||||
selected = kw.get("selected", "")
|
selected = kw.get("selected", "")
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
admin_hdr = post_admin_header_sx(ctx, slug, selected=selected)
|
admin_hdr = await post_admin_header_sx(ctx, slug, selected=selected)
|
||||||
post_hdr = post_header_sx(ctx, child=admin_hdr)
|
post_hdr = await post_header_sx(ctx, child=admin_hdr)
|
||||||
return "(<> " + root_hdr + " " + post_hdr + ")"
|
return "(<> " + root_hdr + " " + post_hdr + ")"
|
||||||
|
|
||||||
|
|
||||||
def _post_admin_oob(ctx: dict, **kw: Any) -> str:
|
async def _post_admin_oob(ctx: dict, **kw: Any) -> str:
|
||||||
slug = ctx.get("post", {}).get("slug", "")
|
slug = ctx.get("post", {}).get("slug", "")
|
||||||
selected = kw.get("selected", "")
|
selected = kw.get("selected", "")
|
||||||
post_hdr = post_header_sx(ctx, oob=True)
|
post_hdr = await post_header_sx(ctx, oob=True)
|
||||||
admin_hdr = post_admin_header_sx(ctx, slug, selected=selected)
|
admin_hdr = await post_admin_header_sx(ctx, slug, selected=selected)
|
||||||
admin_oob = oob_header_sx("post-header-child", "post-admin-header-child", admin_hdr)
|
admin_oob = await oob_header_sx("post-header-child", "post-admin-header-child", admin_hdr)
|
||||||
return "(<> " + post_hdr + " " + admin_oob + ")"
|
return "(<> " + post_hdr + " " + admin_oob + ")"
|
||||||
|
|
||||||
|
|
||||||
def _root_mobile(ctx: dict, **kw: Any) -> str:
|
async def _root_mobile(ctx: dict, **kw: Any) -> str:
|
||||||
return mobile_root_nav_sx(ctx)
|
return await mobile_root_nav_sx(ctx)
|
||||||
|
|
||||||
|
|
||||||
def _post_mobile(ctx: dict, **kw: Any) -> str:
|
async def _post_mobile(ctx: dict, **kw: Any) -> str:
|
||||||
return mobile_menu_sx(post_mobile_nav_sx(ctx), mobile_root_nav_sx(ctx))
|
return mobile_menu_sx(await post_mobile_nav_sx(ctx), await mobile_root_nav_sx(ctx))
|
||||||
|
|
||||||
|
|
||||||
def _post_admin_mobile(ctx: dict, **kw: Any) -> str:
|
async def _post_admin_mobile(ctx: dict, **kw: Any) -> str:
|
||||||
slug = ctx.get("post", {}).get("slug", "")
|
slug = ctx.get("post", {}).get("slug", "")
|
||||||
selected = kw.get("selected", "")
|
selected = kw.get("selected", "")
|
||||||
return mobile_menu_sx(
|
return mobile_menu_sx(
|
||||||
post_admin_mobile_nav_sx(ctx, slug, selected),
|
await post_admin_mobile_nav_sx(ctx, slug, selected),
|
||||||
post_mobile_nav_sx(ctx),
|
await post_mobile_nav_sx(ctx),
|
||||||
mobile_root_nav_sx(ctx),
|
await mobile_root_nav_sx(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ async def execute_page(
|
|||||||
is_htmx = is_htmx_request()
|
is_htmx = is_htmx_request()
|
||||||
|
|
||||||
if is_htmx:
|
if is_htmx:
|
||||||
return sx_response(oob_page_sx(
|
return sx_response(await oob_page_sx(
|
||||||
oobs=oob_headers if oob_headers else "",
|
oobs=oob_headers if oob_headers else "",
|
||||||
filter=filter_sx,
|
filter=filter_sx,
|
||||||
aside=aside_sx,
|
aside=aside_sx,
|
||||||
@@ -276,7 +276,7 @@ async def execute_page(
|
|||||||
menu=menu_sx,
|
menu=menu_sx,
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
return full_page_sx(
|
return await full_page_sx(
|
||||||
tctx,
|
tctx,
|
||||||
header_rows=header_rows,
|
header_rows=header_rows,
|
||||||
filter=filter_sx,
|
filter=filter_sx,
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ IO_PRIMITIVES: frozenset[str] = frozenset({
|
|||||||
"get-children",
|
"get-children",
|
||||||
"g",
|
"g",
|
||||||
"csrf-token",
|
"csrf-token",
|
||||||
|
"abort",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@@ -328,6 +329,22 @@ async def _io_csrf_token(
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
async def _io_abort(
|
||||||
|
args: list[Any], kwargs: dict[str, Any], ctx: RequestContext
|
||||||
|
) -> Any:
|
||||||
|
"""``(abort 403 "message")`` — raise HTTP error from SX.
|
||||||
|
|
||||||
|
Allows defpages to abort with HTTP error codes for auth/ownership
|
||||||
|
checks without needing a Python page helper.
|
||||||
|
"""
|
||||||
|
if not args:
|
||||||
|
raise ValueError("abort requires a status code")
|
||||||
|
from quart import abort
|
||||||
|
status = int(args[0])
|
||||||
|
message = str(args[1]) if len(args) > 1 else ""
|
||||||
|
abort(status, message)
|
||||||
|
|
||||||
|
|
||||||
_IO_HANDLERS: dict[str, Any] = {
|
_IO_HANDLERS: dict[str, Any] = {
|
||||||
"frag": _io_frag,
|
"frag": _io_frag,
|
||||||
"query": _io_query,
|
"query": _io_query,
|
||||||
@@ -341,4 +358,5 @@ _IO_HANDLERS: dict[str, Any] = {
|
|||||||
"get-children": _io_get_children,
|
"get-children": _io_get_children,
|
||||||
"g": _io_g,
|
"g": _io_g,
|
||||||
"csrf-token": _io_csrf_token,
|
"csrf-token": _io_csrf_token,
|
||||||
|
"abort": _io_abort,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,30 +34,30 @@ def _register_sx_layouts() -> None:
|
|||||||
register_custom_layout("sx-section", _sx_section_full_headers, _sx_section_oob_headers, _sx_section_mobile)
|
register_custom_layout("sx-section", _sx_section_full_headers, _sx_section_oob_headers, _sx_section_mobile)
|
||||||
|
|
||||||
|
|
||||||
def _sx_full_headers(ctx: dict, **kw: Any) -> str:
|
async def _sx_full_headers(ctx: dict, **kw: Any) -> str:
|
||||||
"""Full headers for sx home page: root + sx menu row."""
|
"""Full headers for sx home page: root + sx menu row."""
|
||||||
from shared.sx.helpers import root_header_sx
|
from shared.sx.helpers import root_header_sx
|
||||||
from sxc.sx_components import _sx_header_sx, _main_nav_sx
|
from sxc.sx_components import _sx_header_sx, _main_nav_sx
|
||||||
|
|
||||||
main_nav = _main_nav_sx(kw.get("section"))
|
main_nav = await _main_nav_sx(kw.get("section"))
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
sx_row = _sx_header_sx(main_nav)
|
sx_row = await _sx_header_sx(main_nav)
|
||||||
return "(<> " + root_hdr + " " + sx_row + ")"
|
return "(<> " + root_hdr + " " + sx_row + ")"
|
||||||
|
|
||||||
|
|
||||||
def _sx_oob_headers(ctx: dict, **kw: Any) -> str:
|
async def _sx_oob_headers(ctx: dict, **kw: Any) -> str:
|
||||||
"""OOB headers for sx home page."""
|
"""OOB headers for sx home page."""
|
||||||
from shared.sx.helpers import root_header_sx, oob_header_sx
|
from shared.sx.helpers import root_header_sx, oob_header_sx
|
||||||
from sxc.sx_components import _sx_header_sx, _main_nav_sx
|
from sxc.sx_components import _sx_header_sx, _main_nav_sx
|
||||||
|
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
main_nav = _main_nav_sx(kw.get("section"))
|
main_nav = await _main_nav_sx(kw.get("section"))
|
||||||
sx_row = _sx_header_sx(main_nav)
|
sx_row = await _sx_header_sx(main_nav)
|
||||||
rows = "(<> " + root_hdr + " " + sx_row + ")"
|
rows = "(<> " + root_hdr + " " + sx_row + ")"
|
||||||
return oob_header_sx("root-header-child", "sx-header-child", rows)
|
return await oob_header_sx("root-header-child", "sx-header-child", rows)
|
||||||
|
|
||||||
|
|
||||||
def _sx_section_full_headers(ctx: dict, **kw: Any) -> str:
|
async def _sx_section_full_headers(ctx: dict, **kw: Any) -> str:
|
||||||
"""Full headers for sx section pages: root + sx row + sub row."""
|
"""Full headers for sx section pages: root + sx row + sub row."""
|
||||||
from shared.sx.helpers import root_header_sx
|
from shared.sx.helpers import root_header_sx
|
||||||
from sxc.sx_components import (
|
from sxc.sx_components import (
|
||||||
@@ -70,14 +70,14 @@ def _sx_section_full_headers(ctx: dict, **kw: Any) -> str:
|
|||||||
sub_nav = kw.get("sub_nav", "")
|
sub_nav = kw.get("sub_nav", "")
|
||||||
selected = kw.get("selected", "")
|
selected = kw.get("selected", "")
|
||||||
|
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
main_nav = _main_nav_sx(section)
|
main_nav = await _main_nav_sx(section)
|
||||||
sub_row = _sub_row_sx(sub_label, sub_href, sub_nav, selected)
|
sub_row = await _sub_row_sx(sub_label, sub_href, sub_nav, selected)
|
||||||
sx_row = _sx_header_sx(main_nav, child=sub_row)
|
sx_row = await _sx_header_sx(main_nav, child=sub_row)
|
||||||
return "(<> " + root_hdr + " " + sx_row + ")"
|
return "(<> " + root_hdr + " " + sx_row + ")"
|
||||||
|
|
||||||
|
|
||||||
def _sx_section_oob_headers(ctx: dict, **kw: Any) -> str:
|
async def _sx_section_oob_headers(ctx: dict, **kw: Any) -> str:
|
||||||
"""OOB headers for sx section pages."""
|
"""OOB headers for sx section pages."""
|
||||||
from shared.sx.helpers import root_header_sx, oob_header_sx
|
from shared.sx.helpers import root_header_sx, oob_header_sx
|
||||||
from sxc.sx_components import (
|
from sxc.sx_components import (
|
||||||
@@ -90,34 +90,34 @@ def _sx_section_oob_headers(ctx: dict, **kw: Any) -> str:
|
|||||||
sub_nav = kw.get("sub_nav", "")
|
sub_nav = kw.get("sub_nav", "")
|
||||||
selected = kw.get("selected", "")
|
selected = kw.get("selected", "")
|
||||||
|
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
main_nav = _main_nav_sx(section)
|
main_nav = await _main_nav_sx(section)
|
||||||
sub_row = _sub_row_sx(sub_label, sub_href, sub_nav, selected)
|
sub_row = await _sub_row_sx(sub_label, sub_href, sub_nav, selected)
|
||||||
sx_row = _sx_header_sx(main_nav, child=sub_row)
|
sx_row = await _sx_header_sx(main_nav, child=sub_row)
|
||||||
rows = "(<> " + root_hdr + " " + sx_row + ")"
|
rows = "(<> " + root_hdr + " " + sx_row + ")"
|
||||||
return oob_header_sx("root-header-child", "sx-header-child", rows)
|
return await oob_header_sx("root-header-child", "sx-header-child", rows)
|
||||||
|
|
||||||
|
|
||||||
def _sx_mobile(ctx: dict, **kw: Any) -> str:
|
async def _sx_mobile(ctx: dict, **kw: Any) -> str:
|
||||||
"""Mobile menu for sx home page: main nav + root."""
|
"""Mobile menu for sx home page: main nav + root."""
|
||||||
from shared.sx.helpers import (
|
from shared.sx.helpers import (
|
||||||
mobile_menu_sx, mobile_root_nav_sx, sx_call, SxExpr,
|
mobile_menu_sx, mobile_root_nav_sx, render_to_sx, SxExpr,
|
||||||
)
|
)
|
||||||
from sxc.sx_components import _main_nav_sx
|
from sxc.sx_components import _main_nav_sx
|
||||||
|
|
||||||
main_nav = _main_nav_sx(kw.get("section"))
|
main_nav = await _main_nav_sx(kw.get("section"))
|
||||||
return mobile_menu_sx(
|
return mobile_menu_sx(
|
||||||
sx_call("mobile-menu-section",
|
await render_to_sx("mobile-menu-section",
|
||||||
label="sx", href="/", level=1, colour="violet",
|
label="sx", href="/", level=1, colour="violet",
|
||||||
items=SxExpr(main_nav)),
|
items=SxExpr(main_nav)),
|
||||||
mobile_root_nav_sx(ctx),
|
await mobile_root_nav_sx(ctx),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _sx_section_mobile(ctx: dict, **kw: Any) -> str:
|
async def _sx_section_mobile(ctx: dict, **kw: Any) -> str:
|
||||||
"""Mobile menu for sx section pages: sub nav + main nav + root."""
|
"""Mobile menu for sx section pages: sub nav + main nav + root."""
|
||||||
from shared.sx.helpers import (
|
from shared.sx.helpers import (
|
||||||
mobile_menu_sx, mobile_root_nav_sx, sx_call, SxExpr,
|
mobile_menu_sx, mobile_root_nav_sx, render_to_sx, SxExpr,
|
||||||
)
|
)
|
||||||
from sxc.sx_components import _main_nav_sx
|
from sxc.sx_components import _main_nav_sx
|
||||||
|
|
||||||
@@ -125,17 +125,17 @@ def _sx_section_mobile(ctx: dict, **kw: Any) -> str:
|
|||||||
sub_label = kw.get("sub_label", section)
|
sub_label = kw.get("sub_label", section)
|
||||||
sub_href = kw.get("sub_href", "/")
|
sub_href = kw.get("sub_href", "/")
|
||||||
sub_nav = kw.get("sub_nav", "")
|
sub_nav = kw.get("sub_nav", "")
|
||||||
main_nav = _main_nav_sx(section)
|
main_nav = await _main_nav_sx(section)
|
||||||
|
|
||||||
parts = []
|
parts = []
|
||||||
if sub_nav:
|
if sub_nav:
|
||||||
parts.append(sx_call("mobile-menu-section",
|
parts.append(await render_to_sx("mobile-menu-section",
|
||||||
label=sub_label, href=sub_href, level=2, colour="violet",
|
label=sub_label, href=sub_href, level=2, colour="violet",
|
||||||
items=SxExpr(sub_nav)))
|
items=SxExpr(sub_nav)))
|
||||||
parts.append(sx_call("mobile-menu-section",
|
parts.append(await render_to_sx("mobile-menu-section",
|
||||||
label="sx", href="/", level=1, colour="violet",
|
label="sx", href="/", level=1, colour="violet",
|
||||||
items=SxExpr(main_nav)))
|
items=SxExpr(main_nav)))
|
||||||
parts.append(mobile_root_nav_sx(ctx))
|
parts.append(await mobile_root_nav_sx(ctx))
|
||||||
return mobile_menu_sx(*parts)
|
return mobile_menu_sx(*parts)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import os
|
|||||||
|
|
||||||
from shared.sx.jinja_bridge import load_sx_dir, watch_sx_dir
|
from shared.sx.jinja_bridge import load_sx_dir, watch_sx_dir
|
||||||
from shared.sx.helpers import (
|
from shared.sx.helpers import (
|
||||||
sx_call, SxExpr, get_asset_url,
|
render_to_sx, SxExpr, get_asset_url,
|
||||||
)
|
)
|
||||||
from content.highlight import highlight
|
from content.highlight import highlight
|
||||||
|
|
||||||
@@ -108,11 +108,11 @@ def _full_wire_text(sx_src: str, *comp_names: str) -> str:
|
|||||||
# Navigation helpers
|
# Navigation helpers
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _nav_items_sx(items: list[tuple[str, str]], current: str | None = None) -> str:
|
async def _nav_items_sx(items: list[tuple[str, str]], current: str | None = None) -> str:
|
||||||
"""Build nav link items as sx."""
|
"""Build nav link items as sx."""
|
||||||
parts = []
|
parts = []
|
||||||
for label, href in items:
|
for label, href in items:
|
||||||
parts.append(sx_call("nav-link",
|
parts.append(await render_to_sx("nav-link",
|
||||||
href=href, label=label,
|
href=href, label=label,
|
||||||
is_selected="true" if current == label else None,
|
is_selected="true" if current == label else None,
|
||||||
select_colours="aria-selected:bg-violet-200 aria-selected:text-violet-900",
|
select_colours="aria-selected:bg-violet-200 aria-selected:text-violet-900",
|
||||||
@@ -120,9 +120,9 @@ def _nav_items_sx(items: list[tuple[str, str]], current: str | None = None) -> s
|
|||||||
return "(<> " + " ".join(parts) + ")"
|
return "(<> " + " ".join(parts) + ")"
|
||||||
|
|
||||||
|
|
||||||
def _sx_header_sx(nav: str | None = None, *, child: str | None = None) -> str:
|
async def _sx_header_sx(nav: str | None = None, *, child: str | None = None) -> str:
|
||||||
"""Build the sx docs menu-row."""
|
"""Build the sx docs menu-row."""
|
||||||
return sx_call("menu-row-sx",
|
return await render_to_sx("menu-row-sx",
|
||||||
id="sx-row", level=1, colour="violet",
|
id="sx-row", level=1, colour="violet",
|
||||||
link_href="/", link_label="sx",
|
link_href="/", link_label="sx",
|
||||||
link_label_content=SxExpr('(span :class "font-mono" "(</>) sx")'),
|
link_label_content=SxExpr('(span :class "font-mono" "(</>) sx")'),
|
||||||
@@ -132,40 +132,40 @@ def _sx_header_sx(nav: str | None = None, *, child: str | None = None) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _docs_nav_sx(current: str | None = None) -> str:
|
async def _docs_nav_sx(current: str | None = None) -> str:
|
||||||
from content.pages import DOCS_NAV
|
from content.pages import DOCS_NAV
|
||||||
return _nav_items_sx(DOCS_NAV, current)
|
return await _nav_items_sx(DOCS_NAV, current)
|
||||||
|
|
||||||
|
|
||||||
def _reference_nav_sx(current: str | None = None) -> str:
|
async def _reference_nav_sx(current: str | None = None) -> str:
|
||||||
from content.pages import REFERENCE_NAV
|
from content.pages import REFERENCE_NAV
|
||||||
return _nav_items_sx(REFERENCE_NAV, current)
|
return await _nav_items_sx(REFERENCE_NAV, current)
|
||||||
|
|
||||||
|
|
||||||
def _protocols_nav_sx(current: str | None = None) -> str:
|
async def _protocols_nav_sx(current: str | None = None) -> str:
|
||||||
from content.pages import PROTOCOLS_NAV
|
from content.pages import PROTOCOLS_NAV
|
||||||
return _nav_items_sx(PROTOCOLS_NAV, current)
|
return await _nav_items_sx(PROTOCOLS_NAV, current)
|
||||||
|
|
||||||
|
|
||||||
def _examples_nav_sx(current: str | None = None) -> str:
|
async def _examples_nav_sx(current: str | None = None) -> str:
|
||||||
from content.pages import EXAMPLES_NAV
|
from content.pages import EXAMPLES_NAV
|
||||||
return _nav_items_sx(EXAMPLES_NAV, current)
|
return await _nav_items_sx(EXAMPLES_NAV, current)
|
||||||
|
|
||||||
|
|
||||||
def _essays_nav_sx(current: str | None = None) -> str:
|
async def _essays_nav_sx(current: str | None = None) -> str:
|
||||||
from content.pages import ESSAYS_NAV
|
from content.pages import ESSAYS_NAV
|
||||||
return _nav_items_sx(ESSAYS_NAV, current)
|
return await _nav_items_sx(ESSAYS_NAV, current)
|
||||||
|
|
||||||
|
|
||||||
def _main_nav_sx(current_section: str | None = None) -> str:
|
async def _main_nav_sx(current_section: str | None = None) -> str:
|
||||||
from content.pages import MAIN_NAV
|
from content.pages import MAIN_NAV
|
||||||
return _nav_items_sx(MAIN_NAV, current_section)
|
return await _nav_items_sx(MAIN_NAV, current_section)
|
||||||
|
|
||||||
|
|
||||||
def _sub_row_sx(sub_label: str, sub_href: str, sub_nav: str,
|
async def _sub_row_sx(sub_label: str, sub_href: str, sub_nav: str,
|
||||||
selected: str = "") -> str:
|
selected: str = "") -> str:
|
||||||
"""Build the level-2 sub-section menu-row."""
|
"""Build the level-2 sub-section menu-row."""
|
||||||
return sx_call("menu-row-sx",
|
return await render_to_sx("menu-row-sx",
|
||||||
id="sx-sub-row", level=2, colour="violet",
|
id="sx-sub-row", level=2, colour="violet",
|
||||||
link_href=sub_href, link_label=sub_label,
|
link_href=sub_href, link_label=sub_label,
|
||||||
selected=selected or None,
|
selected=selected or None,
|
||||||
@@ -178,22 +178,22 @@ def _sub_row_sx(sub_label: str, sub_href: str, sub_nav: str,
|
|||||||
# Content builders — return sx source strings
|
# Content builders — return sx source strings
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _doc_nav_sx(items: list[tuple[str, str]], current: str) -> str:
|
async def _doc_nav_sx(items: list[tuple[str, str]], current: str) -> str:
|
||||||
"""Build the in-page doc navigation pills."""
|
"""Build the in-page doc navigation pills."""
|
||||||
items_sx = " ".join(
|
items_sx = " ".join(
|
||||||
f'(list "{label}" "{href}")'
|
f'(list "{label}" "{href}")'
|
||||||
for label, href in items
|
for label, href in items
|
||||||
)
|
)
|
||||||
return sx_call("doc-nav", items=SxExpr(f"(list {items_sx})"), current=current)
|
return await render_to_sx("doc-nav", items=SxExpr(f"(list {items_sx})"), current=current)
|
||||||
|
|
||||||
|
|
||||||
def _attr_table_sx(title: str, attrs: list[tuple[str, str, bool]]) -> str:
|
async def _attr_table_sx(title: str, attrs: list[tuple[str, str, bool]]) -> str:
|
||||||
"""Build an attribute reference table."""
|
"""Build an attribute reference table."""
|
||||||
from content.pages import ATTR_DETAILS
|
from content.pages import ATTR_DETAILS
|
||||||
rows = []
|
rows = []
|
||||||
for attr, desc, exists in attrs:
|
for attr, desc, exists in attrs:
|
||||||
href = f"/reference/attributes/{attr}" if exists and attr in ATTR_DETAILS else None
|
href = f"/reference/attributes/{attr}" if exists and attr in ATTR_DETAILS else None
|
||||||
rows.append(sx_call("doc-attr-row", attr=attr, description=desc,
|
rows.append(await render_to_sx("doc-attr-row", attr=attr, description=desc,
|
||||||
exists="true" if exists else None,
|
exists="true" if exists else None,
|
||||||
href=href))
|
href=href))
|
||||||
return (
|
return (
|
||||||
@@ -209,13 +209,13 @@ def _attr_table_sx(title: str, attrs: list[tuple[str, str, bool]]) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _primitives_section_sx() -> str:
|
async def _primitives_section_sx() -> str:
|
||||||
"""Build the primitives section."""
|
"""Build the primitives section."""
|
||||||
from content.pages import PRIMITIVES
|
from content.pages import PRIMITIVES
|
||||||
parts = []
|
parts = []
|
||||||
for category, prims in PRIMITIVES.items():
|
for category, prims in PRIMITIVES.items():
|
||||||
prims_sx = " ".join(f'"{p}"' for p in prims)
|
prims_sx = " ".join(f'"{p}"' for p in prims)
|
||||||
parts.append(sx_call("doc-primitives-table",
|
parts.append(await render_to_sx("doc-primitives-table",
|
||||||
category=category,
|
category=category,
|
||||||
primitives=SxExpr(f"(list {prims_sx})")))
|
primitives=SxExpr(f"(list {prims_sx})")))
|
||||||
return " ".join(parts)
|
return " ".join(parts)
|
||||||
@@ -245,8 +245,9 @@ def _headers_table_sx(title: str, headers: list[tuple[str, str, str]]) -> str:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _docs_content_sx(slug: str) -> str:
|
async def _docs_content_sx(slug: str) -> str:
|
||||||
"""Route to the right docs content builder."""
|
"""Route to the right docs content builder."""
|
||||||
|
import inspect
|
||||||
builders = {
|
builders = {
|
||||||
"introduction": _docs_introduction_sx,
|
"introduction": _docs_introduction_sx,
|
||||||
"getting-started": _docs_getting_started_sx,
|
"getting-started": _docs_getting_started_sx,
|
||||||
@@ -257,7 +258,8 @@ def _docs_content_sx(slug: str) -> str:
|
|||||||
"server-rendering": _docs_server_rendering_sx,
|
"server-rendering": _docs_server_rendering_sx,
|
||||||
}
|
}
|
||||||
builder = builders.get(slug, _docs_introduction_sx)
|
builder = builders.get(slug, _docs_introduction_sx)
|
||||||
return builder()
|
result = builder()
|
||||||
|
return await result if inspect.isawaitable(result) else result
|
||||||
|
|
||||||
|
|
||||||
def _docs_introduction_sx() -> str:
|
def _docs_introduction_sx() -> str:
|
||||||
@@ -379,8 +381,8 @@ def _docs_evaluator_sx() -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _docs_primitives_sx() -> str:
|
async def _docs_primitives_sx() -> str:
|
||||||
prims = _primitives_section_sx()
|
prims = await _primitives_section_sx()
|
||||||
return (
|
return (
|
||||||
f'(~doc-page :title "Primitives"'
|
f'(~doc-page :title "Primitives"'
|
||||||
f' (~doc-section :title "Built-in functions" :id "builtins"'
|
f' (~doc-section :title "Built-in functions" :id "builtins"'
|
||||||
@@ -471,14 +473,16 @@ def _docs_server_rendering_sx() -> str:
|
|||||||
# Reference pages
|
# Reference pages
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _reference_content_sx(slug: str) -> str:
|
async def _reference_content_sx(slug: str) -> str:
|
||||||
|
import inspect
|
||||||
builders = {
|
builders = {
|
||||||
"attributes": _reference_attrs_sx,
|
"attributes": _reference_attrs_sx,
|
||||||
"headers": _reference_headers_sx,
|
"headers": _reference_headers_sx,
|
||||||
"events": _reference_events_sx,
|
"events": _reference_events_sx,
|
||||||
"js-api": _reference_js_api_sx,
|
"js-api": _reference_js_api_sx,
|
||||||
}
|
}
|
||||||
return builders.get(slug or "", _reference_attrs_sx)()
|
result = builders.get(slug or "", _reference_attrs_sx)()
|
||||||
|
return await result if inspect.isawaitable(result) else result
|
||||||
|
|
||||||
|
|
||||||
def _reference_index_sx() -> str:
|
def _reference_index_sx() -> str:
|
||||||
@@ -573,18 +577,22 @@ def _reference_attr_detail_sx(slug: str) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _reference_attrs_sx() -> str:
|
async def _reference_attrs_sx() -> str:
|
||||||
from content.pages import REQUEST_ATTRS, BEHAVIOR_ATTRS, SX_UNIQUE_ATTRS, HTMX_MISSING_ATTRS
|
from content.pages import REQUEST_ATTRS, BEHAVIOR_ATTRS, SX_UNIQUE_ATTRS, HTMX_MISSING_ATTRS
|
||||||
|
req = await _attr_table_sx("Request Attributes", REQUEST_ATTRS)
|
||||||
|
beh = await _attr_table_sx("Behavior Attributes", BEHAVIOR_ATTRS)
|
||||||
|
uniq = await _attr_table_sx("Unique to sx", SX_UNIQUE_ATTRS)
|
||||||
|
missing = await _attr_table_sx("htmx features not yet in sx", HTMX_MISSING_ATTRS)
|
||||||
return (
|
return (
|
||||||
f'(~doc-page :title "Attribute Reference"'
|
f'(~doc-page :title "Attribute Reference"'
|
||||||
f' (p :class "text-stone-600 mb-6"'
|
f' (p :class "text-stone-600 mb-6"'
|
||||||
f' "sx attributes mirror htmx where possible. This table shows what exists, '
|
f' "sx attributes mirror htmx where possible. This table shows what exists, '
|
||||||
f'what\'s unique to sx, and what\'s not yet implemented.")'
|
f'what\'s unique to sx, and what\'s not yet implemented.")'
|
||||||
f' (div :class "space-y-8"'
|
f' (div :class "space-y-8"'
|
||||||
f' {_attr_table_sx("Request Attributes", REQUEST_ATTRS)}'
|
f' {req}'
|
||||||
f' {_attr_table_sx("Behavior Attributes", BEHAVIOR_ATTRS)}'
|
f' {beh}'
|
||||||
f' {_attr_table_sx("Unique to sx", SX_UNIQUE_ATTRS)}'
|
f' {uniq}'
|
||||||
f' {_attr_table_sx("htmx features not yet in sx", HTMX_MISSING_ATTRS)}))'
|
f' {missing}))'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -2066,9 +2074,9 @@ def home_content_sx() -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def docs_content_partial_sx(slug: str) -> str:
|
async def docs_content_partial_sx(slug: str) -> str:
|
||||||
"""Docs content as sx wire format."""
|
"""Docs content as sx wire format."""
|
||||||
inner = _docs_content_sx(slug)
|
inner = await _docs_content_sx(slug)
|
||||||
return (
|
return (
|
||||||
f'(section :id "main-panel"'
|
f'(section :id "main-panel"'
|
||||||
f' :class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"'
|
f' :class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"'
|
||||||
@@ -2076,8 +2084,8 @@ def docs_content_partial_sx(slug: str) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def reference_content_partial_sx(slug: str) -> str:
|
async def reference_content_partial_sx(slug: str) -> str:
|
||||||
inner = _reference_content_sx(slug)
|
inner = await _reference_content_sx(slug)
|
||||||
return (
|
return (
|
||||||
f'(section :id "main-panel"'
|
f'(section :id "main-panel"'
|
||||||
f' :class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"'
|
f' :class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"'
|
||||||
@@ -2085,8 +2093,8 @@ def reference_content_partial_sx(slug: str) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def protocol_content_partial_sx(slug: str) -> str:
|
async def protocol_content_partial_sx(slug: str) -> str:
|
||||||
inner = _protocol_content_sx(slug)
|
inner = await _protocol_content_sx(slug)
|
||||||
return (
|
return (
|
||||||
f'(section :id "main-panel"'
|
f'(section :id "main-panel"'
|
||||||
f' :class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"'
|
f' :class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"'
|
||||||
@@ -2094,8 +2102,8 @@ def protocol_content_partial_sx(slug: str) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def examples_content_partial_sx(slug: str) -> str:
|
async def examples_content_partial_sx(slug: str) -> str:
|
||||||
inner = _examples_content_sx(slug)
|
inner = await _examples_content_sx(slug)
|
||||||
return (
|
return (
|
||||||
f'(section :id "main-panel"'
|
f'(section :id "main-panel"'
|
||||||
f' :class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"'
|
f' :class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"'
|
||||||
@@ -2103,8 +2111,8 @@ def examples_content_partial_sx(slug: str) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def essay_content_partial_sx(slug: str) -> str:
|
async def essay_content_partial_sx(slug: str) -> str:
|
||||||
inner = _essay_content_sx(slug)
|
inner = await _essay_content_sx(slug)
|
||||||
return (
|
return (
|
||||||
f'(section :id "main-panel"'
|
f'(section :id "main-panel"'
|
||||||
f' :class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"'
|
f' :class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"'
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ def register(url_prefix: str = "/") -> Blueprint:
|
|||||||
# S-expression wire format — sx.js renders client-side
|
# S-expression wire format — sx.js renders client-side
|
||||||
from shared.sx.helpers import sx_response
|
from shared.sx.helpers import sx_response
|
||||||
from sx.sx_components import test_detail_sx
|
from sx.sx_components import test_detail_sx
|
||||||
return sx_response(test_detail_sx(test))
|
return sx_response(await test_detail_sx(test))
|
||||||
|
|
||||||
# Full page render (direct navigation / refresh)
|
# Full page render (direct navigation / refresh)
|
||||||
from shared.sx.page import get_template_context
|
from shared.sx.page import get_template_context
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from datetime import datetime
|
|||||||
|
|
||||||
from shared.sx.jinja_bridge import load_service_components
|
from shared.sx.jinja_bridge import load_service_components
|
||||||
from shared.sx.helpers import (
|
from shared.sx.helpers import (
|
||||||
sx_call, SxExpr,
|
render_to_sx, SxExpr,
|
||||||
root_header_sx, full_page_sx, header_child_sx,
|
root_header_sx, full_page_sx, header_child_sx,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -50,9 +50,9 @@ def _filter_tests(tests: list[dict], active_filter: str | None,
|
|||||||
# Results partial
|
# Results partial
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def test_detail_sx(test: dict) -> str:
|
async def test_detail_sx(test: dict) -> str:
|
||||||
"""Return s-expression wire format for a test detail view."""
|
"""Return s-expression wire format for a test detail view."""
|
||||||
inner = sx_call(
|
inner = await render_to_sx(
|
||||||
"test-detail",
|
"test-detail",
|
||||||
nodeid=test["nodeid"],
|
nodeid=test["nodeid"],
|
||||||
outcome=test["outcome"],
|
outcome=test["outcome"],
|
||||||
@@ -70,10 +70,10 @@ def test_detail_sx(test: dict) -> str:
|
|||||||
# Sx-native versions — return sx source (not HTML)
|
# Sx-native versions — return sx source (not HTML)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
def _test_header_sx(ctx: dict, active_service: str | None = None) -> str:
|
async def _test_header_sx(ctx: dict, active_service: str | None = None) -> str:
|
||||||
"""Build the Tests menu-row as sx call."""
|
"""Build the Tests menu-row as sx call."""
|
||||||
nav = _service_nav_sx(ctx, active_service)
|
nav = await _service_nav_sx(ctx, active_service)
|
||||||
return sx_call("menu-row-sx",
|
return await render_to_sx("menu-row-sx",
|
||||||
id="test-row", level=1, colour="sky",
|
id="test-row", level=1, colour="sky",
|
||||||
link_href="/", link_label="Tests", icon="fa fa-flask",
|
link_href="/", link_label="Tests", icon="fa fa-flask",
|
||||||
nav=SxExpr(nav),
|
nav=SxExpr(nav),
|
||||||
@@ -81,17 +81,17 @@ def _test_header_sx(ctx: dict, active_service: str | None = None) -> str:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _service_nav_sx(ctx: dict, active_service: str | None = None) -> str:
|
async def _service_nav_sx(ctx: dict, active_service: str | None = None) -> str:
|
||||||
"""Service filter nav as sx."""
|
"""Service filter nav as sx."""
|
||||||
from runner import _SERVICE_ORDER
|
from runner import _SERVICE_ORDER
|
||||||
parts = []
|
parts = []
|
||||||
parts.append(sx_call("nav-link",
|
parts.append(await render_to_sx("nav-link",
|
||||||
href="/", label="all",
|
href="/", label="all",
|
||||||
is_selected="true" if not active_service else None,
|
is_selected="true" if not active_service else None,
|
||||||
select_colours="aria-selected:bg-sky-200 aria-selected:text-sky-900",
|
select_colours="aria-selected:bg-sky-200 aria-selected:text-sky-900",
|
||||||
))
|
))
|
||||||
for svc in _SERVICE_ORDER:
|
for svc in _SERVICE_ORDER:
|
||||||
parts.append(sx_call("nav-link",
|
parts.append(await render_to_sx("nav-link",
|
||||||
href=f"/?service={svc}", label=svc,
|
href=f"/?service={svc}", label=svc,
|
||||||
is_selected="true" if active_service == svc else None,
|
is_selected="true" if active_service == svc else None,
|
||||||
select_colours="aria-selected:bg-sky-200 aria-selected:text-sky-900",
|
select_colours="aria-selected:bg-sky-200 aria-selected:text-sky-900",
|
||||||
@@ -99,19 +99,19 @@ def _service_nav_sx(ctx: dict, active_service: str | None = None) -> str:
|
|||||||
return "(<> " + " ".join(parts) + ")"
|
return "(<> " + " ".join(parts) + ")"
|
||||||
|
|
||||||
|
|
||||||
def _header_stack_sx(ctx: dict, active_service: str | None = None) -> str:
|
async def _header_stack_sx(ctx: dict, active_service: str | None = None) -> str:
|
||||||
"""Full header stack as sx."""
|
"""Full header stack as sx."""
|
||||||
hdr = root_header_sx(ctx)
|
hdr = await root_header_sx(ctx)
|
||||||
inner = _test_header_sx(ctx, active_service)
|
inner = await _test_header_sx(ctx, active_service)
|
||||||
child = header_child_sx(inner)
|
child = await header_child_sx(inner)
|
||||||
return "(<> " + hdr + " " + child + ")"
|
return "(<> " + hdr + " " + child + ")"
|
||||||
|
|
||||||
|
|
||||||
def _test_rows_sx(tests: list[dict]) -> str:
|
async def _test_rows_sx(tests: list[dict]) -> str:
|
||||||
"""Render all test result rows as sx."""
|
"""Render all test result rows as sx."""
|
||||||
parts = []
|
parts = []
|
||||||
for t in tests:
|
for t in tests:
|
||||||
parts.append(sx_call("test-row",
|
parts.append(await render_to_sx("test-row",
|
||||||
nodeid=t["nodeid"],
|
nodeid=t["nodeid"],
|
||||||
outcome=t["outcome"],
|
outcome=t["outcome"],
|
||||||
duration=str(t["duration"]),
|
duration=str(t["duration"]),
|
||||||
@@ -120,46 +120,46 @@ def _test_rows_sx(tests: list[dict]) -> str:
|
|||||||
return "(<> " + " ".join(parts) + ")"
|
return "(<> " + " ".join(parts) + ")"
|
||||||
|
|
||||||
|
|
||||||
def _grouped_rows_sx(tests: list[dict]) -> str:
|
async def _grouped_rows_sx(tests: list[dict]) -> str:
|
||||||
"""Test rows grouped by service as sx."""
|
"""Test rows grouped by service as sx."""
|
||||||
from runner import group_tests_by_service
|
from runner import group_tests_by_service
|
||||||
sections = group_tests_by_service(tests)
|
sections = group_tests_by_service(tests)
|
||||||
parts = []
|
parts = []
|
||||||
for sec in sections:
|
for sec in sections:
|
||||||
parts.append(sx_call("test-service-header",
|
parts.append(await render_to_sx("test-service-header",
|
||||||
service=sec["service"],
|
service=sec["service"],
|
||||||
total=str(sec["total"]),
|
total=str(sec["total"]),
|
||||||
passed=str(sec["passed"]),
|
passed=str(sec["passed"]),
|
||||||
failed=str(sec["failed"]),
|
failed=str(sec["failed"]),
|
||||||
))
|
))
|
||||||
parts.append(_test_rows_sx(sec["tests"]))
|
parts.append(await _test_rows_sx(sec["tests"]))
|
||||||
return "(<> " + " ".join(parts) + ")"
|
return "(<> " + " ".join(parts) + ")"
|
||||||
|
|
||||||
|
|
||||||
def _results_partial_sx(result: dict | None, running: bool, csrf: str,
|
async def _results_partial_sx(result: dict | None, running: bool, csrf: str,
|
||||||
active_filter: str | None = None,
|
active_filter: str | None = None,
|
||||||
active_service: str | None = None) -> str:
|
active_service: str | None = None) -> str:
|
||||||
"""Results section as sx."""
|
"""Results section as sx."""
|
||||||
if running and not result:
|
if running and not result:
|
||||||
summary = sx_call("test-summary",
|
summary = await render_to_sx("test-summary",
|
||||||
status="running", passed="0", failed="0", errors="0",
|
status="running", passed="0", failed="0", errors="0",
|
||||||
skipped="0", total="0", duration="...",
|
skipped="0", total="0", duration="...",
|
||||||
last_run="in progress", running=True, csrf=csrf,
|
last_run="in progress", running=True, csrf=csrf,
|
||||||
active_filter=active_filter,
|
active_filter=active_filter,
|
||||||
)
|
)
|
||||||
return "(<> " + summary + " " + sx_call("test-running-indicator") + ")"
|
return "(<> " + summary + " " + await render_to_sx("test-running-indicator") + ")"
|
||||||
|
|
||||||
if not result:
|
if not result:
|
||||||
summary = sx_call("test-summary",
|
summary = await render_to_sx("test-summary",
|
||||||
status=None, passed="0", failed="0", errors="0",
|
status=None, passed="0", failed="0", errors="0",
|
||||||
skipped="0", total="0", duration="0",
|
skipped="0", total="0", duration="0",
|
||||||
last_run="never", running=running, csrf=csrf,
|
last_run="never", running=running, csrf=csrf,
|
||||||
active_filter=active_filter,
|
active_filter=active_filter,
|
||||||
)
|
)
|
||||||
return "(<> " + summary + " " + sx_call("test-no-results") + ")"
|
return "(<> " + summary + " " + await render_to_sx("test-no-results") + ")"
|
||||||
|
|
||||||
status = "running" if running else result["status"]
|
status = "running" if running else result["status"]
|
||||||
summary = sx_call("test-summary",
|
summary = await render_to_sx("test-summary",
|
||||||
status=status,
|
status=status,
|
||||||
passed=str(result["passed"]),
|
passed=str(result["passed"]),
|
||||||
failed=str(result["failed"]),
|
failed=str(result["failed"]),
|
||||||
@@ -174,16 +174,16 @@ def _results_partial_sx(result: dict | None, running: bool, csrf: str,
|
|||||||
)
|
)
|
||||||
|
|
||||||
if running:
|
if running:
|
||||||
return "(<> " + summary + " " + sx_call("test-running-indicator") + ")"
|
return "(<> " + summary + " " + await render_to_sx("test-running-indicator") + ")"
|
||||||
|
|
||||||
tests = result.get("tests", [])
|
tests = result.get("tests", [])
|
||||||
tests = _filter_tests(tests, active_filter, active_service)
|
tests = _filter_tests(tests, active_filter, active_service)
|
||||||
if not tests:
|
if not tests:
|
||||||
return "(<> " + summary + " " + sx_call("test-no-results") + ")"
|
return "(<> " + summary + " " + await render_to_sx("test-no-results") + ")"
|
||||||
|
|
||||||
has_failures = result["failed"] > 0 or result["errors"] > 0
|
has_failures = result["failed"] > 0 or result["errors"] > 0
|
||||||
rows = _grouped_rows_sx(tests)
|
rows = await _grouped_rows_sx(tests)
|
||||||
table = sx_call("test-results-table",
|
table = await render_to_sx("test-results-table",
|
||||||
rows=SxExpr(rows),
|
rows=SxExpr(rows),
|
||||||
has_failures=str(has_failures).lower(),
|
has_failures=str(has_failures).lower(),
|
||||||
)
|
)
|
||||||
@@ -203,10 +203,10 @@ async def render_dashboard_page_sx(ctx: dict, result: dict | None,
|
|||||||
active_filter: str | None = None,
|
active_filter: str | None = None,
|
||||||
active_service: str | None = None) -> str:
|
active_service: str | None = None) -> str:
|
||||||
"""Full page: test dashboard (sx wire format)."""
|
"""Full page: test dashboard (sx wire format)."""
|
||||||
hdr = _header_stack_sx(ctx, active_service)
|
hdr = await _header_stack_sx(ctx, active_service)
|
||||||
inner = _results_partial_sx(result, running, csrf, active_filter, active_service)
|
inner = await _results_partial_sx(result, running, csrf, active_filter, active_service)
|
||||||
content = _wrap_results_div_sx(inner, running)
|
content = _wrap_results_div_sx(inner, running)
|
||||||
return full_page_sx(ctx, header_rows=hdr, content=content)
|
return await full_page_sx(ctx, header_rows=hdr, content=content)
|
||||||
|
|
||||||
|
|
||||||
async def render_results_partial_sx(result: dict | None, running: bool,
|
async def render_results_partial_sx(result: dict | None, running: bool,
|
||||||
@@ -214,25 +214,27 @@ async def render_results_partial_sx(result: dict | None, running: bool,
|
|||||||
active_filter: str | None = None,
|
active_filter: str | None = None,
|
||||||
active_service: str | None = None) -> str:
|
active_service: str | None = None) -> str:
|
||||||
"""HTMX partial: results section (sx wire format)."""
|
"""HTMX partial: results section (sx wire format)."""
|
||||||
inner = _results_partial_sx(result, running, csrf, active_filter, active_service)
|
inner = await _results_partial_sx(result, running, csrf, active_filter, active_service)
|
||||||
return _wrap_results_div_sx(inner, running)
|
return _wrap_results_div_sx(inner, running)
|
||||||
|
|
||||||
|
|
||||||
async def render_test_detail_page_sx(ctx: dict, test: dict) -> str:
|
async def render_test_detail_page_sx(ctx: dict, test: dict) -> str:
|
||||||
"""Full page: test detail (sx wire format)."""
|
"""Full page: test detail (sx wire format)."""
|
||||||
root_hdr = root_header_sx(ctx)
|
root_hdr = await root_header_sx(ctx)
|
||||||
test_row = _test_header_sx(ctx)
|
test_row = await _test_header_sx(ctx)
|
||||||
detail_row = sx_call("menu-row-sx",
|
detail_row = await render_to_sx("menu-row-sx",
|
||||||
id="test-detail-row", level=2, colour="sky",
|
id="test-detail-row", level=2, colour="sky",
|
||||||
link_href=f"/test/{test['nodeid']}",
|
link_href=f"/test/{test['nodeid']}",
|
||||||
link_label=test["nodeid"].rsplit("::", 1)[-1],
|
link_label=test["nodeid"].rsplit("::", 1)[-1],
|
||||||
)
|
)
|
||||||
inner = "(<> " + test_row + " " + header_child_sx(detail_row, id="test-header-child") + ")"
|
hdr_child_detail = await header_child_sx(detail_row, id="test-header-child")
|
||||||
hdr = "(<> " + root_hdr + " " + header_child_sx(inner) + ")"
|
inner = "(<> " + test_row + " " + hdr_child_detail + ")"
|
||||||
content = sx_call("test-detail",
|
hdr_child_inner = await header_child_sx(inner)
|
||||||
|
hdr = "(<> " + root_hdr + " " + hdr_child_inner + ")"
|
||||||
|
content = await render_to_sx("test-detail",
|
||||||
nodeid=test["nodeid"],
|
nodeid=test["nodeid"],
|
||||||
outcome=test["outcome"],
|
outcome=test["outcome"],
|
||||||
duration=str(test["duration"]),
|
duration=str(test["duration"]),
|
||||||
longrepr=test.get("longrepr", ""),
|
longrepr=test.get("longrepr", ""),
|
||||||
)
|
)
|
||||||
return full_page_sx(ctx, header_rows=hdr, content=content)
|
return await full_page_sx(ctx, header_rows=hdr, content=content)
|
||||||
|
|||||||
Reference in New Issue
Block a user