mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-12-11 06:05:56 +08:00
Make the app list on auth screen live (#1836)
This commit is contained in:
parent
dbab38a763
commit
92bb567645
5 changed files with 85 additions and 32 deletions
|
|
@ -140,4 +140,17 @@ defmodule Livebook.Apps do
|
||||||
|
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Checks if the apps directory is configured and contains no notebooks.
|
||||||
|
"""
|
||||||
|
@spec empty_apps_path?() :: boolean()
|
||||||
|
def empty_apps_path?() do
|
||||||
|
if path = Livebook.Config.apps_path() do
|
||||||
|
pattern = Path.join([path, "**", "*.livemd"])
|
||||||
|
Path.wildcard(pattern) == []
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,8 @@ defmodule LivebookWeb.AuthController do
|
||||||
render(conn, "index.html",
|
render(conn, "index.html",
|
||||||
errors: [],
|
errors: [],
|
||||||
auth_mode: Livebook.Config.auth_mode(),
|
auth_mode: Livebook.Config.auth_mode(),
|
||||||
app_sessions: app_sessions(),
|
any_public_app?: any_public_app?(),
|
||||||
empty_apps_path?: empty_apps_path?()
|
empty_apps_path?: Livebook.Apps.empty_apps_path?()
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -56,8 +56,8 @@ defmodule LivebookWeb.AuthController do
|
||||||
render(conn, "index.html",
|
render(conn, "index.html",
|
||||||
errors: errors,
|
errors: errors,
|
||||||
auth_mode: auth_mode,
|
auth_mode: auth_mode,
|
||||||
app_sessions: app_sessions(),
|
any_public_app?: any_public_app?(),
|
||||||
empty_apps_path?: empty_apps_path?()
|
empty_apps_path?: Livebook.Apps.empty_apps_path?()
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -75,18 +75,8 @@ defmodule LivebookWeb.AuthController do
|
||||||
|> halt()
|
|> halt()
|
||||||
end
|
end
|
||||||
|
|
||||||
defp app_sessions() do
|
defp any_public_app?() do
|
||||||
Livebook.Sessions.list_sessions()
|
Livebook.Sessions.list_sessions()
|
||||||
|> Enum.filter(&(&1.mode == :app and &1.app_info.public? and &1.app_info.registered))
|
|> Enum.any?(&(&1.mode == :app and &1.app_info.public?))
|
||||||
|> Enum.sort_by(& &1.notebook_name)
|
|
||||||
end
|
|
||||||
|
|
||||||
defp empty_apps_path?() do
|
|
||||||
if path = Livebook.Config.apps_path() do
|
|
||||||
pattern = Path.join([path, "**", "*.livemd"])
|
|
||||||
Path.wildcard(pattern) == []
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -62,22 +62,15 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
:if={@app_sessions != [] or @empty_apps_path?}
|
:if={@any_public_app? or @empty_apps_path?}
|
||||||
class="w-full h-full px-4 py-8 flex justify-center items-center"
|
class="w-full h-full px-4 py-8 flex justify-center items-center"
|
||||||
>
|
>
|
||||||
<div class="w-full flex flex-col items-center">
|
<div class="w-full flex flex-col items-center">
|
||||||
<div class="text-gray-700 text-xl font-medium">
|
<div class="text-gray-700 text-xl font-medium">
|
||||||
Public apps
|
Public apps
|
||||||
</div>
|
</div>
|
||||||
<div :if={@app_sessions != []} class="mt-5 max-w-[400px] w-full flex flex-col space-y-4">
|
<div :if={@any_public_app?} class="w-full mt-5 mx-auto max-w-[400px]">
|
||||||
<.link
|
<%= live_render(@conn, LivebookWeb.AuthAppListLive) %>
|
||||||
:for={session <- @app_sessions}
|
|
||||||
navigate={~p"/apps/#{session.app_info.slug}"}
|
|
||||||
class="px-4 py-3 border border-gray-200 rounded-xl text-gray-800 pointer hover:bg-gray-50 flex justify-between"
|
|
||||||
>
|
|
||||||
<span class="font-semibold"><%= session.notebook_name %></span>
|
|
||||||
<.remix_icon icon="arrow-right-line" class="" />
|
|
||||||
</.link>
|
|
||||||
</div>
|
</div>
|
||||||
<div :if={@empty_apps_path?} class="mt-5 text-gray-600">
|
<div :if={@empty_apps_path?} class="mt-5 text-gray-600">
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -5,41 +5,42 @@ defmodule LivebookWeb.AppHelpers do
|
||||||
Renders app status with indicator.
|
Renders app status with indicator.
|
||||||
"""
|
"""
|
||||||
attr :status, :atom, required: true
|
attr :status, :atom, required: true
|
||||||
|
attr :show_label, :boolean, default: true
|
||||||
|
|
||||||
def app_status(%{status: :booting} = assigns) do
|
def app_status(%{status: :booting} = assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<.app_status_indicator text="Booting" variant={:progressing} />
|
<.app_status_indicator text={@show_label && "Booting"} variant={:progressing} />
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
def app_status(%{status: :running} = assigns) do
|
def app_status(%{status: :running} = assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<.app_status_indicator text="Running" variant={:success} />
|
<.app_status_indicator text={@show_label && "Running"} variant={:success} />
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
def app_status(%{status: :error} = assigns) do
|
def app_status(%{status: :error} = assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<.app_status_indicator text="Error" variant={:error} />
|
<.app_status_indicator text={@show_label && "Error"} variant={:error} />
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
def app_status(%{status: :shutting_down} = assigns) do
|
def app_status(%{status: :shutting_down} = assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<.app_status_indicator text="Shutting down" variant={:inactive} />
|
<.app_status_indicator text={@show_label && "Shutting down"} variant={:inactive} />
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
def app_status(%{status: :stopped} = assigns) do
|
def app_status(%{status: :stopped} = assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<.app_status_indicator text="Stopped" variant={:inactive} />
|
<.app_status_indicator text={@show_label && "Stopped"} variant={:inactive} />
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp app_status_indicator(assigns) do
|
defp app_status_indicator(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="flex items-center space-x-2">
|
<div class="flex items-center space-x-2">
|
||||||
<div><%= @text %></div>
|
<div :if={@text}><%= @text %></div>
|
||||||
<.status_indicator variant={@variant} />
|
<.status_indicator variant={@variant} />
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
56
lib/livebook_web/live/auth_app_list_live.ex
Normal file
56
lib/livebook_web/live/auth_app_list_live.ex
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
defmodule LivebookWeb.AuthAppListLive do
|
||||||
|
use LivebookWeb, :live_view
|
||||||
|
|
||||||
|
import LivebookWeb.AppHelpers
|
||||||
|
import LivebookWeb.SessionHelpers
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def mount(_params, _session, socket) do
|
||||||
|
if connected?(socket) do
|
||||||
|
Livebook.Sessions.subscribe()
|
||||||
|
end
|
||||||
|
|
||||||
|
sessions = Livebook.Sessions.list_sessions() |> Enum.filter(&(&1.mode == :app))
|
||||||
|
|
||||||
|
{:ok, assign(socket, sessions: sessions), layout: false}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def render(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div class="w-full flex flex-col space-y-4">
|
||||||
|
<.link
|
||||||
|
:for={session <- visible_sessions(@sessions)}
|
||||||
|
navigate={~p"/apps/#{session.app_info.slug}"}
|
||||||
|
class={[
|
||||||
|
"px-4 py-3 border border-gray-200 rounded-xl text-gray-800 pointer hover:bg-gray-50 flex justify-between",
|
||||||
|
not session.app_info.registered && "pointer-events-none"
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<span class="font-semibold"><%= session.notebook_name %></span>
|
||||||
|
<%= if session.app_info.registered do %>
|
||||||
|
<.remix_icon icon="arrow-right-line" class="" />
|
||||||
|
<% else %>
|
||||||
|
<div class="mr-0.5 flex">
|
||||||
|
<.app_status status={session.app_info.status} show_label={false} />
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
</.link>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_info({type, session} = event, socket)
|
||||||
|
when type in [:session_created, :session_updated, :session_closed] and session.mode == :app do
|
||||||
|
{:noreply, update(socket, :sessions, &update_session_list(&1, event))}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_info(_message, socket), do: {:noreply, socket}
|
||||||
|
|
||||||
|
defp visible_sessions(sessions) do
|
||||||
|
sessions
|
||||||
|
|> Enum.filter(& &1.app_info.public?)
|
||||||
|
|> Enum.sort_by(& &1.notebook_name)
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Add table
Reference in a new issue