1 <!DOCTYPE html> 2 <!-- 3 Copyright 2016 The Chromium Authors. All rights reserved. 4 Use of this source code is governed by a BSD-style license that can be 5 found in the LICENSE file. 6 --> 7 8 <link type="text/css" rel="stylesheet" href="/dashboard/static/base.css"> 9 <link rel="import" href="/components/paper-button/paper-button.html"> 10 <link rel="import" href="/components/polymer/polymer.html"> 11 <link rel="import" href="/dashboard/elements/alerts-table.html"> 12 <link rel="import" href="/dashboard/elements/overlay-message.html"> 13 <link rel="import" href="/dashboard/elements/quick-log.html"> 14 <link rel="import" href="/dashboard/elements/select-menu.html"> 15 <link rel="import" href="/dashboard/static/simple_xhr.html"> 16 <link rel="import" href="/dashboard/static/uri.html"> 17 18 <polymer-element name="alerts-page"> 19 <template> 20 <style> 21 .error { 22 color: #dd4b39; 23 font-weight: bold; 24 } 25 26 .center { 27 margin: auto; 28 padding: 10px; 29 } 30 31 /* The action bar contains the graph button and triage button. */ 32 #action-bar { 33 margin-top: 20px; 34 width: 100%; 35 } 36 37 /* The content container contains everything below the sheriff select menu. 38 */ 39 #content { 40 display: inline-flex; 41 display: -webkit-inline-flex; 42 flex-direction: column; 43 -webkit-flex-direction: column; 44 align-items: flex-start; 45 -webkit-align-items: flex-start; 46 } 47 48 /* This class indicates a button toggled on (e.g. show improvements). */ 49 .alert-togglebutton { 50 float: right; 51 margin-left: 4px; 52 margin-right: 4px; 53 } 54 55 #auto-triage-log { 56 padding: 15px 0 15px 0; 57 } 58 59 #anomaly-table, #stoppage-alert-table { 60 width: 100%; 61 } 62 63 #loading-spinner { 64 width: 100%; 65 display: flex; 66 justify-content: center; 67 } 68 </style> 69 <template if="{{loading}}"> 70 <div id="loading-spinner"><img src="//www.google.com/images/loading.gif"></div> 71 </template> 72 <template if="{{error}}"> 73 <div class="error">{{error}}</div> 74 </template> 75 <template if="{{!(loading || error)}}"> 76 <div id="content"> 77 <div id="action-bar"> 78 <select-menu id="sheriff-select" 79 menuItems="{{sheriffList}}" 80 on-core-activate="{{onSheriffChange}}"></select-menu> 81 <paper-button raised noink id="improvements-toggle" 82 class="alert-togglebutton" 83 on-click="{{onToggleImprovements}}">Show improvements</paper-button> 84 <paper-button raised noink id="triaged-toggle" 85 class="alert-togglebutton" 86 on-click="{{onToggleTriaged}}">Show triaged</paper-button> 87 </div> 88 <template if="{{anomalies.length > 0}}"> 89 <h2>Performance alerts</h2> 90 <p id='num-alerts'> 91 <template if="{{anomalies.length == 1}}">1 alert.</template> 92 <template if="{{anomalies.length != 1}}">{{anomalies.length}} alerts.</template> 93 </p> 94 <alerts-table id="anomaly-table" 95 xsrfToken="{{xsrfToken}}" 96 alertList="{{anomalies}}" 97 extraColumns="{{extraAnomaliesColumns}}" 98 on-sortby="{{onPushHistoryState}}" 99 on-sortdirection="{{onPushHistoryState}}"> 100 </alerts-table> 101 </template> 102 <template if="{{stoppageAlerts.length > 0}}"> 103 <h2>Data stoppage alerts</h2> 104 <alerts-table id="stoppage-alert-table" 105 xsrfToken="{{xsrfToken}}" 106 alertList="{{stoppageAlerts}}" 107 extraColumns="{{extraStoppageAlertsColumns}}"> 108 </alerts-table> 109 </template> 110 <template if="{{anomalies.length == 0 && stoppageAlerts.length == 0 && !error}}"> 111 <h2 class="center">All alerts triaged!</h2> 112 <img class="center" src="http://thecatapi.com/api/images/get?api_key=MjUzMDQ&category=space&size=small"> 113 </template> 114 <quick-log id="auto-triage-log" xsrfToken="{{xsrfToken}}" 115 style="width:100%; display:block;"></quick-log> 116 </div> 117 </template> 118 </template> 119 <script> 120 'use strict'; 121 Polymer('alerts-page', { 122 loading: true, 123 124 get anomaliesTable() { 125 return this.$['anomaly-table']; 126 }, 127 128 get stoppageAlertsTable() { 129 return this.$['stoppage-alert-table']; 130 }, 131 132 extraAnomaliesColumns: [{ 133 'key': 'percent_changed', 134 'label': 'Delta %' 135 }], 136 137 extraStoppageAlertsColumns: [{ 138 'key': 'last_row_date', 139 'label': 'Date' 140 }], 141 142 onSheriffChange: function(e) { 143 var sheriff = e.detail.item.getAttribute('label'); 144 if (!sheriff) { 145 return; 146 } 147 var params = uri.getAllParameters(); 148 params['sheriff'] = sheriff; 149 // TODO(sullivan): changing the param should automatically update 150 // everything without needing to reload. 151 window.location.href = uri.getCurrentPathWithParams(params); 152 }, 153 154 onToggleTriaged: function(e) { 155 var params = uri.getAllParameters(); 156 if (params['triaged']) { 157 delete params['triaged']; 158 } else { 159 params['triaged'] = 'true'; 160 } 161 // TODO(sullivan): changing the param should automatically update 162 // everything without needing to reload. 163 window.location.href = uri.getCurrentPathWithParams(params); 164 }, 165 166 onToggleImprovements: function(e) { 167 var params = uri.getAllParameters(); 168 if (params['improvements']) { 169 delete params['improvements']; 170 } else { 171 params['improvements'] = 'true'; 172 } 173 // TODO(sullivan): changing the param should automatically update 174 // everything without needing to reload. 175 window.location.href = uri.getCurrentPathWithParams(params); 176 }, 177 178 onPopState: function(e) { 179 // Pop State event will have a non-null state if this came from an 180 // actual pop instead of the load event. 181 if (e['state']) { 182 this.updateFromURIParameters(); 183 } 184 }, 185 186 onPushHistoryState: function(event, detail, sender) { 187 if (!sender) { 188 return; 189 } 190 var params = uri.getAllParameters(); 191 params['sortby'] = sender['sortBy']; 192 params['sortdirection'] = sender['sortDirection']; 193 var newUri = uri.getCurrentPathWithParams(params); 194 history.pushState(params, '', newUri); 195 }, 196 197 updateFromURIParameters: function() { 198 this.anomaliesTable.sortBy = uri.getParameter('sortby', 'end_revision'); 199 this.anomaliesTable.sortDirection = uri.getParameter( 200 'sortdirection', 'down'); 201 var sheriff = uri.getParameter('sheriff', 'Chromium Perf Sheriff'); 202 this.$['sheriff-select'].select(sheriff); 203 // The show improvements and show triaged toggles are initially "off"; 204 // set them to on if the corresponding query parameter is set. 205 // The buttons are displayed differently if they have the "active" 206 // attribute. 207 if (uri.getParameter('improvements')) { 208 this.$['improvements-toggle'].setAttribute('active', ''); 209 } 210 if (uri.getParameter('triaged')) { 211 this.$['triaged-toggle'].setAttribute('active', ''); 212 } 213 }, 214 215 ready: function() { 216 this.sheriff = uri.getParameter('sheriff', 'Chromium Perf Sheriff'); 217 this.sortBy = uri.getParameter('sortby', 'end_revision'); 218 this.sortDirection = uri.getParameter('sortdirection', 'down'); 219 this.showImprovements = uri.getParameter('improvements', false); 220 this.showTriaged = uri.getParameter('triaged', false); 221 var params = { 222 'sheriff': this.sheriff 223 }; 224 if (this.showImprovements) { 225 params['improvements'] = true; 226 } 227 if (this.showTriaged) { 228 params['triaged'] = true; 229 } 230 simple_xhr.send('/alerts', params, 231 function(response) { 232 this.anomalies = response['anomaly_list']; 233 this.stoppageAlerts = response['stoppage_alert_list']; 234 this.sheriffList = response['sheriff_list']; 235 this.xsrfToken = response['xsrf_token']; 236 this.loading = false; 237 }.bind(this), 238 function(msg) { 239 this.error = msg; 240 this.loading = false; 241 }.bind(this)); 242 } 243 }); 244 </script> 245 </polymer-element> 246