You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ro...@apache.org on 2015/10/21 17:02:11 UTC

[4/4] fauxton commit: updated refs/heads/master to 246057e

implement table layout option

 - refactor header
 - create new bulk-select component

PR: #543
PR-URL: https://github.com/apache/couchdb-fauxton/pull/543
Reviewed-By: Benjamin Keen <be...@gmail.com>
Reviewed-By: Michelle Phung <mi...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/246057e6
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/246057e6
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/246057e6

Branch: refs/heads/master
Commit: 246057e64ee0683a44f1c9c1ca1d74f75638a740
Parents: 852d6ae
Author: Robert Kowalski <ro...@apache.org>
Authored: Mon Sep 21 16:05:14 2015 +0200
Committer: Robert Kowalski <ro...@apache.org>
Committed: Wed Oct 21 17:01:40 2015 +0200

----------------------------------------------------------------------
 .../components/assets/less/bulk-selector.less   |   144 +
 .../components/assets/less/code-editor.less     |    12 +
 .../components/assets/less/components.less      |     1 +
 app/addons/components/assets/less/docs.less     |     2 +-
 .../assets/less/header-togglebutton.less        |     1 -
 .../components/react-components.react.jsx       |   102 +-
 app/addons/databases/assets/less/databases.less |     3 +
 app/addons/documents/assets/less/header.less    |    43 +-
 .../documents/assets/less/index-results.less    |    43 +
 app/addons/documents/header/header.actions.js   |    25 +-
 .../documents/header/header.actiontypes.js      |    10 +-
 app/addons/documents/header/header.react.jsx    |   208 +-
 app/addons/documents/header/header.stores.js    |    76 -
 .../documents/header/tests/headerSpec.react.jsx |   113 -
 app/addons/documents/index-results/actions.js   |    33 +-
 .../documents/index-results/actiontypes.js      |     5 +-
 .../index-results.components.react.jsx          |   240 +-
 app/addons/documents/index-results/stores.js    |   240 +-
 .../tests/index-results.actionsSpec.js          |    44 +-
 .../index-results.componentsSpec.react.jsx      |   185 +-
 .../tests/index-results.storesSpec.js           |   170 +-
 app/addons/documents/routes-documents.js        |     5 +-
 app/addons/documents/routes-index-editor.js     |    11 +-
 app/addons/documents/routes-mango.js            |    10 +-
 app/addons/documents/shared-resources.js        |    11 +-
 .../documents/tests/nightwatch/bulkDelete.js    |    14 +-
 .../documents/tests/nightwatch/bulkSelect.js    |    34 -
 .../tests/nightwatch/deletesDocuments.js        |     6 +-
 app/addons/documents/tests/routeSpec.js         |    20 -
 assets/js/libs/react-bootstrap.js               | 16265 +++++++++++++++++
 assets/less/variables.less                      |     2 +
 31 files changed, 17382 insertions(+), 696 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/components/assets/less/bulk-selector.less
