veyron/examples/pipetobrowser: making data-grid responsive and polishing the
data-grid and vLog plugin UIs.

data-grid component is now responsive by reducing width and hiding columns
as available space shrinks. The responsive behaviour can be controlled by
the flex, minFlex and priority attributes on the grid-column component.
When needed, grid automatically starts reducing width until it hits minFlex
for each column at which point if it needs to reduce width further, it hides
columns. Priority attribute specifies the order of columns in which 
developer wants them to be reduced or hidden.

Since columns can be truncated/hidden, each row now has a "more info"
action which opens a modal dialog with all the data displayed for that row.

UI polish includes: Search tools are now housed in a collapse panel. Color
and spacing adjustments. live search. icons for log levels.

Change-Id: Iece0a02841ec51f9671abfe5ce64a2388bfbf301
diff --git a/examples/pipetobrowser/browser/libs/css/common-style.css b/examples/pipetobrowser/browser/libs/css/common-style.css
new file mode 100644
index 0000000..62bc38c
--- /dev/null
+++ b/examples/pipetobrowser/browser/libs/css/common-style.css
@@ -0,0 +1,28 @@
+.hidden {
+  display: none !important;
+}
+
+.secondary-text {
+  color: rgba(0,0,0,.54);
+}
+
+.no-wrap {
+  white-space: nowrap;
+}
+
+.screen-reader {
+  position: absolute;
+  top: -1000px;
+  left: -1000px;
+  width: 0px !important;
+  height: 0px !important;
+}
+
+@-webkit-keyframes blink {
+  0% {
+    opacity: 1;
+  }
+  100% {
+    opacity: 0.05;
+  }
+}
diff --git a/examples/pipetobrowser/browser/libs/ui-components/blackhole/component.html b/examples/pipetobrowser/browser/libs/ui-components/blackhole/component.html
index 6ad8264..58a9cc6 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/blackhole/component.html
+++ b/examples/pipetobrowser/browser/libs/ui-components/blackhole/component.html
@@ -5,7 +5,7 @@
 -->
 <polymer-element name="p2b-blackhole">
   <template>
-    <link rel="stylesheet" href="../common/common.css">
+    <link rel="stylesheet" href="/libs/css/common-style.css">
     <link rel="stylesheet" href="component.css">
     <img class="spinner {{ !running ? 'hidden' : '' }}" src="{{ running ? 'libs/ui-components/common/spinner.gif' : '' }}" alt="Represents a blackhole destroying objects falling into it."/>
     <cite class="attribution">Photo from Wikipedia <a target="_blank" href="http://en.wikipedia.org/wiki/Black_hole#mediaviewer/File:BH_LMC.png">by Alan R</a> (CC BY-SA 2.5)</cite>
diff --git a/examples/pipetobrowser/browser/libs/ui-components/common/common.css b/examples/pipetobrowser/browser/libs/ui-components/common/common.css
deleted file mode 100644
index 23f4105..0000000
--- a/examples/pipetobrowser/browser/libs/ui-components/common/common.css
+++ /dev/null
@@ -1,3 +0,0 @@
-.hidden {
-  display: none !important;
-}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/common.css b/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/common.css
new file mode 100644
index 0000000..bacc586
--- /dev/null
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/common.css
@@ -0,0 +1,14 @@
+.filter-container {
+  margin-bottom: 1.5em;
+}
+
+.filter-container h3 {
+  margin: 0;
+  margin-bottom: -10px;
+}
+
+.filter-container h3 {
+  font-size: 1em;
+  color: #9e9e9e;
+  font-weight: normal;
+}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/select/component.css b/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/select/component.css
index e69de29..a01a3bc 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/select/component.css
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/select/component.css
@@ -0,0 +1,19 @@
+paper-checkbox, paper-radio-button {
+  padding: 16px 16px 0px 12px !important;
+}
+
+paper-checkbox::shadow #ink[checked] {
+  color: #4285f4;
+}
+
+paper-checkbox::shadow #checkbox.checked {
+  border-color: #4285f4;
+}
+
+paper-radio-button::shadow #ink[checked] {
+  color: #e91e63;
+}
+
+paper-radio-button::shadow #onRadio {
+  background-color: #e91e63;
+}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/select/component.html b/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/select/component.html
index f005eb3..7419829 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/select/component.html
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/select/component.html
@@ -2,11 +2,13 @@
 <link rel="import" href="/libs/vendor/polymer/paper-checkbox/paper-checkbox.html">
 <link rel="import" href="/libs/vendor/polymer/paper-radio-button/paper-radio-button.html">
 <link rel="import" href="/libs/vendor/polymer/paper-radio-group/paper-radio-group.html">
