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:
Jonatan Kłosko 2021-11-09 18:37:22 +01:00 committed by GitHub
parent 1842c203ab
commit d8d52c9e89
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 202 additions and 161 deletions

View file

@ -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) {

View file

@ -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;

View file

@ -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();

View file

@ -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">
<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> </div>
<div data-element="runtime-info">
<.runtime_info data_view={@data_view} session={@session} socket={@socket} empty_default_runtime={@empty_default_runtime} />
</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

View file

@ -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.

View file

@ -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>

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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