Merge "Report number of checks results with fix"
diff --git a/Documentation/note-db.txt b/Documentation/note-db.txt
index 0e1dfd0..29c794c 100644
--- a/Documentation/note-db.txt
+++ b/Documentation/note-db.txt
@@ -54,7 +54,7 @@
 The metadata is a notes branch. The commit messages on the branch hold
 modifications to global data of the change (votes, global comments). The inline
 comments are in a
-link:https://git.eclipse.org/r/plugins/gitiles/jgit/jgit/\+/master/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java[NoteMap],
+link:https://eclipse.gerrithub.io/plugins/gitiles/eclipse-jgit/jgit/\+/refs/heads/master/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteMap.java[NoteMap],
 where the key is the commit SHA-1 of the patchset
 that the comment refers to, and the value is JSON data. The format of the
 JSON is in the
diff --git a/polygerrit-ui/app/constants/reporting.ts b/polygerrit-ui/app/constants/reporting.ts
index 17ec6f5..abcc3ed 100644
--- a/polygerrit-ui/app/constants/reporting.ts
+++ b/polygerrit-ui/app/constants/reporting.ts
@@ -131,6 +131,7 @@
   CHECKS_RUNS_PANEL_TOGGLE = 'checks-runs-panel-toggle',
   CHECKS_RUNS_SELECTED_TRIGGERED = 'checks-runs-selected-triggered',
   CHECKS_STATS = 'checks-stats',
+  COMMENTS_STATS = 'comments-stats',
   CHANGE_ACTION_FIRED = 'change-action-fired',
   BUTTON_CLICK = 'button-click',
   LINK_CLICK = 'link-click',
diff --git a/polygerrit-ui/app/models/comments/comments-model.ts b/polygerrit-ui/app/models/comments/comments-model.ts
index 497962f..cda93ad 100644
--- a/polygerrit-ui/app/models/comments/comments-model.ts
+++ b/polygerrit-ui/app/models/comments/comments-model.ts
@@ -19,6 +19,7 @@
   isError,
   isDraft,
   isNew,
+  PatchSetNumber,
 } from '../../types/common';
 import {
   addPath,
@@ -27,6 +28,7 @@
   createNewPatchsetLevel,
   getFirstComment,
   hasSuggestion,
+  hasUserSuggestion,
   id,
   isDraftThread,
   isNewThread,
@@ -562,6 +564,14 @@
           })
         )
     );
+    this.subscriptions.push(
+      combineLatest([
+        this.comments$,
+        this.changeModel.latestPatchNum$,
+      ]).subscribe(([comments, latestPatchset]) => {
+        this.reportCommentStats(comments, latestPatchset);
+      })
+    );
   }
 
   // Note that this does *not* reload ported comments.
@@ -602,6 +612,44 @@
     );
   }
 
+  private reportCommentStats(
+    obj?: {[path: string]: CommentInfo[]},
+    latestPatchset?: PatchSetNumber
+  ) {
+    if (!obj || !latestPatchset) return;
+    const comments = Object.values(obj).flat();
+    if (comments.length === 0) return;
+    const commentsLatest = comments.filter(c => c.patch_set === latestPatchset);
+    const commentsFixes = comments
+      .map(c => c.fix_suggestions?.length ?? 0)
+      .filter(l => l > 0);
+    const commentsLatestFixes = commentsLatest
+      .map(c => c.fix_suggestions?.length ?? 0)
+      .filter(l => l > 0);
+    const commentsLatestUnresolved = commentsLatest.filter(c => c.unresolved);
+    const commentsLatestUnresolvedFixes = commentsLatestUnresolved
+      .map(c => c.fix_suggestions?.length ?? 0)
+      .filter(l => l > 0);
+    const details = {
+      countLatest: commentsLatest.length,
+      countLatestWithFix: commentsLatestFixes.length,
+      countLatestWithUserFix: commentsLatest.filter(c => hasUserSuggestion(c))
+        .length,
+      countLatestUnresolved: commentsLatestUnresolved.length,
+      countLatestUnresolvedWithFix: commentsLatestUnresolvedFixes.length,
+      countLatestUnresolvedWithUserFix: commentsLatestUnresolved.filter(c =>
+        hasUserSuggestion(c)
+      ).length,
+      countAll: comments.length,
+      countAllUnresolved: comments.filter(c => c.unresolved).length,
+      countAllWithFix: commentsFixes.length,
+      countAllWithUserFix: comments.filter(c => hasUserSuggestion(c)).length,
+    };
+    this.reporting.reportInteraction(Interaction.COMMENTS_STATS, details, {
+      deduping: Deduping.EVENT_ONCE_PER_CHANGE,
+    });
+  }
+
   async restoreDraft(draftId: UrlEncodedCommentId) {
     const found = this.discardedDrafts?.find(d => id(d) === draftId);
     if (!found) throw new Error('discarded draft not found');