-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #499 from podlove/outline_nodes
add: inbox & outline context
- Loading branch information
Showing
8 changed files
with
300 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
defmodule Radiator.Outline do | ||
@moduledoc """ | ||
The Outline context. | ||
""" | ||
|
||
import Ecto.Query, warn: false | ||
alias Radiator.Repo | ||
|
||
alias Radiator.Outline.Node | ||
|
||
@doc """ | ||
Returns the list of nodes. | ||
## Examples | ||
iex> list_nodes() | ||
[%Node{}, ...] | ||
""" | ||
def list_nodes do | ||
Repo.all(Node) | ||
end | ||
|
||
@doc """ | ||
Gets a single node. | ||
Raises `Ecto.NoResultsError` if the Node does not exist. | ||
## Examples | ||
iex> get_node!(123) | ||
%Node{} | ||
iex> get_node!(456) | ||
** (Ecto.NoResultsError) | ||
""" | ||
def get_node!(id), do: Repo.get!(Node, id) | ||
|
||
@doc """ | ||
Creates a node. | ||
## Examples | ||
iex> create_node(%{field: value}) | ||
{:ok, %Node{}} | ||
iex> create_node(%{field: bad_value}) | ||
{:error, %Ecto.Changeset{}} | ||
""" | ||
def create_node(attrs \\ %{}) do | ||
%Node{} | ||
|> Node.changeset(attrs) | ||
|> Repo.insert() | ||
end | ||
|
||
@doc """ | ||
Updates a node. | ||
## Examples | ||
iex> update_node(node, %{field: new_value}) | ||
{:ok, %Node{}} | ||
iex> update_node(node, %{field: bad_value}) | ||
{:error, %Ecto.Changeset{}} | ||
""" | ||
def update_node(%Node{} = node, attrs) do | ||
node | ||
|> Node.changeset(attrs) | ||
|> Repo.update() | ||
end | ||
|
||
@doc """ | ||
Deletes a node. | ||
## Examples | ||
iex> delete_node(node) | ||
{:ok, %Node{}} | ||
iex> delete_node(node) | ||
{:error, %Ecto.Changeset{}} | ||
""" | ||
def delete_node(%Node{} = node) do | ||
Repo.delete(node) | ||
end | ||
|
||
@doc """ | ||
Returns an `%Ecto.Changeset{}` for tracking node changes. | ||
## Examples | ||
iex> change_node(node) | ||
%Ecto.Changeset{data: %Node{}} | ||
""" | ||
def change_node(%Node{} = node, attrs \\ %{}) do | ||
Node.changeset(node, attrs) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
defmodule Radiator.Outline.Node do | ||
use Ecto.Schema | ||
import Ecto.Changeset | ||
|
||
@primary_key {:uuid, :binary_id, autogenerate: true} | ||
schema "outline_nodes" do | ||
field :content, :string | ||
|
||
timestamps(type: :utc_datetime) | ||
end | ||
|
||
@fields [ | ||
:content | ||
] | ||
|
||
@doc false | ||
def changeset(node, attrs) do | ||
node | ||
|> cast(attrs, @fields) | ||
|> validate_required(@fields) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,43 @@ | ||
defmodule RadiatorWeb.OutlineLive.Index do | ||
use RadiatorWeb, :live_view | ||
|
||
alias Radiator.Outline | ||
alias Radiator.Outline.Node | ||
|
||
@impl true | ||
def mount(_params, _session, socket) do | ||
node = %Node{} | ||
changeset = Outline.change_node(node) | ||
|
||
socket | ||
|> assign(:page_title, "Outline") | ||
|> assign(:node, node) | ||
|> assign(:form, to_form(changeset)) | ||
|> stream_configure(:nodes, dom_id: &"node-#{&1.uuid}") | ||
|> stream(:nodes, Outline.list_nodes()) | ||
|> reply(:ok) | ||
end | ||
|
||
@impl true | ||
def handle_event("update", %{"node" => _params}, socket) do | ||
socket | ||
|> reply(:noreply) | ||
end | ||
|
||
@impl true | ||
def handle_event("next", %{"node" => params}, socket) do | ||
{:ok, node} = Outline.create_node(params) | ||
|
||
socket | ||
|> stream_insert(:nodes, node, at: 0) | ||
|> reply(:noreply) | ||
end | ||
|
||
@impl true | ||
def handle_event("delete", %{"uuid" => uuid}, socket) do | ||
node = Outline.get_node!(uuid) | ||
{:ok, _} = Outline.delete_node(node) | ||
|
||
{:noreply, stream_delete(socket, :nodes, node)} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,25 @@ | ||
<section> | ||
<h1>Outline</h1> | ||
|
||
<h2>Inbox</h2> | ||
|
||
<.focus_wrap id="input-form-wrap"> | ||
<.form id="inbox-form" for={@form} phx-change="update" phx-submit="next"> | ||
<.input type="text" field={@form[:content]} /> | ||
<.input type="hidden" field={@form[:uuid]} /> | ||
</.form> | ||
</.focus_wrap> | ||
|
||
<ul id="inbox" class="mt-8 list-disc list-inside" phx-update="stream"> | ||
<li :for={{dom_id, node} <- @streams.nodes} id={dom_id}> | ||
<%= node.content %> | ||
<.link | ||
phx-click={JS.push("delete", value: %{uuid: node.uuid}) |> hide("##{dom_id}")} | ||
data-confirm="Delete?" | ||
> | ||
<.icon name="hero-x-circle" class="w-5 h-5" /> | ||
<div class="sr-only">Delete</div> | ||
</.link> | ||
</li> | ||
</ul> | ||
</section> |
12 changes: 12 additions & 0 deletions
12
priv/repo/migrations/20231120103619_create_outline_nodes.exs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
defmodule Radiator.Repo.Migrations.CreateOutlineNodes do | ||
use Ecto.Migration | ||
|
||
def change do | ||
create table(:outline_nodes, primary_key: false) do | ||
add :uuid, :uuid, primary_key: true | ||
add :content, :text | ||
|
||
timestamps(type: :utc_datetime) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
defmodule Radiator.OutlineTest do | ||
use Radiator.DataCase | ||
|
||
alias Radiator.Outline | ||
|
||
describe "outline_nodes" do | ||
alias Radiator.Outline.Node | ||
|
||
import Radiator.OutlineFixtures | ||
|
||
@invalid_attrs %{content: nil} | ||
|
||
test "list_nodes/0 returns all nodes" do | ||
node = node_fixture() | ||
assert Outline.list_nodes() == [node] | ||
end | ||
|
||
test "get_node!/1 returns the node with given id" do | ||
node = node_fixture() | ||
assert Outline.get_node!(node.uuid) == node | ||
end | ||
|
||
test "create_node/1 with valid data creates a node" do | ||
valid_attrs = %{content: "some content"} | ||
|
||
assert {:ok, %Node{} = node} = Outline.create_node(valid_attrs) | ||
assert node.content == "some content" | ||
end | ||
|
||
test "create_node/1 with invalid data returns error changeset" do | ||
assert {:error, %Ecto.Changeset{}} = Outline.create_node(@invalid_attrs) | ||
end | ||
|
||
test "update_node/2 with valid data updates the node" do | ||
node = node_fixture() | ||
update_attrs = %{content: "some updated content"} | ||
|
||
assert {:ok, %Node{} = node} = Outline.update_node(node, update_attrs) | ||
assert node.content == "some updated content" | ||
end | ||
|
||
test "update_node/2 with invalid data returns error changeset" do | ||
node = node_fixture() | ||
assert {:error, %Ecto.Changeset{}} = Outline.update_node(node, @invalid_attrs) | ||
assert node == Outline.get_node!(node.uuid) | ||
end | ||
|
||
test "delete_node/1 deletes the node" do | ||
node = node_fixture() | ||
assert {:ok, %Node{}} = Outline.delete_node(node) | ||
assert_raise Ecto.NoResultsError, fn -> Outline.get_node!(node.uuid) end | ||
end | ||
|
||
test "change_node/1 returns a node changeset" do | ||
node = node_fixture() | ||
assert %Ecto.Changeset{} = Outline.change_node(node) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
defmodule Radiator.OutlineFixtures do | ||
@moduledoc """ | ||
This module defines test helpers for creating | ||
entities via the `Radiator.Outline` context. | ||
""" | ||
|
||
@doc """ | ||
Generate a node. | ||
""" | ||
def node_fixture(attrs \\ %{}) do | ||
{:ok, node} = | ||
attrs | ||
|> Enum.into(%{content: "some content"}) | ||
|> Radiator.Outline.create_node() | ||
|
||
node | ||
end | ||
end |