Get More from Phoenix LiveDashboard with the Built-In PageBuilder

An angled view of a classic car dashboard

Phoenix LiveDashboard is a powerful tool within the Phoenix framework for real-time monitoring and debugging of applications. It provides developers with a visual interface to track various aspects of their Phoenix applications’ performance, such as CPU and memory usage, request logging, running processes, and application metrics.

LiveDashboard offers a handful of modules, each providing valuable insights into different facets of the application’s behavior. With LiveDashboard, developers can identify performance bottlenecks, troubleshoot issues, and optimize their applications in real time.

This post will explore the built-in Page Builder feature of LiveDashboard so that you can extend the functionality of the LiveDashboard and build your own custom pages by using a Pokédex (digital encyclopedia in the Pokémon series that provides information about different Pokémon species) as an example.

What is the PageBuilder?

The PageBuilder is a built-in module that specifically provides functionality for dynamically building and customizing monitoring dashboard pages within the LiveDashboard interface. Developers can use this module to create custom monitoring pages tailored to their specific needs, adding and arranging widgets, charts, and other elements to visualize key metrics and data relevant to their application.

In essence, the PageBuilder module empowers developers to create personalized and informative monitoring dashboards within the LiveDashboard environment, enhancing their ability to monitor and optimize the performance of their Phoenix applications.

Popular libraries such as flame_on and ecsx make use of the PageBuilder to provide additional insights into the LiveDashboard. Let’s walk through on how to extend the LiveDashboard using the PageBuilder module for our own Phoenix apps or libraries:

Creating a Custom Pokédex Page Example

First of all, make sure to properly install LiveDashboard in your Phoenix environment. With the LiveDashboard set, we can now create a module for our dashboard. Our goal will be to have a dedicated tab right next to the included ETS page:

Imgur

For our custom module, we are going to start with a regular LiveView module with some callbacks. The menu_link/2 callback will return the text that our tab will render and the mount/3 callback will serve as our usual LiveView entry point:

defmodule MyAppWeb.Pokemon do
  @moduledoc false
  use Phoenix.LiveDashboard.PageBuilder

  @impl true
  def menu_link(_, _) do
    {:ok, "Pokédex"}
  end

  @impl true
  def mount(_params, _session, socket) do
    pokemon = fetch_random_pokemon()

    {:ok, assign(socket, pokemon: pokemon)}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <.row>
      <:col>
        <.card title={"#{@pokemon.name} ##{@pokemon.id}"} hint="Gotta catch 'em all!">
          <img src={@pokemon.image} alt={@pokemon.name} />
        </.card>
      </:col>
      <:col>
        <.row>
          <:col>
            <.card title="Weight (hg)">
              <%= @pokemon.weight %>
            </.card>
          </:col>
          <:col>
            <.card title="Height (dm)">
              <%= @pokemon.height %>
            </.card>
          </:col>
          <:col>
            <.card title="Base XP">
              <%= @pokemon.base_xp %>
            </.card>
          </:col>
        </.row>
        <.row>
          <:col>
            <.fields_card title="Types" fields={@pokemon.types} />
          </:col>
        </.row>

        <.row>
          <:col>
            <.card_title title="Game Sprites" />
          </:col>
        </.row>
        <.row>
          <:col>
            <.card>
              <img src={@pokemon.sprites["front_default"]} />
            </.card>
          </:col>
          <:col>
            <.card>
              <img src={@pokemon.sprites["front_shiny"]} />
            </.card>
          </:col>
        </.row>
      </:col>
    </.row>
    """
  end

  defp fetch_random_pokemon do
    body = Req.get!("https://pokeapi.co/api/v2/pokemon/#{Enum.random(1..1010)}").body

    %{
      name: String.capitalize(body["name"]),
      id: body["id"],
      weight: body["weight"],
      height: body["height"],
      base_xp: body["base_experience"] || "?",
      types: list_types(body["types"]),
      image: body["sprites"]["other"]["official-artwork"]["front_default"],
      sprites: body["sprites"]
    }
  end

  defp list_types(types),
    do: Enum.map(types, fn %{"type" => %{"name" => name}} -> {nil, name} end)
end

Once we have our module ready, we need to define the route within the dashboard from our router module:

live_dashboard "/dashboard",
  additional_pages: [
    route_name: MyAppWeb.Pokemon
  ]

And that should be everything needed to render a custom tab within the LiveDashboard using the PageBuilder module, you may now explore the new tab by visiting http://localhost:4000/dev/dashboard. One important detail to be aware of is the fact that the PageBuilder offers some default components that we can conveniently use for building pages.

With all the pieces in place, we may have a page like the following (for more information visit the repo here):

Imgur

Conclusion

The LiveDashboard was a needed addition to the Phoenix Framework, developers can now monitor many aspects of the application and also allocate data that is of common knowledge to the engineering team. With the PageBuilder we can keep leveraging the use of a centralized monitoring system with the convenience of having prebuilt components for designing, thus offering extensive possibilities in terms of information allocation.

Newsletter

Stay in the Know

Get the latest news and insights on Elixir, Phoenix, machine learning, product strategy, and more—delivered straight to your inbox.

Narwin holding a press release sheet while opening the DockYard brand kit box