Packages
livebook
0.14.2
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Current section
Files
Jump to
Current section
Files
lib/livebook_web/live/session_live/app_info_component.ex
defmodule LivebookWeb.SessionLive.AppInfoComponent do
use LivebookWeb, :live_component
import LivebookWeb.AppComponents
@impl true
def render(assigns) do
~H"""
<div class="flex flex-col" data-el-app-info>
<div class="flex items-center justify-between">
<h3 class="uppercase text-sm font-semibold text-gray-500">
App
</h3>
<.app_info_icon />
</div>
<%= if @session.mode == :app do %>
<div class="mt-5 flex flex-col">
<.message_box
kind={:info}
message="This session is a running app. To deploy a modified version, you can fork it."
/>
<div class="mt-6">
<.button phx-click="fork_session">
<.remix_icon icon="git-branch-line" />
<span>Fork</span>
</.button>
</div>
</div>
<% else %>
<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 Workspace secrets instead."
/>
<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">
<.button
color="blue"
patch={
cond do
Livebook.Hubs.Provider.type(@hub) != "team" ->
~p"/sessions/#{@session.id}/app-teams-hub-info"
not Livebook.Notebook.AppSettings.valid?(@settings) ->
~p"/sessions/#{@session.id}/settings/app?context=app-teams"
true ->
~p"/sessions/#{@session.id}/app-teams"
end
}
>
<.remix_icon icon="rocket-line" /> Deploy with Livebook Teams
</.button>
<.button
color="gray"
outlined
patch={
if Livebook.Notebook.AppSettings.valid?(@settings),
do: ~p"/sessions/#{@session.id}/app-docker",
else: ~p"/sessions/#{@session.id}/settings/app?context=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>
</div>
<div class={["grid gap-2", @app && "grid-cols-2"]}>
<span class="flex flex-col">
<%= if @app do %>
<.button color="gray" outlined phx-click="deploy_app">
<.remix_icon icon="slideshow-4-line" /> Relaunch
</.button>
<% else %>
<.button color="blue" phx-click="deploy_app">
<.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>
<% 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}/sessions/#{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
class="tooltip bottom-left"
data-tooltip={
~S'''
App deployment is a way to share your
notebook for people to interact with. Use
inputs and controls to build interactive
UIs, perfect for demos and tasks.
'''
}
>
<.icon_button>
<.remix_icon icon="question-line" />
</.icon_button>
</span>
"""
end
@impl true
def handle_event("terminate_app", %{}, socket) do
{:noreply, confirm_app_termination(socket, socket.assigns.app.pid, "preview")}
end
def handle_event("terminate_app_session", %{"session_id" => session_id}, socket) do
app_session = Enum.find(socket.assigns.app.sessions, &(&1.id == session_id))
Livebook.Session.close(app_session.pid)
{:noreply, socket}
end
def handle_event("deactivate_app_session", %{"session_id" => session_id}, socket) do
app_session = Enum.find(socket.assigns.app.sessions, &(&1.id == session_id))
Livebook.Session.app_deactivate(app_session.pid)
{:noreply, socket}
end
end