List public apps on the auth screen (#1757)

This commit is contained in:
Jonatan Kłosko 2023-03-07 23:37:57 +01:00 committed by GitHub
parent 1cdc5251dd
commit 96c24d7002
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 129 additions and 51 deletions

View file

@ -115,7 +115,8 @@ defmodule Livebook.Session do
@type app_info :: %{
slug: String.t(),
status: Data.app_status(),
registered: boolean()
registered: boolean(),
public?: boolean()
}
@typedoc """
@ -1529,7 +1530,8 @@ defmodule Livebook.Session do
%{
slug: state.data.notebook.app_settings.slug,
status: state.data.app_data.status,
registered: state.data.app_data.registered
registered: state.data.app_data.registered,
public?: state.data.notebook.app_settings.access_type == :public
}
end
}

View file

@ -22,7 +22,12 @@ defmodule LivebookWeb.AuthController do
end
def index(conn, _params) do
render(conn, "index.html", errors: [], auth_mode: Livebook.Config.auth_mode())
render(conn, "index.html",
errors: [],
auth_mode: Livebook.Config.auth_mode(),
app_sessions: app_sessions(),
empty_apps_path?: empty_apps_path?()
)
end
def authenticate(conn, %{"password" => password}) do
@ -47,7 +52,13 @@ defmodule LivebookWeb.AuthController do
defp render_form_error(conn, auth_mode) do
errors = [{"%{auth_mode} is invalid", [auth_mode: auth_mode]}]
render(conn, "index.html", errors: errors, auth_mode: auth_mode)
render(conn, "index.html",
errors: errors,
auth_mode: auth_mode,
app_sessions: app_sessions(),
empty_apps_path?: empty_apps_path?()
)
end
defp redirect_to(conn) do
@ -63,4 +74,19 @@ defmodule LivebookWeb.AuthController do
end)
|> halt()
end
defp app_sessions() do
Livebook.Sessions.list_sessions()
|> Enum.filter(&(&1.mode == :app and &1.app_info.public? and &1.app_info.registered))
|> 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

View file

@ -1,53 +1,103 @@
<div class="h-screen flex items-center justify-center bg-gray-900">
<div class="flex flex-col space-y-4 items-center">
<a href={~p"/"}>
<img src={~p"/images/logo.png"} height="128" width="128" alt="livebook" />
</a>
<div class="text-2xl text-gray-50">
Authentication required
</div>
<div class="h-screen w-full flex flex-col sm:flex-row">
<div class="w-full h-full px-4 py-8 bg-gray-900 flex justify-center items-center">
<div class="max-w-[400px] w-full flex flex-col">
<a href={~p"/"} class="mb-8">
<img src={~p"/images/logo.png"} height="128" width="128" alt="livebook" />
</a>
<div class="mb-2 text-2xl text-gray-100 font-medium">
Authentication required
</div>
<div class="max-w-2xl text-center text-gray-300">
<span :if={@auth_mode == :password}>
Type password to access the Livebook.
</span>
<span :if={@auth_mode == :token}>
Please check out the console for authentication URL or type the token directly
here.<br />To use password authentication, set the <code>LIVEBOOK_PASSWORD</code>
environment variable.
</span>
</div>
<div class="text-2xl text-gray-50 w-full pt-2">
<form method="post" class="flex flex-col space-y-4 items-center">
<input type="hidden" value={Phoenix.Controller.get_csrf_token()} name="_csrf_token" />
<div phx-feedback-for={@auth_mode} class={["w-[20ch]", @errors != [] && "show-errors"]}>
<input
:if={@auth_mode == :password}
type="password"
name="password"
class="input"
placeholder="Password"
autofocus
/>
<input
:if={@auth_mode == :token}
type="text"
name="token"
class="input"
placeholder="Token"
autofocus
/>
<span
:for={error <- @errors}
class="mt-1 hidden text-red-600 text-sm phx-form-error:block"
<div class="mb-10 text-gray-200">
<span :if={@auth_mode == :password}>
Type password to access the Livebook.
</span>
<span :if={@auth_mode == :token}>
Please check out the console for authentication URL or type the token directly
here.<br />To use password authentication, set the <code>LIVEBOOK_PASSWORD</code>
environment variable.
</span>
</div>
<div class="text-gray-50 w-full">
<form method="post" class="flex flex-col w-full">
<input type="hidden" value={Phoenix.Controller.get_csrf_token()} name="_csrf_token" />
<div phx-feedback-for={@auth_mode} class={[@errors != [] && "show-errors"]}>
<input
:if={@auth_mode == :password}
type="password"
name="password"
class="px-4 py-3 w-full text-gray-300 placeholder-gray-400 border border-gray-500 rounded-lg bg-transparent phx-form-error:border-red-600 phx-form-error:text-red-600 phx-form-error:placeholder-red-600"
placeholder="Password"
autofocus
/>
<input
:if={@auth_mode == :token}
type="text"
name="token"
class="px-4 py-3 w-full text-gray-300 placeholder-gray-400 border border-gray-500 rounded-lg bg-transparent phx-form-error:border-red-600 phx-form-error:text-red-600 phx-form-error:placeholder-red-600"
placeholder="Token"
autofocus
/>
<span
:for={error <- @errors}
class="mt-1 hidden text-red-600 text-sm phx-form-error:block"
>
<%= translate_error(error) %>
</span>
</div>
<button
type="submit"
class="mt-8 px-4 py-3 w-full rounded-lg text-gray-200 bg-blue-600 hover:bg-blue-700 focus:bg-blue-700"
>
<%= translate_error(error) %>
</span>
<span>Authenticate</span>
<.remix_icon icon="arrow-right-line" class="ml-1 align-middle" />
</button>
</form>
</div>
</div>
</div>
<div
:if={@app_sessions != [] or @empty_apps_path?}
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="text-gray-700 text-xl font-medium">
Public apps
</div>
<div :if={@app_sessions != []} class="mt-5 max-w-[400px] w-full flex flex-col space-y-4">
<.link
: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 text-lg 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 :if={@empty_apps_path?} class="mt-5 text-gray-600">
<div>
No app notebooks found. To list your apps here follow these steps:
</div>
<button type="submit" class="button-base button-blue">
Authenticate
</button>
</form>
<ol class="mt-4 pl-4 flex flex-col space-y-1 list-decimal list-inside">
<li>
Open a notebook
</li>
<li>
Click <.remix_icon icon="rocket-line" class="align-sub text-lg" />
in the sidebar, configure the app and make sure it is public
</li>
<li>
Place the notebook in the
<span class="font-medium"><%= Livebook.Config.apps_path() %></span>
folder
</li>
<li>
Relaunch your Livebook app
</li>
</ol>
</div>
</div>
</div>
</div>