Service functions for managing dashboards in Lotus.
Provides CRUD operations for dashboards, cards, filters, and filter mappings, as well as execution functions for running all cards in a dashboard.
Dashboard Structure
Dashboards contain:
- Cards - Query results, text, links, or headings arranged in a 12-column grid
- Filters - User inputs that control query variables across multiple cards
- Filter Mappings - Connections between dashboard filters and card query variables
Execution
Use run_dashboard/2 to execute all query cards in a dashboard simultaneously.
Filter values are resolved and passed to each card's query variables via the
configured mappings.
Summary
Functions
Creates a new dashboard.
Creates a new card for a dashboard.
Creates a new filter for a dashboard.
Creates a filter mapping connecting a dashboard filter to a card's query variable.
Deletes a dashboard.
Deletes a card.
Deletes a filter.
Deletes a filter mapping.
Disables public sharing for a dashboard by removing its token.
Enables public sharing for a dashboard by generating a unique token.
Gets a single dashboard by ID.
Gets a single dashboard by ID.
Gets a dashboard by its public sharing token.
Gets a single card by ID.
Gets a single card by ID.
Gets a single filter by ID.
Gets a single filter by ID.
Lists all filter mappings for a card.
Lists all cards for a dashboard.
Lists all filters for a dashboard.
Lists all dashboards.
Lists dashboards with optional filtering.
Reorders cards in a dashboard.
Runs all query cards in a dashboard and returns their results.
Runs a single dashboard card and returns its result.
Updates a dashboard.
Updates a card.
Updates a filter.
Types
Functions
@spec create_dashboard(attrs()) :: {:ok, Lotus.Storage.Dashboard.t()} | {:error, Ecto.Changeset.t()}
Creates a new dashboard.
Examples
iex> create_dashboard(%{name: "Sales Dashboard"})
{:ok, %Dashboard{}}
iex> create_dashboard(%{})
{:error, %Ecto.Changeset{}}
@spec create_dashboard_card(Lotus.Storage.Dashboard.t() | id(), attrs()) :: {:ok, Lotus.Storage.DashboardCard.t()} | {:error, Ecto.Changeset.t()}
Creates a new card for a dashboard.
Examples
iex> create_dashboard_card(dashboard, %{
...> card_type: :query,
...> query_id: 123,
...> position: 0,
...> layout: %{x: 0, y: 0, w: 6, h: 4}
...> })
{:ok, %DashboardCard{}}
@spec create_dashboard_filter(Lotus.Storage.Dashboard.t() | id(), attrs()) :: {:ok, Lotus.Storage.DashboardFilter.t()} | {:error, Ecto.Changeset.t()}
Creates a new filter for a dashboard.
Examples
iex> create_dashboard_filter(dashboard, %{
...> name: "date_range",
...> label: "Date Range",
...> filter_type: :date_range,
...> widget: :date_range_picker,
...> position: 0
...> })
{:ok, %DashboardFilter{}}
@spec create_filter_mapping( Lotus.Storage.DashboardCard.t() | id(), Lotus.Storage.DashboardFilter.t() | id(), String.t(), keyword() ) :: {:ok, Lotus.Storage.DashboardCardFilterMapping.t()} | {:error, Ecto.Changeset.t()}
Creates a filter mapping connecting a dashboard filter to a card's query variable.
Options
:transform- Optional transformation config for the filter value
Examples
iex> create_filter_mapping(card, filter, "start_date")
{:ok, %DashboardCardFilterMapping{}}
iex> create_filter_mapping(card, filter, "end_date", transform: %{type: "date_range_end"})
{:ok, %DashboardCardFilterMapping{}}
@spec delete_dashboard(Lotus.Storage.Dashboard.t()) :: {:ok, Lotus.Storage.Dashboard.t()} | {:error, Ecto.Changeset.t()}
Deletes a dashboard.
Also deletes all associated cards, filters, and filter mappings.
Examples
iex> delete_dashboard(dashboard)
{:ok, %Dashboard{}}
@spec delete_dashboard_card(Lotus.Storage.DashboardCard.t() | id()) :: {:ok, Lotus.Storage.DashboardCard.t()} | {:error, Ecto.Changeset.t() | :not_found}
Deletes a card.
Also deletes all associated filter mappings.
@spec delete_dashboard_filter(Lotus.Storage.DashboardFilter.t() | id()) :: {:ok, Lotus.Storage.DashboardFilter.t()} | {:error, Ecto.Changeset.t() | :not_found}
Deletes a filter.
Also deletes all associated filter mappings.
@spec delete_filter_mapping(Lotus.Storage.DashboardCardFilterMapping.t() | id()) :: {:ok, Lotus.Storage.DashboardCardFilterMapping.t()} | {:error, Ecto.Changeset.t() | :not_found}
Deletes a filter mapping.
@spec disable_public_sharing(Lotus.Storage.Dashboard.t()) :: {:ok, Lotus.Storage.Dashboard.t()} | {:error, Ecto.Changeset.t()}
Disables public sharing for a dashboard by removing its token.
Examples
iex> disable_public_sharing(dashboard)
{:ok, %Dashboard{public_token: nil}}
@spec enable_public_sharing(Lotus.Storage.Dashboard.t()) :: {:ok, Lotus.Storage.Dashboard.t()} | {:error, Ecto.Changeset.t()}
Enables public sharing for a dashboard by generating a unique token.
The token can be used to access the dashboard without authentication
via get_dashboard_by_token/1.
Examples
iex> enable_public_sharing(dashboard)
{:ok, %Dashboard{public_token: "abc123..."}}
@spec get_dashboard(id()) :: Lotus.Storage.Dashboard.t() | nil
Gets a single dashboard by ID.
Returns nil if the dashboard does not exist.
@spec get_dashboard!(id()) :: Lotus.Storage.Dashboard.t() | no_return()
Gets a single dashboard by ID.
Raises Ecto.NoResultsError if the dashboard does not exist.
@spec get_dashboard_by_token(String.t()) :: Lotus.Storage.Dashboard.t() | nil
Gets a dashboard by its public sharing token.
Returns nil if no dashboard has the given token.
@spec get_dashboard_card( id(), keyword() ) :: Lotus.Storage.DashboardCard.t() | nil
Gets a single card by ID.
Returns nil if the card does not exist.
Options
:preload- A list of associations to preload
@spec get_dashboard_card!( id(), keyword() ) :: Lotus.Storage.DashboardCard.t() | no_return()
Gets a single card by ID.
Raises Ecto.NoResultsError if the card does not exist.
Options
:preload- A list of associations to preload
@spec get_dashboard_filter(id()) :: Lotus.Storage.DashboardFilter.t() | nil
Gets a single filter by ID.
Returns nil if the filter does not exist.
@spec get_dashboard_filter!(id()) :: Lotus.Storage.DashboardFilter.t() | no_return()
Gets a single filter by ID.
Raises Ecto.NoResultsError if the filter does not exist.
@spec list_card_filter_mappings(Lotus.Storage.DashboardCard.t() | id()) :: [ Lotus.Storage.DashboardCardFilterMapping.t() ]
Lists all filter mappings for a card.
@spec list_dashboard_cards( Lotus.Storage.Dashboard.t() | id(), keyword() ) :: [Lotus.Storage.DashboardCard.t()]
Lists all cards for a dashboard.
Returns cards ordered by position, then by id.
Options
:preload- A list of associations to preload (e.g.,[:query, :filter_mappings])
Examples
iex> list_dashboard_cards(dashboard)
[%DashboardCard{}, ...]
iex> list_dashboard_cards(dashboard_id, preload: [:query, :filter_mappings])
[%DashboardCard{query: %Query{}, filter_mappings: [...]}, ...]
@spec list_dashboard_filters(Lotus.Storage.Dashboard.t() | id()) :: [ Lotus.Storage.DashboardFilter.t() ]
Lists all filters for a dashboard.
Returns filters ordered by position, then by id.
@spec list_dashboards() :: [Lotus.Storage.Dashboard.t()]
Lists all dashboards.
Returns dashboards ordered by name.
@spec list_dashboards_by(keyword()) :: [Lotus.Storage.Dashboard.t()]
Lists dashboards with optional filtering.
Options
:search- Search term to match against dashboard names (case insensitive)
Examples
iex> list_dashboards_by(search: "sales")
[%Dashboard{name: "Sales Overview"}, ...]
@spec reorder_dashboard_cards(Lotus.Storage.Dashboard.t() | id(), [id()]) :: :ok
Reorders cards in a dashboard.
Accepts a list of card IDs in the desired order. Each card's position will be updated to match its index in the list.
Examples
iex> reorder_dashboard_cards(dashboard, [card3_id, card1_id, card2_id])
:ok
@spec run_dashboard( Lotus.Storage.Dashboard.t() | id(), keyword() ) :: %{required(id()) => {:ok, Lotus.Result.t()} | {:error, term()}}
Runs all query cards in a dashboard and returns their results.
Returns a map of card IDs to their results. By default, cards are executed in parallel for better performance.
Options
:filter_values- Map of filter names to their current values:parallel- Whether to run cards in parallel (default: true):timeout- Timeout per card in milliseconds (default: 30000)
Filter Resolution
Filter values are resolved to query variables through the configured mappings. For each card:
- Get all filter mappings for the card
- For each mapping, get the filter value from
:filter_values - Apply any configured transform to the value
- Pass the value to the query as the mapped variable name
Examples
iex> run_dashboard(dashboard, filter_values: %{"date_range" => "2024-01-01"})
%{
1 => {:ok, %Lotus.Result{}},
2 => {:ok, %Lotus.Result{}},
3 => {:error, "Missing required variable: status"}
}
@spec run_dashboard_card( Lotus.Storage.DashboardCard.t() | id(), keyword() ) :: {:ok, Lotus.Result.t()} | {:error, term()}
Runs a single dashboard card and returns its result.
Options
:filter_values- Map of filter names to their current values:timeout- Query timeout in milliseconds
Examples
iex> run_dashboard_card(card, filter_values: %{"user_id" => "123"})
{:ok, %Lotus.Result{}}
@spec update_dashboard(Lotus.Storage.Dashboard.t(), attrs()) :: {:ok, Lotus.Storage.Dashboard.t()} | {:error, Ecto.Changeset.t()}
Updates a dashboard.
Examples
iex> update_dashboard(dashboard, %{name: "New Name"})
{:ok, %Dashboard{}}
@spec update_dashboard_card(Lotus.Storage.DashboardCard.t(), attrs()) :: {:ok, Lotus.Storage.DashboardCard.t()} | {:error, Ecto.Changeset.t()}
Updates a card.
Examples
iex> update_dashboard_card(card, %{title: "Revenue Chart"})
{:ok, %DashboardCard{}}
@spec update_dashboard_filter(Lotus.Storage.DashboardFilter.t(), attrs()) :: {:ok, Lotus.Storage.DashboardFilter.t()} | {:error, Ecto.Changeset.t()}
Updates a filter.
Examples
iex> update_dashboard_filter(filter, %{label: "Select Period"})
{:ok, %DashboardFilter{}}