# `PhoenixKit.Dashboard.Registry`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v1.7.87/lib/phoenix_kit/dashboard/registry.ex#L1)

Registry for managing dashboard tabs across the application.

The Registry provides both compile-time configuration via application config
and runtime registration for dynamic tabs. Tabs are stored in an ETS table
for efficient access.

## Configuration

Tabs can be configured in your application config:

    config :phoenix_kit, :user_dashboard_tabs, [
      %{
        id: :orders,
        label: "Orders",
        icon: "hero-shopping-bag",
        path: "/dashboard/orders",
        priority: 100
      },
      %{
        id: :settings,
        label: "Settings",
        icon: "hero-cog-6-tooth",
        path: "/dashboard/settings",
        priority: 900
      }
    ]

## Runtime Registration

Parent applications can register tabs at runtime:

    PhoenixKit.Dashboard.Registry.register(:my_app, [
      Tab.new!(id: :custom, label: "Custom", path: "/dashboard/custom", priority: 150)
    ])

## Groups

Tabs can be organized into groups:

    config :phoenix_kit, :user_dashboard_tab_groups, [
      %{id: :main, label: nil, priority: 100},
      %{id: :farm, label: "Farm Management", priority: 200, icon: "hero-cube"},
      %{id: :account, label: "Account", priority: 900}
    ]

Then assign tabs to groups:

    %{id: :printers, label: "Printers", path: "/dashboard/printers", group: :farm}

## PubSub Integration

The registry can broadcast tab updates:

    PhoenixKit.Dashboard.Registry.update_tab_badge(:notifications, Badge.count(5))

LiveViews subscribed to "phoenix_kit:dashboard:tabs" will receive updates.

# `broadcast_refresh`

```elixir
@spec broadcast_refresh() :: :ok
```

Broadcasts a full tab list refresh to all subscribers.

# `broadcast_update`

```elixir
@spec broadcast_update(PhoenixKit.Dashboard.Tab.t()) :: :ok
```

Broadcasts a tab update to all subscribers.

# `child_spec`

Returns a specification to start this module under a supervisor.

See `Supervisor`.

# `clear_tab_attention`

```elixir
@spec clear_tab_attention(atom()) :: :ok
```

Clears attention animation from a tab.

# `get_admin_tabs`

```elixir
@spec get_admin_tabs(keyword()) :: [PhoenixKit.Dashboard.Tab.t()]
```

Gets admin-level tabs, filtered by permission and module-enabled status.

## Options

- `:scope` - The current scope (for permission and visibility filtering)
- `:include_hidden` - Include tabs that would be hidden (default: false)

# `get_groups`

```elixir
@spec get_groups() :: [PhoenixKit.Dashboard.Group.t()]
```

Gets all registered groups, sorted by priority.

# `get_subtabs`

```elixir
@spec get_subtabs(
  atom(),
  keyword()
) :: [PhoenixKit.Dashboard.Tab.t()]
```

Gets all subtabs for a given parent tab ID.

## Examples

    Registry.get_subtabs(:orders)
    # => [%Tab{id: :pending_orders, parent: :orders, ...}, ...]

# `get_tab`

```elixir
@spec get_tab(atom()) :: PhoenixKit.Dashboard.Tab.t() | nil
```

Gets a specific tab by ID.

# `get_tabs`

```elixir
@spec get_tabs(keyword()) :: [PhoenixKit.Dashboard.Tab.t()]
```

Gets all registered tabs, sorted by priority.

## Options

- `:scope` - The current scope (for visibility filtering)
- `:level` - Filter by tab level: `:admin`, `:user`, or nil for all
- `:path` - The current path (for active state detection)
- `:include_hidden` - Include tabs that would be hidden (default: false)

## Examples

    Registry.get_tabs()
    Registry.get_tabs(scope: scope, level: :user)
    Registry.get_tabs(scope: scope, level: :admin)

# `get_tabs_in_group`

```elixir
@spec get_tabs_in_group(
  atom(),
  keyword()
) :: [PhoenixKit.Dashboard.Tab.t()]
```

Gets all tabs in a specific group.

# `get_tabs_with_active`

```elixir
@spec get_tabs_with_active(
  String.t(),
  keyword()
) :: [map()]
```

Gets all tabs with their active state for the given path.

Returns tabs with an additional `:active` key set based on path matching.

# `get_top_level_tabs`

```elixir
@spec get_top_level_tabs(keyword()) :: [PhoenixKit.Dashboard.Tab.t()]
```

Gets only top-level tabs (tabs without a parent).

## Options

Same as `get_tabs/1`.

