cob: Move comment reactions to comment
To simplify the code, we move comment reactions to the comment struct itself.
This commit is contained in:
parent
8b010c27a2
commit
e4ab523669
|
|
@ -11,7 +11,7 @@ use radicle::cob::patch::Merge;
|
||||||
use radicle::cob::patch::Review;
|
use radicle::cob::patch::Review;
|
||||||
use radicle::cob::patch::{Patch, PatchId};
|
use radicle::cob::patch::{Patch, PatchId};
|
||||||
use radicle::cob::thread;
|
use radicle::cob::thread;
|
||||||
use radicle::cob::thread::{CommentId, Thread};
|
use radicle::cob::thread::CommentId;
|
||||||
use radicle::cob::{ActorId, Author, Reaction, Timestamp};
|
use radicle::cob::{ActorId, Author, Reaction, Timestamp};
|
||||||
use radicle::git::RefString;
|
use radicle::git::RefString;
|
||||||
use radicle::node::AliasStore;
|
use radicle::node::AliasStore;
|
||||||
|
|
@ -105,7 +105,7 @@ pub(crate) fn issue(id: IssueId, issue: Issue, aliases: &impl AliasStore) -> Val
|
||||||
"assignees": issue.assigned().collect::<Vec<_>>(),
|
"assignees": issue.assigned().collect::<Vec<_>>(),
|
||||||
"discussion": issue
|
"discussion": issue
|
||||||
.comments()
|
.comments()
|
||||||
.map(|(id, comment)| Comment::new(id, comment, issue.thread(), aliases))
|
.map(|(id, comment)| Comment::new(id, comment, aliases))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
"tags": issue.tags().collect::<Vec<_>>(),
|
"tags": issue.tags().collect::<Vec<_>>(),
|
||||||
})
|
})
|
||||||
|
|
@ -136,7 +136,7 @@ pub(crate) fn patch(
|
||||||
"oid": rev.head(),
|
"oid": rev.head(),
|
||||||
"refs": get_refs(repo, patch.author().id(), &rev.head()).unwrap_or(vec![]),
|
"refs": get_refs(repo, patch.author().id(), &rev.head()).unwrap_or(vec![]),
|
||||||
"discussions": rev.discussion().comments()
|
"discussions": rev.discussion().comments()
|
||||||
.map(|(id, comment)| Comment::new(id, comment, rev.discussion(), aliases))
|
.map(|(id, comment)| Comment::new(id, comment, aliases))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
"timestamp": rev.timestamp(),
|
"timestamp": rev.timestamp(),
|
||||||
"reviews": rev.reviews().map(|(nid, _review)| review(nid, aliases.alias(nid), _review)).collect::<Vec<_>>(),
|
"reviews": rev.reviews().map(|(nid, _review)| review(nid, aliases.alias(nid), _review)).collect::<Vec<_>>(),
|
||||||
|
|
@ -245,18 +245,13 @@ struct Comment<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Comment<'a> {
|
impl<'a> Comment<'a> {
|
||||||
fn new(
|
fn new(id: &'a CommentId, comment: &'a thread::Comment, aliases: &impl AliasStore) -> Self {
|
||||||
id: &'a CommentId,
|
|
||||||
comment: &'a thread::Comment,
|
|
||||||
thread: &'a Thread,
|
|
||||||
aliases: &impl AliasStore,
|
|
||||||
) -> Self {
|
|
||||||
let comment_author = Author::new(comment.author());
|
let comment_author = Author::new(comment.author());
|
||||||
Self {
|
Self {
|
||||||
id: *id,
|
id: *id,
|
||||||
author: author(&comment_author, aliases.alias(comment_author.id())),
|
author: author(&comment_author, aliases.alias(comment_author.id())),
|
||||||
body: comment.body(),
|
body: comment.body(),
|
||||||
reactions: thread.reactions(id).collect::<Vec<_>>(),
|
reactions: comment.reactions().collect::<Vec<_>>(),
|
||||||
timestamp: comment.timestamp(),
|
timestamp: comment.timestamp(),
|
||||||
reply_to: comment.reply_to(),
|
reply_to: comment.reply_to(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -836,7 +836,7 @@ mod test {
|
||||||
|
|
||||||
let id = issue.id;
|
let id = issue.id;
|
||||||
let issue = issues.get(&id).unwrap().unwrap();
|
let issue = issues.get(&id).unwrap().unwrap();
|
||||||
let (_, r) = issue.reactions(&comment).next().unwrap();
|
let (_, r) = issue.comment(&comment).unwrap().reactions().next().unwrap();
|
||||||
|
|
||||||
assert_eq!(r, &reaction);
|
assert_eq!(r, &reaction);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@ pub struct Comment {
|
||||||
author: ActorId,
|
author: ActorId,
|
||||||
/// The comment body.
|
/// The comment body.
|
||||||
edits: GMap<Lamport, Max<Edit>>,
|
edits: GMap<Lamport, Max<Edit>>,
|
||||||
|
/// Reactions to this comment.
|
||||||
|
reactions: LWWSet<(ActorId, Reaction)>,
|
||||||
/// Comment this is a reply to.
|
/// Comment this is a reply to.
|
||||||
/// Should always be set, except for the root comment.
|
/// Should always be set, except for the root comment.
|
||||||
reply_to: Option<CommentId>,
|
reply_to: Option<CommentId>,
|
||||||
|
|
@ -78,6 +80,7 @@ impl Comment {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
author,
|
author,
|
||||||
|
reactions: LWWSet::default(),
|
||||||
edits: GMap::singleton(Lamport::initial(), Max::from(edit)),
|
edits: GMap::singleton(Lamport::initial(), Max::from(edit)),
|
||||||
reply_to,
|
reply_to,
|
||||||
}
|
}
|
||||||
|
|
@ -124,6 +127,11 @@ impl Comment {
|
||||||
pub fn edit(&mut self, clock: Lamport, body: String, timestamp: Timestamp) {
|
pub fn edit(&mut self, clock: Lamport, body: String, timestamp: Timestamp) {
|
||||||
self.edits.insert(clock, Edit { body, timestamp }.into())
|
self.edits.insert(clock, Edit { body, timestamp }.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Comment reactions.
|
||||||
|
pub fn reactions(&self) -> impl Iterator<Item = (&ActorId, &Reaction)> {
|
||||||
|
self.reactions.iter().map(|(a, r)| (a, r))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for Comment {
|
impl PartialOrd for Comment {
|
||||||
|
|
@ -175,16 +183,13 @@ impl From<Action> for nonempty::NonEmpty<Action> {
|
||||||
pub struct Thread {
|
pub struct Thread {
|
||||||
/// The comments under the thread.
|
/// The comments under the thread.
|
||||||
comments: GMap<CommentId, Redactable<Comment>>,
|
comments: GMap<CommentId, Redactable<Comment>>,
|
||||||
/// Reactions to changes.
|
|
||||||
reactions: GMap<CommentId, LWWSet<(ActorId, Reaction), Lamport>>,
|
|
||||||
/// Comment timeline.
|
/// Comment timeline.
|
||||||
timeline: GSet<(Lamport, EntryId)>,
|
timeline: GSet<(Lamport, CommentId)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Semilattice for Thread {
|
impl Semilattice for Thread {
|
||||||
fn merge(&mut self, other: Self) {
|
fn merge(&mut self, other: Self) {
|
||||||
self.comments.merge(other.comments);
|
self.comments.merge(other.comments);
|
||||||
self.reactions.merge(other.reactions);
|
|
||||||
self.timeline.merge(other.timeline);
|
self.timeline.merge(other.timeline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -193,7 +198,6 @@ impl Thread {
|
||||||
pub fn new(id: CommentId, comment: Comment) -> Self {
|
pub fn new(id: CommentId, comment: Comment) -> Self {
|
||||||
Self {
|
Self {
|
||||||
comments: GMap::singleton(id, Redactable::Present(comment)),
|
comments: GMap::singleton(id, Redactable::Present(comment)),
|
||||||
reactions: GMap::default(),
|
|
||||||
timeline: GSet::default(),
|
timeline: GSet::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -244,17 +248,6 @@ impl Thread {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reactions<'a>(
|
|
||||||
&'a self,
|
|
||||||
to: &'a CommentId,
|
|
||||||
) -> impl Iterator<Item = (&ActorId, &Reaction)> {
|
|
||||||
self.reactions
|
|
||||||
.get(to)
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(move |rs| rs.iter())
|
|
||||||
.map(|(a, r)| (a, r))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn comments(&self) -> impl DoubleEndedIterator<Item = (&CommentId, &Comment)> + '_ {
|
pub fn comments(&self) -> impl DoubleEndedIterator<Item = (&CommentId, &Comment)> + '_ {
|
||||||
self.timeline.iter().filter_map(|(_, id)| {
|
self.timeline.iter().filter_map(|(_, id)| {
|
||||||
self.comments
|
self.comments
|
||||||
|
|
@ -335,14 +328,17 @@ impl cob::store::FromHistory for Thread {
|
||||||
active,
|
active,
|
||||||
} => {
|
} => {
|
||||||
let key = (op.author, reaction);
|
let key = (op.author, reaction);
|
||||||
let reactions = if active {
|
if let Some(redactable) = self.comments.get_mut(&to) {
|
||||||
LWWSet::singleton(key, op.clock)
|
if let Redactable::Present(comment) = redactable {
|
||||||
|
if active {
|
||||||
|
comment.reactions.insert(key, op.clock);
|
||||||
|
} else {
|
||||||
|
comment.reactions.remove(key, op.clock);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut set = LWWSet::default();
|
return Err(Error::Missing(id));
|
||||||
set.remove(key, op.clock);
|
}
|
||||||
set
|
|
||||||
};
|
|
||||||
self.reactions.insert(to, reactions);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue