Skip to content

Commit d401b90

Browse files
kraleppaGuzekAlan
andauthored
Enhancement: apply new navigation to UI (#433)
* remove from function names when not necessary * dont remove table when any process is watching * add specs * properly send events and delete state server record * add indicator, change state names * add styling * add flag for dead view mode * add docs, conditional using `watch` function * fix tests * make dead view mode default * add tests * remove unnecessary config * fix e2e tests * end gitignore with newline * manually compile deploy assets * Changed sidebar icon * Moved sidebar to right * Applied single column layout * Changed long assign example * Added navigation bar * Added separator between theme and sidebar icons * Bigger bap between connected and logo * Changed info in the sidebar * Updated LiveDropdown * Added base for menu dropdown * remove from function names when not necessary * dont remove table when any process is watching * add specs * properly send events and delete state server record * add indicator, change state names * add styling * add flag for dead view mode * add docs, conditional using `watch` function * fix tests * make dead view mode default * add tests * remove unnecessary config * fix e2e tests * end gitignore with newline * manually compile deploy assets * use LiveDebugger.Feature module * add docs * add tooltip: * remove from docs * fetch if not cached * change tooltip info * Moved navigation menu to separate module * add config for disabling redirects in devtools * Fixed icons * Added dropdown options * Correct routing in dropdown * Fixed navbar * Fixed most of tests * Fixed updating module on changing tree elements * Added missing attr * Removed readme updates * Removed config * Removed deadview from docs * Removed spec * Removed post merge artifact * Hide return link for window liveview in iframe * Added truncate * Fixed tooltip --------- Co-authored-by: Alan Guzek <alan.guzek@swmansion.com>
1 parent eb7514c commit d401b90

17 files changed

Lines changed: 225 additions & 154 deletions

File tree

assets/icons/globe.svg

Lines changed: 3 additions & 0 deletions
Loading

assets/icons/info.svg

Lines changed: 3 additions & 0 deletions
Loading

assets/icons/panel-right.svg

Lines changed: 3 additions & 0 deletions
Loading

dev/live_views/main.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ defmodule LiveDebuggerDev.LiveViews.Main do
1515
|> assign(list: [%Phoenix.LiveComponent.CID{cid: 1}, %Phoenix.LiveComponent.CID{cid: 2}])
1616
|> assign(
1717
long_assign:
18-
"flex items-center gap-2 flex grow flex-col xl:flex-row flex items-center gap-2 flex grow flex-col xl:flex-row gap-4 xl:gap-8 p-8 overflow-y-auto xl:overflow-y-hidden max-w-screen-2xl mx-auto"
18+
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
1919
)
2020

2121
{:ok, socket}

lib/live_debugger_web/components.ex

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,29 @@ defmodule LiveDebuggerWeb.Components do
613613
"""
614614
end
615615

616+
@doc """
617+
Renders an icon with navbar styles.
618+
"""
619+
attr(:icon, :string, required: true, doc: "Icon to be displayed.")
620+
attr(:class, :any, default: nil, doc: "Additional classes to add to the nav icon.")
621+
622+
attr(:rest, :global, include: ~w(id))
623+
624+
def nav_icon(assigns) do
625+
~H"""
626+
<button
627+
aria-label={Parsers.kebab_to_text(@icon)}
628+
class={[
629+
"w-8! h-8! px-[0.25rem] py-[0.25rem] w-max h-max rounded text-xs font-semibold text-navbar-icon hover:text-navbar-icon-hover hover:bg-navbar-icon-bg-hover"
630+
| List.wrap(@class)
631+
]}
632+
{@rest}
633+
>
634+
<.icon name={@icon} class="h-6 w-6" />
635+
</button>
636+
"""
637+
end
638+
616639
attr(:variant, :string, required: true, values: ["danger"])
617640

618641
defp alert_icon(assigns) do

lib/live_debugger_web/components/navbar.ex

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ defmodule LiveDebuggerWeb.Components.Navbar do
55

66
use LiveDebuggerWeb, :component
77

8-
alias LiveDebugger.Utils.Parsers
9-
108
@doc """
119
Renders base navbar component.
1210
"""
@@ -55,11 +53,13 @@ defmodule LiveDebuggerWeb.Components.Navbar do
5553
@doc """
5654
Renders a link to return to the previous page.
5755
"""
58-
attr(:link, :any, required: true, doc: "Link to navigate to.")
56+
57+
attr(:return_link, :any, required: true, doc: "Link to navigate to.")
58+
attr(:class, :any, default: nil, doc: "Additional classes to add to the link.")
5959

6060
def return_link(assigns) do
6161
~H"""
62-
<.link patch={@link}>
62+
<.link patch={@return_link} class={@class}>
6363
<.nav_icon icon="icon-arrow-left" />
6464
</.link>
6565
"""
@@ -82,29 +82,6 @@ defmodule LiveDebuggerWeb.Components.Navbar do
8282
"""
8383
end
8484

85-
@doc """
86-
Renders an icon with navbar styles.
87-
"""
88-
attr(:icon, :string, required: true, doc: "Icon to be displayed.")
89-
attr(:class, :any, default: nil, doc: "Additional classes to add to the nav icon.")
90-
91-
attr(:rest, :global, include: ~w(id))
92-
93-
def nav_icon(assigns) do
94-
~H"""
95-
<button
96-
aria-label={Parsers.kebab_to_text(@icon)}
97-
class={[
98-
"w-8! h-8! px-[0.25rem] py-[0.25rem] w-max h-max rounded text-xs font-semibold text-navbar-icon hover:text-navbar-icon-hover hover:bg-navbar-icon-bg-hover"
99-
| List.wrap(@class)
100-
]}
101-
{@rest}
102-
>
103-
<.icon name={@icon} class="h-6 w-6" />
104-
</button>
105-
"""
106-
end
107-
10885
@doc """
10986
Component for displaying the connection status of a LiveView.
11087
When button is clicked, it will trigger a `find-successor` event with the PID of the LiveView.
@@ -126,7 +103,7 @@ defmodule LiveDebuggerWeb.Components.Navbar do
126103
)
127104
}
128105
>
129-
<div id={@id} class="flex items-center gap-1 text-xs text-primary">
106+
<div id={@id} class="flex items-center gap-1 text-xs text-primary ml-1">
130107
<.status_icon connected?={@connected?} />
131108
<%= if @connected? do %>
132109
<span class="font-medium">Monitored PID </span>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
defmodule LiveDebuggerWeb.Components.NavigationMenu do
2+
@moduledoc """
3+
Set of components used in the navigation menu.
4+
"""
5+
use LiveDebuggerWeb, :component
6+
7+
alias LiveDebuggerWeb.LiveComponents.LiveDropdown
8+
9+
attr(:class, :any, default: nil, doc: "Additional classes to add to the navigation bar.")
10+
11+
def sidebar(assigns) do
12+
~H"""
13+
<div class={[
14+
"flex flex-col gap-3 bg-sidebar-bg shadow-custom h-full p-2 border-r border-default-border"
15+
| List.wrap(@class)
16+
]}>
17+
<.nav_icon icon="icon-info" />
18+
<.nav_icon icon="icon-globe" />
19+
</div>
20+
"""
21+
end
22+
23+
attr(:class, :any, default: nil, doc: "Additional classes to add to the navigation bar.")
24+
attr(:return_link, :any, required: true, doc: "Link to navigate to.")
25+
26+
def dropdown(assigns) do
27+
~H"""
28+
<.live_component
29+
module={LiveDropdown}
30+
id="navigation-bar-dropdown"
31+
class={@class}
32+
direction="right"
33+
>
34+
<:button>
35+
<.nav_icon icon="icon-menu-hamburger" />
36+
</:button>
37+
<div class="min-w-44 flex flex-col p-1">
38+
<.link navigate={@return_link}>
39+
<LiveDropdown.dropdown_item icon="icon-arrow-left" label="Back to Home" />
40+
</.link>
41+
<span class="w-full border-b border-default-border my-1"></span>
42+
<LiveDropdown.dropdown_item icon="icon-info" label="Node Inspector" />
43+
<LiveDropdown.dropdown_item icon="icon-globe" label="Global Callbacks" />
44+
</div>
45+
</.live_component>
46+
"""
47+
end
48+
end

lib/live_debugger_web/live/channel_dashboard_live.ex

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ defmodule LiveDebuggerWeb.ChannelDashboardLive do
1818
alias LiveDebuggerWeb.SidebarLive
1919
alias LiveDebugger.Utils.PubSub, as: PubSubUtils
2020
alias LiveDebugger.Utils.Parsers
21+
alias LiveDebuggerWeb.Components.NavigationMenu
2122

2223
@impl true
2324
def handle_params(params, url, socket) do
@@ -31,22 +32,38 @@ defmodule LiveDebuggerWeb.ChannelDashboardLive do
3132
def render(assigns) do
3233
~H"""
3334
<div id="channel-dashboard" class="w-screen h-screen grid grid-rows-[auto_1fr]">
34-
<Navbar.navbar class="grid grid-cols-[auto_auto_1fr_auto_auto]">
35-
<Navbar.return_link link={get_return_link(@lv_process, @in_iframe?)} />
35+
<Navbar.navbar class="grid grid-cols-[auto_auto_1fr_auto] pl-2 lg:pr-4">
36+
<Navbar.return_link
37+
return_link={get_return_link(@lv_process, @in_iframe?)}
38+
class="hidden sm:block"
39+
/>
40+
<NavigationMenu.dropdown
41+
return_link={get_return_link(@lv_process, @in_iframe?)}
42+
class="sm:hidden"
43+
/>
3644
<Navbar.live_debugger_logo_icon />
45+
<div
46+
:if={not @lv_process.ok?}
47+
class="animate-pulse w-36 bg-surface-1-bg rounded text-surface-1-bg"
48+
>
49+
Loading...
50+
</div>
3751
<Navbar.connected
3852
:if={@lv_process.ok?}
3953
id="navbar-connected"
4054
connected?={@lv_process.result.alive?}
4155
pid={Parsers.pid_to_string(@lv_process.result.pid)}
4256
/>
43-
<Navbar.theme_toggle />
44-
<Navbar.nav_icon
45-
:if={@lv_process.ok?}
46-
phx-click={JS.push("open-sidebar", target: "#sidebar")}
47-
class="flex lg:hidden"
48-
icon="icon-menu-hamburger"
49-
/>
57+
<div class="flex items-center gap-2">
58+
<Navbar.theme_toggle />
59+
<span :if={@lv_process.ok?} class="h-5 border-r border-default-border lg:hidden"></span>
60+
<.nav_icon
61+
:if={@lv_process.ok?}
62+
phx-click={JS.push("open-sidebar", target: "#sidebar")}
63+
class="flex lg:hidden"
64+
icon="icon-panel-right"
65+
/>
66+
</div>
5067
</Navbar.navbar>
5168
<.async_result :let={lv_process} assign={@lv_process}>
5269
<:loading>
@@ -55,32 +72,32 @@ defmodule LiveDebuggerWeb.ChannelDashboardLive do
5572
</div>
5673
</:loading>
5774
<div class="flex overflow-hidden">
58-
<SidebarLive.live_render
59-
id="sidebar"
60-
class="h-full"
61-
socket={@socket}
62-
lv_process={lv_process}
63-
url={@url}
64-
node_id={@node_id || lv_process.pid}
65-
/>
66-
67-
<div class="flex grow flex-col xl:flex-row gap-4 xl:gap-8 p-8 overflow-y-auto xl:overflow-y-hidden max-w-screen-2xl mx-auto scrollbar-main">
75+
<NavigationMenu.sidebar class="hidden sm:flex" />
76+
<div class="flex grow flex-col gap-4 p-8 overflow-y-auto max-w-screen-2xl mx-auto scrollbar-main">
6877
<StateLive.live_render
6978
id="node-state-lv"
70-
class="flex xl:w-1/2"
79+
class="flex"
7180
socket={@socket}
7281
lv_process={lv_process}
7382
node_id={@node_id || lv_process.pid}
7483
/>
7584
<TracesLive.live_render
7685
id="traces-list"
77-
class="flex max-xl:grow xl:w-1/2"
86+
class="flex"
7887
socket={@socket}
7988
lv_process={lv_process}
8089
node_id={@node_id || lv_process.pid}
8190
root_pid={self()}
8291
/>
8392
</div>
93+
<SidebarLive.live_render
94+
id="sidebar"
95+
class="h-full"
96+
socket={@socket}
97+
lv_process={lv_process}
98+
url={@url}
99+
node_id={@node_id || lv_process.pid}
100+
/>
84101
</div>
85102
</.async_result>
86103
</div>

lib/live_debugger_web/live/sidebar_live.ex

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ defmodule LiveDebuggerWeb.SidebarLive do
88

99
require Logger
1010

11+
alias LiveDebugger.Structs.TreeNode
1112
alias LiveDebugger.Structs.LvProcess
1213
alias LiveDebugger.Structs.Trace
1314
alias LiveDebugger.Utils.Parsers
@@ -68,6 +69,7 @@ defmodule LiveDebuggerWeb.SidebarLive do
6869
|> assign(:highlight?, false)
6970
|> assign(:hidden?, true)
7071
|> assign_async_tree()
72+
|> assign_async_node_module()
7173
|> assign_async_parent_lv_process()
7274
|> assign_async_existing_node_ids()
7375
|> ok()
@@ -90,6 +92,7 @@ defmodule LiveDebuggerWeb.SidebarLive do
9092
node_id={@node_id}
9193
highlight?={@highlight?}
9294
parent_lv_process={@parent_lv_process}
95+
node_module={@node_module}
9396
/>
9497
</div>
9598
<.sidebar_slide_over :if={not @hidden?}>
@@ -101,6 +104,7 @@ defmodule LiveDebuggerWeb.SidebarLive do
101104
node_id={@node_id}
102105
highlight?={@highlight?}
103106
parent_lv_process={@parent_lv_process}
107+
node_module={@node_module}
104108
/>
105109
</.sidebar_slide_over>
106110
</div>
@@ -139,6 +143,7 @@ defmodule LiveDebuggerWeb.SidebarLive do
139143
def handle_info({:node_changed, node_id}, socket) do
140144
socket
141145
|> assign(:node_id, node_id)
146+
|> assign_async_node_module()
142147
|> noreply()
143148
end
144149

@@ -205,14 +210,16 @@ defmodule LiveDebuggerWeb.SidebarLive do
205210
attr(:max_opened_node_level, :any, required: true)
206211
attr(:highlight?, :boolean, required: true)
207212
attr(:parent_lv_process, :any, required: true)
213+
attr(:node_module, :any, required: true)
208214

209215
defp sidebar_content(assigns) do
210216
~H"""
211217
<div class="grid grid-rows-[auto_auto_1fr_auto] h-full">
212218
<.basic_info
213-
pid={@lv_process.pid}
214-
socket_id={@lv_process.socket_id}
219+
id={@id <> "-basic-info"}
220+
module={@node_module}
215221
parent_lv_process={@parent_lv_process}
222+
node_type={TreeNode.type(@node_id)}
216223
/>
217224
<.live_component
218225
id={@id <> "-nested-live-views"}
@@ -253,28 +260,33 @@ defmodule LiveDebuggerWeb.SidebarLive do
253260
"""
254261
end
255262

256-
attr(:pid, :any, required: true)
257-
attr(:socket_id, :string, required: true)
258-
attr(:parent_lv_process, :any, required: true)
263+
attr(:id, :string, required: true)
264+
attr(:module, :atom, required: true)
265+
attr(:node_type, :atom, required: true)
266+
attr(:parent_lv_process, :map, required: true)
259267

260268
defp basic_info(assigns) do
261269
~H"""
262-
<div class="w-full p-6 shrink-0 flex flex-col gap-2 border-b border-default-border">
270+
<div id={@id} class="w-full p-6 shrink-0 flex flex-col gap-2 border-b border-default-border">
263271
<.async_result :let={parent_lv_process} assign={@parent_lv_process}>
264272
<:loading>
265273
<div class="w-full h-30 flex justify-center items-center"><.spinner size="sm" /></div>
266274
</:loading>
267-
<div
268-
:for={
269-
{text, value} <- [
270-
{"Monitored socket:", @socket_id},
271-
{"Debugged PID:", Parsers.pid_to_string(@pid)}
272-
]
273-
}
274-
class="w-full flex flex-col"
275-
>
276-
<span class="font-medium"><%= text %></span>
277-
<span><%= value %></span>
275+
<div class="w-full flex flex-col">
276+
<span class="font-medium">Type:</span>
277+
<span><%= node_type(@node_type) %></span>
278+
</div>
279+
<div class="w-full flex flex-col">
280+
<span class="font-medium">Module:</span>
281+
282+
<.tooltip
283+
:if={@module.ok?}
284+
id={@id <> "-current-node-module"}
285+
content={Parsers.module_to_string(@module.result)}
286+
class="truncate max-w-[272px]"
287+
>
288+
<%= Parsers.module_to_string(@module.result) %>
289+
</.tooltip>
278290
</div>
279291
<div :if={parent_lv_process} class="w-full flex flex-col">
280292
<span class="font-medium">Parent LiveView Process</span>
@@ -332,6 +344,18 @@ defmodule LiveDebuggerWeb.SidebarLive do
332344
socket
333345
end
334346

347+
defp assign_async_node_module(%{assigns: %{node_id: node_id, lv_process: %{pid: pid}}} = socket) do
348+
assign_async(socket, :node_module, fn ->
349+
with {:ok, channel_state} <- ChannelService.state(pid),
350+
{:ok, node} <- ChannelService.get_node(channel_state, node_id),
351+
true <- not is_nil(node) do
352+
{:ok, %{node_module: node.module}}
353+
else
354+
err -> err
355+
end
356+
end)
357+
end
358+
335359
defp assign_async_existing_node_ids(socket) do
336360
pid = socket.assigns.lv_process.pid
337361

@@ -388,4 +412,7 @@ defmodule LiveDebuggerWeb.SidebarLive do
388412

389413
send(state.socket.transport_pid, state.serializer.encode!(message))
390414
end
415+
416+
defp node_type(:live_component), do: "LiveComponent"
417+
defp node_type(:live_view), do: "LiveView"
391418
end

0 commit comments

Comments
 (0)