commit b1b7aecdffc54f75429dfa7b0ed9e108463e534f Author: Dmitrii Filippov Date: Wed Oct 7 08:16:55 2020 +0200 Rename files to preserve history Test\Eslint fail - this is expected. Change-Id: Ic1521cd4bf68df53804bc4106a57a2dc76167ed1 diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js deleted file mode 100644 index e85f9e4..0000000 --- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.js +++ /dev/null @@ -1,434 +0,0 @@ -/** - * @license - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -import '@polymer/paper-toggle-button/paper-toggle-button.js'; -import '../../shared/gr-button/gr-button.js'; -import '../../shared/gr-icons/gr-icons.js'; -import '../gr-message/gr-message.js'; -import '../../../styles/shared-styles.js'; -import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js'; -import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js'; -import {PolymerElement} from '@polymer/polymer/polymer-element.js'; -import {htmlTemplate} from './gr-messages-list_html.js'; -import { - KeyboardShortcutMixin, - Shortcut, ShortcutSection, -} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.js'; -import {parseDate} from '../../../utils/date-util.js'; -import {MessageTag} from '../../../constants/constants.js'; -import {appContext} from '../../../services/app-context.js'; - -/** - * The content of the enum is also used in the UI for the button text. - * - * @enum {string} - */ -const ExpandAllState = { - EXPAND_ALL: 'Expand All', - COLLAPSE_ALL: 'Collapse All', -}; - -/** - * Computes message author's comments for this change message. The backend - * sets comment.change_message_id for matching, so this computation is fairly - * straightforward. - */ -function computeThreads(message, allMessages, changeComments) { - if ([message, allMessages, changeComments].includes(undefined)) { - return []; - } - if (message._index === undefined) { - return []; - } - - return changeComments.getAllThreadsForChange().filter( - thread => thread.comments.map(comment => { - // collapse all by default - comment.collapsed = true; - return comment; - }).some(comment => { - const condition = comment.change_message_id === message.id; - // Since getAllThreadsForChange() always returns a new copy of - // all comments we can modify them here without worrying about - // polluting other threads. - comment.collapsed = !condition; - return condition; - }) - ); -} - -/** - * If messages have the same tag, then that influences grouping and whether - * a message is initally hidden or not, see isImportant(). So we are applying - * some "magic" rules here in order to hide exactly the right messages. - * - * 1. If a message does not have a tag, but is associated with robot comments, - * then it gets a tag. - * - * 2. Use the same tag for some of Gerrit's standard events, if they should be - * considered one group, e.g. normal and wip patchset uploads. - * - * 3. Everything beyond the ~ character is cut off from the tag. That gives - * tools control over which messages will be hidden. - */ -function computeTag(message) { - if (!message.tag) { - const threads = message.commentThreads || []; - const comments = threads.map( - t => t.comments.find(c => c.change_message_id === message.id)); - const isRobot = comments.some(c => c && !!c.robot_id); - return isRobot ? 'autogenerated:has-robot-comments' : undefined; - } - - if (message.tag === MessageTag.TAG_NEW_WIP_PATCHSET) { - return MessageTag.TAG_NEW_PATCHSET; - } - if (message.tag === MessageTag.TAG_UNSET_ASSIGNEE) { - return MessageTag.TAG_SET_ASSIGNEE; - } - if (message.tag === MessageTag.TAG_UNSET_PRIVATE) { - return MessageTag.TAG_SET_PRIVATE; - } - if (message.tag === MessageTag.TAG_SET_WIP) { - return MessageTag.TAG_SET_READY; - } - - return message.tag.replace(/~.*/, ''); -} - -/** - * Try to set a revision number that makes sense, if none is set. Just copy - * over the revision number of the next older message. This is mostly relevant - * for reviewer updates. Other messages should typically have the revision - * number already set. - */ -function computeRevision(message, allMessages) { - if (message._revision_number > 0) return message._revision_number; - let revision = 0; - for (const m of allMessages) { - if (m.date > message.date) break; - if (m._revision_number > revision) revision = m._revision_number; - } - return revision > 0 ? revision : undefined; -} - -/** - * Unimportant messages are initially hidden. - * - * Human messages are always important. They have an undefined tag. - * - * Autogenerated messages are unimportant, if there is a message with the same - * tag and a higher revision number. - */ -function computeIsImportant(message, allMessages) { - if (!message.tag) return true; - - const hasSameTag = m => m.tag === message.tag; - const revNumber = message._revision_number || 0; - const hasHigherRevisionNumber = m => m._revision_number > revNumber; - return !allMessages.filter(hasSameTag).some(hasHigherRevisionNumber); -} - -export const TEST_ONLY = { - computeThreads, - computeTag, - computeRevision, - computeIsImportant, -}; - -/** - * @extends PolymerElement - */ -class GrMessagesList extends KeyboardShortcutMixin( - GestureEventListeners( - LegacyElementMixin( - PolymerElement))) { - static get template() { return htmlTemplate; } - - static get is() { return 'gr-messages-list'; } - - static get properties() { - return { - /** @type {?} */ - change: Object, - changeNum: Number, - /** - * These are just the change messages. They are combined with reviewer - * updates below. So _combinedMessages is the more important property. - */ - messages: { - type: Array, - value() { return []; }, - }, - /** - * These are just the reviewer updates. They are combined with change - * messages above. So _combinedMessages is the more important property. - */ - reviewerUpdates: { - type: Array, - value() { return []; }, - }, - changeComments: Object, - projectName: String, - showReplyButtons: { - type: Boolean, - value: false, - }, - labels: Object, - - /** - * Keeps track of the state of the "Expand All" toggle button. Note that - * you can individually expand/collapse some messages without affecting - * the toggle button's state. - * - * @type {ExpandAllState} - */ - _expandAllState: { - type: String, - value: ExpandAllState.EXPAND_ALL, - }, - _expandAllTitle: { - type: String, - computed: '_computeExpandAllTitle(_expandAllState)', - }, - - _showAllActivity: { - type: Boolean, - value: false, - observer: '_observeShowAllActivity', - }, - /** - * The merged array of change messages and reviewer updates. - */ - _combinedMessages: { - type: Array, - computed: '_computeCombinedMessages(messages, reviewerUpdates, ' - + 'changeComments)', - observer: '_combinedMessagesChanged', - }, - - _labelExtremes: { - type: Object, - computed: '_computeLabelExtremes(labels.*)', - }, - }; - } - - constructor() { - super(); - this.reporting = appContext.reportingService; - } - - scrollToMessage(messageID) { - const selector = `[data-message-id="${messageID}"]`; - const el = this.shadowRoot.querySelector(selector); - - if (!el && this._showAllActivity) { - console.warn(`Failed to scroll to message: ${messageID}`); - return; - } - if (!el) { - this._showAllActivity = true; - setTimeout(() => this.scrollToMessage(messageID)); - return; - } - - el.set('message.expanded', true); - let top = el.offsetTop; - for (let offsetParent = el.offsetParent; - offsetParent; - offsetParent = offsetParent.offsetParent) { - top += offsetParent.offsetTop; - } - window.scrollTo(0, top); - this._highlightEl(el); - } - - _observeShowAllActivity(showAllActivity) { - // We have to call render() such that the dom-repeat filter picks up the - // change. - this.$.messageRepeat.render(); - } - - /** - * Filter for the dom-repeat of combinedMessages. - */ - _isMessageVisible(message) { - return this._showAllActivity || message.isImportant; - } - - /** - * Merges change messages and reviewer updates into one array. Also processes - * all messages and updates, aligns or massages some of the properties. - */ - _computeCombinedMessages(messages, reviewerUpdates, changeComments) { - const params = [messages, reviewerUpdates, changeComments]; - if (params.some(o => o === undefined)) return []; - - let mi = 0; - let ri = 0; - let combinedMessages = []; - let mDate; - let rDate; - for (let i = 0; i < messages.length; i++) { - messages[i]._index = i; - } - - while (mi < messages.length || ri < reviewerUpdates.length) { - if (mi >= messages.length) { - combinedMessages = combinedMessages.concat(reviewerUpdates.slice(ri)); - break; - } - if (ri >= reviewerUpdates.length) { - combinedMessages = combinedMessages.concat(messages.slice(mi)); - break; - } - mDate = mDate || parseDate(messages[mi].date); - rDate = rDate || parseDate(reviewerUpdates[ri].date); - if (rDate < mDate) { - combinedMessages.push(reviewerUpdates[ri++]); - rDate = null; - } else { - combinedMessages.push(messages[mi++]); - mDate = null; - } - } - combinedMessages.forEach(m => { - if (m.expanded === undefined) { - m.expanded = false; - } - m.commentThreads = computeThreads(m, combinedMessages, changeComments); - m._revision_number = computeRevision(m, combinedMessages); - m.tag = computeTag(m); - }); - // computeIsImportant() depends on tags and revision numbers already being - // updated for all messages, so we have to compute this in its own forEach - // loop. - combinedMessages.forEach(m => { - m.isImportant = computeIsImportant(m, combinedMessages); - }); - return combinedMessages; - } - - _updateExpandedStateOfAllMessages(exp) { - if (this._combinedMessages) { - for (let i = 0; i < this._combinedMessages.length; i++) { - this._combinedMessages[i].expanded = exp; - this.notifyPath(`_combinedMessages.${i}.expanded`); - } - } - } - - _computeExpandAllTitle(_expandAllState) { - if (_expandAllState === ExpandAllState.COLLAPSE_ALL) { - return this.createTitle( - Shortcut.COLLAPSE_ALL_MESSAGES, ShortcutSection.ACTIONS); - } - if (_expandAllState === ExpandAllState.EXPAND_ALL) { - return this.createTitle( - Shortcut.EXPAND_ALL_MESSAGES, ShortcutSection.ACTIONS); - } - return ''; - } - - _highlightEl(el) { - const highlightedEls = - this.root.querySelectorAll('.highlighted'); - for (const highlightedEl of highlightedEls) { - highlightedEl.classList.remove('highlighted'); - } - function handleAnimationEnd() { - el.removeEventListener('animationend', handleAnimationEnd); - el.classList.remove('highlighted'); - } - el.addEventListener('animationend', handleAnimationEnd); - el.classList.add('highlighted'); - } - - /** - * @param {boolean} expand - */ - handleExpandCollapse(expand) { - this._expandAllState = expand ? ExpandAllState.COLLAPSE_ALL - : ExpandAllState.EXPAND_ALL; - this._updateExpandedStateOfAllMessages(expand); - } - - _handleExpandCollapseTap(e) { - e.preventDefault(); - this.handleExpandCollapse( - this._expandAllState === ExpandAllState.EXPAND_ALL); - } - - _handleAnchorClick(e) { - this.scrollToMessage(e.detail.id); - } - - _isVisibleShowAllActivityToggle(messages = []) { - return messages.some(m => !m.isImportant); - } - - _computeHiddenEntriesCount(messages = []) { - return messages.filter(m => !m.isImportant).length; - } - - /** - * This method is for reporting stats only. - */ - _combinedMessagesChanged(combinedMessages) { - if (combinedMessages) { - if (combinedMessages.length === 0) return; - const tags = combinedMessages.map( - message => message.tag || message.type || - (message.comments ? 'comments' : 'none')); - const tagsCounted = tags.reduce((acc, val) => { - acc[val] = (acc[val] || 0) + 1; - return acc; - }, {all: combinedMessages.length}); - this.reporting.reportInteraction('messages-count', tagsCounted); - } - } - - /** - * Compute a mapping from label name to objects representing the minimum and - * maximum possible values for that label. - */ - _computeLabelExtremes(labelRecord) { - const extremes = {}; - const labels = labelRecord.base; - if (!labels) { return extremes; } - for (const key of Object.keys(labels)) { - // TODO(TS): Let's use label-util! - if (!labels[key] || !labels[key].values) { continue; } - const values = Object.keys(labels[key].values) - .map(v => parseInt(v, 10)); - values.sort((a, b) => a - b); - if (!values.length) { continue; } - extremes[key] = {min: values[0], max: values[values.length - 1]}; - } - return extremes; - } - - /** - * Work around a issue on iOS when clicking turns into double tap - */ - _onTapShowAllActivityToggle(e) { - e.preventDefault(); - } -} - -customElements.define(GrMessagesList.is, - GrMessagesList); diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts new file mode 100644 index 0000000..e85f9e4 --- /dev/null +++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.ts @@ -0,0 +1,434 @@ +/** + * @license + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import '@polymer/paper-toggle-button/paper-toggle-button.js'; +import '../../shared/gr-button/gr-button.js'; +import '../../shared/gr-icons/gr-icons.js'; +import '../gr-message/gr-message.js'; +import '../../../styles/shared-styles.js'; +import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js'; +import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js'; +import {PolymerElement} from '@polymer/polymer/polymer-element.js'; +import {htmlTemplate} from './gr-messages-list_html.js'; +import { + KeyboardShortcutMixin, + Shortcut, ShortcutSection, +} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin.js'; +import {parseDate} from '../../../utils/date-util.js'; +import {MessageTag} from '../../../constants/constants.js'; +import {appContext} from '../../../services/app-context.js'; + +/** + * The content of the enum is also used in the UI for the button text. + * + * @enum {string} + */ +const ExpandAllState = { + EXPAND_ALL: 'Expand All', + COLLAPSE_ALL: 'Collapse All', +}; + +/** + * Computes message author's comments for this change message. The backend + * sets comment.change_message_id for matching, so this computation is fairly + * straightforward. + */ +function computeThreads(message, allMessages, changeComments) { + if ([message, allMessages, changeComments].includes(undefined)) { + return []; + } + if (message._index === undefined) { + return []; + } + + return changeComments.getAllThreadsForChange().filter( + thread => thread.comments.map(comment => { + // collapse all by default + comment.collapsed = true; + return comment; + }).some(comment => { + const condition = comment.change_message_id === message.id; + // Since getAllThreadsForChange() always returns a new copy of + // all comments we can modify them here without worrying about + // polluting other threads. + comment.collapsed = !condition; + return condition; + }) + ); +} + +/** + * If messages have the same tag, then that influences grouping and whether + * a message is initally hidden or not, see isImportant(). So we are applying + * some "magic" rules here in order to hide exactly the right messages. + * + * 1. If a message does not have a tag, but is associated with robot comments, + * then it gets a tag. + * + * 2. Use the same tag for some of Gerrit's standard events, if they should be + * considered one group, e.g. normal and wip patchset uploads. + * + * 3. Everything beyond the ~ character is cut off from the tag. That gives + * tools control over which messages will be hidden. + */ +function computeTag(message) { + if (!message.tag) { + const threads = message.commentThreads || []; + const comments = threads.map( + t => t.comments.find(c => c.change_message_id === message.id)); + const isRobot = comments.some(c => c && !!c.robot_id); + return isRobot ? 'autogenerated:has-robot-comments' : undefined; + } + + if (message.tag === MessageTag.TAG_NEW_WIP_PATCHSET) { + return MessageTag.TAG_NEW_PATCHSET; + } + if (message.tag === MessageTag.TAG_UNSET_ASSIGNEE) { + return MessageTag.TAG_SET_ASSIGNEE; + } + if (message.tag === MessageTag.TAG_UNSET_PRIVATE) { + return MessageTag.TAG_SET_PRIVATE; + } + if (message.tag === MessageTag.TAG_SET_WIP) { + return MessageTag.TAG_SET_READY; + } + + return message.tag.replace(/~.*/, ''); +} + +/** + * Try to set a revision number that makes sense, if none is set. Just copy + * over the revision number of the next older message. This is mostly relevant + * for reviewer updates. Other messages should typically have the revision + * number already set. + */ +function computeRevision(message, allMessages) { + if (message._revision_number > 0) return message._revision_number; + let revision = 0; + for (const m of allMessages) { + if (m.date > message.date) break; + if (m._revision_number > revision) revision = m._revision_number; + } + return revision > 0 ? revision : undefined; +} + +/** + * Unimportant messages are initially hidden. + * + * Human messages are always important. They have an undefined tag. + * + * Autogenerated messages are unimportant, if there is a message with the same + * tag and a higher revision number. + */ +function computeIsImportant(message, allMessages) { + if (!message.tag) return true; + + const hasSameTag = m => m.tag === message.tag; + const revNumber = message._revision_number || 0; + const hasHigherRevisionNumber = m => m._revision_number > revNumber; + return !allMessages.filter(hasSameTag).some(hasHigherRevisionNumber); +} + +export const TEST_ONLY = { + computeThreads, + computeTag, + computeRevision, + computeIsImportant, +}; + +/** + * @extends PolymerElement + */ +class GrMessagesList extends KeyboardShortcutMixin( + GestureEventListeners( + LegacyElementMixin( + PolymerElement))) { + static get template() { return htmlTemplate; } + + static get is() { return 'gr-messages-list'; } + + static get properties() { + return { + /** @type {?} */ + change: Object, + changeNum: Number, + /** + * These are just the change messages. They are combined with reviewer + * updates below. So _combinedMessages is the more important property. + */ + messages: { + type: Array, + value() { return []; }, + }, + /** + * These are just the reviewer updates. They are combined with change + * messages above. So _combinedMessages is the more important property. + */ + reviewerUpdates: { + type: Array, + value() { return []; }, + }, + changeComments: Object, + projectName: String, + showReplyButtons: { + type: Boolean, + value: false, + }, + labels: Object, + + /** + * Keeps track of the state of the "Expand All" toggle button. Note that + * you can individually expand/collapse some messages without affecting + * the toggle button's state. + * + * @type {ExpandAllState} + */ + _expandAllState: { + type: String, + value: ExpandAllState.EXPAND_ALL, + }, + _expandAllTitle: { + type: String, + computed: '_computeExpandAllTitle(_expandAllState)', + }, + + _showAllActivity: { + type: Boolean, + value: false, + observer: '_observeShowAllActivity', + }, + /** + * The merged array of change messages and reviewer updates. + */ + _combinedMessages: { + type: Array, + computed: '_computeCombinedMessages(messages, reviewerUpdates, ' + + 'changeComments)', + observer: '_combinedMessagesChanged', + }, + + _labelExtremes: { + type: Object, + computed: '_computeLabelExtremes(labels.*)', + }, + }; + } + + constructor() { + super(); + this.reporting = appContext.reportingService; + } + + scrollToMessage(messageID) { + const selector = `[data-message-id="${messageID}"]`; + const el = this.shadowRoot.querySelector(selector); + + if (!el && this._showAllActivity) { + console.warn(`Failed to scroll to message: ${messageID}`); + return; + } + if (!el) { + this._showAllActivity = true; + setTimeout(() => this.scrollToMessage(messageID)); + return; + } + + el.set('message.expanded', true); + let top = el.offsetTop; + for (let offsetParent = el.offsetParent; + offsetParent; + offsetParent = offsetParent.offsetParent) { + top += offsetParent.offsetTop; + } + window.scrollTo(0, top); + this._highlightEl(el); + } + + _observeShowAllActivity(showAllActivity) { + // We have to call render() such that the dom-repeat filter picks up the + // change. + this.$.messageRepeat.render(); + } + + /** + * Filter for the dom-repeat of combinedMessages. + */ + _isMessageVisible(message) { + return this._showAllActivity || message.isImportant; + } + + /** + * Merges change messages and reviewer updates into one array. Also processes + * all messages and updates, aligns or massages some of the properties. + */ + _computeCombinedMessages(messages, reviewerUpdates, changeComments) { + const params = [messages, reviewerUpdates, changeComments]; + if (params.some(o => o === undefined)) return []; + + let mi = 0; + let ri = 0; + let combinedMessages = []; + let mDate; + let rDate; + for (let i = 0; i < messages.length; i++) { + messages[i]._index = i; + } + + while (mi < messages.length || ri < reviewerUpdates.length) { + if (mi >= messages.length) { + combinedMessages = combinedMessages.concat(reviewerUpdates.slice(ri)); + break; + } + if (ri >= reviewerUpdates.length) { + combinedMessages = combinedMessages.concat(messages.slice(mi)); + break; + } + mDate = mDate || parseDate(messages[mi].date); + rDate = rDate || parseDate(reviewerUpdates[ri].date); + if (rDate < mDate) { + combinedMessages.push(reviewerUpdates[ri++]); + rDate = null; + } else { + combinedMessages.push(messages[mi++]); + mDate = null; + } + } + combinedMessages.forEach(m => { + if (m.expanded === undefined) { + m.expanded = false; + } + m.commentThreads = computeThreads(m, combinedMessages, changeComments); + m._revision_number = computeRevision(m, combinedMessages); + m.tag = computeTag(m); + }); + // computeIsImportant() depends on tags and revision numbers already being + // updated for all messages, so we have to compute this in its own forEach + // loop. + combinedMessages.forEach(m => { + m.isImportant = computeIsImportant(m, combinedMessages); + }); + return combinedMessages; + } + + _updateExpandedStateOfAllMessages(exp) { + if (this._combinedMessages) { + for (let i = 0; i < this._combinedMessages.length; i++) { + this._combinedMessages[i].expanded = exp; + this.notifyPath(`_combinedMessages.${i}.expanded`); + } + } + } + + _computeExpandAllTitle(_expandAllState) { + if (_expandAllState === ExpandAllState.COLLAPSE_ALL) { + return this.createTitle( + Shortcut.COLLAPSE_ALL_MESSAGES, ShortcutSection.ACTIONS); + } + if (_expandAllState === ExpandAllState.EXPAND_ALL) { + return this.createTitle( + Shortcut.EXPAND_ALL_MESSAGES, ShortcutSection.ACTIONS); + } + return ''; + } + + _highlightEl(el) { + const highlightedEls = + this.root.querySelectorAll('.highlighted'); + for (const highlightedEl of highlightedEls) { + highlightedEl.classList.remove('highlighted'); + } + function handleAnimationEnd() { + el.removeEventListener('animationend', handleAnimationEnd); + el.classList.remove('highlighted'); + } + el.addEventListener('animationend', handleAnimationEnd); + el.classList.add('highlighted'); + } + + /** + * @param {boolean} expand + */ + handleExpandCollapse(expand) { + this._expandAllState = expand ? ExpandAllState.COLLAPSE_ALL + : ExpandAllState.EXPAND_ALL; + this._updateExpandedStateOfAllMessages(expand); + } + + _handleExpandCollapseTap(e) { + e.preventDefault(); + this.handleExpandCollapse( + this._expandAllState === ExpandAllState.EXPAND_ALL); + } + + _handleAnchorClick(e) { + this.scrollToMessage(e.detail.id); + } + + _isVisibleShowAllActivityToggle(messages = []) { + return messages.some(m => !m.isImportant); + } + + _computeHiddenEntriesCount(messages = []) { + return messages.filter(m => !m.isImportant).length; + } + + /** + * This method is for reporting stats only. + */ + _combinedMessagesChanged(combinedMessages) { + if (combinedMessages) { + if (combinedMessages.length === 0) return; + const tags = combinedMessages.map( + message => message.tag || message.type || + (message.comments ? 'comments' : 'none')); + const tagsCounted = tags.reduce((acc, val) => { + acc[val] = (acc[val] || 0) + 1; + return acc; + }, {all: combinedMessages.length}); + this.reporting.reportInteraction('messages-count', tagsCounted); + } + } + + /** + * Compute a mapping from label name to objects representing the minimum and + * maximum possible values for that label. + */ + _computeLabelExtremes(labelRecord) { + const extremes = {}; + const labels = labelRecord.base; + if (!labels) { return extremes; } + for (const key of Object.keys(labels)) { + // TODO(TS): Let's use label-util! + if (!labels[key] || !labels[key].values) { continue; } + const values = Object.keys(labels[key].values) + .map(v => parseInt(v, 10)); + values.sort((a, b) => a - b); + if (!values.length) { continue; } + extremes[key] = {min: values[0], max: values[values.length - 1]}; + } + return extremes; + } + + /** + * Work around a issue on iOS when clicking turns into double tap + */ + _onTapShowAllActivityToggle(e) { + e.preventDefault(); + } +} + +customElements.define(GrMessagesList.is, + GrMessagesList);