Convert test/cart/blog/market layouts to use _ctx_to_env + render_to_sx_with_env

Phase 4 (Test): Update ~test-layout-full and ~test-detail-layout-full defcomps
to use ~root-header with env free variables. Switch render functions to
render_to_sx_with_env.

Phase 5 (Cart): Convert cart-page, cart-admin, and order render functions.
Update cart .sx layout defcomps to use ~root-header from free variables.

Phase 6 (Blog): Convert all 7 blog layouts (blog, settings, sub-settings x5).
Remove all root_header_sx calls from blog.

Phase 7 (Market): Convert market and market-admin layouts plus browse/product
render functions. Remove root_header_sx import.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 15:02:59 +00:00
parent a30e7228d8
commit 1dbf600af2
8 changed files with 507 additions and 350 deletions

104
test/sx/components.sx Normal file
View File

@@ -0,0 +1,104 @@
;; Test service composition defcomps — replaces Python string concatenation
;; in test/sxc/pages/__init__.py.
;; Service filter nav links
(defcomp ~test-service-nav (&key services active-service)
(<>
(~nav-link :href "/" :label "all"
:is-selected (if (not active-service) "true" nil)
:select-colours "aria-selected:bg-sky-200 aria-selected:text-sky-900")
(map (lambda (svc)
(~nav-link :href (str "/?service=" svc) :label svc
:is-selected (if (= active-service svc) "true" nil)
:select-colours "aria-selected:bg-sky-200 aria-selected:text-sky-900"))
services)))
;; Test header menu row
(defcomp ~test-header-row (&key services active-service)
(~menu-row-sx :id "test-row" :level 1 :colour "sky"
:link-href "/" :link-label "Tests" :icon "fa fa-flask"
:nav (~test-service-nav :services services :active-service active-service)
:child-id "test-header-child"))
;; Layout: full page header stack (reads root header values from env free variables)
(defcomp ~test-layout-full (&key services active-service)
(<> (~root-header :cart-mini cart-mini :blog-url blog-url :site-title site-title
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin)
(~header-child-sx
:inner (~test-header-row :services services :active-service active-service))))
;; Map test dicts to test-row components
(defcomp ~test-rows (&key tests)
(<> (map (lambda (t)
(~test-row
:nodeid (get t "nodeid")
:outcome (get t "outcome")
:duration (str (get t "duration"))
:longrepr (or (get t "longrepr") "")))
tests)))
;; Grouped test rows with service headers
(defcomp ~test-grouped-rows (&key sections)
(<> (map (lambda (sec)
(<> (~test-service-header
:service (get sec "service")
:total (str (get sec "total"))
:passed (str (get sec "passed"))
:failed (str (get sec "failed")))
(~test-rows :tests (get sec "tests"))))
sections)))
;; Results partial: conditional rendering based on running/result state
(defcomp ~test-results-partial (&key status summary-data tests sections has-failures)
(let* ((state (get summary-data "state")))
(<>
(~test-summary
:status (get summary-data "status")
:passed (get summary-data "passed")
:failed (get summary-data "failed")
:errors (get summary-data "errors")
:skipped (get summary-data "skipped")
:total (get summary-data "total")
:duration (get summary-data "duration")
:last-run (get summary-data "last_run")
:running (get summary-data "running")
:csrf (get summary-data "csrf")
:active-filter (get summary-data "active_filter"))
(cond
((= state "running") (~test-running-indicator))
((= state "no-results") (~test-no-results))
((= state "empty-filtered") (~test-no-results))
(true (~test-results-table
:rows (~test-grouped-rows :sections sections)
:has-failures has-failures))))))
;; Wrap results in a div with optional HTMX polling
(defcomp ~test-results-wrap (&key running inner)
(div :id "test-results" :class "space-y-6 p-4"
:sx-get (when running "/results")
:sx-trigger (when running "every 2s")
:sx-swap (when running "outerHTML")
inner))
;; Test detail section wrapper
(defcomp ~test-detail-section (&key test)
(section :id "main-panel"
:class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"
(~test-detail
:nodeid (get test "nodeid")
:outcome (get test "outcome")
:duration (str (get test "duration"))
:longrepr (or (get test "longrepr") ""))))
;; Detail page header stack (reads root header values from env free variables)
(defcomp ~test-detail-layout-full (&key services test-nodeid test-label)
(<> (~root-header :cart-mini cart-mini :blog-url blog-url :site-title site-title
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin)
(~header-child-sx
:inner (<> (~test-header-row :services services)
(~header-child-sx :id "test-header-child"
:inner (~menu-row-sx :id "test-detail-row" :level 2 :colour "sky"
:link-href (str "/test/" test-nodeid)
:link-label test-label))))))