-<polymer-element name="p2b-grid-filter-select" attributes="multiple key" grid-filter expects-grid-state>
+<polymer-element name="p2b-grid-filter-select" attributes="multiple key label" grid-filter expects-grid-state>
   <template>
     <link rel="stylesheet" href="component.css">
+    <link rel="stylesheet" href="../common.css">
     <content id="content" select="*"></content>
-    <div>
+    <div class="filter-container">
+      <h3>{{label}}</h3>
       <template if="{{ multiple }}" bind>
         <core-selector id="multiSelector" multi selectedAttribute="checked" valueattr="value" core-select="{{updateGridState}}" selected="{{ selected }}">
           <template repeat="{{ item in items }}">
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/toggle/component.css b/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/toggle/component.css
index e69de29..eb2aa4b 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/toggle/component.css
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/toggle/component.css
@@ -0,0 +1,3 @@
+paper-toggle-button {
+  padding: 16px 16px 0px 12px !important;
+}
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/toggle/component.html b/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/toggle/component.html
index 70b8bfc..dabe0bc 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/toggle/component.html
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/filter/toggle/component.html
@@ -3,7 +3,11 @@
 <polymer-element name="p2b-grid-filter-toggle" attributes="key checked label" grid-filter expects-grid-state>
   <template>
     <link rel="stylesheet" href="component.css">
