Merge "Add reportInteraction calls for attention set actions"
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
index 04cd2b2..6bb7f0c 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.js
@@ -40,6 +40,7 @@
 import {GrDisplayNameUtils} from '../../../scripts/gr-display-name-utils/gr-display-name-utils.js';
 import {pluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints.js';
 import {pluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
+import {appContext} from '../../../services/app-context.js';
 
 const CHANGE_SIZE = {
   XS: 10,
@@ -83,6 +84,8 @@
       /** @type {?} */
       change: Object,
       config: Object,
+      /** Name of the section in the change-list. Used for reporting. */
+      sectionName: String,
       changeURL: {
         type: String,
         computed: '_computeChangeURL(change)',
@@ -106,6 +109,11 @@
     };
   }
 
+  constructor() {
+    super();
+    this.reporting = appContext.reportingService;
+  }
+
   /** @override */
   attached() {
     super.attached();
@@ -298,6 +306,20 @@
       detail: {change: this.change, reviewed: newVal},
     }));
   }
+
+  _handleChangeClick(e) {
+    // Don't prevent the default and neither stop bubbling. We just want to
+    // report the click, but then let the browser handle the click on the link.
+
+    const selfId = (this.account && this.account._account_id) || -1;
+    const ownerId = (this.change && this.change.owner
+        && this.change.owner._account_id) || -1;
+
+    this.reporting.reportInteraction('change-row-clicked', {
+      section: this.sectionName,
+      isOwner: selfId === ownerId,
+    });
+  }
 }
 
 customElements.define(GrChangeListItem.is, GrChangeListItem);
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.js b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.js
index cc1bf62..48aab4c 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item_html.js
@@ -133,7 +133,11 @@
   >
     <div class="container">
       <div class="content">
-        <a title$="[[change.subject]]" href$="[[changeURL]]">
+        <a
+          title$="[[change.subject]]"
+          href$="[[changeURL]]"
+          on-click="_handleChangeClick"
+        >
           [[change.subject]]
         </a>
       </div>
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.js b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.js
index a18ffd0..623838b 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.js
@@ -137,6 +137,7 @@
             needs-review$="[[_computeItemNeedsReview(account, change, showReviewedState, _config)]]"
             change="[[change]]"
             config="[[_config]]"
+            section-name="[[changeSection.name]]"
             visible-change-table-columns="[[visibleChangeTableColumns]]"
             show-number="[[showNumber]]"
             show-star="[[showStar]]"
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
index b5d40d2..3fb8442 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.js
@@ -561,6 +561,9 @@
         }
       }
     }
+    this.reportAttentionSetChanges(this._attentionModified,
+        reviewInput.add_to_attention_set,
+        reviewInput.remove_from_attention_set);
 
     if (this.draft != null) {
       if (this._isPatchsetCommentsExperimentEnabled) {
@@ -1086,6 +1089,26 @@
       composed: true, bubbles: true,
     }));
   }
+
+  reportAttentionSetChanges(modified, addedSet, removedSet) {
+    const actions = modified ? ['MODIFIED'] : ['NOT_MODIFIED'];
+    const ownerId = (this.change && this.change.owner
+        && this.change.owner._account_id) || -1;
+    const selfId = (this._account && this._account._account_id) || -1;
+    for (const added of (addedSet || [])) {
+      const addedId = added.user;
+      const self = addedId === selfId ? '_SELF' : '';
+      const role = addedId === ownerId ? '_OWNER' : '_REVIEWER';
+      actions.push('ADD' + self + role);
+    }
+    for (const removed of (removedSet || [])) {
+      const removedId = removed.user;
+      const self = removedId === selfId ? '_SELF' : '';
+      const role = removedId === ownerId ? '_OWNER' : '_REVIEWER';
+      actions.push('REMOVE' + self + role);
+    }
+    this.reporting.reportInteraction('attention-set-actions', {actions});
+  }
 }
 
 customElements.define(GrReplyDialog.is, GrReplyDialog);
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.js b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.js
index ac9bd62..717a28e 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.js
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.js
@@ -26,6 +26,7 @@
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js';
 import {PolymerElement} from '@polymer/polymer/polymer-element.js';
 import {htmlTemplate} from './gr-hovercard-account_html.js';
+import {appContext} from '../../../services/app-context.js';
 
 /** @extends PolymerElement */
 class GrHovercardAccount extends GestureEventListeners(
@@ -72,6 +73,11 @@
     };
   }
 
+  constructor() {
+    super();
+    this.reporting = appContext.reportingService;
+  }
+
   attached() {
     super.attached();
     this.$.restAPI.getConfig().then(config => {
@@ -120,6 +126,8 @@
       composed: true,
       bubbles: true,
     }));
+    this.reporting.reportInteraction('attention-hovercard-add',
+        this._reportingDetails());
     this.$.restAPI.addToAttentionSet(this.change._number,
         this.account._account_id, 'manually added').then(obj => {
       GerritNav.navigateToChange(this.change);
@@ -136,12 +144,34 @@
       composed: true,
       bubbles: true,
     }));
+    this.reporting.reportInteraction('attention-hovercard-remove',
+        this._reportingDetails());
     this.$.restAPI.removeFromAttentionSet(this.change._number,
         this.account._account_id, 'manually removed').then(obj => {
       GerritNav.navigateToChange(this.change);
     });
     this.hide();
   }
+
+  _reportingDetails() {
+    const targetId = this.account._account_id;
+    const ownerId = (this.change && this.change.owner
+        && this.change.owner._account_id) || -1;
+    const selfId = (this._selfAccount && this._selfAccount._account_id) || -1;
+    const reviewers = (
+      this.change && this.change.reviewers && this.change.reviewers.REVIEWER ?
+        [...this.change.reviewers.REVIEWER] : []);
+    const reviewerIds = reviewers
+        .map(r => r._account_id)
+        .filter(rId => rId !== ownerId);
+    return {
+      actionByOwner: selfId === ownerId,
+      actionByReviewer: reviewerIds.includes(selfId),
+      targetIsOwner: targetId === ownerId,
+      targetIsReviewer: reviewerIds.includes(targetId),
+      targetIsSelf: targetId === selfId,
+    };
+  }
 }
 
 customElements.define(GrHovercardAccount.is, GrHovercardAccount);