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.
"""