Skip to content

Commit c5cac69

Browse files
authored
Feature: Add highlighting active LiveViews (#878)
* Add highlighting active LiveViews * Refactor getting root_socket_id * Add highlight_in_browser setting and remove highlight toggle in Components Tree * Refactor * Fix and update e2e tests * Disable sending highlight and pulse events when in DeadView mode * Remove unused assign * CR suggestions * Add tests
1 parent 1c9387a commit c5cac69

34 files changed

+494
-233
lines changed

assets/app/hooks/highlight.js

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,40 @@
11
const Highlight = {
22
mounted() {
3-
const highlightSwitch = document.querySelector('#highlight-switch');
4-
let params = {};
3+
this.highlighted = false;
4+
this.liveComponent = this.el.closest('[data-phx-id]');
55

6-
this.pushHighlight = (e) => {
7-
if (highlightSwitch.checked) {
8-
const attr = e.target.attributes;
6+
const attr = this.el.attributes;
97

10-
params = {
11-
'search-attribute': attr['phx-value-search-attribute'].value,
12-
'search-value': attr['phx-value-search-value'].value,
13-
type: attr['phx-value-type'].value,
14-
module: attr['phx-value-module'].value,
15-
id: attr['phx-value-id'].value,
16-
};
8+
this.params = {
9+
'root-socket-id': attr['phx-value-root-socket-id']?.value,
10+
'search-attribute': attr['phx-value-search-attribute']?.value,
11+
'search-value': attr['phx-value-search-value'].value,
12+
type: attr['phx-value-type']?.value,
13+
module: attr['phx-value-module']?.value,
14+
id: attr['phx-value-id']?.value,
15+
};
1716

18-
this.pushEvent('highlight', params);
19-
}
17+
this.pushHighlight = () => {
18+
this.pushEventTo(this.liveComponent, 'highlight', this.params);
19+
this.highlighted = !this.highlighted;
2020
};
2121

22-
if (highlightSwitch) {
23-
this.el.addEventListener('mouseenter', this.pushHighlight);
24-
this.el.addEventListener('mouseleave', this.pushHighlight);
25-
}
22+
this.el.addEventListener('mouseenter', () => {
23+
if (!this.highlighted) this.pushHighlight();
24+
});
25+
this.el.addEventListener('mouseleave', () => {
26+
if (this.highlighted) this.pushHighlight();
27+
});
2628
},
2729
destroyed() {
2830
this.el.removeEventListener('mouseenter', this.pushHighlight);
2931
this.el.removeEventListener('mouseleave', this.pushHighlight);
32+
33+
setTimeout(() => {
34+
if (this.highlighted && this.liveComponent.checkVisibility()) {
35+
this.pushHighlight();
36+
}
37+
}, 200);
3038
},
3139
};
3240

lib/live_debugger/api/live_view_discovery.ex

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ defmodule LiveDebugger.API.LiveViewDiscovery do
1313
@callback lv_processes() :: [LvProcess.t()]
1414
@callback children_lv_processes(pid(), searched_lv_processes :: [LvProcess.t()] | nil) ::
1515
[LvProcess.t()]
16+
@callback get_root_socket_id(LvProcess.t()) :: String.t() | nil
1617

1718
@doc """
1819
Returns all debugged LvProcesses.
@@ -66,6 +67,11 @@ defmodule LiveDebugger.API.LiveViewDiscovery do
6667
impl().children_lv_processes(pid, searched_lv_processes)
6768
end
6869

70+
@spec get_root_socket_id(LvProcess.t()) :: LvProcess.t()
71+
def get_root_socket_id(lv_process) do
72+
impl().get_root_socket_id(lv_process)
73+
end
74+
6975
defp impl() do
7076
Application.get_env(
7177
:live_debugger,
@@ -161,5 +167,35 @@ defmodule LiveDebugger.API.LiveViewDiscovery do
161167
end)
162168
|> List.flatten()
163169
end
170+
171+
@impl true
172+
def get_root_socket_id(%LvProcess{embedded?: false, nested?: false} = lv_process) do
173+
lv_process.socket_id
174+
end
175+
176+
def get_root_socket_id(%LvProcess{embedded?: true, nested?: false} = lv_process) do
177+
case find_root_lv_process_over_transport_pid(lv_process.transport_pid) do
178+
%LvProcess{socket_id: socket_id} -> socket_id
179+
_ -> lv_process.socket_id
180+
end
181+
end
182+
183+
def get_root_socket_id(lv_process) do
184+
lv_process.root_pid
185+
|> lv_process()
186+
|> case do
187+
%LvProcess{embedded?: false} = lv_process -> lv_process.socket_id
188+
%LvProcess{embedded?: true, nested?: false} = lv_process -> get_root_socket_id(lv_process)
189+
_ -> nil
190+
end
191+
end
192+
193+
def find_root_lv_process_over_transport_pid(transport_pid) do
194+
debugged_lv_processes()
195+
|> Enum.find(fn
196+
%LvProcess{transport_pid: ^transport_pid, embedded?: false, nested?: false} -> true
197+
_ -> false
198+
end)
199+
end
164200
end
165201
end

lib/live_debugger/api/settings_storage.ex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ defmodule LiveDebugger.API.SettingsStorage do
44
:garbage_collection,
55
:debug_button,
66
:tracing_enabled_on_start,
7-
:dead_liveviews
7+
:dead_liveviews,
8+
:highlight_in_browser
89
]
910

1011
@moduledoc """
@@ -79,7 +80,8 @@ defmodule LiveDebugger.API.SettingsStorage do
7980
garbage_collection: true,
8081
debug_button: true,
8182
tracing_enabled_on_start: true,
82-
dead_liveviews: false
83+
dead_liveviews: false,
84+
highlight_in_browser: true
8385
}
8486

8587
@table_name :lvdbg_settings

lib/live_debugger/app/debugger/components_tree/web/components_tree_live.ex

Lines changed: 22 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ defmodule LiveDebugger.App.Debugger.ComponentsTree.Web.ComponentsTreeLive do
77

88
require Logger
99

10+
alias LiveDebugger.API.SettingsStorage
1011
alias LiveDebugger.Client
1112
alias LiveDebugger.App.Utils.URL
1213
alias LiveDebugger.Structs.LvProcess
@@ -33,7 +34,6 @@ defmodule LiveDebugger.App.Debugger.ComponentsTree.Web.ComponentsTreeLive do
3334
attr(:id, :string, required: true)
3435
attr(:socket, Phoenix.LiveView.Socket, required: true)
3536
attr(:lv_process, LvProcess, required: true)
36-
attr(:root_socket_id, :string, required: true)
3737
attr(:node_id, :any, required: true)
3838
attr(:url, :string, required: true)
3939
attr(:class, :string, default: "", doc: "CSS class for the wrapper div")
@@ -42,7 +42,6 @@ defmodule LiveDebugger.App.Debugger.ComponentsTree.Web.ComponentsTreeLive do
4242
session = %{
4343
"lv_process" => assigns.lv_process,
4444
"node_id" => assigns.node_id,
45-
"root_socket_id" => assigns.root_socket_id,
4645
"url" => assigns.url,
4746
"parent_pid" => self()
4847
}
@@ -68,10 +67,7 @@ defmodule LiveDebugger.App.Debugger.ComponentsTree.Web.ComponentsTreeLive do
6867
|> assign(lv_process: lv_process)
6968
|> assign(parent_pid: parent_pid)
7069
|> assign(node_id: session["node_id"])
71-
|> assign(root_socket_id: session["root_socket_id"])
7270
|> assign(url: session["url"])
73-
|> assign(highlight?: false)
74-
|> assign(highlight_disabled?: !lv_process.alive?)
7571
|> assign_async_tree()
7672
|> ok()
7773
end
@@ -89,14 +85,6 @@ defmodule LiveDebugger.App.Debugger.ComponentsTree.Web.ComponentsTreeLive do
8985
<div class="min-h-20 px-1 overflow-y-auto overflow-x-hidden flex flex-col">
9086
<div class="flex items-center justify-between">
9187
<div class="shrink-0 font-medium text-secondary-text px-6 py-3">Components Tree</div>
92-
<.toggle_switch
93-
:if={LiveDebugger.Feature.enabled?(:browser_features?)}
94-
id="highlight-switch"
95-
label="Highlight"
96-
checked={@highlight?}
97-
phx-click="toggle-highlight"
98-
disabled={@highlight_disabled?}
99-
/>
10088
</div>
10189
<div class="flex-1">
10290
<TreeComponents.tree_node
@@ -112,12 +100,6 @@ defmodule LiveDebugger.App.Debugger.ComponentsTree.Web.ComponentsTreeLive do
112100
end
113101

114102
@impl true
115-
def handle_event("toggle-highlight", _params, socket) do
116-
socket
117-
|> update(:highlight?, &(not &1))
118-
|> noreply()
119-
end
120-
121103
def handle_event("highlight", params, socket) do
122104
socket
123105
|> highlight_element(params)
@@ -128,7 +110,6 @@ defmodule LiveDebugger.App.Debugger.ComponentsTree.Web.ComponentsTreeLive do
128110
socket
129111
|> pulse_element(params)
130112
|> push_patch(to: URL.upsert_query_param(socket.assigns.url, "node_id", node_id))
131-
|> assign(:highlight?, false)
132113
|> noreply()
133114
end
134115

@@ -165,58 +146,49 @@ defmodule LiveDebugger.App.Debugger.ComponentsTree.Web.ComponentsTreeLive do
165146
%{assigns: %{parent_pid: pid}} = socket
166147
) do
167148
socket
168-
|> assign(highlight_disabled?: true)
169-
|> assign(highlight?: false)
149+
|> assign(lv_process: socket.assigns.lv_process |> LvProcess.set_alive(false))
170150
|> noreply()
171151
end
172152

