defmodule LiveDebuggerWeb.LiveViewsDashboardLive do @moduledoc """ It displays all active LiveView sessions in the debugged application. """ use LiveDebuggerWeb, :live_view alias Phoenix.LiveView.AsyncResult alias LiveDebugger.Services.LiveViewDiscoveryService alias LiveDebugger.Utils.Parsers alias LiveDebuggerWeb.Helpers.RoutesHelper @impl true def handle_params(_unsigned_params, _uri, socket) do socket |> assign_async_grouped_lv_processes() |> noreply() end @impl true def render(assigns) do ~H"""
<.navbar return_link?={false} />
<.h1>Active LiveViews <.button phx-click="refresh">
<.icon name="icon-refresh" class="w-4 h-4" />

Refresh

<.async_result :let={grouped_lv_processes} assign={@grouped_lv_processes}> <:loading>
<.spinner size="md" />
<:failed> <.alert variant="danger" with_icon heading="Error fetching active LiveViews"> Check logs for more
<%= if Enum.empty?(grouped_lv_processes) do %>

No active LiveViews

<% else %> <.tab_group :for={{transport_pid, grouped_lv_processes} <- grouped_lv_processes} transport_pid={transport_pid} grouped_lv_processes={grouped_lv_processes} /> <% end %>
""" end @impl true def handle_event("refresh", _params, socket) do socket |> assign(:grouped_lv_processes, AsyncResult.loading()) |> assign_async_grouped_lv_processes() |> noreply() end attr(:transport_pid, :any, required: true) attr(:grouped_lv_processes, :list, required: true) defp tab_group(assigns) do ~H"""

<%= Parsers.pid_to_string(@transport_pid) %>

<.list elements={@grouped_lv_processes}> <:item :let={{root_lv_process, lv_processes}}>
<.list_element lv_process={root_lv_process} />
<.list elements={lv_processes} item_class="group"> <:item :let={lv_process}>
<.nested_indent /> <.list_element lv_process={lv_process} />
""" end defp nested_indent(assigns) do ~H"""
""" end attr(:lv_process, LiveDebugger.Structs.LvProcess, required: true) defp list_element(assigns) do ~H""" <.link navigate={RoutesHelper.channel_dashboard(@lv_process.socket_id, @lv_process.transport_pid)} class="flex justify-between items-center h-full w-full text-xs p-1.5 hover:bg-surface-0-bg-hover rounded-sm" >

<%= Parsers.pid_to_string(@lv_process.pid) %> · <%= @lv_process.socket_id %>

<.badge :if={@lv_process.embedded? and not @lv_process.nested?} text="Embedded" icon="icon-code" />
""" end defp assign_async_grouped_lv_processes(socket) do assign_async(socket, :grouped_lv_processes, fn -> lv_processes = with [] <- fetch_lv_processes_after(200), [] <- fetch_lv_processes_after(800) do fetch_lv_processes_after(1000) end {:ok, %{grouped_lv_processes: LiveViewDiscoveryService.group_lv_processes(lv_processes)}} end) end defp fetch_lv_processes_after(milliseconds) do Process.sleep(milliseconds) LiveViewDiscoveryService.debugged_lv_processes() end end