diff --git a/lib/vyasa/sangh.ex b/lib/vyasa/sangh.ex
index e6df6301..67579a89 100644
--- a/lib/vyasa/sangh.ex
+++ b/lib/vyasa/sangh.ex
@@ -6,9 +6,12 @@ defmodule Vyasa.Sangh do
import Ecto.Query, warn: false
import EctoLtree.Functions, only: [nlevel: 1]
alias Vyasa.Repo
+ alias EctoLtree.LabelTree, as: Ltree
# alias Vyasa.Draft
alias Vyasa.Sangh.{Sheaf}
+ @max_sheaf_depth 3
+
@doc """
Returns a list of sheafs associated with a specific session.
@@ -403,11 +406,117 @@ defmodule Vyasa.Sangh do
# """
def update_sheaf(%Sheaf{} = sheaf, attrs) do
+ IO.puts("CHECKPOINT: update_sheaf")
+
sheaf
|> Sheaf.mutate_changeset(attrs)
|> Repo.update()
end
+ @doc """
+ Given a sheaf that is ready to be published as a reply, ensures that the
+ replies adhere to the 3-level nesting limit.
+
+ There are 3 ways that the reply to context is determined:
+ 1. if the attrs contain :parent, then use that sheaf. This is more of an override-case,
+ for example, in the context of quick replies
+ 2. if the attrs don't contain parent, but the draft sheaf already has an associated parent,
+ then that's the reply to context
+ 3. there are no parents associated -- so the reply's parent is nil and there's no :parent in the attrs
+
+ Suppose the reply to context is already at depth = 3 (zero-indexed, then level = 2) then we need to reconcile this.
+ To reconcile, we shall update the attrs payload such that:
+ 1. the parent of the reply sheaf ends up being the grandparent instead
+ 2. the reply sheaf's path gets updated, is now encoded as though its the child of its grandparent
+ """
+ # way number 1 -- using parent in attr
+ def make_reply(
+ %Sheaf{
+ id: id
+ } = reply,
+ %{
+ parent:
+ %Sheaf{
+ parent_id: grandparent_id,
+ path: %Ltree{
+ labels: parent_path_labels
+ }
+ } = _injected_parent
+ } = attrs
+ ) do
+ IO.puts("CHECKPOINT Make Reply way 1 -- use injected parent in attr")
+
+ reconciled_attrs =
+ case parent_path_labels |> Enum.count() do
+ # need to reassign both path and parent:
+ @max_sheaf_depth ->
+ attrs |> reconcile_payload_using_grandparent(grandparent_id, id)
+
+ # keep as is
+ _ ->
+ attrs
+ end
+
+ reply |> update_sheaf(reconciled_attrs)
+ end
+
+ # way number 2 -- if not in attr, then use pre-existing associated parent to the reply sheaf
+ def make_reply(
+ %Sheaf{
+ id: id,
+ parent: %Sheaf{
+ parent_id: grandparent_id,
+ path: %Ltree{
+ labels: parent_path_labels
+ }
+ }
+ } = reply,
+ attrs
+ ) do
+ IO.puts("CHECKPOINT Make Reply way 2 -- use pre-associated parent")
+
+ reconciled_attrs =
+ case parent_path_labels |> Enum.count() do
+ # need to reassign both path and parent:
+ @max_sheaf_depth ->
+ attrs |> reconcile_payload_using_grandparent(grandparent_id, id)
+
+ _ ->
+ attrs
+ end
+
+ reply |> update_sheaf(reconciled_attrs)
+ end
+
+ # way number 3 -- no assoced parent, nothing to reconcile
+ def make_reply(
+ %Sheaf{
+ parent: nil
+ } = reply,
+ attrs
+ ) do
+ IO.puts("CHECKPOINT Make Reply way 3 -- no parent to associate to")
+ reply |> update_sheaf(attrs)
+ end
+
+ # To reconcile, we shall update the attrs payload such that:
+ # 1. the parent of the reply sheaf ends up being the grandparent instead
+ # 2. the reply sheaf's path gets updated, is now encoded as though its the child of its grandparent
+ defp reconcile_payload_using_grandparent(%{} = attrs, grandparent_id, child_id)
+ when is_binary(grandparent_id) do
+ %Sheaf{path: %Ltree{} = grandparent_path} = grandparent = get_sheaf!(grandparent_id)
+
+ IO.puts(
+ "CHECKPOINT -- turns out we need to reconcile this sheaf and assoc to its grandparent instead"
+ )
+
+ attrs
+ |> Map.merge(%{
+ parent: grandparent,
+ path: child_id |> Sheaf.encode_path(grandparent_path)
+ })
+ end
+
# @doc """
# Updates a sheaf.
@@ -421,6 +530,8 @@ defmodule Vyasa.Sangh do
# """
def update_sheaf!(%Sheaf{} = sheaf, attrs) do
+ IO.puts("CHECKPOINT: update_sheaf!")
+
sheaf
|> Sheaf.mutate_changeset(attrs)
|> Repo.update!()
diff --git a/lib/vyasa/sangh/sheaf.ex b/lib/vyasa/sangh/sheaf.ex
index 759ce83b..a1f7a58a 100644
--- a/lib/vyasa/sangh/sheaf.ex
+++ b/lib/vyasa/sangh/sheaf.ex
@@ -67,13 +67,19 @@ defmodule Vyasa.Sangh.Sheaf do
end
def mutate_changeset(%Sheaf{} = sheaf, attrs) do
- sheaf
- |> Vyasa.Repo.preload([:marks])
- |> cast(attrs, [:id, :body, :active, :signature, :traits])
- |> cast_path(attrs)
- |> assoc_marks(attrs)
- |> Map.put(:repo_opts, on_conflict: {:replace_all_except, [:id]}, conflict_target: :id)
- |> validate_include_subset(:traits, ["personal", "draft", "published"])
+ IO.inspect(%{sheaf: sheaf, attrs: attrs}, label: "CHECKPOINT: mutate_changeset")
+
+ cs =
+ sheaf
+ |> Vyasa.Repo.preload([:marks])
+ |> cast(attrs, [:id, :body, :active, :signature, :traits, :updated_at, :inserted_at])
+ |> cast_path(attrs)
+ |> assoc_marks(attrs)
+ |> Map.put(:repo_opts, on_conflict: {:replace_all_except, [:id]}, conflict_target: :id)
+ |> validate_include_subset(:traits, ["personal", "draft", "published"])
+
+ IO.inspect(cs, label: "CHECKPOINT: mutate changeset outcome changeset:")
+ cs
end
defp assoc_marks(sheaf, %{marks: [%Mark{} | _] = marks}) do
@@ -87,17 +93,25 @@ defmodule Vyasa.Sangh.Sheaf do
end
defp cast_path(%{changes: %{id: sheaf_id}} = sheaf, %{
- parent: %Sheaf{id: p_sheaf_id, path: lpath}
+ parent: %Sheaf{id: p_sheaf_id, path: lpath} = parent
}) do
+ IO.inspect(parent, label: "SEE ME : cast_path, parent:")
+
sheaf
|> cast(%{parent_id: p_sheaf_id, path: encode_path(sheaf_id, lpath)}, [:parent_id, :path])
end
defp cast_path(%{changes: %{id: sheaf_id}} = sheaf, _) do
+ IO.inspect(sheaf, label: "SEE ME : cast_path, sheaf:")
+
sheaf
|> cast(%{path: encode_path(sheaf_id)}, [:path])
end
+ defp cast_path(%{data: %{id: sheaf_id}} = sheaf, %{parent: %Sheaf{id: p_sheaf_id, path: lpath}}) do
+ cast(sheaf, %{parent_id: p_sheaf_id, path: encode_path(sheaf_id, lpath)}, [:parent_id, :path])
+ end
+
defp cast_path(sheaf, _) do
sheaf
end
@@ -204,4 +218,18 @@ defmodule Vyasa.Sangh.Sheaf do
) do
labels
end
+
+ @doc """
+ For sorting sheafs, we should just default to only caring about their insertion time,
+ ignoring the update time.
+
+ TODO: update clauses once we are supporting other kinds of ordering
+ """
+ def sort_sheafs_chrono([%Sheaf{} | _] = sheafs) do
+ Enum.sort_by(sheafs, &elem(&1, 1).inserted_at, :desc)
+ end
+
+ def sort_sheaf_chrono(sheafs) do
+ sheafs
+ end
end
diff --git a/lib/vyasa/sangh/sheaf_lattice.ex b/lib/vyasa/sangh/sheaf_lattice.ex
index b5433d79..2eba336b 100644
--- a/lib/vyasa/sangh/sheaf_lattice.ex
+++ b/lib/vyasa/sangh/sheaf_lattice.ex
@@ -323,6 +323,8 @@ defmodule Vyasa.Sangh.SheafLattice do
sheaf_lattice
|> read_sheaf_lattice(level, match)
|> Enum.reject(fn %Sheaf{traits: traits} -> "draft" in traits end)
+ # TODO: to verify this, may not be correct
+ |> sort_sheaf_lattice_entries_chrono()
end
# fetches all sheafs in level 0:
@@ -449,4 +451,12 @@ defmodule Vyasa.Sangh.SheafLattice do
lattice |> update_sheaf_in_lattice(lattice_key, %Sheaf{old_sheaf | marks: updated_marks})
end
+
+ def sort_sheaf_lattice_entries_chrono([{label, %Sheaf{}} | _] = entries) when is_list(label) do
+ entries |> Enum.sort_by(fn {_, %Sheaf{} = sheaf} -> sheaf.inserted_at end, :desc)
+ end
+
+ def sort_sheaf_lattice_entries_chrono(entries) do
+ entries
+ end
end
diff --git a/lib/vyasa_web/components/contexts/components.ex b/lib/vyasa_web/components/contexts/components.ex
index 79ed0277..48a6d1cb 100644
--- a/lib/vyasa_web/components/contexts/components.ex
+++ b/lib/vyasa_web/components/contexts/components.ex
@@ -4,6 +4,7 @@ defmodule VyasaWeb.Context.Components do
"""
use VyasaWeb, :html
alias Vyasa.Sangh.{Sheaf}
+ alias VyasaWeb.CoreComponents
alias VyasaWeb.Context.Components.UiState.Mark, as: MarkUiState
alias VyasaWeb.Context.Components.UiState.Sheaf, as: SheafUiState
@@ -323,7 +324,7 @@ defmodule VyasaWeb.Context.Components do