-    <paper-toggle-button id="toggle" on-change="{{ updateGridState }}" checked?="{{ checked }}"></paper-toggle-button>
+    <link rel="stylesheet" href="../common.css">
+    <div class="filter-container">
+      <h3>{{label}}</h3>
+      <paper-toggle-button id="toggle" on-change="{{ updateGridState }}" checked?="{{ checked }}"></paper-toggle-button>
+    </div>
   </template>
   <script>
     Polymer('p2b-grid-filter-toggle', {
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/cell/renderer.css b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/cell/renderer.css
index e69de29..4ee59db 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/cell/renderer.css
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/cell/renderer.css
@@ -0,0 +1,9 @@
+.cell {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  padding: 0.75em 0.5em;
+}
+
+:host {
+  overflow: hidden;
+}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/cell/renderer.html b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/cell/renderer.html
index fd2a2cb..200c998 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/cell/renderer.html
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/cell/renderer.html
@@ -1,8 +1,11 @@
 <link rel="import" href="/libs/vendor/polymer/polymer/polymer.html">
-<polymer-element name="p2b-grid-cell-renderer" extends="td">
+<polymer-element name="p2b-grid-cell-renderer" extends="td" attributes="data">
   <template>
     <link rel="stylesheet" href="renderer.css">
-    <content></content>
+    <link rel="stylesheet" href="/libs/css/common-style.css">
+    <div class="cell {{ {'secondary-text': !data.primary, 'no-wrap': !data.wrap} | tokenList }}">
+      <content></content>
+    </div>
   </template>
   <script>
    /*
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/component.html b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/component.html
index d2067a2..40e87d2 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/component.html
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/component.html
@@ -1,5 +1,5 @@
 <link rel="import" href="/libs/vendor/polymer/polymer/polymer.html">
-<polymer-element name="p2b-grid-column" grid-column attributes="label sortable key">
+<polymer-element name="p2b-grid-column" grid-column attributes="label sortable key primary wrap flex minFlex priority">
   <script>
     Polymer('p2b-grid-column', {
       /*
@@ -9,12 +9,52 @@
       label: '',
 
       /*
+       * number specifying how flexible the width of the column is
+       * compared to other columns. For instance for a grid with three columns
+       * flex values of 1, 3, 1. means the middle column needs to be three times
+       * as wide as the other two.
+       * Flex value of 0 means the column should not be displayed.
+       * Flex values for all the columns can add up to any value.
+       * @type {integer}
+       */
+      flex: 1,
+
+      /*
+       * minimum Flex value that this column can be reduced to by the responsive data grid
+       * Defaults to 1 meaning column can be reduced to 1 flex as available space shrinks.
+       * @type {integer}
+       */
+      minFlex: 1,
+
+      /*
+       * specifies the importance of this column. Responsive grid uses this number
+       * to decide which columns to reduce/hide when available space shrinks.
+       * Lower number means more important.
+       * @type {integer}
+       */
+      priority: 1,
+
+      /*
        * whether this column is sortable
        * @type {boolean}
        */
       sortable: false,
 
       /*
+       * whether this the primary column of the grid.
+       * Normally there is a single column that other columns are dependents on
+       * @type {boolean}
+       */
+      primary: false,
+
+
+      /*
+       * whether text inside the cells of this columns are allowed to wrap.
+       * @type {boolean}
+       */
+      wrap: false,
+
+      /*
        * Key that will be pass as sort.key to fetch() function of your data source.
        * @type {string}
        */
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/renderer.css b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/renderer.css
index e69de29..b87be43 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/renderer.css
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/renderer.css
@@ -0,0 +1,26 @@
+:host {
+  color: rgba(0,0,0, 0.26);
+  font-weight: normal;
+  text-align: left;
+  white-space: nowrap;
+}
+
+paper-button {
+  text-align: left;
+  width: 100%;
+  text-transform: none;
+}
+
+paper-button[disabled] {
+  background: inherit !important;
+  color: inherit !important;
+}
+
+paper-button[disabled] {
+  background: inherit !important;
+  color: inherit !important;
+}
+
+paper-button::shadow #ripple {
+  color: #0f9d58;
+}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/renderer.html b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/renderer.html
index 7b57b8a..5a70ce6 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/renderer.html
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/column/renderer.html
@@ -1,31 +1,47 @@
 <link rel="import" href="/libs/vendor/polymer/polymer/polymer.html">
-<polymer-element name="p2b-grid-column-renderer" extends="th" attributes="data gridState" expects-grid-state on-tap="{{ updateGridState }}">
+<link rel="import" href="/libs/vendor/polymer/paper-button/paper-button.html">
+<polymer-element name="p2b-grid-column-renderer" extends="th" attributes="data gridState" expects-grid-state>
   <template>
     <link rel="stylesheet" href="renderer.css">
-    <span> {{ data.label }}</span>
-    <template if="{{ data.sortable && gridState.sort.key == data.key }}">
-
-      <template if="{{ gridState.sort.ascending }}">
-        <span>▲</span>
-      </template>
-
-      <template if="{{ !gridState.sort.ascending }}">
-        <span>▼</span>
-      </template>
-    </template>
-
+    <paper-button label="{{ formattedLabel }}" disabled?="{{!data.sortable}}" on-tap="{{ updateGridState }}"></paper-button>
   </template>
   <script>
    /*
     * @private
     */
     Polymer('p2b-grid-column-renderer', {
+      'observe': {
+        'data.flex' : 'updateWidth',
+        'data.totalFlex' : 'updateWidth'
+      },
+
+      domReady: function() {
+        this.updateWidth();
+      },
+
+      updateWidth: function() {
+        // calculate the width value based on flex and total flex of the whole grid.
+        this.style.width = (this.data.flex / this.data.totalFlex) * 100 + '%';
+      },
+
       updateGridState:function() {
         if( !this.data.sortable ) {
           return;
         }
         this.gridState.sort.ascending = !this.gridState.sort.ascending;
         this.gridState.sort.key = this.data.key;
+      },
+
+      get formattedLabel() {
+        if (!this.data.sortable || this.gridState.sort.key != this.data.key) {
+          return this.data.label;
+        }
+
+        if (this.gridState.sort.ascending) {
+          return this.data.label + ' \u21A7'; // up wedge unicode character
+        } else {
+          return this.data.label + ' \u21A5'; // down wedge unicode character
+        }
       }
     });
   </script>
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/component.css b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/component.css
index e69de29..8a2cebe 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/component.css
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/component.css
@@ -0,0 +1,73 @@
+table {
+  border-collapse: collapse;
+  table-layout: fixed;
+  width: 100%;
+  border-spacing: 0;
+  margin-top: 15px;
+}
+
+thead tr {
+  border-bottom: solid 1px rgba(0,0,0, .12);
+  padding-bottom: 0.75em;
+}
+
+thead tr th {
+  position: relative;
+}
+
+td {
+  overflow: hidden;
+  vertical-align: top;
+}
+
+table tbody tr:nth-child(2) td {
+  padding-top: 15px;
+}
+
+.more-icon {
+  fill: #0a7e07;
+}
+
+paper-dialog {
+  width: 50%;
+}
+
+/* hack: wrong z-index in shadow of paper-dialog disables text selection in dialog */
+paper-dialog /deep/ #shadow {
+  z-index: -1;
+}
+
+.more-dialog-content .heading {
+  font-size: 1.0em;
+  padding-top: 0.2em;
+  padding-bottom: 0.2em;
+  color: #4285f4;
+  border-bottom: 1px solid rgba(0,0,0,0.05);
+  font-weight: normal;
+  text-transform: uppercase;
+  margin: 0;
+}
+
+.more-dialog-content .details {
+  margin-bottom: 1em;
+}
+
+.search-fab {
+  position: absolute;
+  right: 20px;
+  top: 10px;
+  background-color: #03a9f4;
+}
+
+#searchTools {
+  box-shadow: rgba(0, 0, 0, 0.14902) 2px 2px 4px;
+  background-color: #f5f5f5;
+  padding: 1em;
+  padding-bottom: 0;
+}
+
+.result-count {
+  font-size: 0.8em;
+  color: #616161;
+  float: right;
+}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/component.html b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/component.html
index 178f529..526e44e 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/component.html
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/grid/component.html
@@ -1,23 +1,34 @@
 <link rel="import" href="/libs/vendor/polymer/polymer/polymer.html">
