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
6 changes: 6 additions & 0 deletions assets/app/hooks/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,20 @@ const Tooltip = {
tooltipEl.style.display = 'none';
};

this.handleScroll = () => {
tooltipEl.style.display = 'none';
Comment thread
srzeszut marked this conversation as resolved.
};

this.el.addEventListener('mouseenter', this.handleMouseEnter);
this.el.addEventListener('mouseleave', this.handleMouseLeave);
window.addEventListener('scroll', this.handleScroll, true);
},
destroyed() {
clearTimeout(this._hoverTimeout);
document.querySelector('#tooltip').style.display = 'none';
this.el.removeEventListener('mouseenter', this.handleMouseEnter);
this.el.removeEventListener('mouseleave', this.handleMouseLeave);
window.removeEventListener('scroll', this.handleScroll, true);
},
};

Expand Down
4 changes: 4 additions & 0 deletions dev/live_views/main.ex
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ defmodule LiveDebuggerDev.LiveViews.Main do
{:noreply, assign(socket, :message, %{name: "message name", text: "some text"})}
end

Comment thread
srzeszut marked this conversation as resolved.
def handle_event("increment", _, socket) when is_binary(socket) do
{:noreply, update(socket, :counter, &(&1 + 1))}
end

def handle_event("increment", _, socket) do
{:noreply, update(socket, :counter, &(&1 + 1))}
end
Expand Down
1 change: 1 addition & 0 deletions e2e/tests/async-jobs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ test('user can see and track async jobs in LiveView and LiveComponent', async ({
'No active async jobs found'
);

await devApp.locator('#component-long-load-toggle').click();
await devApp.locator('#component-start-cancelable-async-button').click();
await expect(
asyncJobName(dbgApp, ':component_cancelable_fetch')
Expand Down
5 changes: 3 additions & 2 deletions e2e/tests/elements-inspection.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
expect,
findNodeModuleInfo,
findSidebarBasicInfo,
prepareDevDebuggerPairTest,
getDevPid,
Page,
Expand Down Expand Up @@ -42,7 +43,7 @@ const selectLiveViewByPid = async (dbgApp: Page, pid: string) => {
);
await btn.hover();
await btn.click();
await expect(findNodeModuleInfo(dbgApp)).toBeVisible();
await expect(findSidebarBasicInfo(dbgApp)).toBeVisible();
};

const openDbgForLiveView = async (
Expand All @@ -67,7 +68,7 @@ const openMobileDbgForLiveView = async (
);
await btn.hover();
await btn.click();
await expect(findNodeModuleInfo(dbgApp)).toBeVisible();
await expect(findSidebarBasicInfo(dbgApp)).toBeVisible();
return dbgApp;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Structs.TraceDisplay do
:body,
:side_section_left,
:side_section_right,
:error
:error,
:source
]

@type type() :: :normal | :diff | :error
Expand All @@ -44,7 +45,8 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Structs.TraceDisplay do
body: list({String.t(), term()}),
side_section_left: side_section_left(),
side_section_right: side_section_right(),
error: ErrorTrace.t() | nil
error: ErrorTrace.t() | nil,
source: FunctionTrace.SourceLocation.t() | nil
}

@spec from_trace(Trace.t(), boolean()) :: t()
Expand All @@ -60,7 +62,8 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Structs.TraceDisplay do
body: get_body(trace),
side_section_left: get_side_section_left(trace),
side_section_right: get_side_section_right(trace),
error: get_error(trace)
error: get_error(trace),
source: get_source(trace)
}
end

Expand Down Expand Up @@ -121,4 +124,8 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Structs.TraceDisplay do
defp get_error(%FunctionTrace{error: error}), do: error

defp get_error(_), do: nil

defp get_source(%FunctionTrace{source: source}), do: source

defp get_source(_), do: nil
end
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,57 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.Components.Trace do

alias LiveDebugger.Structs.Trace.ErrorTrace

alias LiveDebugger.App.Debugger.Utils.Editor
alias Phoenix.LiveView.JS

@doc """
Button to open the trace source in an external editor.
"""
attr(:id, :string, required: true)
attr(:elixir_editor, :string, default: nil)
attr(:source, SourceLocation, default: nil)
attr(:fullscreen?, :boolean, default: false)

def open_in_editor_button(assigns) do
assigns = assign(assigns, :editor_docs_url, Editor.editor_docs_url())

