diff --git a/radicle-cli/src/terminal/comment.rs b/radicle-cli/src/terminal/comment.rs index 78bb707c..1383b9bc 100644 --- a/radicle-cli/src/terminal/comment.rs +++ b/radicle-cli/src/terminal/comment.rs @@ -5,9 +5,9 @@ use crate::terminal as term; use crate::terminal::format::Author; /// Return a comment header as a [`term::Element`]. -pub fn header( +pub fn header( id: &CommentId, - comment: &Comment, + comment: &Comment, profile: &Profile, ) -> term::hstack::HStack<'static> { let author = comment.author(); @@ -27,7 +27,7 @@ pub fn header( } /// Return a full comment widget as a [`term::Element`]. -pub fn widget<'a>(id: &CommentId, comment: &Comment, profile: &Profile) -> term::VStack<'a> { +pub fn widget<'a, T>(id: &CommentId, comment: &Comment, profile: &Profile) -> term::VStack<'a> { term::vstack::bordered(header(id, comment, profile)) .child(term::textarea(comment.body()).wrap(60)) } diff --git a/radicle-httpd/src/api/json.rs b/radicle-httpd/src/api/json.rs index 11b28fe5..0e829dae 100644 --- a/radicle-httpd/src/api/json.rs +++ b/radicle-httpd/src/api/json.rs @@ -103,7 +103,7 @@ pub(crate) fn issue(id: IssueId, issue: Issue, aliases: &impl AliasStore) -> Val "title": issue.title(), "state": issue.state(), "assignees": issue.assignees().collect::>(), - "discussion": issue.comments().map(|(id, c)| comment(id, c, aliases)).collect::>(), + "discussion": issue.comments().map(|(id, c)| issue_comment(id, c, aliases)).collect::>(), "labels": issue.labels().collect::>(), }) } @@ -132,7 +132,7 @@ pub(crate) fn patch( "base": rev.base(), "oid": rev.head(), "refs": get_refs(repo, patch.author().id(), &rev.head()).unwrap_or_default(), - "discussions": rev.discussion().comments().map(|(id, c)| comment(id, c, aliases)).collect::>(), + "discussions": rev.discussion().comments().map(|(id, c)| patch_comment(id, c, aliases)).collect::>(), "timestamp": rev.timestamp().as_secs(), "reviews": rev.reviews().map(|(nid, r)| review(nid, r, aliases)).collect::>(), }) @@ -172,8 +172,8 @@ fn review(nid: &NodeId, review: &Review, aliases: &impl AliasStore) -> Value { }) } -/// Returns JSON for a `Comment`. -fn comment(id: &CommentId, comment: &Comment, aliases: &impl AliasStore) -> Value { +/// Returns JSON for a Issue `Comment`. +fn issue_comment(id: &CommentId, comment: &Comment, aliases: &impl AliasStore) -> Value { json!({ "id": *id, "author": author(&Author::from(comment.author()), aliases.alias(&comment.author())), @@ -194,6 +194,33 @@ fn comment(id: &CommentId, comment: &Comment, aliases: &impl AliasStore) -> Valu }) } +/// Returns JSON for a Patch `Comment`. +fn patch_comment( + id: &CommentId, + comment: &Comment, + aliases: &impl AliasStore, +) -> Value { + json!({ + "id": *id, + "author": author(&Author::from(comment.author()), aliases.alias(&comment.author())), + "body": comment.body(), + "edits": comment.edits().map(|edit| { + json!({ + "author": author(&Author::from(edit.author), aliases.alias(&edit.author)), + "body": edit.body, + "timestamp": edit.timestamp.as_secs(), + "embeds": edit.embeds, + }) + }).collect::>(), + "embeds": comment.embeds().to_vec(), + "reactions": comment.reactions().collect::>(), + "timestamp": comment.timestamp().as_secs(), + "replyTo": comment.reply_to(), + "location": comment.location(), + "resolved": comment.resolved(), + }) +} + /// Returns JSON for a `Review`. fn review_comment( id: &CommentId, diff --git a/radicle-httpd/src/api/v1/projects.rs b/radicle-httpd/src/api/v1/projects.rs index d8f411cb..79ac4025 100644 --- a/radicle-httpd/src/api/v1/projects.rs +++ b/radicle-httpd/src/api/v1/projects.rs @@ -3041,6 +3041,7 @@ mod routes { "reactions": [["z6Mkk7oqY4pPxhMmGEotDYsFo97vhCj85BLY1H256HrJmjN8","🚀"]], "timestamp": TIMESTAMP, "replyTo": null, + "location": null, "resolved": false, }, { @@ -3063,6 +3064,7 @@ mod routes { "reactions": [], "timestamp": TIMESTAMP, "replyTo": comment_id, + "location": null, "resolved": false, }, ], diff --git a/radicle/src/cob/patch.rs b/radicle/src/cob/patch.rs index e6ec5a83..4e196ea9 100644 --- a/radicle/src/cob/patch.rs +++ b/radicle/src/cob/patch.rs @@ -1012,7 +1012,7 @@ impl Patch { body, reply_to, embeds, - .. + location, } => { if let Some(revision) = lookup::revision_mut(self, &revision)? { thread::comment( @@ -1022,7 +1022,7 @@ impl Patch { timestamp, body, reply_to, - None, + location, embeds, )?; } @@ -1255,7 +1255,7 @@ pub struct Revision { /// Reference to the Git object containing the code (revision head). pub(super) oid: git::Oid, /// Discussion around this revision. - pub(super) discussion: Thread, + pub(super) discussion: Thread>, /// Reviews of this revision's changes (one per actor). pub(super) reviews: BTreeMap>, /// When this revision was created. @@ -1313,7 +1313,7 @@ impl Revision { } /// Discussion around this revision. - pub fn discussion(&self) -> &Thread { + pub fn discussion(&self) -> &Thread> { &self.discussion } diff --git a/radicle/src/cob/thread.rs b/radicle/src/cob/thread.rs index 337d604c..f67eb24a 100644 --- a/radicle/src/cob/thread.rs +++ b/radicle/src/cob/thread.rs @@ -1,5 +1,6 @@ use std::cmp::Ordering; use std::collections::{BTreeMap, BTreeSet}; +use std::convert::Infallible; use std::str::FromStr; use once_cell::sync::Lazy; @@ -67,7 +68,7 @@ pub struct Edit { /// A comment on a discussion thread. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Comment { +pub struct Comment { /// Comment author. author: ActorId, /// The comment body. @@ -265,7 +266,7 @@ impl From for nonempty::NonEmpty { /// A discussion thread. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Thread> { +pub struct Thread { /// The comments under the thread. pub(crate) comments: BTreeMap>, /// Comment timeline.