+<link rel="import" href="/libs/vendor/polymer/paper-icon-button/paper-icon-button.html">
+<link rel="import" href="/libs/vendor/polymer/paper-dialog/paper-dialog.html">
+<link rel="import" href="/libs/vendor/polymer/paper-dialog/paper-dialog-transition.html">
+<link rel="import" href="/libs/vendor/polymer/paper-fab/paper-fab.html">
+<link rel="import" href="/libs/vendor/polymer/core-collapse/core-collapse.html">
 <link rel="import" href="/libs/ui-components/data-grid/grid/row/renderer.html">
 <link rel="import" href="/libs/ui-components/data-grid/grid/cell/renderer.html">
 <link rel="import" href="/libs/ui-components/data-grid/grid/column/renderer.html">
 
 <polymer-element name="p2b-grid" attributes="summary dataSource defaultSortKey defaultSortAscending">
   <template>
+    <link rel="stylesheet" href="/libs/css/common-style.css">
     <link rel="stylesheet" href="component.css">
     <div id="templates"></div>
-    <div>
-      <content select="[grid-search]"></content>
-    </div>
-    <div>
-      <content select="[grid-filter]"></content>
-    </div>
-    <div>{{ dataSourceResult.length }} items</div>
-    <table summary="{{ summary }}">
+    <core-collapse id="searchTools">
+      <div class="result-count">Showing {{ dataSourceResult.length }} items</div>
+      <div>
+        <content select="[grid-search]"></content>
+      </div>
+      <div>
+        <content select="[grid-filter]"></content>
+      </div>
+    </core-collapse>
+    <table id="table" summary="{{ summary }}" cellpadding="0" cellpadding="0" border="0"  style="visibility:hidden" >
       <thead>
         <tr>
           <th is="p2b-grid-column-renderer" gridState="{{ gridState }}" data="{{ col.columnData }}" repeat="{{ col in columns }}" template></th>
+          <th style="width:40px">&nbsp;<span class="screen-reader">More info</span>
+            <paper-fab class="search-fab" focused icon="search" on-tap="{{ toggleSearchTools }}"></paper-fab>
+          </th>
         </tr>
       </thead>
       <tbody>
