mirror of
https://github.com/livebook-dev/livebook.git
synced 2024-09-20 10:05:57 +08:00
Update to Phoenix LV 1.0 (#2607)
This commit is contained in:
parent
6a45307e4c
commit
602d852b31
|
@ -122,7 +122,6 @@ module.exports = {
|
||||||
addVariant("phx-loading", [".phx-loading&", ".phx-loading &"]);
|
addVariant("phx-loading", [".phx-loading&", ".phx-loading &"]);
|
||||||
addVariant("phx-connected", [".phx-connected&", ".phx-connected &"]);
|
addVariant("phx-connected", [".phx-connected&", ".phx-connected &"]);
|
||||||
addVariant("phx-error", [".phx-error&", ".phx-error &"]);
|
addVariant("phx-error", [".phx-error&", ".phx-error &"]);
|
||||||
addVariant("phx-form-error", [":not(.phx-no-feedback).show-errors &"]);
|
|
||||||
addVariant("phx-click-loading", [
|
addVariant("phx-click-loading", [
|
||||||
".phx-click-loading&",
|
".phx-click-loading&",
|
||||||
".phx-click-loading &",
|
".phx-click-loading &",
|
||||||
|
|
|
@ -19,6 +19,8 @@ defprotocol Livebook.Hubs.Provider do
|
||||||
"""
|
"""
|
||||||
@type notebook_stamp :: map()
|
@type notebook_stamp :: map()
|
||||||
|
|
||||||
|
@type field_errors :: list({atom(), list(String.t())})
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Transforms given hub to `Livebook.Hubs.Metadata` struct.
|
Transforms given hub to `Livebook.Hubs.Metadata` struct.
|
||||||
"""
|
"""
|
||||||
|
@ -60,7 +62,7 @@ defprotocol Livebook.Hubs.Provider do
|
||||||
"""
|
"""
|
||||||
@spec create_secret(t(), Secret.t()) ::
|
@spec create_secret(t(), Secret.t()) ::
|
||||||
:ok
|
:ok
|
||||||
| {:error, Ecto.Changeset.t()}
|
| {:error, field_errors()}
|
||||||
| {:transport_error, String.t()}
|
| {:transport_error, String.t()}
|
||||||
def create_secret(hub, secret)
|
def create_secret(hub, secret)
|
||||||
|
|
||||||
|
@ -69,7 +71,7 @@ defprotocol Livebook.Hubs.Provider do
|
||||||
"""
|
"""
|
||||||
@spec update_secret(t(), Secret.t()) ::
|
@spec update_secret(t(), Secret.t()) ::
|
||||||
:ok
|
:ok
|
||||||
| {:error, Ecto.Changeset.t()}
|
| {:error, field_errors()}
|
||||||
| {:transport_error, String.t()}
|
| {:transport_error, String.t()}
|
||||||
def update_secret(hub, secret)
|
def update_secret(hub, secret)
|
||||||
|
|
||||||
|
@ -120,7 +122,7 @@ defprotocol Livebook.Hubs.Provider do
|
||||||
"""
|
"""
|
||||||
@spec create_file_system(t(), FileSystem.t()) ::
|
@spec create_file_system(t(), FileSystem.t()) ::
|
||||||
:ok
|
:ok
|
||||||
| {:error, Ecto.Changeset.t()}
|
| {:error, field_errors()}
|
||||||
| {:transport_error, String.t()}
|
| {:transport_error, String.t()}
|
||||||
def create_file_system(hub, file_system)
|
def create_file_system(hub, file_system)
|
||||||
|
|
||||||
|
@ -129,7 +131,7 @@ defprotocol Livebook.Hubs.Provider do
|
||||||
"""
|
"""
|
||||||
@spec update_file_system(t(), FileSystem.t()) ::
|
@spec update_file_system(t(), FileSystem.t()) ::
|
||||||
:ok
|
:ok
|
||||||
| {:error, Ecto.Changeset.t()}
|
| {:error, field_errors()}
|
||||||
| {:transport_error, String.t()}
|
| {:transport_error, String.t()}
|
||||||
def update_file_system(hub, file_system)
|
def update_file_system(hub, file_system)
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,7 @@ defimpl Livebook.Hubs.Provider, for: Livebook.Hubs.Team do
|
||||||
def create_secret(%Team{} = team, %Secret{} = secret) do
|
def create_secret(%Team{} = team, %Secret{} = secret) do
|
||||||
case Requests.create_secret(team, secret) do
|
case Requests.create_secret(team, secret) do
|
||||||
{:ok, %{"id" => _}} -> :ok
|
{:ok, %{"id" => _}} -> :ok
|
||||||
{:error, %{"errors" => errors}} -> {:error, add_secret_errors(secret, errors)}
|
{:error, %{"errors" => errors}} -> {:error, parse_secret_errors(errors)}
|
||||||
any -> any
|
any -> any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -220,7 +220,7 @@ defimpl Livebook.Hubs.Provider, for: Livebook.Hubs.Team do
|
||||||
def update_secret(%Team{} = team, %Secret{} = secret) do
|
def update_secret(%Team{} = team, %Secret{} = secret) do
|
||||||
case Requests.update_secret(team, secret) do
|
case Requests.update_secret(team, secret) do
|
||||||
{:ok, %{"id" => _}} -> :ok
|
{:ok, %{"id" => _}} -> :ok
|
||||||
{:error, %{"errors" => errors}} -> {:error, add_secret_errors(secret, errors)}
|
{:error, %{"errors" => errors}} -> {:error, parse_secret_errors(errors)}
|
||||||
any -> any
|
any -> any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -228,7 +228,7 @@ defimpl Livebook.Hubs.Provider, for: Livebook.Hubs.Team do
|
||||||
def delete_secret(%Team{} = team, %Secret{} = secret) do
|
def delete_secret(%Team{} = team, %Secret{} = secret) do
|
||||||
case Requests.delete_secret(team, secret) do
|
case Requests.delete_secret(team, secret) do
|
||||||
{:ok, _} -> :ok
|
{:ok, _} -> :ok
|
||||||
{:error, %{"errors" => errors}} -> {:error, add_secret_errors(secret, errors)}
|
{:error, %{"errors" => errors}} -> {:error, parse_secret_errors(errors)}
|
||||||
any -> any
|
any -> any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -238,7 +238,7 @@ defimpl Livebook.Hubs.Provider, for: Livebook.Hubs.Team do
|
||||||
def create_file_system(%Team{} = team, file_system) do
|
def create_file_system(%Team{} = team, file_system) do
|
||||||
case Requests.create_file_system(team, file_system) do
|
case Requests.create_file_system(team, file_system) do
|
||||||
{:ok, %{"id" => _}} -> :ok
|
{:ok, %{"id" => _}} -> :ok
|
||||||
{:error, %{"errors" => errors}} -> {:error, add_file_system_errors(file_system, errors)}
|
{:error, %{"errors" => errors}} -> {:error, parse_file_system_errors(file_system, errors)}
|
||||||
any -> any
|
any -> any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -246,7 +246,7 @@ defimpl Livebook.Hubs.Provider, for: Livebook.Hubs.Team do
|
||||||
def update_file_system(%Team{} = team, file_system) do
|
def update_file_system(%Team{} = team, file_system) do
|
||||||
case Requests.update_file_system(team, file_system) do
|
case Requests.update_file_system(team, file_system) do
|
||||||
{:ok, %{"id" => _}} -> :ok
|
{:ok, %{"id" => _}} -> :ok
|
||||||
{:error, %{"errors" => errors}} -> {:error, add_file_system_errors(file_system, errors)}
|
{:error, %{"errors" => errors}} -> {:error, parse_file_system_errors(file_system, errors)}
|
||||||
any -> any
|
any -> any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -254,7 +254,7 @@ defimpl Livebook.Hubs.Provider, for: Livebook.Hubs.Team do
|
||||||
def delete_file_system(%Team{} = team, file_system) do
|
def delete_file_system(%Team{} = team, file_system) do
|
||||||
case Requests.delete_file_system(team, file_system) do
|
case Requests.delete_file_system(team, file_system) do
|
||||||
{:ok, _} -> :ok
|
{:ok, _} -> :ok
|
||||||
{:error, %{"errors" => errors}} -> {:error, add_file_system_errors(file_system, errors)}
|
{:error, %{"errors" => errors}} -> {:error, parse_file_system_errors(file_system, errors)}
|
||||||
any -> any
|
any -> any
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -276,13 +276,13 @@ defimpl Livebook.Hubs.Provider, for: Livebook.Hubs.Team do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp add_secret_errors(%Secret{} = secret, errors_map) do
|
defp parse_secret_errors(errors_map) do
|
||||||
Requests.add_errors(secret, errors_map)
|
Requests.to_error_list(Secret, errors_map)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp add_file_system_errors(file_system, errors_map) do
|
defp parse_file_system_errors(%struct{} = file_system, errors_map) do
|
||||||
%{error_field: field} = FileSystem.external_metadata(file_system)
|
%{error_field: field} = FileSystem.external_metadata(file_system)
|
||||||
errors_map = Map.new(errors_map, fn {_key, values} -> {field, values} end)
|
errors_map = Map.new(errors_map, fn {_key, values} -> {field, values} end)
|
||||||
Requests.add_errors(file_system, errors_map)
|
Requests.to_error_list(struct, errors_map)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,19 +42,18 @@ defmodule Livebook.Teams do
|
||||||
defp create_org_request(%Org{} = org, attrs, callback) when is_function(callback, 1) do
|
defp create_org_request(%Org{} = org, attrs, callback) when is_function(callback, 1) do
|
||||||
changeset = Org.changeset(org, attrs)
|
changeset = Org.changeset(org, attrs)
|
||||||
|
|
||||||
with {:ok, %Org{} = org} <- apply_action(changeset, :insert),
|
with {:ok, %Org{} = org} <- apply_action(changeset, :insert) do
|
||||||
{:ok, response} <- callback.(org) do
|
case callback.(org) do
|
||||||
{:ok, response}
|
{:ok, response} ->
|
||||||
else
|
{:ok, response}
|
||||||
{:error, %Ecto.Changeset{} = changeset} ->
|
|
||||||
{:error, changeset}
|
|
||||||
|
|
||||||
{:error, %{"errors" => errors}} ->
|
{:error, %{"errors" => errors}} ->
|
||||||
errors = map_teams_field_to_livebook_field(errors, "key_hash", "teams_key")
|
errors = map_teams_field_to_livebook_field(errors, "key_hash", "teams_key")
|
||||||
{:error, add_org_errors(changeset, errors)}
|
{:error, changeset |> add_external_errors(errors) |> Map.replace!(:action, :insert)}
|
||||||
|
|
||||||
any ->
|
any ->
|
||||||
any
|
any
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -152,10 +151,6 @@ defmodule Livebook.Teams do
|
||||||
Plug.Crypto.KeyGenerator.generate(binary_key, "notebook secret", cache: Plug.Crypto.Keys)
|
Plug.Crypto.KeyGenerator.generate(binary_key, "notebook secret", cache: Plug.Crypto.Keys)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp add_org_errors(%Ecto.Changeset{} = changeset, errors_map) do
|
|
||||||
Requests.add_errors(changeset, Org.__schema__(:fields), errors_map)
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Returns an `%Ecto.Changeset{}` for tracking deployment group changes.
|
Returns an `%Ecto.Changeset{}` for tracking deployment group changes.
|
||||||
"""
|
"""
|
||||||
|
@ -167,15 +162,27 @@ defmodule Livebook.Teams do
|
||||||
@doc """
|
@doc """
|
||||||
Creates a Deployment Group.
|
Creates a Deployment Group.
|
||||||
"""
|
"""
|
||||||
@spec create_deployment_group(Team.t(), DeploymentGroup.t()) ::
|
@spec create_deployment_group(Team.t(), map()) ::
|
||||||
{:ok, pos_integer()}
|
{:ok, DeploymentGroup.t()}
|
||||||
| {:error, Ecto.Changeset.t()}
|
| {:error, Ecto.Changeset.t()}
|
||||||
| {:transport_error, String.t()}
|
| {:transport_error, String.t()}
|
||||||
def create_deployment_group(%Team{} = team, deployment_group) do
|
def create_deployment_group(%Team{} = team, attrs) do
|
||||||
case Requests.create_deployment_group(team, deployment_group) do
|
changeset = DeploymentGroup.changeset(%DeploymentGroup{}, attrs)
|
||||||
{:ok, %{"id" => id}} -> {:ok, id}
|
|
||||||
{:error, %{"errors" => errors}} -> {:error, Requests.add_errors(deployment_group, errors)}
|
with {:ok, %DeploymentGroup{} = deployment_group} <- apply_action(changeset, :insert) do
|
||||||
any -> any
|
case Requests.create_deployment_group(team, deployment_group) do
|
||||||
|
{:ok, %{"id" => id}} ->
|
||||||
|
{:ok, %{deployment_group | id: to_string(id)}}
|
||||||
|
|
||||||
|
{:error, %{"errors" => errors}} ->
|
||||||
|
{:error,
|
||||||
|
changeset
|
||||||
|
|> add_external_errors(errors)
|
||||||
|
|> Map.replace!(:action, :insert)}
|
||||||
|
|
||||||
|
any ->
|
||||||
|
any
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -200,10 +207,10 @@ defmodule Livebook.Teams do
|
||||||
:ok
|
:ok
|
||||||
|
|
||||||
{:error, %{"errors" => %{"detail" => error}}} ->
|
{:error, %{"errors" => %{"detail" => error}}} ->
|
||||||
{:error, Requests.add_errors(app_deployment, %{"file" => [error]})}
|
{:error, add_external_errors(app_deployment, %{"file" => [error]})}
|
||||||
|
|
||||||
{:error, %{"errors" => errors}} ->
|
{:error, %{"errors" => errors}} ->
|
||||||
{:error, Requests.add_errors(app_deployment, errors)}
|
{:error, add_external_errors(app_deployment, errors)}
|
||||||
|
|
||||||
any ->
|
any ->
|
||||||
any
|
any
|
||||||
|
@ -233,4 +240,13 @@ defmodule Livebook.Teams do
|
||||||
map
|
map
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp add_external_errors(%Ecto.Changeset{data: %struct{}} = changeset, errors_map) do
|
||||||
|
errors = Requests.to_error_list(struct, errors_map)
|
||||||
|
Livebook.Utils.put_changeset_errors(changeset, errors)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp add_external_errors(struct, errors_map) do
|
||||||
|
struct |> Ecto.Changeset.change() |> add_external_errors(errors_map)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -212,22 +212,17 @@ defmodule Livebook.Teams.Requests do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Add requests errors to a `changeset` for the given `fields`.
|
Normalizes errors map into errors for the given schema.
|
||||||
"""
|
"""
|
||||||
def add_errors(%Ecto.Changeset{} = changeset, fields, errors_map) do
|
@spec to_error_list(module(), %{String.t() => list(String.t())}) ::
|
||||||
|
list({atom(), list(String.t())})
|
||||||
|
def to_error_list(struct, errors_map) do
|
||||||
|
fields = struct.__schema__(:fields) |> MapSet.new()
|
||||||
|
|
||||||
for {key, errors} <- errors_map,
|
for {key, errors} <- errors_map,
|
||||||
field = String.to_atom(key),
|
field = String.to_atom(key),
|
||||||
field in fields,
|
field in fields,
|
||||||
error <- errors,
|
do: {field, errors}
|
||||||
reduce: changeset,
|
|
||||||
do: (acc -> Ecto.Changeset.add_error(acc, field, error))
|
|
||||||
end
|
|
||||||
|
|
||||||
@doc """
|
|
||||||
Add requests errors to a struct.
|
|
||||||
"""
|
|
||||||
def add_errors(%struct{} = value, errors_map) do
|
|
||||||
value |> Ecto.Changeset.change() |> add_errors(struct.__schema__(:fields), errors_map)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
|
|
|
@ -213,6 +213,19 @@ defmodule Livebook.Utils do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Adds all the given errors to the changeset for the corresponding
|
||||||
|
fields.
|
||||||
|
"""
|
||||||
|
@spec put_changeset_errors(Ecto.Changeset.t(), list({atom(), list(String.t())})) ::
|
||||||
|
Ecto.Changeset.t()
|
||||||
|
def put_changeset_errors(changeset, errors) do
|
||||||
|
for {field, errors} <- errors,
|
||||||
|
error <- errors,
|
||||||
|
reduce: changeset,
|
||||||
|
do: (changeset -> Ecto.Changeset.add_error(changeset, field, error))
|
||||||
|
end
|
||||||
|
|
||||||
@doc ~S"""
|
@doc ~S"""
|
||||||
Validates if the given string forms valid CLI flags.
|
Validates if the given string forms valid CLI flags.
|
||||||
|
|
||||||
|
|
|
@ -30,15 +30,23 @@ defmodule LivebookWeb.FormComponents do
|
||||||
name={@name}
|
name={@name}
|
||||||
id={@id || @name}
|
id={@id || @name}
|
||||||
value={Phoenix.HTML.Form.normalize_value("text", @value)}
|
value={Phoenix.HTML.Form.normalize_value("text", @value)}
|
||||||
class={[input_classes(), @class]}
|
class={[input_classes(@errors), @class]}
|
||||||
{@rest}
|
{@rest}
|
||||||
/>
|
/>
|
||||||
</.field_wrapper>
|
</.field_wrapper>
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
defp input_classes() do
|
defp input_classes(errors) do
|
||||||
"w-full px-3 py-2 bg-gray-50 text-sm font-normal border border-gray-200 rounded-lg placeholder-gray-400 text-gray-600 disabled:opacity-70 disabled:cursor-not-allowed phx-form-error:bg-red-50 phx-form-error:border-red-600 phx-form-error:text-red-600 invalid:bg-red-50 invalid:border-red-600 invalid:text-red-600"
|
[
|
||||||
|
"w-full px-3 py-2 text-sm font-normal border rounded-lg placeholder-gray-400 disabled:opacity-70 disabled:cursor-not-allowed",
|
||||||
|
if errors == [] do
|
||||||
|
"bg-gray-50 border-gray-200 text-gray-600"
|
||||||
|
else
|
||||||
|
"bg-red-50 border-red-600 text-red-600"
|
||||||
|
end,
|
||||||
|
"invalid:bg-red-50 invalid:border-red-600 invalid:text-red-600"
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -65,7 +73,12 @@ defmodule LivebookWeb.FormComponents do
|
||||||
<textarea
|
<textarea
|
||||||
id={@id || @name}
|
id={@id || @name}
|
||||||
name={@name}
|
name={@name}
|
||||||
class={[input_classes(), "resize-none tiny-scrollbar", @monospace && "font-mono", @class]}
|
class={[
|
||||||
|
input_classes(@errors),
|
||||||
|
"resize-none tiny-scrollbar",
|
||||||
|
@monospace && "font-mono",
|
||||||
|
@class
|
||||||
|
]}
|
||||||
{@rest}
|
{@rest}
|
||||||
><%= Phoenix.HTML.Form.normalize_value("textarea", @value) %></textarea>
|
><%= Phoenix.HTML.Form.normalize_value("textarea", @value) %></textarea>
|
||||||
</.field_wrapper>
|
</.field_wrapper>
|
||||||
|
@ -115,7 +128,7 @@ defmodule LivebookWeb.FormComponents do
|
||||||
name={@name}
|
name={@name}
|
||||||
id={@id || @name}
|
id={@id || @name}
|
||||||
value={Phoenix.HTML.Form.normalize_value("text", @value)}
|
value={Phoenix.HTML.Form.normalize_value("text", @value)}
|
||||||
class={[input_classes(), "pr-8", @class]}
|
class={[input_classes(@errors), "pr-8", @class]}
|
||||||
{@rest}
|
{@rest}
|
||||||
/>
|
/>
|
||||||
<div class="flex items-center absolute inset-y-0 right-1">
|
<div class="flex items-center absolute inset-y-0 right-1">
|
||||||
|
@ -184,7 +197,7 @@ defmodule LivebookWeb.FormComponents do
|
||||||
name={@name}
|
name={@name}
|
||||||
id={@id || @name}
|
id={@id || @name}
|
||||||
value={@value}
|
value={@value}
|
||||||
class={input_classes()}
|
class={input_classes(@errors)}
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
maxlength="7"
|
maxlength="7"
|
||||||
{@rest}
|
{@rest}
|
||||||
|
@ -221,7 +234,7 @@ defmodule LivebookWeb.FormComponents do
|
||||||
assigns = assigns_from_field(assigns)
|
assigns = assigns_from_field(assigns)
|
||||||
|
|
||||||
~H"""
|
~H"""
|
||||||
<div phx-feedback-for={@name} class={[@errors != [] && "show-errors"]}>
|
<div>
|
||||||
<div class="flex items-center gap-1 sm:gap-3 justify-between">
|
<div class="flex items-center gap-1 sm:gap-3 justify-between">
|
||||||
<span :if={@label} class="text-gray-700 flex gap-1 items-center">
|
<span :if={@label} class="text-gray-700 flex gap-1 items-center">
|
||||||
<%= @label %>
|
<%= @label %>
|
||||||
|
@ -281,7 +294,7 @@ defmodule LivebookWeb.FormComponents do
|
||||||
assigns = assigns_from_field(assigns)
|
assigns = assigns_from_field(assigns)
|
||||||
|
|
||||||
~H"""
|
~H"""
|
||||||
<div phx-feedback-for={@name} class={[@errors != [] && "show-errors"]}>
|
<div>
|
||||||
<label class="flex items-center gap-2 cursor-pointer">
|
<label class="flex items-center gap-2 cursor-pointer">
|
||||||
<input :if={@unchecked_value} type="hidden" value={@unchecked_value} name={@name} />
|
<input :if={@unchecked_value} type="hidden" value={@unchecked_value} name={@name} />
|
||||||
<input
|
<input
|
||||||
|
@ -327,7 +340,7 @@ defmodule LivebookWeb.FormComponents do
|
||||||
assigns = assigns_from_field(assigns)
|
assigns = assigns_from_field(assigns)
|
||||||
|
|
||||||
~H"""
|
~H"""
|
||||||
<div phx-feedback-for={@name} class={[@errors != [] && "show-errors"]}>
|
<div>
|
||||||
<.label :if={@label} for={@id} help={@help}><%= @label %></.label>
|
<.label :if={@label} for={@id} help={@help}><%= @label %></.label>
|
||||||
<div class="flex gap-4 text-gray-600">
|
<div class="flex gap-4 text-gray-600">
|
||||||
<label :for={{value, description} <- @options} class="flex items-center gap-2 cursor-pointer">
|
<label :for={{value, description} <- @options} class="flex items-center gap-2 cursor-pointer">
|
||||||
|
@ -371,7 +384,7 @@ defmodule LivebookWeb.FormComponents do
|
||||||
assigns = assigns_from_field(assigns)
|
assigns = assigns_from_field(assigns)
|
||||||
|
|
||||||
~H"""
|
~H"""
|
||||||
<div phx-feedback-for={@name} class={[@errors != [] && "show-errors"]}>
|
<div>
|
||||||
<.label :if={@label} for={@id} help={@help}><%= @label %></.label>
|
<.label :if={@label} for={@id} help={@help}><%= @label %></.label>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<label
|
<label
|
||||||
|
@ -474,7 +487,8 @@ defmodule LivebookWeb.FormComponents do
|
||||||
id={@id}
|
id={@id}
|
||||||
name={@name}
|
name={@name}
|
||||||
class={[
|
class={[
|
||||||
"w-full px-3 py-2 pr-7 appearance-none bg-gray-50 text-sm border border-gray-200 rounded-lg placeholder-gray-400 text-gray-600 phx-form-error:border-red-300 disabled:opacity-70 disabled:cursor-not-allowed",
|
"w-full px-3 py-2 pr-7 appearance-none bg-gray-50 text-sm border rounded-lg placeholder-gray-400 text-gray-600 disabled:opacity-70 disabled:cursor-not-allowed",
|
||||||
|
if(@errors == [], do: "border-gray-200", else: "border-red-300"),
|
||||||
@class
|
@class
|
||||||
]}
|
]}
|
||||||
{@rest}
|
{@rest}
|
||||||
|
@ -491,9 +505,11 @@ defmodule LivebookWeb.FormComponents do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp assigns_from_field(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
|
defp assigns_from_field(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
|
||||||
|
errors = if Phoenix.Component.used_input?(field), do: field.errors, else: []
|
||||||
|
|
||||||
assigns
|
assigns
|
||||||
|> assign(field: nil, id: assigns.id || field.id)
|
|> assign(field: nil, id: assigns.id || field.id)
|
||||||
|> assign(:errors, Enum.map(field.errors, &translate_error/1))
|
|> assign(:errors, Enum.map(errors, &translate_error(&1)))
|
||||||
|> assign_new(:name, fn -> field.name end)
|
|> assign_new(:name, fn -> field.name end)
|
||||||
|> assign_new(:value, fn -> field.value end)
|
|> assign_new(:value, fn -> field.value end)
|
||||||
end
|
end
|
||||||
|
@ -520,7 +536,7 @@ defmodule LivebookWeb.FormComponents do
|
||||||
|
|
||||||
defp field_wrapper(assigns) do
|
defp field_wrapper(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<div phx-feedback-for={@name} class={[@errors != [] && "show-errors"]}>
|
<div>
|
||||||
<.label :if={@label} for={@id} help={@help}><%= @label %></.label>
|
<.label :if={@label} for={@id} help={@help}><%= @label %></.label>
|
||||||
<%= render_slot(@inner_block) %>
|
<%= render_slot(@inner_block) %>
|
||||||
<.error :for={msg <- @errors}><%= msg %></.error>
|
<.error :for={msg <- @errors}><%= msg %></.error>
|
||||||
|
@ -551,7 +567,7 @@ defmodule LivebookWeb.FormComponents do
|
||||||
|
|
||||||
def error(assigns) do
|
def error(assigns) do
|
||||||
~H"""
|
~H"""
|
||||||
<p class="mt-0.5 text-red-600 text-sm hidden phx-form-error:block">
|
<p class="mt-0.5 text-red-600 text-sm">
|
||||||
<%= render_slot(@inner_block) %>
|
<%= render_slot(@inner_block) %>
|
||||||
</p>
|
</p>
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -24,12 +24,19 @@
|
||||||
<div class="text-gray-50 w-full">
|
<div class="text-gray-50 w-full">
|
||||||
<form method="post" class="flex flex-col w-full">
|
<form method="post" class="flex flex-col w-full">
|
||||||
<input type="hidden" value={Phoenix.Controller.get_csrf_token()} name="_csrf_token" />
|
<input type="hidden" value={Phoenix.Controller.get_csrf_token()} name="_csrf_token" />
|
||||||
<div phx-feedback-for={@auth_mode} class={[@errors != [] && "show-errors"]}>
|
<div>
|
||||||
<input
|
<input
|
||||||
:if={@auth_mode == :password}
|
:if={@auth_mode == :password}
|
||||||
type="password"
|
type="password"
|
||||||
name="password"
|
name="password"
|
||||||
class="px-4 py-2 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"
|
class={[
|
||||||
|
"px-4 py-2 w-full border rounded-lg bg-transparent",
|
||||||
|
if @errors == [] do
|
||||||
|
"border-gray-500 text-gray-300 placeholder-gray-400"
|
||||||
|
else
|
||||||
|
"border-red-600 text-red-600 placeholder-red-600"
|
||||||
|
end
|
||||||
|
]}
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
autofocus
|
autofocus
|
||||||
/>
|
/>
|
||||||
|
@ -37,14 +44,18 @@
|
||||||
:if={@auth_mode == :token}
|
:if={@auth_mode == :token}
|
||||||
type="text"
|
type="text"
|
||||||
name="token"
|
name="token"
|
||||||
class="px-4 py-2 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"
|
class={[
|
||||||
|
"px-4 py-2 w-full border rounded-lg bg-transparent",
|
||||||
|
if @errors == [] do
|
||||||
|
"border-gray-500 text-gray-300 placeholder-gray-400"
|
||||||
|
else
|
||||||
|
"border-red-600 text-red-600 placeholder-red-600"
|
||||||
|
end
|
||||||
|
]}
|
||||||
placeholder="Token"
|
placeholder="Token"
|
||||||
autofocus
|
autofocus
|
||||||
/>
|
/>
|
||||||
<span
|
<span :for={error <- @errors} class="mt-1 text-red-600 text-sm">
|
||||||
:for={error <- @errors}
|
|
||||||
class="mt-1 hidden text-red-600 text-sm phx-form-error:block"
|
|
||||||
>
|
|
||||||
<%= translate_error(error) %>
|
<%= translate_error(error) %>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -41,7 +41,7 @@ defmodule LivebookWeb.AppAuthLive do
|
||||||
</div>
|
</div>
|
||||||
<div class="text-2xl text-gray-800 w-full pt-2">
|
<div class="text-2xl text-gray-800 w-full pt-2">
|
||||||
<form class="flex flex-col space-y-4 items-center" phx-submit="authenticate">
|
<form class="flex flex-col space-y-4 items-center" phx-submit="authenticate">
|
||||||
<div phx-feedback-for="password" class={["w-[20ch]", @errors != [] && "show-errors"]}>
|
<div class="w-[20ch]">
|
||||||
<.text_field
|
<.text_field
|
||||||
type="password"
|
type="password"
|
||||||
name="password"
|
name="password"
|
||||||
|
@ -49,10 +49,7 @@ defmodule LivebookWeb.AppAuthLive do
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
autofocus
|
autofocus
|
||||||
/>
|
/>
|
||||||
<span
|
<span :for={error <- @errors} class="mt-1 text-red-600 text-sm">
|
||||||
:for={error <- @errors}
|
|
||||||
class="mt-1 hidden text-red-600 text-sm phx-form-error:block"
|
|
||||||
>
|
|
||||||
<%= translate_error(error) %>
|
<%= translate_error(error) %>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -120,7 +120,7 @@ defmodule LivebookWeb.Hub.FileSystemFormComponent do
|
||||||
|
|
||||||
with {:ok, file_system} <- Ecto.Changeset.apply_action(changeset, :update),
|
with {:ok, file_system} <- Ecto.Changeset.apply_action(changeset, :update),
|
||||||
:ok <- check_file_system_connectivity(file_system),
|
:ok <- check_file_system_connectivity(file_system),
|
||||||
:ok <- save_file_system(file_system, socket) do
|
:ok <- save_file_system(file_system, changeset, socket) do
|
||||||
message =
|
message =
|
||||||
case socket.assigns.mode do
|
case socket.assigns.mode do
|
||||||
:new -> "File storage added successfully"
|
:new -> "File storage added successfully"
|
||||||
|
@ -152,10 +152,18 @@ defmodule LivebookWeb.Hub.FileSystemFormComponent do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp save_file_system(file_system, socket) do
|
defp save_file_system(file_system, changeset, socket) do
|
||||||
case socket.assigns.mode do
|
result =
|
||||||
:new -> Livebook.Hubs.create_file_system(socket.assigns.hub, file_system)
|
case socket.assigns.mode do
|
||||||
:edit -> Livebook.Hubs.update_file_system(socket.assigns.hub, file_system)
|
:new -> Livebook.Hubs.create_file_system(socket.assigns.hub, file_system)
|
||||||
|
:edit -> Livebook.Hubs.update_file_system(socket.assigns.hub, file_system)
|
||||||
|
end
|
||||||
|
|
||||||
|
with {:error, errors} <- result do
|
||||||
|
{:error,
|
||||||
|
changeset
|
||||||
|
|> Livebook.Utils.put_changeset_errors(errors)
|
||||||
|
|> Map.replace!(:action, :validate)}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -249,8 +249,6 @@ defmodule LivebookWeb.Hub.NewLive do
|
||||||
|> assign_form(changeset)}
|
|> assign_form(changeset)}
|
||||||
|
|
||||||
{:error, changeset} ->
|
{:error, changeset} ->
|
||||||
changeset = Map.replace!(changeset, :action, :validate)
|
|
||||||
|
|
||||||
{:noreply, assign_form(socket, changeset)}
|
{:noreply, assign_form(socket, changeset)}
|
||||||
|
|
||||||
{:transport_error, message} ->
|
{:transport_error, message} ->
|
||||||
|
|
|
@ -7,25 +7,23 @@ defmodule LivebookWeb.Hub.SecretFormComponent do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def mount(socket) do
|
def mount(socket) do
|
||||||
{:ok, assign(socket, changeset: nil, error_message: nil)}
|
{:ok, assign(socket, error_message: nil)}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def update(assigns, socket) do
|
def update(assigns, socket) do
|
||||||
changeset =
|
|
||||||
socket.assigns.changeset ||
|
|
||||||
Secrets.change_secret(%Secret{}, %{
|
|
||||||
name: assigns.secret_name,
|
|
||||||
value: assigns.secret_value
|
|
||||||
})
|
|
||||||
|
|
||||||
{:ok,
|
{:ok,
|
||||||
socket
|
socket
|
||||||
|> assign(assigns)
|
|> assign(assigns)
|
||||||
|
|> assign_new(:changeset, fn ->
|
||||||
|
Secrets.change_secret(%Secret{}, %{
|
||||||
|
name: assigns.secret_name,
|
||||||
|
value: assigns.secret_value
|
||||||
|
})
|
||||||
|
end)
|
||||||
|> assign(
|
|> assign(
|
||||||
title: title(socket),
|
title: title(socket),
|
||||||
button: button_attrs(socket),
|
button: button_attrs(socket),
|
||||||
changeset: changeset,
|
|
||||||
deployment_group_id: assigns[:deployment_group_id]
|
deployment_group_id: assigns[:deployment_group_id]
|
||||||
)}
|
)}
|
||||||
end
|
end
|
||||||
|
@ -91,8 +89,10 @@ defmodule LivebookWeb.Hub.SecretFormComponent do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_event("save", %{"secret" => attrs}, socket) do
|
def handle_event("save", %{"secret" => attrs}, socket) do
|
||||||
with {:ok, secret} <- Secrets.update_secret(%Secret{}, attrs),
|
changeset = Secrets.change_secret(%Secret{}, attrs)
|
||||||
:ok <- set_secret(socket, secret) do
|
|
||||||
|
with {:ok, secret} <- Ecto.Changeset.apply_action(changeset, :insert),
|
||||||
|
:ok <- save_secret(socket, secret, changeset) do
|
||||||
message =
|
message =
|
||||||
if socket.assigns.secret_name,
|
if socket.assigns.secret_name,
|
||||||
do: "Secret #{secret.name} updated successfully",
|
do: "Secret #{secret.name} updated successfully",
|
||||||
|
@ -103,8 +103,8 @@ defmodule LivebookWeb.Hub.SecretFormComponent do
|
||||||
|> put_flash(:success, message)
|
|> put_flash(:success, message)
|
||||||
|> push_patch(to: socket.assigns.return_to)}
|
|> push_patch(to: socket.assigns.return_to)}
|
||||||
else
|
else
|
||||||
{:error, changeset} ->
|
{:error, %Ecto.Changeset{} = changeset} ->
|
||||||
{:noreply, assign(socket, changeset: Map.replace!(changeset, :action, :validate))}
|
{:noreply, assign(socket, changeset: changeset)}
|
||||||
|
|
||||||
{:transport_error, error} ->
|
{:transport_error, error} ->
|
||||||
{:noreply, assign(socket, error_message: error)}
|
{:noreply, assign(socket, error_message: error)}
|
||||||
|
@ -126,12 +126,20 @@ defmodule LivebookWeb.Hub.SecretFormComponent do
|
||||||
defp button_attrs(%{assigns: %{secret_name: nil}}), do: %{icon: "add-line", label: "Add"}
|
defp button_attrs(%{assigns: %{secret_name: nil}}), do: %{icon: "add-line", label: "Add"}
|
||||||
defp button_attrs(_), do: %{icon: "save-line", label: "Save"}
|
defp button_attrs(_), do: %{icon: "save-line", label: "Save"}
|
||||||
|
|
||||||
defp set_secret(%{assigns: %{secret_name: nil}} = socket, %Secret{} = secret) do
|
defp save_secret(socket, secret, changeset) do
|
||||||
Hubs.create_secret(socket.assigns.hub, secret)
|
result =
|
||||||
end
|
if socket.assigns.secret_name do
|
||||||
|
Hubs.update_secret(socket.assigns.hub, secret)
|
||||||
|
else
|
||||||
|
Hubs.create_secret(socket.assigns.hub, secret)
|
||||||
|
end
|
||||||
|
|
||||||
defp set_secret(socket, %Secret{} = secret) do
|
with {:error, errors} <- result do
|
||||||
Hubs.update_secret(socket.assigns.hub, secret)
|
{:error,
|
||||||
|
changeset
|
||||||
|
|> Livebook.Utils.put_changeset_errors(errors)
|
||||||
|
|> Map.replace!(:action, :validate)}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp secret_name_input_class(nil), do: "uppercase"
|
defp secret_name_input_class(nil), do: "uppercase"
|
||||||
|
|
|
@ -23,7 +23,7 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupFormComponent do
|
||||||
%{}
|
%{}
|
||||||
end
|
end
|
||||||
|
|
||||||
{:ok, assign_form(socket, change_deployment_group(socket, attrs))}
|
{:ok, assign_form(socket, Teams.change_deployment_group(%DeploymentGroup{}, attrs))}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -88,6 +88,8 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupFormComponent do
|
||||||
phx-debounce
|
phx-debounce
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<.hidden_field field={@form[:hub_id]} value={@hub.id} />
|
||||||
|
|
||||||
<LivebookWeb.AppComponents.deployment_group_form_content hub={@hub} form={@form} />
|
<LivebookWeb.AppComponents.deployment_group_form_content hub={@hub} form={@form} />
|
||||||
|
|
||||||
<div class="flex space-x-2">
|
<div class="flex space-x-2">
|
||||||
|
@ -145,10 +147,7 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupFormComponent do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_event("save", %{"deployment_group" => attrs}, socket) do
|
def handle_event("save", %{"deployment_group" => attrs}, socket) do
|
||||||
changeset = change_deployment_group(socket, attrs)
|
with {:ok, _deployment_group} <- Teams.create_deployment_group(socket.assigns.hub, attrs) do
|
||||||
|
|
||||||
with {:ok, deployment_group} <- Ecto.Changeset.apply_action(changeset, :update),
|
|
||||||
{:ok, _id} <- Teams.create_deployment_group(socket.assigns.hub, deployment_group) do
|
|
||||||
if return_to = socket.assigns.return_to do
|
if return_to = socket.assigns.return_to do
|
||||||
{:noreply,
|
{:noreply,
|
||||||
socket
|
socket
|
||||||
|
@ -159,7 +158,7 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupFormComponent do
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
{:error, %Ecto.Changeset{} = changeset} ->
|
{:error, %Ecto.Changeset{} = changeset} ->
|
||||||
{:noreply, assign_form(socket, Map.replace!(changeset, :action, :validate))}
|
{:noreply, assign_form(socket, changeset)}
|
||||||
|
|
||||||
{:transport_error, message} ->
|
{:transport_error, message} ->
|
||||||
{:noreply, assign(socket, error_message: message)}
|
{:noreply, assign(socket, error_message: message)}
|
||||||
|
@ -171,14 +170,9 @@ defmodule LivebookWeb.Hub.Teams.DeploymentGroupFormComponent do
|
||||||
|
|
||||||
def handle_event("validate", %{"deployment_group" => attrs}, socket) do
|
def handle_event("validate", %{"deployment_group" => attrs}, socket) do
|
||||||
changeset =
|
changeset =
|
||||||
change_deployment_group(socket, attrs)
|
Teams.change_deployment_group(%DeploymentGroup{}, attrs)
|
||||||
|> Map.replace!(:action, :validate)
|
|> Map.replace!(:action, :validate)
|
||||||
|
|
||||||
{:noreply, assign_form(socket, changeset)}
|
{:noreply, assign_form(socket, changeset)}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp change_deployment_group(socket, attrs) do
|
|
||||||
%DeploymentGroup{hub_id: socket.assigns.hub.id}
|
|
||||||
|> Teams.change_deployment_group(attrs)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -216,14 +216,18 @@ defmodule LivebookWeb.SessionLive.SecretsComponent do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def handle_event("save", %{"secret" => attrs}, socket) do
|
def handle_event("save", %{"secret" => attrs}, socket) do
|
||||||
with {:ok, secret} <- Secrets.update_secret(%Secret{}, attrs),
|
changeset = Secrets.change_secret(%Secret{}, attrs)
|
||||||
:ok <- set_secret(socket, secret) do
|
|
||||||
|
with {:ok, secret} <- Ecto.Changeset.apply_action(changeset, :insert),
|
||||||
|
:ok <- save_secret(socket, secret, changeset) do
|
||||||
|
Session.set_secret(socket.assigns.session.pid, secret)
|
||||||
|
|
||||||
{:noreply,
|
{:noreply,
|
||||||
socket
|
socket
|
||||||
|> push_patch(to: socket.assigns.return_to)
|
|> push_patch(to: socket.assigns.return_to)
|
||||||
|> push_secret_selected(secret.name)}
|
|> push_secret_selected(secret.name)}
|
||||||
else
|
else
|
||||||
{:error, changeset} ->
|
{:error, %Ecto.Changeset{} = changeset} ->
|
||||||
{:noreply, assign(socket, changeset: changeset)}
|
{:noreply, assign(socket, changeset: changeset)}
|
||||||
|
|
||||||
{:transport_error, error} ->
|
{:transport_error, error} ->
|
||||||
|
@ -271,13 +275,16 @@ defmodule LivebookWeb.SessionLive.SecretsComponent do
|
||||||
defp title(%{assigns: %{select_secret_metadata: %{options: %{"title" => title}}}}), do: title
|
defp title(%{assigns: %{select_secret_metadata: %{options: %{"title" => title}}}}), do: title
|
||||||
defp title(_), do: "Select secret"
|
defp title(_), do: "Select secret"
|
||||||
|
|
||||||
defp set_secret(socket, %Secret{hub_id: nil} = secret) do
|
defp save_secret(socket, secret, changeset) do
|
||||||
Session.set_secret(socket.assigns.session.pid, secret)
|
if secret.hub_id do
|
||||||
end
|
with {:error, errors} <- Hubs.create_secret(socket.assigns.hub, secret) do
|
||||||
|
{:error,
|
||||||
defp set_secret(socket, %Secret{} = secret) do
|
changeset
|
||||||
with :ok <- Hubs.create_secret(socket.assigns.hub, secret) do
|
|> Livebook.Utils.put_changeset_errors(errors)
|
||||||
Session.set_secret(socket.assigns.session.pid, secret)
|
|> Map.replace!(:action, :validate)}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
:ok
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
2
mix.exs
2
mix.exs
|
@ -99,7 +99,7 @@ defmodule Livebook.MixProject do
|
||||||
defp deps do
|
defp deps do
|
||||||
[
|
[
|
||||||
{:phoenix, "~> 1.7.8"},
|
{:phoenix, "~> 1.7.8"},
|
||||||
{:phoenix_live_view, "~> 0.20.2"},
|
{:phoenix_live_view, "~> 1.0.0-rc.0", override: true},
|
||||||
{:phoenix_html, "~> 4.0"},
|
{:phoenix_html, "~> 4.0"},
|
||||||
{:phoenix_live_dashboard, "~> 0.8.0"},
|
{:phoenix_live_dashboard, "~> 0.8.0"},
|
||||||
{:telemetry_metrics, "~> 1.0"},
|
{:telemetry_metrics, "~> 1.0"},
|
||||||
|
|
2
mix.lock
2
mix.lock
|
@ -36,7 +36,7 @@
|
||||||
"phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"},
|
"phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"},
|
||||||
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.3", "7ff51c9b6609470f681fbea20578dede0e548302b0c8bdf338b5a753a4f045bf", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f9470a0a8bae4f56430a23d42f977b5a6205fdba6559d76f932b876bfaec652d"},
|
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.3", "7ff51c9b6609470f681fbea20578dede0e548302b0c8bdf338b5a753a4f045bf", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "f9470a0a8bae4f56430a23d42f977b5a6205fdba6559d76f932b876bfaec652d"},
|
||||||
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"},
|
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.5.3", "f2161c207fda0e4fb55165f650f7f8db23f02b29e3bff00ff7ef161d6ac1f09d", [:mix], [{:file_system, "~> 0.3 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "b4ec9cd73cb01ff1bd1cac92e045d13e7030330b74164297d1aee3907b54803c"},
|
||||||
"phoenix_live_view": {:hex, :phoenix_live_view, "0.20.14", "70fa101aa0539e81bed4238777498f6215e9dda3461bdaa067cad6908110c364", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "82f6d006c5264f979ed5eb75593d808bbe39020f20df2e78426f4f2d570e2402"},
|
"phoenix_live_view": {:hex, :phoenix_live_view, "1.0.0-rc.0", "42a5a568d7105d1d4e6542badfe061154491da584836a4a4ead148a2c67d649e", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "10cb32643a0cfecb6f3f1feff8211273ba5917891e451b635abc940e3b907a4a"},
|
||||||
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
|
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
|
||||||
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
|
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
|
||||||
"plug": {:git, "https://github.com/elixir-plug/plug.git", "0574733fb933e4a2ea78532e38e687d9cffb4858", []},
|
"plug": {:git, "https://github.com/elixir-plug/plug.git", "0574733fb933e4a2ea78532e38e687d9cffb4858", []},
|
||||||
|
|
|
@ -70,21 +70,20 @@ defmodule Livebook.HubsTest do
|
||||||
value = hub.id
|
value = hub.id
|
||||||
secret = build(:secret, name: name, value: value, hub_id: hub.id)
|
secret = build(:secret, name: name, value: value, hub_id: hub.id)
|
||||||
|
|
||||||
assert Hubs.create_secret(hub, secret) == :ok
|
assert :ok = Hubs.create_secret(hub, secret)
|
||||||
assert secret in Hubs.get_secrets(hub)
|
assert secret in Hubs.get_secrets(hub)
|
||||||
|
|
||||||
# Guarantee uniqueness
|
# Guarantee uniqueness
|
||||||
assert {:error, changeset} = Hubs.create_secret(hub, secret)
|
assert {:error, errors} = Hubs.create_secret(hub, secret)
|
||||||
assert "has already been taken" in errors_on(changeset).name
|
assert "has already been taken" in errors[:name]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns changeset errors when data is invalid", %{user: user, node: node} do
|
test "returns changeset errors when data is invalid", %{user: user, node: node} do
|
||||||
hub = connect_to_teams(user, node)
|
hub = connect_to_teams(user, node)
|
||||||
secret = build(:secret, name: "LB_FOO", value: "BAR", hub_id: hub.id)
|
secret = build(:secret, name: "LB_FOO", value: "BAR", hub_id: hub.id)
|
||||||
|
|
||||||
assert {:error, changeset} = Hubs.create_secret(hub, secret)
|
assert {:error, errors} = Hubs.create_secret(hub, secret)
|
||||||
assert "cannot start with the LB_ prefix" in errors_on(changeset).name
|
assert "cannot start with the LB_ prefix" in errors[:name]
|
||||||
refute secret in Hubs.get_secrets(hub)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -119,8 +118,8 @@ defmodule Livebook.HubsTest do
|
||||||
|
|
||||||
updated_secret = Map.replace!(secret, :value, "")
|
updated_secret = Map.replace!(secret, :value, "")
|
||||||
|
|
||||||
assert {:error, changeset} = Hubs.update_secret(hub, updated_secret)
|
assert {:error, errors} = Hubs.update_secret(hub, updated_secret)
|
||||||
assert "can't be blank" in errors_on(changeset).value
|
assert "can't be blank" in errors[:value]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -156,16 +155,16 @@ defmodule Livebook.HubsTest do
|
||||||
assert_receive {:file_system_created, %{bucket_url: ^bucket_url, region: ^region}}
|
assert_receive {:file_system_created, %{bucket_url: ^bucket_url, region: ^region}}
|
||||||
|
|
||||||
# Guarantee uniqueness
|
# Guarantee uniqueness
|
||||||
assert {:error, changeset} = Hubs.create_file_system(hub, file_system)
|
assert {:error, errors} = Hubs.create_file_system(hub, file_system)
|
||||||
assert "has already been taken" in errors_on(changeset).bucket_url
|
assert "has already been taken" in errors[:bucket_url]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns changeset errors when data is invalid", %{user: user, node: node} do
|
test "returns changeset errors when data is invalid", %{user: user, node: node} do
|
||||||
hub = connect_to_teams(user, node)
|
hub = connect_to_teams(user, node)
|
||||||
file_system = build(:fs_s3, bucket_url: nil)
|
file_system = build(:fs_s3, bucket_url: nil)
|
||||||
|
|
||||||
assert {:error, changeset} = Hubs.create_file_system(hub, file_system)
|
assert {:error, errors} = Hubs.create_file_system(hub, file_system)
|
||||||
assert "can't be blank" in errors_on(changeset).bucket_url
|
assert "can't be blank" in errors[:bucket_url]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -202,8 +201,8 @@ defmodule Livebook.HubsTest do
|
||||||
|
|
||||||
update_file_system = Map.replace!(file_system, :bucket_url, "")
|
update_file_system = Map.replace!(file_system, :bucket_url, "")
|
||||||
|
|
||||||
assert {:error, changeset} = Hubs.update_file_system(hub, update_file_system)
|
assert {:error, errors} = Hubs.update_file_system(hub, update_file_system)
|
||||||
assert "can't be blank" in errors_on(changeset).bucket_url
|
assert "can't be blank" in errors[:bucket_url]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -170,34 +170,32 @@ defmodule Livebook.TeamsTest do
|
||||||
test "creates a new deployment group when the data is valid", %{user: user, node: node} do
|
test "creates a new deployment group when the data is valid", %{user: user, node: node} do
|
||||||
team = connect_to_teams(user, node)
|
team = connect_to_teams(user, node)
|
||||||
|
|
||||||
deployment_group =
|
attrs = params_for(:deployment_group, name: "DEPLOYMENT_GROUP_#{team.id}", mode: :online)
|
||||||
build(:deployment_group, name: "DEPLOYMENT_GROUP_#{team.id}", mode: :online)
|
|
||||||
|
|
||||||
assert {:ok, id} = Teams.create_deployment_group(team, deployment_group)
|
assert {:ok, deployment_group} = Teams.create_deployment_group(team, attrs)
|
||||||
|
|
||||||
%{name: name, mode: mode} = deployment_group
|
%{id: id, name: name, mode: mode} = deployment_group
|
||||||
id = to_string(id)
|
|
||||||
|
|
||||||
assert_receive {:deployment_group_created, %{id: ^id, name: ^name, mode: ^mode}}
|
assert_receive {:deployment_group_created, %{id: ^id, name: ^name, mode: ^mode}}
|
||||||
|
|
||||||
# Guarantee uniqueness
|
# Guarantee uniqueness
|
||||||
assert {:error, changeset} = Teams.create_deployment_group(team, deployment_group)
|
assert {:error, changeset} = Teams.create_deployment_group(team, attrs)
|
||||||
assert "has already been taken" in errors_on(changeset).name
|
assert "has already been taken" in errors_on(changeset).name
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns changeset errors when the name is invalid", %{user: user, node: node} do
|
test "returns changeset errors when the name is invalid", %{user: user, node: node} do
|
||||||
team = connect_to_teams(user, node)
|
team = connect_to_teams(user, node)
|
||||||
deployment_group = %{build(:deployment_group) | name: ""}
|
attrs = params_for(:deployment_group, name: "")
|
||||||
|
|
||||||
assert {:error, changeset} = Teams.create_deployment_group(team, deployment_group)
|
assert {:error, changeset} = Teams.create_deployment_group(team, attrs)
|
||||||
assert "can't be blank" in errors_on(changeset).name
|
assert "can't be blank" in errors_on(changeset).name
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns changeset errors when the mode is invalid", %{user: user, node: node} do
|
test "returns changeset errors when the mode is invalid", %{user: user, node: node} do
|
||||||
team = connect_to_teams(user, node)
|
team = connect_to_teams(user, node)
|
||||||
deployment_group = %{build(:deployment_group) | mode: "invalid"}
|
attrs = params_for(:deployment_group, mode: "invalid")
|
||||||
|
|
||||||
assert {:error, changeset} = Teams.create_deployment_group(team, deployment_group)
|
assert {:error, changeset} = Teams.create_deployment_group(team, attrs)
|
||||||
assert "is invalid" in errors_on(changeset).mode
|
assert "is invalid" in errors_on(changeset).mode
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -206,10 +204,9 @@ defmodule Livebook.TeamsTest do
|
||||||
@tag :tmp_dir
|
@tag :tmp_dir
|
||||||
test "deploys app to Teams from a notebook", %{user: user, node: node, tmp_dir: tmp_dir} do
|
test "deploys app to Teams from a notebook", %{user: user, node: node, tmp_dir: tmp_dir} do
|
||||||
team = connect_to_teams(user, node)
|
team = connect_to_teams(user, node)
|
||||||
deployment_group = build(:deployment_group, name: "BAZ", mode: :online)
|
attrs = params_for(:deployment_group, name: "BAZ", mode: :online)
|
||||||
{:ok, id} = Teams.create_deployment_group(team, deployment_group)
|
{:ok, %{id: id}} = Teams.create_deployment_group(team, attrs)
|
||||||
|
|
||||||
id = to_string(id)
|
|
||||||
assert_receive {:deployment_group_created, %{id: ^id}}
|
assert_receive {:deployment_group_created, %{id: ^id}}
|
||||||
|
|
||||||
# creates the app deployment
|
# creates the app deployment
|
||||||
|
|
|
@ -147,11 +147,10 @@ defmodule Livebook.Factory do
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_deployment_group(attrs \\ %{}) do
|
def insert_deployment_group(attrs \\ %{}) do
|
||||||
deployment_group = build(:deployment_group, attrs)
|
attrs = params_for(:deployment_group, attrs)
|
||||||
hub = Livebook.Hubs.fetch_hub!(deployment_group.hub_id)
|
hub = Livebook.Hubs.fetch_hub!(attrs.hub_id)
|
||||||
{:ok, id} = Livebook.Teams.create_deployment_group(hub, deployment_group)
|
{:ok, deployment_group} = Livebook.Teams.create_deployment_group(hub, attrs)
|
||||||
|
deployment_group
|
||||||
%{deployment_group | id: to_string(id)}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def insert_env_var(factory_name, attrs \\ %{}) do
|
def insert_env_var(factory_name, attrs \\ %{}) do
|
||||||
|
|
Loading…
Reference in a new issue