Skip to content

Commit 2b5e5d9

Browse files
authored
Enhancement: global traces preparations (#447)
* Updated trace topics * Added basic global traces view and basic routing * Added navbar and nav menu to global callback traces * Fixed navbar and nav menu * Added selected states to navigation menu * Updated tooltips * Removed dot * Added tooltips for nav menu * Updated `connected` tooltip * Changed loading of connected element * Fixed bug with redirecting with query params * Added test * Changed tooltip designs * Added `take_nth` function * Added tests for take_nth_segment * Fixed bug with switching font-weight of tooltips
1 parent d90a9b4 commit 2b5e5d9

19 files changed

Lines changed: 339 additions & 84 deletions

File tree

assets/css/themes/dark.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
--button-secondary-content: var(--gray-200);
4545
--button-secondary-content-hover: var(--gray-200);
4646

47+
/* Tooltip */
48+
--tooltip-text: var(--gray-900);
49+
--tooltip-bg: var(--swm-sea-blue-60);
50+
4751
/* Icons */
4852
--accent-icon: var(--swm-sea-blue-60);
4953

assets/css/themes/light.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
--button-secondary-content: var(--swm-brand);
4545
--button-secondary-content-hover: var(--swm-brand);
4646

47+
/* Tooltip */
48+
--tooltip-text: var(--neutrals-white);
49+
--tooltip-bg: var(--swm-brand);
50+
4751
/* Icons */
4852
--accent-icon: var(--swm-brand);
4953

assets/js/hooks/tooltip.js

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,53 @@ const Tooltip = {
22
mounted() {
33
this.handleMouseEnter = () => {
44
tooltipEl.style.display = 'block';
5+
tooltipEl.style.fontWeight =
6+
this.el.dataset.variant === 'primary' ? '600' : '400';
57
tooltipEl.innerHTML = this.el.dataset.tooltip;
68

79
const tooltipRect = tooltipEl.getBoundingClientRect();
810
const rect = this.el.getBoundingClientRect();
911

10-
const topOffset =
11-
this.el.dataset.position == 'top'
12-
? rect.top - tooltipRect.height
13-
: rect.bottom;
12+
// Reset any previous positioning
13+
tooltipEl.style.top = '';
14+
tooltipEl.style.left = '';
15+
tooltipEl.style.right = '';
16+
tooltipEl.style.bottom = '';
1417

15-
if (rect.left + tooltipRect.width > window.innerWidth) {
16-
tooltipEl.style.right = `${window.innerWidth - rect.right}px`;
17-
tooltipEl.style.left = 'auto';
18-
} else {
19-
tooltipEl.style.left = `${rect.left}px`;
20-
tooltipEl.style.right = 'auto';
18+
switch (this.el.dataset.position) {
19+
case 'top':
20+
tooltipEl.style.top = `${rect.top - tooltipRect.height}px`;
21+
tooltipEl.style.left = `${rect.left}px`;
22+
break;
23+
case 'bottom':
24+
tooltipEl.style.top = `${rect.bottom}px`;
25+
tooltipEl.style.left = `${rect.left}px`;
26+
break;
27+
case 'left':
28+
tooltipEl.style.left = `${rect.left - tooltipRect.width}px`;
29+
tooltipEl.style.top = `${rect.top + (rect.height - tooltipRect.height) / 2}px`;
30+
break;
31+
case 'right':
32+
tooltipEl.style.left = `${rect.right}px`;
33+
tooltipEl.style.top = `${rect.top + (rect.height - tooltipRect.height) / 2}px`;
34+
break;
35+
}
36+
37+
// Handle horizontal overflow for top/bottom positions
38+
if (['top', 'bottom'].includes(this.el.dataset.position)) {
39+
if (rect.left + tooltipRect.width > window.innerWidth) {
40+
tooltipEl.style.right = `${window.innerWidth - rect.right}px`;
41+
tooltipEl.style.left = 'auto';
42+
}
43+
}
44+
45+
// Handle vertical overflow for left/right positions
46+
if (['left', 'right'].includes(this.el.dataset.position)) {
47+
if (rect.top + tooltipRect.height > window.innerHeight) {
48+
tooltipEl.style.top = `${window.innerHeight - tooltipRect.height}px`;
49+
}
2150
}
2251

23-
tooltipEl.style.top = `${topOffset}px`;
2452
tooltipEl.style.zIndex = 100;
2553
};
2654
this.handleMouseLeave = () => {

assets/tailwind.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ module.exports = {
5252
'button-secondary-content': 'var(--button-secondary-content)',
5353
'button-secondary-content-hover':
5454
'var(--button-secondary-content-hover)',
55+
'tooltip-text': 'var(--tooltip-text)',
56+
'tooltip-bg': 'var(--tooltip-bg)',
5557
'accent-icon': 'var(--accent-icon)',
5658
'sidebar-bg': 'var(--sidebar-bg)',
5759
'code-1': 'var(--code-1)',

lib/live_debugger/gen_servers/callback_tracing_server.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ defmodule LiveDebugger.GenServers.CallbackTracingServer do
211211
fun = trace.function
212212

213213
pid
214-
|> PubSubUtils.trace_topic(node_id, fun, :call)
214+
|> PubSubUtils.trace_topic_per_node(node_id, fun, :call)
215215
|> PubSubUtils.broadcast({:new_trace, trace})
216216
end
217217

@@ -227,7 +227,7 @@ defmodule LiveDebugger.GenServers.CallbackTracingServer do
227227
end
228228

229229
pid
230-
|> PubSubUtils.trace_topic(node_id, fun, :return)
230+
|> PubSubUtils.trace_topic_per_node(node_id, fun, :return)
231231
|> PubSubUtils.broadcast({:updated_trace, trace})
232232
end
233233
end

lib/live_debugger/utils/pubsub.ex

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,25 @@ defmodule LiveDebugger.Utils.PubSub do
7171
7272
Use `{:new_trace, trace}` or `{:updated_trace, trace}` for broadcasting.
7373
"""
74-
@spec trace_topic(
74+
@spec trace_topic_per_node(
7575
pid :: pid(),
7676
node_id :: TreeNode.id(),
7777
fun :: atom(),
7878
type :: :call | :return
7979
) :: String.t()
80-
def trace_topic(pid, node_id, fun, type \\ :call) do
80+
def trace_topic_per_node(pid, node_id, fun, type \\ :call) do
8181
"#{inspect(pid)}/#{inspect(node_id)}/#{inspect(fun)}/#{inspect(type)}"
8282
end
8383

84+
@spec trace_topic_per_pid(
85+
pid :: pid(),
86+
fun :: atom(),
87+
type :: :call | :return
88+
) :: String.t()
89+
def trace_topic_per_pid(pid, fun, type \\ :call) do
90+
"#{inspect(pid)}/#{inspect(fun)}/#{inspect(type)}"
91+
end
92+
8493
@spec impl() :: module()
8594
defp impl() do
8695
Application.get_env(

lib/live_debugger/utils/url.ex

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,20 @@ defmodule LiveDebugger.Utils.URL do
4848
modify_query_params(url, &Map.drop(&1, keys))
4949
end
5050

51+
@spec remove_query_params(url :: String.t()) :: String.t()
52+
def remove_query_params(url) when is_binary(url) do
53+
modify_query_params(url, fn _ -> %{} end)
54+
end
55+
56+
@spec take_nth_segment(url :: String.t(), n :: integer()) :: String.t() | nil
57+
def take_nth_segment(url, n) when is_binary(url) and is_integer(n) do
58+
url
59+
|> to_relative()
60+
|> remove_query_params()
61+
|> String.split("/")
62+
|> Enum.at(n)
63+
end
64+
5165
@spec modify_query_params(url :: String.t(), fun :: (map() -> map())) :: String.t()
5266
def modify_query_params(url, fun) when is_binary(url) and is_function(fun) do
5367
uri = URI.parse(url)

lib/live_debugger_web/components.ex

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,8 @@ defmodule LiveDebuggerWeb.Components do
539539
"""
540540
attr(:id, :string, required: true, doc: "ID of the tooltip. Prefix is added automatically.")
541541
attr(:content, :string, default: nil)
542-
attr(:position, :string, default: "top", values: ["top", "bottom"])
542+
attr(:position, :string, default: "top", values: ["top", "bottom", "left", "right"])
543+
attr(:variant, :string, default: "secondary", values: ["primary", "secondary"])
543544
attr(:rest, :global)
544545
slot(:inner_block, required: true)
545546

@@ -550,6 +551,7 @@ defmodule LiveDebuggerWeb.Components do
550551
phx-hook="Tooltip"
551552
data-tooltip={@content}
552553
data-position={@position}
554+
data-variant={@variant}
553555
{@rest}
554556
>
555557
<%= render_slot(@inner_block) %>
@@ -614,15 +616,25 @@ defmodule LiveDebuggerWeb.Components do
614616
"""
615617
attr(:icon, :string, required: true, doc: "Icon to be displayed.")
616618
attr(:class, :any, default: nil, doc: "Additional classes to add to the nav icon.")
619+
attr(:selected?, :boolean, default: false, doc: "Whether the icon is selected.")
617620

618621
attr(:rest, :global, include: ~w(id))
619622

620623
def nav_icon(assigns) do
624+
selected_class =
625+
if assigns.selected? do
626+
"text-navbar-icon-hover bg-navbar-icon-bg-hover"
627+
else
628+
"text-navbar-icon hover:text-navbar-icon-hover hover:bg-navbar-icon-bg-hover"
629+
end
630+
631+
assigns = assign(assigns, :selected_class, selected_class)
632+
621633
~H"""
622634
<button
623635
aria-label={Parsers.kebab_to_text(@icon)}
624636
class={[
625-
"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"
637+
"w-8! h-8! px-[0.25rem] py-[0.25rem] w-max h-max rounded text-xs font-semibold #{@selected_class}"
626638
| List.wrap(@class)
627639
]}
628640
{@rest}

lib/live_debugger_web/components/navbar.ex

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ defmodule LiveDebuggerWeb.Components.Navbar do
66
use LiveDebuggerWeb, :component
77

88
alias LiveDebuggerWeb.Helpers.RoutesHelper
9+
alias LiveDebugger.Utils.Parsers
910

1011
@doc """
1112
Renders base navbar component.
@@ -83,27 +84,22 @@ defmodule LiveDebuggerWeb.Components.Navbar do
8384
When button is clicked, it will trigger a `find-successor` event with the PID of the LiveView.
8485
"""
8586
attr(:id, :string, required: true)
86-
attr(:connected?, :boolean, required: true, doc: "Whether LiveView is connected.")
87-
attr(:pid, :string, required: true, doc: "The PID of the LiveView.")
87+
attr(:lv_process, :map, required: true, doc: "The LiveView process.")
8888
attr(:rest, :global)
8989

90-
def connected(assigns) do
90+
def connected(%{lv_process: %{ok?: true}} = assigns) do
91+
connected? = assigns.lv_process.result.alive?
92+
status = if(connected?, do: :connected, else: :disconnected)
93+
94+
assigns = assign(assigns, status: status, connected?: connected?)
95+
9196
~H"""
92-
<.tooltip
93-
id={@id}
94-
position="bottom"
95-
content={
96-
if(@connected?,
97-
do: "LiveView process is alive.",
98-
else: "LiveView process is dead. You can still debug the last state."
99-
)
100-
}
101-
>
97+
<.tooltip id={@id} position="bottom" content={tooltip_content(@connected?)}>
10298
<div id={@id} class="flex items-center gap-1 text-xs text-primary ml-1">
103-
<.status_icon connected?={@connected?} />
99+
<.status_icon status={@status} />
104100
<%= if @connected? do %>
105101
<span class="font-medium">Monitored PID </span>
106-
<%= @pid %>
102+
<%= Parsers.pid_to_string(@lv_process.result.pid) %>
107103
<% else %>
108104
<span class="font-medium">Disconnected</span>
109105
<.button phx-click="find-successor" variant="secondary" size="sm">Continue</.button>
@@ -113,19 +109,42 @@ defmodule LiveDebuggerWeb.Components.Navbar do
113109
"""
114110
end
115111

116-
attr(:connected?, :boolean, required: true)
112+
def connected(assigns) do
113+
~H"""
114+
<div id={@id} class="flex items-center gap-1 text-xs text-primary ml-1">
115+
<.status_icon status={:loading} />
116+
<span class="font-medium">Loading LiveView process...</span>
117+
</div>
118+
"""
119+
end
120+
121+
attr(:status, :atom, required: true, values: [:connected, :disconnected, :loading])
117122

118123
defp status_icon(assigns) do
124+
assigns =
125+
case(assigns.status) do
126+
:connected ->
127+
assign(assigns, icon: "icon-check-small", class: "bg-[--swm-green-100]")
128+
129+
:disconnected ->
130+
assign(assigns, icon: "icon-cross-small", class: "bg-[--swm-pink-100]")
131+
132+
:loading ->
133+
assign(assigns, icon: nil, class: "bg-[--swm-yellow-100] animate-pulse")
134+
end
135+
119136
~H"""
120-
<div class={[
121-
"w-4 h-4 rounded-full flex items-center justify-center",
122-
if(@connected?, do: "bg-[--swm-green-100]", else: "bg-[--swm-pink-100]")
123-
]}>
124-
<.icon
125-
name={if(@connected?, do: "icon-check-small", else: "icon-cross-small")}
126-
class="bg-white w-4 h-4"
127-
/>
137+
<div class={["w-4 h-4 rounded-full flex items-center justify-center", @class]}>
138+
<.icon :if={@icon} name={@icon} class="bg-white w-4 h-4" />
128139
</div>
129140
"""
130141
end
142+
143+
defp tooltip_content(true) do
144+
"LiveView process is alive"
145+
end
146+
147+
defp tooltip_content(false) do
148+
"LiveView process is dead - you can still debug the last state"
149+
end
131150
end

0 commit comments

Comments
 (0)