diff --git a/backend/lib/prymn/servers.ex b/backend/lib/prymn/servers.ex index 1c70860..d6d5bef 100644 --- a/backend/lib/prymn/servers.ex +++ b/backend/lib/prymn/servers.ex @@ -50,7 +50,8 @@ defmodule Prymn.Servers do """ def create_server(attrs \\ %{}) do - %Server{} + # FIXME: Maybe use a cryptographically secure token (if UUID v4 is not one)? + %Server{connection_token: Ecto.UUID.generate()} |> Server.changeset(attrs) |> Repo.insert() end diff --git a/backend/lib/prymn/servers/server.ex b/backend/lib/prymn/servers/server.ex index 13c20e4..21b22ac 100644 --- a/backend/lib/prymn/servers/server.ex +++ b/backend/lib/prymn/servers/server.ex @@ -6,6 +6,8 @@ defmodule Prymn.Servers.Server do field :name, :string field :ipv4, :string field :ipv6, :string + field :provider, Ecto.Enum, values: [:Hetzner, :Custom] + field :connection_token, Ecto.UUID, redact: true timestamps() end @@ -13,7 +15,8 @@ defmodule Prymn.Servers.Server do @doc false def changeset(server, attrs) do server - |> cast(attrs, [:name]) - |> validate_required([:name]) + |> cast(attrs, [:name, :provider]) + |> validate_required([:name, :provider, :connection_token]) + |> validate_inclusion(:provider, [:Custom], message: "Provider not available (yet)") end end diff --git a/backend/lib/prymn_web/components/core_components.ex b/backend/lib/prymn_web/components/core_components.ex index 2840ece..f9c99ca 100644 --- a/backend/lib/prymn_web/components/core_components.ex +++ b/backend/lib/prymn_web/components/core_components.ex @@ -436,6 +436,8 @@ defmodule PrymnWeb.CoreComponents do attr :rows, :list, required: true attr :row_id, :any, default: nil, doc: "the function for generating the row id" attr :row_click, :any, default: nil, doc: "the function for handling phx-click on each row" + attr :row_indicator, :any, default: nil + attr :indicator_label, :string, default: "Indicator" attr :row_item, :any, default: &Function.identity/1, @@ -458,6 +460,9 @@ defmodule PrymnWeb.CoreComponents do
+ <%= @indicator_label %>
+ |
<%= col[:label] %> | <%= gettext("Actions") %> |
---|---|---|
+
+
+ <%= @row_indicator.(row) %>
+
+ |
-
<%= render_slot(col, @row_item.(row)) %>
diff --git a/backend/lib/prymn_web/live/server_live/edit.ex b/backend/lib/prymn_web/live/server_live/edit.ex
deleted file mode 100644
index 79c4e2c..0000000
--- a/backend/lib/prymn_web/live/server_live/edit.ex
+++ /dev/null
@@ -1,25 +0,0 @@
-defmodule PrymnWeb.ServerLive.Edit do
- use PrymnWeb, :live_view
-
- alias Prymn.Servers
-
- @impl true
- def mount(_params, _session, socket) do
- {:ok, socket}
- end
-
- @impl true
- def handle_params(%{"id" => id}, _, socket) do
- server = Servers.get_server!(id)
-
- {:noreply,
- socket
- |> assign(:page_title, "Editing #{server.name}")
- |> assign(:server, server)}
- end
-
- @impl true
- def handle_info({PrymnWeb.ServerLive.FormComponent, {:saved, server}}, socket) do
- {:noreply, assign(socket, :server, server)}
- end
-end
diff --git a/backend/lib/prymn_web/live/server_live/edit.html.heex b/backend/lib/prymn_web/live/server_live/edit.html.heex
deleted file mode 100644
index 6716cd2..0000000
--- a/backend/lib/prymn_web/live/server_live/edit.html.heex
+++ /dev/null
@@ -1,11 +0,0 @@
-<.header>Editing server <%= @server.name %>
-
-<.live_component
- module={PrymnWeb.ServerLive.FormComponent}
- title="Test"
- id={@server.id}
- action={@live_action}
- server={@server}
-/>
-
-<.back navigate={~p"/servers/#{@server}"}>Go back to server <%= @server.name %>
diff --git a/backend/lib/prymn_web/live/server_live/form_component.ex b/backend/lib/prymn_web/live/server_live/form_component.ex
deleted file mode 100644
index 9b03703..0000000
--- a/backend/lib/prymn_web/live/server_live/form_component.ex
+++ /dev/null
@@ -1,88 +0,0 @@
-defmodule PrymnWeb.ServerLive.FormComponent do
- use PrymnWeb, :live_component
-
- alias Prymn.Servers
-
- @impl true
- def render(assigns) do
- ~H"""
-
- <.simple_form
- for={@form}
- id="server-form"
- phx-target={@myself}
- phx-change="validate"
- phx-submit="save"
- >
- <.input field={@form[:name]} type="text" label="Name" />
- <:actions>
- <.button phx-disable-with="Saving...">Save Server
-
-
-
- """
- end
-
- @impl true
- def update(%{server: server} = assigns, socket) do
- changeset = Servers.change_server(server)
-
- {:ok,
- socket
- |> assign(assigns)
- |> assign_form(changeset)}
- end
-
- @impl true
- def handle_event("validate", %{"server" => server_params}, socket) do
- changeset =
- socket.assigns.server
- |> Servers.change_server(server_params)
- |> Map.put(:action, :validate)
-
- {:noreply, assign_form(socket, changeset)}
- end
-
- def handle_event("save", %{"server" => server_params}, socket) do
- save_server(socket, socket.assigns.action, server_params)
- end
-
- defp save_server(socket, :edit, server_params) do
- case Servers.update_server(socket.assigns.server, server_params) do
- {:ok, server} ->
- notify_parent({:saved, server})
-
- socket = socket |> put_flash(:info, "Server updated successfully")
-
- if Map.has_key?(socket.assigns, :patch) do
- socket = push_patch(socket, to: socket.assigns.patch)
- end
-
- {:noreply, socket}
-
- {:error, %Ecto.Changeset{} = changeset} ->
- {:noreply, assign_form(socket, changeset)}
- end
- end
-
- defp save_server(socket, :new, server_params) do
- case Servers.create_server(server_params) do
- {:ok, server} ->
- notify_parent({:saved, server})
-
- {:noreply,
- socket
- |> put_flash(:info, "Server created successfully")
- |> push_patch(to: socket.assigns.patch || false)}
-
- {:error, %Ecto.Changeset{} = changeset} ->
- {:noreply, assign_form(socket, changeset)}
- end
- end
-
- defp assign_form(socket, %Ecto.Changeset{} = changeset) do
- assign(socket, :form, to_form(changeset))
- end
-
- defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
-end
diff --git a/backend/lib/prymn_web/live/server_live/index.ex b/backend/lib/prymn_web/live/server_live/index.ex
index e277cf0..99ddd39 100644
--- a/backend/lib/prymn_web/live/server_live/index.ex
+++ b/backend/lib/prymn_web/live/server_live/index.ex
@@ -2,7 +2,6 @@ defmodule PrymnWeb.ServerLive.Index do
use PrymnWeb, :live_view
alias Prymn.Servers
- alias Prymn.Servers.Server
@impl true
def mount(_params, _session, socket) do
@@ -14,26 +13,21 @@ defmodule PrymnWeb.ServerLive.Index do
{:noreply, apply_action(socket, socket.assigns.live_action, params)}
end
- defp apply_action(socket, :edit, %{"id" => id}) do
- socket
- |> assign(:page_title, "Edit Server")
- |> assign(:server, Servers.get_server!(id))
- end
-
defp apply_action(socket, :new, _params) do
socket
|> assign(:page_title, "New Server")
- |> assign(:server, %Server{})
end
defp apply_action(socket, :index, _params) do
socket
|> assign(:page_title, "Listing Servers")
- |> assign(:server, nil)
end
@impl true
- def handle_info({PrymnWeb.ServerLive.FormComponent, {:saved, server}}, socket) do
+ def handle_info({:connect, server}, socket) do
+ # TODO: Connect the new server:
+ # For custom connections: will need to generate a new prompt for the user to execute
+ # For API connections: the "prompt" will be automatic, but same execution server-side
{:noreply, stream_insert(socket, :servers, server)}
end
diff --git a/backend/lib/prymn_web/live/server_live/index.html.heex b/backend/lib/prymn_web/live/server_live/index.html.heex
index 44fadf3..3f38d52 100644
--- a/backend/lib/prymn_web/live/server_live/index.html.heex
+++ b/backend/lib/prymn_web/live/server_live/index.html.heex
@@ -11,6 +11,12 @@
id="servers"
rows={@streams.servers}
row_click={fn {_id, server} -> JS.navigate(~p"/servers/#{server}") end}
+ row_indicator={
+ fn {_id, _server} ->
+ ~H(Connecting)
+ end
+ }
+ indicator_label="Status"
>
<:col :let={{_id, server}} label="Name"><%= server.name %>
<:col :let={{_id, server}} label="IPv4"><%= server.ipv4 || "N/A" %>
@@ -25,22 +31,6 @@
-<.modal
- :if={@live_action in [:new, :edit]}
- id="server-modal"
- show
- on_cancel={JS.patch(~p"/servers")}
->
- <.header>
- Add a new server
- <:subtitle>Connect your server to Prymn!
-
- <.live_component
- module={PrymnWeb.ServerLive.FormComponent}
- id={:new}
- title={@page_title}
- action={@live_action}
- server={@server}
- patch={~p"/servers"}
- />
+<.modal :if={@live_action == :new} id="server-modal" show on_cancel={JS.patch(~p"/servers")}>
+ <.live_component module={PrymnWeb.ServerLive.NewServer} id={:new} patch={~p"/servers"} />
diff --git a/backend/lib/prymn_web/live/server_live/new_server.ex b/backend/lib/prymn_web/live/server_live/new_server.ex
new file mode 100644
index 0000000..5e8949b
--- /dev/null
+++ b/backend/lib/prymn_web/live/server_live/new_server.ex
@@ -0,0 +1,92 @@
+defmodule PrymnWeb.ServerLive.NewServer do
+ use PrymnWeb, :live_component
+
+ alias Prymn.Servers
+ require Logger
+
+ @impl true
+ def render(assigns) do
+ ~H"""
+
+ <.header>
+ Add a new server
+ <:subtitle>Connect your server to Prymn!
+
+
+ <.error :if={assigns[:error]}>There were some errors.
+
+ <.simple_form for={@form} phx-change="validate" phx-submit="connect" phx-target={@myself}>
+ <.input field={@form[:name]} label="Server Name" phx-debounce={1000} />
+ <.input
+ field={@form[:provider]}
+ label="Provider"
+ type="select"
+ prompt="Select a provider"
+ options={Ecto.Enum.mappings(Servers.Server, :provider)}
+ />
+ <.provider id="provider" provider={@form[:provider]} />
+ <:actions>
+ <.button>Connect
+
+
+
+ """
+ end
+
+ @impl true
+ def update(assigns, socket) do
+ changeset = Servers.change_server(%Servers.Server{})
+
+ socket =
+ socket
+ |> assign(assigns)
+ |> assign(:form, to_form(changeset))
+
+ {:ok, socket}
+ end
+
+ @impl true
+ def handle_event("validate", %{"server" => params}, socket) do
+ form =
+ %Servers.Server{}
+ |> Servers.change_server(params)
+ |> Map.put(:action, :validate)
+ |> to_form()
+
+ {:noreply, assign(socket, form: form)}
+ end
+
+ @impl true
+ def handle_event("connect", %{"server" => params}, socket) do
+ socket =
+ case Servers.create_server(params) do
+ {:ok, server} ->
+ # Notify parent
+ send(self(), {:connect, server})
+
+ socket
+ |> put_flash(:info, "Starting new server connection...")
+ |> push_patch(to: ~p"/servers")
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ socket
+ |> assign(:form, to_form(changeset))
+ |> assign(:error, true)
+ end
+
+ {:noreply, socket}
+ end
+
+ defp provider(%{provider: %{value: :Custom}} = assigns) do
+ ~H"""
+
+
+
<.back navigate={~p"/servers"}>Back to servers
-
-<.modal
- :if={@live_action == :edit}
- id="server-modal"
- show
- on_cancel={JS.patch(~p"/servers/#{@server}")}
->
- <.live_component
- module={PrymnWeb.ServerLive.FormComponent}
- id={@server.id}
- title={@page_title}
- action={@live_action}
- server={@server}
- patch={~p"/servers/#{@server}"}
- />
-
diff --git a/backend/lib/prymn_web/router.ex b/backend/lib/prymn_web/router.ex
index 76a9fd6..5cb50c4 100644
--- a/backend/lib/prymn_web/router.ex
+++ b/backend/lib/prymn_web/router.ex
@@ -22,9 +22,7 @@ defmodule PrymnWeb.Router do
live "/servers", ServerLive.Index, :index
live "/servers/new", ServerLive.Index, :new
- live "/servers/:id", ServerLive.Show, :show
-
- live "/servers/:id/edit", ServerLive.Edit, :edit
+ live "/servers/:id", ServerLive.Show
end
# Other scopes may use custom stacks.
diff --git a/backend/priv/repo/migrations/20230609164352_create_servers.exs b/backend/priv/repo/migrations/20230609164352_create_servers.exs
index b17422a..93e046b 100644
--- a/backend/priv/repo/migrations/20230609164352_create_servers.exs
+++ b/backend/priv/repo/migrations/20230609164352_create_servers.exs
@@ -6,6 +6,8 @@ defmodule Prymn.Repo.Migrations.CreateServers do
add :name, :string
add :ipv4, :string
add :ipv6, :string
+ add :provider, :string
+ add :connection_token, :binary
timestamps()
end
Sites+ |