Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions assets/app/icons/triangle-alert.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion assets/app/styles/themes/dark.css
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@
--info-text: var(--primary-text);

/* Warning */
--warning-text: var(--swm-yellow-60);
--warning-bg: var(--surface-0-bg);
--warning-border: var(--swm-yellow-40);
--warning-text: var(--primary-text);

--search-highlight-bg: var(--swm-yellow-100);
--search-highlight-text: var(--gray-900);
Expand Down
4 changes: 3 additions & 1 deletion assets/app/styles/themes/light.css
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@
--info-text: var(--primary-text);

/* Warning */
--warning-text: #e6bf00;
--warning-bg: var(--swm-yellow-20);
--warning-border: var(--swm-yellow-40);
--warning-text: var(--primary-text);

--search-highlight-bg: var(--swm-yellow-80);
--search-highlight-text: var(--slate-900);
Expand Down
3 changes: 3 additions & 0 deletions assets/app/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ module.exports = {
'info-border': 'var(--info-border)',
'info-icon': 'var(--info-icon)',
'info-text': 'var(--info-text)',
'warning-bg': 'var(--warning-bg)',
'warning-border': 'var(--warning-border)',
'warning-text': 'var(--warning-text)',
'diff-border': 'var(--diff-border)',
'diff-negative-bg': 'var(--diff-negative-bg)',
'diff-positive-bg': 'var(--diff-positive-bg)',
Expand Down
1 change: 1 addition & 0 deletions lib/live_debugger/app/debugger/web/debugger_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ defmodule LiveDebugger.App.Debugger.Web.DebuggerLive do
<Navbar.live_debugger_logo_icon />
<HookComponents.DeadViewMode.render id="navbar-connected" lv_process={lv_process} />
<div class="flex items-center gap-2">
<Navbar.garbage_collection_warning />
<HookComponents.InspectButton.render
inspect_mode?={@inspect_mode?}
lv_process={lv_process}
Expand Down
25 changes: 9 additions & 16 deletions lib/live_debugger/app/discovery/queries.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,40 @@ defmodule LiveDebugger.App.Discovery.Queries do
alias LiveDebugger.API.LiveViewDiscovery
alias LiveDebugger.Structs.LvProcess

@type grouped_lv_processes() :: %{pid() => %{LvProcess.t() => [LvProcess.t()]}}

@doc """
Fetches all active LiveView processes grouped by their transport PID.
Performs delayed fetching to ensure processes are captured.
"""
@spec fetch_grouped_lv_processes(transport_pid :: pid() | nil) ::
{:ok,
%{
grouped_lv_processes: %{
pid() => %{LvProcess.t() => [LvProcess.t()]}
}
}}
{grouped_lv_processes :: grouped_lv_processes(),
lv_processes_count :: non_neg_integer()}
def fetch_grouped_lv_processes(transport_pid \\ nil) do
lv_processes =
with [] <- fetch_lv_processes_after(200, transport_pid),
[] <- fetch_lv_processes_after(800, transport_pid) do
fetch_lv_processes_after(1000, transport_pid)
end

{:ok, %{grouped_lv_processes: LiveViewDiscovery.group_lv_processes(lv_processes)}}
{LiveViewDiscovery.group_lv_processes(lv_processes), length(lv_processes)}
end

@doc """
Fetches all dead LiveView processes grouped by their transport PID.
Retrieves states from storage and checks for process aliveness.
"""
@spec fetch_dead_grouped_lv_processes() ::
{:ok,
%{
dead_grouped_lv_processes: %{
pid() => %{LvProcess.t() => [LvProcess.t()]}
}
}}
{dead_grouped_lv_processes :: grouped_lv_processes(),
lv_processes_count :: non_neg_integer()}
def fetch_dead_grouped_lv_processes() do
dead_grouped_lv_processes =
dead_lv_processes =
StatesStorage.get_all_states()
|> Enum.filter(fn {pid, %LvState{}} -> not Process.alive?(pid) end)
|> Enum.map(&elem(&1, 1))
|> Enum.map(&(LvProcess.new(&1.pid, &1.socket) |> LvProcess.set_alive(false)))
|> LiveViewDiscovery.group_lv_processes()

{:ok, %{dead_grouped_lv_processes: dead_grouped_lv_processes}}
{LiveViewDiscovery.group_lv_processes(dead_lv_processes), length(dead_lv_processes)}
end

defp fetch_lv_processes_after(milliseconds, nil) do
Expand Down
51 changes: 28 additions & 23 deletions lib/live_debugger/app/discovery/web/components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,48 @@ defmodule LiveDebugger.App.Discovery.Web.Components do
assign(assigns, garbage_collection_enabled?: SettingsStorage.get(:garbage_collection))

~H"""
<div class={[
"mt-6 p-4 bg-surface-0-bg rounded shadow-custom border flex justify-center",
if(@garbage_collection_enabled?, do: "border-info-text", else: "border-warning-text")
]}>
<div class="text-center max-w-[40rem]">
<.info_block variant={if(@garbage_collection_enabled?, do: "info", else: "warning")} class="mt-6">
<:header>
<%= if @garbage_collection_enabled? do %>
<p class="text-info-text">
You have <b>Garbage Collection enabled</b>
which means that LiveViews listed below will be removed automatically.
You can disable this behaviour in <.settings_link />.
</p>
The LiveViews listed below are no longer active and will be removed shortly.
<% else %>
<p class="text-warning-text">
You have <b>Garbage Collection disabled</b>
which means that LiveViews listed below will not be removed automatically.
This will lead to increased memory usage. You can enable it in <.settings_link />.
</p>
Garbage Collection is disabled, so the LiveViews below will not be removed automatically.
<% end %>
</:header>
<div>
<%= if @garbage_collection_enabled? do %>
To keep them longer, disable Garbage Collection in <b><.settings_link /></b>. Note that this may increase memory usage.
<% else %>
Note that this may increase memory usage. To have them removed automatically, enable Garbage Collection in <b><.settings_link /></b>.
<% end %>
</div>
</div>
</.info_block>
"""
end

attr(:title, :string, required: true)
attr(:lv_processes_count, :integer, default: 0)
attr(:refresh_event, :string, required: true)
attr(:disabled?, :boolean, default: false)
attr(:target, :any, default: nil)
slot(:inner_block)

def header(assigns) do
~H"""
<div class="flex items-center gap-2">
<.h1 class={if(@disabled?, do: "opacity-30")}><%= @title %></.h1>
<div class="flex-1">
<%= render_slot(@inner_block) %>
<div class="flex flex-1 items-center gap-2 justify-between">
<div class="flex items-center gap-3">
<.h1><%= @title %></.h1>
<.info_block size="sm">
<:header>
<%= @lv_processes_count %>
</:header>
</.info_block>
</div>
<.button phx-click={@refresh_event} disabled={@disabled?} phx-target={@target}>
<.button
phx-click={@refresh_event}
disabled={@disabled?}
phx-target={@target}
class="show-on-open"
>
<div class="flex items-center gap-2">
<.icon name="icon-refresh" class="w-4 h-4" />
<p>Refresh</p>
Expand Down Expand Up @@ -207,7 +212,7 @@ defmodule LiveDebugger.App.Discovery.Web.Components do
defp settings_link(assigns) do
~H"""
<.link navigate={RoutesHelper.settings()} class="underline cursor-pointer">
settings
Settings
</.link>
"""
end
Expand Down
5 changes: 4 additions & 1 deletion lib/live_debugger/app/discovery/web/discovery_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ defmodule LiveDebugger.App.Discovery.Web.DiscoveryLive do
<div class="h-full flex-1 min-w-[25rem] grid grid-rows-[auto_1fr]">
<NavbarComponents.navbar class="flex justify-between">
<NavbarComponents.live_debugger_logo />
<NavbarComponents.settings_button return_to={@url} />
<div class="flex items-center gap-2">
<NavbarComponents.garbage_collection_warning />
<NavbarComponents.settings_button return_to={@url} />
</div>
</NavbarComponents.navbar>
<div class="h-full flex flex-col">
<.live_component module={ActiveLiveViews} id="active-live-views" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,28 @@ defmodule LiveDebugger.App.Discovery.Web.LiveComponents.ActiveLiveViews do

use LiveDebugger.App.Web, :live_component

alias Phoenix.LiveView.AsyncResult
alias LiveDebugger.App.Discovery.Web.Components, as: DiscoveryComponents
alias LiveDebugger.App.Discovery.Queries, as: DiscoveryQueries

def refresh(id) do
send_update(__MODULE__, id: id)
send_update(__MODULE__, id: id, action: :refresh)
end

@impl true
def update(%{action: :refresh}, socket) do
socket
|> start_async_grouped_lv_processes()
|> ok()
end

def update(assigns, socket) do
socket
|> assign(assigns)
|> assign_async_grouped_lv_processes()
|> assign(open?: true)
|> assign(lv_processes_count: 0)
|> assign(grouped_lv_processes: AsyncResult.loading())
|> start_async_grouped_lv_processes()
|> ok()
end

Expand All @@ -25,41 +35,71 @@ defmodule LiveDebugger.App.Discovery.Web.LiveComponents.ActiveLiveViews do
@impl true
def render(assigns) do
~H"""
<div id={@id} class="h-3/7 min-h-92 lg:min-h-120 max-lg:p-8 pt-8 lg:w-[60rem] lg:mx-auto">
<DiscoveryComponents.header
title="Active LiveViews"
refresh_event="refresh-active"
target={@myself}
/>

<div class="mt-6 max-h-72 lg:max-h-100 overflow-y-auto">
<.async_result :let={grouped_lv_processes} assign={@grouped_lv_processes}>
<:loading><DiscoveryComponents.loading /></:loading>
<:failed><DiscoveryComponents.failed /></:failed>
<DiscoveryComponents.liveview_sessions
id="live-sessions"
grouped_lv_processes={grouped_lv_processes}
empty_info="No active LiveViews"
<div id={@id} class={if(@open?, do: "flex-1")}>
<.static_collapsible
chevron_class="mr-2"
class="h-full flex! flex-col max-lg:p-8 max-lg:pb-0 pt-8 lg:w-[60rem] lg:mx-auto"
open={@open?}
phx-click="toggle-open"
phx-target={@myself}
>
<:label :let={open?}>
<DiscoveryComponents.header
title="Active LiveViews"
lv_processes_count={@lv_processes_count}
refresh_event="refresh-active"
disabled?={!open?}
target={@myself}
/>
</.async_result>
</div>
</:label>

<div class="mt-6 flex-[1_0_0] overflow-y-scroll">
<.async_result :let={grouped_lv_processes} assign={@grouped_lv_processes}>
<:loading><DiscoveryComponents.loading /></:loading>
<:failed><DiscoveryComponents.failed /></:failed>
<DiscoveryComponents.liveview_sessions
id="live-sessions"
grouped_lv_processes={grouped_lv_processes}
empty_info="No active LiveViews"
/>
</.async_result>
</div>
</.static_collapsible>
</div>
"""
end

@impl true
def handle_event("refresh-active", _params, socket) do
socket
|> assign_async_grouped_lv_processes()
|> assign(grouped_lv_processes: AsyncResult.loading())
|> start_async_grouped_lv_processes()
|> noreply()
end

def handle_event("toggle-open", _params, socket) do
socket
|> assign(open?: !socket.assigns.open?)
|> noreply()
end

@impl true
def handle_async(
:fetch_grouped_lv_processes,
{:ok, {grouped_lv_processes, lv_processes_count}},
socket
) do
socket
|> assign(lv_processes_count: lv_processes_count)
|> assign(grouped_lv_processes: AsyncResult.ok(grouped_lv_processes))
|> noreply()
end

defp assign_async_grouped_lv_processes(socket) do
assign_async(
defp start_async_grouped_lv_processes(socket) do
start_async(
socket,
:grouped_lv_processes,
&DiscoveryQueries.fetch_grouped_lv_processes/0,
reset: true
:fetch_grouped_lv_processes,
&DiscoveryQueries.fetch_grouped_lv_processes/0
)
end
end
Loading