diff --git a/assets/app/styles/themes/dark.css b/assets/app/styles/themes/dark.css index 4957a6cf8..5ad888aa3 100644 --- a/assets/app/styles/themes/dark.css +++ b/assets/app/styles/themes/dark.css @@ -90,5 +90,9 @@ --diff-pulse-text: var(--gray-900); --diff-negative-bg: var(--red-900); --diff-positive-bg: rgb(from var(--swm-green-100) r g b / 0.3); + + --status-dot-success-bg: var(--swm-green-100); + --status-dot-warning-bg: var(--swm-yellow-100); + --status-dot-error-bg: var(--swm-pink-100); } } diff --git a/assets/app/styles/themes/light.css b/assets/app/styles/themes/light.css index 6a7aa49ef..62492ee2b 100644 --- a/assets/app/styles/themes/light.css +++ b/assets/app/styles/themes/light.css @@ -89,4 +89,8 @@ --diff-pulse-text: var(--slate-900); --diff-negative-bg: var(--red-300); --diff-positive-bg: var(--swm-green-60); + + --status-dot-success-bg: var(--swm-green-100); + --status-dot-warning-bg: var(--swm-yellow-100); + --status-dot-error-bg: var(--swm-pink-100); } diff --git a/assets/app/tailwind.config.js b/assets/app/tailwind.config.js index eb550b51d..0ddc8e2a8 100644 --- a/assets/app/tailwind.config.js +++ b/assets/app/tailwind.config.js @@ -69,6 +69,9 @@ module.exports = { 'diff-border': 'var(--diff-border)', 'diff-negative-bg': 'var(--diff-negative-bg)', 'diff-positive-bg': 'var(--diff-positive-bg)', + 'status-dot-success-bg': 'var(--status-dot-success-bg)', + 'status-dot-warning-bg': 'var(--status-dot-warning-bg)', + 'status-dot-error-bg': 'var(--status-dot-error-bg)', }, screens: { xs: '380px' }, fontFamily: { diff --git a/lib/live_debugger/app/debugger/node_state/web/components.ex b/lib/live_debugger/app/debugger/node_state/web/components.ex index 356811bdb..3ff5f98f6 100644 --- a/lib/live_debugger/app/debugger/node_state/web/components.ex +++ b/lib/live_debugger/app/debugger/node_state/web/components.ex @@ -33,6 +33,7 @@ defmodule LiveDebugger.App.Debugger.NodeState.Web.Components do attr(:assigns_sizes, AsyncResult, required: true) attr(:assigns_search_phrase, :string, default: "") attr(:pinned_assigns, :map, default: %{}) + attr(:node_assigns_status, :atom, required: true) def assigns_section(assigns) do opened_term_node = @@ -42,7 +43,11 @@ defmodule LiveDebugger.App.Debugger.NodeState.Web.Components do ~H"""
- <.section id="assigns" class="h-max overflow-y-hidden" title="Assigns" title_class="!min-w-14"> + <.section id="assigns" class="h-max overflow-y-hidden" title="Assigns" title_class="!min-w-18"> + <:title_sub_panel> + <.assigns_status_indicator node_assigns_status={@node_assigns_status} /> + + <:right_panel>
""" end + + attr(:node_assigns_status, :atom, required: true) + + defp assigns_status_indicator(assigns) do + assigns = assign(assigns, get_status_indicator_params(assigns.node_assigns_status)) + + ~H""" + <.status_dot status={@status} pulse?={@pulse?} tooltip={@tooltip} /> + """ + end + + defp get_status_indicator_params(:updating) do + [status: :warning, pulse?: true, tooltip: "Updating assigns..."] + end + + defp get_status_indicator_params(:loaded) do + [status: :success, pulse?: false, tooltip: "Assigns are up to date."] + end + + defp get_status_indicator_params(:error) do + [status: :error, pulse?: false, tooltip: "Error while fetching assigns."] + end + + defp get_status_indicator_params(:disconnected) do + [status: :error, pulse?: false, tooltip: "Disconnected from the LiveView process."] + end end diff --git a/lib/live_debugger/app/debugger/node_state/web/hooks/node_assigns.ex b/lib/live_debugger/app/debugger/node_state/web/hooks/node_assigns.ex index 8dfbdbd98..546a8c46f 100644 --- a/lib/live_debugger/app/debugger/node_state/web/hooks/node_assigns.ex +++ b/lib/live_debugger/app/debugger/node_state/web/hooks/node_assigns.ex @@ -30,8 +30,8 @@ defmodule LiveDebugger.App.Debugger.NodeState.Web.Hooks.NodeAssigns do |> attach_hook(:node_assigns, :handle_async, &handle_async/3) |> attach_hook(:node_assigns, :handle_event, &handle_event/3) |> register_hook(:node_assigns) - |> assign(:node_assigns_info, AsyncResult.loading()) - |> assign(:assigns_sizes, AsyncResult.loading()) + |> assign(:node_assigns_info, AsyncResult.loading(stage: :init)) + |> assign(:assigns_sizes, AsyncResult.loading(stage: :init)) |> assign(:pinned_assigns, %{}) |> put_private(:pulse_cleared?, true) |> assign_async_node_assigns() @@ -55,16 +55,16 @@ defmodule LiveDebugger.App.Debugger.NodeState.Web.Hooks.NodeAssigns do when not is_nil(node_id) do node_assigns_info = if Keyword.get(opts, :reset, false) do - AsyncResult.loading() + AsyncResult.loading(stage: :initial) else - socket.assigns.node_assigns_info + AsyncResult.loading(socket.assigns.node_assigns_info, stage: :update) end assigns_sizes = if Keyword.get(opts, :reset, false) do - AsyncResult.loading() + AsyncResult.loading(stage: :initial) else - socket.assigns.assigns_sizes + AsyncResult.loading(socket.assigns.assigns_sizes, stage: :update) end socket diff --git a/lib/live_debugger/app/debugger/node_state/web/node_state_live.ex b/lib/live_debugger/app/debugger/node_state/web/node_state_live.ex index 844096e6f..37558f20e 100644 --- a/lib/live_debugger/app/debugger/node_state/web/node_state_live.ex +++ b/lib/live_debugger/app/debugger/node_state/web/node_state_live.ex @@ -13,8 +13,11 @@ defmodule LiveDebugger.App.Debugger.NodeState.Web.NodeStateLive do alias LiveDebugger.Bus alias LiveDebugger.App.Debugger.Events.NodeIdParamChanged + alias LiveDebugger.App.Debugger.Events.DeadViewModeEntered alias LiveDebugger.Services.CallbackTracer.Events.StateChanged + alias Phoenix.LiveView.AsyncResult + @doc """ Renders the `NodeStateLive` as a nested LiveView component. @@ -89,6 +92,7 @@ defmodule LiveDebugger.App.Debugger.NodeState.Web.NodeStateLive do assigns_sizes={@assigns_sizes} pinned_assigns={@pinned_assigns} assigns_search_phrase={@assigns_search_phrase} + node_assigns_status={assigns_status(@lv_process, @node_assigns_info)} /> noreply() end + def handle_info(%DeadViewModeEntered{}, socket) do + socket + |> assign(:lv_process, LvProcess.set_alive(socket.assigns.lv_process, false)) + |> noreply() + end + def handle_info(_, socket), do: {:noreply, socket} + + defp assigns_status(%LvProcess{alive?: false}, _), do: :disconnected + defp assigns_status(_, %AsyncResult{loading: [stage: :update]}), do: :updating + defp assigns_status(_, %AsyncResult{ok?: true}), do: :loaded + defp assigns_status(_, _), do: :error end diff --git a/lib/live_debugger/app/web/components.ex b/lib/live_debugger/app/web/components.ex index cc6618df2..8186e7581 100644 --- a/lib/live_debugger/app/web/components.ex +++ b/lib/live_debugger/app/web/components.ex @@ -292,6 +292,7 @@ defmodule LiveDebugger.App.Web.Components do attr(:inner_class, :any, default: nil) slot(:right_panel) + slot(:title_sub_panel) slot(:inner_block) def section(assigns) do @@ -305,7 +306,13 @@ defmodule LiveDebugger.App.Web.Components do >
-
<%= @title %>
+
+

<%= @title %>

+ <%= render_slot(@title_sub_panel) %> +
<%= render_slot(@right_panel) %>
@@ -624,6 +631,36 @@ defmodule LiveDebugger.App.Web.Components do """ end + @doc """ + Renders a status dot with a tooltip. + """ + + attr(:status, :atom, required: true) + attr(:pulse?, :boolean, default: false) + attr(:tooltip, :string, required: true) + + def status_dot(assigns) do + assigns = + case assigns.status do + :success -> assign(assigns, :bg_class, "bg-status-dot-success-bg") + :warning -> assign(assigns, :bg_class, "bg-status-dot-warning-bg") + :error -> assign(assigns, :bg_class, "bg-status-dot-error-bg") + end + + ~H""" + <.tooltip id="loading-dot-tooltip" content={@tooltip}> + + + + + + + """ + end + @doc """ Renders a tooltip using Tooltip hook. """