Threads of comments on the places of a room's components: a range of a text, a node of a canvas, a cell of a grid, or the page as a whole. People and agents start them, reply, edit and delete their own, react, mention each other, resolve and reopen them.
A room's threads are a document of the room, "board:42/issho.comments"
(document/1), with Issho's own engine (Issho.Engine.Comments): it is
Issho's, whatever your policy's document/2 says of that id, kept in
the instance's store, shared and live as any document is. Your policy
says who may comment: a change to it asks for :comment, not :write,
so a reader with a can: :read grant may comment when your policy
allows it (Issho.Policy).
From your server
ada = %{id: "user:ada", name: "Ada"}
place = %{"doc" => "board:42", "at" => %{"node" => "n7"}}
{:ok, %{thread: thread}} =
Issho.Comments.start(MyApp.Issho, "board:42", ada, place, "Should this go first?",
mentions: ["agent:claude"])
{:ok, _} = Issho.Comments.reply(MyApp.Issho, "board:42", claude, thread, "Yes: it blocks the rest.")
{:ok, _} = Issho.Comments.resolve(MyApp.Issho, "board:42", ada, thread)
{:ok, threads} = Issho.Comments.threads(MyApp.Issho, "board:42")An actor is an Issho.Actor, or an Issho.Identity (an agent and whom it
acts for). From a LiveView, an agent's participant or a browser, the
same changes are operations of the comments document (Issho.Comments.Ops),
committed under the policy as any change.
Who wrote it, and when
Each comment names its author and its time. Before a change is accepted, Issho holds them to the writer: the author is the signed identity of whoever made the change (its key, name, kind, avatar, colour and whom it acts for), and the time is within a few minutes of the server's clock, so a browser cannot write as someone else, or in the past. A thread's place is in the room.
Events
After each change is saved, the room has its events (Issho.Events):
"thread.created":%{thread: id, comment: id, place: place, body: text, mentions: [key]};"comment.created": every new comment, the first of a thread too,%{thread: id, comment: id, place: place, body: text, mentions: [key], reply: boolean};"comment.edited"(body,mentions) and"comment.deleted";"thread.resolved"and"thread.reopened":%{thread: id, place: place}.
An agent mentioned in a comment hears it (wait_for_events with
mentions_me), and answers in the thread (the comment tool).
Summary
Functions
Deletes one's own comment; a thread with none left goes.
The comments document of a room.
Whether a document is a room's comments.
Edits one's own comment. Options: :mentions, whom the comment
mentions after the edit (none unless given).
Adds the actor's reaction (an emoji) to a comment.
Reopens a resolved thread.
Replies in a thread. Options: :mentions. Gives {:ok, %{thread: id, comment: id}}.
Resolves a thread.
Starts a thread at a place (nil for the page as a whole), with its
first comment. Options: :mentions, the keys of the actors it mentions.
Gives {:ok, %{thread: id, comment: id}}.
The threads of a room, in the order they began.
Takes the actor's reaction back.
Functions
@spec delete( atom(), String.t(), Issho.Actor.t() | Issho.Identity.t(), String.t(), String.t() ) :: {:ok, map()} | {:error, term()}
Deletes one's own comment; a thread with none left goes.
The comments document of a room.
iex> Issho.Comments.document("board:42")
"board:42/issho.comments"
Whether a document is a room's comments.
iex> Issho.Comments.document?("board:42/issho.comments")
true
iex> Issho.Comments.document?("board:42/n7/issho.comments")
false
@spec edit( atom(), String.t(), Issho.Actor.t() | Issho.Identity.t(), String.t(), String.t(), String.t(), keyword() ) :: {:ok, map()} | {:error, term()}
Edits one's own comment. Options: :mentions, whom the comment
mentions after the edit (none unless given).
@spec react( atom(), String.t(), Issho.Actor.t() | Issho.Identity.t(), String.t(), String.t(), String.t() ) :: {:ok, map()} | {:error, term()}
Adds the actor's reaction (an emoji) to a comment.
@spec reopen(atom(), String.t(), Issho.Actor.t() | Issho.Identity.t(), String.t()) :: {:ok, map()} | {:error, term()}
Reopens a resolved thread.
@spec reply( atom(), String.t(), Issho.Actor.t() | Issho.Identity.t(), String.t(), String.t(), keyword() ) :: {:ok, %{thread: String.t(), comment: String.t()}} | {:error, term()}
Replies in a thread. Options: :mentions. Gives {:ok, %{thread: id, comment: id}}.
@spec resolve(atom(), String.t(), Issho.Actor.t() | Issho.Identity.t(), String.t()) :: {:ok, map()} | {:error, term()}
Resolves a thread.
@spec start( atom(), String.t(), Issho.Actor.t() | Issho.Identity.t(), map() | nil, String.t(), keyword() ) :: {:ok, %{thread: String.t(), comment: String.t()}} | {:error, term()}
Starts a thread at a place (nil for the page as a whole), with its
first comment. Options: :mentions, the keys of the actors it mentions.
Gives {:ok, %{thread: id, comment: id}}.
The threads of a room, in the order they began.
@spec unreact( atom(), String.t(), Issho.Actor.t() | Issho.Identity.t(), String.t(), String.t(), String.t() ) :: {:ok, map()} | {:error, term()}
Takes the actor's reaction back.