Packages
livebook
0.17.3
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/app_live.ex
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)}
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"""
<div class="h-full relative overflow-y-auto px-4 md:px-20">
<div class="w-full max-w-screen-lg py-4 mx-auto">
<div class="absolute md:fixed right-8 md:left-4 top-3 w-10 h-10">
<.link navigate={~p"/"}>
<img src={~p"/images/logo.png"} height="40" widthz="40" alt="logo livebook" />
</.link>
</div>
<div class="flex items-center pb-4 mb-2 space-x-4 border-b border-gray-200 pr-20 md:pr-0">
<h1 class="text-3xl font-semibold text-gray-800">
{@app.notebook_name}
</h1>
</div>
<div class="pt-4 flex flex-col space-y-16">
<.content_skeleton :for={_idx <- 1..5} empty={false} />
</div>
</div>
</div>
<.modal id="sessions-modal" show width="big" patch={~p"/apps"}>
<div class="flex flex-col space-y-3">
<h3 class="text-2xl font-semibold text-gray-800">
{@app.notebook_name}
</h3>
<p class="text-gray-700">
<%= 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 %>
</p>
<div class="flex justify-end">
<.button outlined patch={~p"/apps/#{@app.slug}/new"}>
<.remix_icon icon="add-line" />
<span>New session</span>
</.button>
</div>
<div :if={@app_settings.show_existing_sessions} class="w-full flex flex-col space-y-4">
<.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"
>
<span>
Started
<span :if={app_session.started_by}>
by <span class="font-semibold">{app_session.started_by.name || "Anonymous"}</span>
</span>
{LivebookWeb.HTMLHelpers.format_datetime_relatively(app_session.created_at)} ago
</span>
<div class="mr-0.5 flex">
<.app_status status={app_session.app_status} show_label={false} />
</div>
</.link>
</div>
</div>
</.modal>
"""
end
def render(assigns) when not assigns.app_authorized? do
~H"""
<LivebookWeb.ErrorHTML.error_page
status={401}
title="Not authorized"
details="You don't have permission to access this app"
/>
"""
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