----------------------------------------------------------------------
diff --git a/app/addons/components/assets/less/bulk-selector.less b/app/addons/components/assets/less/bulk-selector.less
new file mode 100644
index 0000000..b1cd405
--- /dev/null
+++ b/app/addons/components/assets/less/bulk-selector.less
@@ -0,0 +1,144 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#bulk-action-component-popover {
+  font-size: 13px;
+
+  i.icon {
+    margin-right: 10px;
+  }
+
+  ul {
+    margin: inherit;
+  }
+
+  li {
+    padding: 14px 15px;
+    line-height: 0;
+    cursor: pointer;
+    list-style-type: none;
+
+    &.disabled {
+      color: #cccccc;
+      cursor: default;
+      &:hover {
+        background-color: inherit;
+      }
+    }
+
+    &:hover {
+      background-color: #fbcece; // light red
+    }
+    &:last-child {
+      -webkit-border-bottom-right-radius: 5px;
+      -webkit-border-bottom-left-radius: 5px;
+      -moz-border-radius-bottomright: 5px;
+      -moz-border-radius-bottomleft: 5px;
+      border-bottom-right-radius: 5px;
+      border-bottom-left-radius: 5px;
+    }
+  }
+  .popover-title {
+    margin: -1px;
+  }
+
+  .popover {
+    left: 10px !important;
+
+    .arrow {
+      margin-left: -39px;
+    }
+  }
+
+  .popover-content {
+    padding: 0;
+  }
+}
+
+.bulk-action-component {
+  min-height: 43px;
+
+  button {
+    height: 26px;
+    width: 26px;
+    background-color: @background;
+    border: 1px solid @darkBorder;
+    margin-left: 7px;
+  }
+
+  .fonticon-trash:before {
+    font-size: 12px;
+    margin-left: 2px;
+    margin-top: 1px;
+  }
+
+  .separator {
+    border-left: 1px solid @darkBorder;
+    margin: 5px 0;
+    height: 15px;
+  }
+
+  .bulk-actions {
+    height: 27px;
+  }
+
+  .bulk-action-component-selector-group {
+
+    .fonticon {
+      font-size: 8px;
+      color: @darkBorder;
+      padding: 3px 0;
+    }
+
+  }
+
+  .bulk-action-component-panel {
+    input[type="checkbox"] {
+      margin: 6px;
+    }
+
+    border: 1px solid @darkBorder;
+
+    position: relative;
+    float: left;
+    div.arrow-button {
+      height: 24px;
+      width: 24px;
+      transform: rotate(90deg);
+      cursor: pointer;
+      i {
+        margin-left: 10px;
+      }
+    }
+  }
+
+  .bulk-actions {
+    margin-left: 10px;
+    width: 29px;
+
+    float: left;
+
+    .fonticon {
+      font-size: 11px;
+      border: 0;
+      background-color: transparent;
+      padding: 2px;
+      width: 13px;
+      margin-top: -5px;
+      color: @darkBorder;
+    }
+
+    button.disabled {
+      cursor: default;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/components/assets/less/code-editor.less
----------------------------------------------------------------------
diff --git a/app/addons/components/assets/less/code-editor.less b/app/addons/components/assets/less/code-editor.less
index 571882e..eff819b 100644
--- a/app/addons/components/assets/less/code-editor.less
+++ b/app/addons/components/assets/less/code-editor.less
@@ -1,3 +1,15 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
 .zen-editor-icon {
   float: right;
   font-size: 13px;

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/components/assets/less/components.less
----------------------------------------------------------------------
diff --git a/app/addons/components/assets/less/components.less b/app/addons/components/assets/less/components.less
index fcf8b21..d719075 100644
--- a/app/addons/components/assets/less/components.less
+++ b/app/addons/components/assets/less/components.less
@@ -17,3 +17,4 @@
 @import "docs.less";
 @import "loading-lines.less";
 @import "code-editor.less";
+@import "bulk-selector.less";

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/components/assets/less/docs.less
----------------------------------------------------------------------
diff --git a/app/addons/components/assets/less/docs.less b/app/addons/components/assets/less/docs.less
index 3f8a8f8..ed93f34 100644
--- a/app/addons/components/assets/less/docs.less
+++ b/app/addons/components/assets/less/docs.less
@@ -63,7 +63,7 @@
 
 .show-select {
   #doc-list {
-    padding: 30px 0 30px 0;
+    padding: 0px 0 30px 0;
     .custom-inputs {
       display: block;
       float: left;

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/components/assets/less/header-togglebutton.less
----------------------------------------------------------------------
diff --git a/app/addons/components/assets/less/header-togglebutton.less b/app/addons/components/assets/less/header-togglebutton.less
index b8e6e77..78da3db 100644
--- a/app/addons/components/assets/less/header-togglebutton.less
+++ b/app/addons/components/assets/less/header-togglebutton.less
@@ -56,7 +56,6 @@ button.header-control-box:focus {
   .icon, span {
     color: @linkColor;
   }
-
 }
 
 button.control-toggle-alternative-header {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/components/react-components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/react-components.react.jsx b/app/addons/components/react-components.react.jsx
index 7da23cc..a909647 100644
--- a/app/addons/components/react-components.react.jsx
+++ b/app/addons/components/react-components.react.jsx
@@ -17,10 +17,12 @@ define([
   'addons/components/stores',
   'addons/fauxton/components.react',
   'ace/ace',
-  'plugins/beautify'
+  'plugins/beautify',
+  'libs/react-bootstrap'
 ],
 
-function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper) {
+function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper, ReactBootstrap) {
+
   var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
   var componentStore = Stores.componentStore;
 
@@ -60,6 +62,101 @@ function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper
     }
   });
 
+
+  var BulkActionComponent = React.createClass({
+
+    propTypes: {
+      hasSelectedItem: React.PropTypes.bool.isRequired,
+      removeItem: React.PropTypes.func.isRequired,
+      selectAll: React.PropTypes.func.isRequired,
+      toggleSelect: React.PropTypes.func.isRequired,
+      isChecked: React.PropTypes.bool.isRequired
+    },
+
+    getDefaultProps: function () {
+      return {
+        disabled: false,
+        title: 'Select rows that can be...',
+        bulkIcon: 'fonticon-trash',
+        buttonTitle: 'Delete all selected',
+        dropdownContentText: 'Deleted',
+        enableOverlay: false
+      };
+    },
+
+    render: function () {
+      return (
+        <div className="bulk-action-component">
+          <div className="bulk-action-component-selector-group">
+            {this.getMasterSelector()}
+            {this.getMultiSelectOptions()}
+          </div>
+        </div>
+      );
+    },
+
+    getMultiSelectOptions: function () {
+      if (!this.props.hasSelectedItem) {
+        return null;
+      }
+
+      return (
+        <button
+          onClick={this.props.removeItem}
+          className={'fonticon ' + this.props.bulkIcon}
+          title={this.props.buttonTitle} />
+      );
+    },
+
+    getPopupContent: function () {
+      return (
+        <ul className="bulk-action-component-popover-actions">
+          <li onClick={this.selectAll} >
+            <i className="icon fonticon-cancel"></i> {this.props.dropdownContentText}
+          </li>
+        </ul>
+      );
+    },
+
+    selectAll: function () {
+      this.refs.bulkActionPopover.hide();
+      this.props.selectAll();
+    },
+
+    getOverlay: function () {
+      return (
+        <ReactBootstrap.OverlayTrigger
+          ref="bulkActionPopover"
+          trigger="click"
+          placement="bottom"
+          rootClose={true}
+          overlay={
+            <ReactBootstrap.Popover id="bulk-action-component-popover" title={this.props.title}>
+              {this.getPopupContent()}
+            </ReactBootstrap.Popover>
+          }>
+          <div className="arrow-button">
+            <i className="fonticon fonticon-play"></i>
+          </div>
+        </ReactBootstrap.OverlayTrigger>
+      );
+    },
+
+    getMasterSelector: function () {
+      return (
+        <div className="bulk-action-component-panel">
+          <input type="checkbox"
+            checked={this.props.isChecked}
+            onChange={this.props.toggleSelect}
+            disabled={this.props.disabled} />
+          {this.props.enableOverlay ? <div className="separator"></div> : null}
+          {this.props.enableOverlay ? this.getOverlay() : null}
+        </div>
+      );
+    },
+
+  });
+
   var StyledSelect = React.createClass({
     render: function () {
       return (
@@ -1167,6 +1264,7 @@ function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper
   });
 
   return {
+    BulkActionComponent: BulkActionComponent,
     ConfirmButton: ConfirmButton,
     ToggleHeaderButton: ToggleHeaderButton,
     StyledSelect: StyledSelect,

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/databases/assets/less/databases.less
----------------------------------------------------------------------
diff --git a/app/addons/databases/assets/less/databases.less b/app/addons/databases/assets/less/databases.less
index e21b8ef..ddf616c 100644
--- a/app/addons/databases/assets/less/databases.less
+++ b/app/addons/databases/assets/less/databases.less
@@ -28,6 +28,9 @@
     text-decoration: none;
     font-size: 19px;
   }
+  td {
+    vertical-align: middle;
+  }
 }
 
 .new-database-tray {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/assets/less/header.less
----------------------------------------------------------------------
diff --git a/app/addons/documents/assets/less/header.less b/app/addons/documents/assets/less/header.less
index 2b095f7..1ffc162 100644
--- a/app/addons/documents/assets/less/header.less
+++ b/app/addons/documents/assets/less/header.less
@@ -10,10 +10,45 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-.control-cancel {
-  border-right: none;
+
+button.control-view {
+  border-right: 1px solid @btnBorder;
+  border-left: none;
+}
+
+#react-headerbar .dropdown {
+  a {
+    text-decoration: none;
+    div {
+      margin-left: 30px;
+    }
+  }
+  li {
+    cursor: pointer;
+    i {
+      font-size: 17px;
+      position: absolute;
+    }
+  }
+  .icon {
+    position: relative;
+  }
+  .dropdown-toggle.fonticon-json:before {
+    margin-top: 9px;
+  }
+  .dropdown-menu {
+    left: -101px;
+    top: 55px;
+  }
 }
 
-.alternative-header {
-  float: left;
+#react-headerbar {
+  // dropdown needs position absolute
+  .add-dropdown {
+    right: initial;
+    top: initial;
+  }
+  .control-select-all {
+    margin-left: 95px;
+  }
 }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/assets/less/index-results.less
----------------------------------------------------------------------
diff --git a/app/addons/documents/assets/less/index-results.less b/app/addons/documents/assets/less/index-results.less
index 7809757..4bfa77f 100644
--- a/app/addons/documents/assets/less/index-results.less
+++ b/app/addons/documents/assets/less/index-results.less
@@ -10,6 +10,15 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
+@import "../../../../../assets/less/variables.less";
+
+
+.document-result-screen {
+  .bulk-action-component {
+    padding-bottom: 15px;
+  }
+}
+
 .watermark-logo {
   background: transparent url('../img/couch-watermark.png') no-repeat 50% 50%;
   min-height: 400px;
@@ -25,3 +34,37 @@
     margin: 0 10px;
   }
 }
+
+.table-view-docs {
+  .tableview-data-cell-id {
+    font-weight: 700;
+    a {
+      color: @linkColor;
+    }
+  }
+  .tableview-header-el-checkbox {
+    border: none;
+  }
+
+  td, th, td a {
+    vertical-align: middle;
+    line-height: 20px;
+    font-size: 14px;
+    color: @defaultHTag;
+  }
+  td {
+    height: 49px;
+  }
+  td, th {
+    max-width: 160px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+  td.tableview-checkbox-cell, th.tableview-header-el-checkbox {
+    width: 28px;
+  }
+  .tableview-checkbox-cell input {
+    margin: 0px;
+  }
+}

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/header/header.actions.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/header/header.actions.js b/app/addons/documents/header/header.actions.js
index 5a6dfe0..3e7cc04 100644
--- a/app/addons/documents/header/header.actions.js
+++ b/app/addons/documents/header/header.actions.js
@@ -22,46 +22,37 @@ function (app, FauxtonAPI, ActionTypes) {
       FauxtonAPI.dispatch({
         type: ActionTypes.COLLAPSE_DOCUMENTS
       });
-
     },
 
     unCollapseDocuments: function () {
       FauxtonAPI.dispatch({
         type: ActionTypes.EXPAND_DOCUMENTS
       });
-
     },
 
-    selectAllDocuments: function () {
+    collapseAllDocuments: function () {
       FauxtonAPI.dispatch({
-        type: ActionTypes.SELECT_ALL_DOCUMENTS
+        type: ActionTypes.COLLAPSE_ALL_DOCUMENTS
       });
     },
 
-    deSelectAllDocuments: function () {
+    unCollapseAllDocuments: function () {
       FauxtonAPI.dispatch({
-        type: ActionTypes.DESELECT_ALL_DOCUMENTS
+        type: ActionTypes.EXPAND_ALL_DOCUMENTS
       });
     },
 
-    updateDocumentCount: function (options) {
+    enableTableView: function () {
       FauxtonAPI.dispatch({
-        type: ActionTypes.UPDATE_DOCUMENT_COUNT,
-        options: options
+        type: ActionTypes.ENABLE_TABLE_VIEW
       });
     },
 
-    toggleHeaderControls: function () {
+    disableTableView: function () {
       FauxtonAPI.dispatch({
-        type: ActionTypes.TOGGLE_HEADER_CONTROLS
+        type: ActionTypes.DISABLE_TABLE_VIEW
       });
     },
 
-    resetHeaderController: function () {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.RESET_HEADER_BAR
-      });
-    }
-
   };
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/header/header.actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/header/header.actiontypes.js b/app/addons/documents/header/header.actiontypes.js
index 18cc41f..ee5039f 100644
--- a/app/addons/documents/header/header.actiontypes.js
+++ b/app/addons/documents/header/header.actiontypes.js
@@ -12,13 +12,11 @@
 
 define([], function () {
   return {
-    UPDATE_DOCUMENT_COUNT: 'UPDATE_DOCUMENT_COUNT',
     COLLAPSE_DOCUMENTS: 'COLLAPSE_DOCUMENTS',
     EXPAND_DOCUMENTS: 'UNCOLLAPSE_DOCUMENTS',
-    TOGGLE_HEADER_CONTROLS: 'TOGGLE_HEADER_CONTROLS',
-    RESET_HEADER_BAR: 'RESET_HEADER_BAR',
-    DELETE_SELECTED_DOCUMENTS: 'DELETE_SELECTED_DOCUMENTS',
-    SELECT_ALL_DOCUMENTS: 'SELECT_ALL_DOCUMENTS',
-    DESELECT_ALL_DOCUMENTS: 'DESELECT_ALL_DOCUMENTS'
+    COLLAPSE_ALL_DOCUMENTS: 'COLLAPSE_ALL_DOCUMENTS',
+    EXPAND_ALL_DOCUMENTS: 'EXPAND_ALL_DOCUMENTS',
+    DISABLE_TABLE_VIEW: 'DISABLE_TABLE_VIEW',
+    ENABLE_TABLE_VIEW: 'ENABLE_TABLE_VIEW'
   };
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/header/header.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/header/header.react.jsx b/app/addons/documents/header/header.react.jsx
index b277e31..03246bd 100644
--- a/app/addons/documents/header/header.react.jsx
+++ b/app/addons/documents/header/header.react.jsx
@@ -14,27 +14,24 @@ define([
   'app',
   'api',
   'react',
-  'addons/documents/header/header.stores',
   'addons/documents/header/header.actions',
   'addons/components/react-components.react',
   'addons/documents/index-results/stores',
   'addons/documents/index-results/actions',
 ],
 
-function (app, FauxtonAPI, React, Stores, Actions, ReactComponents, IndexResultsStore, IndexResultsActions) {
+function (app, FauxtonAPI, React, Actions, ReactComponents, IndexResultsStore, IndexResultsActions) {
   var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
-  var headerBarStore = Stores.headerBarStore;
-  var bulkDocumentHeaderStore = Stores.bulkDocumentHeaderStore;
+
   var indexResultsStore = IndexResultsStore.indexResultsStore;
   var ToggleHeaderButton = ReactComponents.ToggleHeaderButton;
+  var MenuDropDown = ReactComponents.MenuDropDown;
+
 
   var BulkDocumentHeaderController = React.createClass({
     getStoreState: function () {
       return {
-        canCollapseDocs: indexResultsStore.canCollapseDocs(),
-        canUncollapseDocs: indexResultsStore.canUncollapseDocs(),
-        canDeselectAll: indexResultsStore.canDeselectAll(),
-        canSelectAll: indexResultsStore.canSelectAll()
+        selectedView: indexResultsStore.getCurrentViewType()
       };
     },
 
@@ -54,64 +51,63 @@ function (app, FauxtonAPI, React, Stores, Actions, ReactComponents, IndexResults
       this.setState(this.getStoreState());
     },
 
-    render: function () {
-      var baseClass = 'header-control-box header-control-square ',
-          canDeselectAll = this.state.canDeselectAll,
-          canSelectAll = this.state.canSelectAll,
-          canCollapseDocs = this.state.canCollapseDocs,
-          canUncollapseDocs = this.state.canUncollapseDocs;
+    getIcon: function () {
+      if (this.state.selectedView === 'table') {
+        return 'fonticon-table';
+      }
+
+      if (this.state.selectedView === 'collapsed') {
+        return 'fonticon-list-alt';
+      }
+
+      return 'fonticon-json';
+    },
+
+    getCollapseDocsButton: function () {
+      var icon = this.getIcon();
+
+      return (
+        <div className="add-dropdown">
+          <div className="dropdown">
+            <button data-toggle="dropdown" className="button header-control-box control-view">
+              <i className={"dropdown-toggle icon " + icon}></i> View
+            </button>
+            <ul className="dropdown-menu arrow" role="menu" aria-labelledby="dLabel">
+              <li>
+                <a onClick={this.collapseAllDocuments}>
+                  <i className="fonticon-list-alt" />
+                  <div>
+                    Collapsed View
+                  </div>
+                </a>
+              </li>
+              <li>
+                <a onClick={this.toggleToNormalJson}>
+                  <i className="fonticon-json" />
+                  <div>
+                    Expanded View
+                  </div>
+                </a>
+              </li>
+              <li>
+                <a onClick={this.tablelizeView}>
+                  <i className="fonticon-table" />
+                  <div>
+                    Table View
+                  </div>
+                </a>
+              </li>
+            </ul>
+
+          </div>
+        </div>
+      );
+    },
 
+    render: function () {
       return (
         <div className='alternative-header'>
-          <ToggleHeaderButton
-            fonticon={'fonticon-select-all'}
-            toggleCallback={this.selectAllDocuments}
-            containerClasses={baseClass + 'control-select-all'}
-            text={''}
-            selected={!canSelectAll}
-            disabled={!canSelectAll}
-            title={'Select all Documents'} />
-
-          <ToggleHeaderButton
-            fonticon={'fonticon-deselect-all'}
-            toggleCallback={this.deSelectAllDocuments}
-            containerClasses={baseClass + 'control-de-select-all'}
-            text={''}
-            selected={!canDeselectAll}
-            disabled={!canDeselectAll}
-            title={'Deselect all Documents'} />
-
-          <ToggleHeaderButton
-            fonticon={'fonticon-collapse'}
-            toggleCallback={this.collapseDocuments}
-            containerClasses={baseClass + 'control-collapse'}
-            text={''}
-            selected={!canCollapseDocs}
-            disabled={!canCollapseDocs}
-            title={'Collapse Selected'} />
-
-          <ToggleHeaderButton
-            fonticon={'fonticon-expand'}
-            toggleCallback={this.unCollapseDocuments}
-            containerClasses={baseClass + 'control-expand'}
-            text={''}
-            selected={!canUncollapseDocs}
-            disabled={!canUncollapseDocs}
-            title={'Expand Selected'} />
-
-          <ToggleHeaderButton
-            fonticon={'fonticon-trash'}
-            toggleCallback={this.deleteSelected}
-            containerClasses={baseClass + 'control-delete'}
-            text={''}
-            title={'Delete selected'} />
-
-          <ToggleHeaderButton
-            fonticon={''}
-            toggleCallback={this.cancelView}
-            containerClasses={baseClass + 'control-cancel'}
-            text={'Cancel'}
-            title={'Switch to other view'} />
+          {this.getCollapseDocsButton()}
         </div>
       );
     },
@@ -124,95 +120,21 @@ function (app, FauxtonAPI, React, Stores, Actions, ReactComponents, IndexResults
       Actions.unCollapseDocuments();
     },
 
-    selectAllDocuments: function () {
-      Actions.selectAllDocuments();
-    },
-
-    deSelectAllDocuments: function () {
-      Actions.deSelectAllDocuments();
-    },
-
-    cancelView: function () {
-      Actions.toggleHeaderControls();
+    toggleToNormalJson: function () {
+      Actions.unCollapseAllDocuments();
     },
 
-    deleteSelected: function () {
-      IndexResultsActions.deleteSelected();
-    }
-  });
-
-  var HeaderBarController = React.createClass({
-    getStoreState: function () {
-      return {
-        isToggled: headerBarStore.getToggleStatus(),
-        toggleClass: headerBarStore.getToggleClass()
-      };
+    collapseAllDocuments: function () {
+      Actions.collapseAllDocuments();
     },
 
-    getInitialState: function () {
-      return this.getStoreState();
-    },
-
-    onChange: function () {
-      this.setState(this.getStoreState());
-    },
-
-    componentDidMount: function () {
-      headerBarStore.on('change', this.onChange, this);
-    },
-
-    componentWillUnmount: function () {
-      headerBarStore.off('change', this.onChange);
-    },
-
-    toggleCallback: function () {
-      Actions.toggleHeaderControls();
-    },
-
-    componentDidUpdate: function () {
-      // todo reactify right header (api bar, query options)
-      var $oldHeader = $('#api-navbar, #right-header, #notification-center-btn');
-      if (this.state.isToggled) {
-        $oldHeader.hide();
-        return;
-      }
-
-      setTimeout(function () {
-        $oldHeader.velocity('fadeIn', 250);
-      }, 250);
-    },
-
-    render: function () {
-      var containerClasses = 'header-control-box ' +
-        'control-toggle-alternative-header ' + this.state.toggleClass;
-      var innerClasses = '';
-
-      var headerbar = null;
-      if (this.state.isToggled) {
-        headerbar = (<BulkDocumentHeaderController key={1} />);
-      }
-
-      return (
-        <div>
-          <div>
-            <ToggleHeaderButton
-              fonticon={'fonticon-ok-circled'}
-              toggleCallback={this.toggleCallback}
-              containerClasses={containerClasses}
-              innerClasses={innerClasses}
-              text={'Select'} />
-              <ReactCSSTransitionGroup transitionName={'fade'}>
-                {headerbar}
-              </ReactCSSTransitionGroup>
-          </div>
-        </div>
-      );
+    tablelizeView: function () {
+      Actions.enableTableView();
     }
   });
 
   var Views = {
     BulkDocumentHeaderController: BulkDocumentHeaderController,
-    HeaderBarController: HeaderBarController,
     ToggleHeaderButton: ToggleHeaderButton
   };
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/header/header.stores.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/header/header.stores.js b/app/addons/documents/header/header.stores.js
deleted file mode 100644
index 5d5d1e2..0000000
--- a/app/addons/documents/header/header.stores.js
+++ /dev/null
@@ -1,76 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-
-define([
-  'api',
-  'addons/documents/header/header.actiontypes',
-  'addons/documents/index-results/actiontypes'
-],
-
-function (FauxtonAPI, ActionTypes, IndexResultsActions) {
-  var Stores = {};
-
-  Stores.HeaderBarStore = FauxtonAPI.Store.extend({
-    initialize: function (options) {
-      this.reset();
-    },
-
-    reset: function () {
-      this._toggleClass = '';
-      this._isToggled = false;
-    },
-
-    toogleStatus: function () {
-      this._isToggled = !this._isToggled;
-    },
-
-    toggleClass: function () {
-      this._toggleClass = '';
-
-      if (this._isToggled) {
-        this._toggleClass = 'js-headerbar-togglebutton-selected';
-      }
-    },
-
-    getToggleStatus: function () {
-      return this._isToggled;
-    },
-
-    getToggleClass: function () {
-      return this._toggleClass;
-    },
-
-    dispatch: function (action) {
-      switch (action.type) {
-        case ActionTypes.TOGGLE_HEADER_CONTROLS:
-          this.toogleStatus();
-          this.toggleClass();
-          this.triggerChange();
-        break;
-
-        case ActionTypes.RESET_HEADER_BAR:
-          this.reset();
-          this.toggleClass();
-          this.triggerChange();
-        break;
-
-        default:
-        return;
-      }
-    }
-  });
-
-  Stores.headerBarStore = new Stores.HeaderBarStore();
-  Stores.headerBarStore.dispatchToken = FauxtonAPI.dispatcher.register(Stores.headerBarStore.dispatch);
-
-  return Stores;
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/header/tests/headerSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/header/tests/headerSpec.react.jsx b/app/addons/documents/header/tests/headerSpec.react.jsx
deleted file mode 100644
index a2bbe72..0000000
--- a/app/addons/documents/header/tests/headerSpec.react.jsx
+++ /dev/null
@@ -1,113 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License"); you may not
-// use this file except in compliance with the License. You may obtain a copy of
-// the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-// License for the specific language governing permissions and limitations under
-// the License.
-define([
-  'api',
-  'addons/documents/header/header.react',
-  'addons/documents/header/header.stores',
-  'addons/documents/header/header.actions',
-
-  'addons/databases/base',
-  'addons/documents/resources',
-  'addons/documents/index-results/actions',
-  'addons/documents/index-results/stores',
-
-  'testUtils',
-  'react'
-], function (FauxtonAPI, Views, Stores, Actions, Databases, Resources,
-             IndexResultsActions, IndexResultsStore, utils, React) {
-
-  var assert = utils.assert;
-  var restore = utils.restore;
-  var TestUtils = React.addons.TestUtils;
-
-  describe('Header Controller', function () {
-    var container, toggleEl;
-    beforeEach(function () {
-      container = document.createElement('div');
-    });
-
-    afterEach(function () {
-      React.unmountComponentAtNode(container);
-    });
-
-    it('should not include invalid calssname', function () {
-      toggleEl = TestUtils.renderIntoDocument(<Views.HeaderBarController />, container);
-      var $el = $(toggleEl.getDOMNode()).find('.control-toggle-alternative-header');
-      assert.equal($(toggleEl.getDOMNode()).find('.undefined').length, 0);
-    });
-
-    it('should use the passed classname', function () {
-      toggleEl = TestUtils.renderIntoDocument(<Views.HeaderBarController />, container);
-      var $el = $(toggleEl.getDOMNode()).find('.control-toggle-alternative-header');
-
-      TestUtils.Simulate.click($el[0]);
-      assert.ok($el.hasClass('js-headerbar-togglebutton-selected'));
-    });
-
-    it('should not render the alternative header if the button is not clicked', function () {
-      Actions.resetHeaderController();
-      toggleEl = TestUtils.renderIntoDocument(<Views.HeaderBarController />, container);
-      var $el = $(toggleEl.getDOMNode()).find('.control-toggle-alternative-header');
-      assert.equal($(toggleEl.getDOMNode()).find('.alternative-header').length, 0);
-    });
-
-    it('should render the alternative header', function () {
-      toggleEl = TestUtils.renderIntoDocument(<Views.HeaderBarController />, container);
-      var $el = $(toggleEl.getDOMNode()).find('.control-toggle-alternative-header');
-      TestUtils.Simulate.click($el[0]);
-      assert.equal($(toggleEl.getDOMNode()).find('.alternative-header').length, 1);
-    });
-  });
-
-  describe('Bulkdocument Headerbar Controller', function () {
-    var container, header;
-    beforeEach(function () {
-      var database = new Databases.Model({id: 'registry'});
-
-      database.allDocs = new Resources.AllDocs({_id: "ente"}, {
-        database: database,
-        viewMeta: {update_seq: 1},
-        params: {}
-      });
-
-      //override reset so we don't loose the added doc needed for testing
-      database.allDocs.reset = function () {};
-
-      IndexResultsActions.newResultsList({
-        collection: database.allDocs,
-        isListDeletable: false
-      });
-
-
-      container = document.createElement('div');
-    });
-
-    afterEach(function () {
-      React.unmountComponentAtNode(container);
-      restore(Actions.collapseDocuments);
-    });
-
-    it('should trigger action', function () {
-      var spy = sinon.spy(Actions, 'collapseDocuments');
-      header = TestUtils.renderIntoDocument(<Views.BulkDocumentHeaderController />, container);
-      TestUtils.Simulate.click($(header.getDOMNode()).find('.control-collapse')[0]);
-
-      assert.ok(spy.calledOnce);
-    });
-
-    it('pressing SelectAll should fill the selected items list', function () {
-      TestUtils.Simulate.click($(header.getDOMNode()).find('.control-select-all')[0]);
-
-      assert.equal(IndexResultsStore.indexResultsStore.getSelectedItemsLength(), 1);
-    });
-  });
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/index-results/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/actions.js b/app/addons/documents/index-results/actions.js
index 65505ee..ea22f9a 100644
--- a/app/addons/documents/index-results/actions.js
+++ b/app/addons/documents/index-results/actions.js
@@ -15,13 +15,11 @@ define([
   'api',
   'addons/documents/index-results/actiontypes',
   'addons/documents/index-results/stores',
-  'addons/documents/header/header.stores',
   'addons/documents/header/header.actions',
   'addons/documents/resources'
 ],
-function (app, FauxtonAPI, ActionTypes, Stores, HeaderStores, HeaderActions, Documents) {
+function (app, FauxtonAPI, ActionTypes, Stores, HeaderActions, Documents) {
   var indexResultsStore = Stores.indexResultsStore;
-  var headerBarStore = HeaderStores.headerBarStore;
 
   var errorMessage = function (ids) {
     var msg = 'Failed to delete your document!';
@@ -38,11 +36,16 @@ function (app, FauxtonAPI, ActionTypes, Stores, HeaderStores, HeaderActions, Doc
   };
 
   return {
-    newResultsList: function (options) {
+
+    sendMessageNewResultList: function (options) {
       FauxtonAPI.dispatch({
         type: ActionTypes.INDEX_RESULTS_NEW_RESULTS,
         options: options
       });
+    },
+
+    newResultsList: function (options) {
+      this.sendMessageNewResultList(options);
 
       if (!options.collection.fetch) { return; }
       this.clearResults();
@@ -91,7 +94,6 @@ function (app, FauxtonAPI, ActionTypes, Stores, HeaderStores, HeaderActions, Doc
           this.resultsListReset();
           this.newMangoResultsList({
             collection: collection,
-            isListDeletable: indexResultsStore.isListDeletable(),
             query: options.queryCode,
             textEmptyIndex: 'No Results Found!',
             bulkCollection: Documents.BulkDeleteDocCollection
@@ -111,7 +113,6 @@ function (app, FauxtonAPI, ActionTypes, Stores, HeaderStores, HeaderActions, Doc
       if (indexResultsStore.getTypeOfIndex() === 'mango') {
         return this.newResultsList({
           collection: indexResultsStore.getCollection(),
-          isListDeletable: true,
           bulkCollection: Documents.MangoBulkDeleteDocCollection,
           typeOfIndex: 'mango'
         });
@@ -119,7 +120,6 @@ function (app, FauxtonAPI, ActionTypes, Stores, HeaderStores, HeaderActions, Doc
 
       return this.newResultsList({
         collection: indexResultsStore.getCollection(),
-        isListDeletable: indexResultsStore.isListDeletable(),
         bulkCollection: Documents.BulkDeleteDocCollection
       });
     },
@@ -135,17 +135,18 @@ function (app, FauxtonAPI, ActionTypes, Stores, HeaderStores, HeaderActions, Doc
         type: ActionTypes.INDEX_RESULTS_SELECT_DOC,
         id: id
       });
+    },
 
-      //show menu
-      if (!headerBarStore.getToggleStatus()) {
-        HeaderActions.toggleHeaderControls();
-        return;
-      }
+    selectAllDocuments: function () {
+      FauxtonAPI.dispatch({
+        type: ActionTypes.INDEX_RESULTS_SELECT_ALL_DOCUMENTS
+      });
+    },
 
-      //hide menu
-      if (headerBarStore.getToggleStatus() && indexResultsStore.getSelectedItemsLength() === 0) {
-        HeaderActions.toggleHeaderControls();
-      }
+    toggleAllDocuments: function () {
+      FauxtonAPI.dispatch({
+        type: ActionTypes.INDEX_RESULTS_TOOGLE_SELECT_ALL_DOCUMENTS
+      });
     },
 
     selectListOfDocs: function (ids) {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/index-results/actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/actiontypes.js b/app/addons/documents/index-results/actiontypes.js
index 72157c7..4794610 100644
--- a/app/addons/documents/index-results/actiontypes.js
+++ b/app/addons/documents/index-results/actiontypes.js
@@ -16,6 +16,9 @@ define([], function () {
     INDEX_RESULTS_RESET: 'INDEX_RESULTS_RESET',
     INDEX_RESULTS_SELECT_DOC: 'INDEX_RESULTS_SELECT_DOC',
     INDEX_RESULTS_SELECT_LIST_OF_DOCS: 'INDEX_RESULTS_SELECT_LIST_OF_DOCS',
-    INDEX_RESULTS_CLEAR_RESULTS: 'INDEX_RESULTS_CLEAR_RESULTS'
+    INDEX_RESULTS_CLEAR_RESULTS: 'INDEX_RESULTS_CLEAR_RESULTS',
+    INDEX_RESULTS_SELECT_ALL_DOCUMENTS: 'INDEX_RESULTS_SELECT_ALL_DOCUMENTS',
+    INDEX_RESULTS_TOOGLE_SELECT_ALL_DOCUMENTS: 'INDEX_RESULTS_TOOGLE_SELECT_ALL_DOCUMENTS',
+
   };
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/index-results/index-results.components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/index-results.components.react.jsx b/app/addons/documents/index-results/index-results.components.react.jsx
index 2b5fe39..bbcd196 100644
--- a/app/addons/documents/index-results/index-results.components.react.jsx
+++ b/app/addons/documents/index-results/index-results.components.react.jsx
@@ -25,6 +25,7 @@ define([
 function (app, FauxtonAPI, React, Stores, Actions, Components, Documents) {
   var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
   var store = Stores.indexResultsStore;
+  var BulkActionComponent = Components.BulkActionComponent;
 
   var NoResultScreen = React.createClass({
     render: function () {
@@ -36,6 +37,142 @@ function (app, FauxtonAPI, React, Stores, Actions, Components, Documents) {
     }
   });
 
+  var TableRow = React.createClass({
+    propTypes: {
+      docIdentifier: React.PropTypes.string.isRequired,
+      docChecked: React.PropTypes.func.isRequired,
+      isSelected: React.PropTypes.bool.isRequired,
+      index: React.PropTypes.number.isRequired,
+      data: React.PropTypes.object.isRequired
+    },
+
+    onChange: function (e) {
+      this.props.docChecked(this.props.docIdentifier, this.props.data, e);
+    },
+
+    getInitialState: function () {
+      return {
+        checked: this.props.isSelected
+      };
+    },
+
+    getRowContents: function (element, rownumber) {
+      var row = this.props.schema.map(function (k, i) {
+        var el = element.content;
+        var key = 'tableview-data-cell-' + rownumber + k + i + el[k];
+        var stringified = typeof el[k] === 'object' ? JSON.stringify(el[k]) : el[k];
+        var className = k === '_id' ? 'tableview-data-cell-id' : null;
+
+        return (
+          <td className={className} key={key} title={stringified}>
+            {k === '_id' ? this.maybeGetUrl(element.url, stringified) : stringified}
+          </td>
+        );
+      }.bind(this));
+
+      return row;
+    },
+
+    maybeGetUrl: function (url, stringified) {
+      if (!url) {
+        return stringified;
+      }
+
+      return (
+        <a href={url}>
+          {stringified}
+        </a>
+      );
+    },
+
+    maybeGetCheckboxCell: function (i) {
+      if (!this.props.docId) {
+        return null;
+      }
+
+      return (
+        <td className="tableview-checkbox-cell" key={"tableview-checkbox-cell-" + i}>
+          <input
+            id={"checkbox-" + this.props.docIdentifier}
+            checked={this.props.isSelected}
+            type="checkbox"
+            onChange={this.onChange} />
+        </td>
+      );
+    },
+
+    render: function () {
+      var i = this.props.index;
+
+      return (
+        <tr key={"tableview-content-row-" + i}>
+          {this.maybeGetCheckboxCell(i)}
+          {this.getRowContents(this.props.data, i)}
+        </tr>
+      );
+    }
+  });
+
+  var TableView = React.createClass({
+    getContentRows: function () {
+      var data = this.props.data.results;
+      var schema = this.props.data.schema;
+
+      var res = data.map(function (el, i) {
+
+        return (
+          <TableRow
+            key={"tableview-row-component-" + i}
+            index={i}
+            data={el}
+            docId={el.id}
+            docIdentifier={el.id || "tableview-row-component-" + i}
+            docChecked={this.props.docChecked}
+            isSelected={this.props.isSelected(el.id)}
+            schema={schema} />
+        );
+      }.bind(this));
+
+      return res;
+    },
+
+    getHeader: function () {
+      var row = this.props.data.schema.map(function (el, i) {
+        return <th key={"header-el-" + i} title={el}>{el}</th>;
+      });
+
+      var box = null;
+
+      if (this.props.isListDeletable) {
+        box = (<th className="tableview-header-el-checkbox" key="tableview-header-el-checkbox"></th>);
+      }
+
+      return (
+        <tr key="tableview-content-row-header">
+          {box}
+          {row}
+        </tr>
+      );
+    },
+
+    render: function () {
+      var header = this.getHeader();
+      var contentRows = this.getContentRows();
+
+      return (
+        <table className="table table-striped table-view-docs">
+          <thead>
+            {header}
+          </thead>
+          <tbody>
+            {contentRows}
+          </tbody>
+        </table>
+      );
+    }
+  });
+
+
   var ResultsScreen = React.createClass({
 
     onDoubleClick: function (id, doc) {
@@ -55,8 +192,9 @@ function (app, FauxtonAPI, React, Stores, Actions, Components, Documents) {
 
     getDocumentList: function () {
       var noop = function () {};
+      var data = this.props.results.results;
 
-      return _.map(this.props.results, function (doc, i) {
+      return _.map(data, function (doc, i) {
         return (
          <Components.Document
            key={doc.id + i}
@@ -75,31 +213,71 @@ function (app, FauxtonAPI, React, Stores, Actions, Components, Documents) {
       }, this);
     },
 
-    render: function () {
+    getDocumentStyleView: function (loadLines) {
       var classNames = 'view';
-      var loadLines = null;
-
-      if (this.props.isLoading) {
-        loadLines = <Components.LoadLines />;
-      }
 
       if (this.props.isListDeletable) {
         classNames += ' show-select';
       }
 
       return (
-      <div className={classNames}>
-        {loadLines}
+        <div className={classNames}>
+          {loadLines}
+
 
-        <div id="doc-list">
-          <ReactCSSTransitionGroup transitionName={'slow-fade'}>
-            {this.getDocumentList()}
-          </ReactCSSTransitionGroup>
+          <div id="doc-list">
+            <ReactCSSTransitionGroup transitionName="slow-fade">
+              {this.getDocumentList()}
+            </ReactCSSTransitionGroup>
+          </div>
         </div>
-      </div>
       );
     },
 
+    getTableStyleView: function (loadLines) {
+      return (
+        <div>
+          <TableView
+            docChecked={this.props.docChecked}
+            isSelected={this.props.isSelected}
+            isListDeletable={this.props.isListDeletable}
+            data={this.props.results} />
+        </div>
+      );
+    },
+
+    render: function () {
+
+      var loadLines = null;
+      var isTableView = this.props.isTableView;
+
+      if (this.props.isLoading) {
+        loadLines = <Components.LoadLines />;
+      }
+
+      var mainView = isTableView ? this.getTableStyleView(loadLines) : this.getDocumentStyleView(loadLines);
+      return (
+        <div className="document-result-screen">
+          <BulkActionComponent
+            removeItem={this.props.removeItem}
+            isChecked={this.props.allDocumentsSelected}
+            hasSelectedItem={this.props.hasSelectedItem}
+            selectAll={this.selectAllDocs}
+            toggleSelect={this.toggleSelectAll}
+            title="Select all docs that can be..." />
+          {mainView}
+        </div>
+      );
+    },
+
+    selectAllDocs: function () {
+      Actions.selectAllDocuments();
+    },
+
+    toggleSelectAll: function () {
+      Actions.toggleAllDocuments();
+    },
+
     componentDidMount: function () {
       prettyPrint();
     },
@@ -110,21 +288,32 @@ function (app, FauxtonAPI, React, Stores, Actions, Components, Documents) {
 
   });
 
+
+
   var ViewResultListController = React.createClass({
     getStoreState: function () {
       return {
         hasResults: store.hasResults(),
         results: store.getResults(),
-        isListDeletable: store.isListDeletable(),
-        isSelected: store.isSelected,
+        selectedItems: store.getSelectedItems(),
         isLoading: store.isLoading(),
         isEditable: store.isEditable(),
-        textEmptyIndex: store.getTextEmptyIndex()
+        textEmptyIndex: store.getTextEmptyIndex(),
+        isTableView: store.getIsTableView(),
+
+        canDeselectAll: store.canDeselectAll(),
+        canSelectAll: store.canSelectAll(),
+        allDocumentsSelected: store.areAllDocumentsSelected(),
+        hasSelectedItem: !!store.getSelectedItemsLength()
       };
     },
 
     isSelected: function (id) {
-      return this.state.isSelected(id);
+      return !!this.state.selectedItems[id];
+    },
+
+    removeItem: function () {
+      Actions.deleteSelected();
     },
 
     getInitialState: function () {
@@ -152,12 +341,17 @@ function (app, FauxtonAPI, React, Stores, Actions, Components, Documents) {
 
       if (this.state.hasResults) {
         view = <ResultsScreen
+          removeItem={this.removeItem}
+          hasSelectedItem={this.state.hasSelectedItem}
+          allDocumentsSelected={this.state.allDocumentsSelected}
+          canSelectAll={this.state.canSelectAll}
           isSelected={this.isSelected}
           isEditable={this.state.isEditable}
-          isListDeletable={this.state.isListDeletable}
+          isListDeletable={this.state.results.hasEditableAndDeletableDoc}
           docChecked={this.docChecked}
           isLoading={this.state.isLoading}
-          results={this.state.results} />;
+          results={this.state.results}
+          isTableView={this.state.isTableView} />;
       }
 
       return (
@@ -167,12 +361,6 @@ function (app, FauxtonAPI, React, Stores, Actions, Components, Documents) {
   });
 
   var Views = {
-    renderViewResultList: function (el) {
-      React.render(<ViewResultListController />, el);
-    },
-    removeViewResultList: function (el) {
-      React.unmountComponentAtNode(el);
-    },
     List: ViewResultListController,
     ResultsScreen: ResultsScreen
   };

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/index-results/stores.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/stores.js b/app/addons/documents/index-results/stores.js
index 37989f1..525cadf 100644
--- a/app/addons/documents/index-results/stores.js
+++ b/app/addons/documents/index-results/stores.js
@@ -11,6 +11,7 @@
 // the License.
 
 define([
+  'app',
   'api',
   'addons/documents/index-results/actiontypes',
   'addons/documents/header/header.actiontypes',
@@ -18,7 +19,7 @@ define([
   'addons/documents/mango/mango.helper'
 ],
 
-function (FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
+function (app, FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
   var Stores = {};
 
   /*TODO:
@@ -28,10 +29,12 @@ function (FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
   Stores.IndexResultsStore = FauxtonAPI.Store.extend({
 
     initialize: function () {
-      this._isListDeletable = false;
+      this.reset();
+    },
+
+    reset: function () {
       this._collection = [];
       this.clearSelectedItems();
-      this.clearCollapsedDocs();
       this._isLoading = false;
       this._textEmptyIndex = 'No Index Created Yet!';
       this._typeOfIndex = 'view';
@@ -43,15 +46,9 @@ function (FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
       this._selectedItems = {};
     },
 
-    clearCollapsedDocs: function () {
-      this._collapsedDocs = {};
-    },
-
     newResults: function (options) {
       this._collection = options.collection;
-      this._isListDeletable = options.isListDeletable;
       this.clearSelectedItems();
-      this.clearCollapsedDocs();
 
       this._bulkDeleteDocCollection = options.bulkCollection;
 
@@ -110,10 +107,6 @@ function (FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
       return doc.isDeletable();
     },
 
-    isListDeletable: function () {
-      return this._isListDeletable;
-    },
-
     getCollection: function () {
       return this._collection;
     },
@@ -121,7 +114,11 @@ function (FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
     getDocContent: function (originalDoc) {
       var doc = originalDoc.toJSON();
 
-      return this.isCollapsed(doc._id) ? '' : JSON.stringify(doc, null, ' ');
+      if (this._allCollapsed) {
+        return JSON.stringify({id: doc.id, rev: doc._rev}, null, ' ');
+      }
+
+      return JSON.stringify(doc, null, ' ');
     },
 
     getDocId: function (doc) {
@@ -143,7 +140,11 @@ function (FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
       delete doc.ddoc;
       delete doc.name;
 
-      return this.isCollapsed(originalDoc.id) ? '' : JSON.stringify(doc, null, ' ');
+      if (this._allCollapsed) {
+        return '';
+      }
+
+      return JSON.stringify(doc, null, ' ');
     },
 
     getMangoDoc: function (doc, index) {
@@ -179,11 +180,27 @@ function (FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
     },
 
     getResults: function () {
+      var hasEditableAndDeletableDoc;
+      var res;
+      var collection;
+
+
       function filterOutGeneratedMangoDocs (doc) {
-        return doc.get('language') !== 'query';
+        if (doc.get && typeof doc.get === 'function') {
+          return doc.get('language') !== 'query';
+        }
+
+        return doc.language !== 'query';
+      }
+
+      // Table sytle view
+      if (this.getIsTableView()) {
+        collection = this._collection.toJSON().filter(filterOutGeneratedMangoDocs);
+        return this.getTableViewData(collection);
       }
 
-      return this._collection
+      // JSON style views
+      res = this._collection
         .filter(filterOutGeneratedMangoDocs)
         .map(function (doc, i) {
           if (doc.get('def') || this.isGhostDoc(doc)) {
@@ -199,6 +216,100 @@ function (FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
             isEditable: this.isEditable(doc)
           };
         }, this);
+
+      hasEditableAndDeletableDoc = this.getHasEditableAndDeletableDoc(res);
+
+      return {
+        hasEditableAndDeletableDoc: hasEditableAndDeletableDoc,
+        results: res
+      };
+    },
+
+    getPseudoSchema: function (data) {
+      var cache = [];
+
+      data.forEach(function (el) {
+        Object.keys(el).forEach(function (k) {
+          cache.push(k);
+        });
+      });
+
+      cache = _.uniq(cache);
+
+      // always begin with _id
+      var i = cache.indexOf('_id');
+      if (i !== -1) {
+        cache.splice(i, 1);
+        cache.unshift('_id');
+      }
+
+      return cache;
+    },
+
+    // filter out cruft and JSONify strings
+    normalizeTableData: function (data) {
+      // include_docs enabled
+      if (data[0] && data[0].doc && data[0].doc._rev) {
+        return data.map(function (el) {
+          el = el.doc;
+          return el;
+        });
+      }
+
+      return data;
+    },
+
+    getTableViewData: function (data, hasEditableAndDeletableDoc) {
+      var res;
+      var schema;
+      var database;
+
+      data = this.normalizeTableData(data);
+      schema = this.getPseudoSchema(data);
+      database = this.getDatabase().safeID();
+
+      res = data.map(function (doc) {
+        var safeId = app.utils.getSafeIdForDoc(doc._id);
+        var url;
+
+        if (safeId) {
+          url = FauxtonAPI.urls('document', 'app', database, safeId);
+        }
+
+        return {
+          content: doc,
+          id: safeId,
+          header: '',
+          keylabel: '',
+          url: url,
+          isDeletable: !!safeId,
+          isEditable: !!safeId
+        };
+      });
+
+      hasEditableAndDeletableDoc = this.getHasEditableAndDeletableDoc(res);
+
+      return {
+        hasEditableAndDeletableDoc: hasEditableAndDeletableDoc,
+        schema: schema,
+        results: res
+      };
+    },
+
+    getHasEditableAndDeletableDoc: function (data) {
+      var found = false;
+      var length = data.length;
+      var i;
+
+      // use a for loop here as we can end it once we found the first id
+      for (i = 0; i < length; i++) {
+        if (data[i].id) {
+          found = true;
+          break;
+        }
+      }
+
+      return found;
     },
 
     hasResults: function () {
@@ -236,20 +347,20 @@ function (FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
       }, this);
     },
 
-    deSelectAllDocuments: function () {
-      this.clearSelectedItems();
-    },
+    toggleSelectAllDocuments: function () {
+      if (this.areAllDocumentsSelected()) {
+        return this.clearSelectedItems();
+      }
 
-    getSelectedItemsLength: function () {
-      return _.keys(this._selectedItems).length;
+      return this.selectAllDocuments();
     },
 
-    getCollapsedDocsLength: function () {
-      return _.keys(this._collapsedDocs).length;
+    areAllDocumentsSelected: function () {
+      return Object.keys(this._selectedItems).length === this._collection.length;
     },
 
-    getCollapsedDocs: function () {
-      return this._collapsedDocs;
+    getSelectedItemsLength: function () {
+      return Object.keys(this._selectedItems).length;
     },
 
     getDatabase: function () {
@@ -300,32 +411,47 @@ function (FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
       return this._selectedItems;
     },
 
-    canCollapseDocs: function () {
-      return this._collection.length > this.getCollapsedDocsLength();
+    hasSelectedItem: function () {
+      return this.getSelectedItemsLength() > 0;
     },
 
-    canUncollapseDocs: function () {
-      return this.getCollapsedDocsLength() > 0;
+    collapseAllDocs: function () {
+      this.disableTableView();
+
+      this._allCollapsed = true;
     },
 
-    isSelected: function (id) {
-      return !!this._selectedItems[id];
+    unCollapseAllDocs: function () {
+      this.disableTableView();
+
+      this._allCollapsed = false;
     },
 
-    isCollapsed: function (id) {
-      return !!this._collapsedDocs[id];
+    enableTableView: function () {
+      this._allCollapsed = false;
+      this._tableView = true;
     },
 
-    collapseSelectedDocs: function () {
-      _.each(this._selectedItems, function (val, key) {
-        this._collapsedDocs[key] = true;
-      }, this);
+    disableTableView: function () {
+      this._allCollapsed = false;
+      this._tableView = false;
     },
 
-    unCollapseSelectedDocs: function () {
-      _.each(this._selectedItems, function (val, key) {
-        delete this._collapsedDocs[key];
-      }, this);
+    getIsTableView: function () {
+      return this._tableView;
+    },
+
+    getCurrentViewType: function () {
+
+      if (this._tableView) {
+        return 'table';
+      }
+
+      if (this._allCollapsed) {
+        return 'collapsed';
+      }
+
+      return 'expanded';
     },
 
     clearResultsBeforeFetch: function () {
@@ -343,44 +469,50 @@ function (FauxtonAPI, ActionTypes, HeaderActionTypes, Documents, MangoHelper) {
       switch (action.type) {
         case ActionTypes.INDEX_RESULTS_NEW_RESULTS:
           this.newResults(action.options);
-          this.triggerChange();
         break;
         case ActionTypes.INDEX_RESULTS_RESET:
           this.resultsResetFromFetch();
-          this.triggerChange();
         break;
         case ActionTypes.INDEX_RESULTS_SELECT_DOC:
           this.selectDoc(action.id);
-          this.triggerChange();
         break;
         case ActionTypes.INDEX_RESULTS_SELECT_LIST_OF_DOCS:
           this.selectListOfDocs(action.ids);
-          this.triggerChange();
         break;
         case ActionTypes.INDEX_RESULTS_CLEAR_RESULTS:
           this.clearResultsBeforeFetch();
-          this.triggerChange();
         break;
-        case HeaderActionTypes.SELECT_ALL_DOCUMENTS:
+        case ActionTypes.INDEX_RESULTS_SELECT_ALL_DOCUMENTS:
           this.selectAllDocuments();
-          this.triggerChange();
         break;
-        case HeaderActionTypes.DESELECT_ALL_DOCUMENTS:
-          this.deSelectAllDocuments();
-          this.triggerChange();
+        case ActionTypes.INDEX_RESULTS_TOOGLE_SELECT_ALL_DOCUMENTS:
+          this.toggleSelectAllDocuments();
         break;
         case HeaderActionTypes.COLLAPSE_DOCUMENTS:
           this.collapseSelectedDocs();
-          this.triggerChange();
         break;
         case HeaderActionTypes.EXPAND_DOCUMENTS:
           this.unCollapseSelectedDocs();
-          this.triggerChange();
         break;
+        case HeaderActionTypes.COLLAPSE_ALL_DOCUMENTS:
+          this.collapseAllDocs();
+        break;
+        case HeaderActionTypes.EXPAND_ALL_DOCUMENTS:
+          this.unCollapseAllDocs();
+        break;
+        case HeaderActionTypes.DISABLE_TABLE_VIEW:
+          this.disableTableView();
+        break;
+        case HeaderActionTypes.ENABLE_TABLE_VIEW:
+          this.enableTableView();
+        break;
+
         default:
         return;
         // do nothing
       }
+
+      this.triggerChange();
     }
 
   });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/index-results/tests/index-results.actionsSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/tests/index-results.actionsSpec.js b/app/addons/documents/index-results/tests/index-results.actionsSpec.js
index fb67414..97b892a 100644
--- a/app/addons/documents/index-results/tests/index-results.actionsSpec.js
+++ b/app/addons/documents/index-results/tests/index-results.actionsSpec.js
@@ -14,11 +14,9 @@ define([
   'api',
   'addons/documents/index-results/actions',
   'addons/documents/index-results/stores',
-  'addons/documents/header/header.stores',
-  'addons/documents/header/header.actions',
   'addons/documents/resources',
   'testUtils',
-], function (FauxtonAPI, Actions, Stores, HeaderStores, HeaderActions, Documents, testUtils) {
+], function (FauxtonAPI, Actions, Stores, Documents, testUtils) {
   var assert = testUtils.assert;
   var restore = testUtils.restore;
   var store = Stores.indexResultsStore;
@@ -48,46 +46,6 @@ define([
 
   });
 
-  describe('#selectDoc', function () {
-    afterEach(function () {
-      restore(HeaderStores.headerBarStore.getToggleStatus);
-      restore(HeaderActions.toggleHeaderControls);
-    });
-
-    it('toggles header controls if not active', function () {
-      var stub = sinon.stub(HeaderStores.headerBarStore, 'getToggleStatus');
-      stub.returns(false);
-
-      var spy = sinon.spy(HeaderActions, 'toggleHeaderControls');
-
-      Actions.selectDoc('id');
-      assert.ok(spy.calledOnce);
-    });
-
-    it('does not toggles header controls if active', function () {
-      store.clearSelectedItems();
-      var stub = sinon.stub(HeaderStores.headerBarStore, 'getToggleStatus');
-      stub.returns(true);
-
-      var spy = sinon.spy(HeaderActions, 'toggleHeaderControls');
-
-      Actions.selectDoc('id');
-      assert.notOk(spy.calledOnce);
-    });
-
-    it('hides header control if active and no items selected', function () {
-      var stub = sinon.stub(HeaderStores.headerBarStore, 'getToggleStatus');
-      stub.returns(true);
-      store._selectedItems = {'id': true};
-
-      var spy = sinon.spy(HeaderActions, 'toggleHeaderControls');
-
-      Actions.selectDoc('id');
-      assert.ok(spy.calledOnce);
-
-    });
-
-  });
 
   describe('#deleteSelected', function () {
     var confirmStub;

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/index-results/tests/index-results.componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/tests/index-results.componentsSpec.react.jsx b/app/addons/documents/index-results/tests/index-results.componentsSpec.react.jsx
index 85dfecd..ee4811c 100644
--- a/app/addons/documents/index-results/tests/index-results.componentsSpec.react.jsx
+++ b/app/addons/documents/index-results/tests/index-results.componentsSpec.react.jsx
@@ -13,79 +13,196 @@ define([
   'api',
   'addons/documents/index-results/index-results.components.react',
   'addons/documents/index-results/actions',
+  'addons/documents/index-results/stores',
   'addons/documents/resources',
   'addons/databases/resources',
   'testUtils',
   "react"
-], function (FauxtonAPI, Views, IndexResultsActions, Resources, Databases, utils, React) {
+], function (FauxtonAPI, Views, IndexResultsActions, Stores, Documents, Databases, utils, React) {
   FauxtonAPI.router = new FauxtonAPI.Router([]);
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
+  var store = Stores.indexResultsStore;
 
   describe('Index Results', function () {
-    var container, el;
+    var container, instance;
 
-    beforeEach(function () {
-      container = document.createElement('div');
-    });
+    describe('no results text', function () {
+      beforeEach(function () {
+        container = document.createElement('div');
+        store.reset();
+      });
 
-    afterEach(function () {
-      React.unmountComponentAtNode(container);
-    });
+      afterEach(function () {
+        React.unmountComponentAtNode(React.findDOMNode(instance).parentNode);
+        store.reset();
+      });
+
+      it('renders a default text', function () {
+        IndexResultsActions.newResultsList({
+          collection: [],
+          deleteable: true
+        });
+        IndexResultsActions.resultsListReset();
 
-    it('renders a default text', function () {
-      IndexResultsActions.newResultsList({
-        collection: [],
-        deleteable: true
+        instance = TestUtils.renderIntoDocument(<Views.List />, container);
+        var $el = $(instance.getDOMNode());
+        assert.equal($el.text(), 'No Index Created Yet!');
       });
-      IndexResultsActions.resultsListReset();
 
-      el = TestUtils.renderIntoDocument(<Views.List />, container);
-      var $el = $(el.getDOMNode());
-      assert.equal($el.text(), 'No Index Created Yet!');
+      it('you can change the default text', function () {
+        IndexResultsActions.newResultsList({
+          collection: [],
+          deleteable: true,
+          textEmptyIndex: 'I <3 Hamburg'
+        });
+
+        instance = TestUtils.renderIntoDocument(<Views.List />, container);
+        var $el = $(instance.getDOMNode());
+        assert.equal($el.text(), 'I <3 Hamburg');
+      });
     });
 
-    it('you can change the default text', function () {
-      IndexResultsActions.newResultsList({
-        collection: [],
-        deleteable: true,
-        textEmptyIndex: 'No Document Created Yet!'
+    describe('checkbox rendering', function () {
+      var opts = {
+        params: {},
+        database: {
+          safeID: function () { return '1';}
+        }
+      };
+
+      beforeEach(function () {
+        container = document.createElement('div');
+        store.reset();
+      });
+
+      afterEach(function () {
+        React.unmountComponentAtNode(React.findDOMNode(instance).parentNode);
+        store.reset();
+      });
+
+      function createDocColumn (docs) {
+        docs = docs.map(function (doc) {
+          return Documents.Doc.prototype.parse(doc);
+        });
+
+        return new Documents.AllDocs(docs, opts);
+      }
+
+      it('does not render checkboxes for elements with no id in a table', function () {
+        IndexResultsActions.sendMessageNewResultList({
+          collection: createDocColumn([{foo: 'testId1'}, {bar: 'testId1'}])
+        });
+
+        store.enableTableView();
+
+        IndexResultsActions.resultsListReset();
+
+        instance = TestUtils.renderIntoDocument(
+          <Views.List />,
+          container
+        );
+
+        var $el = $(instance.getDOMNode());
+
+        assert.ok($el.find('.tableview-header-el-checkbox').length === 0);
+      });
+
+      it('renders checkboxes for elements with id in a table', function () {
+        IndexResultsActions.sendMessageNewResultList({
+          collection: createDocColumn([{id: '1', foo: 'testId1'}, {bar: 'testId1'}])
+        });
+
+        store.enableTableView();
+
+        IndexResultsActions.resultsListReset();
+
+        instance = TestUtils.renderIntoDocument(
+          <Views.List />,
+          container
+        );
+
+        var $el = $(instance.getDOMNode());
+
+        assert.ok($el.find('.tableview-checkbox-cell').length > 0);
+      });
+
+      it('renders checkboxes for elements with an id in a json view', function () {
+        IndexResultsActions.sendMessageNewResultList({
+          collection: createDocColumn([{id: '1', foo: 'testId1'}, {bar: 'testId1'}])
+        });
+
+        IndexResultsActions.resultsListReset();
+
+        store.disableTableView();
+
+        instance = TestUtils.renderIntoDocument(
+          <Views.List />,
+          container
+        );
+
+        var $el = $(instance.getDOMNode());
+
+        assert.ok($el.find('.js-row-select').length > 0);
+      });
+
+      it('does not render checkboxes for elements with no id in a json view', function () {
+        IndexResultsActions.sendMessageNewResultList({
+          collection: createDocColumn([{foo: 'testId1'}, {bar: 'testId1'}])
+        });
+
+        IndexResultsActions.resultsListReset();
+
+        store.disableTableView();
+
+        instance = TestUtils.renderIntoDocument(
+          <Views.List />,
+          container
+        );
+
+        var $el = $(instance.getDOMNode());
+
+        assert.notOk($el.hasClass('show-select'));
       });
-      IndexResultsActions.resultsListReset();
 
-      el = TestUtils.renderIntoDocument(<Views.List />, container);
-      var $el = $(el.getDOMNode());
-      assert.equal($el.text(), 'No Document Created Yet!');
     });
 
     describe('loading', function () {
       beforeEach(function () {
         container = document.createElement('div');
+        store.reset();
       });
 
       afterEach(function () {
-        React.unmountComponentAtNode(container);
+        React.unmountComponentAtNode(React.findDOMNode(instance).parentNode);
+        store.reset();
       });
+
       it('should show loading component', function () {
-        var resultsEl = TestUtils.renderIntoDocument(<Views.ResultsScreen
-          isLoading={true}
-          />, container);
+        var results = {results: []};
+        instance = TestUtils.renderIntoDocument(
+          <Views.ResultsScreen results={results} isLoading={true} />,
+          container
+        );
 
-        var $el = $(resultsEl.getDOMNode());
+        var $el = $(instance.getDOMNode());
 
         assert.ok($el.find('.loading-lines').length === 1);
       });
 
       it('should not show loading component', function () {
-        var resultsEl = TestUtils.renderIntoDocument(<Views.ResultsScreen
-          isLoading={false}
-          />, container);
+        var results = {results: []};
+        instance = TestUtils.renderIntoDocument(
+          <Views.ResultsScreen results={results} isLoading={false} />,
+          container
+        );
 
-        var $el = $(resultsEl.getDOMNode());
+        var $el = $(instance.getDOMNode());
 
         assert.ok($el.find('.loading-lines').length === 0);
       });
     });
+
   });
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/index-results/tests/index-results.storesSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-results/tests/index-results.storesSpec.js b/app/addons/documents/index-results/tests/index-results.storesSpec.js
index e72d25c..85e1420 100644
--- a/app/addons/documents/index-results/tests/index-results.storesSpec.js
+++ b/app/addons/documents/index-results/tests/index-results.storesSpec.js
@@ -59,7 +59,7 @@ define([
       it('has correct doc format', function () {
         store._collection = new Documents.AllDocs([{_id: 'testId'}], opts);
 
-        var doc = store.getResults()[0];
+        var doc = store.getResults().results[0];
         assert.equal(doc.id, 'testId');
         assert.equal(doc.keylabel, 'id');
       });
@@ -118,41 +118,6 @@ define([
 
   });
 
-  describe('canCollapseDocs', function () {
-
-    it('returns true for no collapsed docs', function () {
-      store._collapsedDocs = {};
-      assert.ok(store.canCollapseDocs());
-    });
-
-    it('returns false for all collapsed docs', function () {
-      store._collection = new Documents.AllDocs([{_id: 'testId1'}, {_id: 'testId2'}], opts);
-
-      store._collapsedDocs = {
-        'testId1': true,
-        'testId2': true
-      };
-
-      assert.notOk(store.canCollapseDocs());
-    });
-
-  });
-
-  describe('canUncollapseDocs', function () {
-
-    it('returns true for collapsed docs', function () {
-      store._collapsedDocs = {'testId1': true};
-      assert.ok(store.canUncollapseDocs());
-    });
-
-    it('returns false for no collapsed docs', function () {
-      store.clearCollapsedDocs();
-
-      assert.notOk(store.canUncollapseDocs());
-    });
-
-  });
-
   describe('getDocContent', function () {
 
     it('returns full doc if not collapsed', function () {
@@ -164,14 +129,14 @@ define([
       assert.equal(JSON.parse(result).value, 'one');
     });
 
-    it('returns no doc content if collapsed', function () {
-      store._collection = new Documents.AllDocs([{_id: 'testId1', 'value': 'one'}], opts);
+    it('returns just the revision as content if collapsed', function () {
+      store._collection = new Documents.AllDocs([{_id: 'testId1', _rev: 'a', 'value': 'one'}], opts);
 
       var doc = store._collection.first();
-      store._collapsedDocs = {'testId1': true};
+      store._allCollapsed = true;
       var result = store.getDocContent(doc);
 
-      assert.equal('', result);
+      assert.deepEqual({"rev": "a"}, JSON.parse(result));
     });
 
   });
@@ -202,77 +167,135 @@ define([
 
   });
 
-  describe('#deSelectAllDocuments', function () {
+  describe('toggleSelectAllDocuments', function () {
 
     it('deselects all documents', function () {
       store._collection = new Documents.AllDocs([{_id: 'testId1', 'value': 'one'}], opts);
 
       store.selectAllDocuments();
       assert.ok(store.getSelectedItems().testId1);
-      store.deSelectAllDocuments();
+      store.toggleSelectAllDocuments();
       assert.equal(store.getSelectedItemsLength(), 0);
     });
+
+    it('deselects all documents', function () {
+      store.reset();
+      store._collection = new Documents.AllDocs([{_id: 'testId1', 'value': 'one'}], opts);
+
+      assert.equal(Object.keys(store.getSelectedItems()).length, 0);
+      store.toggleSelectAllDocuments();
+      assert.equal(store.getSelectedItemsLength(), 1);
+    });
   });
 
-  describe('#collapseSelectedDocs', function () {
+  describe('#createBulkDeleteFromSelected', function () {
 
-    it('collapses all selected docs', function () {
+    it('correctly creates BulkDeleteDocCollection', function () {
       store._collection = new Documents.AllDocs([{_id: 'testId1'}, {_id: 'testId2'}], opts);
 
-      store.clearCollapsedDocs();
+      store._bulkDeleteDocCollection = Documents.BulkDeleteDocCollection;
 
       store._selectedItems = {
         'testId1': true,
         'testId2': true
       };
 
-      store.collapseSelectedDocs();
-      assert.equal(store.getCollapsedDocsLength(), 2);
+      var bulkDelete = store.createBulkDeleteFromSelected();
+
+      assert.equal(bulkDelete.length, 2);
+      assert.ok(bulkDelete.at(0).get('_deleted'));
     });
+  });
+
+  it('tries to guess a pseudo schema for table views', function () {
+    var doclist = [
+      {_id: 'testId1', value: 'one'},
+      {_id: 'testId2', foo: 'one'},
+      {_id: 'testId3', bar: 'one'},
+    ];
 
+    var schema = store.getPseudoSchema(doclist);
+
+    assert.ok(schema.indexOf('_id') !== -1);
+    assert.ok(schema.indexOf('value') !== -1);
+    assert.ok(schema.indexOf('foo') !== -1);
+    assert.ok(schema.indexOf('bar') !== -1);
   });
 
-  describe('#unCollapseSelectedDocs', function () {
+  it('uses unique values for the pseudo schema', function () {
+    var doclist = [
+      {_id: 'testId1', foo: 'one'},
+      {_id: 'testId2', foo: 'one'}
+    ];
 
-    it('uncollapses all selected docs', function () {
-      store._collection = new Documents.AllDocs([{_id: 'testId1'}, {_id: 'testId2'}], opts);
+    var schema = store.getPseudoSchema(doclist);
 
-      store.clearCollapsedDocs();
+    assert.equal(schema.length, 2);
+    assert.equal(schema.length, 2);
+    assert.ok(schema.indexOf('foo') !== -1);
+    assert.ok(schema.indexOf('_id') !== -1);
+  });
 
-      store._selectedItems = {
-        'testId1': true,
-        'testId2': true
-      };
+  it('puts the id into the array as first element', function () {
+    var doclist = [
+      {foo: 'one', _id: 'testId1'},
+      {foo: 'one', _id: 'testId2'}
+    ];
 
-      store.collapseSelectedDocs();
-      assert.equal(store.getCollapsedDocsLength(), 2);
-      store.unCollapseSelectedDocs();
-      assert.equal(store.getCollapsedDocsLength(), 0);
-    });
+    var schema = store.getPseudoSchema(doclist);
+
+    assert.equal(schema.shift(), '_id');
   });
 
-  describe('#createBulkDeleteFromSelected', function () {
+  it('normalizes different content from include_docs enabled', function () {
+    var doclist = [
+      {_id: 'testId2', foo: 'one', doc: {"_rev": "1", "ente": "gans", "fuchs": "hase"}},
+      {_id: 'testId3', foo: 'two', doc: {"_rev": "2", "haus": "blau", "tanne": "acht"}}
+    ];
 
-    it('correctly creates BulkDeleteDocCollection', function () {
-      store._collection = new Documents.AllDocs([{_id: 'testId1'}, {_id: 'testId2'}], opts);
+    var res = store.normalizeTableData(doclist);
+    assert.deepEqual(res[0], {"_rev": "1", "ente": "gans", "fuchs": "hase"});
+  });
 
-      store._bulkDeleteDocCollection = Documents.BulkDeleteDocCollection;
+  it('normalizes different content from include_docs disabled', function () {
+    var doclist = [
+      {id: 'testId2', foo: 'one'},
+      {id: 'testId3', foo: 'two'}
+    ];
 
-      store._selectedItems = {
-        'testId1': true,
-        'testId2': true
-      };
+    var res = store.normalizeTableData(doclist);
+    assert.deepEqual(doclist, res);
+  });
 
-      var bulkDelete = store.createBulkDeleteFromSelected();
+  it('finds out if we have at least one editable/deleteable doc which needs an id', function () {
+    var doclist = [
+      {id: 'testId2', foo: 'one'},
+      {id: 'testId3', foo: 'two'}
+    ];
 
-      assert.equal(bulkDelete.length, 2);
-      assert.ok(bulkDelete.at(0).get('_deleted'));
-    });
+    assert.ok(store.getHasEditableAndDeletableDoc(doclist));
 
+    doclist = [
+      {foo: 'one'},
+      {foo: 'two'}
+    ];
+
+    assert.notOk(store.getHasEditableAndDeletableDoc(doclist));
   });
 
+
   describe('#getMangoDoc', function () {
-    var store = new Stores.IndexResultsStore();
+    beforeEach(function () {
+      store = new Stores.IndexResultsStore();
+      dispatchToken = FauxtonAPI.dispatcher.register(store.dispatch);
+      opts = {
+        params: {},
+        database: {
+          safeID: function () { return '1';}
+        }
+      };
+    });
+
     var fakeMango = {
       ddoc: '_design/e4d338e5d6f047749f5399ab998b4fa04ba0c816',
       def: {
@@ -314,6 +337,7 @@ define([
       assert.ok(doc.get('name'));
       assert.ok(doc.get('ddoc'));
 
+      store._allCollapsed = false;
       var newDoc = store.getMangoDoc(doc);
       assert.notOk(JSON.parse(newDoc.content).name);
       assert.notOk(JSON.parse(newDoc.content).ddoc);

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/routes-documents.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-documents.js b/app/addons/documents/routes-documents.js
index 7ed5f58..0b4042d 100644
--- a/app/addons/documents/routes-documents.js
+++ b/app/addons/documents/routes-documents.js
@@ -114,9 +114,7 @@ function (app, FauxtonAPI, BaseRoute, Documents, Changes, ChangesActions, Databa
             docParams = params.docParams,
             collection;
 
-        ReactActions.resetHeaderController();
-
-        this.setComponent('#react-headerbar', ReactHeader.HeaderBarController);
+        this.setComponent('#react-headerbar', ReactHeader.BulkDocumentHeaderController);
         this.setComponent('#footer', ReactPagination.Footer);
 
         this.leftheader.updateCrumbs(this.getCrumbs(this.database));
@@ -139,7 +137,6 @@ function (app, FauxtonAPI, BaseRoute, Documents, Changes, ChangesActions, Databa
 
         IndexResultsActions.newResultsList({
           collection: collection,
-          isListDeletable: true,
           textEmptyIndex: 'No Documents Found',
           bulkCollection: Documents.BulkDeleteDocCollection
         });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/routes-index-editor.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-index-editor.js b/app/addons/documents/routes-index-editor.js
index 52c5da5..b156d1f 100644
--- a/app/addons/documents/routes-index-editor.js
+++ b/app/addons/documents/routes-index-editor.js
@@ -25,13 +25,14 @@ define([
   'addons/documents/pagination/stores',
   'addons/documents/index-results/actions',
   'addons/documents/index-results/index-results.components.react',
-  'addons/documents/pagination/pagination.react'
-
+  'addons/documents/pagination/pagination.react',
+  'addons/documents/header/header.react',
+  'addons/documents/header/header.actions',
 ],
 
 function (app, FauxtonAPI, Helpers, BaseRoute, Documents, IndexEditorComponents, ActionsIndexEditor,
           Databases, Components, PaginationStores, IndexResultsActions,
-          IndexResultsComponents, ReactPagination) {
+          IndexResultsComponents, ReactPagination, ReactHeader, ReactHeaderActions) {
 
 
   var IndexEditorAndResults = BaseRoute.extend({
@@ -97,7 +98,6 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Documents, IndexEditorComponents,
 
       IndexResultsActions.newResultsList({
         collection: this.indexedDocs,
-        isListDeletable: false,
         bulkCollection: Documents.BulkDeleteDocCollection
       });
 
@@ -109,6 +109,8 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Documents, IndexEditorComponents,
         designDocId: '_design/' + decodeDdoc
       });
 
+      this.setComponent('#react-headerbar', ReactHeader.BulkDocumentHeaderController);
+
       this.setComponent('#left-content', IndexEditorComponents.EditorController);
       this.setComponent('#dashboard-lower-content', IndexResultsComponents.List);
 
@@ -152,7 +154,6 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Documents, IndexEditorComponents,
 
       IndexResultsActions.newResultsList({
         collection: [],
-        isListDeletable: false,
         bulkCollection: Documents.BulkDeleteDocCollection
       });
     }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/routes-mango.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-mango.js b/app/addons/documents/routes-mango.js
index e2d827e..1293eef 100644
--- a/app/addons/documents/routes-mango.js
+++ b/app/addons/documents/routes-mango.js
@@ -86,15 +86,12 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Databases,
             }
           });
 
-      ReactActions.resetHeaderController();
-
       SidebarActions.setSelectedTab('mango-query');
-      this.setComponent('#react-headerbar', ReactHeader.HeaderBarController);
+      this.setComponent('#react-headerbar', ReactHeader.BulkDocumentHeaderController);
       this.setComponent('#footer', ReactPagination.Footer);
 
       IndexResultsActions.newMangoResultsList({
         collection: mangoResultCollection,
-        isListDeletable: true,
         textEmptyIndex: 'No Results',
         bulkCollection: Documents.BulkDeleteDocCollection
       });
@@ -135,10 +132,8 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Databases,
             }
           });
 
-
       IndexResultsActions.newResultsList({
         collection: mangoIndexCollection,
-        isListDeletable: true,
         bulkCollection: Documents.MangoBulkDeleteDocCollection,
         typeOfIndex: 'mango'
       });
@@ -152,8 +147,7 @@ function (app, FauxtonAPI, Helpers, BaseRoute, Databases,
         ]
       }));
 
-      ReactActions.resetHeaderController();
-      this.setComponent('#react-headerbar', ReactHeader.HeaderBarController);
+      this.setComponent('#react-headerbar', ReactHeader.BulkDocumentHeaderController);
       this.setComponent('#footer', ReactPagination.Footer);
 
       this.setComponent('#dashboard-lower-content', IndexResultsComponents.List);

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/shared-resources.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/shared-resources.js b/app/addons/documents/shared-resources.js
index 0c16154..7a635d9 100644
--- a/app/addons/documents/shared-resources.js
+++ b/app/addons/documents/shared-resources.js
@@ -293,13 +293,18 @@ define([
       });
 
       resp.rows = _.map(cleanRows, function (row) {
-        return {
+        var res = {
           _id: row.id,
           _rev: row.value.rev,
           value: row.value,
-          key: row.key,
-          doc: row.doc || undefined
+          key: row.key
         };
+
+        if (row.doc) {
+          res.doc = row.doc;
+        }
+
+        return res;
       });
 
       return PagingCollection.prototype.parse.call(this, resp);

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/246057e6/app/addons/documents/tests/nightwatch/bulkDelete.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/bulkDelete.js b/app/addons/documents/tests/nightwatch/bulkDelete.js
index 205f3b4..4889d15 100644
--- a/app/addons/documents/tests/nightwatch/bulkDelete.js
+++ b/app/addons/documents/tests/nightwatch/bulkDelete.js
@@ -24,14 +24,13 @@ module.exports = {
       .createDocument(newDocumentName1, newDatabaseName)
       .createDocument(newDocumentName2, newDatabaseName)
       .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
-      .waitForElementPresent('.control-toggle-alternative-header', waitTime, false)
+      .waitForElementPresent('.bulk-action-component-selector-group', waitTime, false)
 
       // ensures page content has loaded before proceeding
       .waitForElementVisible('.prettyprint', waitTime, false)
 
-      .clickWhenVisible('.control-toggle-alternative-header')
-      .clickWhenVisible('.control-select-all', waitTime, false)
-      .clickWhenVisible('.control-delete', waitTime, false)
+      .clickWhenVisible('.bulk-action-component-selector-group input[type="checkbox"]')
+      .clickWhenVisible('.bulk-actions button.fonticon-trash', waitTime, false)
       .acceptAlert()
       .waitForElementVisible('#global-notifications .alert.alert-info', waitTime, false)
       .waitForElementNotPresent('[data-id="' + newDocumentName1 + '"]', waitTime, false)
@@ -60,15 +59,14 @@ module.exports = {
       // ensures page content has loaded before proceeding
       .waitForElementVisible('.prettyprint', waitTime, false)
 
-      .clickWhenVisible('.control-toggle-alternative-header')
-      .waitForElementPresent('.control-select-all', waitTime, false)
-      .clickWhenVisible('.control-select-all', waitTime, false)
+      .clickWhenVisible('.bulk-action-component-selector-group input[type="checkbox"]')
+
       .waitForElementPresent('#next', waitTime, false)
       .clickWhenVisible('#next', waitTime, false)
       .waitForElementVisible('[data-id="27"]', waitTime, false)
       .waitForElementPresent('#previous', waitTime, false)
       .clickWhenVisible('#previous', waitTime, false)
-      .waitForElementPresent('.control-select-all.js-headerbar-togglebutton-selected', waitTime, false)
+      .waitForElementPresent('.bulk-action-component-selector-group input[type="checkbox"]:checked', waitTime, false)
       .end();
   }
 };