Remove render_to_sx from public API: enforce sx_call for all service code
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m44s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m44s
Replace ~250 render_to_sx calls across all services with sync sx_call, converting many async functions to sync where no other awaits remained. Make render_to_sx/render_to_sx_with_env private (_render_to_sx). Add (post-header-ctx) IO primitive and shared post/post-admin defmacros. Convert built-in post/post-admin layouts from Python to register_sx_layout with .sx defcomps. Remove dead post_admin_mobile_nav_sx. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,7 @@ from .services.pages_data import pages_data
|
||||
from shared.browser.app.redis_cacher import cache_page, invalidate_tag_cache
|
||||
from shared.browser.app.utils.htmx import is_htmx_request
|
||||
from shared.browser.app.authz import require_admin
|
||||
from shared.sx.helpers import sx_response, render_to_sx
|
||||
from shared.sx.helpers import sx_response, sx_call
|
||||
from shared.utils import host_url
|
||||
|
||||
def register(url_prefix, title):
|
||||
@@ -67,7 +67,7 @@ def register(url_prefix, title):
|
||||
from shared.sx.helpers import root_header_sx, full_page_sx
|
||||
from shared.sx.parser import SxExpr
|
||||
root_hdr = await root_header_sx(tctx)
|
||||
blog_hdr = await render_to_sx("menu-row-sx",
|
||||
blog_hdr = sx_call("menu-row-sx",
|
||||
id="blog-row", level=1,
|
||||
link_label_content=SxExpr("(div)"),
|
||||
child_id="blog-header-child")
|
||||
@@ -132,7 +132,7 @@ def register(url_prefix, title):
|
||||
|
||||
from shared.sx.page import get_template_context
|
||||
from shared.sx.helpers import (
|
||||
render_to_sx, root_header_sx, full_page_sx, oob_page_sx,
|
||||
sx_call, root_header_sx, full_page_sx, oob_page_sx,
|
||||
post_header_sx, oob_header_sx, mobile_menu_sx,
|
||||
post_mobile_nav_sx, mobile_root_nav_sx,
|
||||
)
|
||||
@@ -143,11 +143,11 @@ def register(url_prefix, title):
|
||||
tctx.update(ctx)
|
||||
|
||||
post = ctx.get("post", {})
|
||||
content = await render_to_sx("blog-home-main",
|
||||
content = sx_call("blog-home-main",
|
||||
html_content=post.get("html", ""),
|
||||
sx_content=SxExpr(post.get("sx_content", "")) if post.get("sx_content") else None)
|
||||
meta_data = services.blog_page.post_meta_data(post, ctx.get("base_title", ""))
|
||||
meta = await render_to_sx("blog-meta", **meta_data)
|
||||
meta = sx_call("blog-meta", **meta_data)
|
||||
|
||||
if not is_htmx_request():
|
||||
root_hdr = await root_header_sx(tctx)
|
||||
@@ -171,12 +171,12 @@ def register(url_prefix, title):
|
||||
"""Blog listing — moved from / to /index."""
|
||||
from shared.services.registry import services
|
||||
from shared.sx.helpers import (
|
||||
render_to_sx, root_header_sx, full_page_sx, oob_page_sx, oob_header_sx,
|
||||
sx_call, root_header_sx, full_page_sx, oob_page_sx, oob_header_sx,
|
||||
)
|
||||
from shared.sx.parser import SxExpr
|
||||
|
||||
async def _blog_hdr(ctx, oob=False):
|
||||
return await render_to_sx("menu-row-sx",
|
||||
def _blog_hdr(ctx, oob=False):
|
||||
return sx_call("menu-row-sx",
|
||||
id="blog-row", level=1,
|
||||
link_label_content=SxExpr("(div)"),
|
||||
child_id="blog-header-child", oob=oob)
|
||||
@@ -184,16 +184,16 @@ def register(url_prefix, title):
|
||||
data = await services.blog_page.index_data(g.s)
|
||||
|
||||
# Render content, aside, and filter via .sx defcomps
|
||||
content = await render_to_sx("blog-index-main-content", **data)
|
||||
aside = await render_to_sx("blog-index-aside-content", **data)
|
||||
filter_sx = await render_to_sx("blog-index-filter-content", **data)
|
||||
content = sx_call("blog-index-main-content", **data)
|
||||
aside = sx_call("blog-index-aside-content", **data)
|
||||
filter_sx = sx_call("blog-index-filter-content", **data)
|
||||
|
||||
from shared.sx.page import get_template_context
|
||||
tctx = await get_template_context()
|
||||
|
||||
if not is_htmx_request():
|
||||
root_hdr = await root_header_sx(tctx)
|
||||
blog_hdr = await _blog_hdr(tctx)
|
||||
blog_hdr = _blog_hdr(tctx)
|
||||
header_rows = "(<> " + root_hdr + " " + blog_hdr + ")"
|
||||
html = await full_page_sx(tctx, header_rows=header_rows,
|
||||
content=content, aside=aside, filter=filter_sx)
|
||||
@@ -203,7 +203,7 @@ def register(url_prefix, title):
|
||||
return sx_response(content)
|
||||
else:
|
||||
root_hdr = await root_header_sx(tctx)
|
||||
blog_hdr = await _blog_hdr(tctx)
|
||||
blog_hdr = _blog_hdr(tctx)
|
||||
rows = "(<> " + root_hdr + " " + blog_hdr + ")"
|
||||
header_oob = await oob_header_sx("root-header-child", "blog-header-child", rows)
|
||||
sx_src = await oob_page_sx(oobs=header_oob, content=content,
|
||||
@@ -231,7 +231,7 @@ def register(url_prefix, title):
|
||||
from shared.sx.page import get_template_context
|
||||
from sxc.pages.renders import render_editor_panel
|
||||
tctx = await get_template_context()
|
||||
tctx["editor_html"] = await render_editor_panel(save_error="Invalid JSON in editor content.")
|
||||
tctx["editor_html"] = render_editor_panel(save_error="Invalid JSON in editor content.")
|
||||
html = await _render_new_post_page(tctx)
|
||||
return await make_response(html, 400)
|
||||
|
||||
@@ -240,7 +240,7 @@ def register(url_prefix, title):
|
||||
from shared.sx.page import get_template_context
|
||||
from sxc.pages.renders import render_editor_panel
|
||||
tctx = await get_template_context()
|
||||
tctx["editor_html"] = await render_editor_panel(save_error=reason)
|
||||
tctx["editor_html"] = render_editor_panel(save_error=reason)
|
||||
html = await _render_new_post_page(tctx)
|
||||
return await make_response(html, 400)
|
||||
|
||||
@@ -287,7 +287,7 @@ def register(url_prefix, title):
|
||||
from shared.sx.page import get_template_context
|
||||
from sxc.pages.renders import render_editor_panel
|
||||
tctx = await get_template_context()
|
||||
tctx["editor_html"] = await render_editor_panel(save_error="Invalid JSON in editor content.", is_page=True)
|
||||
tctx["editor_html"] = render_editor_panel(save_error="Invalid JSON in editor content.", is_page=True)
|
||||
tctx["is_page"] = True
|
||||
html = await _render_new_post_page(tctx)
|
||||
return await make_response(html, 400)
|
||||
@@ -297,7 +297,7 @@ def register(url_prefix, title):
|
||||
from shared.sx.page import get_template_context
|
||||
from sxc.pages.renders import render_editor_panel
|
||||
tctx = await get_template_context()
|
||||
tctx["editor_html"] = await render_editor_panel(save_error=reason, is_page=True)
|
||||
tctx["editor_html"] = render_editor_panel(save_error=reason, is_page=True)
|
||||
tctx["is_page"] = True
|
||||
html = await _render_new_post_page(tctx)
|
||||
return await make_response(html, 400)
|
||||
|
||||
@@ -13,12 +13,12 @@ from .services.menu_items import (
|
||||
MenuItemError,
|
||||
)
|
||||
from markupsafe import escape
|
||||
from shared.sx.helpers import sx_response, render_to_sx
|
||||
from shared.sx.helpers import sx_response, sx_call
|
||||
from shared.sx.parser import SxExpr
|
||||
from shared.browser.app.csrf import generate_csrf_token
|
||||
|
||||
|
||||
async def _render_menu_items_list(menu_items):
|
||||
def _render_menu_items_list(menu_items):
|
||||
"""Serialize ORM menu items and render via .sx defcomp."""
|
||||
csrf = generate_csrf_token()
|
||||
items = []
|
||||
@@ -32,8 +32,8 @@ async def _render_menu_items_list(menu_items):
|
||||
"delete_url": url_for("menu_items.delete_menu_item_route", item_id=item.id),
|
||||
})
|
||||
new_url = url_for("menu_items.new_menu_item")
|
||||
return await render_to_sx("blog-menu-items-content",
|
||||
menu_items=items, new_url=new_url, csrf=csrf)
|
||||
return sx_call("blog-menu-items-content",
|
||||
menu_items=items, new_url=new_url, csrf=csrf)
|
||||
|
||||
|
||||
def _render_menu_item_form(menu_item=None) -> str:
|
||||
@@ -120,16 +120,16 @@ document.addEventListener('click', function(e) {{
|
||||
return html
|
||||
|
||||
|
||||
async def _render_page_search_results(pages, query, page, has_more) -> str:
|
||||
def _render_page_search_results(pages, query, page, has_more) -> str:
|
||||
"""Render page search results."""
|
||||
if not pages and query:
|
||||
return await render_to_sx("page-search-empty", query=query)
|
||||
return sx_call("page-search-empty", query=query)
|
||||
if not pages:
|
||||
return ""
|
||||
|
||||
items = []
|
||||
for post in pages:
|
||||
items.append(await render_to_sx("page-search-item",
|
||||
items.append(sx_call("page-search-item",
|
||||
id=post.id, title=post.title,
|
||||
slug=post.slug,
|
||||
feature_image=post.feature_image or None))
|
||||
@@ -137,22 +137,22 @@ async def _render_page_search_results(pages, query, page, has_more) -> str:
|
||||
sentinel = ""
|
||||
if has_more:
|
||||
search_url = url_for("menu_items.search_pages_route")
|
||||
sentinel = await render_to_sx("page-search-sentinel",
|
||||
sentinel = sx_call("page-search-sentinel",
|
||||
url=search_url, query=query,
|
||||
next_page=page + 1)
|
||||
|
||||
items_sx = "(<> " + " ".join(items) + ")"
|
||||
return await render_to_sx("page-search-results",
|
||||
return sx_call("page-search-results",
|
||||
items=SxExpr(items_sx),
|
||||
sentinel=SxExpr(sentinel) if sentinel else None)
|
||||
|
||||
|
||||
async def _render_menu_items_nav_oob(menu_items) -> str:
|
||||
def _render_menu_items_nav_oob(menu_items) -> str:
|
||||
"""Render OOB nav update for menu items."""
|
||||
from quart import request as qrequest
|
||||
|
||||
if not menu_items:
|
||||
return await render_to_sx("blog-nav-empty", wrapper_id="menu-items-nav-wrapper")
|
||||
return sx_call("blog-nav-empty", wrapper_id="menu-items-nav-wrapper")
|
||||
|
||||
first_seg = qrequest.path.strip("/").split("/")[0] if qrequest else ""
|
||||
|
||||
@@ -185,23 +185,23 @@ async def _render_menu_items_nav_oob(menu_items) -> str:
|
||||
href = f"/{item_slug}/"
|
||||
selected = "true" if item_slug == first_seg else "false"
|
||||
|
||||
img_sx = await render_to_sx("img-or-placeholder", src=fi, alt=label,
|
||||
img_sx = sx_call("img-or-placeholder", src=fi, alt=label,
|
||||
size_cls="w-8 h-8 rounded-full object-cover flex-shrink-0")
|
||||
|
||||
if item_slug != "cart":
|
||||
item_parts.append(await render_to_sx("blog-nav-item-link",
|
||||
item_parts.append(sx_call("blog-nav-item-link",
|
||||
href=href, hx_get=f"/{item_slug}/", selected=selected,
|
||||
nav_cls=nav_button_cls, img=SxExpr(img_sx), label=label,
|
||||
))
|
||||
else:
|
||||
item_parts.append(await render_to_sx("blog-nav-item-plain",
|
||||
item_parts.append(sx_call("blog-nav-item-plain",
|
||||
href=href, selected=selected, nav_cls=nav_button_cls,
|
||||
img=SxExpr(img_sx), label=label,
|
||||
))
|
||||
|
||||
items_sx = "(<> " + " ".join(item_parts) + ")" if item_parts else ""
|
||||
|
||||
return await render_to_sx("scroll-nav-wrapper",
|
||||
return sx_call("scroll-nav-wrapper",
|
||||
wrapper_id="menu-items-nav-wrapper", container_id=container_id,
|
||||
arrow_cls=arrow_cls,
|
||||
left_hs=f"on click set #{container_id}.scrollLeft to #{container_id}.scrollLeft - 200",
|
||||
@@ -214,9 +214,9 @@ async def _render_menu_items_nav_oob(menu_items) -> str:
|
||||
def register():
|
||||
bp = Blueprint("menu_items", __name__, url_prefix='/settings/menu_items')
|
||||
|
||||
async def get_menu_items_nav_oob_async(menu_items):
|
||||
def get_menu_items_nav_oob_sync(menu_items):
|
||||
"""Helper to generate OOB update for root nav menu items"""
|
||||
return await _render_menu_items_nav_oob(menu_items)
|
||||
return _render_menu_items_nav_oob(menu_items)
|
||||
|
||||
@bp.get("/new/")
|
||||
@require_admin
|
||||
@@ -245,8 +245,8 @@ def register():
|
||||
|
||||
# Get updated list and nav OOB
|
||||
menu_items = await get_all_menu_items(g.s)
|
||||
html = await _render_menu_items_list(menu_items)
|
||||
nav_oob = await get_menu_items_nav_oob_async(menu_items)
|
||||
html = _render_menu_items_list(menu_items)
|
||||
nav_oob = get_menu_items_nav_oob_sync(menu_items)
|
||||
return sx_response(html + nav_oob)
|
||||
|
||||
except MenuItemError as e:
|
||||
@@ -283,8 +283,8 @@ def register():
|
||||
|
||||
# Get updated list and nav OOB
|
||||
menu_items = await get_all_menu_items(g.s)
|
||||
html = await _render_menu_items_list(menu_items)
|
||||
nav_oob = await get_menu_items_nav_oob_async(menu_items)
|
||||
html = _render_menu_items_list(menu_items)
|
||||
nav_oob = get_menu_items_nav_oob_sync(menu_items)
|
||||
return sx_response(html + nav_oob)
|
||||
|
||||
except MenuItemError as e:
|
||||
@@ -303,8 +303,8 @@ def register():
|
||||
|
||||
# Get updated list and nav OOB
|
||||
menu_items = await get_all_menu_items(g.s)
|
||||
html = await _render_menu_items_list(menu_items)
|
||||
nav_oob = await get_menu_items_nav_oob_async(menu_items)
|
||||
html = _render_menu_items_list(menu_items)
|
||||
nav_oob = get_menu_items_nav_oob_sync(menu_items)
|
||||
return sx_response(html + nav_oob)
|
||||
|
||||
@bp.get("/pages/search/")
|
||||
@@ -318,7 +318,7 @@ def register():
|
||||
pages, total = await search_pages(g.s, query, page, per_page)
|
||||
has_more = (page * per_page) < total
|
||||
|
||||
return sx_response(await _render_page_search_results(pages, query, page, has_more))
|
||||
return sx_response(_render_page_search_results(pages, query, page, has_more))
|
||||
|
||||
@bp.post("/reorder/")
|
||||
@require_admin
|
||||
@@ -342,8 +342,8 @@ def register():
|
||||
|
||||
# Get updated list and nav OOB
|
||||
menu_items = await get_all_menu_items(g.s)
|
||||
html = await _render_menu_items_list(menu_items)
|
||||
nav_oob = await get_menu_items_nav_oob_async(menu_items)
|
||||
html = _render_menu_items_list(menu_items)
|
||||
nav_oob = get_menu_items_nav_oob_sync(menu_items)
|
||||
return sx_response(html + nav_oob)
|
||||
|
||||
return bp
|
||||
|
||||
@@ -11,7 +11,7 @@ from quart import (
|
||||
)
|
||||
from shared.browser.app.authz import require_admin, require_post_author
|
||||
from markupsafe import escape
|
||||
from shared.sx.helpers import sx_response, render_to_sx
|
||||
from shared.sx.helpers import sx_response, sx_call
|
||||
from shared.sx.parser import SxExpr, serialize as sx_serialize
|
||||
from shared.utils import host_url
|
||||
|
||||
@@ -60,10 +60,10 @@ def _post_to_edit_dict(post) -> dict:
|
||||
return d
|
||||
|
||||
|
||||
async def _render_features(features, post, result):
|
||||
def _render_features(features, post, result):
|
||||
"""Render features panel via .sx defcomp."""
|
||||
slug = post.get("slug", "")
|
||||
return await render_to_sx("blog-features-panel-content",
|
||||
return sx_call("blog-features-panel-content",
|
||||
features_url=host_url(url_for("blog.post.admin.update_features", slug=slug)),
|
||||
calendar_checked=bool(features.get("calendar")),
|
||||
market_checked=bool(features.get("market")),
|
||||
@@ -187,7 +187,7 @@ def _render_calendar_view(
|
||||
return _raw_html_sx(html)
|
||||
|
||||
|
||||
async def _render_associated_entries(all_calendars, associated_entry_ids, post_slug: str) -> str:
|
||||
def _render_associated_entries(all_calendars, associated_entry_ids, post_slug: str) -> str:
|
||||
"""Render the associated entries panel."""
|
||||
from shared.browser.app.csrf import generate_csrf_token
|
||||
from quart import url_for as qurl
|
||||
@@ -216,13 +216,13 @@ async def _render_associated_entries(all_calendars, associated_entry_ids, post_s
|
||||
|
||||
toggle_url = host_url(qurl("blog.post.admin.toggle_entry", slug=post_slug, entry_id=e_id))
|
||||
|
||||
img_sx = await render_to_sx("blog-entry-image", src=cal_fi, title=cal_title)
|
||||
img_sx = sx_call("blog-entry-image", src=cal_fi, title=cal_title)
|
||||
|
||||
date_str = e_start.strftime("%A, %B %d, %Y at %H:%M") if e_start else ""
|
||||
if e_end:
|
||||
date_str += f" \u2013 {e_end.strftime('%H:%M')}"
|
||||
|
||||
entry_items.append(await render_to_sx("blog-associated-entry",
|
||||
entry_items.append(sx_call("blog-associated-entry",
|
||||
confirm_text=f"This will remove {e_name} from this post",
|
||||
toggle_url=toggle_url,
|
||||
hx_headers=f'{{"X-CSRFToken": "{csrf}"}}',
|
||||
@@ -231,16 +231,16 @@ async def _render_associated_entries(all_calendars, associated_entry_ids, post_s
|
||||
))
|
||||
|
||||
if has_entries:
|
||||
content_sx = await render_to_sx("blog-associated-entries-content",
|
||||
content_sx = sx_call("blog-associated-entries-content",
|
||||
items=SxExpr("(<> " + " ".join(entry_items) + ")"),
|
||||
)
|
||||
else:
|
||||
content_sx = await render_to_sx("blog-associated-entries-empty")
|
||||
content_sx = sx_call("blog-associated-entries-empty")
|
||||
|
||||
return await render_to_sx("blog-associated-entries-panel", content=SxExpr(content_sx))
|
||||
return sx_call("blog-associated-entries-panel", content=SxExpr(content_sx))
|
||||
|
||||
|
||||
async def _render_nav_entries_oob(associated_entries, calendars, post: dict) -> str:
|
||||
def _render_nav_entries_oob(associated_entries, calendars, post: dict) -> str:
|
||||
"""Render the OOB nav entries swap."""
|
||||
entries_list = []
|
||||
if associated_entries and hasattr(associated_entries, "entries"):
|
||||
@@ -249,7 +249,7 @@ async def _render_nav_entries_oob(associated_entries, calendars, post: dict) ->
|
||||
has_items = bool(entries_list or calendars)
|
||||
|
||||
if not has_items:
|
||||
return await render_to_sx("blog-nav-entries-empty")
|
||||
return sx_call("blog-nav-entries-empty")
|
||||
|
||||
select_colours = (
|
||||
"[.hover-capable_&]:hover:bg-yellow-300"
|
||||
@@ -291,7 +291,7 @@ async def _render_nav_entries_oob(associated_entries, calendars, post: dict) ->
|
||||
entry_path = f"/{post_slug}/{cal_slug}/"
|
||||
date_str = ""
|
||||
|
||||
item_parts.append(await render_to_sx("calendar-entry-nav",
|
||||
item_parts.append(sx_call("calendar-entry-nav",
|
||||
href=entry_path, nav_class=nav_cls, name=e_name, date_str=date_str,
|
||||
))
|
||||
|
||||
@@ -300,13 +300,13 @@ async def _render_nav_entries_oob(associated_entries, calendars, post: dict) ->
|
||||
cal_slug = getattr(calendar, "slug", "")
|
||||
cal_path = f"/{post_slug}/{cal_slug}/"
|
||||
|
||||
item_parts.append(await render_to_sx("blog-nav-calendar-item",
|
||||
item_parts.append(sx_call("blog-nav-calendar-item",
|
||||
href=cal_path, nav_cls=nav_cls, name=cal_name,
|
||||
))
|
||||
|
||||
items_sx = "(<> " + " ".join(item_parts) + ")" if item_parts else ""
|
||||
|
||||
return await render_to_sx("scroll-nav-wrapper",
|
||||
return sx_call("scroll-nav-wrapper",
|
||||
wrapper_id="entries-calendars-nav-wrapper", container_id="associated-items-container",
|
||||
arrow_cls="entries-nav-arrow",
|
||||
left_hs="on click set #associated-items-container.scrollLeft to #associated-items-container.scrollLeft - 200",
|
||||
@@ -353,7 +353,7 @@ def register():
|
||||
})
|
||||
|
||||
features = result.get("features", {})
|
||||
html = await _render_features(features, post, result)
|
||||
html = _render_features(features, post, result)
|
||||
return sx_response(html)
|
||||
|
||||
@bp.put("/admin/sumup/")
|
||||
@@ -386,7 +386,7 @@ def register():
|
||||
result = await call_action("blog", "update-page-config", payload=payload)
|
||||
|
||||
features = result.get("features", {})
|
||||
html = await _render_features(features, post, result)
|
||||
html = _render_features(features, post, result)
|
||||
return sx_response(html)
|
||||
|
||||
@bp.get("/entries/calendar/<int:calendar_id>/")
|
||||
@@ -508,8 +508,8 @@ def register():
|
||||
|
||||
# Return the associated entries admin list + OOB update for nav entries
|
||||
post = g.post_data["post"]
|
||||
admin_list = await _render_associated_entries(all_calendars, associated_entry_ids, post["slug"])
|
||||
nav_entries_html = await _render_nav_entries_oob(associated_entries, calendars, post)
|
||||
admin_list = _render_associated_entries(all_calendars, associated_entry_ids, post["slug"])
|
||||
nav_entries_html = _render_nav_entries_oob(associated_entries, calendars, post)
|
||||
|
||||
return sx_response(admin_list + nav_entries_html)
|
||||
|
||||
@@ -686,7 +686,7 @@ def register():
|
||||
|
||||
slug = post.get("slug", "")
|
||||
create_url = host_url(url_for("blog.post.admin.create_market", slug=slug))
|
||||
html = await render_to_sx("blog-markets-panel-content",
|
||||
html = sx_call("blog-markets-panel-content",
|
||||
markets=_serialize_markets(page_markets, slug), create_url=create_url)
|
||||
return sx_response(html)
|
||||
|
||||
@@ -715,7 +715,7 @@ def register():
|
||||
|
||||
slug = post.get("slug", "")
|
||||
create_url = host_url(url_for("blog.post.admin.create_market", slug=slug))
|
||||
html = await render_to_sx("blog-markets-panel-content",
|
||||
html = sx_call("blog-markets-panel-content",
|
||||
markets=_serialize_markets(page_markets, slug), create_url=create_url)
|
||||
return sx_response(html)
|
||||
|
||||
@@ -738,7 +738,7 @@ def register():
|
||||
|
||||
slug = post.get("slug", "")
|
||||
create_url = host_url(url_for("blog.post.admin.create_market", slug=slug))
|
||||
html = await render_to_sx("blog-markets-panel-content",
|
||||
html = sx_call("blog-markets-panel-content",
|
||||
markets=_serialize_markets(page_markets, slug), create_url=create_url)
|
||||
return sx_response(html)
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ def register():
|
||||
async def post_detail(slug: str):
|
||||
from shared.sx.page import get_template_context
|
||||
from shared.sx.helpers import (
|
||||
render_to_sx, root_header_sx, full_page_sx, oob_page_sx,
|
||||
sx_call, root_header_sx, full_page_sx, oob_page_sx,
|
||||
post_header_sx, oob_header_sx, mobile_menu_sx,
|
||||
post_mobile_nav_sx, mobile_root_nav_sx,
|
||||
)
|
||||
@@ -124,9 +124,9 @@ def register():
|
||||
csrf = generate_csrf_token()
|
||||
svc = services.blog_page
|
||||
detail_data = svc.post_detail_data(post, user, rights, csrf, blog_url_base)
|
||||
content = await render_to_sx("blog-post-detail-content", **detail_data)
|
||||
content = sx_call("blog-post-detail-content", **detail_data)
|
||||
meta_data = svc.post_meta_data(post, tctx.get("base_title", ""))
|
||||
meta = await render_to_sx("blog-meta", **meta_data)
|
||||
meta = sx_call("blog-meta", **meta_data)
|
||||
|
||||
if not is_htmx_request():
|
||||
root_hdr = await root_header_sx(tctx)
|
||||
@@ -149,24 +149,24 @@ def register():
|
||||
@clear_cache(tag="post.post_detail", tag_scope="user")
|
||||
async def like_toggle(slug: str):
|
||||
from shared.utils import host_url
|
||||
from shared.sx.helpers import render_to_sx
|
||||
from shared.sx.helpers import sx_call
|
||||
from shared.browser.app.csrf import generate_csrf_token
|
||||
|
||||
like_url = host_url(url_for('blog.post.like_toggle', slug=slug))
|
||||
csrf = generate_csrf_token()
|
||||
|
||||
async def _like_btn(liked):
|
||||
def _like_btn(liked):
|
||||
if liked:
|
||||
colour, icon, label = "text-red-600", "fa-solid fa-heart", "Unlike this post"
|
||||
else:
|
||||
colour, icon, label = "text-stone-300", "fa-regular fa-heart", "Like this post"
|
||||
return await render_to_sx("market-like-toggle-button",
|
||||
return sx_call("market-like-toggle-button",
|
||||
colour=colour, action=like_url,
|
||||
hx_headers=f'{{"X-CSRFToken": "{csrf}"}}',
|
||||
label=label, icon_cls=icon)
|
||||
|
||||
if not g.user:
|
||||
return sx_response(await _like_btn(False), status=403)
|
||||
return sx_response(_like_btn(False), status=403)
|
||||
|
||||
post_id = g.post_data["post"]["id"]
|
||||
user_id = g.user.id
|
||||
@@ -175,7 +175,7 @@ def register():
|
||||
"user_id": user_id, "target_type": "post", "target_id": post_id,
|
||||
})
|
||||
|
||||
return sx_response(await _like_btn(result["liked"]))
|
||||
return sx_response(_like_btn(result["liked"]))
|
||||
|
||||
@bp.get("/w/<widget_domain>/")
|
||||
async def widget_paginate(slug: str, widget_domain: str):
|
||||
|
||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
from quart import Blueprint, request, g, abort
|
||||
|
||||
from shared.browser.app.authz import require_login
|
||||
from shared.sx.helpers import sx_response, render_to_sx
|
||||
from shared.sx.helpers import sx_response, sx_call
|
||||
from models import Snippet
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ async def _render_snippets():
|
||||
"""Render snippets list via service data + .sx defcomp."""
|
||||
from shared.services.registry import services
|
||||
data = await services.blog_page.snippets_data(g.s)
|
||||
return await render_to_sx("blog-snippets-content", **data)
|
||||
return sx_call("blog-snippets-content", **data)
|
||||
|
||||
|
||||
def register():
|
||||
|
||||
@@ -126,22 +126,22 @@ def _register_blog_helpers() -> None:
|
||||
|
||||
# --- Editor helpers ---
|
||||
|
||||
async def _h_editor_content(**kw):
|
||||
def _h_editor_content(**kw):
|
||||
from .renders import render_editor_panel
|
||||
return await render_editor_panel()
|
||||
return render_editor_panel()
|
||||
|
||||
|
||||
async def _h_editor_page_content(**kw):
|
||||
def _h_editor_page_content(**kw):
|
||||
from .renders import render_editor_panel
|
||||
return await render_editor_panel(is_page=True)
|
||||
return render_editor_panel(is_page=True)
|
||||
|
||||
|
||||
# --- Post admin helpers ---
|
||||
|
||||
async def _h_post_admin_content(slug=None, **kw):
|
||||
await _ensure_post_data(slug)
|
||||
from shared.sx.helpers import render_to_sx
|
||||
return await render_to_sx("blog-admin-placeholder")
|
||||
from shared.sx.helpers import sx_call
|
||||
return sx_call("blog-admin-placeholder")
|
||||
|
||||
|
||||
async def _h_post_data_content(slug=None, **kw):
|
||||
@@ -264,32 +264,32 @@ async def _h_post_preview_content(slug=None, **kw):
|
||||
await _ensure_post_data(slug)
|
||||
from quart import g
|
||||
from shared.services.registry import services
|
||||
from shared.sx.helpers import render_to_sx
|
||||
from shared.sx.helpers import sx_call
|
||||
from shared.sx.parser import SxExpr
|
||||
|
||||
preview = await services.blog_page.preview_data(g.s)
|
||||
|
||||
sections: list[str] = []
|
||||
if preview.get("sx_pretty"):
|
||||
sections.append(await render_to_sx("blog-preview-section",
|
||||
sections.append(sx_call("blog-preview-section",
|
||||
title="S-Expression Source", content=SxExpr(preview["sx_pretty"])))
|
||||
if preview.get("json_pretty"):
|
||||
sections.append(await render_to_sx("blog-preview-section",
|
||||
sections.append(sx_call("blog-preview-section",
|
||||
title="Lexical JSON", content=SxExpr(preview["json_pretty"])))
|
||||
if preview.get("sx_rendered"):
|
||||
rendered_sx = await render_to_sx("blog-preview-rendered", html=preview["sx_rendered"])
|
||||
sections.append(await render_to_sx("blog-preview-section",
|
||||
rendered_sx = sx_call("blog-preview-rendered", html=preview["sx_rendered"])
|
||||
sections.append(sx_call("blog-preview-section",
|
||||
title="SX Rendered", content=SxExpr(rendered_sx)))
|
||||
if preview.get("lex_rendered"):
|
||||
rendered_sx = await render_to_sx("blog-preview-rendered", html=preview["lex_rendered"])
|
||||
sections.append(await render_to_sx("blog-preview-section",
|
||||
rendered_sx = sx_call("blog-preview-rendered", html=preview["lex_rendered"])
|
||||
sections.append(sx_call("blog-preview-section",
|
||||
title="Lexical Rendered", content=SxExpr(rendered_sx)))
|
||||
|
||||
if not sections:
|
||||
return await render_to_sx("blog-preview-empty")
|
||||
return sx_call("blog-preview-empty")
|
||||
|
||||
inner = " ".join(sections)
|
||||
return await render_to_sx("blog-preview-panel", sections=SxExpr(f"(<> {inner})"))
|
||||
return sx_call("blog-preview-panel", sections=SxExpr(f"(<> {inner})"))
|
||||
|
||||
|
||||
async def _h_post_entries_content(slug=None, **kw):
|
||||
@@ -315,7 +315,7 @@ async def _h_post_entries_content(slug=None, **kw):
|
||||
await g.s.refresh(calendar, ["entries", "post"])
|
||||
|
||||
# Associated entries list
|
||||
assoc_html = await _render_associated_entries(all_calendars, associated_entry_ids, post_slug)
|
||||
assoc_html = _render_associated_entries(all_calendars, associated_entry_ids, post_slug)
|
||||
|
||||
# Calendar browser
|
||||
cal_items: list[str] = []
|
||||
@@ -505,7 +505,7 @@ async def _h_post_edit_content(slug=None, **kw):
|
||||
from sqlalchemy.orm import selectinload
|
||||
from shared.infrastructure.data_client import fetch_data
|
||||
from shared.browser.app.csrf import generate_csrf_token
|
||||
from shared.sx.helpers import render_to_sx
|
||||
from shared.sx.helpers import sx_call
|
||||
from shared.sx.parser import SxExpr, serialize as sx_serialize
|
||||
from bp.post.admin.routes import _post_to_edit_dict
|
||||
|
||||
@@ -584,9 +584,9 @@ async def _h_post_edit_content(slug=None, **kw):
|
||||
parts: list[str] = []
|
||||
|
||||
if save_error:
|
||||
parts.append(await render_to_sx("blog-editor-error", error=save_error))
|
||||
parts.append(sx_call("blog-editor-error", error=save_error))
|
||||
|
||||
parts.append(await render_to_sx("blog-editor-edit-form",
|
||||
parts.append(sx_call("blog-editor-edit-form",
|
||||
csrf=csrf,
|
||||
updated_at=str(updated_at),
|
||||
title_val=title_val,
|
||||
@@ -603,9 +603,9 @@ async def _h_post_edit_content(slug=None, **kw):
|
||||
footer_extra=footer_extra_sx,
|
||||
))
|
||||
|
||||
parts.append(await render_to_sx("blog-editor-publish-js", already_emailed=already_emailed))
|
||||
parts.append(await render_to_sx("blog-editor-styles", css_href=editor_css))
|
||||
parts.append(await render_to_sx("sx-editor-styles"))
|
||||
parts.append(sx_call("blog-editor-publish-js", already_emailed=already_emailed))
|
||||
parts.append(sx_call("blog-editor-styles", css_href=editor_css))
|
||||
parts.append(sx_call("sx-editor-styles"))
|
||||
|
||||
init_js = (
|
||||
'(function() {'
|
||||
@@ -705,10 +705,10 @@ async def _h_post_edit_content(slug=None, **kw):
|
||||
' }, 50); }'
|
||||
'})();'
|
||||
)
|
||||
parts.append(await render_to_sx("blog-editor-scripts",
|
||||
parts.append(sx_call("blog-editor-scripts",
|
||||
js_src=editor_js,
|
||||
sx_editor_js_src=sx_editor_js,
|
||||
init_js=init_js))
|
||||
|
||||
return await render_to_sx("blog-editor-panel",
|
||||
return sx_call("blog-editor-panel",
|
||||
parts=SxExpr("(<> " + " ".join(parts) + ")"))
|
||||
|
||||
@@ -5,19 +5,19 @@ from typing import Any
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Header helpers (moved from sx_components — thin render_to_sx wrappers)
|
||||
# Header helpers (moved from sx_components — thin sx_call wrappers)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
async def _settings_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
||||
from shared.sx.helpers import render_to_sx
|
||||
def _settings_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
||||
from shared.sx.helpers import sx_call
|
||||
from shared.sx.parser import SxExpr
|
||||
from quart import url_for as qurl
|
||||
|
||||
settings_href = qurl("settings.defpage_settings_home")
|
||||
label_sx = await render_to_sx("blog-admin-label")
|
||||
nav_sx = await _settings_nav_sx(ctx)
|
||||
label_sx = sx_call("blog-admin-label")
|
||||
nav_sx = _settings_nav_sx(ctx)
|
||||
|
||||
return await render_to_sx("menu-row-sx",
|
||||
return sx_call("menu-row-sx",
|
||||
id="root-settings-row", level=1,
|
||||
link_href=settings_href,
|
||||
link_label_content=SxExpr(label_sx),
|
||||
@@ -25,20 +25,20 @@ async def _settings_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
||||
child_id="root-settings-header-child", oob=oob)
|
||||
|
||||
|
||||
async def _settings_nav_sx(ctx: dict) -> str:
|
||||
from shared.sx.helpers import render_to_sx
|
||||
return await render_to_sx("blog-settings-nav")
|
||||
def _settings_nav_sx(ctx: dict) -> str:
|
||||
from shared.sx.helpers import sx_call
|
||||
return sx_call("blog-settings-nav")
|
||||
|
||||
|
||||
async def _sub_settings_header_sx(row_id: str, child_id: str, href: str,
|
||||
icon: str, label: str, ctx: dict,
|
||||
*, oob: bool = False, nav_sx: str = "") -> str:
|
||||
from shared.sx.helpers import render_to_sx
|
||||
def _sub_settings_header_sx(row_id: str, child_id: str, href: str,
|
||||
icon: str, label: str, ctx: dict,
|
||||
*, oob: bool = False, nav_sx: str = "") -> str:
|
||||
from shared.sx.helpers import sx_call
|
||||
from shared.sx.parser import SxExpr
|
||||
|
||||
label_sx = await render_to_sx("blog-sub-settings-label",
|
||||
label_sx = sx_call("blog-sub-settings-label",
|
||||
icon=f"fa fa-{icon}", label=label)
|
||||
return await render_to_sx("menu-row-sx",
|
||||
return sx_call("menu-row-sx",
|
||||
id=row_id, level=2,
|
||||
link_href=href,
|
||||
link_label_content=SxExpr(label_sx),
|
||||
@@ -82,19 +82,19 @@ async def _settings_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env
|
||||
from shared.sx.parser import SxExpr
|
||||
return await render_to_sx_with_env("settings-layout-full", {},
|
||||
settings_header=SxExpr(await _settings_header_sx(ctx)))
|
||||
settings_header=SxExpr(_settings_header_sx(ctx)))
|
||||
|
||||
|
||||
async def _settings_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
|
||||
from shared.sx.parser import SxExpr
|
||||
rows = await render_to_sx_with_env("settings-layout-full", {},
|
||||
settings_header=SxExpr(await _settings_header_sx(ctx)))
|
||||
settings_header=SxExpr(_settings_header_sx(ctx)))
|
||||
return await oob_header_sx("root-header-child", "root-settings-header-child", rows)
|
||||
|
||||
|
||||
async def _settings_mobile(ctx: dict, **kw: Any) -> str:
|
||||
return await _settings_nav_sx(ctx)
|
||||
def _settings_mobile(ctx: dict, **kw: Any) -> str:
|
||||
return _settings_nav_sx(ctx)
|
||||
|
||||
|
||||
# --- Sub-settings helpers ---
|
||||
@@ -105,21 +105,21 @@ async def _sub_settings_full(ctx: dict, row_id: str, child_id: str,
|
||||
from shared.sx.parser import SxExpr
|
||||
from quart import url_for as qurl
|
||||
return await render_to_sx_with_env("sub-settings-layout-full", {},
|
||||
settings_header=SxExpr(await _settings_header_sx(ctx)),
|
||||
sub_header=SxExpr(await _sub_settings_header_sx(
|
||||
settings_header=SxExpr(_settings_header_sx(ctx)),
|
||||
sub_header=SxExpr(_sub_settings_header_sx(
|
||||
row_id, child_id, qurl(endpoint), icon, label, ctx)))
|
||||
|
||||
|
||||
async def _sub_settings_oob(ctx: dict, row_id: str, child_id: str,
|
||||
endpoint: str, icon: str, label: str) -> str:
|
||||
from shared.sx.helpers import oob_header_sx, render_to_sx
|
||||
from shared.sx.helpers import oob_header_sx, sx_call
|
||||
from shared.sx.parser import SxExpr
|
||||
from quart import url_for as qurl
|
||||
settings_hdr_oob = await _settings_header_sx(ctx, oob=True)
|
||||
sub_hdr = await _sub_settings_header_sx(
|
||||
settings_hdr_oob = _settings_header_sx(ctx, oob=True)
|
||||
sub_hdr = _sub_settings_header_sx(
|
||||
row_id, child_id, qurl(endpoint), icon, label, ctx)
|
||||
sub_oob = await oob_header_sx("root-settings-header-child", child_id, sub_hdr)
|
||||
return await render_to_sx("sub-settings-layout-oob",
|
||||
return sx_call("sub-settings-layout-oob",
|
||||
settings_header_oob=SxExpr(settings_hdr_oob),
|
||||
sub_header_oob=SxExpr(sub_oob))
|
||||
|
||||
@@ -180,8 +180,8 @@ async def _tag_group_edit_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.parser import SxExpr
|
||||
g_id = (request.view_args or {}).get("id")
|
||||
return await render_to_sx_with_env("sub-settings-layout-full", {},
|
||||
settings_header=SxExpr(await _settings_header_sx(ctx)),
|
||||
sub_header=SxExpr(await _sub_settings_header_sx(
|
||||
settings_header=SxExpr(_settings_header_sx(ctx)),
|
||||
sub_header=SxExpr(_sub_settings_header_sx(
|
||||
"tag-groups-row", "tag-groups-header-child",
|
||||
qurl("defpage_tag_group_edit", id=g_id),
|
||||
"tags", "Tag Groups", ctx)))
|
||||
@@ -189,15 +189,15 @@ async def _tag_group_edit_full(ctx: dict, **kw: Any) -> str:
|
||||
|
||||
async def _tag_group_edit_oob(ctx: dict, **kw: Any) -> str:
|
||||
from quart import request, url_for as qurl
|
||||
from shared.sx.helpers import oob_header_sx, render_to_sx
|
||||
from shared.sx.helpers import oob_header_sx, sx_call
|
||||
from shared.sx.parser import SxExpr
|
||||
g_id = (request.view_args or {}).get("id")
|
||||
settings_hdr_oob = await _settings_header_sx(ctx, oob=True)
|
||||
sub_hdr = await _sub_settings_header_sx(
|
||||
settings_hdr_oob = _settings_header_sx(ctx, oob=True)
|
||||
sub_hdr = _sub_settings_header_sx(
|
||||
"tag-groups-row", "tag-groups-header-child",
|
||||
qurl("defpage_tag_group_edit", id=g_id),
|
||||
"tags", "Tag Groups", ctx)
|
||||
sub_oob = await oob_header_sx("root-settings-header-child", "tag-groups-header-child", sub_hdr)
|
||||
return await render_to_sx("sub-settings-layout-oob",
|
||||
return sx_call("sub-settings-layout-oob",
|
||||
settings_header_oob=SxExpr(settings_hdr_oob),
|
||||
sub_header_oob=SxExpr(sub_oob))
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
async def render_editor_panel(save_error: str | None = None, is_page: bool = False) -> str:
|
||||
def render_editor_panel(save_error: str | None = None, is_page: bool = False) -> str:
|
||||
"""Build the WYSIWYG editor panel HTML for new post/page creation."""
|
||||
import os
|
||||
from quart import url_for as qurl, current_app
|
||||
from shared.browser.app.csrf import generate_csrf_token
|
||||
from shared.sx.helpers import render_to_sx
|
||||
from shared.sx.helpers import sx_call
|
||||
|
||||
csrf = generate_csrf_token()
|
||||
asset_url_fn = current_app.jinja_env.globals.get("asset_url", lambda p: "")
|
||||
@@ -28,15 +28,15 @@ async def render_editor_panel(save_error: str | None = None, is_page: bool = Fal
|
||||
parts: list[str] = []
|
||||
|
||||
if save_error:
|
||||
parts.append(await render_to_sx("blog-editor-error", error=str(save_error)))
|
||||
parts.append(sx_call("blog-editor-error", error=str(save_error)))
|
||||
|
||||
parts.append(await render_to_sx("blog-editor-form",
|
||||
parts.append(sx_call("blog-editor-form",
|
||||
csrf=csrf, title_placeholder=title_placeholder,
|
||||
create_label=create_label,
|
||||
))
|
||||
|
||||
parts.append(await render_to_sx("blog-editor-styles", css_href=editor_css))
|
||||
parts.append(await render_to_sx("sx-editor-styles"))
|
||||
parts.append(sx_call("blog-editor-styles", css_href=editor_css))
|
||||
parts.append(sx_call("sx-editor-styles"))
|
||||
|
||||
init_js = (
|
||||
"console.log('[EDITOR-DEBUG] init script running');\n"
|
||||
@@ -167,11 +167,11 @@ async def render_editor_panel(save_error: str | None = None, is_page: bool = Fal
|
||||
" }\n"
|
||||
"})();\n"
|
||||
)
|
||||
parts.append(await render_to_sx("blog-editor-scripts",
|
||||
parts.append(sx_call("blog-editor-scripts",
|
||||
js_src=editor_js,
|
||||
sx_editor_js_src=sx_editor_js,
|
||||
init_js=init_js))
|
||||
|
||||
from shared.sx.parser import SxExpr
|
||||
return await render_to_sx("blog-editor-panel",
|
||||
return sx_call("blog-editor-panel",
|
||||
parts=SxExpr("(<> " + " ".join(parts) + ")")) if parts else ""
|
||||
|
||||
Reference in New Issue
Block a user