~H"""
<.tooltip
:if={@source}
id={@id <> "-open-in-editor-tooltip"}
class="my-2"
content={
if(@elixir_editor,
do: "Open in editor",
else: "Editor not configured. Click for setup instructions."
)
}
position="top-center"
fullscreen?={@fullscreen?}
>
<.icon_button
:if={@elixir_editor}
id={"#{@id}-open-in-editor-button"}
icon="icon-external-link"
phx-click="open-in-editor"
phx-value-file={@source.source_file}
phx-value-line={@source.line}
variant="secondary"
/>
<.button_link
:if={@elixir_editor == nil}
href={@editor_docs_url}
id={"#{@id}-open-in-editor"}
variant="secondary"
size="sm"
class="opacity-50 cursor-pointer"
>
<.icon name="icon-external-link" class="w-4 h-4" />
</.button_link>
</.tooltip>
"""
end

@doc """
Displays the label of the trace with a polymorphic composition.
"""
Expand Down Expand Up @@ -106,6 +155,7 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.Components.Trace do
attr(:trace_display, TraceDisplay, required: true)
attr(:search_phrase, :string, required: true)
attr(:fullscreen?, :boolean, default: false)
attr(:elixir_editor, :string, default: nil)

def trace_body_navbar_wrapper(assigns) do
assigns =
Expand Down Expand Up @@ -133,6 +183,7 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.Components.Trace do
"peer-checked/content:[&_.tab-content]:text-navbar-selected-bg peer-checked/content:[&_.tab-content]:border-navbar-selected-bg",
"peer-checked/stack:[&_.tab-stack]:text-navbar-selected-bg peer-checked/stack:[&_.tab-stack]:border-navbar-selected-bg",
"peer-checked/raw:[&_.tab-raw]:text-navbar-selected-bg peer-checked/raw:[&_.tab-raw]:border-navbar-selected-bg",
"peer-checked/content:[&_.editor-btn-content]:block",
"peer-checked/stack:[&_.copy-btn-stack]:block",
"peer-checked/raw:[&_.copy-btn-raw]:block"
]}>
Expand Down Expand Up @@ -183,6 +234,15 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.Components.Trace do
/>
</div>

<div class="editor-btn-content hidden">
<.open_in_editor_button
id={@id}
elixir_editor={@elixir_editor}
source={@trace_display.source}
fullscreen?={@fullscreen?}
/>
</div>

<.fullscreen_button
id={"trace-fullscreen-#{@id}"}
class="m-2"
Expand Down Expand Up @@ -237,6 +297,7 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.Components.Trace do
attr(:displayed_trace, TraceDisplay, required: true)
attr(:search_phrase, :string, required: true)
attr(:page, :atom, required: true, values: [:node_inspector, :global_callbacks])
attr(:elixir_editor, :string, default: nil)

