Skip to content

Commit ed398fd

Browse files
authored
Enhancement: Create form for filtering by execution time (#361)
* Add input component * Add form inputs for filtering by execution time * Rename * Refactor * Change micro symbol rendering * Refactor input component * Add form validation
1 parent 6eef997 commit ed398fd

4 files changed

Lines changed: 131 additions & 27 deletions

File tree

lib/live_debugger_web/components.ex

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

66
use Phoenix.Component
77

8+
import Phoenix.HTML
9+
810
alias Phoenix.LiveView.JS
911
alias LiveDebuggerWeb.Helpers.RoutesHelper
1012

@@ -72,6 +74,50 @@ defmodule LiveDebuggerWeb.Components do
7274
"""
7375
end
7476

77+
@doc """
78+
Renders an input with label.
79+
"""
80+
attr(:field, Phoenix.HTML.FormField, required: true)
81+
attr(:label_text, :string, default: nil)
82+
attr(:label_raw, :boolean, default: false)
83+
attr(:type, :string, default: "text")
84+
85+
attr(:wrapper_class, :any, default: nil)
86+
attr(:input_class, :any, default: nil)
87+
attr(:label_class, :any, default: nil)
88+
attr(:rest, :global, include: ~w(min max))
89+
90+
def input(assigns) do
91+
assigns =
92+
assigns
93+
|> assign(:errors, assigns.field.errors)
94+
95+
~H"""
96+
<div phx-feedback-for={@field.name} class={["" | List.wrap(@wrapper_class)]}>
97+
<label for={@field.id} class={["block font-medium text-xs" | List.wrap(@label_class)]}>
98+
<%= if @label_raw, do: raw(@label_text), else: @label_text %>
99+
</label>
100+
<input
101+
type={@type}
102+
name={@field.name}
103+
id={@field.id}
104+
value={Phoenix.HTML.Form.normalize_value(@type, @field.value)}
105+
class={[
106+
"mt-2 block w-full rounded-lg bg-surface-1-bg focus:ring-0 text-xs",
107+
"phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400",
108+
@errors == [] && "border-default-border focus:border-secondary-text",
109+
@errors != [] && "border-error-text focus:border-error-text"
110+
| List.wrap(@input_class)
111+
]}
112+
{@rest}
113+
/>
114+
<p :for={msg <- @errors} class="mt-2 block text-error-text">
115+
<%= msg %>
116+
</p>
117+
</div>
118+
"""
119+
end
120+
75121
@doc """
76122
Renders a button.
77123

lib/live_debugger_web/helpers/tracing_helper.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ defmodule LiveDebuggerWeb.Helpers.TracingHelper do
138138
lv_process = socket.assigns.lv_process
139139
node_id = socket.assigns.node_id
140140

141-
socket.assigns.current_filters
141+
socket.assigns.current_filters.functions
142142
|> Enum.filter(fn {_, active?} -> active? end)
143143
|> Enum.flat_map(fn {function, _} ->
144144
[
@@ -164,7 +164,7 @@ defmodule LiveDebuggerWeb.Helpers.TracingHelper do
164164
lv_process = socket.assigns.lv_process
165165
node_id = socket.assigns.node_id
166166

167-
socket.assigns.current_filters
167+
socket.assigns.current_filters.functions
168168
|> Enum.map(fn {function, _} ->
169169
PubSubUtils.trace_topic(
170170
lv_process.socket_id,

lib/live_debugger_web/live/traces_live.ex

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -398,17 +398,26 @@ defmodule LiveDebuggerWeb.TracesLive do
398398
end
399399

400400
defp default_filters(node_id) do
401-
node_id
402-
|> TreeNode.type()
403-
|> case do
404-
:live_view -> UtilsCallbacks.live_view_callbacks()
405-
:live_component -> UtilsCallbacks.live_component_callbacks()
406-
end
407-
|> Enum.map(fn {function, _} -> {function, true} end)
401+
functions =
402+
node_id
403+
|> TreeNode.type()
404+
|> case do
405+
:live_view -> UtilsCallbacks.live_view_callbacks()
406+
:live_component -> UtilsCallbacks.live_component_callbacks()
407+
end
408+
|> Enum.map(fn {function, _} -> {function, true} end)
409+
410+
%{
411+
functions: functions,
412+
execution_time: [
413+
{:exec_time_max, ""},
414+
{:exec_time_min, "0"}
415+
]
416+
}
408417
end
409418

410419
defp get_active_functions(socket) do
411-
socket.assigns.current_filters
420+
socket.assigns.current_filters.functions
412421
|> Enum.filter(fn {_, active?} -> active? end)
413422
|> Enum.map(fn {function, _} -> function end)
414423
end

lib/live_debugger_web/live_components/filters_form.ex

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ defmodule LiveDebuggerWeb.LiveComponents.FiltersForm do
2121

2222
@impl true
2323
def render(assigns) do
24-
assigns = assign(assigns, :selected_filters_number, calculate_selected_filters(assigns.form))
24+
assigns =
25+
assign(assigns, :selected_filters_number, calculate_selected_filters(assigns.form))
2526

2627
~H"""
2728
<div id={@id <> "-wrapper"}>
@@ -34,6 +35,23 @@ defmodule LiveDebuggerWeb.LiveComponents.FiltersForm do
3435
<.checkbox field={@form[function]} label={"#{function}/#{arity}"} />
3536
<% end %>
3637
</div>
38+
<p class="font-medium mb-4 mt-6">Callback execution time</p>
39+
<div class="flex flex-col gap-3">
40+
<.input
41+
label_text="max [&micro;s]"
42+
label_raw
43+
field={@form[:exec_time_max]}
44+
type="number"
45+
min="0"
46+
/>
47+
<.input
48+
label_text="min [&micro;s]"
49+
label_raw
50+
field={@form[:exec_time_min]}
51+
type="number"
52+
min="0"
53+
/>
54+
</div>
3755
</div>
3856
<div class="flex py-3 px-4 border-t border-default-border items-center justify-between">
3957
<button
@@ -59,20 +77,31 @@ defmodule LiveDebuggerWeb.LiveComponents.FiltersForm do
5977

6078
@impl true
6179
def handle_event("submit", params, socket) do
62-
filters = update_filters(socket.assigns.active_filters, params)
80+
case update_filters(socket.assigns.active_filters, params) do
81+
{:ok, filters} ->
82+
send(self(), {:filters_updated, filters})
6383

64-
send(self(), {:filters_updated, filters})
84+
_ ->
85+
nil
86+
end
6587

66-
{:noreply, socket}
88+
socket
89+
|> noreply()
6790
end
6891

6992
@impl true
7093
def handle_event("change", params, socket) do
71-
filters = update_filters(socket.assigns.active_filters, params)
94+
case update_filters(socket.assigns.active_filters, params) do
95+
{:ok, filters} ->
96+
socket
97+
|> assign_form(filters)
98+
|> noreply()
7299

73-
socket
74-
|> assign_form(filters)
75-
|> noreply()
100+
{:error, errors} ->
101+
socket
102+
|> assign(form: to_form(params, errors: errors))
103+
|> noreply()
104+
end
76105
end
77106

78107
@impl true
@@ -82,11 +111,11 @@ defmodule LiveDebuggerWeb.LiveComponents.FiltersForm do
82111
|> noreply()
83112
end
84113

85-
def assign_form(socket, filters) do
114+
def assign_form(socket, %{functions: functions, execution_time: execution_time}) do
86115
form =
87-
filters
88-
|> Enum.reduce(%{}, fn {function, active}, acc ->
89-
Map.put(acc, Atom.to_string(function), active)
116+
(functions ++ execution_time)
117+
|> Enum.reduce(%{}, fn {filter, value}, acc ->
118+
Map.put(acc, Atom.to_string(filter), value)
90119
end)
91120
|> to_form()
92121

@@ -103,15 +132,35 @@ defmodule LiveDebuggerWeb.LiveComponents.FiltersForm do
103132
end
104133

105134
defp update_filters(active_filters, params) do
106-
active_filters
107-
|> Enum.map(fn {function, _} ->
108-
{function, Map.has_key?(params, Atom.to_string(function))}
109-
end)
135+
functions =
136+
active_filters.functions
137+
|> Enum.map(fn {function, _} ->
138+
{function, Map.has_key?(params, Atom.to_string(function))}
139+
end)
140+
141+
execution_time =
142+
active_filters.execution_time
143+
|> Enum.map(fn {filter, value} ->
144+
{filter, Map.get(params, Atom.to_string(filter), value)}
145+
end)
146+
147+
min_time = Keyword.get(execution_time, :exec_time_min, 0)
148+
max_time = Keyword.get(execution_time, :exec_time_max, :infinity)
149+
150+
if String.to_integer(min_time) > String.to_integer(max_time) do
151+
{:error, [exec_time_min: "min must be less than max", exec_time_max: ""]}
152+
else
153+
{:ok, %{functions: functions, execution_time: execution_time}}
154+
end
110155
end
111156

112157
defp calculate_selected_filters(form) do
158+
callbacks =
159+
UtilsCallbacks.callbacks_functions()
160+
|> Enum.map(&Atom.to_string/1)
161+
113162
form.params
114-
|> Map.values()
163+
|> Enum.filter(fn {name, value} -> Enum.member?(callbacks, name) && value end)
115164
|> Enum.count(&Function.identity/1)
116165
end
117166
end

0 commit comments

Comments
 (0)