PhoenixKitDashboards.Widget (PhoenixKitDashboards v0.1.0)

Copy Markdown View Source

A widget type — the catalog entry that describes a kind of widget that can be placed on a dashboard.

Widgets come from two places:

  1. Built-in widgets shipped by this module (note, clock, module-stats…).
  2. Provider widgets contributed by any other PhoenixKit module.

The provider contract (decoupled by design)

A provider module exposes widgets by defining a zero-arity phoenix_kit_widgets/0 that returns a list of plain maps. It does NOT depend on phoenix_kit_dashboards at all — the dashboards module normalizes the maps into %Widget{} structs via from_map/2. This keeps the dependency arrow pointing one way: data modules know nothing about dashboards.

# in phoenix_kit_emails.ex
def phoenix_kit_widgets do
  [
    %{
      key: "emails.deliverability",
      name: "Deliverability",
      description: "Bounce / complaint rates over time",
      icon: "hero-envelope",
      module_key: "emails",
      component: PhoenixKitEmails.Widgets.DeliverabilityLive,
      default_size: %{w: 6, h: 2},
      min_size: %{w: 3, h: 1},
      settings_schema: [
        %{key: "window", type: :select, label: "Window",
          options: ["7d", "30d", "90d"], default: "30d"}
      ]
    }
  ]
end

:component is a Phoenix.LiveComponent module. The dashboard host renders it with <.live_component module={w.component} id={instance_id} settings={...} view={...} size={%{w: w, h: h}} scope={...} /> — the selected view key and the instance's current span ride along, so one widget can render several densities/layouts. Each widget owns its own data loading and refresh lifecycle.

Settings schema

Each field map drives one input in the generated per-widget settings form:

%{key: "window", type: :select, label: "Window",
  options: ["7d", "30d", "90d"], default: "30d"}

Supported :type values: :string, :text, :number, :boolean, :select. Select options may be plain strings or {label, value} tuples (the label is translated at render when a translation exists).

Summary

Functions

Default settings map derived from a widget type's settings_schema.

The default view key for a widget type: the first declared view, or nil when the widget has a single intrinsic view.

Normalize a provider-supplied plain map into a %Widget{}.

The minimum size for an instance showing view_key — the view's own min_size when it declares one (an analog clock needs more room than a text one), else the widget type's. nil resolves through the default view, so instances created before a widget declared views get the right floor too.

Types

settings_field()

@type settings_field() :: %{
  :key => String.t(),
  :type => :string | :text | :number | :boolean | :select,
  optional(:label) => String.t(),
  optional(:options) => [String.t() | {String.t(), String.t()}],
  optional(:default) => term()
}

size()

@type size() :: %{w: pos_integer(), h: pos_integer()}

t()

@type t() :: %PhoenixKitDashboards.Widget{
  category: String.t(),
  component: module(),
  default_size: size(),
  description: String.t() | nil,
  icon: String.t(),
  key: String.t(),
  max_size: size(),
  min_size: size(),
  module_key: String.t() | nil,
  name: String.t(),
  refresh_interval: pos_integer() | nil,
  settings_schema: [settings_field()],
  source: module() | nil,
  views: [view()]
}

view()

@type view() :: %{
  :key => String.t(),
  :name => String.t(),
  optional(:min_size) => size()
}

Functions

default_settings(widget)

@spec default_settings(t()) :: map()

Default settings map derived from a widget type's settings_schema.

default_view(widget)

@spec default_view(t()) :: String.t() | nil

The default view key for a widget type: the first declared view, or nil when the widget has a single intrinsic view.

from_map(map, source)

@spec from_map(term(), source :: module()) :: {:ok, t()} | {:error, term()}

Normalize a provider-supplied plain map into a %Widget{}.

Returns {:ok, widget} or {:error, reason}. Invalid widgets are dropped by the registry (and logged) rather than crashing discovery.

min_size_for(widget, view_key)

@spec min_size_for(t(), String.t() | nil) :: size()

The minimum size for an instance showing view_key — the view's own min_size when it declares one (an analog clock needs more room than a text one), else the widget type's. nil resolves through the default view, so instances created before a widget declared views get the right floor too.