mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-02-02 20:28:11 +08:00
Redesign deploy and runtime panels (#2478)
Co-authored-by: Jonatan Kłosko <jonatanklosko@gmail.com>
This commit is contained in:
parent
c9d505a2b4
commit
f3206d9791
11 changed files with 277 additions and 204 deletions
|
@ -279,11 +279,6 @@ solely client-side operations.
|
|||
@apply text-gray-50 bg-gray-700;
|
||||
}
|
||||
|
||||
[data-el-session][data-js-side-panel-content="app-info"]
|
||||
[data-el-app-indicator] {
|
||||
@apply border-gray-700;
|
||||
}
|
||||
|
||||
[data-el-clients-list-item]:not([data-js-followed]) [data-meta="unfollow"] {
|
||||
@apply hidden;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ Example usage:
|
|||
display: flex;
|
||||
--distance: 4px;
|
||||
--arrow-size: 5px;
|
||||
--arrow-side-offset: 10px;
|
||||
--show-delay: 0.5s;
|
||||
}
|
||||
|
||||
|
@ -82,7 +83,17 @@ otherwise there's a tiny space between them.
|
|||
transform: translate(-50%, calc(1px - var(--arrow-size) - var(--distance)));
|
||||
}
|
||||
|
||||
.tooltip.top:after {
|
||||
.tooltip.top-right:before {
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
transform: translate(
|
||||
calc(0px - var(--arrow-side-offset)),
|
||||
calc(1px - var(--arrow-size) - var(--distance))
|
||||
);
|
||||
}
|
||||
|
||||
.tooltip.top:after,
|
||||
.tooltip.top-right:after {
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, calc(0px - var(--distance)));
|
||||
|
@ -100,8 +111,11 @@ otherwise there's a tiny space between them.
|
|||
|
||||
.tooltip.bottom-left:before {
|
||||
top: 100%;
|
||||
right: 0;
|
||||
transform: translate(0%, calc(var(--arrow-size) - 1px + var(--distance)));
|
||||
left: 50%;
|
||||
transform: translate(
|
||||
calc(-100% + var(--arrow-side-offset)),
|
||||
calc(var(--arrow-size) - 1px + var(--distance))
|
||||
);
|
||||
}
|
||||
|
||||
.tooltip.bottom:after,
|
||||
|
|
|
@ -68,15 +68,15 @@ defmodule LivebookWeb.AppComponents do
|
|||
@doc """
|
||||
Shows a confirmation modal and closes the app on confirm.
|
||||
"""
|
||||
def confirm_app_termination(socket, app_pid) do
|
||||
def confirm_app_termination(socket, app_pid, title \\ "app") do
|
||||
on_confirm = fn socket ->
|
||||
Livebook.App.close(app_pid)
|
||||
socket
|
||||
end
|
||||
|
||||
confirm(socket, on_confirm,
|
||||
title: "Terminate app",
|
||||
description: "All app sessions will be immediately terminated.",
|
||||
title: "Terminate #{title}",
|
||||
description: "All #{title} sessions will be immediately terminated.",
|
||||
confirm_text: "Terminate",
|
||||
confirm_icon: "delete-bin-6-line"
|
||||
)
|
||||
|
|
|
@ -99,7 +99,7 @@ defmodule LivebookWeb.LayoutComponents do
|
|||
</div>
|
||||
<.sidebar_link title="Home" icon="home-6-line" to={~p"/"} current={@current_page} />
|
||||
<.sidebar_link
|
||||
title="Apps"
|
||||
title="Local apps"
|
||||
icon="rocket-line"
|
||||
to={~p"/apps-dashboard"}
|
||||
current={@current_page}
|
||||
|
|
|
@ -26,15 +26,18 @@ defmodule LivebookWeb.AppsDashboardLive do
|
|||
current_user={@current_user}
|
||||
saved_hubs={@saved_hubs}
|
||||
>
|
||||
<div class="p-4 md:px-12 md:py-7 max-w-screen-lg mx-auto">
|
||||
<div class="space-y-2 p-4 md:px-12 md:py-7 max-w-screen-lg mx-auto">
|
||||
<div class="flex items-center justify-between">
|
||||
<LayoutComponents.title text="Apps" />
|
||||
<LayoutComponents.title text="Local apps" />
|
||||
<.link navigate={~p"/apps"} class="flex items-center text-blue-600">
|
||||
<span class="font-semibold">Listing</span>
|
||||
<.remix_icon icon="arrow-right-line" class="align-middle ml-1" />
|
||||
</.link>
|
||||
</div>
|
||||
<div class="mt-10">
|
||||
<p class="text-gray-700 text-sm">
|
||||
An overview of all deployed applications and previews running on this instance.
|
||||
</p>
|
||||
<div class="pt-6">
|
||||
<.app_list apps={@apps} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -46,7 +49,7 @@ defmodule LivebookWeb.AppsDashboardLive do
|
|||
~H"""
|
||||
<.no_entries>
|
||||
You do not have any apps running. <br />
|
||||
You can deploy new apps by opening a notebook and clicking
|
||||
You can preview and deploy new apps by opening a notebook and clicking
|
||||
<.remix_icon icon="rocket-line" class="align-top text-lg" /> in the sidebar.
|
||||
</.no_entries>
|
||||
"""
|
||||
|
@ -70,10 +73,7 @@ defmodule LivebookWeb.AppsDashboardLive do
|
|||
</div>
|
||||
<div class="flex-col mb-8">
|
||||
<div class="p-4 border-x border-t border-gray-200 rounded-t-lg ">
|
||||
<div class="uppercase text-gray-500 text-sm font-medium leading-normal tracking-wider">
|
||||
App Info
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-[minmax(0,_2fr)_minmax(0,_2fr)_minmax(0,_1fr)_minmax(0,_1fr)_minmax(0,_1fr)] gap-4 mt-3">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-[minmax(0,_2fr)_minmax(0,_2fr)_minmax(0,_1fr)_minmax(0,_1fr)_minmax(0,_1fr)] gap-4">
|
||||
<div class="break-words">
|
||||
<.labeled_text label="Name">
|
||||
<%= app.notebook_name %>
|
||||
|
@ -196,7 +196,10 @@ defmodule LivebookWeb.AppsDashboardLive do
|
|||
<div class="grid grid-cols-[minmax(0,_0.5fr)_minmax(0,_0.75fr)_minmax(0,_0.5fr)_minmax(0,_0.5fr)_minmax(0,_0.5fr)] md:grid-cols-[minmax(0,_2fr)_minmax(0,_2fr)_minmax(0,_1fr)_minmax(0,_1fr)_minmax(0,_1fr)] gap-4 px-2">
|
||||
<div
|
||||
:for={col <- @col}
|
||||
class={["text-gray-500 text-sm font-normal", align_to_class(col[:align])]}
|
||||
class={[
|
||||
"text-gray-500 text-sm font-normal flex items-center",
|
||||
align_to_class(col[:align])
|
||||
]}
|
||||
>
|
||||
<%= col[:label] %>
|
||||
</div>
|
||||
|
@ -205,7 +208,10 @@ defmodule LivebookWeb.AppsDashboardLive do
|
|||
<div class="grid grid-cols-[minmax(0,_0.5fr)_minmax(0,_0.75fr)_minmax(0,_0.5fr)_minmax(0,_0.5fr)_minmax(0,_0.5fr)] md:grid-cols-[minmax(0,_2fr)_minmax(0,_2fr)_minmax(0,_1fr)_minmax(0,_1fr)_minmax(0,_1fr)] gap-4">
|
||||
<div
|
||||
:for={col <- @col}
|
||||
class={["py-2 text-gray-800 text-sm font-semibold", align_to_class(col[:align])]}
|
||||
class={[
|
||||
"py-2 text-gray-800 text-sm font-semibold flex items-center",
|
||||
align_to_class(col[:align])
|
||||
]}
|
||||
>
|
||||
<%= render_slot(col, row) %>
|
||||
</div>
|
||||
|
|
|
@ -59,7 +59,7 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
|||
~H"""
|
||||
<div class="p-6 flex flex-col space-y-8">
|
||||
<h3 class="text-2xl font-semibold text-gray-800">
|
||||
App deployment
|
||||
App deployment with Docker
|
||||
</h3>
|
||||
<.content
|
||||
file={@file}
|
||||
|
@ -149,7 +149,7 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
|||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div :if={@warnings != []} class="flex flex-col gap-2">
|
||||
<.message_box :for={warning <- @warnings} kind={:warning}>
|
||||
<%= raw(warning) %>
|
||||
</.message_box>
|
||||
|
|
|
@ -27,140 +27,188 @@ defmodule LivebookWeb.SessionLive.AppInfoComponent do
|
|||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="mt-5 flex flex-col gap-6">
|
||||
<div class="flex flex-col gap-3 mt-2">
|
||||
<.message_box
|
||||
:if={@any_session_secrets?}
|
||||
kind={:warning}
|
||||
message="The notebook uses session secrets, but those are not available to deployed apps. Convert them to Hub secrets instead."
|
||||
/>
|
||||
<div class="flex flex-col gap-3">
|
||||
<div class="flex gap-2">
|
||||
<.button
|
||||
phx-click="deploy_app"
|
||||
disabled={not Livebook.Notebook.AppSettings.valid?(@settings)}
|
||||
>
|
||||
<.remix_icon icon="rocket-line" />
|
||||
<span>Deploy</span>
|
||||
</.button>
|
||||
<.button color="gray" outlined patch={~p"/sessions/#{@session.id}/settings/app"}>
|
||||
Configure
|
||||
</.button>
|
||||
|
||||
<div class="flex flex-col space-y-3">
|
||||
<.labeled_text label="Slug" one_line>
|
||||
<%= @settings.slug || "?" %>
|
||||
</.labeled_text>
|
||||
|
||||
<.labeled_text label="Session type" one_line>
|
||||
<%= if @settings.multi_session, do: "Multi", else: "Single" %>
|
||||
</.labeled_text>
|
||||
|
||||
<.labeled_text label="Access" one_line>
|
||||
<%= if @settings.access_type == :public do %>
|
||||
No password <.remix_icon icon="lock-unlock-line" />
|
||||
<% else %>
|
||||
Password protected <.remix_icon icon="lock-password-line" />
|
||||
<% end %>
|
||||
</.labeled_text>
|
||||
</div>
|
||||
|
||||
<.button color="gray" outlined patch={~p"/sessions/#{@session.id}/settings/app"}>
|
||||
Configure
|
||||
</.button>
|
||||
</div>
|
||||
|
||||
<h3 class="mt-12 uppercase text-sm font-semibold text-gray-500">
|
||||
Remote deployment
|
||||
</h3>
|
||||
|
||||
<div class="mt-2 flex flex-col gap-2">
|
||||
<%!-- TODO: Livebook Teams flow --%>
|
||||
<.button color="blue" patch={~p"/sessions/#{@session.id}/app-docker"}>
|
||||
<.remix_icon icon="rocket-line" /> Deploy with Livebook Teams
|
||||
</.button>
|
||||
|
||||
<.button color="gray" outlined patch={~p"/sessions/#{@session.id}/app-docker"}>
|
||||
<.remix_icon icon="ship-line" /> Manual Docker deployment
|
||||
</.button>
|
||||
</div>
|
||||
|
||||
<h3 class="mt-12 uppercase text-sm font-semibold text-gray-500">
|
||||
Local preview
|
||||
</h3>
|
||||
|
||||
<div class="flex flex-col mt-2 space-y-4">
|
||||
<div :if={@app} class="flex flex-col space-y-3">
|
||||
<.labeled_text label="URL" one_line>
|
||||
<a href={~p"/apps/#{@app.slug}"}>
|
||||
<%= ~p"/apps/#{@app.slug}" %>
|
||||
</a>
|
||||
</.labeled_text>
|
||||
|
||||
<.labeled_text :if={@app.multi_session} label="Latest version" one_line>
|
||||
v<%= @app.version %>
|
||||
</.labeled_text>
|
||||
|
||||
<div :if={@app.sessions != []}>
|
||||
<span class="text-sm text-gray-500">Running sessions</span>
|
||||
|
||||
<div class="mt-2 flex flex-col space-y-4">
|
||||
<.app_sessions app={@app} myself={@myself} />
|
||||
</div>
|
||||
</div>
|
||||
<.link
|
||||
class="text-sm text-gray-700 hover:text-blue-600"
|
||||
patch={~p"/sessions/#{@session.id}/app-docker"}
|
||||
</div>
|
||||
|
||||
<div class={["grid gap-2", @app && "grid-cols-2"]}>
|
||||
<span
|
||||
class={[
|
||||
"flex flex-col",
|
||||
not Livebook.Notebook.AppSettings.valid?(@settings) && "tooltip top"
|
||||
]}
|
||||
data-tooltip="You must configure the app to preview it"
|
||||
>
|
||||
<.remix_icon icon="arrow-right-line" />
|
||||
<span>Deploy with Docker</span>
|
||||
</.link>
|
||||
<%= if @app do %>
|
||||
<.button
|
||||
color="gray"
|
||||
outlined
|
||||
phx-click="deploy_app"
|
||||
disabled={not Livebook.Notebook.AppSettings.valid?(@settings)}
|
||||
>
|
||||
<.remix_icon icon="slideshow-4-line" /> Relaunch
|
||||
</.button>
|
||||
<% else %>
|
||||
<.button
|
||||
color="blue"
|
||||
phx-click="deploy_app"
|
||||
disabled={not Livebook.Notebook.AppSettings.valid?(@settings)}
|
||||
>
|
||||
<.remix_icon icon="slideshow-4-line" /> Launch preview
|
||||
</.button>
|
||||
<% end %>
|
||||
</span>
|
||||
<.button
|
||||
:if={@app}
|
||||
color="red"
|
||||
outlined
|
||||
type="button"
|
||||
phx-click="terminate_app"
|
||||
phx-target={@myself}
|
||||
>
|
||||
Terminate
|
||||
</.button>
|
||||
</div>
|
||||
</div>
|
||||
<%= if @app do %>
|
||||
<h3 class="mt-10 uppercase text-sm font-semibold text-gray-500">
|
||||
Latest deployment
|
||||
</h3>
|
||||
<div class="mt-2 border border-gray-200 rounded-lg">
|
||||
<div class="p-4 flex flex-col gap-3">
|
||||
<.labeled_text label="URL" one_line>
|
||||
<a href={~p"/apps/#{@app.slug}"}>
|
||||
<%= ~p"/apps/#{@app.slug}" %>
|
||||
</a>
|
||||
</.labeled_text>
|
||||
<div class="flex gap-3">
|
||||
<.labeled_text label="Session type" one_line class="grow">
|
||||
<%= if(@app.multi_session, do: "Multi", else: "Single") %>
|
||||
</.labeled_text>
|
||||
<.labeled_text label="Version" one_line class="grow">
|
||||
v<%= @app.version %>
|
||||
</.labeled_text>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 px-3 py-2 flex space-x-2">
|
||||
<div class="grow" />
|
||||
<span class="tooltip top" data-tooltip="Terminate">
|
||||
<.icon_button
|
||||
aria-label="terminate app"
|
||||
phx-click={JS.push("terminate_app", target: @myself)}
|
||||
>
|
||||
<.remix_icon icon="delete-bin-6-line" />
|
||||
</.icon_button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="mt-10 uppercase text-sm font-semibold text-gray-500">
|
||||
Running sessions
|
||||
</h3>
|
||||
<div class="mt-2 flex flex-col space-y-4">
|
||||
<div :for={app_session <- @app.sessions} class="w-full border border-gray-200 rounded-lg">
|
||||
<div class="p-4 flex gap-3">
|
||||
<.labeled_text label="Status" class="grow">
|
||||
<a
|
||||
class="inline-block"
|
||||
aria-label="debug app"
|
||||
href={app_session.app_status == :error && ~p"/sessions/#{app_session.id}"}
|
||||
target="_blank"
|
||||
>
|
||||
<.app_status status={app_session.app_status} />
|
||||
</a>
|
||||
</.labeled_text>
|
||||
<.labeled_text label="Version" class="grow">
|
||||
v<%= app_session.version %>
|
||||
</.labeled_text>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 px-3 py-2 flex space-x-2">
|
||||
<span class="tooltip top" data-tooltip="Open">
|
||||
<.icon_button
|
||||
disabled={app_session.app_status.lifecycle}
|
||||
aria-label="open app"
|
||||
href={~p"/apps/#{@app.slug}/#{app_session.id}"}
|
||||
>
|
||||
<.remix_icon icon="link" />
|
||||
</.icon_button>
|
||||
</span>
|
||||
<div class="grow" />
|
||||
<span class="tooltip top" data-tooltip="Debug">
|
||||
<.icon_button aria-label="debug app" href={~p"/sessions/#{app_session.id}"}>
|
||||
<.remix_icon icon="terminal-line" />
|
||||
</.icon_button>
|
||||
</span>
|
||||
<%= if app_session.app_status.lifecycle == :active do %>
|
||||
<span class="tooltip top" data-tooltip="Deactivate">
|
||||
<.icon_button
|
||||
aria-label="deactivate app session"
|
||||
phx-click={
|
||||
JS.push("deactivate_app_session",
|
||||
value: %{session_id: app_session.id},
|
||||
target: @myself
|
||||
)
|
||||
}
|
||||
>
|
||||
<.remix_icon icon="stop-circle-line" />
|
||||
</.icon_button>
|
||||
</span>
|
||||
<% else %>
|
||||
<span class="tooltip top" data-tooltip="Terminate">
|
||||
<.icon_button
|
||||
aria-label="terminate app session"
|
||||
phx-click={
|
||||
JS.push("terminate_app_session",
|
||||
value: %{session_id: app_session.id},
|
||||
target: @myself
|
||||
)
|
||||
}
|
||||
>
|
||||
<.remix_icon icon="delete-bin-6-line" />
|
||||
</.icon_button>
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp app_sessions(assigns) do
|
||||
~H"""
|
||||
<div :for={app_session <- @app.sessions} class="w-full border border-gray-200 rounded-lg">
|
||||
<div class="px-4 py-3 flex gap-3">
|
||||
<.labeled_text label="Status" class="grow">
|
||||
<a
|
||||
class="inline-block"
|
||||
aria-label="debug app"
|
||||
href={app_session.app_status == :error && ~p"/sessions/#{app_session.id}"}
|
||||
target="_blank"
|
||||
>
|
||||
<.app_status status={app_session.app_status} />
|
||||
</a>
|
||||
</.labeled_text>
|
||||
<.labeled_text label="Version" class="grow">
|
||||
v<%= app_session.version %>
|
||||
</.labeled_text>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 px-3 py-1 flex space-x-2">
|
||||
<div class="grow" />
|
||||
<span class="tooltip top" data-tooltip="Open">
|
||||
<.icon_button
|
||||
disabled={app_session.app_status.lifecycle != :active}
|
||||
aria-label="open app"
|
||||
href={~p"/apps/#{@app.slug}/#{app_session.id}"}
|
||||
>
|
||||
<.remix_icon icon="link" />
|
||||
</.icon_button>
|
||||
</span>
|
||||
<span class="tooltip top" data-tooltip="Debug">
|
||||
<.icon_button aria-label="debug app" href={~p"/sessions/#{app_session.id}"}>
|
||||
<.remix_icon icon="terminal-line" />
|
||||
</.icon_button>
|
||||
</span>
|
||||
<%= if app_session.app_status.lifecycle == :active do %>
|
||||
<span class="tooltip top" data-tooltip="Deactivate">
|
||||
<.icon_button
|
||||
aria-label="deactivate app session"
|
||||
phx-click={
|
||||
JS.push("deactivate_app_session",
|
||||
value: %{session_id: app_session.id},
|
||||
target: @myself
|
||||
)
|
||||
}
|
||||
>
|
||||
<.remix_icon icon="stop-circle-line" />
|
||||
</.icon_button>
|
||||
</span>
|
||||
<% else %>
|
||||
<span class="tooltip top" data-tooltip="Terminate">
|
||||
<.icon_button
|
||||
aria-label="terminate app session"
|
||||
phx-click={
|
||||
JS.push("terminate_app_session",
|
||||
value: %{session_id: app_session.id},
|
||||
target: @myself
|
||||
)
|
||||
}
|
||||
>
|
||||
<.remix_icon icon="delete-bin-6-line" />
|
||||
</.icon_button>
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
defp app_info_icon(assigns) do
|
||||
~H"""
|
||||
<span
|
||||
|
@ -183,7 +231,7 @@ defmodule LivebookWeb.SessionLive.AppInfoComponent do
|
|||
|
||||
@impl true
|
||||
def handle_event("terminate_app", %{}, socket) do
|
||||
{:noreply, confirm_app_termination(socket, socket.assigns.app.pid)}
|
||||
{:noreply, confirm_app_termination(socket, socket.assigns.app.pid, "preview")}
|
||||
end
|
||||
|
||||
def handle_event("terminate_app_session", %{"session_id" => session_id}, socket) do
|
||||
|
|
|
@ -24,7 +24,14 @@ defmodule LivebookWeb.SessionLive.AppSettingsComponent do
|
|||
<h3 class="text-2xl font-semibold text-gray-800">
|
||||
App settings
|
||||
</h3>
|
||||
<.form :let={f} for={@changeset} phx-change="validate" phx-target={@myself} autocomplete="off">
|
||||
<.form
|
||||
:let={f}
|
||||
for={@changeset}
|
||||
phx-change="validate"
|
||||
phx-submit="save"
|
||||
phx-target={@myself}
|
||||
autocomplete="off"
|
||||
>
|
||||
<div class="flex flex-col space-y-4">
|
||||
<.text_field field={f[:slug]} label="Slug" spellcheck="false" phx-debounce />
|
||||
<div class="flex flex-col space-y-1">
|
||||
|
@ -118,13 +125,8 @@ defmodule LivebookWeb.SessionLive.AppSettingsComponent do
|
|||
<% end %>
|
||||
</div>
|
||||
<div class="mt-8 flex space-x-2">
|
||||
<.button
|
||||
type="button"
|
||||
phx-click={JS.patch(~p"/sessions/#{@session.id}") |> JS.push("deploy_app")}
|
||||
disabled={not @changeset.valid?}
|
||||
>
|
||||
<.remix_icon icon="rocket-line" />
|
||||
<span>Deploy</span>
|
||||
<.button type="submit" disabled={not @changeset.valid?}>
|
||||
<span>Save</span>
|
||||
</.button>
|
||||
<.button color="gray" outlined type="reset" name="reset">
|
||||
Reset
|
||||
|
@ -148,10 +150,14 @@ defmodule LivebookWeb.SessionLive.AppSettingsComponent do
|
|||
|> AppSettings.change(params)
|
||||
|> Map.put(:action, :validate)
|
||||
|
||||
{:noreply, assign(socket, changeset: changeset)}
|
||||
end
|
||||
|
||||
def handle_event("save", %{"app_settings" => params}, socket) do
|
||||
with {:ok, settings} <- AppSettings.update(socket.assigns.settings, params) do
|
||||
Livebook.Session.set_app_settings(socket.assigns.session.pid, settings)
|
||||
end
|
||||
|
||||
{:noreply, assign(socket, changeset: changeset)}
|
||||
{:noreply, push_patch(socket, to: ~p"/sessions/#{socket.assigns.session.id}")}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -30,7 +30,7 @@ defmodule LivebookWeb.SessionLive.ElixirStandaloneLive do
|
|||
<%= @error_message %>
|
||||
</div>
|
||||
<p class="text-gray-700">
|
||||
Start a new local node to handle code evaluation.
|
||||
Start a new local node to evaluate code.
|
||||
</p>
|
||||
<.button phx-click="init">
|
||||
<%= if(matching_runtime?(@current_runtime), do: "Reconnect", else: "Connect") %>
|
||||
|
|
|
@ -323,20 +323,11 @@ defmodule LivebookWeb.SessionLive.Render do
|
|||
button_attrs={["data-el-files-list-toggle": true]}
|
||||
/>
|
||||
|
||||
<div class="relative">
|
||||
<.button_item
|
||||
icon="rocket-line"
|
||||
label="App settings (sa)"
|
||||
button_attrs={["data-el-app-info-toggle": true]}
|
||||
/>
|
||||
<div
|
||||
data-el-app-indicator
|
||||
class={[
|
||||
"absolute w-[12px] h-[12px] border-gray-900 border-2 rounded-full right-1.5 top-1.5 pointer-events-none",
|
||||
app_status_color(app_status(@app))
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<.button_item
|
||||
icon="rocket-line"
|
||||
label="App settings (sa)"
|
||||
button_attrs={["data-el-app-info-toggle": true]}
|
||||
/>
|
||||
|
||||
<div class="grow"></div>
|
||||
|
||||
|
@ -373,17 +364,6 @@ defmodule LivebookWeb.SessionLive.Render do
|
|||
"""
|
||||
end
|
||||
|
||||
defp app_status(%{sessions: [app_session | _]}), do: app_session.app_status
|
||||
defp app_status(_), do: nil
|
||||
|
||||
defp app_status_color(nil), do: "bg-gray-400"
|
||||
defp app_status_color(%{lifecycle: :shutting_down}), do: "bg-gray-500"
|
||||
defp app_status_color(%{lifecycle: :deactivated}), do: "bg-gray-500"
|
||||
defp app_status_color(%{execution: :executing}), do: "bg-blue-500"
|
||||
defp app_status_color(%{execution: :executed}), do: "bg-green-bright-400"
|
||||
defp app_status_color(%{execution: :error}), do: "bg-red-400"
|
||||
defp app_status_color(%{execution: :interrupted}), do: "bg-gray-400"
|
||||
|
||||
def side_panel(assigns) do
|
||||
~H"""
|
||||
<div
|
||||
|
@ -601,9 +581,19 @@ defmodule LivebookWeb.SessionLive.Render do
|
|||
<h3 class="uppercase text-sm font-semibold text-gray-500">
|
||||
Runtime
|
||||
</h3>
|
||||
<.icon_button patch={~p"/sessions/#{@session.id}/settings/runtime"}>
|
||||
<.remix_icon icon="settings-3-line" />
|
||||
</.icon_button>
|
||||
<span
|
||||
class="tooltip bottom-left"
|
||||
data-tooltip={
|
||||
~S'''
|
||||
The runtime configures which Erlang VM
|
||||
instance the notebook code runs on.
|
||||
'''
|
||||
}
|
||||
>
|
||||
<.icon_button>
|
||||
<.remix_icon icon="question-line" />
|
||||
</.icon_button>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-col mt-2 space-y-4">
|
||||
<div class="flex flex-col space-y-3">
|
||||
|
@ -615,37 +605,47 @@ defmodule LivebookWeb.SessionLive.Render do
|
|||
<%= value %>
|
||||
</.labeled_text>
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<%= if Runtime.connected?(@data_view.runtime) do %>
|
||||
<.button phx-click="reconnect_runtime">
|
||||
<.remix_icon icon="wireless-charging-line" />
|
||||
<span>Reconnect</span>
|
||||
</.button>
|
||||
<.button color="red" outlined type="button" phx-click="disconnect_runtime">
|
||||
Disconnect
|
||||
</.button>
|
||||
<% else %>
|
||||
<.button phx-click="connect_runtime">
|
||||
<.remix_icon icon="wireless-charging-line" />
|
||||
<span>Connect</span>
|
||||
</.button>
|
||||
<.button color="gray" outlined patch={~p"/sessions/#{@session.id}/settings/runtime"}>
|
||||
Configure
|
||||
</.button>
|
||||
<% end %>
|
||||
<.button color="gray" outlined patch={~p"/sessions/#{@session.id}/settings/runtime"}>
|
||||
Configure
|
||||
</.button>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col pt-6 space-y-2">
|
||||
<%= if uses_memory?(@session.memory_usage) do %>
|
||||
<.memory_info memory_usage={@session.memory_usage} />
|
||||
<% else %>
|
||||
<div class="text-sm text-gray-800 flex flex-col">
|
||||
<span class="w-full uppercase font-semibold text-gray-500">Memory</span>
|
||||
<p class="py-1">
|
||||
<%= format_bytes(@session.memory_usage.system.free) %> available out of <%= format_bytes(
|
||||
@session.memory_usage.system.total
|
||||
) %>
|
||||
</p>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<.button
|
||||
:if={Runtime.connected?(@data_view.runtime)}
|
||||
color="red"
|
||||
outlined
|
||||
type="button"
|
||||
phx-click="disconnect_runtime"
|
||||
>
|
||||
Disconnect
|
||||
</.button>
|
||||
</div>
|
||||
<%= if uses_memory?(@session.memory_usage) do %>
|
||||
<.memory_info memory_usage={@session.memory_usage} />
|
||||
<% else %>
|
||||
<div class="mb-1 text-sm text-gray-800 py-6 flex flex-col">
|
||||
<span class="w-full uppercase font-semibold text-gray-500">Memory</span>
|
||||
<p class="py-1">
|
||||
<%= format_bytes(@session.memory_usage.system.free) %> available out of <%= format_bytes(
|
||||
@session.memory_usage.system.total
|
||||
) %>
|
||||
</p>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
@ -655,7 +655,7 @@ defmodule LivebookWeb.SessionLive.Render do
|
|||
assigns = assign(assigns, :runtime_memory, runtime_memory(assigns.memory_usage))
|
||||
|
||||
~H"""
|
||||
<div class="py-6 flex flex-col justify-center">
|
||||
<div class="flex flex-col justify-center">
|
||||
<div class="mb-1 text-sm text-gray-800 flex flex-row justify-between">
|
||||
<span class="text-gray-500 font-semibold uppercase">Memory</span>
|
||||
<span class="text-right">
|
||||
|
|
|
@ -2127,7 +2127,11 @@ defmodule LivebookWeb.SessionLiveTest do
|
|||
|> render_change(%{"app_settings" => %{"slug" => slug}})
|
||||
|
||||
view
|
||||
|> element(~s/#app-settings-modal button/, "Deploy")
|
||||
|> element(~s/#app-settings-modal form/)
|
||||
|> render_submit(%{"app_settings" => %{"slug" => slug}})
|
||||
|
||||
view
|
||||
|> element(~s/[data-el-app-info] button/, "Launch preview")
|
||||
|> render_click()
|
||||
|
||||
assert_receive {:app_created, %{slug: ^slug} = app}
|
||||
|
|
Loading…
Reference in a new issue