@@ -28,12 +39,31 @@
          W3C Spec bug: https://www.w3.org/Bugs/Public/show_bug.cgi?id=15616
          -->
         <tr is="p2b-grid-row-renderer" repeat="{{ item in dataSourceResult }}" template>
-          <td is="p2b-grid-cell-renderer" repeat="{{ col in columns }}" template>
+          <td is="p2b-grid-cell-renderer" data="{{ col.columnData }}" repeat="{{ col in columns }}" template>
             <template ref="{{ col.cellTemplateId }}" bind></template>
           </td>
+          <td>
+            <paper-icon-button on-tap="{{ showMoreInfo }}" class="more-icon" icon="more-vert" title="more info"></paper-icon-button
+            >
+          </td>
         </tr>
       </tbody>
     </table>
+
+    <!-- Dialog that displays all columns and their values when more info icon activated -->
+    <paper-dialog layered id="dialog" heading="Details" transition="paper-dialog-transition-bottom">
+      <template id="moreInfoTemplate" bind>
+        <div class="more-dialog-content">
+          <template repeat="{{ item in selectedItems }}">
+            <template repeat="{{ col in columns }}">
+              <h3 class="heading">{{ col.columnData.label }}</h3>
+              <div class="details"><template ref="{{ col.cellTemplateId }}" bind></template></div>
+            </template>
+          </template>
+        </div>
+      </template>
+    </paper-dialog>
+
   </template>
   <script>
     /*
@@ -113,6 +143,16 @@
        */
       defaultSortAscending: false,
 
+      showMoreInfo: function(e) {
+        // quirk + hack: cheating here and breaking shadow dom boundaries
+        // since paper-dialog does not support backdrop yet
+        this.$.dialog.shadowRoot.querySelector('#overlay').backdrop = true;
+
+        var item = e.target.templateInstance.model.item;
+        this.selectedItems = [item];
+        this.$.dialog.opened = true;
+      },
+
       ready: function() {
 
         // private property fields
@@ -138,8 +178,22 @@
         this.initTemplates(); // loads cell templates
         this.initGridStateDependents(); //  initialize filters and search
         this.initGridStateObserver(); // observe changes to grid state by filters
+
       },
 
+      /*
+       * Called by Polymer when DOM is read.
+       * @private
+       */
+      domReady: function() {
+        this.adjustFlexWidths();
+        this.$.table.style.visibility = 'visible';
+      },
+
+      /*
+       * Called by Polymer when dataSource attribute changes.
+       * @private
+       */
       dataSourceChanged: function() {
         this.refresh();
       },
