draft: apps
This commit is contained in:
parent
78051bb796
commit
4a37cc402a
8 changed files with 354 additions and 0 deletions
103
app/lib/prymn/apps.ex
Normal file
103
app/lib/prymn/apps.ex
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
defmodule Prymn.Apps do
|
||||||
|
@moduledoc """
|
||||||
|
The Apps context.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import Ecto.Query, warn: false
|
||||||
|
alias Prymn.Repo
|
||||||
|
alias Prymn.Apps.App
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns the list of apps.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> list_apps()
|
||||||
|
[%App{}, ...]
|
||||||
|
|
||||||
|
"""
|
||||||
|
def list_apps do
|
||||||
|
Repo.all(App)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Gets a single app.
|
||||||
|
|
||||||
|
Raises `Ecto.NoResultsError` if the App does not exist.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> get_app!(123)
|
||||||
|
%App{}
|
||||||
|
|
||||||
|
iex> get_app!(456)
|
||||||
|
** (Ecto.NoResultsError)
|
||||||
|
|
||||||
|
"""
|
||||||
|
def get_app!(id), do: Repo.get!(App, id)
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Creates a app.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> create_app(%{field: value})
|
||||||
|
{:ok, %App{}}
|
||||||
|
|
||||||
|
iex> create_app(%{field: bad_value})
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def create_app(attrs \\ %{}) do
|
||||||
|
%App{}
|
||||||
|
|> App.changeset(attrs)
|
||||||
|
|> Repo.insert()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Updates a app.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> update_app(app, %{field: new_value})
|
||||||
|
{:ok, %App{}}
|
||||||
|
|
||||||
|
iex> update_app(app, %{field: bad_value})
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def update_app(%App{} = app, attrs) do
|
||||||
|
app
|
||||||
|
|> App.changeset(attrs)
|
||||||
|
|> Repo.update()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Deletes a app.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> delete_app(app)
|
||||||
|
{:ok, %App{}}
|
||||||
|
|
||||||
|
iex> delete_app(app)
|
||||||
|
{:error, %Ecto.Changeset{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def delete_app(%App{} = app) do
|
||||||
|
Repo.delete(app)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Returns an `%Ecto.Changeset{}` for tracking app changes.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> change_app(app)
|
||||||
|
%Ecto.Changeset{data: %App{}}
|
||||||
|
|
||||||
|
"""
|
||||||
|
def change_app(%App{} = app, attrs \\ %{}) do
|
||||||
|
App.changeset(app, attrs)
|
||||||
|
end
|
||||||
|
end
|
17
app/lib/prymn/apps/app.ex
Normal file
17
app/lib/prymn/apps/app.ex
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
defmodule Prymn.Apps.App do
|
||||||
|
use Ecto.Schema
|
||||||
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
schema "apps" do
|
||||||
|
field :name, :string
|
||||||
|
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
def changeset(app, attrs) do
|
||||||
|
app
|
||||||
|
|> cast(attrs, [:name])
|
||||||
|
|> validate_required([:name])
|
||||||
|
end
|
||||||
|
end
|
78
app/lib/prymn_web/components/create_app.ex
Normal file
78
app/lib/prymn_web/components/create_app.ex
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
defmodule PrymnWeb.CreateApp do
|
||||||
|
use PrymnWeb, :live_component
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def render(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div class="mx-auto max-w-2xl">
|
||||||
|
<fieldset>
|
||||||
|
<legend class="mb-6 border-b border-slate-200 pb-2 text-base font-semibold">App Type</legend>
|
||||||
|
<span>
|
||||||
|
<input
|
||||||
|
id="wordpress"
|
||||||
|
type="radio"
|
||||||
|
name="app_type"
|
||||||
|
value="wordpress"
|
||||||
|
class="peer hidden"
|
||||||
|
checked={@app_type == "wordpress"}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="wordpress"
|
||||||
|
class="inline-block cursor-pointer rounded p-5 shadow peer-checked:bg-black peer-checked:text-white"
|
||||||
|
phx-click={JS.patch(~p"/apps/new?app_type=wordpress")}
|
||||||
|
>
|
||||||
|
WordPress
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<input
|
||||||
|
id="plain_html"
|
||||||
|
type="radio"
|
||||||
|
name="app_type"
|
||||||
|
value="plain_html"
|
||||||
|
class="peer hidden"
|
||||||
|
checked={@app_type == "plain_html"}
|
||||||
|
/>
|
||||||
|
<label
|
||||||
|
for="plain_html"
|
||||||
|
class="inline-block cursor-pointer rounded p-5 shadow peer-checked:bg-black peer-checked:text-white"
|
||||||
|
phx-click={JS.patch(~p"/apps/new?app_type=plain_html")}
|
||||||
|
>
|
||||||
|
Plain HTML
|
||||||
|
</label>
|
||||||
|
</span>
|
||||||
|
</fieldset>
|
||||||
|
<.wordpress_app_form :if={assigns.app_type == "wordpress"} servers={assigns[:servers]} />
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp wordpress_app_form(assigns) do
|
||||||
|
~H"""
|
||||||
|
<.simple_form id="test" for={nil}>
|
||||||
|
<.input
|
||||||
|
:if={assigns.servers != nil}
|
||||||
|
id="server"
|
||||||
|
type="select"
|
||||||
|
name="server"
|
||||||
|
prompt="Select a server to host this app..."
|
||||||
|
options={[]}
|
||||||
|
value={nil}
|
||||||
|
label="Hosting Server"
|
||||||
|
/>
|
||||||
|
<.input id="name" type="text" name="app_name" value={nil} label="WordPress Site Name" required />
|
||||||
|
<.input id="domain" type="text" name="domain" value={nil} label="Domain Name" required />
|
||||||
|
<.input type="checkbox" name="create_database?" label="Create a new database?" />
|
||||||
|
<.input type="text" name="db_name" value={nil} label="Database name" />
|
||||||
|
|
||||||
|
<.input type="select" name="db_name" value={nil} options={["db1", "db2"]} label="Database" />
|
||||||
|
|
||||||
|
<.input type="text" name="admin_username" value={nil} label="Admin Username" />
|
||||||
|
<.input type="email" name="admin_email" value={nil} label="Admin Email" />
|
||||||
|
<.input type="password" name="admin_password" value={nil} label="Admin Password" />
|
||||||
|
|
||||||
|
<.button type="submit">Create</.button>
|
||||||
|
</.simple_form>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
63
app/lib/prymn_web/live/app_index_live.ex
Normal file
63
app/lib/prymn_web/live/app_index_live.ex
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
defmodule PrymnWeb.AppIndexLive do
|
||||||
|
use PrymnWeb, :live_view
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def mount(_, _, socket) do
|
||||||
|
apps = Prymn.Apps.list_apps()
|
||||||
|
servers = Prymn.Servers.list_servers()
|
||||||
|
|
||||||
|
{:ok,
|
||||||
|
socket
|
||||||
|
|> assign(:servers, servers)
|
||||||
|
|> assign(:apps, apps)}
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def render(assigns) do
|
||||||
|
~H"""
|
||||||
|
<%= cond do %>
|
||||||
|
<% assigns.live_action == :new -> %>
|
||||||
|
<.back navigate={~p"/apps"}>Go back</.back>
|
||||||
|
<.live_component
|
||||||
|
id={:new}
|
||||||
|
module={PrymnWeb.CreateApp}
|
||||||
|
app_type={assigns[:app_type]}
|
||||||
|
servers={@servers}
|
||||||
|
/>
|
||||||
|
<% assigns.apps == [] -> %>
|
||||||
|
<.onboarding />
|
||||||
|
<% true -> %>
|
||||||
|
<div class="mx-auto max-w-2xl">
|
||||||
|
<.header>
|
||||||
|
Live Apps
|
||||||
|
<:subtitle>
|
||||||
|
All of your apps accross all projects.
|
||||||
|
</:subtitle>
|
||||||
|
</.header>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl true
|
||||||
|
def handle_params(%{"app_type" => app_type}, _, socket) do
|
||||||
|
{:noreply, assign(socket, app_type: app_type)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_params(_, _, socket) do
|
||||||
|
{:noreply,
|
||||||
|
socket
|
||||||
|
|> assign(:page_title, (socket.assigns.live_action == :new && "New App") || "Apps")}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp onboarding(assigns) do
|
||||||
|
~H"""
|
||||||
|
<div class="mx-auto max-w-2xl text-center">
|
||||||
|
<h1 class="mb-5 text-3xl font-medium">You have no Apps.</h1>
|
||||||
|
<.button type="link" patch={~p"/apps/new"}>
|
||||||
|
<.icon class="mr-2 h-6 w-6" name="hero-plus" /> Create your first App!
|
||||||
|
</.button>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
|
@ -37,6 +37,9 @@ defmodule PrymnWeb.Router do
|
||||||
live "/servers", ServerLive.Index, :index
|
live "/servers", ServerLive.Index, :index
|
||||||
live "/servers/new", ServerLive.Index, :new
|
live "/servers/new", ServerLive.Index, :new
|
||||||
live "/servers/:id", ServerLive.Show
|
live "/servers/:id", ServerLive.Show
|
||||||
|
|
||||||
|
live "/apps", AppIndexLive
|
||||||
|
live "/apps/new", AppIndexLive, :new
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
59
app/test/prymn/apps_test.exs
Normal file
59
app/test/prymn/apps_test.exs
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
defmodule Prymn.AppsTest do
|
||||||
|
use Prymn.DataCase
|
||||||
|
|
||||||
|
alias Prymn.Apps
|
||||||
|
|
||||||
|
describe "apps" do
|
||||||
|
alias Prymn.Apps.App
|
||||||
|
|
||||||
|
import Prymn.AppsFixtures
|
||||||
|
|
||||||
|
@invalid_attrs %{name: nil}
|
||||||
|
|
||||||
|
test "list_apps/0 returns all apps" do
|
||||||
|
app = app_fixture()
|
||||||
|
assert Apps.list_apps() == [app]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "get_app!/1 returns the app with given id" do
|
||||||
|
app = app_fixture()
|
||||||
|
assert Apps.get_app!(app.id) == app
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_app/1 with valid data creates a app" do
|
||||||
|
valid_attrs = %{name: "some name"}
|
||||||
|
|
||||||
|
assert {:ok, %App{} = app} = Apps.create_app(valid_attrs)
|
||||||
|
assert app.name == "some name"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "create_app/1 with invalid data returns error changeset" do
|
||||||
|
assert {:error, %Ecto.Changeset{}} = Apps.create_app(@invalid_attrs)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "update_app/2 with valid data updates the app" do
|
||||||
|
app = app_fixture()
|
||||||
|
update_attrs = %{name: "some updated name"}
|
||||||
|
|
||||||
|
assert {:ok, %App{} = app} = Apps.update_app(app, update_attrs)
|
||||||
|
assert app.name == "some updated name"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "update_app/2 with invalid data returns error changeset" do
|
||||||
|
app = app_fixture()
|
||||||
|
assert {:error, %Ecto.Changeset{}} = Apps.update_app(app, @invalid_attrs)
|
||||||
|
assert app == Apps.get_app!(app.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "delete_app/1 deletes the app" do
|
||||||
|
app = app_fixture()
|
||||||
|
assert {:ok, %App{}} = Apps.delete_app(app)
|
||||||
|
assert_raise Ecto.NoResultsError, fn -> Apps.get_app!(app.id) end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "change_app/1 returns a app changeset" do
|
||||||
|
app = app_fixture()
|
||||||
|
assert %Ecto.Changeset{} = Apps.change_app(app)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
20
app/test/support/fixtures/apps_fixtures.ex
Normal file
20
app/test/support/fixtures/apps_fixtures.ex
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
defmodule Prymn.AppsFixtures do
|
||||||
|
@moduledoc """
|
||||||
|
This module defines test helpers for creating
|
||||||
|
entities via the `Prymn.Apps` context.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Generate a app.
|
||||||
|
"""
|
||||||
|
def app_fixture(attrs \\ %{}) do
|
||||||
|
{:ok, app} =
|
||||||
|
attrs
|
||||||
|
|> Enum.into(%{
|
||||||
|
name: "some name"
|
||||||
|
})
|
||||||
|
|> Prymn.Apps.create_app()
|
||||||
|
|
||||||
|
app
|
||||||
|
end
|
||||||
|
end
|
11
priv/repo/migrations/20231119141943_create_apps.exs
Normal file
11
priv/repo/migrations/20231119141943_create_apps.exs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
defmodule Prymn.Repo.Migrations.CreateApps do
|
||||||
|
use Ecto.Migration
|
||||||
|
|
||||||
|
def change do
|
||||||
|
create table(:apps) do
|
||||||
|
add :name, :string
|
||||||
|
|
||||||
|
timestamps()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue