I have created a function component, <.inspector />
, that fires an event. inspect-source
.
defmodule DerpyToolsWeb.DevComponents do
@moduledoc """
Useful component for development.
Can be embedded into other components, which will allow developers to open
the source code of the component directly from browser.
"""
use Phoenix.Component
def inspector(assigns) do
~H"""
<div class="absolute -top-10 flex justify-end w-full">
<%!-- To link directly to the storybook page! --%>
<button class="rounded-tl-lg rounded-bl-lg p-2 bg-slate-100 m-0" title="Show in Catalog">
<Heroicons.eye solid class="h-3 w-3 text-gray-500" />
</button>
<button
phx-click="inspect-source"
phx-value-file={@file}
phx-value-line={@line}
class="-ml-1 rounded-tr-lg rounded-br-lg p-2 bg-slate-100 m-0 border-l border-slate-200"
title="Open in VS Code"
>
<Heroicons.code_bracket solid class="h-3 w-3 text-gray-500" />
</button>
</div>
"""
end
end
Add the component to the html_helpers
function, so we won’t have to import it again and again:
defp html_helpers do
quote do
...
# Custom Dev Components
import DerpyToolsWeb.DevComponents
...
end
end
Then place the inspector component anywhere and when we click on inspect source button, the file opens up appropriately in the code editor.
<div class="w-60 m-auto relative">
<.inspector :if={Mix.env() == :dev} file={__ENV__.file} line={__ENV__.line} />
</div>
Instead of writing the handle_event
function in every component, where I wish to add the <.inspector />
, I just created a module to hold the common handle_event callbacks.
scope "/", DerpyToolsWeb do
pipe_through([:browser])
live_session :no_log_in_required,
on_mount: [DerpyToolsWeb.Nav] do
live("/utm-builder", UtmBuilderLive)
live("/metadata-analyzer", MetadataAnalyzerLive)
end
end
defmodule DerpyToolsWeb.Nav do
import Phoenix.LiveView
def on_mount(:default, _params, _session, socket) do
{:cont,
socket
|> attach_hook(:inspect_source, :handle_event, &handle_event/3)}
end
def handle_event("inspect-source", %{"file" => file, "line" => line}, socket) do
System.cmd("code", ["--goto", "#{file}:#{line}"])
{:cont, socket}
end
def handle_event(_, _, socket), do: {:cont, socket}
end
In that module, I have defined the handle_event function and it works as well.
In the router, I just specified that module using on_mount
.
However, I still see this error, even though I have declared a common handle_event!
no function clause matching in DerpyToolsWeb.UtmBuilderLive.handle_event/3
.
Here’s how it works:
I have added this suggestion to Live View, hopefully, it gets added to the later version of Live View!
N.B. You have to add this to your environment so that the BEAM will open the correct editor for you and jump to the right file and line!
export ELIXIR_EDITOR="code --goto __FILE__:__LINE__"
P.S. I know I can do this:
def handle_event(_, _, socket), do: {:noreply, socket}
or
def handle_event(event, params, socket) do
IO.inspect(event)
IO.inspect(params)
{:noreply, socket}
end
But, I prefer not to.