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
53 changes: 41 additions & 12 deletions assets/js/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,42 @@ function getSessionId() {
}
}

function handleMetaTagError() {
const message = `
LiveDebugger meta tag not found!
If you have recently bumped LiveDebugger version, please update your layout according to the instructions in the GitHub README.
You can find it here: https://github.com/software-mansion/live-debugger#installation
`;

throw new Error(message);
}

function debugButtonEnabled() {
const metaTag = document.querySelector('meta[name="live-debugger-config"]');

if (metaTag) {
return metaTag.hasAttribute('debug-button');
} else {
handleMetaTagError();
}
}

function highlightingEnabled() {
const metaTag = document.querySelector('meta[name="live-debugger-config"]');

if (metaTag) {
return metaTag.hasAttribute('highlighting');
}
}

function getLiveDebuggerBaseURL() {
return document
.getElementById('live-debugger-scripts')
.src.replace('/assets/live_debugger/client.js', '');
const metaTag = document.querySelector('meta[name="live-debugger-config"]');

if (metaTag) {
return metaTag.getAttribute('url');
} else {
handleMetaTagError();
}
}

function getSessionURL(baseURL) {
Expand All @@ -31,20 +63,17 @@ function getSessionURL(baseURL) {
return `${baseURL}/${session_path}`;
}

window.getLiveDebuggerURL = function () {
const baseURL = getLiveDebuggerBaseURL();
const sessionURL = getSessionURL(baseURL);

return sessionURL;
};

window.document.addEventListener('DOMContentLoaded', function () {
const baseURL = getLiveDebuggerBaseURL();
const sessionURL = getSessionURL(baseURL);

initDebugButton(sessionURL);
if (debugButtonEnabled()) {
initDebugButton(sessionURL);
}

initHighlight();
if (highlightingEnabled()) {
initHighlight();
}

// Finalize
console.info(`LiveDebugger available at: ${baseURL}`);
Expand Down
3 changes: 0 additions & 3 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ if config_env() == :dev do
]
]

config :live_debugger, server: true

config :live_debugger, browser_features?: true
config :live_debugger, experimental_features: :all
end

Expand Down
5 changes: 1 addition & 4 deletions dev/layout.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ defmodule LiveDebuggerDev.Layout do
</script>
<script src="/assets/phoenix_live_view/phoenix_live_view.js">
</script>
<%= if Application.get_env(:live_debugger, :browser_features?) do %>
<script id="live-debugger-scripts" src={Application.get_env(:live_debugger, :assets_url)}>
</script>
<% end %>
<%= Application.get_env(:live_debugger, :live_debugger_tags) %>
<script>
// Set global hooks and uploaders objects to be used by the LiveSocket,
// so they can be overwritten in user provided templates.
Expand Down
53 changes: 45 additions & 8 deletions devtools/devtools.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,52 @@
function getLiveDebuggerSessionURL() {
return new Promise((resolve, reject) => {
chrome.devtools.inspectedWindow.eval(
"getLiveDebuggerURL()",
(result, isException) => {
if (isException) {
reject(isException);
} else {
resolve(result);
const script = `
(function() {
function getSessionId() {
let el;
if ((el = document.querySelector('[data-phx-main]'))) {
return el.id;
}
if ((el = document.querySelector('[id^="phx-"]'))) {
return el.id;
}
if ((el = document.querySelector('[data-phx-root-id]'))) {
return el.getAttribute('data-phx-root-id');
}
return null;
}

function handleMetaTagError() {
throw new Error("LiveDebugger meta tag not found!");
}

function getLiveDebuggerBaseURL() {
const metaTag = document.querySelector('meta[name="live-debugger-config"]');
if (metaTag) {
return metaTag.getAttribute('url');
} else {
handleMetaTagError();
}
}

function getSessionURL(baseURL) {
const session_id = getSessionId();
const session_path = session_id ? \`transport_pid/\${session_id}\` : '';
return \`\${baseURL}/\${session_path}\`;
}

const baseURL = getLiveDebuggerBaseURL();
return getSessionURL(baseURL);
})();
`;

chrome.devtools.inspectedWindow.eval(script, (result, isException) => {
if (isException || !result) {
reject(new Error("Error fetching LiveDebugger session URL"));
} else {
resolve(result);
}
);
});
});
}

Expand Down
23 changes: 19 additions & 4 deletions devtools/panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<style>
body {
margin: 0;
background-color: rgb(241 245 249);
background-color: #f1f5f9;
}
iframe {
border: none;
Expand All @@ -21,7 +21,7 @@
#error-info svg {
width: 48px;
height: 48px;
color: rgb(76 43 138);
color: #ef4444;
}
#error-info div {
font-weight: 600;
Expand All @@ -33,6 +33,14 @@
max-width: 70%;
margin: 0;
}
a {
color: #001a72;
text-decoration: none;
}
a:hover {
color: #33498b;
text-decoration: none;
}
</style>
</head>
<body>
Expand All @@ -59,8 +67,15 @@
</svg>
<div>Debugger disconnected</div>
<p>
Couldn't find url. Ensure you've turned on browser features in the
config and added LiveDebugger scripts to your application root layout.
Couldn't find LiveDebugger url - please update your root layout
according to the instructions in the GitHub README.
<br />
You can find it
<a
target="_blank"
href="https://github.com/software-mansion/live-debugger#installation"
>here</a
>
</p>
</div>

Expand Down
59 changes: 42 additions & 17 deletions lib/live_debugger.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,8 @@ defmodule LiveDebugger do
def start(_type, _args) do
config = Application.get_all_env(@app_name)

default_adapter = default_adapter()
ip = Keyword.get(config, :ip, @default_ip)
ip_string = ip |> :inet.ntoa() |> List.to_string()
port = Keyword.get(config, :port, @default_port)

endpoint_config =
[
http: [ip: ip, port: port],
secret_key_base: Keyword.get(config, :secret_key_base, @default_secret_key_base),
live_view: [signing_salt: Keyword.get(config, :signing_salt, @default_signing_salt)],
adapter: Keyword.get(config, :adapter, default_adapter),
live_reload: Keyword.get(config, :live_reload, []),
server: Keyword.get(config, :server, false)
]

Application.put_env(@app_name, LiveDebugger.Endpoint, endpoint_config)
Application.put_env(@app_name, :assets_url, "http://#{ip_string}:#{port}/#{@assets_path}")
put_endpoint_config(config)
put_live_debugger_tags(config)

children = [
{Phoenix.PubSub, name: LiveDebugger.PubSub},
Expand Down Expand Up @@ -62,4 +47,44 @@ defmodule LiveDebugger do
{:error, _} -> Phoenix.Endpoint.Cowboy2Adapter
end
end

defp put_endpoint_config(config) do
endpoint_config =
[
http: [
ip: Keyword.get(config, :ip, @default_ip),
port: Keyword.get(config, :port, @default_port)
],
secret_key_base: Keyword.get(config, :secret_key_base, @default_secret_key_base),
live_view: [signing_salt: Keyword.get(config, :signing_salt, @default_signing_salt)],
adapter: Keyword.get(config, :adapter, default_adapter()),
live_reload: Keyword.get(config, :live_reload, []),
server: true
]

Application.put_env(@app_name, LiveDebugger.Endpoint, endpoint_config)
end

defp put_live_debugger_tags(config) do
ip_string = config |> Keyword.get(:ip, @default_ip) |> :inet.ntoa() |> List.to_string()
port = Keyword.get(config, :port, @default_port)

browser_features? = Keyword.get(config, :browser_features?, true)
debug_button? = Keyword.get(config, :debug_button?, true)
highlighting? = Keyword.get(config, :highlighting?, true)

live_debugger_url = "http://#{ip_string}:#{port}"
live_debugger_assets_url = "http://#{ip_string}:#{port}/#{@assets_path}"

assigns = %{
url: live_debugger_url,
assets_url: live_debugger_assets_url,
browser_features?: browser_features?,
debug_button?: debug_button?,
highlighting?: highlighting?
}

tags = LiveDebugger.Components.Config.live_debugger_tags(assigns)
Application.put_env(@app_name, :live_debugger_tags, tags)
end
end
29 changes: 29 additions & 0 deletions lib/live_debugger/components/config.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
defmodule LiveDebugger.Components.Config do
@moduledoc """
Renders the LiveDebugger config meta tag and the browser features script.
It is meant to be injected to the debugged application layout.
"""

use Phoenix.Component

attr(:url, :string, required: true)
attr(:assets_url, :string, required: true)
attr(:browser_features?, :boolean, default: true)
attr(:debug_button?, :boolean, default: true)
attr(:highlighting?, :boolean, default: true)

def live_debugger_tags(assigns) do
~H"""
<meta
name="live-debugger-config"
url={@url}
debug-button={@debug_button?}
highlighting={@highlighting?}
/>
<%= if @browser_features? do %>
<script src={@assets_url}>
</script>
<% end %>
"""
end
end
2 changes: 1 addition & 1 deletion lib/live_debugger/components/tree.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ defmodule LiveDebugger.Components.Tree do
<div class={["w-full overflow-y-auto flex flex-col", @class]}>
<div class="flex items-center justify-between">
<div class="shrink-0 font-medium text-secondary-text px-6 py-3"><%= @title %></div>
<%= if Application.get_env(:live_debugger, :browser_features?) && LiveDebugger.Feature.enabled?(:highlighting) do %>
<%= if LiveDebugger.Feature.enabled?(:highlighting) do %>
<.toggle_switch label="Highlight" checked={@highlight?} phx-click="toggle-highlight" />
<% end %>
</div>
Expand Down
32 changes: 20 additions & 12 deletions lib/live_debugger/feature.ex
Original file line number Diff line number Diff line change
@@ -1,24 +1,32 @@
defmodule LiveDebugger.Feature do
@moduledoc """
Feature flags for LiveDebugger. If you create a new feature, you need to add it to the @experimental_features list.
This way we can easily find all the features that are experimental and not ready for production.
Feature flags for LiveDebugger.
If you create a new feature, create a new function here with defined rules for enabling it.
"""

@experimental_features [
:dark_mode,
:highlighting,
:callback_filters
]
def enabled?(:highlighting) do
experimental_feature_enabled?(:highlighting) and
Application.get_env(:live_debugger, :browser_features?, true) and
Application.get_env(:live_debugger, :highlighting?, true)
end

def enabled?(:dark_mode) do
experimental_feature_enabled?(:dark_mode)
end

def enabled?(feature_name) when feature_name in @experimental_features do
def enabled?(:callback_filters) do
experimental_feature_enabled?(:callback_filters)
end

def enabled?(feature_name) do
raise "Feature #{feature_name} is not allowed"
end

defp experimental_feature_enabled?(feature_name) do
case Application.get_env(:live_debugger, :experimental_features, false) do
:all -> true
features when is_list(features) -> Enum.member?(features, feature_name)
_ -> false
end
end

def enabled?(feature_name) do
raise "Feature #{feature_name} is not allowed"
end
end
7 changes: 3 additions & 4 deletions lib/live_debugger/live_views/sidebar_live.ex
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ defmodule LiveDebugger.LiveViews.SidebarLive do
@impl true
def render(assigns) do
~H"""
<div class="w-max flex bg-sidebar-bg shadow-custom border-x border-default-border h-full">
<div class="hidden lg:flex max-h-full flex-col w-72 lg:w-80 gap-1 justify-between">
<div class="w-max flex bg-sidebar-bg shadow-custom h-full">
<div class="hidden lg:flex max-h-full flex-col w-72 border-x border-default-border lg:w-80 gap-1 justify-between">
<.sidebar_content
id="sidebar-content"
lv_process={@lv_process}
Expand Down Expand Up @@ -157,8 +157,7 @@ defmodule LiveDebugger.LiveViews.SidebarLive do
def handle_event("select_node", params, socket) do
%{"node_id" => node_id, "search-attribute" => attr, "search-value" => val} = params

if Application.get_env(:live_debugger, :browser_features?) &&
LiveDebugger.Feature.enabled?(:highlighting) do
if LiveDebugger.Feature.enabled?(:highlighting) do
if !socket.assigns.hidden? && socket.assigns.highlight? do
send_event(socket.assigns.lv_process.pid, "highlight", %{attr: attr, val: val})
end
Expand Down
Loading