Improves zuul-status design

* This redesigns it so that it's more spread out and uses icons
   where necessary.

This design is based on @guillaum design and so all credits go to him
for the design.

Change-Id: I8015dce97af43b3ba5f75d4122f82c7be06f9ec7
diff --git a/src/main/resources/static/zuul-status-view.html b/src/main/resources/static/zuul-status-view.html
index a6063b9..e50beab 100644
--- a/src/main/resources/static/zuul-status-view.html
+++ b/src/main/resources/static/zuul-status-view.html
@@ -14,7 +14,7 @@
 
 <dom-module id="zuul-status-view">
   <template>
-    <style>
+    <style include="shared-styles">
       #view-container {
         display: block;
       }
@@ -41,8 +41,8 @@
         overflow: hidden;
         height: 20px;
         margin-bottom: 20px;
-        background-color: #f5f5f5;
-        border-radius: 4px;
+        background-color: #ededed;
+        border-radius: 1px;
         -webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
         box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
       }
@@ -50,87 +50,86 @@
         float: left;
         width: 0;
         height: 100%;
-        font-size: 12px;
+        font-size: 11px;
         line-height: 20px;
         color: #fff;
         text-align: center;
-        background-color: #428bca;
+        background-color: #39a5dc;
         -webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);
         box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);
         -webkit-transition: width .6s ease;
+        -o-transition: width .6s ease;
         transition: width .6s ease;
       }
-      .zuul-job-result {
-        float: right;
-        width: 70px;
-        height: 15px;
-        margin: 2px 0 0 0;
-      }
       #progressBar {
         width: var(--progress-bar-width, 0%);
       }
-      .genericList th {
-        white-space: nowrap;
-      }
-      .genericList th,
-      .genericList td {
-        padding-right: 1rem;
-      }
-      .genericList tr th:first-of-type,
-      .genericList tr td:first-of-type {
-        padding-left: 1rem;
-      }
-      .genericList td {
-        flex-shrink: 0;
-      }
-      .genericList .topHeader {
-        color: var(--primary-text-color);
-        font-weight: var(--font-weight-bold);
-        text-align: left;
-        vertical-align: middle
-      }
-      .genericList a {
-        color: var(--primary-text-color);
-        text-decoration: none;
-      }
-      .genericList a:hover {
-        text-decoration: underline;
-      }
       #list {
         padding-bottom: 1em;
       }
-      .zuul-job-result {
-        float: right;
-        width: 70px;
-        height: 15px;
-        margin: 2px 0 0 0;
-      }
-      .label {
+      .labels {
         display: inline;
         padding: .2em .6em .3em;
-        font-size: 75%;
-        font-weight: 700;
+        font-size: 100%;
+        font-weight: 600;
         line-height: 1;
         color: #fff;
         text-align: center;
         white-space: nowrap;
         vertical-align: baseline;
-        border-radius: .25em;
+        border-radius: 0;
       }
       .label-danger {
-        background-color: #d9534f;
+        background-color: #c00;
       }
       .label-default {
-        background-color: #999;
+        background-color: #9c9c9c;
       }
       .label-info {
-        background-color: #5bc0de;
+        background-color: #00659c;
       }
       .label-success {
-        background-color: #5cb85c;
+        background-color: #3f9c35;
       }
       .label-warning {
-        background-color: #f0ad4e;
+        background-color: #ec7a08;
+      }
+      .zuul-job-result {
+        float: right;
+        width: 90px;
+        height: 20px;
+        margin: 2px 5px 0;
+        padding: 4px;
+      }
+      a {
+        color: var(--primary-text-color);
+        cursor: pointer;
+        display: inline-block;
+        text-decoration: none;
+      }
+      a:hover {
+        text-decoration: underline;
+      }
+      .time, {
+        align-items: center;
+        color: #757575;
+        display: flex;
+      }
+      #icon {
+        margin-right: 0.5em;
+      }
+    </style>
+    <style include="gr-change-list-styles">
+      :host {
+        font-size: var(--font-size-normal);
+      }
+      .padding {
+        width: var(--default-horizontal-margin);
+        padding: 0.5em;
+      }
+      #changeList {
+        border-collapse: collapse;
+        width: 100%;
       }
     </style>
     <template is="dom-if" if="[[zuulUrl]]">