def trace_fullscreen(assigns) do
~H"""
Expand All @@ -261,16 +322,31 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.Components.Trace do
/>
</div>
</:header>
<div class={[
"flex flex-col gap-4 items-start justify-center hover:[&>div>div>div>button]:hidden",
if(is_nil(@displayed_trace.error), do: "p-4", else: "[&>div>div>div>div>button]:hidden")
]}>
<.trace_body_navbar_wrapper
id={@id <> "-fullscreen"}
trace_display={@displayed_trace}
search_phrase={@search_phrase}
fullscreen?={true}
/>

<div class="relative">
<div
:if={is_nil(@displayed_trace.error)}
class="absolute right-4 top-0 z-10"
>
<.open_in_editor_button
id={@id <> "-fullscreen"}
elixir_editor={@elixir_editor}
source={@displayed_trace.source}
fullscreen?={true}
/>
</div>
<div class={[
"max-h-[70vh] overflow-y-auto overflow-x-auto flex flex-col gap-4 items-start justify-center hover:[&>div>div>div>button]:hidden",
if(is_nil(@displayed_trace.error), do: "p-4", else: "[&>div>div>div>div>button]:hidden")
]}>
<.trace_body_navbar_wrapper
id={@id <> "-fullscreen"}
trace_display={@displayed_trace}
search_phrase={@search_phrase}
fullscreen?={true}
elixir_editor={@elixir_editor}
/>
</div>
</div>
</.fullscreen>
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.GlobalTracesLive do
alias LiveDebugger.Services.ProcessMonitor.Events.LiveComponentCreated
alias LiveDebugger.Services.ProcessMonitor.Events.LiveComponentDeleted
alias LiveDebugger.App.Debugger.CallbackTracing.Web.LiveComponents.FiltersForm
alias LiveDebugger.App.Debugger.Utils.Editor

@live_stream_limit 128
@page_size 25
Expand Down Expand Up @@ -97,7 +98,8 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.GlobalTracesLive do
node_id: nil,
url: url,
inspect_mode?: inspect_mode?,
return_link: return_link
return_link: return_link,
elixir_editor: Editor.detect_editor()
)
|> stream(:existing_traces, [], reset: true)
|> put_private(:page_size, @page_size)
Expand Down Expand Up @@ -168,7 +170,11 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.GlobalTracesLive do
existing_traces={@streams.existing_traces}
>
<:trace :let={{id, trace_display}}>
<HookComponents.TraceWrapper.render id={id} trace_display={trace_display}>
<HookComponents.TraceWrapper.render
id={id}
trace_display={trace_display}
elixir_editor={@elixir_editor}
>
<:label>
<.trace_label
id={id <> "-label"}
Expand All @@ -184,6 +190,7 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.GlobalTracesLive do
id={id <> "-body"}
trace_display={trace_display}
search_phrase={@trace_search_phrase}
elixir_editor={@elixir_editor}
/>
</:body>
</HookComponents.TraceWrapper.render>
Expand All @@ -199,6 +206,7 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.GlobalTracesLive do
displayed_trace={@displayed_trace}
search_phrase={@trace_search_phrase}
page={:global_callbacks}
elixir_editor={@elixir_editor}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,17 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.HookComponents.TraceWrap

import LiveDebugger.App.Web.Hooks.Flash, only: [push_flash: 4]

import LiveDebugger.App.Debugger.CallbackTracing.Web.Components.Trace,
only: [open_in_editor_button: 1]

alias LiveDebugger.API.TracesStorage
alias LiveDebugger.App.Debugger.CallbackTracing.Structs.TraceDisplay
alias LiveDebugger.App.Debugger.Utils.Editor
alias LiveDebugger.Utils.FunctionMatcher
alias LiveDebugger.Services.CallbackTracer.Actions.FunctionTrace
alias LiveDebugger.Structs.Trace.DiffTrace

@required_assigns [:lv_process, :displayed_trace, :parent_pid]
@required_assigns [:lv_process, :displayed_trace, :parent_pid, :elixir_editor]
@trace_not_found_close_delay_ms 200

@impl true
Expand All @@ -38,6 +45,7 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.HookComponents.TraceWrap

attr(:id, :string, required: true)
attr(:trace_display, TraceDisplay, required: true)
attr(:elixir_editor, :string, default: nil)

slot(:body, required: true)
slot(:label, required: true)
Expand Down Expand Up @@ -66,12 +74,20 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.HookComponents.TraceWrap
:if={@trace_display.render_body? && is_nil(@trace_display.error)}
class="absolute right-0 top-0 z-10"
>
<.fullscreen_button
id={"trace-fullscreen-#{@id}"}
class="m-2"
phx-click="open-trace"
phx-value-trace-id={@trace_display.id}
/>
<div class="flex flex-row">
<.open_in_editor_button
id={@id}
elixir_editor={@elixir_editor}
source={@trace_display.source}
/>

<.fullscreen_button
id={"trace-fullscreen-#{@id}"}
class="m-2"
phx-click="open-trace"
phx-value-trace-id={@trace_display.id}
/>
</div>
</div>
<div class={[
"overflow-x-auto max-w-full max-h-[30vh] overflow-y-auto",
Expand Down Expand Up @@ -119,12 +135,28 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.HookComponents.TraceWrap
handle_trace_not_found(string_trace_id)
socket

diff_trace = %DiffTrace{} ->
stream_insert_trace(socket, diff_trace, !render_body?)

trace ->
trace = maybe_resolve_and_persist_source(trace)
stream_insert_trace(socket, trace, !render_body?)
end
|> halt()
end

defp handle_event("open-in-editor", %{"file" => file, "line" => line}, socket) do
Editor.open_in_editor(
socket.assigns.elixir_editor,
file,
String.to_integer(line),
socket.assigns.parent_pid
)

socket
|> halt()
end

defp handle_event(_, _, socket), do: {:cont, socket}

defp handle_info({:trace_wrapper_not_found, string_trace_id}, socket) do
Expand All @@ -136,6 +168,22 @@ defmodule LiveDebugger.App.Debugger.CallbackTracing.Web.HookComponents.TraceWrap

defp handle_info(_, socket), do: {:cont, socket}

defp maybe_resolve_and_persist_source(
%{source: nil, module: module, function: function, args: args} = trace
) do
case FunctionMatcher.find_matching_clause_line(module, function, args) do
{:ok, source} ->
new_trace = %{trace | source: source}
FunctionTrace.persist_trace(new_trace)
new_trace

_ ->
trace
end
end

defp maybe_resolve_and_persist_source(trace), do: trace

defp get_trace(socket, string_trace_id) do
TracesStorage.get_by_id!(socket.assigns.lv_process.pid, String.to_integer(string_trace_id))
end
Expand Down
Loading
Loading