Skip to content

Commit df88cc1

Browse files
authored
Enhancement: Update Active LiveViews page (#858)
* Change Dead LiveViews to collapsible * Add lv processes counters * Adjust info_block to designs * Add gc disabled warning * Reset dead LiveViews counter * Change info and remove comment * Refactor layout * Change closed collapsible label look * Fix e2e tests
1 parent 2bcf4d6 commit df88cc1

File tree

15 files changed

+291
-162
lines changed

15 files changed

+291
-162
lines changed
Lines changed: 4 additions & 0 deletions
Loading

assets/app/styles/themes/dark.css

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@
7979
--info-text: var(--primary-text);
8080

8181
/* Warning */
82-
--warning-text: var(--swm-yellow-60);
82+
--warning-bg: var(--surface-0-bg);
83+
--warning-border: var(--swm-yellow-40);
84+
--warning-text: var(--primary-text);
8385

8486
--search-highlight-bg: var(--swm-yellow-100);
8587
--search-highlight-text: var(--gray-900);

assets/app/styles/themes/light.css

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@
7878
--info-text: var(--primary-text);
7979

8080
/* Warning */
81-
--warning-text: #e6bf00;
81+
--warning-bg: var(--swm-yellow-20);
82+
--warning-border: var(--swm-yellow-40);
83+
--warning-text: var(--primary-text);
8284

8385
--search-highlight-bg: var(--swm-yellow-80);
8486
--search-highlight-text: var(--slate-900);

assets/app/tailwind.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ module.exports = {
6666
'info-border': 'var(--info-border)',
6767
'info-icon': 'var(--info-icon)',
6868
'info-text': 'var(--info-text)',
69+
'warning-bg': 'var(--warning-bg)',
70+
'warning-border': 'var(--warning-border)',
71+
'warning-text': 'var(--warning-text)',
6972
'diff-border': 'var(--diff-border)',
7073
'diff-negative-bg': 'var(--diff-negative-bg)',
7174
'diff-positive-bg': 'var(--diff-positive-bg)',

lib/live_debugger/app/debugger/web/debugger_live.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ defmodule LiveDebugger.App.Debugger.Web.DebuggerLive do
6666
<Navbar.live_debugger_logo_icon />
6767
<HookComponents.DeadViewMode.render id="navbar-connected" lv_process={lv_process} />
6868
<div class="flex items-center gap-2">
69+
<Navbar.garbage_collection_warning />
6970
<HookComponents.InspectButton.render
7071
inspect_mode?={@inspect_mode?}
7172
lv_process={lv_process}

lib/live_debugger/app/discovery/queries.ex

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,47 +8,40 @@ defmodule LiveDebugger.App.Discovery.Queries do
88
alias LiveDebugger.API.LiveViewDiscovery
99
alias LiveDebugger.Structs.LvProcess
1010

11+
@type grouped_lv_processes() :: %{pid() => %{LvProcess.t() => [LvProcess.t()]}}
12+
1113
@doc """
1214
Fetches all active LiveView processes grouped by their transport PID.
1315
Performs delayed fetching to ensure processes are captured.
1416
"""
1517
@spec fetch_grouped_lv_processes(transport_pid :: pid() | nil) ::
16-
{:ok,
17-
%{
18-
grouped_lv_processes: %{
19-
pid() => %{LvProcess.t() => [LvProcess.t()]}
20-
}
21-
}}
18+
{grouped_lv_processes :: grouped_lv_processes(),
19+
lv_processes_count :: non_neg_integer()}
2220
def fetch_grouped_lv_processes(transport_pid \\ nil) do
2321
lv_processes =
2422
with [] <- fetch_lv_processes_after(200, transport_pid),
2523
[] <- fetch_lv_processes_after(800, transport_pid) do
2624
fetch_lv_processes_after(1000, transport_pid)
2725
end
2826

29-
{:ok, %{grouped_lv_processes: LiveViewDiscovery.group_lv_processes(lv_processes)}}
27+
{LiveViewDiscovery.group_lv_processes(lv_processes), length(lv_processes)}
3028
end
3129

3230
@doc """
3331
Fetches all dead LiveView processes grouped by their transport PID.
3432
Retrieves states from storage and checks for process aliveness.
3533
"""
3634
@spec fetch_dead_grouped_lv_processes() ::
37-
{:ok,
38-
%{
39-
dead_grouped_lv_processes: %{
40-
pid() => %{LvProcess.t() => [LvProcess.t()]}
41-
}
42-
}}
35+
{dead_grouped_lv_processes :: grouped_lv_processes(),
36+
lv_processes_count :: non_neg_integer()}
4337
def fetch_dead_grouped_lv_processes() do
44-
dead_grouped_lv_processes =
38+
dead_lv_processes =
4539
StatesStorage.get_all_states()
4640
|> Enum.filter(fn {pid, %LvState{}} -> not Process.alive?(pid) end)
4741
|> Enum.map(&elem(&1, 1))
4842
|> Enum.map(&(LvProcess.new(&1.pid, &1.socket) |> LvProcess.set_alive(false)))
49-
|> LiveViewDiscovery.group_lv_processes()
5043

51-
{:ok, %{dead_grouped_lv_processes: dead_grouped_lv_processes}}
44+
{LiveViewDiscovery.group_lv_processes(dead_lv_processes), length(dead_lv_processes)}
5245
end
5346

5447
defp fetch_lv_processes_after(milliseconds, nil) do

lib/live_debugger/app/discovery/web/components.ex

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,43 +15,48 @@ defmodule LiveDebugger.App.Discovery.Web.Components do
1515
assign(assigns, garbage_collection_enabled?: SettingsStorage.get(:garbage_collection))
1616

1717
~H"""
18-
<div class={[
19-
"mt-6 p-4 bg-surface-0-bg rounded shadow-custom border flex justify-center",
20-
if(@garbage_collection_enabled?, do: "border-info-text", else: "border-warning-text")
21-
]}>
22-
<div class="text-center max-w-[40rem]">
18+
<.info_block variant={if(@garbage_collection_enabled?, do: "info", else: "warning")} class="mt-6">
19+
<:header>
2320
<%= if @garbage_collection_enabled? do %>
24-
<p class="text-info-text">
25-
You have <b>Garbage Collection enabled</b>
26-
which means that LiveViews listed below will be removed automatically.
27-
You can disable this behaviour in <.settings_link />.
28-
</p>
21+
The LiveViews listed below are no longer active and will be removed shortly.
2922
<% else %>
30-
<p class="text-warning-text">
31-
You have <b>Garbage Collection disabled</b>
32-
which means that LiveViews listed below will not be removed automatically.
33-
This will lead to increased memory usage. You can enable it in <.settings_link />.
34-
</p>
23+
Garbage Collection is disabled, so the LiveViews below will not be removed automatically.
24+
<% end %>
25+
</:header>
26+
<div>
27+
<%= if @garbage_collection_enabled? do %>
28+
To keep them longer, disable Garbage Collection in <b><.settings_link /></b>. Note that this may increase memory usage.
29+
<% else %>
30+
Note that this may increase memory usage. To have them removed automatically, enable Garbage Collection in <b><.settings_link /></b>.
3531
<% end %>
3632
</div>
37-
</div>
33+
</.info_block>
3834
"""
3935
end
4036

4137
attr(:title, :string, required: true)
38+
attr(:lv_processes_count, :integer, default: 0)
4239
attr(:refresh_event, :string, required: true)
4340
attr(:disabled?, :boolean, default: false)
4441
attr(:target, :any, default: nil)
45-
slot(:inner_block)
4642

4743
def header(assigns) do
4844
~H"""
49-
<div class="flex items-center gap-2">
50-
<.h1 class={if(@disabled?, do: "opacity-30")}><%= @title %></.h1>
51-
<div class="flex-1">
52-
<%= render_slot(@inner_block) %>
45+
<div class="flex flex-1 items-center gap-2 justify-between">
46+
<div class="flex items-center gap-3">
47+
<.h1><%= @title %></.h1>
48+
<.info_block size="sm">
49+
<:header>
50+
<%= @lv_processes_count %>
51+
</:header>
52+
</.info_block>
5353
</div>
54-
<.button phx-click={@refresh_event} disabled={@disabled?} phx-target={@target}>
54+
<.button
55+
phx-click={@refresh_event}
56+
disabled={@disabled?}
57+
phx-target={@target}
58+
class="show-on-open"
59+
>
5560
<div class="flex items-center gap-2">
5661
<.icon name="icon-refresh" class="w-4 h-4" />
5762
<p>Refresh</p>
@@ -207,7 +212,7 @@ defmodule LiveDebugger.App.Discovery.Web.Components do
207212
defp settings_link(assigns) do
208213
~H"""
209214
<.link navigate={RoutesHelper.settings()} class="underline cursor-pointer">
210-
settings
215+
Settings
211216
</.link>
212217
"""
213218
end

lib/live_debugger/app/discovery/web/discovery_live.ex

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ defmodule LiveDebugger.App.Discovery.Web.DiscoveryLive do
3030
<div class="h-full flex-1 min-w-[25rem] grid grid-rows-[auto_1fr]">
3131
<NavbarComponents.navbar class="flex justify-between">
3232
<NavbarComponents.live_debugger_logo />
33-
<NavbarComponents.settings_button return_to={@url} />
33+
<div class="flex items-center gap-2">
34+
<NavbarComponents.garbage_collection_warning />
35+
<NavbarComponents.settings_button return_to={@url} />
36+
</div>
3437
</NavbarComponents.navbar>
3538
<div class="h-full flex flex-col">
3639
<.live_component module={ActiveLiveViews} id="active-live-views" />

lib/live_debugger/app/discovery/web/live_components/active_live_views.ex

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,28 @@ defmodule LiveDebugger.App.Discovery.Web.LiveComponents.ActiveLiveViews do
55

66
use LiveDebugger.App.Web, :live_component
77

8+
alias Phoenix.LiveView.AsyncResult
89
alias LiveDebugger.App.Discovery.Web.Components, as: DiscoveryComponents
910
alias LiveDebugger.App.Discovery.Queries, as: DiscoveryQueries
1011

1112
def refresh(id) do
12-
send_update(__MODULE__, id: id)
13+
send_update(__MODULE__, id: id, action: :refresh)
1314
end
1415

1516
@impl true
17+
def update(%{action: :refresh}, socket) do
18+
socket
19+
|> start_async_grouped_lv_processes()
20+
|> ok()
21+
end
22+
1623
def update(assigns, socket) do
1724
socket
1825
|> assign(assigns)
19-
|> assign_async_grouped_lv_processes()
26+
|> assign(open?: true)
27+
|> assign(lv_processes_count: 0)
28+
|> assign(grouped_lv_processes: AsyncResult.loading())
29+
|> start_async_grouped_lv_processes()
2030
|> ok()
2131
end
2232

@@ -25,41 +35,71 @@ defmodule LiveDebugger.App.Discovery.Web.LiveComponents.ActiveLiveViews do
2535
@impl true
2636
def render(assigns) do
2737
~H"""
28-
<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">
29-
<DiscoveryComponents.header
30-
title="Active LiveViews"
31-
refresh_event="refresh-active"
32-
target={@myself}
33-
/>
34-
35-
<div class="mt-6 max-h-72 lg:max-h-100 overflow-y-auto">
36-
<.async_result :let={grouped_lv_processes} assign={@grouped_lv_processes}>
37-
<:loading><DiscoveryComponents.loading /></:loading>
38-
<:failed><DiscoveryComponents.failed /></:failed>
39-
<DiscoveryComponents.liveview_sessions
40-
id="live-sessions"
41-
grouped_lv_processes={grouped_lv_processes}
42-
empty_info="No active LiveViews"
38+
<div id={@id} class={if(@open?, do: "flex-1")}>
39+
<.static_collapsible
40+
chevron_class="mr-2"
41+
class="h-full flex! flex-col max-lg:p-8 max-lg:pb-0 pt-8 lg:w-[60rem] lg:mx-auto"
42+
open={@open?}
43+
phx-click="toggle-open"
44+
phx-target={@myself}
45+
>
46+
<:label :let={open?}>
47+
<DiscoveryComponents.header
48+
title="Active LiveViews"
49+
lv_processes_count={@lv_processes_count}
50+
refresh_event="refresh-active"
51+
disabled?={!open?}
52+
target={@myself}
4353
/>
44-
</.async_result>
45-
</div>
54+
</:label>
55+
56+
<div class="mt-6 flex-[1_0_0] overflow-y-scroll">
57+
<.async_result :let={grouped_lv_processes} assign={@grouped_lv_processes}>
58+
<:loading><DiscoveryComponents.loading /></:loading>
59+
<:failed><DiscoveryComponents.failed /></:failed>
60+
<DiscoveryComponents.liveview_sessions
61+
id="live-sessions"
62+
grouped_lv_processes={grouped_lv_processes}
63+
empty_info="No active LiveViews"
64+
/>
65+
</.async_result>
66+
</div>
67+
</.static_collapsible>
4668
</div>
4769
"""
4870
end
4971

5072
@impl true
5173
def handle_event("refresh-active", _params, socket) do
5274
socket
53-
|> assign_async_grouped_lv_processes()
75+
|> assign(grouped_lv_processes: AsyncResult.loading())
76+
|> start_async_grouped_lv_processes()
77+
|> noreply()
78+
end
79+
80+
def handle_event("toggle-open", _params, socket) do
81+
socket
82+
|> assign(open?: !socket.assigns.open?)
83+
|> noreply()
84+
end
85+
86+
@impl true
87+
def handle_async(
88+
:fetch_grouped_lv_processes,
89+
{:ok, {grouped_lv_processes, lv_processes_count}},
90+
socket
91+
) do
92+
socket
93+
|> assign(lv_processes_count: lv_processes_count)
94+
|> assign(grouped_lv_processes: AsyncResult.ok(grouped_lv_processes))
5495
|> noreply()
5596
end
5697

57-
defp assign_async_grouped_lv_processes(socket) do
58-
assign_async(
98+
defp start_async_grouped_lv_processes(socket) do
99+
start_async(
59100
socket,
60-
:grouped_lv_processes,
61-
&DiscoveryQueries.fetch_grouped_lv_processes/0,
62-
reset: true
101+
:fetch_grouped_lv_processes,
102+
&DiscoveryQueries.fetch_grouped_lv_processes/0
63103
)
64104
end
65105
end

0 commit comments

Comments
 (0)