@@ -150,51 +149,86 @@
         </div>
         <template is="dom-if" if="[[!zuulDisable]]" restamp="true">
           <div class="bottom container">
-            <table id="list" class="genericList">
-              <tr class="headerRow">
-                <th class="pipeline topHeader">Pipeline</th>
-                <th class="jobName topHeader">Job Name</th>
-                <th class="progressName topHeader">Progress</th>
-              </tr>
-              <tbody>
-                <template is="dom-repeat" items=[[_response]] as="response">
-                  <template is="dom-repeat" items=[[response.jobs]] as="jobs">
-                    <tr class="table">
-                      <td class="pipeline">
-                        [[jobs.pipeline]]
-                      </td>
-                      <td class="jobName">
-                        <a href="[[_computeReportURL(jobs)]]" target="_blank"
-                           hidden$="[[!jobs.name]]">
-                          [[jobs.name]]
-                        </a>
-                      </td>
-                      <td class="progressName">
-                        <template is="dom-if" if="[[_getResults(jobs, 'true', 'in progress')]]">
-                          <div class="progress zuul-job-result">
-                            <div class="progress-bar"
-                              id="progressBar"
-                              role="progressbar"
-                              aria-valuenow$="[[_progressPercent(jobs)]]"
-                              aria-valuemin="0"
-                              aria-valuemax="100"></div>
-                          </div>
-                        </template>
-                        <template is="dom-if" if="[[!_getResults(jobs, 'true', 'in progress')]]">
-                          <span class$="zuul-job-result label [[_renderJobStatusLabel(jobs)]]">
-                            [[_getResults(jobs)]]
-                          </span>
-                        </template>
-                      </td>
-                    </tr>
-                  </template>
+            <table id="changeList">
+              <template is="dom-repeat" items=[[_response]] as="response">
+                <tr class="groupHeader">
+                  <td class="padding">
+                    <template is="dom-if" if="[[!_isFailing(response)]]" restamp="true">
+                      <span class="fullStatus success">
+                        <iron-icon id="icon" icon="gr-icons:check" style="color: #388E3C;"></iron-icon>
+                      </span>
+                    </template>
+                    <template is="dom-if" if="[[_isFailing(response)]]" restamp="true">
+                      <span class="fullStatus failed">
+                        <iron-icon id="icon" icon="gr-icons:close" style="color: #D32F2F;"></iron-icon>
+                      </span>
+                    </template>
+                  </td>
+                  <td class="cell" colspan="15">[[response.name]]</td>
+                </tr>
+                <template is="dom-repeat" items=[[response.results.jobs]] as="jobs">
+                  <tr class="table">
+                    <td class="padding"></td>
+                    <td class="cell jobName">
+                      <iron-icon id="icon" icon="zuul-icons:code"></iron-icon>
+                      <a href="[[_computeReportURL(jobs)]]" target="_blank"
+                         hidden$="[[!jobs.name]]">
+                        [[jobs.name]]
+                      </a>
+                    </td>
+                    <td class="cell">
+                      <div class="time">
+                        <iron-icon id="icon" icon="zuul-icons:query-builder"></iron-icon>
+                        <div class="remainingTime">
+                          [[_getRemainingTime(response.results.remaining_time)]]
+                        </div>
+                      </div>
+                    </td>
+                    <td class="cell">
+                      <div class="time">
+                        <iron-icon id="icon" icon="zuul-icons:today"></iron-icon>
+                        <div class="enqueueTime">
+                          [[_getEnqueueTime(response.results.enqueue_time)]]
+                        </div>
+                      </div>
+                    </td>
+                    <td class="cell progressName">
+                      <template is="dom-if" if="[[_getResults(jobs, 'true', 'in progress')]]" restamp="true">
+                        <div class="progress zuul-job-result">
+                          <div class="progress-bar"
+                            id="progressBar"
+                            role="progressbar"
+                            aria-valuenow$="[[_progressPercent(jobs)]]"
+                            aria-valuemin="0"
+                            aria-valuemax="100"></div>
+                        </div>
+                      </template>
+                      <template is="dom-if" if="[[!_getResults(jobs, 'true', 'in progress')]]" restamp="true">
+                        <span class$="zuul-job-result labels [[_renderJobStatusLabel(jobs)]]">
+                          [[_getResults(jobs)]]
+                        </span>
+                      </template>
+                    </td>
+                  </tr>
                 </template>
