defmodule LivebookWeb.SessionLive.AppInfoComponent do use LivebookWeb, :live_component import LivebookWeb.AppComponents @impl true def render(assigns) do ~H"""

App

<.app_info_icon />
<%= if @session.mode == :app do %>
<.message_box kind={:info} message="This session is a running app. To deploy a modified version, you can fork it." />
<.button phx-click="fork_session"> <.remix_icon icon="git-branch-line" /> Fork
<% else %>
<.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." />
<.labeled_text label="Slug" one_line> <%= @settings.slug || "?" %> <.labeled_text label="Session type" one_line> <%= if @settings.multi_session, do: "Multi", else: "Single" %> <.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 %>
<.button color="gray" outlined patch={~p"/sessions/#{@session.id}/settings/app"}> Configure

Remote deployment

<%!-- TODO: Livebook Teams flow --%> <.button color="blue" patch={~p"/sessions/#{@session.id}/app-docker"}> <.remix_icon icon="rocket-line" /> Deploy with Livebook Teams <.button color="gray" outlined patch={~p"/sessions/#{@session.id}/app-docker"}> <.remix_icon icon="ship-line" /> Manual Docker deployment

Local preview

<.labeled_text label="URL" one_line> <%= ~p"/apps/#{@app.slug}" %> <.labeled_text :if={@app.multi_session} label="Latest version" one_line> v<%= @app.version %>
Running sessions
<.app_sessions app={@app} myself={@myself} />
<%= 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 <% else %> <.button color="blue" phx-click="deploy_app" disabled={not Livebook.Notebook.AppSettings.valid?(@settings)} > <.remix_icon icon="slideshow-4-line" /> Launch preview <% end %> <.button :if={@app} color="red" outlined type="button" phx-click="terminate_app" phx-target={@myself} > Terminate
<% end %>
""" end defp app_sessions(assigns) do ~H"""
<.labeled_text label="Status" class="grow"> <.app_status status={app_session.app_status} /> <.labeled_text label="Version" class="grow"> v<%= app_session.version %>
<.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 aria-label="debug app" href={~p"/sessions/#{app_session.id}"}> <.remix_icon icon="terminal-line" /> <%= if app_session.app_status.lifecycle == :active do %> <.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" /> <% else %> <.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" /> <% end %>
""" end defp app_info_icon(assigns) do ~H""" <.icon_button> <.remix_icon icon="question-line" /> """ 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