diff --git a/src/gh_comments.rs b/src/gh_comments.rs index dc58aabd..f6320faf 100644 --- a/src/gh_comments.rs +++ b/src/gh_comments.rs @@ -17,8 +17,8 @@ use hyper::{ use crate::{ cache, github::{ - GitHubGraphQlComment, GitHubGraphQlReviewThreadComment, GitHubIssueState, - GitHubIssueWithComments, GitHubReviewState, + GitHubGraphQlComment, GitHubGraphQlReactionGroup, GitHubGraphQlReviewThreadComment, + GitHubIssueState, GitHubIssueWithComments, GitHubReviewState, }, }; use crate::{ @@ -28,7 +28,7 @@ use crate::{ utils::{immutable_headers, is_repo_autorized}, }; -pub const STYLE_URL: &str = "/gh-comments/style@0.0.2.css"; +pub const STYLE_URL: &str = "/gh-comments/style@0.0.3.css"; pub const MARKDOWN_URL: &str = "/gh-comments/github-markdown@20260117.css"; pub const GH_COMMENTS_CACHE_CAPACITY_BYTES: usize = 35 * 1024 * 1024; // 35 Mb @@ -228,6 +228,7 @@ pub async fn gh_comments( &issue_with_comments.author, &issue_with_comments.created_at, &issue_with_comments.updated_at, + &issue_with_comments.reactions, false, None, )?; @@ -275,6 +276,7 @@ pub async fn gh_comments( &comment.author, &comment.created_at, &comment.updated_at, + &comment.reactions, comment.is_minimized, comment.minimized_reason.as_deref(), )?; @@ -290,6 +292,7 @@ pub async fn gh_comments( review.state, &review.submitted_at, &review.updated_at, + &review.reactions, review.is_minimized, review.minimized_reason.as_deref(), )?; @@ -322,6 +325,7 @@ pub async fn gh_comments( &comment.author, &comment.created_at, &comment.updated_at, + &comment.reactions, comment.is_minimized, comment.minimized_reason.as_deref(), )?; @@ -368,6 +372,7 @@ fn write_comment_as_html( author: &GitHubSimplifiedAuthor, created_at: &chrono::DateTime, updated_at: &chrono::DateTime, + reaction_groups: &[GitHubGraphQlReactionGroup], minimized: bool, minimized_reason: Option<&str>, ) -> anyhow::Result<()> { @@ -408,10 +413,10 @@ fn write_comment_as_html(
{body_html}
- - "### )?; + write_reaction_groups_as_html(buffer, reaction_groups)?; + writeln!(buffer, "")?; } else { let edited = if created_at != updated_at { " ยท edited" @@ -450,10 +455,10 @@ fn write_comment_as_html(
{body_html}
- - "### )?; + write_reaction_groups_as_html(buffer, reaction_groups)?; + writeln!(buffer, "")?; } Ok(()) @@ -467,6 +472,7 @@ fn write_review_as_html( state: GitHubReviewState, submitted_at: &chrono::DateTime, updated_at: &chrono::DateTime, + reaction_groups: &[GitHubGraphQlReactionGroup], minimized: bool, minimized_reason: Option<&str>, ) -> anyhow::Result<()> { @@ -538,10 +544,10 @@ fn write_review_as_html(
{body_html}
- - "### )?; + write_reaction_groups_as_html(buffer, reaction_groups)?; + writeln!(buffer, "")?; } else { let edited = if submitted_at != updated_at { " ยท edited" @@ -567,10 +573,10 @@ fn write_review_as_html(
{body_html}
- - "### )?; + write_reaction_groups_as_html(buffer, reaction_groups)?; + writeln!(buffer, "")?; } } @@ -616,6 +622,7 @@ fn write_review_thread_as_html( let created_at_rfc3339 = comment.created_at.to_rfc3339(); let body_html = &comment.body_html; let comment_url = &comment.url; + let reaction_groups = &*comment.reactions; let id = extract_id_from_github_link(comment_url); let edited = if comment.created_at != comment.updated_at { @@ -642,9 +649,10 @@ fn write_review_thread_as_html(
{body_html}
- "### )?; + write_reaction_groups_as_html(buffer, reaction_groups)?; + writeln!(buffer, "")?; } writeln!( @@ -658,6 +666,46 @@ fn write_review_thread_as_html( Ok(()) } +fn write_reaction_groups_as_html( + buffer: &mut String, + reaction_groups: &[GitHubGraphQlReactionGroup], +) -> anyhow::Result<()> { + let any_reactions = reaction_groups.iter().any(|rg| rg.users.total_count > 0); + + if any_reactions { + writeln!(buffer, r##"
"##)?; + + for reaction_group in reaction_groups { + let total_count = reaction_group.users.total_count; + + if total_count == 0 { + continue; + } + + use crate::github::GitHubGraphQlReactionContent::*; + let emoji = match reaction_group.content { + ThumbsUp => "๐Ÿ‘", + ThumbsDown => "๐Ÿ‘Ž", + Laugh => "๐Ÿ˜„", + Hooray => "๐ŸŽ‰", + Confused => "๐Ÿ˜•", + Heart => "โค๏ธ", + Rocket => "๐Ÿš€", + Eyes => "๐Ÿ‘€", + }; + + write!( + buffer, + r##"
{emoji}{total_count}
"## + )?; + } + + writeln!(buffer, r##"
"##)?; + } + + Ok(()) +} + fn extract_id_from_github_link(url: &str) -> &str { url.rfind('#').map(|pos| &url[pos + 1..]).unwrap_or("") } diff --git a/src/gh_comments/style.css b/src/gh_comments/style.css index b44d6d1f..68dc5130 100644 --- a/src/gh_comments/style.css +++ b/src/gh_comments/style.css @@ -1,3 +1,11 @@ +/* SPDX-License-Identifier: MIT */ + +/* + * Style for the /gh-comments endpoints in Triagebot. + * + * Be sure to update the version number in src/gh_comments.rs to reset the cache. + */ + /* === Theme variables === */ :root { --bg-default: #ffffff; @@ -210,6 +218,31 @@ details:not([open]) > .review-thread-header { fill: currentColor; } +/* === Reactions === */ +.reactions { + display: flex; + gap: 10px; + flex-wrap: wrap; + margin-left: 16px; + margin-bottom: 16px; +} + +.review-thread-comment .reactions { + margin-left: 2rem; + margin-bottom: 0px; +} + +.reaction { + border-radius: 100px; + border: 0.00625rem solid var(--border-default); + padding: 5px 9px; + font-size: 13px; +} + +.reaction .reaction-number { + margin-left: 0.35rem; +} + /* === Tab links === */ .meta-links .selected { border-radius: 0.375rem; diff --git a/src/github.rs b/src/github.rs index 7a930e9f..041800b0 100644 --- a/src/github.rs +++ b/src/github.rs @@ -2958,6 +2958,12 @@ query ($owner: String!, $repo: String!, $issueNumber: Int!, $commentsCursor: Str login avatarUrl } + reactionGroups { + content + users { + totalCount + } + } comments(first: 100, after: $commentsCursor) { nodes { author { @@ -2970,6 +2976,12 @@ query ($owner: String!, $repo: String!, $issueNumber: Int!, $commentsCursor: Str minimizedReason bodyHTML url + reactionGroups { + content + users { + totalCount + } + } } pageInfo { hasNextPage @@ -2989,6 +3001,12 @@ query ($owner: String!, $repo: String!, $issueNumber: Int!, $commentsCursor: Str login avatarUrl } + reactionGroups { + content + users { + totalCount + } + } comments(first: 100, after: $commentsCursor) { nodes { author { @@ -3001,6 +3019,12 @@ query ($owner: String!, $repo: String!, $issueNumber: Int!, $commentsCursor: Str minimizedReason bodyHTML url + reactionGroups { + content + users { + totalCount + } + } } pageInfo { hasNextPage @@ -3023,6 +3047,12 @@ query ($owner: String!, $repo: String!, $issueNumber: Int!, $commentsCursor: Str updatedAt bodyHTML url + reactionGroups { + content + users { + totalCount + } + } pullRequestReview { id } @@ -3048,6 +3078,12 @@ query ($owner: String!, $repo: String!, $issueNumber: Int!, $commentsCursor: Str minimizedReason bodyHTML url + reactionGroups { + content + users { + totalCount + } + } } pageInfo { hasNextPage @@ -3156,6 +3192,8 @@ pub struct GitHubIssueWithComments { pub created_at: chrono::DateTime, #[serde(rename = "updatedAt")] pub updated_at: chrono::DateTime, + #[serde(rename = "reactionGroups")] + pub reactions: Vec, pub comments: GitHubGraphQlComments, #[serde(rename = "reviewThreads")] pub review_threads: Option, @@ -3188,6 +3226,8 @@ pub struct GitHubGraphQlComment { #[serde(rename = "bodyHTML")] pub body_html: String, pub url: String, + #[serde(rename = "reactionGroups")] + pub reactions: Vec, } #[derive(Debug, serde::Deserialize, serde::Serialize)] @@ -3222,6 +3262,8 @@ pub struct GitHubGraphQlReviewThreadComment { #[serde(rename = "bodyHTML")] pub body_html: String, pub url: String, + #[serde(rename = "reactionGroups")] + pub reactions: Vec, #[serde(rename = "pullRequestReview")] pub pull_request_review: GitHubGraphQlPullRequestReview, } @@ -3252,6 +3294,33 @@ pub struct GitHubGraphQlReview { #[serde(rename = "minimizedReason")] pub minimized_reason: Option, pub url: String, + #[serde(rename = "reactionGroups")] + pub reactions: Vec, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct GitHubGraphQlReactionGroup { + pub content: GitHubGraphQlReactionContent, + pub users: GitHubGraphQlReactionGroupUsers, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize)] +pub struct GitHubGraphQlReactionGroupUsers { + #[serde(rename = "totalCount")] + pub total_count: u32, +} + +#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum GitHubGraphQlReactionContent { + ThumbsUp, + ThumbsDown, + Laugh, + Hooray, + Confused, + Heart, + Rocket, + Eyes, } #[derive(Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)]