mirror of
https://github.com/livebook-dev/livebook.git
synced 2025-10-10 13:38:09 +08:00
Simplify code that is no longer shared across views
This commit is contained in:
parent
4c6869d69c
commit
cb11b26cdc
9 changed files with 135 additions and 153 deletions
|
@ -309,7 +309,7 @@ defmodule Livebook.Teams.Requests do
|
||||||
|
|
||||||
{:ok, %{status: 401}} ->
|
{:ok, %{status: 401}} ->
|
||||||
{:transport_error,
|
{:transport_error,
|
||||||
"You are not authorized to perform this action, make sure you have the access or you are not in a Livebook Agent/Offline instance"}
|
"You are not authorized to perform this action, make sure you have the access and you are not in a Livebook App Server/Offline instance"}
|
||||||
|
|
||||||
_otherwise ->
|
_otherwise ->
|
||||||
{:transport_error, @error_message}
|
{:transport_error, @error_message}
|
||||||
|
|
|
@ -82,30 +82,6 @@ defmodule LivebookWeb.AppComponents do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
|
||||||
Renders form fields for Dockerfile configuration.
|
|
||||||
"""
|
|
||||||
attr :form, Phoenix.HTML.Form, required: true
|
|
||||||
attr :hub, :map, required: true
|
|
||||||
attr :show_deploy_all, :boolean, default: true
|
|
||||||
|
|
||||||
def docker_config_form_content(assigns) do
|
|
||||||
~H"""
|
|
||||||
<div class="flex flex-col space-y-4">
|
|
||||||
<.radio_field
|
|
||||||
:if={@show_deploy_all}
|
|
||||||
label="Deploy"
|
|
||||||
field={@form[:deploy_all]}
|
|
||||||
options={[
|
|
||||||
{"false", "Only this notebook"},
|
|
||||||
{"true", "All notebooks in the current directory"}
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<.radio_field label="Base image" field={@form[:docker_tag]} options={docker_tag_options()} />
|
|
||||||
</div>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Renders form fields for Deployment Group.
|
Renders form fields for Deployment Group.
|
||||||
"""
|
"""
|
||||||
|
@ -184,103 +160,18 @@ defmodule LivebookWeb.AppComponents do
|
||||||
|
|
||||||
defp zta_options(), do: @zta_options
|
defp zta_options(), do: @zta_options
|
||||||
|
|
||||||
@docker_tag_options for image <- Livebook.Config.docker_images(), do: {image.tag, image.name}
|
|
||||||
|
|
||||||
defp docker_tag_options(), do: @docker_tag_options
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Renders Docker deployment instruction for an app.
|
|
||||||
"""
|
|
||||||
attr :hub, :map, required: true
|
|
||||||
attr :dockerfile, :string, required: true
|
|
||||||
attr :dockerfile_config, :map, required: true
|
|
||||||
|
|
||||||
slot :dockerfile_actions, default: nil
|
|
||||||
|
|
||||||
def docker_instructions(assigns) do
|
|
||||||
~H"""
|
|
||||||
<div class="flex flex-col gap-4">
|
|
||||||
<div>
|
|
||||||
<div class="flex items-end mb-1 gap-1">
|
|
||||||
<span class="text-sm text-gray-700 font-semibold">Dockerfile</span>
|
|
||||||
<div class="grow" />
|
|
||||||
<%= render_slot(@dockerfile_actions) %>
|
|
||||||
<.button
|
|
||||||
color="gray"
|
|
||||||
small
|
|
||||||
data-tooltip="Copied to clipboard"
|
|
||||||
type="button"
|
|
||||||
aria-label="copy to clipboard"
|
|
||||||
phx-click={
|
|
||||||
JS.dispatch("lb:clipcopy", to: "#dockerfile-source")
|
|
||||||
|> JS.transition("tooltip top", time: 2000)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<.remix_icon icon="clipboard-line" />
|
|
||||||
<span>Copy source</span>
|
|
||||||
</.button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<.code_preview source_id="dockerfile-source" source={@dockerfile} language="dockerfile" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-gray-700">
|
|
||||||
To test the deployment locally, go the the notebook directory, save the Dockerfile, then run:
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<.code_preview
|
|
||||||
source_id="dockerfile-cmd"
|
|
||||||
source={
|
|
||||||
~s'''
|
|
||||||
docker build -t my-app .
|
|
||||||
docker run --rm -p 8080:8080 -p 8081:8081 my-app
|
|
||||||
'''
|
|
||||||
}
|
|
||||||
language="text"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<p class="text-gray-700 py-2">
|
|
||||||
You may additionally perform the following optional steps:
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ul class="text-gray-700 space-y-3">
|
|
||||||
<li :if={Hubs.Provider.type(@hub) == "team"} class="flex gap-2">
|
|
||||||
<div><.remix_icon icon="arrow-right-line" class="text-gray-900" /></div>
|
|
||||||
<span>
|
|
||||||
you may remove the default value for <code>TEAMS_KEY</code>
|
|
||||||
from your Dockerfile and set it as a build argument in your deployment
|
|
||||||
platform
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li :if={@dockerfile_config.clustering} class="flex gap-2">
|
|
||||||
<div><.remix_icon icon="arrow-right-line" class="text-gray-900" /></div>
|
|
||||||
<span>
|
|
||||||
you may set <code>LIVEBOOK_SECRET_KEY_BASE</code>
|
|
||||||
and <code>LIVEBOOK_COOKIE</code>
|
|
||||||
as runtime environment secrets in your deployment platform, to ensure their
|
|
||||||
values stay the same across deployments. If you do that, you can remove
|
|
||||||
the defaults from your Dockerfile
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
<li class="flex gap-2">
|
|
||||||
<div><.remix_icon icon="arrow-right-line" class="text-gray-900" /></div>
|
|
||||||
<span>
|
|
||||||
if you want to debug your deployed notebooks in production, you may
|
|
||||||
set the <code>LIVEBOOK_PASSWORD</code> environment variable with a
|
|
||||||
value of at least 12 characters of your choice
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
"""
|
|
||||||
end
|
|
||||||
|
|
||||||
defp zta_metadata(nil), do: nil
|
defp zta_metadata(nil), do: nil
|
||||||
|
|
||||||
defp zta_metadata(zta_provider) do
|
defp zta_metadata(zta_provider) do
|
||||||
Enum.find(Livebook.Config.identity_providers(), &(&1.type == zta_provider))
|
Enum.find(Livebook.Config.identity_providers(), &(&1.type == zta_provider))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Lists all docker tag options.
|
||||||
|
"""
|
||||||
|
@docker_tag_options for image <- Livebook.Config.docker_images(), do: {image.tag, image.name}
|
||||||
|
def docker_tag_options(), do: @docker_tag_options
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Updates app list with the given apps event.
|
Updates app list with the given apps event.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -162,7 +162,8 @@ defmodule LivebookWeb.Hub.Edit.TeamComponent do
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
Secrets are a safe way to share credentials and tokens with notebooks.
|
Secrets are a safe way to share credentials and tokens with notebooks
|
||||||
|
across your whole team.
|
||||||
They are often used by Smart cells and can be read as
|
They are often used by Smart cells and can be read as
|
||||||
environment variables using the <code>LB_</code> prefix.
|
environment variables using the <code>LB_</code> prefix.
|
||||||
</p>
|
</p>
|
||||||
|
@ -189,7 +190,7 @@ defmodule LivebookWeb.Hub.Edit.TeamComponent do
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700">
|
||||||
File storages are used to store notebooks and their files.
|
File storages are used to store notebooks and their files across your whole team.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<.live_component
|
<.live_component
|
||||||
|
|
|
@ -33,11 +33,11 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupComponent do
|
||||||
<h3 class="font-semibold"><%= @deployment_group.name %></h3>
|
<h3 class="font-semibold"><%= @deployment_group.name %></h3>
|
||||||
<%= if @deployment_group.mode == :online do %>
|
<%= if @deployment_group.mode == :online do %>
|
||||||
<div class="bg-green-100 text-green-800 text-xs px-2.5 py-0.5 rounded cursor-default">
|
<div class="bg-green-100 text-green-800 text-xs px-2.5 py-0.5 rounded cursor-default">
|
||||||
<%= @deployment_group.mode %>
|
Online
|
||||||
</div>
|
</div>
|
||||||
<% else %>
|
<% else %>
|
||||||
<div class="bg-red-100 text-red-800 text-xs px-2.5 py-0.5 rounded cursor-default">
|
<div class="bg-red-100 text-red-800 text-xs px-2.5 py-0.5 rounded cursor-default">
|
||||||
<%= @deployment_group.mode %>
|
Airgapped
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -123,9 +123,8 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
||||||
defp content(assigns) do
|
defp content(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div class="flex flex-col gap-4">
|
<div class="flex flex-col gap-4">
|
||||||
<p class="text-gray-700">
|
<p class="text-gray-700 pb-4">
|
||||||
You can deploy this app in the cloud using Docker. To do that, configure
|
Choose your deployment settings and then deploy your notebook using the generated Dockerfile.
|
||||||
the deployment and then use the generated Dockerfile.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="flex gap-12">
|
<div class="flex gap-12">
|
||||||
|
@ -158,7 +157,16 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
||||||
<.label help={deployment_group_help()}>
|
<.label help={deployment_group_help()}>
|
||||||
Deployment Group
|
Deployment Group
|
||||||
</.label>
|
</.label>
|
||||||
<span>No deployment groups available</span>
|
<span>
|
||||||
|
None configured
|
||||||
|
<.link
|
||||||
|
navigate={~p"/hub/#{@hub.id}/groups/new"}
|
||||||
|
target="_blank"
|
||||||
|
class="pl-3 text-blue-600 font-semibold"
|
||||||
|
>
|
||||||
|
+ add new
|
||||||
|
</.link>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
@ -177,16 +185,29 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
||||||
form={f}
|
form={f}
|
||||||
disabled={@deployment_group_id != nil}
|
disabled={@deployment_group_id != nil}
|
||||||
/>
|
/>
|
||||||
<AppComponents.docker_config_form_content hub={@hub} form={f} />
|
<div class="flex flex-col space-y-4">
|
||||||
|
<.radio_field
|
||||||
|
label="Deploy"
|
||||||
|
field={f[:deploy_all]}
|
||||||
|
options={[
|
||||||
|
{"false", "Only this notebook"},
|
||||||
|
{"true", "All notebooks in the current directory"}
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<.radio_field
|
||||||
|
label="Base image"
|
||||||
|
field={f[:docker_tag]}
|
||||||
|
options={AppComponents.docker_tag_options()}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</.form>
|
</.form>
|
||||||
|
|
||||||
<AppComponents.docker_instructions
|
<div class="flex flex-col gap-4 pt-6">
|
||||||
hub={@hub}
|
<div>
|
||||||
dockerfile={@dockerfile}
|
<div class="flex items-end mb-1 gap-1">
|
||||||
dockerfile_config={apply_changes(@changeset)}
|
<span class="text-sm text-gray-700 font-semibold">Dockerfile</span>
|
||||||
>
|
<div class="grow" />
|
||||||
<:dockerfile_actions>
|
|
||||||
<.button
|
<.button
|
||||||
color="gray"
|
color="gray"
|
||||||
small
|
small
|
||||||
|
@ -198,8 +219,73 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
||||||
<.remix_icon icon="save-line" />
|
<.remix_icon icon="save-line" />
|
||||||
<span>Save alongside notebook</span>
|
<span>Save alongside notebook</span>
|
||||||
</.button>
|
</.button>
|
||||||
</:dockerfile_actions>
|
<.button
|
||||||
</AppComponents.docker_instructions>
|
color="gray"
|
||||||
|
small
|
||||||
|
data-tooltip="Copied to clipboard"
|
||||||
|
type="button"
|
||||||
|
aria-label="copy to clipboard"
|
||||||
|
phx-click={
|
||||||
|
JS.dispatch("lb:clipcopy", to: "#dockerfile-source")
|
||||||
|
|> JS.transition("tooltip top", time: 2000)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<.remix_icon icon="clipboard-line" />
|
||||||
|
<span>Copy source</span>
|
||||||
|
</.button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<.code_preview source_id="dockerfile-source" source={@dockerfile} language="dockerfile" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="text-gray-700">
|
||||||
|
To test the deployment locally, go the the notebook directory, save the Dockerfile, then run:
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<.code_preview
|
||||||
|
source_id="dockerfile-cmd"
|
||||||
|
source={
|
||||||
|
~s'''
|
||||||
|
docker build -t my-app .
|
||||||
|
docker run --rm -p 8080:8080 -p 8081:8081 my-app
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
language="text"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p class="text-gray-700 py-2">
|
||||||
|
You may additionally perform the following optional steps:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul class="text-gray-700 space-y-3">
|
||||||
|
<li :if={Hubs.Provider.type(@hub) == "team"} class="flex gap-2">
|
||||||
|
<div><.remix_icon icon="arrow-right-line" class="text-gray-900" /></div>
|
||||||
|
<span>
|
||||||
|
you may remove the default value for <code>TEAMS_KEY</code>
|
||||||
|
from your Dockerfile and set it as a build argument in your deployment
|
||||||
|
platform
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li :if={apply_changes(@changeset).clustering} class="flex gap-2">
|
||||||
|
<div><.remix_icon icon="arrow-right-line" class="text-gray-900" /></div>
|
||||||
|
<span>
|
||||||
|
you may set <code>LIVEBOOK_SECRET_KEY_BASE</code>
|
||||||
|
and <code>LIVEBOOK_COOKIE</code>
|
||||||
|
as runtime environment secrets in your deployment platform, to ensure their
|
||||||
|
values stay the same across deployments. If you do that, you can remove
|
||||||
|
the defaults from your Dockerfile
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
<li class="flex gap-2">
|
||||||
|
<div><.remix_icon icon="arrow-right-line" class="text-gray-900" /></div>
|
||||||
|
<span>
|
||||||
|
if you want to debug your deployed notebooks in production, you may
|
||||||
|
set the <code>LIVEBOOK_PASSWORD</code> environment variable with a
|
||||||
|
value of at least 12 characters of your choice
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
@ -289,9 +375,14 @@ defmodule LivebookWeb.SessionLive.AppDockerComponent do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp deployment_group_options(deployment_groups) do
|
defp deployment_group_options(deployment_groups) do
|
||||||
for deployment_group <- [%{name: "none", id: nil}] ++ deployment_groups,
|
[{"none", nil}] ++
|
||||||
do: {deployment_group.name, deployment_group.id}
|
for deployment_group <- deployment_groups do
|
||||||
|
{"#{deployment_group.name} (#{mode(deployment_group.mode)})", deployment_group.id}
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp mode(:online), do: "online"
|
||||||
|
defp mode(:offline), do: "airgapped"
|
||||||
|
|
||||||
defp deployment_group_help() do
|
defp deployment_group_help() do
|
||||||
"Share deployment credentials, secrets, and configuration with deployment groups."
|
"Share deployment credentials, secrets, and configuration with deployment groups."
|
||||||
|
|
|
@ -62,13 +62,12 @@ defmodule LivebookWeb.SessionLive.AppInfoComponent do
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div class="mt-2 flex flex-col gap-2">
|
<div class="mt-2 flex flex-col gap-2">
|
||||||
<%!-- TODO: Livebook Teams flow --%>
|
|
||||||
<.button
|
<.button
|
||||||
color="blue"
|
color="blue"
|
||||||
patch={
|
patch={
|
||||||
if Livebook.Notebook.AppSettings.valid?(@settings),
|
if Livebook.Notebook.AppSettings.valid?(@settings),
|
||||||
do: ~p"/sessions/#{@session.id}/app-docker",
|
do: ~p"/sessions/#{@session.id}/app-teams",
|
||||||
else: ~p"/sessions/#{@session.id}/settings/app?context=app-docker"
|
else: ~p"/sessions/#{@session.id}/settings/app?context=app-teams"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<.remix_icon icon="rocket-line" /> Deploy with Livebook Teams
|
<.remix_icon icon="rocket-line" /> Deploy with Livebook Teams
|
||||||
|
|
|
@ -113,7 +113,7 @@ defmodule LivebookWeb.SessionLive.AppTeamsComponent do
|
||||||
<.label help={deployment_group_help()}>
|
<.label help={deployment_group_help()}>
|
||||||
Deployment Group
|
Deployment Group
|
||||||
</.label>
|
</.label>
|
||||||
<span>No deployment groups available</span>
|
<span>None configured</span>
|
||||||
</p>
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -328,7 +328,7 @@ defmodule LivebookWeb.Integration.Hub.EditLiveTest do
|
||||||
assert view
|
assert view
|
||||||
|> element("#secrets-form")
|
|> element("#secrets-form")
|
||||||
|> render_submit(attrs) =~
|
|> render_submit(attrs) =~
|
||||||
"You are not authorized to perform this action, make sure you have the access or you are not in a Livebook Agent/Offline instance"
|
"You are not authorized to perform this action, make sure you have the access and you are not in a Livebook App Server/Offline instance"
|
||||||
|
|
||||||
refute_receive {:secret_created, ^secret}
|
refute_receive {:secret_created, ^secret}
|
||||||
refute secret in Livebook.Hubs.get_secrets(hub)
|
refute secret in Livebook.Hubs.get_secrets(hub)
|
||||||
|
@ -356,7 +356,7 @@ defmodule LivebookWeb.Integration.Hub.EditLiveTest do
|
||||||
assert view
|
assert view
|
||||||
|> element("#file-systems-form")
|
|> element("#file-systems-form")
|
||||||
|> render_submit(attrs) =~
|
|> render_submit(attrs) =~
|
||||||
"You are not authorized to perform this action, make sure you have the access or you are not in a Livebook Agent/Offline instance"
|
"You are not authorized to perform this action, make sure you have the access and you are not in a Livebook App Server/Offline instance"
|
||||||
|
|
||||||
refute_receive {:file_system_created, %{id: ^id}}
|
refute_receive {:file_system_created, %{id: ^id}}
|
||||||
refute file_system in Livebook.Hubs.get_file_systems(hub)
|
refute file_system in Livebook.Hubs.get_file_systems(hub)
|
||||||
|
|
|
@ -457,7 +457,7 @@ defmodule LivebookWeb.Integration.SessionLiveTest do
|
||||||
{:ok, view, _} = live(conn, ~p"/sessions/#{session.id}/app-docker")
|
{:ok, view, _} = live(conn, ~p"/sessions/#{session.id}/app-docker")
|
||||||
|
|
||||||
assert render(view) =~ "Deployment Group"
|
assert render(view) =~ "Deployment Group"
|
||||||
assert render(view) =~ "No deployment groups available"
|
assert render(view) =~ "None configured"
|
||||||
refute has_element?(view, "#select_deployment_group_form")
|
refute has_element?(view, "#select_deployment_group_form")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue