Discovers and caches the widget catalog.
The catalog is the union of every PhoenixKit module that defines
phoenix_kit_widgets/0 (see PhoenixKitDashboards.Widget for the contract).
This module is one such provider — its built-in widgets (note, clock,
module-stats) are exposed through the same phoenix_kit_widgets/0 entry point
as any other module, so there is no special-cased "built-in" path.
Discovery is convention-based — it queries PhoenixKit.ModuleRegistry at
runtime and calls phoenix_kit_widgets/0 on any module that exports it (always
including PhoenixKitDashboards itself, so the built-ins are available even
before/without ModuleRegistry discovery). No new core PhoenixKit.Module
callback is required, so this ships independently of a core release. (If the
contract proves load-bearing, it can later be promoted into the
PhoenixKit.Module behaviour.)
The result is memoized in :persistent_term, mirroring how core's
ModuleRegistry caches tabs and permissions. Call refresh/0 after modules
are toggled to rebuild.
Summary
Functions
The full widget catalog, keyed by widget key.
Look up a single widget type by key.
List all catalog widgets, sorted by category then name.
Catalog widgets visible to a given scope.
Rebuild the catalog from every discovered widget provider and re-cache it.
Whether one widget type is visible to a scope — the same gate list_for_scope/1
applies to the catalog. The render path uses it too, so a placed widget stops
rendering (and refreshing) when its module is disabled or the viewer's scope
lacks the module permission — placing a widget must not outlive the gate that
offered it. nil scope skips the permission half (module enablement still
applies); a widget with no module_key is always visible.
Functions
@spec catalog() :: %{required(String.t()) => PhoenixKitDashboards.Widget.t()}
The full widget catalog, keyed by widget key.
Memoized in :persistent_term; first call builds it.
@spec get(String.t()) :: PhoenixKitDashboards.Widget.t() | nil
Look up a single widget type by key.
@spec list() :: [PhoenixKitDashboards.Widget.t()]
List all catalog widgets, sorted by category then name.
@spec list_for_scope(scope :: term() | nil) :: [PhoenixKitDashboards.Widget.t()]
Catalog widgets visible to a given scope.
Filters out widgets whose owning module is disabled or whose module_key
permission the scope lacks. Built-in widgets (no module_key) are always
visible. Pass nil to skip filtering (e.g. system/internal callers).
@spec refresh() :: %{required(String.t()) => PhoenixKitDashboards.Widget.t()}
Rebuild the catalog from every discovered widget provider and re-cache it.
@spec visible_for_scope?(PhoenixKitDashboards.Widget.t(), scope :: term() | nil) :: boolean()
Whether one widget type is visible to a scope — the same gate list_for_scope/1
applies to the catalog. The render path uses it too, so a placed widget stops
rendering (and refreshing) when its module is disabled or the viewer's scope
lacks the module permission — placing a widget must not outlive the gate that
offered it. nil scope skips the permission half (module enablement still
applies); a widget with no module_key is always visible.