mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-12-18 06:02:45 +08:00
Add runtime info panel (#692)
* Add runtime info panel * Remove intro from the runtime modal * Show default runtime in the panel if no runtime is set
This commit is contained in:
parent
1842c203ab
commit
d8d52c9e89
10 changed files with 202 additions and 161 deletions
|
|
@ -109,6 +109,11 @@ solely client-side operations.
|
||||||
@apply hidden;
|
@apply hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-element="session"]:not([data-js-side-panel-content="runtime-info"])
|
||||||
|
[data-element="runtime-info"] {
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
|
||||||
[data-element="session"][data-js-side-panel-content="sections-list"]
|
[data-element="session"][data-js-side-panel-content="sections-list"]
|
||||||
[data-element="sections-list-toggle"] {
|
[data-element="sections-list-toggle"] {
|
||||||
@apply text-gray-50 bg-gray-700;
|
@apply text-gray-50 bg-gray-700;
|
||||||
|
|
@ -119,6 +124,11 @@ solely client-side operations.
|
||||||
@apply text-gray-50 bg-gray-700;
|
@apply text-gray-50 bg-gray-700;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[data-element="session"][data-js-side-panel-content="runtime-info"]
|
||||||
|
[data-element="runtime-info-toggle"] {
|
||||||
|
@apply text-gray-50 bg-gray-700;
|
||||||
|
}
|
||||||
|
|
||||||
[data-element="section-headline"]:not(:hover)
|
[data-element="section-headline"]:not(:hover)
|
||||||
[data-element="section-name"]:not(:focus)
|
[data-element="section-name"]:not(:focus)
|
||||||
+ [data-element="section-actions"]:not(:focus-within) {
|
+ [data-element="section-actions"]:not(:focus-within) {
|
||||||
|
|
|
||||||
|
|
@ -32,13 +32,13 @@ Example usage:
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
display: block;
|
display: block;
|
||||||
|
z-index: 100;
|
||||||
background-color: #1c273c;
|
background-color: #1c273c;
|
||||||
color: #f0f5f9;
|
color: #f0f5f9;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 3px 12px;
|
padding: 3px 12px;
|
||||||
z-index: 100;
|
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
transition-property: visibility;
|
transition-property: visibility;
|
||||||
transition-duration: 0s;
|
transition-duration: 0s;
|
||||||
|
|
@ -50,6 +50,7 @@ Example usage:
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: block;
|
display: block;
|
||||||
|
z-index: 100;
|
||||||
/* For the arrow we use the triangle trick: https://css-tricks.com/snippets/css/css-triangle/ */
|
/* For the arrow we use the triangle trick: https://css-tricks.com/snippets/css/css-triangle/ */
|
||||||
border-width: var(--arrow-size);
|
border-width: var(--arrow-size);
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
|
|
|
||||||
|
|
@ -119,6 +119,10 @@ const Session = {
|
||||||
toggleClientsList(this);
|
toggleClientsList(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
getRuntimeInfoToggle().addEventListener("click", (event) => {
|
||||||
|
toggleRuntimeInfo(this);
|
||||||
|
});
|
||||||
|
|
||||||
getNotebook().addEventListener("scroll", (event) => {
|
getNotebook().addEventListener("scroll", (event) => {
|
||||||
updateSectionListHighlight();
|
updateSectionListHighlight();
|
||||||
});
|
});
|
||||||
|
|
@ -335,7 +339,7 @@ function handleDocumentKeyDown(hook, event) {
|
||||||
} else if (keyBuffer.tryMatch(["s", "u"])) {
|
} else if (keyBuffer.tryMatch(["s", "u"])) {
|
||||||
toggleClientsList(hook);
|
toggleClientsList(hook);
|
||||||
} else if (keyBuffer.tryMatch(["s", "r"])) {
|
} else if (keyBuffer.tryMatch(["s", "r"])) {
|
||||||
showNotebookRuntimeSettings(hook);
|
toggleRuntimeInfo(hook);
|
||||||
} else if (keyBuffer.tryMatch(["s", "b"])) {
|
} else if (keyBuffer.tryMatch(["s", "b"])) {
|
||||||
showBin(hook);
|
showBin(hook);
|
||||||
} else if (keyBuffer.tryMatch(["e", "x"])) {
|
} else if (keyBuffer.tryMatch(["e", "x"])) {
|
||||||
|
|
@ -581,23 +585,23 @@ function updateSectionListHighlight() {
|
||||||
// User action handlers (mostly keybindings)
|
// User action handlers (mostly keybindings)
|
||||||
|
|
||||||
function toggleSectionsList(hook) {
|
function toggleSectionsList(hook) {
|
||||||
if (hook.el.getAttribute("data-js-side-panel-content") === "sections-list") {
|
toggleSidePanelContent(hook, "sections-list");
|
||||||
hook.el.removeAttribute("data-js-side-panel-content");
|
|
||||||
} else {
|
|
||||||
hook.el.setAttribute("data-js-side-panel-content", "sections-list");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleClientsList(hook) {
|
function toggleClientsList(hook) {
|
||||||
if (hook.el.getAttribute("data-js-side-panel-content") === "clients-list") {
|
toggleSidePanelContent(hook, "clients-list");
|
||||||
hook.el.removeAttribute("data-js-side-panel-content");
|
|
||||||
} else {
|
|
||||||
hook.el.setAttribute("data-js-side-panel-content", "clients-list");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showNotebookRuntimeSettings(hook) {
|
function toggleRuntimeInfo(hook) {
|
||||||
hook.pushEvent("show_runtime_settings", {});
|
toggleSidePanelContent(hook, "runtime-info");
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSidePanelContent(hook, name) {
|
||||||
|
if (hook.el.getAttribute("data-js-side-panel-content") === name) {
|
||||||
|
hook.el.removeAttribute("data-js-side-panel-content");
|
||||||
|
} else {
|
||||||
|
hook.el.setAttribute("data-js-side-panel-content", name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showBin(hook) {
|
function showBin(hook) {
|
||||||
|
|
@ -1024,6 +1028,10 @@ function getClientsListToggle() {
|
||||||
return document.querySelector(`[data-element="clients-list-toggle"]`);
|
return document.querySelector(`[data-element="clients-list-toggle"]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRuntimeInfoToggle() {
|
||||||
|
return document.querySelector(`[data-element="runtime-info-toggle"]`);
|
||||||
|
}
|
||||||
|
|
||||||
function cancelEvent(event) {
|
function cancelEvent(event) {
|
||||||
// Cancel any default browser behavior.
|
// Cancel any default browser behavior.
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ defmodule LivebookWeb.SessionLive do
|
||||||
platform: platform,
|
platform: platform,
|
||||||
self: self(),
|
self: self(),
|
||||||
data_view: data_to_view(data),
|
data_view: data_to_view(data),
|
||||||
autofocus_cell_id: autofocus_cell_id(data.notebook)
|
autofocus_cell_id: autofocus_cell_id(data.notebook),
|
||||||
|
empty_default_runtime: Livebook.Config.default_runtime() |> elem(0) |> struct()
|
||||||
)
|
)
|
||||||
|> assign_private(data: data)
|
|> assign_private(data: data)
|
||||||
|> allow_upload(:cell_image,
|
|> allow_upload(:cell_image,
|
||||||
|
|
@ -87,11 +88,10 @@ defmodule LivebookWeb.SessionLive do
|
||||||
icon="group-fill"
|
icon="group-fill"
|
||||||
label="Connected users (su)"
|
label="Connected users (su)"
|
||||||
data_element="clients-list-toggle" />
|
data_element="clients-list-toggle" />
|
||||||
<SidebarHelpers.link_item
|
<SidebarHelpers.button_item
|
||||||
icon="cpu-line"
|
icon="cpu-line"
|
||||||
label="Runtime settings (sr)"
|
label="Runtime settings (sr)"
|
||||||
path={Routes.session_path(@socket, :runtime_settings, @session.id)}
|
data_element="runtime-info-toggle" />
|
||||||
active={@live_action == :runtime_settings} />
|
|
||||||
<SidebarHelpers.link_item
|
<SidebarHelpers.link_item
|
||||||
icon="delete-bin-6-fill"
|
icon="delete-bin-6-fill"
|
||||||
label="Bin (sb)"
|
label="Bin (sb)"
|
||||||
|
|
@ -110,81 +110,13 @@ defmodule LivebookWeb.SessionLive do
|
||||||
<div class="flex flex-col h-full w-full max-w-xs absolute z-30 top-0 left-[64px] overflow-y-auto shadow-xl md:static md:shadow-none bg-gray-50 border-r border-gray-100 px-6 py-10"
|
<div class="flex flex-col h-full w-full max-w-xs absolute z-30 top-0 left-[64px] overflow-y-auto shadow-xl md:static md:shadow-none bg-gray-50 border-r border-gray-100 px-6 py-10"
|
||||||
data-element="side-panel">
|
data-element="side-panel">
|
||||||
<div data-element="sections-list">
|
<div data-element="sections-list">
|
||||||
<div class="flex flex-col flex-grow">
|
<.sections_list data_view={@data_view} />
|
||||||
<h3 class="text-lg font-semibold text-gray-800">
|
|
||||||
Sections
|
|
||||||
</h3>
|
|
||||||
<div class="flex flex-col mt-4 space-y-4">
|
|
||||||
<%= for section_item <- @data_view.sections_items do %>
|
|
||||||
<div class="flex items-center">
|
|
||||||
<button class="flex-grow flex items-center text-gray-500 hover:text-gray-900"
|
|
||||||
data-element="sections-list-item"
|
|
||||||
data-section-id={section_item.id}>
|
|
||||||
<span class="flex items-center space-x-1">
|
|
||||||
<span><%= section_item.name %></span>
|
|
||||||
<%= if section_item.parent do %>
|
|
||||||
<%# Note: the container has overflow-y auto, so we cannot set overflow-x visible,
|
|
||||||
consequently we show the tooltip wrapped to a fixed number of characters %>
|
|
||||||
<span {branching_tooltip_attrs(section_item.name, section_item.parent.name)}>
|
|
||||||
<.remix_icon icon="git-branch-line" class="text-lg font-normal leading-none flip-horizontally" />
|
|
||||||
</span>
|
|
||||||
<% end %>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
<.session_status status={elem(section_item.status, 0)} cell_id={elem(section_item.status, 1)} />
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<button class="inline-flex items-center justify-center p-8 py-1 mt-8 space-x-2 text-sm font-medium text-gray-500 border border-gray-400 border-dashed rounded-xl hover:bg-gray-100"
|
|
||||||
phx-click="append_section">
|
|
||||||
<.remix_icon icon="add-line" class="text-lg align-center" />
|
|
||||||
<span>New section</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div data-element="clients-list">
|
<div data-element="clients-list">
|
||||||
<div class="flex flex-col flex-grow">
|
<.clients_list data_view={@data_view} self={@self} />
|
||||||
<div class="flex items-center justify-between space-x-4">
|
</div>
|
||||||
<h3 class="text-lg font-semibold text-gray-800 flex-lg">
|
<div data-element="runtime-info">
|
||||||
Users
|
<.runtime_info data_view={@data_view} session={@session} socket={@socket} empty_default_runtime={@empty_default_runtime} />
|
||||||
</h3>
|
|
||||||
<span class="flex items-center p-2 space-x-2 text-sm bg-gray-200 rounded-lg">
|
|
||||||
<span class="inline-flex w-3 h-3 bg-green-600 rounded-full"></span>
|
|
||||||
<span><%= length(@data_view.clients) %> connected</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col mt-4 space-y-4">
|
|
||||||
<%= for {client_pid, user} <- @data_view.clients do %>
|
|
||||||
<div class="flex items-center justify-between space-x-2"
|
|
||||||
id={"clients-list-item-#{inspect(client_pid)}"}
|
|
||||||
data-element="clients-list-item"
|
|
||||||
data-client-pid={inspect(client_pid)}>
|
|
||||||
<button class="flex items-center space-x-2 text-gray-500 hover:text-gray-900 disabled:pointer-events-none"
|
|
||||||
disabled={client_pid == @self}
|
|
||||||
data-element="client-link">
|
|
||||||
<.user_avatar user={user} class="flex-shrink-0 h-7 w-7" text_class="text-xs" />
|
|
||||||
<span><%= user.name || "Anonymous" %></span>
|
|
||||||
</button>
|
|
||||||
<%= if client_pid != @self do %>
|
|
||||||
<span class="tooltip left" data-tooltip="Follow this user"
|
|
||||||
data-element="client-follow-toggle"
|
|
||||||
data-meta="follow">
|
|
||||||
<button class="icon-button" aria-label="follow this user">
|
|
||||||
<.remix_icon icon="pushpin-line" class="text-lg" />
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
<span class="tooltip left" data-tooltip="Unfollow this user"
|
|
||||||
data-element="client-follow-toggle"
|
|
||||||
data-meta="unfollow">
|
|
||||||
<button class="icon-button" aria-label="unfollow this user">
|
|
||||||
<.remix_icon icon="pushpin-fill" class="text-lg" />
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow overflow-y-auto scroll-smooth" data-element="notebook">
|
<div class="flex-grow overflow-y-auto scroll-smooth" data-element="notebook">
|
||||||
|
|
@ -355,6 +287,143 @@ defmodule LivebookWeb.SessionLive do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp sections_list(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div class="flex flex-col flex-grow">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800">
|
||||||
|
Sections
|
||||||
|
</h3>
|
||||||
|
<div class="flex flex-col mt-4 space-y-4">
|
||||||
|
<%= for section_item <- @data_view.sections_items do %>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<button class="flex-grow flex items-center text-gray-500 hover:text-gray-900"
|
||||||
|
data-element="sections-list-item"
|
||||||
|
data-section-id={section_item.id}>
|
||||||
|
<span class="flex items-center space-x-1">
|
||||||
|
<span><%= section_item.name %></span>
|
||||||
|
<%= if section_item.parent do %>
|
||||||
|
<%# Note: the container has overflow-y auto, so we cannot set overflow-x visible,
|
||||||
|
consequently we show the tooltip wrapped to a fixed number of characters %>
|
||||||
|
<span {branching_tooltip_attrs(section_item.name, section_item.parent.name)}>
|
||||||
|
<.remix_icon icon="git-branch-line" class="text-lg font-normal leading-none flip-horizontally" />
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<.session_status status={elem(section_item.status, 0)} cell_id={elem(section_item.status, 1)} />
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<button class="inline-flex items-center justify-center p-8 py-1 mt-8 space-x-2 text-sm font-medium text-gray-500 border border-gray-400 border-dashed rounded-xl hover:bg-gray-100"
|
||||||
|
phx-click="append_section">
|
||||||
|
<.remix_icon icon="add-line" class="text-lg align-center" />
|
||||||
|
<span>New section</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp clients_list(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div class="flex flex-col flex-grow">
|
||||||
|
<div class="flex items-center justify-between space-x-4">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800 flex-lg">
|
||||||
|
Users
|
||||||
|
</h3>
|
||||||
|
<span class="flex items-center p-2 space-x-2 text-sm bg-gray-200 rounded-lg">
|
||||||
|
<span class="inline-flex w-3 h-3 bg-green-600 rounded-full"></span>
|
||||||
|
<span><%= length(@data_view.clients) %> connected</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col mt-4 space-y-4">
|
||||||
|
<%= for {client_pid, user} <- @data_view.clients do %>
|
||||||
|
<div class="flex items-center justify-between space-x-2"
|
||||||
|
id={"clients-list-item-#{inspect(client_pid)}"}
|
||||||
|
data-element="clients-list-item"
|
||||||
|
data-client-pid={inspect(client_pid)}>
|
||||||
|
<button class="flex items-center space-x-2 text-gray-500 hover:text-gray-900 disabled:pointer-events-none"
|
||||||
|
disabled={client_pid == @self}
|
||||||
|
data-element="client-link">
|
||||||
|
<.user_avatar user={user} class="flex-shrink-0 h-7 w-7" text_class="text-xs" />
|
||||||
|
<span><%= user.name || "Anonymous" %></span>
|
||||||
|
</button>
|
||||||
|
<%= if client_pid != @self do %>
|
||||||
|
<span class="tooltip left" data-tooltip="Follow this user"
|
||||||
|
data-element="client-follow-toggle"
|
||||||
|
data-meta="follow">
|
||||||
|
<button class="icon-button" aria-label="follow this user">
|
||||||
|
<.remix_icon icon="pushpin-line" class="text-lg" />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
<span class="tooltip left" data-tooltip="Unfollow this user"
|
||||||
|
data-element="client-follow-toggle"
|
||||||
|
data-meta="unfollow">
|
||||||
|
<button class="icon-button" aria-label="unfollow this user">
|
||||||
|
<.remix_icon icon="pushpin-fill" class="text-lg" />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp runtime_info(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div class="flex flex-col flex-grow">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-800">
|
||||||
|
Runtime
|
||||||
|
</h3>
|
||||||
|
<div class="flex flex-col mt-4 space-y-4">
|
||||||
|
<%= if @data_view.runtime do %>
|
||||||
|
<div class="flex flex-col space-y-3">
|
||||||
|
<.labeled_text label="Type" text={runtime_type_label(@data_view.runtime)} />
|
||||||
|
<.labeled_text label="Node name" text={@data_view.runtime.node} />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col space-y-3">
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<button class="button button-outlined-blue w-full" phx-click="restart_runtime">
|
||||||
|
Reconnect
|
||||||
|
</button>
|
||||||
|
<button class="button button-outlined-red w-full"
|
||||||
|
type="button"
|
||||||
|
phx-click="disconnect_runtime">
|
||||||
|
Disconnect
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<%= live_patch to: Routes.session_path(@socket, :runtime_settings, @session.id),
|
||||||
|
class: "button button-gray button-square-icon",
|
||||||
|
type: "button" do %>
|
||||||
|
<.remix_icon icon="settings-3-line" />
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% else %>
|
||||||
|
<div class="flex flex-col space-y-3">
|
||||||
|
<.labeled_text label="Type" text={runtime_type_label(@empty_default_runtime)} />
|
||||||
|
</div>
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<button class="button button-blue" phx-click="connect_default_runtime">
|
||||||
|
Connect
|
||||||
|
</button>
|
||||||
|
<%= live_patch to: Routes.session_path(@socket, :runtime_settings, @session.id),
|
||||||
|
class: "button button-gray button-square-icon",
|
||||||
|
type: "button" do %>
|
||||||
|
<.remix_icon icon="settings-3-line" />
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp runtime_type_label(%Runtime.ElixirStandalone{}), do: "Elixir standalone"
|
||||||
|
defp runtime_type_label(%Runtime.MixStandalone{}), do: "Mix standalone"
|
||||||
|
defp runtime_type_label(%Runtime.Attached{}), do: "Attached"
|
||||||
|
defp runtime_type_label(%Runtime.Embedded{}), do: "Embedded"
|
||||||
|
|
||||||
defp session_status(%{status: :evaluating} = assigns) do
|
defp session_status(%{status: :evaluating} = assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<button data-element="focus-cell-button" data-target={@cell_id}>
|
<button data-element="focus-cell-button" data-target={@cell_id}>
|
||||||
|
|
@ -660,13 +729,6 @@ defmodule LivebookWeb.SessionLive do
|
||||||
push_patch(socket, to: Routes.session_path(socket, :shortcuts, socket.assigns.session.id))}
|
push_patch(socket, to: Routes.session_path(socket, :shortcuts, socket.assigns.session.id))}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_event("show_runtime_settings", %{}, socket) do
|
|
||||||
{:noreply,
|
|
||||||
push_patch(socket,
|
|
||||||
to: Routes.session_path(socket, :runtime_settings, socket.assigns.session.id)
|
|
||||||
)}
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_event("show_bin", %{}, socket) do
|
def handle_event("show_bin", %{}, socket) do
|
||||||
{:noreply,
|
{:noreply,
|
||||||
push_patch(socket, to: Routes.session_path(socket, :bin, socket.assigns.session.id))}
|
push_patch(socket, to: Routes.session_path(socket, :bin, socket.assigns.session.id))}
|
||||||
|
|
@ -690,6 +752,27 @@ defmodule LivebookWeb.SessionLive do
|
||||||
{:noreply, socket}
|
{:noreply, socket}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_event("connect_default_runtime", %{}, socket) do
|
||||||
|
{runtime_module, args} = Livebook.Config.default_runtime()
|
||||||
|
|
||||||
|
socket =
|
||||||
|
case apply(runtime_module, :init, args) do
|
||||||
|
{:ok, runtime} ->
|
||||||
|
Session.connect_runtime(socket.assigns.session.pid, runtime)
|
||||||
|
socket
|
||||||
|
|
||||||
|
{:error, message} ->
|
||||||
|
put_flash(socket, :error, "Failed to setup runtime - #{message}")
|
||||||
|
end
|
||||||
|
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_event("disconnect_runtime", %{}, socket) do
|
||||||
|
Session.disconnect_runtime(socket.assigns.session.pid)
|
||||||
|
{:noreply, socket}
|
||||||
|
end
|
||||||
|
|
||||||
def handle_event("intellisense_request", %{"cell_id" => cell_id} = params, socket) do
|
def handle_event("intellisense_request", %{"cell_id" => cell_id} = params, socket) do
|
||||||
request =
|
request =
|
||||||
case params do
|
case params do
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ defmodule LivebookWeb.SessionLive.AttachedLive do
|
||||||
use LivebookWeb, :live_view
|
use LivebookWeb, :live_view
|
||||||
|
|
||||||
alias Livebook.{Session, Runtime, Utils}
|
alias Livebook.{Session, Runtime, Utils}
|
||||||
alias LivebookWeb.SessionLive.RuntimeHelpers
|
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def mount(_params, %{"session" => session, "current_runtime" => current_runtime}, socket) do
|
def mount(_params, %{"session" => session, "current_runtime" => current_runtime}, socket) do
|
||||||
|
|
@ -28,7 +27,6 @@ defmodule LivebookWeb.SessionLive.AttachedLive do
|
||||||
<%= @error_message %>
|
<%= @error_message %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<RuntimeHelpers.default_runtime_note module={Runtime.Attached} />
|
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
Connect the session to an already running node
|
Connect the session to an already running node
|
||||||
and evaluate code in the context of that node.
|
and evaluate code in the context of that node.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ defmodule LivebookWeb.SessionLive.ElixirStandaloneLive do
|
||||||
use LivebookWeb, :live_view
|
use LivebookWeb, :live_view
|
||||||
|
|
||||||
alias Livebook.{Session, Runtime}
|
alias Livebook.{Session, Runtime}
|
||||||
alias LivebookWeb.SessionLive.RuntimeHelpers
|
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def mount(_params, %{"session" => session, "current_runtime" => current_runtime}, socket) do
|
def mount(_params, %{"session" => session, "current_runtime" => current_runtime}, socket) do
|
||||||
|
|
@ -22,7 +21,6 @@ defmodule LivebookWeb.SessionLive.ElixirStandaloneLive do
|
||||||
<%= @error_message %>
|
<%= @error_message %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
<RuntimeHelpers.default_runtime_note module={Runtime.ElixirStandalone} />
|
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
Start a new local node to handle code evaluation.
|
Start a new local node to handle code evaluation.
|
||||||
</p>
|
</p>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ defmodule LivebookWeb.SessionLive.EmbeddedLive do
|
||||||
use LivebookWeb, :live_view
|
use LivebookWeb, :live_view
|
||||||
|
|
||||||
alias Livebook.{Session, Runtime}
|
alias Livebook.{Session, Runtime}
|
||||||
alias LivebookWeb.SessionLive.RuntimeHelpers
|
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def mount(_params, %{"session" => session, "current_runtime" => current_runtime}, socket) do
|
def mount(_params, %{"session" => session, "current_runtime" => current_runtime}, socket) do
|
||||||
|
|
@ -17,7 +16,6 @@ defmodule LivebookWeb.SessionLive.EmbeddedLive do
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="flex-col space-y-5">
|
<div class="flex-col space-y-5">
|
||||||
<RuntimeHelpers.default_runtime_note module={Runtime.Embedded} />
|
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
Run the notebook code within the Livebook node itself.
|
Run the notebook code within the Livebook node itself.
|
||||||
This is reserved for specific cases where there is no option
|
This is reserved for specific cases where there is no option
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ defmodule LivebookWeb.SessionLive.MixStandaloneLive do
|
||||||
use LivebookWeb, :live_view
|
use LivebookWeb, :live_view
|
||||||
|
|
||||||
alias Livebook.{Session, Runtime, Utils, FileSystem}
|
alias Livebook.{Session, Runtime, Utils, FileSystem}
|
||||||
alias LivebookWeb.SessionLive.RuntimeHelpers
|
|
||||||
|
|
||||||
@type status :: :initial | :initializing | :finished
|
@type status :: :initial | :initializing | :finished
|
||||||
|
|
||||||
|
|
@ -27,7 +26,6 @@ defmodule LivebookWeb.SessionLive.MixStandaloneLive do
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="flex-col space-y-5">
|
<div class="flex-col space-y-5">
|
||||||
<RuntimeHelpers.default_runtime_note module={Runtime.MixStandalone} />
|
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
Start a new local node in the context of a Mix project.
|
Start a new local node in the context of a Mix project.
|
||||||
This way all your code and dependencies will be available
|
This way all your code and dependencies will be available
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
defmodule LivebookWeb.SessionLive.RuntimeComponent do
|
defmodule LivebookWeb.SessionLive.RuntimeComponent do
|
||||||
use LivebookWeb, :live_component
|
use LivebookWeb, :live_component
|
||||||
|
|
||||||
alias Livebook.{Session, Runtime}
|
alias Livebook.Runtime
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def mount(socket) do
|
def mount(socket) do
|
||||||
|
|
@ -31,31 +31,11 @@ defmodule LivebookWeb.SessionLive.RuntimeComponent do
|
||||||
@impl true
|
@impl true
|
||||||
def render(assigns) do
|
def render(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="p-6 pb-4 max-w-4xl flex flex-col space-y-3">
|
<div class="p-6 pb-4 max-w-4xl flex flex-col space-y-5">
|
||||||
<h3 class="text-2xl font-semibold text-gray-800">
|
<h3 class="text-2xl font-semibold text-gray-800">
|
||||||
Runtime
|
Runtime
|
||||||
</h3>
|
</h3>
|
||||||
<div class="w-full flex-col space-y-5">
|
<div class="w-full flex-col space-y-5">
|
||||||
<p class="text-gray-700">
|
|
||||||
The code is evaluated in a separate Elixir runtime (node),
|
|
||||||
which you can configure yourself here.
|
|
||||||
</p>
|
|
||||||
<div class="flex items-center justify-between border border-gray-200 rounded-lg p-4">
|
|
||||||
<%= if @runtime do %>
|
|
||||||
<.labeled_text label="Type" text={runtime_type_label(@runtime)} />
|
|
||||||
<.labeled_text label="Node name" text={@runtime.node} />
|
|
||||||
<button class="button button-outlined-red"
|
|
||||||
type="button"
|
|
||||||
phx-click="disconnect"
|
|
||||||
phx-target={@myself}>
|
|
||||||
Disconnect
|
|
||||||
</button>
|
|
||||||
<% else %>
|
|
||||||
<p class="text-sm text-gray-700">
|
|
||||||
No connected node
|
|
||||||
</p>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
|
||||||
<div class="flex space-x-4">
|
<div class="flex space-x-4">
|
||||||
<.choice_button
|
<.choice_button
|
||||||
active={@type == "elixir_standalone"}
|
active={@type == "elixir_standalone"}
|
||||||
|
|
@ -96,11 +76,6 @@ defmodule LivebookWeb.SessionLive.RuntimeComponent do
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp runtime_type_label(%Runtime.ElixirStandalone{}), do: "Elixir standalone"
|
|
||||||
defp runtime_type_label(%Runtime.MixStandalone{}), do: "Mix standalone"
|
|
||||||
defp runtime_type_label(%Runtime.Attached{}), do: "Attached"
|
|
||||||
defp runtime_type_label(%Runtime.Embedded{}), do: "Embedded"
|
|
||||||
|
|
||||||
defp runtime_type(%Runtime.ElixirStandalone{}), do: "elixir_standalone"
|
defp runtime_type(%Runtime.ElixirStandalone{}), do: "elixir_standalone"
|
||||||
defp runtime_type(%Runtime.MixStandalone{}), do: "mix_standalone"
|
defp runtime_type(%Runtime.MixStandalone{}), do: "mix_standalone"
|
||||||
defp runtime_type(%Runtime.Attached{}), do: "attached"
|
defp runtime_type(%Runtime.Attached{}), do: "attached"
|
||||||
|
|
@ -115,10 +90,4 @@ defmodule LivebookWeb.SessionLive.RuntimeComponent do
|
||||||
def handle_event("set_runtime_type", %{"type" => type}, socket) do
|
def handle_event("set_runtime_type", %{"type" => type}, socket) do
|
||||||
{:noreply, assign(socket, type: type)}
|
{:noreply, assign(socket, type: type)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_event("disconnect", _params, socket) do
|
|
||||||
Session.disconnect_runtime(socket.assigns.session.pid)
|
|
||||||
|
|
||||||
{:noreply, socket}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
defmodule LivebookWeb.SessionLive.RuntimeHelpers do
|
|
||||||
use Phoenix.Component
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Displays an info text if `@module` is the default runtime.
|
|
||||||
"""
|
|
||||||
def default_runtime_note(assigns) do
|
|
||||||
~H"""
|
|
||||||
<%= if default_runtime_module?(@module) do %>
|
|
||||||
<p class="text-gray-600 text-sm">
|
|
||||||
Note: This is the <span class="font-semibold">default runtime</span> and starts
|
|
||||||
automatically as soon as you evaluate the first cell.
|
|
||||||
</p>
|
|
||||||
<% end %>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
defp default_runtime_module?(module) do
|
|
||||||
{default_module, _args} = Livebook.Config.default_runtime()
|
|
||||||
default_module == module
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Loading…
Add table
Reference in a new issue