153+
def handle_info(_, socket), do: {:noreply, socket}
154+
173155
defp assign_async_tree(socket) do
174156
pid = socket.assigns.lv_process.pid
175157
assign_async(socket, [:tree], fn -> ComponentsTreeQueries.fetch_components_tree(pid) end)
176158
end
177159

178-
defp highlight_element(
179-
%{assigns: %{highlight_disabled?: false, highlight?: true}} = socket,
180-
params
181-
) do
182-
payload = %{
183-
attr: params["search-attribute"],
184-
val: params["search-value"],
185-
type: if(params["type"] == "live_view", do: "LiveView", else: "LiveComponent"),
186-
module: Parsers.module_to_string(params["module"]),
187-
id_value: params["id"],
188-
id_key: if(params["type"] == "live_view", do: "PID", else: "CID")
189-
}
190-
191-
Client.push_event!(socket.assigns.root_socket_id, "highlight", payload)
192-
193-
socket
194-
end
160+
defp highlight_element(%{assigns: %{lv_process: %LvProcess{alive?: true}}} = socket, params) do
161+
if SettingsStorage.get(:highlight_in_browser) do
162+
payload = %{
163+
attr: params["search-attribute"],
164+
val: params["search-value"],
165+
type: if(params["type"] == "live_view", do: "LiveView", else: "LiveComponent"),
166+
module: Parsers.module_to_string(params["module"]),
167+
id_value: params["id"],
168+
id_key: if(params["type"] == "live_view", do: "PID", else: "CID")
169+
}
195170

