Home | History | Annotate | Download | only in elements
      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