Index: dashboard/dashboard/elements/alerts-table.html |
diff --git a/dashboard/dashboard/elements/alerts-table.html b/dashboard/dashboard/elements/alerts-table.html |
index 87946c31d8831e1a5d7d20699e43aa54f1e7d161..21567fc683f2139d4f3f367d3d6cfdce0f8243b2 100644 |
--- a/dashboard/dashboard/elements/alerts-table.html |
+++ b/dashboard/dashboard/elements/alerts-table.html |
@@ -298,7 +298,7 @@ found in the LICENSE file. |
improvement$="{{item.improvement}}" |
triaged$="{{item.triaged}}" |
hidden$="{{item.hideRow}}" |
- highlighted$="{{item.highlighted}}" |
+ highlighted$="{{isHighlighted(commonRevisionRange, item)}}" |
expanded$="{{item.expanded}}" |
on-click="onRowClicked"> |
@@ -335,10 +335,10 @@ found in the LICENSE file. |
<td class="revision_range"> |
<revision-range start={{item.start_revision}} end="{{item.end_revision}}"></revision-range> |
</td> |
- <td class="master"><label>{{item.master}}</label><label hidden$="{{computeAbsentOrExpanded(item.additionColumnValues.master, expanded)}}">...</label></td> |
- <td class="bot"><label>{{item.bot}}</label><label hidden$="{{computeAbsentOrExpanded(item.additionColumnValues.bot, expanded)}}">...</label></td> |
- <td class="testsuite"><label>{{item.testsuite}}</label><label hidden$="{{computeAbsentOrExpanded(item.additionColumnValues.testsuite, expanded)}}">...</label></td> |
- <td class="test"><label>{{item.test}}</label><label hidden$="{{computeAbsentOrExpanded(item.additionColumnValues.test, expanded)}}">...</label></td> |
+ <td class="master"><label>{{item.master}}</label><label hidden$="{{!computeColumnEllipsized(item.*, 'master')}}">...</label></td> |
+ <td class="bot"><label>{{item.bot}}</label><label hidden$="{{!computeColumnEllipsized(item.*, 'bot')}}">...</label></td> |
+ <td class="testsuite"><label>{{item.testsuite}}</label><label hidden$="{{!computeColumnEllipsized(item.*, 'testSuite')}}">...</label></td> |
+ <td class="test"><label>{{item.test}}</label><label hidden$="{{!computeColumnEllipsized(item.*, 'test')}}">...</label></td> |
<template is="dom-repeat" items="{{extraColumns}}" as="column" index-as="colnum"> |
<td class="{{column.key}}"><label>{{computeExtraColumnValue(alertList.*, index, column.key)}}</td> |
@@ -366,6 +366,28 @@ found in the LICENSE file. |
return '/group_report?keys=' + keys.join(','); |
} |
+ /** |
+ * Returns the intersection of the two ranges. |
+ * |
+ * @param {Object} range1 An range in the form: |
+ * { start: <Number>, end: <Number> }, or null for an empty range. |
+ * @param {Object} range2 A range in the same form. |
+ * @return {Object} The intersection of the two ranges in the same form, or |
+ * null if no such intersection exists. |
+ */ |
+ function findRangeIntersection(range1, range2) { |
+ if (range1 == null || range2 == null) |
+ return null; |
+ |
+ var start = Math.max(range1.start, range2.start); |
+ var end = Math.min(range1.end, range2.end); |
+ |
+ if (end < start) |
+ return null; |
+ |
+ return { start: start, end: end }; |
+ } |
+ |
Polymer({ |
is: 'alerts-table', |
@@ -423,6 +445,20 @@ found in the LICENSE file. |
*/ |
currentCheckboxId: { value: null }, |
+ /** |
+ * The revision range that's common between all selected alerts. |
+ * |
+ * If there's a common range, this is an object of the form: |
+ * |
+ * { start: <number>, end: <number> } |
+ * |
+ * If there's no common range, this is null. |
+ */ |
+ commonRevisionRange: { |
+ type: Object, |
+ value: null |
+ }, |
+ |
NUM_ALERTS_TO_CHECK_ON_INIT: { |
type: Number, |
value: 10 |
@@ -435,7 +471,26 @@ found in the LICENSE file. |
ready: function() { |
}, |
- computeAbsentOrExpanded: (prop, exanded) => !prop || expanded, |
+ // TODO(charliea): The current implementation of this depends on the fact |
+ // the additional column values are computed immediately after the alerts |
+ // are updated. If the additional column values are updated without |
+ // resetting the alerts, this will stop working because this function |
+ // observes the alert, not the alert's deep properties. Restructuring this |
+ // so that additionalColumnValues is its own computed property that |
+ // observes alerts rather than a weird appendage of the alert itself |
+ // would fix this problem. |
+ /** |
+ * Returns whether the column associated with the given alert property |
+ * should be ellipsized, which indicates that there are grouped alerts |
+ * that have different values for that column. |
+ */ |
+ computeColumnEllipsized: function(iterInfo, property) { |
+ var alert = iterInfo.base; |
+ |
+ return alert.additionalColumnValues != undefined && |
+ alert.additionalColumnValues[property] && |
+ !alert.expanded; |
+ }, |
computeIsPlural: (unused, n) => n > 1, |
@@ -513,23 +568,31 @@ found in the LICENSE file. |
*/ |
addEllipsis: function() { |
for (var i = 0; i < this.alertList.length; i++) { |
+ this.setAlertList(i, 'additionalColumnValues', {}); |
+ } |
+ |
+ for (var i = 0; i < this.alertList.length; i++) { |
var alert = this.alertList[i]; |
if (alert.rowType == 'group-header' && alert.size > 1) { |
- this.setAlertList(i, 'additionColumnValues', {}); |
+ var headerRowIndex = i; |
for (var j = i + 1; j < this.alertList.length; j++) { |
var memberAlert = this.alertList[j]; |
if (memberAlert.rowType == 'group-member') { |
if (memberAlert.master != alert.master) { |
- this.setAlertList(i, 'additionColumnValues.master', true); |
+ this.setAlertList( |
+ headerRowIndex, 'additionalColumnValues.master', true); |
} |
if (memberAlert.bot != alert.bot) { |
- this.setAlertList(i, 'additionColumnValues.bot', true); |
+ this.setAlertList( |
+ headerRowIndex, 'additionalColumnValues.bot', true); |
} |
if (memberAlert.testsuite != alert.testsuite) { |
- this.setAlertList(i, 'additionColumnValues.testsuite', true); |
+ this.setAlertList( |
+ headerRowIndex, 'additionalColumnValues.testsuite', true); |
} |
if (memberAlert.test != alert.test) { |
- this.setAlertList(i, 'additionColumnValues.test', true); |
+ this.setAlertList( |
+ headerRowIndex, 'additionalColumnValues.test', true); |
} |
} else { |
break; |
@@ -549,7 +612,8 @@ found in the LICENSE file. |
var alertIndex = row.rowIndex - 1; |
var alert = this.alertList[alertIndex]; |
var isExpand = !alert.expanded; |
- alert.expanded = isExpand; |
+ this.setAlertList(alertIndex, 'expanded', isExpand); |
+ |
for (var i = alertIndex + 1; i < this.alertList.length; i++) { |
if (this.alertList[i].group == alert.group) { |
this.setAlertList(i, 'hideRow', !isExpand); |
@@ -805,7 +869,7 @@ found in the LICENSE file. |
* represents the range [300, 400]. |
* |
* The input and output revision ranges are inclusive; that is, both |
- * start and end revision are included in the range. Thus the minimum |
+ * start and end revision are included in the range. Thus the common |
* revision range for alerts with ranges [110, 120] and [120, 130] is |
* [120, 120]. |
* |
@@ -813,49 +877,24 @@ found in the LICENSE file. |
* @return {?Object} An object containing start and end revision, |
* or null if the checked alerts don't overlap. |
*/ |
- getMinimumRevisionRange: function(alerts) { |
- if (!alerts || alerts.length == 0) { |
+ getCommonRevisionRange: function(alerts) { |
+ if (!alerts || alerts.length == 0) |
return null; |
- } |
- // Start with the range of the first alert, and then narrow it down. |
- var start = alerts[0]['start_revision']; |
- var end = alerts[0]['end_revision']; |
- for (var i = 1; i < alerts.length; i++) { |
- var a = alerts[i]; |
- if (a['start_revision'] > start) { |
- if (a['start_revision'] > end) { |
- return null; |
- } |
- start = a['start_revision']; |
- } |
- if (a['end_revision'] < end) { |
- if (a['end_revision'] < start) { |
- return null; |
- } |
- end = a['end_revision']; |
- } |
- } |
- return {'start': start, 'end': end}; |
- }, |
- /** |
- * Highlights alerts that overlap with checked alerts revision range. |
- */ |
- updateHighlights: function() { |
- for (var i = 0; i < this.alertList.length; i++) { |
- this.setAlertList(i, 'highlighted', false); |
- } |
- var minRevisionRange = this.getMinimumRevisionRange(this.checkedAlerts); |
- if (!minRevisionRange) { |
- return; |
- } |
- for (var i = 0; i < this.alertList.length; i++) { |
- var alert = this.alertList[i]; |
- if (alert.start_revision > minRevisionRange.end || |
- alert.end_revision < minRevisionRange.start) { |
- this.setAlertList(i, 'highlighted', true); |
- } |
+ var commonRange = { start: -Infinity, end: Infinity }; |
+ for (var alert of alerts) { |
+ var alertRange = { |
+ start: alert['start_revision'], |
+ end: alert['end_revision'] |
+ }; |
+ |
+ commonRange = findRangeIntersection(commonRange, alertRange); |
+ |
+ if (commonRange == null) |
+ return null; |
} |
+ |
+ return commonRange; |
}, |
/** |
@@ -930,8 +969,12 @@ found in the LICENSE file. |
this.set('checkedAlerts', this.alertList.filter(function(alertRow) { |
return alertRow.selected; |
})); |
+ |
+ this.set( |
+ 'commonRevisionRange', |
+ this.getCommonRevisionRange(this.checkedAlerts)); |
+ |
this.updateHeaderCheckbox(); |
- this.updateHighlights(); |
this.maybeDisableButtons(); |
this.fire('changeselection'); |
}, |
@@ -1006,6 +1049,19 @@ found in the LICENSE file. |
}); |
this.onCheckboxChange(); |
this.updateBugColumn(); |
+ }, |
+ |
+ isHighlighted: function(commonRevisionRange, alert) { |
+ if (commonRevisionRange == null) |
+ return false; |
+ |
+ var alertRevisionRange = { |
+ start: alert.start_revision, |
+ end: alert.end_revision |
+ }; |
+ |
+ return findRangeIntersection( |
+ commonRevisionRange, alertRevisionRange) != null; |
} |
}); |
})(); |