196-
defp highlight_element(socket, _) do
197-
socket
198-
end
171+
Client.push_event!(socket.assigns.lv_process.root_socket_id, "highlight", payload)
172+
end
199173

200-
defp pulse_element(%{assigns: %{highlight_disabled?: true}} = socket, _) do
201174
socket
202175
end
203176

204-
defp pulse_element(socket, params) do
205-
if LiveDebugger.Feature.enabled?(:browser_features?) do
206-
# Resets the highlight when the user selects node
207-
if socket.assigns.highlight? do
208-
Client.push_event!(socket.assigns.root_socket_id, "highlight")
209-
end
177+
defp highlight_element(socket, _), do: socket
210178

179+
defp pulse_element(%{assigns: %{lv_process: %LvProcess{alive?: true}}} = socket, params) do
180+
if SettingsStorage.get(:highlight_in_browser) do
211181
payload = %{
212182
attr: params["search-attribute"],
213183
val: params["search-value"],
214184
type: if(params["type"] == "live_view", do: "LiveView", else: "LiveComponent")
215185
}
216186

217-
Client.push_event!(socket.assigns.root_socket_id, "pulse", payload)
187+
Client.push_event!(socket.assigns.lv_process.root_socket_id, "pulse", payload)
218188
end
219189

220190
socket
221191
end
192+
193+
defp pulse_element(socket, _), do: socket
222194
end

lib/live_debugger/app/debugger/web/components/pages.ex

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ defmodule LiveDebugger.App.Debugger.Web.Components.Pages do
3030
attr(:lv_process, LvProcess, required: true)
3131
attr(:url, :string, required: true)
3232
attr(:node_id, :any, required: true)
33-
attr(:root_socket_id, :string, required: true)
3433
attr(:return_link, :string, required: true)
3534
attr(:inspect_mode?, :boolean, required: true)
3635

@@ -97,7 +96,6 @@ defmodule LiveDebugger.App.Debugger.Web.Components.Pages do
9796
id="components-tree"
9897
lv_process={@lv_process}
9998
socket={@socket}
100-
root_socket_id={@root_socket_id}
10199
node_id={@node_id}
102100
url={@url}
103101
class="overflow-x-hidden"

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ defmodule LiveDebugger.App.Debugger.Web.DebuggerLive do
9393
lv_process={lv_process}
9494
url={@url}
9595
node_id={@node_id}
96-
root_socket_id={@root_socket_id}
9796
inspect_mode?={@inspect_mode?}
9897
return_link={RoutesHelper.discovery()}
9998
/>

lib/live_debugger/app/debugger/web/hook_components/inspect_button.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ defmodule LiveDebugger.App.Debugger.Web.HookComponents.InspectButton do
4747
end
4848

4949
defp handle_info(%DeadViewModeEntered{debugger_pid: pid}, socket) when pid == self() do
50-
Client.push_event!(socket.assigns.root_socket_id, "inspect-mode-changed", %{
50+
Client.push_event!(socket.assigns.lv_process.result.root_socket_id, "inspect-mode-changed", %{
5151
inspect_mode: false,
5252
pid: inspect(self())
5353
})
@@ -93,7 +93,7 @@ defmodule LiveDebugger.App.Debugger.Web.HookComponents.InspectButton do
9393
defp handle_event(_, _, socket), do: {:cont, socket}
9494

9595
defp switch_inspect_mode(socket) do
96-
Client.push_event!(socket.assigns.root_socket_id, "inspect-mode-changed", %{
96+
Client.push_event!(socket.assigns.lv_process.result.root_socket_id, "inspect-mode-changed", %{
9797
inspect_mode: !socket.assigns.inspect_mode?,
9898
pid: inspect(self())
9999
})

0 commit comments

Comments
 (0)