-              </tbody>
+              </template>
             </table>
           </div>
         </template>
       </div>
     </template>
+    <iron-iconset-svg name="zuul-icons" size="24">
+      <svg>
+        <defs>
+          <!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/iron-icons.js -->
+          <g id="code"><path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"></path></g>
+          <!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/iron-icons.js -->
+          <g id="query-builder"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"></path></g>
+          <!-- This SVG is a copy from iron-icons https://github.com/PolymerElements/iron-icons/blob/master/iron-icons.js -->
+          <g id="today"><path d="M19 3h-1V1h-2v2H8V1H6v2H5c-1.11 0-1.99.9-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 16H5V8h14v11zM7 10h5v5H7z"></path></g>
+        </defs>
+      </svg>
+    </iron-iconset-svg>
   </template>
   <script src="zuul-status-view.js"></script>
 </dom-module>
diff --git a/src/main/resources/static/zuul-status-view.js b/src/main/resources/static/zuul-status-view.js
index 34475fa..105ebfe 100644
--- a/src/main/resources/static/zuul-status-view.js
+++ b/src/main/resources/static/zuul-status-view.js
@@ -17,6 +17,9 @@
  (function() {
   'use strict';
 
+  const DEFAULT_UPDATE_INTERVAL_MS = 1000 * 2;
+  const MAX_UPDATE_INTERVAL_MS = 1000 * 30 * 2;
+
   /**
    * Wrapper around localStorage to prevent using it if you have it disabled.
    *
@@ -55,9 +58,6 @@
     }
   }
 
-  const DEFAULT_UPDATE_INTERVAL_MS = 1000 * 2;
-  const MAX_UPDATE_INTERVAL_MS = 1000 * 30 * 2;
-
   Polymer({
     is: 'zuul-status-view',
     properties: {
@@ -156,18 +156,15 @@
     /**
      * Fetch current progress state and update properties.
      *
-     * If not all Tricium analyzers are finished yet, this will
-     * set a timeout to update again later.
-     *
-     * It is assumed that this will only be called if the Tricium
-     * host is configured.
-     *
      * @return {Promise} Resolves upon completion.
      */
     async _update() {
       try {
         const response = await this.getZuulStatus(this.change, this.revision);
-        this._response = response;
+        this._response = response.map((results, i) => ({
+          name: results.jobs[i].pipeline,
+          results,
+        }));
         this._updateIntervalMs = DEFAULT_UPDATE_INTERVAL_MS;
       } catch (err) {
         this._updateIntervalMs = Math.min(
@@ -352,5 +349,61 @@
 
       this.reload();
     },
+
+    _isFailing(results) {
+      if (results && results.results &&
+          results.results.failing_reasons.length !== 0) {
+        return true;
+      }
+
+      return false;
+    },
+
+    _getTime(ms, words) {
+      if (typeof (words) === 'undefined') {
+        words = false;
+      }
+      let seconds = (+ms) / 1000;
+      let minutes = Math.floor(seconds / 60);
+      let hours = Math.floor(minutes / 60);
+      seconds = Math.floor(seconds % 60);
+      minutes = Math.floor(minutes % 60);
+      let r = '';
+      if (words) {
+        if (hours) {
+          r += hours + ' hr ';
+        }
+        r += minutes + ' min';
+      } else {
+        if (hours < 10) {
+          r += '0';
+        }
+        r += hours + ':';
+        if (minutes < 10) {
+          r += '0';
+        }
+        r += minutes + ':';
+        if (seconds < 10) {
+          r += '0';
+        }
+        r += seconds;
+      }
+
+      return r;
+    },
+
+    _getRemainingTime(time) {
+      return time === null ?
+          'unknown' : this._getTime(time, true);
+    },
+
+    _getEnqueueTime(ms) {
+      // Special format case for enqueue time to add style
+      let hours = 60 * 60 * 1000;
+      let now = Date.now();
+      let delta = now - ms;
+
+      return this._getTime(delta, true);
+    },
   });
 })();