@@ -169,18 +223,50 @@
        * @private
        */
       initTemplates: function() {
+        var self = this;
         var columnNodes = this.querySelectorAll('[grid-column]');
+        var totalFlex = 0;
         for (var i = 0; i < columnNodes.length; i++) {
           var col = columnNodes[i];
           var cellTemplate = col.querySelector('template');
+          this.originalContext = cellTemplate.model;
           var cellTemplateId = "userProvidedCellTemplate" + i;
           cellTemplate.id = cellTemplateId;
           this.$.templates.appendChild(cellTemplate);
+          totalFlex += col.flex;
+          col.origFlex = col.flex;
           this.columns.push({
             cellTemplateId: cellTemplateId,
             columnData: col
           });
         }
+
+        // add up the total value of flex attribute on each column and add it to data
+        this.columns.forEach(function(c) {
+          c.columnData.totalFlex = totalFlex;
+        });
+
+        // readjust the widths on resize
+        var previousTableWidth = self.$.table.offsetWidth;
+        onResizeHandler = function() {
+          var newWidth = self.$.table.offsetWidth;
+          if (newWidth != previousTableWidth) {
+            self.adjustFlexWidths();
+          }
+          previousTableWidth = newWidth;
+        };
+
+        // quirks: since there is no good way to know if width changes, we pull.
+        // window.resize does not cover all resize cases
+        this.resizeInterval = setInterval(onResizeHandler, 50);
+      },
+
+      /*
+       * Called by Polymer when DOM is gone. We need to unbind custom event listeners here.
+       * @private
+       */
+      detached: function() {
+        clearInterval(this.resizeInterval);
       },
 
       /*
@@ -206,6 +292,80 @@
       },
 
       /*
+       * Performs responsive changes for the grid.
+       * Values of flex, minFlex and priority attributes on the grid column decides
+       * the responsive behavior.
+       * Grid assumes the original total number of columns can fit on a 768px width,
+       * if width of the grid container is less than that, then it starts to reduce
+       * flex values for each columns in reverse priority one by one until it reaches
+       * the minFlex value for all columns.
+       * If it still needs to reduce the width of the table at this point, it starts hiding
+       * columns in reverse priority order.
+       */
+      adjustFlexWidths: function() {
+        var minWidth = 768;
+        var tableWidth = this.$.table.offsetWidth;
+
+        if (tableWidth >= minWidth) {
+          return;
+        }
+
+        // reset to original flex values
+        for (var i = 0; i < this.columns.length; i++) {
+          var col = this.columns[i];
+          col.columnData.flex = col.columnData.origFlex;
+        }
+
+        // total of all flex values from all columns
+        var totalFlex = this.columns.reduce( function(prev, col) {
+          return prev + col.columnData.flex;
+        }, 0);
+
+        // number of pixels per flex point
+        var pixelPerFlex = Math.floor(tableWidth / totalFlex);
+        // number of flex points we need to eliminate to same pixelPerFlex as the minWidth case
+        var numFlexToEliminate = Math.ceil((minWidth - tableWidth) / pixelPerFlex);
+
+        // sort from least important to most important
+        var sortedColumnsData = this.columns.map(function(col) {
+          return col.columnData
+        }).sort(function(a, b) {
+          return b.priority - a.priority;
+        });
+
+        // first try to reduce each flex value until we hit min-flex for each column
+        var numElimintedFlex = 0
+        var numIrreducableColumns = 0;
+        var numColumns = sortedColumnsData.length;
+        while (numElimintedFlex < numFlexToEliminate && numIrreducableColumns < numColumns) {
+          for (var i = 0; i < numColumns; i++) {
+            var col = sortedColumnsData[i];
+            if (col.flex > col.minFlex) {
+              col.flex--;
+              numElimintedFlex++;
+            } else {
+              numIrreducableColumns++;
+            }
+          }
+        }
+
+        // if still need to reduce, start eliminating whole columns based on priority
+        // never eliminate the top priority column, hence only iterate to numColumns - 1
+        if (numElimintedFlex < numFlexToEliminate) {
+          for (var i = 0; i < numColumns - 1 && numElimintedFlex < numFlexToEliminate; i++) {
+            var col = sortedColumnsData[i];
+            numElimintedFlex += col.flex;
+            col.flex = 0;
+          }
+        }
+
+        // update the new totalFlex for each column
+        this.columns.forEach(function(c) {
+          c.columnData.totalFlex = totalFlex - numFlexToEliminate;
+        });
+      },
+
+      /*
        * dataSourceResult is what the UI binds to and integrate over.
        * Only fetches data if scheduled to do so
        * @private
@@ -224,6 +384,14 @@
         this.shouldRefetchData = false;
 
         return this.cachedDataSourceResult;
+      },
+
+      /*
+       * collapse/show search and filter container.
+       * @private
+       */
+      toggleSearchTools: function() {
+        this.$.searchTools.toggle();
       }
     });
   </script>
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/search/component.css b/examples/pipetobrowser/browser/libs/ui-components/data-grid/search/component.css
index e69de29..ba87339 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/search/component.css
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/search/component.css
@@ -0,0 +1,4 @@
+paper-input {
+  width: 50%;
+  color: #9e9e9e;
+}
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/libs/ui-components/data-grid/search/component.html b/examples/pipetobrowser/browser/libs/ui-components/data-grid/search/component.html
index 3ede3b1..0418d40 100644
--- a/examples/pipetobrowser/browser/libs/ui-components/data-grid/search/component.html
+++ b/examples/pipetobrowser/browser/libs/ui-components/data-grid/search/component.html
@@ -3,7 +3,7 @@
 <polymer-element name="p2b-grid-search" grid-search expects-grid-state attributes="label">
   <template>
     <link rel="stylesheet" href="component.css">
