View Source README

test Hex.pm

Luminous

Luminous is a framework for creating dashboards within Phoenix Live View.

Dashboards are defined by the client application (framework consumer) using elixir code and consist of Panels (Luminous.Panel) which are responsible for visualizing the results of multiple client-side queries (Luminous.Query).

Three different types of Panels are currently offered out of the box by Luminous:

A client application can implement its own custom panels by implementing the Luminous.Panel behaviour.

Dashboards are parameterized by:

All panels are refreshed whenever at least one of these paramaters (date range, variables) change. The parameter values are available to client-side queries.

features

Features

  • Date range selection and automatic asynchronous (i.e. non-blocking for the UI) refresh of all dashboard panel queries
  • User-facing variable dropdowns (with single- or multi- selection) whose selected values are available to panel queries
  • Client-side zoom in charts with automatic update of the entire dashboard with the new date range
  • Panel data downloads depending on the panel type (CSV, PNG)
  • Stat panels (show single or multiple stats)
  • Table panels using tabulator
  • Summary statistics in charts

installation

Installation

The package can be installed from hex.pm as follows:

def deps do
  [
    {:luminous, "~> 2.6.1"}
  ]
end

In order to be able to use the provided components, the library's javascript and CSS files must be imported to your project:

In assets/js/app.js:

import { ChartJSHook, TableHook, TimeRangeHook, MultiSelectVariableHook } from "luminous"

let Hooks = {
  TimeRangeHook: new TimeRangeHook(),
  ChartJSHook: new ChartJSHook(),
  TableHook: new TableHook(),
  MultiSelectVariableHook: new MultiSelectVariableHook()
}

...

let liveSocket = new LiveSocket("/live", Socket, {
  ...
  hooks: Hooks
})
...

Finally, in assets/css/app.css:

@import "../../deps/luminous/dist/luminous.css";

usage

Usage

live-view

Live View

The dashboard live view is defined client-side like so:

defmodule ClientApp.DashboardLive do
  alias ClientApp.Router.Helpers, as: Routes

  use Luminous.Live,
    title: "My Title",
    time_zone: "Europe/Paris",
    panels: [
      ...
    ],
    variables: [
      ...
    ]

  # the dashboard can be rendered by leveraging the corresponding functionality
  # from `Luminous.Components`
  def render(assigns) do
    ~H"""
    <Luminous.Components.dashboard dashboard={@dashboard} />
    """
  end

  # we also need to implement the function that generates the LV path
  @impl Luminous.Dashboard
  def dashboard_path(socket, url_params) do
    Routes.dashboard_path(socket, :index, url_params)
  end
end

The client-side dashboard can also (optionally) implement the Luminous.TimeRange behaviour in order to override the dashboard's default time range value which is "today".

panels-and-queries

Panels and Queries

Client-side queries must be included in a module that implements the Luminous.Query behaviour:

defmodule ClientApp.DashboardLive do

  defmodule Queries do
    @behaviour Luminous.Query

    @impl true
    def query(:my_query, _time_range, _variables) do
      [
        [{:time, ~U[2022-08-19T10:00:00Z]}, {"foo", 10}, {"bar", 100}],
        [{:time, ~U[2022-08-19T11:00:00Z]}, {"foo", 11}, {"bar", 101}]
      ]
    end
  end

  use Luminous.Live,
    ...
    panels: [
      Panel.define!(
        type: Luminous.Panel.Chart,
        id: :simple_time_series,
        title: "Simple Time Series",
        queries: [
          Luminous.Query.define(:my_query, Queries)
        ],
        description: """
        This will be rendered as a tooltip
        when hovering over the panel's title
        """
      ),
    ],
    ...
end

A panel may include multiple queries. When a panel is automatically refreshed, the execution flow is as follows:

  • for each query:
    • execute the user query callback
    • execute the panel's transform/2 callback with the query result output
  • aggregate the transformed query results
  • update the dashboard state variable with the panel's data (possible server-side re-rendering)
  • send a JS event to the browser (for panel hooks)

The above flow needs to be understood when implementing custom panels. If the client application uses the panels provided by luminous, then the panel refresh flow is handled automatically and only use Luminous.Live with the appropriate options is necessary.

variables

Variables

Variables represent user-facing elements in the form of dropdowns in which the user can select single (variable type: :single) or multiple (variable type: :multi) values.

Variable selections trigger the refresh of all panels in the dashboard. The state of all variables is available within the query callback that is implemented by the client application.

Just like queries, variables must be included in a module that implements the Luminous.Variable behaviour:

defmodule ClientApp.DashboardLive do

  defmodule Variables do
    @behaviour Luminous.Variable

    @impl true
    def variable(:simple_var, _assigns), do: ["hour", "day", "week"]

    def variable(:descriptive_var, _assigns) do
      [
        %{label: "Visible Value 1", value: "val1"},
        %{label: "Visible Value 2", value: "val2"},
      ]
    end
  end

  use Luminous.Live,
    ...
    variables: [
      Luminous.Variable.define!(id: :simple_var, label: "Select one value", module: Variables),
      Luminous.Variable.define!(id: :descriptive_var, label: "Select one value", module: Variables),
    ],
    ...
end

The variable callback will receive the live view socket assigns as the second argument, however it is important to note that the variable/2 callback is executed once when the dashboard is loaded for populating the dropdown values.

A Variable can be marked as hidden by passing hidden: true to Variable.define!/1. Hidden variables are a means for framework clients to store some kind of state expecially in the case of custom Panels (a typical use case is pagination). As such, hidden variables are not rendered as dropdowns in the dashboard and are not included in URL params.

demo

Demo

Luminous provides a demo dashboard that showcases some of Luminous' capabilities. The demo dashboard can be inspected live using the project's development server (run mix run in the project and then visit this page).