Admin sidebar component for the PhoenixKit admin panel.
Renders the admin navigation using registry-driven Tab structs instead of hardcoded HEEX. Supports:
- Permission-gated tabs (filtered by Registry)
- Module-enabled filtering (filtered by Registry)
- Dynamic children for Entities and Publishing
- Subtab expand/collapse
- Full reuse of the TabItem component for consistent rendering
An entry is rendered only if the visitor can open it
The menu must never offer a page that bounces the visitor on arrival, so
every entry is filtered against the SAME gates its destination enforces —
see reachable_tabs/2. This matters because /admin is the guaranteed
landing for every authenticated user: a visitor with no permissions at all
now renders this shell, where before only a permission holder could.
The registry already drops a tab whose :permission key the scope does not
hold (Registry.get_tabs/1 → Tab.permission_granted?/2) and a tab whose
:visible function says no. Two gates it does NOT apply are added here:
Scope.can_access_admin_area?/1, the first thing:phoenix_kit_ensure_adminchecks. Fail it and EVERY/adminpage redirects you — including the personal ones — so the whole menu is empty.PhoenixKitWeb.Users.Auth.can_access_admin_view?/2for an entry that names alive_view:. A tab may name a view and no permission key; the mount gate then treats that view as unmapped and admits only a scope holding every enabled permission, while the sidebar happily linked it for everyone.
Usage
<.admin_sidebar
current_path={@current_path}
scope={@phoenix_kit_current_scope}
locale={@current_locale}
/>
Summary
Functions
Renders the complete admin sidebar navigation.
Keeps only the entries scope can actually open.
Functions
Renders the complete admin sidebar navigation.
Attributes
current_path- The current URL path for active state detectionscope- The current authentication scope for permission filteringlocale- The current locale for path generationclass- Additional CSS classes
Attributes
current_path(:string) - Defaults to"/admin".scope(:any) - Defaults tonil.locale(:string) - Defaults tonil.class(:string) - Defaults to"".
@spec reachable_tabs( [PhoenixKit.Dashboard.Tab.t()], PhoenixKit.Users.Auth.Scope.t() | nil ) :: [ PhoenixKit.Dashboard.Tab.t() ]
Keeps only the entries scope can actually open.
Two gates, in the order the mount hook applies them:
Scope.can_access_admin_area?/1— the admin-area gate:phoenix_kit_ensure_adminchecks before anything else. A scope that fails it (anilscope, or an authenticated user holding no permission at all) is redirected off every/adminpage, personal ones included, so the answer is[]— not "the tabs with no permission key".PhoenixKitWeb.Users.Auth.can_access_admin_view?/2for any entry naming alive_view:— the same function the mount gate asks. Nothing is restated here, so a rendered entry and its destination cannot disagree.
An entry with no live_view: is left to the registry's own :permission /
:visible filtering — Registry.get_admin_tabs/1 applies both before the
sidebar calls this. Every tab core ships is of that shape: core declares its
admin routes in the router rather than on the tab, so there is no module to
ask, and gate 2 is a structural no-op over core's own menu.