defmodule LivebookWeb.AppLive do
use LivebookWeb, :live_view
import LivebookWeb.AppComponents
@impl true
def mount(%{"slug" => slug}, _session, socket) when not socket.assigns.app_authenticated? do
if connected?(socket) do
{:ok, push_navigate(socket, to: ~p"/apps/#{slug}/authenticate")}
else
{:ok, socket}
end
end
def mount(%{"slug" => slug}, _session, socket) when not socket.assigns.app_authorized? do
if connected?(socket) do
Livebook.Teams.Broadcasts.subscribe(:app_deployments)
end
{:ok, app} = Livebook.Apps.fetch_app(slug)
{:ok, assign(socket, app: app), layout: false}
end
def mount(%{"slug" => slug}, _session, socket) do
if socket.assigns.app_settings.multi_session do
{:ok, app} = Livebook.Apps.fetch_app(slug)
if connected?(socket) do
Livebook.App.subscribe(slug)
Livebook.Teams.Broadcasts.subscribe(:app_deployments)
end
{:ok, assign(socket, app: app, apps_banner: Livebook.Config.apps_banner())}
else
{:ok, pid} = Livebook.Apps.fetch_pid(slug)
session_id = Livebook.App.get_session_id(pid, user: socket.assigns.current_user)
{:ok, push_navigate(socket, to: ~p"/apps/#{slug}/sessions/#{session_id}")}
end
end
@impl true
def render(assigns) when assigns.app_authenticated? and assigns.app_authorized? do
~H"""
<.apps_banner value={@apps_banner} />
{@app.notebook_name}
<.content_skeleton :for={_idx <- 1..5} empty={false} />
<.modal id="sessions-modal" show width="big" patch={~p"/apps"}>
{@app.notebook_name}
<%= if @app_settings.show_existing_sessions do %>
This is a multi-session app, pick an existing session or create a new one.
<% else %>
This is a multi-session app, create a new one to get started.
<% end %>
<.button outlined patch={~p"/apps/#{@app.slug}/new"}>
<.remix_icon icon="add-line" />
New session
<.link
:for={app_session <- active_sessions(@app.sessions)}
navigate={~p"/apps/#{@app.slug}/sessions/#{app_session.id}"}
class="px-4 py-3 border border-gray-200 rounded-xl text-gray-800 pointer hover:bg-gray-50 flex justify-between"
>
Started
by {app_session.started_by.name || "Anonymous"}
{LivebookWeb.HTMLHelpers.format_datetime_relatively(app_session.created_at)} ago
<.app_status status={app_session.app_status} show_label={false} />
"""
end
def render(assigns) when not assigns.app_authorized? do
~H"""
"""
end
def render(assigns), do: auth_placeholder(assigns)
@impl true
def handle_params(_params, _url, socket) when socket.assigns.live_action == :new_session do
session_id =
Livebook.App.get_session_id(socket.assigns.app.pid, user: socket.assigns.current_user)
{:noreply,
push_navigate(socket, to: ~p"/apps/#{socket.assigns.app.slug}/sessions/#{session_id}")}
end
def handle_params(_params, _url, socket), do: {:noreply, socket}
@impl true
def handle_info({:app_updated, app}, socket) do
{:noreply, assign(socket, :app, app)}
end
def handle_info(
{:app_deployment_updated, %{slug: slug}},
%{assigns: %{app: %{slug: slug} = app}} = socket
) do
if socket.assigns.app_authorized? and
Livebook.Apps.authorized?(app, socket.assigns.current_user) do
{:noreply, socket}
else
{:noreply, redirect(socket, to: ~p"/apps/#{slug}")}
end
end
def handle_info(_message, socket), do: {:noreply, socket}
defp active_sessions(sessions) do
Enum.filter(sessions, &(&1.app_status.lifecycle == :active))
end
end