Skip to content

Commit

Permalink
Merge pull request #563 from podlove/outdent-nodes
Browse files Browse the repository at this point in the history
Outdent nodes
  • Loading branch information
electronicbites authored Sep 12, 2024
2 parents 156a01b + ef755e0 commit 9099f3c
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 24 deletions.
79 changes: 66 additions & 13 deletions lib/radiator/outline.ex
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,22 @@ defmodule Radiator.Outline do
prev_id = attrs["prev_id"]
parent_id = attrs["parent_id"]
episode_id = attrs["episode_id"]

prev_node = NodeRepository.get_node_if(prev_id)
parent_node = find_parent_node(prev_node, parent_id)

# find Node which has been previously connected to prev_node
next_node =
Node
|> where(episode_id: ^episode_id)
|> where_prev_node_equals(prev_id)
|> where_parent_node_equals(parent_id)
|> where_parent_node_equals(get_node_id(parent_node))
|> Repo.one()

with prev_node <- NodeRepository.get_node_if(prev_id),
parent_node <- find_parent_node(prev_node, parent_id),
true <- parent_and_prev_consistent?(parent_node, prev_node),
with true <- parent_and_prev_consistent?(parent_node, prev_node),
true <- episode_valid?(episode_id, parent_node, prev_node),
{:ok, node} <- NodeRepository.create_node(set_parent_id_if(attrs, parent_node)),
{:ok, _node_to_move} <- move_node_if(next_node, parent_id, node.uuid) do
{:ok, _node_to_move} <- move_node_if(next_node, get_node_id(parent_node), node.uuid) do
%NodeRepoResult{node: node, next_id: get_node_id(next_node)}
else
false ->
Expand All @@ -117,16 +119,21 @@ defmodule Radiator.Outline do
do_indent_node(node, prev_node)
end
end)
|> case do
{:ok, {:error, error}} ->
{:error, error}
|> unwrap_transaction_result
end

{:ok, {:ok, node_result}} ->
{:ok, node_result}
def outdent_node(node_id) do
Repo.transaction(fn ->
case NodeRepository.get_node(node_id) do
nil ->
{:error, :not_found}

{:error, error} ->
{:error, error}
end
node ->
parent_node = get_parent_node(node)
do_outdent_node(node, parent_node)
end
end)
|> unwrap_transaction_result
end