-    <paper-input on-change="{{ updateGridState }}" id="search" label="{{ label }}"></paper-input>
+    <paper-input inputValue="{{ value }}" id="search" label="{{ label }}"></paper-input>
   </template>
   <script>
     /*
@@ -15,8 +15,8 @@
        * @type {string}
        */
       label: '',
-      updateGridState: function() {
-        this.gridState.search.keyword = this.$.search.value.trim();
+      valueChanged: function() {
+        this.gridState.search.keyword = this.value;
       }
     });
   </script>
diff --git a/examples/pipetobrowser/browser/pipe-viewers/builtin/common/common.css b/examples/pipetobrowser/browser/pipe-viewers/builtin/common/common.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/examples/pipetobrowser/browser/pipe-viewers/builtin/common/common.css
diff --git a/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/component.css b/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/component.css
index b0b01e3..cfbfeee 100644
--- a/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/component.css
+++ b/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/component.css
@@ -1,7 +1,29 @@
-::shadow /deep/ .lineNumber::before {
+::shadow /deep/ .line-number::before {
   content: '#';
 }
-::shadow /deep/ .lineNumber {
+::shadow /deep/ .line-number {
   color: rgb(51, 103, 214);
   margin-left: 0.1em;
+  font-size: 0.8em;
+}
+
+::shadow /deep/ .message-text {
+  word-break: break-word;
+}
+
+::shadow /deep/ .level-icon.error {
+  fill: #e51c23;
+}
+
+::shadow /deep/ .level-icon.warning {
+  fill: #f57c00;
+}
+
+::shadow /deep/ .level-icon.info {
+  fill: #689f38;
+}
+
+::shadow /deep/ .level-icon.fatal {
+  fill: #bf360c;
+  -webkit-animation: blink 0.6s infinite alternate;
 }
diff --git a/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/component.html b/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/component.html
index 7f31ef6..972c7cc 100644
--- a/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/component.html
+++ b/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/component.html
@@ -1,4 +1,5 @@
 <link rel="import" href="/libs/vendor/polymer/polymer/polymer.html">
+<link rel="import" href="/libs/vendor/polymer/core-icon/core-icon.html">
 <link rel="import" href="/libs/ui-components/data-grid/grid/component.html">
 <link rel="import" href="/libs/ui-components/data-grid/grid/column/component.html">
 <link rel="import" href="/libs/ui-components/data-grid/filter/select/component.html">
@@ -8,6 +9,7 @@
 
 <polymer-element name="p2b-plugin-vlog">
   <template>
+    <link rel="stylesheet" href="/libs/css/common-style.css">
     <link rel="stylesheet" href="component.css">
 
     <p2b-grid id="grid" defaultSortKey="date" defaultSortAscending dataSource="{{ dataSource }}" summary="Data Grid displaying veyron log items in a tabular format with filters and search options.">
@@ -16,7 +18,7 @@
       <p2b-grid-search label="Search Logs"></p2b-grid-search>
 
       <!-- Filter to select log level (multiple allowed) -->
-      <p2b-grid-filter-select multiple key="level" label="Levels">
+      <p2b-grid-filter-select multiple key="level" label="Show levels">
         <p2b-grid-filter-select-item checked label="Fatal" value="fatal"></p2b-grid-filter-select-item>
         <p2b-grid-filter-select-item checked label="Error" value="error"></p2b-grid-filter-select-item>
         <p2b-grid-filter-select-item checked label="Warning" value="warning"></p2b-grid-filter-select-item>
@@ -24,7 +26,7 @@
       </p2b-grid-filter-select>
 
       <!-- Filter to select date range -->
-      <p2b-grid-filter-select key="date" label="Date">
+      <p2b-grid-filter-select key="date" label="Logs since">
         <p2b-grid-filter-select-item checked label="Any time" value="all"></p2b-grid-filter-select-item>
         <p2b-grid-filter-select-item label="Past 1 hour" value="1"></p2b-grid-filter-select-item>
         <p2b-grid-filter-select-item label="Past 24 hours" value="24"></p2b-grid-filter-select-item>
@@ -34,20 +36,22 @@
       <p2b-grid-filter-toggle key="autorefresh" label="Live Refresh" checked></p2b-grid-filter-toggle>
 
       <!-- Columns, sorting and cell templates -->
-      <p2b-grid-column sortable label="Level" key="level">
-        <template>{{ item.level }}</template>
+      <p2b-grid-column label="Level" key="level" sortable flex="1" priority="2" >
+        <template>
+          <core-icon class="level-icon {{ item.level }}" icon="{{ item.icon }}" title="{{item.level}}"></core-icon>
+        </template>
       </p2b-grid-column>
-      <p2b-grid-column sortable label="File" key="file">
-        <template>{{ item.file }}<span class="lineNumber">{{ item.fileLine }}</template>
+      <p2b-grid-column label="File" key="file" sortable flex="3" minFlex="2" priority="4" >
+        <template>{{ item.file }}<span class="line-number">{{ item.fileLine }}</span></template>
       </p2b-grid-column>
-      <p2b-grid-column label="Message" key="message">
-        <template>{{ item.message }}</template>
+      <p2b-grid-column label="Message" key="message" primary flex="7" minFlex="5" priority="1" >
+        <template><div class="message-text">{{ item.message }}</div></template>
       </p2b-grid-column>
-      <p2b-grid-column sortable label="Date" key="date">
-        <template>{{ item.date }}</template>
+      <p2b-grid-column label="Date" key="date" sortable flex="5" minFlex="3" priority="3">
+        <template><span class="smaller-text">{{ item.date }}</span></template>
       </p2b-grid-column>
-      <p2b-grid-column sortable label="threadid" key="threadid">
-        <template>{{ item.threadid }}</template>
+      <p2b-grid-column label="Threadid" key="threadid" sortable flex="0" priority="5">
+        <template>{{ item.threadId }}</template>
       </p2b-grid-column>
 
     </p2b-grid>
diff --git a/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/plugin.js b/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/plugin.js
index 28ff69c..dfb2dbd 100644
--- a/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/plugin.js
+++ b/examples/pipetobrowser/browser/pipe-viewers/builtin/vlog/plugin.js
@@ -10,7 +10,6 @@
 import { PipeViewer } from 'pipe-viewer';
 import { vLogDataSource } from './data-source';
 import { Logger } from 'logger'
-
 var log = new Logger('pipe-viewers/builtin/vlog');
 
 var streamUtil = require('event-stream');
@@ -30,23 +29,53 @@
     // create a new data source from the stream and set it.
     logView.dataSource = new vLogDataSource(
       stream,
-      function onNewItem() {
+      function onNewItem(item) {
         // also refresh the grid when new data comes in.
         // grid component batches requests and refreshes UI on the next animation frame.
         logView.refreshGrid();
+
+        // add additional, UI related properties to the item
+        addAdditionalUIProperties(item);
       },
       function onError(err) {
         log.debug(err);
       });
 
-    // also refresh the grid when new data comes in.
-    // grid component batches requests and refreshes UI on the next animation frame.
-    stream.on('data', () => {
-      logView.refreshGrid();
-    });
-
     return new View(logView);
   }
 }
 
+/*
+ * Adds additional UI specific properties to the item
+ * @private
+ */
+function addAdditionalUIProperties(item) {
+  addIconProperty(item);
+}
+
+/*
+ * Adds an icon property to the item specifying what icon to display
+ * based on log level
+ * @private
+ */
+function addIconProperty(item) {
+  var iconName = 'info';
+  switch (item.level) {
+    case 'info':
+      iconName = 'info-outline';
+      break;
+    case 'warning':
+      iconName = 'warning';
+      break;
+    case 'error':
+      iconName = 'info';
+      break;
+    case 'fatal':
+      iconName = 'block';
+      break;
+  }
+
+  item.icon = iconName;
+}
+
 export default vLogPipeViewer;
\ No newline at end of file
diff --git a/examples/pipetobrowser/browser/views/page/component.css b/examples/pipetobrowser/browser/views/page/component.css
index 08ade2f..cecfd1c 100644
--- a/examples/pipetobrowser/browser/views/page/component.css
+++ b/examples/pipetobrowser/browser/views/page/component.css
@@ -1,6 +1,6 @@
 :host {
   font-family: 'Roboto', sans-serif;
-  color: #252525;
+  color: rgba(0,0,0,0.87);
 }
 
 [drawer] {