This repository has been archived on 2026-02-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
shared/services/widget_registry.py
giles 7882644731 Add widget registry for universal UI decoupling
Introduces a widget system where domains register UI fragments into
named slots (container_nav, container_card, account_page, account_link).
Host apps iterate widgets generically without naming any domain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:04:13 +00:00

91 lines
2.6 KiB
Python

"""Singleton widget registry for cross-domain UI composition.
Usage::
from shared.services.widget_registry import widgets
# Register at app startup (after domain services)
widgets.add_container_nav(NavWidget(...))
# Query in templates / context processors
for w in widgets.container_nav:
ctx = await w.context_fn(session, container_type="page", ...)
"""
from __future__ import annotations
from shared.contracts.widgets import (
NavWidget,
CardWidget,
AccountPageWidget,
AccountNavLink,
)
class _WidgetRegistry:
"""Central registry holding all widget descriptors.
Widgets are added at startup and read at request time.
Properties return sorted-by-order copies.
"""
def __init__(self) -> None:
self._container_nav: list[NavWidget] = []
self._container_card: list[CardWidget] = []
self._account_pages: list[AccountPageWidget] = []
self._account_nav: list[AccountNavLink] = []
# -- registration ---------------------------------------------------------
def add_container_nav(self, w: NavWidget) -> None:
self._container_nav.append(w)
def add_container_card(self, w: CardWidget) -> None:
self._container_card.append(w)
def add_account_page(self, w: AccountPageWidget) -> None:
self._account_pages.append(w)
# Auto-create a matching internal nav link
slug = w.slug
def _href(s=slug):
from shared.infrastructure.urls import coop_url
return coop_url(f"/auth/{s}/")
self._account_nav.append(AccountNavLink(
label=w.label,
order=w.order,
href_fn=_href,
external=False,
))
def add_account_link(self, link: AccountNavLink) -> None:
self._account_nav.append(link)
# -- read access (sorted copies) ------------------------------------------
@property
def container_nav(self) -> list[NavWidget]:
return sorted(self._container_nav, key=lambda w: w.order)
@property
def container_cards(self) -> list[CardWidget]:
return sorted(self._container_card, key=lambda w: w.order)
@property
def account_pages(self) -> list[AccountPageWidget]:
return sorted(self._account_pages, key=lambda w: w.order)
@property
def account_nav(self) -> list[AccountNavLink]:
return sorted(self._account_nav, key=lambda w: w.order)
def account_page_by_slug(self, slug: str) -> AccountPageWidget | None:
for w in self._account_pages:
if w.slug == slug:
return w
return None
# Module-level singleton — import this everywhere.
widgets = _WidgetRegistry()