@doc """
Expand Down Expand Up @@ -496,6 +503,40 @@ defmodule Radiator.Outline do
move_node(node.uuid, prev_id: new_previous_id, parent_id: prev_node.uuid)
end

defp do_outdent_node(_node, nil), do: {:error, :no_parent_node}

defp do_outdent_node(node, parent_node) do
new_children =
parent_node
|> order_child_nodes()
|> next_nodes(node)

last_of_old_children =
node
|> order_child_nodes()
|> List.last()

{:ok, main_move_result} =
move_node(node.uuid, prev_id: parent_node.uuid, parent_id: parent_node.parent_id)

# new children are the possible new child elements of the node
# if the node already had children the new children are appended to the list of existing children
_t =
Enum.reduce(new_children, get_node_id(last_of_old_children), fn n, prev_id ->
move_node_if(n, node.uuid, prev_id)
n.uuid
end)

{:ok, Map.put(main_move_result, :children, new_children)}
end

# given a list of nodes in one level, return all the nodes that are after a give
defp next_nodes([], _node), do: []
defp next_nodes([%{prev_id: uuid} | _tail] = children, %{uuid: uuid}), do: children

defp next_nodes([_head | tail_children], node),
do: next_nodes(tail_children, node)

defp parent_and_prev_consistent?(_, nil), do: true
defp parent_and_prev_consistent?(nil, _), do: true

Expand All @@ -522,6 +563,18 @@ defmodule Radiator.Outline do
end
end

defp unwrap_transaction_result({:ok, {:error, error}}) do
{:error, error}
end

defp unwrap_transaction_result({:ok, {:ok, node_result}}) do
{:ok, node_result}
end

defp unwrap_transaction_result({:error, error}) do
{:error, error}
end

defp binaray_uuid_to_ecto_uuid(nil), do: nil

defp binaray_uuid_to_ecto_uuid(uuid) do
Expand Down
11 changes: 10 additions & 1 deletion lib/radiator/outline/command.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ defmodule Radiator.Outline.Command do
DeleteNodeCommand,
IndentNodeCommand,
InsertNodeCommand,
MoveNodeCommand
MoveNodeCommand,
OutdentNodeCommand
}

def build("insert_node", payload, user_id, event_id) do
Expand All @@ -33,6 +34,14 @@ defmodule Radiator.Outline.Command do
}
end

def build("outdent_node", node_id, user_id, event_id) do
%OutdentNodeCommand{
event_id: event_id,
user_id: user_id,
node_id: node_id
}
end

def build("change_node_content", node_id, content, user_id, event_id) do
%ChangeNodeContentCommand{
event_id: event_id,
Expand Down
12 changes: 12 additions & 0 deletions lib/radiator/outline/command/outdent_node_command.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule Radiator.Outline.Command.OutdentNodeCommand do
@moduledoc """
Command to indent a node.
"""
@type t() :: %__MODULE__{
event_id: binary(),
user_id: binary(),
node_id: binary()
}

defstruct [:event_id, :user_id, :node_id]
end
34 changes: 32 additions & 2 deletions lib/radiator/outline/command_processor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ defmodule Radiator.Outline.CommandProcessor do
DeleteNodeCommand,
IndentNodeCommand,
InsertNodeCommand,
MoveNodeCommand
MoveNodeCommand,
OutdentNodeCommand
}

alias Radiator.Outline.Dispatch
Expand Down Expand Up @@ -75,6 +76,12 @@ defmodule Radiator.Outline.CommandProcessor do
|> handle_move_node_result(command)
end

defp process_command(%OutdentNodeCommand{node_id: node_id} = command) do
node_id
|> Outline.outdent_node()
|> handle_move_node_result(command)
end

defp process_command(%DeleteNodeCommand{node_id: node_id} = command) do
case NodeRepository.get_node(node_id) do
nil ->
Expand Down Expand Up @@ -130,7 +137,8 @@ defmodule Radiator.Outline.CommandProcessor do
user_id: command.user_id,
uuid: command.event_id,
next_id: result.next_id,
episode_id: node.episode_id
episode_id: node.episode_id,
children: result.children
}
|> EventStore.persist_event()
|> Dispatch.broadcast()
Expand All @@ -142,6 +150,28 @@ defmodule Radiator.Outline.CommandProcessor do
{:ok, %NodeRepoResult{node: node} = result},
%IndentNodeCommand{} = command
) do
%NodeMovedEvent{
node_id: node.uuid,
parent_id: result.node.parent_id,
prev_id: result.node.prev_id,
old_prev_id: result.old_prev_id,
old_next_id: result.old_next_id,
user_id: command.user_id,
uuid: command.event_id,
next_id: result.next_id,
episode_id: node.episode_id,
children: result.children
}
|> EventStore.persist_event()
|> Dispatch.broadcast()

{:ok, node}
end

def handle_move_node_result(
{:ok, %NodeRepoResult{node: node} = result},
%OutdentNodeCommand{} = command
) do
%NodeMovedEvent{
node_id: node.uuid,
parent_id: result.node.parent_id,
Expand Down
6 changes: 6 additions & 0 deletions lib/radiator/outline/dispatch.ex
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ defmodule Radiator.Outline.Dispatch do
|> EventProducer.enqueue()
end

def outdent_node(node_id, user_id, event_id) do
"outdent_node"
|> Command.build(node_id, user_id, event_id)
|> EventProducer.enqueue()
end

def move_node(node_id, user_id, event_id,
parent_id: parent_id,
prev_id: prev_id
Expand Down
3 changes: 2 additions & 1 deletion lib/radiator/outline/event/node_moved_event.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ defmodule Radiator.Outline.Event.NodeMovedEvent do
:old_prev_id,
:old_next_id,
:next_id,
:episode_id
:episode_id,
:children
]
end
9 changes: 2 additions & 7 deletions lib/radiator_web/live/outline_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -240,14 +240,9 @@ defmodule RadiatorWeb.OutlineComponent do
socket
end

defp outdent(socket, uuid, parent_id) do
defp outdent(socket, uuid, _parent_id) do
user_id = socket.assigns.user_id

Dispatch.move_node(uuid, user_id, generate_event_id(socket.id),
parent_id: nil,
prev_id: parent_id
)

Dispatch.outdent_node(uuid, user_id, generate_event_id(socket.id))
socket
end
end
Loading

0 comments on commit 9099f3c

Please sign in to comment.