## Examples

    Registry.get_top_level_tabs()
    # => [%Tab{id: :orders, parent: nil, ...}, ...]

# `get_user_tabs`

```elixir
@spec get_user_tabs(keyword()) :: [PhoenixKit.Dashboard.Tab.t()]
```

Gets user-level tabs.

## Options

- `:scope` - The current scope (for visibility filtering)
- `:include_hidden` - Include tabs that would be hidden (default: false)

# `has_subtabs?`

```elixir
@spec has_subtabs?(atom()) :: boolean()
```

Checks if a tab has any subtabs.

## Examples

    Registry.has_subtabs?(:orders)
    # => true

# `initialized?`

```elixir
@spec initialized?() :: boolean()
```

Checks if the registry has been initialized.

# `load_admin_defaults`

```elixir
@spec load_admin_defaults() :: :ok
```

Loads admin default tabs.

Called during initialization.

# `load_defaults`

```elixir
@spec load_defaults() :: :ok
```

Loads the default PhoenixKit tabs (Dashboard, Settings).

Called during initialization and can be used to reset to defaults.

# `load_from_config`

```elixir
@spec load_from_config() :: :ok
```

Loads tabs from application configuration.

Reads from `:phoenix_kit, :user_dashboard_tabs` config key.

# `pubsub_topic`

```elixir
@spec pubsub_topic() :: String.t()
```

Gets the PubSub topic for tab updates.

LiveViews can subscribe to this topic to receive real-time tab updates.

## Example

    def mount(_params, _session, socket) do
      if connected?(socket) do
        Phoenix.PubSub.subscribe(PubSubHelper.pubsub(), Registry.pubsub_topic())
      end
      {:ok, socket}
    end

    def handle_info({:tab_updated, tab}, socket) do
      # Handle tab update
      {:noreply, socket}
    end

# `register`

```elixir
@spec register(atom(), PhoenixKit.Dashboard.Tab.t() | [PhoenixKit.Dashboard.Tab.t()]) ::
  :ok
```

Registers tabs for an application namespace.

## Examples

    Registry.register(:my_app, [
      Tab.new!(id: :home, label: "Home", path: "/dashboard", icon: "hero-home"),
      Tab.new!(id: :orders, label: "Orders", path: "/dashboard/orders")
    ])

    # Register a single tab
    Registry.register(:my_app, Tab.new!(id: :settings, label: "Settings", path: "/dashboard/settings"))

# `register_from_config`

```elixir
@spec register_from_config(atom(), [map()] | [keyword()]) :: :ok | {:error, term()}
```

Registers tabs from a map/keyword configuration.

Useful for registering tabs from config files.

## Examples

    Registry.register_from_config(:my_app, [
      %{id: :home, label: "Home", path: "/dashboard", icon: "hero-home"},
      %{id: :orders, label: "Orders", path: "/dashboard/orders"}
    ])

# `register_groups`

```elixir
@spec register_groups([PhoenixKit.Dashboard.Group.t() | map()]) :: :ok
```

Registers tab groups.

## Examples

    Registry.register_groups([
      %{id: :main, label: nil, priority: 100},
      %{id: :farm, label: "Farm Management", priority: 200},
      %{id: :account, label: "Account", priority: 900}
    ])

# `set_tab_attention`

```elixir
@spec set_tab_attention(atom(), atom()) :: :ok
```

Sets an attention animation on a tab.

## Examples

    Registry.set_tab_attention(:alerts, :pulse)
    Registry.set_tab_attention(:notifications, :bounce)

# `start_link`

Starts the Registry GenServer.

This is typically called by the PhoenixKit supervisor.

# `unregister`

```elixir
@spec unregister(atom()) :: :ok
```

Unregisters all tabs for a namespace.

# `unregister_tab`

```elixir
@spec unregister_tab(atom()) :: :ok
```

Unregisters a specific tab by ID.

# `update_tab`

```elixir
@spec update_tab(atom(), map()) :: :ok
```

Updates an existing tab's attributes.

## Examples

    Registry.update_tab(:admin_dashboard, %{label: "Home", icon: "hero-house"})

# `update_tab_badge`

```elixir
@spec update_tab_badge(atom(), PhoenixKit.Dashboard.Badge.t() | map() | nil) :: :ok
```

Updates a tab's badge.

This broadcasts an update to all subscribed LiveViews.

## Examples

    Registry.update_tab_badge(:notifications, Badge.count(5))
    Registry.update_tab_badge(:printers, Badge.count(3, color: :warning))

---

*Consult [api-reference.md](api-reference.md) for complete listing*
