couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From robertkowal...@apache.org
Subject [3/3] fauxton commit: updated refs/heads/master to 8b7e186
Date Mon, 31 Oct 2016 14:04:38 GMT
Fix database-list for dbs with slash in name

This fix for encoded database names also includes a big refactor
of the database page, pulling logic out of the views and gets rid
of backbone models.

 - no backbone models for the db list any more
 - replaces the jquery tooltips on the db list with react tooltips
 - avoiding safeURLName which is broken by design
 - no method calls on passed data in views any more
   (e.g. `{this.props.db.get('name')}` - focus on plain JSON data
   from flux stores

COUCHDB-3187

PR: #782
PR-URL: https://github.com/apache/couchdb-fauxton/pull/782
Reviewed-By: garren smith <garren.smith@gmail.com>


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

Branch: refs/heads/master
Commit: 8b7e186bf7c7aed6f14d1afb3dc52c011ba844b2
Parents: c1bb043
Author: Robert Kowalski <robertkowalski@apache.org>
Authored: Fri Sep 30 16:31:47 2016 +0200
Committer: Robert Kowalski <robertkowalski@apache.org>
Committed: Mon Oct 31 15:04:35 2016 +0100

----------------------------------------------------------------------
 app/addons/databases/actions.js                 | 117 +++++++++----
 app/addons/databases/actiontypes.js             |   5 +-
 app/addons/databases/base.js                    |  11 +-
 app/addons/databases/components.react.jsx       | 110 ++++++-------
 app/addons/databases/resources.js               |  83 +---------
 app/addons/databases/routes.js                  |  15 +-
 app/addons/databases/stores.js                  |  84 ++++++----
 .../databases/tests/componentsSpec.react.jsx    | 165 +++++++------------
 .../tests/nightwatch/checkDatabaseTooltip.js    |   8 +-
 .../tests/nightwatch/deletesDatabase.js         |   6 +-
 .../nightwatch/deletesDatabaseSpecialChars.js   |   6 +-
 .../tests/nightwatch/permissionsDbTable.js      |  40 +++++
 .../tests/nightwatch/specialCharListLinks.js    |  51 ++++++
 app/addons/databases/tests/resourcesSpec.js     |  50 ------
 app/addons/databases/tests/storesSpec.js        |  65 ++++----
 app/addons/documents/base.js                    |  20 +++
 app/addons/documents/routes-documents.js        |   4 +-
 app/addons/documents/routes-index-editor.js     |   4 +-
 app/addons/documents/shared-routes.js           |   4 -
 .../tests/nightwatch/createsDocument.js         |  18 +-
 .../tests/nightwatch/deletesDocuments.js        |   4 +-
 .../tests/nightwatch/editDocumentsFromView.js   |   5 +-
 app/addons/permissions/routes.js                |   4 +-
 .../custom-commands/auth/loginToGUI.js          |  15 +-
 .../custom-commands/createDocument.js           |   1 +
 25 files changed, 453 insertions(+), 442 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/actions.js b/app/addons/databases/actions.js
index 95062b3..9f38663 100644
--- a/app/addons/databases/actions.js
+++ b/app/addons/databases/actions.js
@@ -15,48 +15,99 @@ import Stores from "./stores";
 import ActionTypes from "./actiontypes";
 import Resources from "./resources";
 
+function getDatabaseDetails (dbList, fullDbList, cb) {
+  const databaseDetails = [];
+  const failedDbs = [];
+  let seen = 0;
+
+  dbList.forEach((db) => {
+    const url = FauxtonAPI.urls('databaseBaseURL', 'server', db);
+
+    fetch(url)
+      .then((res) => {
+        databaseDetails.push(res);
+      })
+      .fail((xhr) => {
+        failedDbs.push(db);
+      })
+      .always(() => {
+        seen++;
+
+        if (seen !== dbList.length) {
+          return;
+        }
+
+        updateDatabases({
+          dbList: dbList,
+          databaseDetails: databaseDetails,
+          failedDbs: failedDbs,
+          fullDbList: fullDbList
+        });
+      });
+  });
+}
+
+function fetch (url) {
+  return $.ajax({
+    cache: false,
+    url: url,
+    dataType: 'json'
+  }).then((res) => {
+    return res;
+  });
+}
+
+function getDatabaseList (limit, page) {
+  const url = FauxtonAPI.urls('allDBs', 'server');
+
+  return fetch(url);
+}
+
+function paginate (list, page, perPage) {
+  const start = (page - 1) * perPage;
+  const end = page * perPage;
+  return list.slice(start, end);
+}
+
+function updateDatabases (options) {
+  FauxtonAPI.dispatch({
+    type: ActionTypes.DATABASES_UPDATE,
+    options: options
+  });
+}
+
 export default {
+  getDatabaseList: getDatabaseList,
+  paginate: paginate,
+  getDatabaseDetails: getDatabaseDetails,
+  fetch: fetch,
 
-  init: function (databases) {
-    var params = app.getParams();
-    var page = params.page ? parseInt(params.page, 10) : 1;
-    var perPage = FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
+  init: function () {
+    const params = app.getParams();
+    const page = params.page ? parseInt(params.page, 10) : 1;
+    const limit = FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
 
     this.setStartLoading();
-    FauxtonAPI.when(databases.fetch({ cache: false })).then(function () {
-
-      // if there are no databases, publish the init message anyway
-      if (!databases.paginated(page, perPage).length) {
-        FauxtonAPI.dispatch({
-          type: ActionTypes.DATABASES_INIT,
-          options: {
-            collection: [],
-            backboneCollection: databases,
-            page: page
-          }
-        });
-      }
 
-      var numComplete = 0;
-      _.each(databases.paginated(page, perPage), function (db) {
-        db.status.fetchOnce().always(function () {
-          numComplete++;
-          if (numComplete < databases.paginated(page, perPage).length) {
-            return;
-          }
-          FauxtonAPI.dispatch({
-            type: ActionTypes.DATABASES_INIT,
-            options: {
-              collection: databases.paginated(page, perPage),
-              backboneCollection: databases,
-              page: page
-            }
-          });
+    this.setPage(page);
+
+    getDatabaseList(limit, page)
+      .then((fullDbList) => {
+        const paginatedDbList = paginate(fullDbList, page, limit);
+
+        this.updateDatabases({
+          dbList: paginatedDbList,
+          databaseDetails: [],
+          failedDbs: [],
+          fullDbList: fullDbList
         });
+
+        getDatabaseDetails(paginatedDbList, fullDbList);
       });
-    }.bind(this));
   },
 
+  updateDatabases,
+
   setPage: function (page) {
     FauxtonAPI.dispatch({
       type: ActionTypes.DATABASES_SETPAGE,

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/actiontypes.js b/app/addons/databases/actiontypes.js
index 9305684..e9665c0 100644
--- a/app/addons/databases/actiontypes.js
+++ b/app/addons/databases/actiontypes.js
@@ -10,9 +10,10 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 export default {
-  DATABASES_INIT: 'DATABASES_INIT',
   DATABASES_SETPAGE: 'DATABASES_SETPAGE',
   DATABASES_SET_PROMPT_VISIBLE: 'DATABASES_SET_PROMPT_VISIBLE',
   DATABASES_STARTLOADING: 'DATABASES_STARTLOADING',
-  DATABASES_LOADCOMPLETE: 'DATABASES_LOADCOMPLETE'
+  DATABASES_LOADCOMPLETE: 'DATABASES_LOADCOMPLETE',
+
+  DATABASES_UPDATE: 'DATABASES_UPDATE'
 };

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/base.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/base.js b/app/addons/databases/base.js
index 0ebb174..33cd69a 100644
--- a/app/addons/databases/base.js
+++ b/app/addons/databases/base.js
@@ -35,8 +35,8 @@ Databases.databaseUrl = function (database) {
 FauxtonAPI.registerUrls('changes', {
   server: function (id, query) {
     return app.host + '/' + id + '/_changes' + query;
-
   },
+
   app: function (id, query) {
     return '/database/' + id + '/_changes' + query;
   },
@@ -47,8 +47,16 @@ FauxtonAPI.registerUrls('changes', {
 });
 
 FauxtonAPI.registerUrls('allDBs', {
+  server: function (query = '') {
+    return `${app.host}/_all_dbs${query}`;
+  },
+
   app: function () {
     return '_all_dbs';
+  },
+
+  apiurl: function (id, query) {
+    return window.location.origin + '/_all_dbs';
   }
 });
 
@@ -56,6 +64,7 @@ FauxtonAPI.registerUrls('databaseBaseURL', {
   server: function (database) {
     return window.location.origin + '/' + app.utils.safeURLName(database);
   },
+
   app: function (database) {
     return '/database/' + database;
   }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/databases/components.react.jsx b/app/addons/databases/components.react.jsx
index 2540b6d..654e0d1 100644
--- a/app/addons/databases/components.react.jsx
+++ b/app/addons/databases/components.react.jsx
@@ -21,9 +21,9 @@ import FauxtonComponentsReact from "..//fauxton/components.react";
 import Stores from "./stores";
 import Resources from "./resources";
 import Actions from "./actions";
-import Helpers from "../../helpers";
 
 import ReactSelect from "react-select";
+import {Tooltip, OverlayTrigger} from 'react-bootstrap';
 
 var ToggleHeaderButton = Components.ToggleHeaderButton;
 var databasesStore = Stores.databasesStore;
@@ -35,7 +35,7 @@ var DatabasesController = React.createClass({
 
   getStoreState: function () {
     return {
-      collection: databasesStore.getCollection(),
+      dbList: databasesStore.getDbList(),
       loading: databasesStore.isLoading(),
       showDeleteDatabaseModal: deleteDbModalStore.getShowDeleteDatabaseModal()
     };
@@ -62,25 +62,29 @@ var DatabasesController = React.createClass({
   },
 
   render: function () {
-    var collection = this.state.collection;
-    var loading = this.state.loading;
+    const {loading, dbList} = this.state;
+
     return (
       <DatabaseTable
         showDeleteDatabaseModal={this.state.showDeleteDatabaseModal}
-        body={collection}
+        dbList={dbList}
         loading={loading} />
     );
   }
 });
 
-var DatabaseTable = React.createClass({
+const DatabaseTable = React.createClass({
+
+  propTypes: {
+    dbList: React.PropTypes.array.isRequired,
+    showDeleteDatabaseModal: React.PropTypes.object.isRequired,
+    loading: React.PropTypes.bool.isRequired,
+  },
 
-  createRows: function () {
-    return _.map(this.props.body, function (item, iteration) {
+  createRows: function (dbList) {
+    return dbList.map((item, k) => {
       return (
-        <DatabaseRow
-          row={item}
-          key={iteration} />
+        <DatabaseRow item={item} key={k} />
       );
     });
   },
@@ -107,7 +111,7 @@ var DatabaseTable = React.createClass({
       );
     }
 
-    const rows = this.createRows();
+    const rows = this.createRows(this.props.dbList);
     return (
       <div className="view">
         <DeleteDatabaseModal
@@ -138,16 +142,6 @@ var DatabaseRow = React.createClass({
     row: React.PropTypes.object
   },
 
-  renderGraveyard: function (row) {
-    if (row.status.isGraveYard()) {
-      return (
-        <GraveyardInfo row={row} />
-      );
-    } else {
-      return null;
-    }
-  },
-
   getExtensionColumns: function (row) {
     var cols = FauxtonAPI.getExtensions('DatabaseTable:databaseRow');
     return _.map(cols, function (Item, index) {
@@ -160,64 +154,60 @@ var DatabaseRow = React.createClass({
   },
 
   render: function () {
-    var row = this.props.row;
-    //Adding this row check in as it seems our unit tests need them to pass
-    if (!row || !row.get) {return (<span></span>);};
+    const {
+      item
+    } = this.props;
 
-    var name = row.get("name");
+    const {encodedId, id, url, diskSize, docCount, docDelCount, showTombstoneWarning, failed } = item;
+    const tombStoneWarning = showTombstoneWarning ?
+      (<GraveyardInfo docCount={docCount} docDelCount={docDelCount} />) : null;
 
     // if the row status failed to load, inform the user
-    if (!row.status.loadSuccess) {
+    if (failed) {
       return (
         <tr>
-          <td>{name}</td>
+          <td data-name="database-load-fail-name">{id}</td>
           <td colSpan="4" className="database-load-fail">This database failed to load.</td>
         </tr>
       );
     }
-    var encoded = app.utils.safeURLName(name);
-    var size = Helpers.formatSize(row.status.dataSize());
 
     return (
       <tr>
         <td>
-          <a href={"#/database/" + encoded + "/_all_docs"}>{name}</a>
+          <a href={url}>{id}</a>
         </td>
-        <td>{size}</td>
-        <td>{row.status.numDocs()} {this.renderGraveyard(row)}</td>
-        {this.getExtensionColumns(row)}
+        <td>{diskSize}</td>
+        <td>{docCount} {tombStoneWarning}</td>
+        {this.getExtensionColumns(item)}
+
         <td className="database-actions">
           <a className="db-actions btn fonticon-replicate set-replication-start"
             title={"Replicate " + name}
-            href={"#/replication/" + encoded} />
+            href={"#/replication/" + encodedId} />
           <a
             className="db-actions btn icon-lock set-permissions"
-            title={"Set permissions for " + name} href={"#/database/" + encoded + "/permissions"} />
+            title={"Set permissions for " + name} href={"#/database/" + encodedId + "/permissions"} />
           <a
             className="db-actions btn icon-trash"
-            onClick={this.showDeleteDatabaseModal.bind(this, name)}
-            title={'Delete ' + name} data-bypass="true" />
+            onClick={this.showDeleteDatabaseModal.bind(this, id, encodedId)}
+            title={'Delete ' + id} data-bypass="true" />
         </td>
       </tr>
     );
   }
 });
 
-var GraveyardInfo = React.createClass({
+const GraveyardInfo = ({docCount, docDelCount}) => {
+  const graveyardTitle = `This database has just ${docCount} docs and ${docDelCount} deleted docs`;
+  const tooltip = <Tooltip id="graveyard-tooltip">{graveyardTitle}</Tooltip>;
 
-  componentDidMount: function () {
-    $(ReactDOM.findDOMNode(this.refs.myself)).tooltip();
-  },
-
-  render: function () {
-    var row = this.props.row;
-    var graveyardTitle = "This database has just " + row.status.numDocs() +
-      " docs and " + row.status.numDeletedDocs() + " deleted docs";
-    return (
-      <i className="js-db-graveyard icon icon-exclamation-sign" ref="myself" title={graveyardTitle}></i>
-    );
-  }
-});
+  return (
+    <OverlayTrigger placement="top" overlay={tooltip}>
+      <i className="js-db-graveyard icon icon-exclamation-sign" title={graveyardTitle}></i>
+    </OverlayTrigger>
+  );
+};
 
 const RightDatabasesHeader = () => {
   return (
@@ -312,7 +302,7 @@ var DatabasePagination = React.createClass({
 
   getStoreState: function () {
     return {
-      databaseNames: databasesStore.getDatabaseNames(),
+      totalAmountOfDatabases: databasesStore.getTotalAmountOfDatabases(),
       page: databasesStore.getPage()
     };
   },
@@ -334,18 +324,22 @@ var DatabasePagination = React.createClass({
   },
 
   render: function () {
-    var page = this.state.page;
-    var total = this.props.total || this.state.databaseNames.length;
+    const {page, totalAmountOfDatabases} = this.state;
+
     var urlPrefix = '#/' + this.props.linkPath + '?page=';
     var start = 1 + (page - 1) * FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
-    var end = Math.min(total, page * FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE);
+    var end = Math.min(totalAmountOfDatabases, page * FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE);
 
     return (
       <footer className="all-db-footer pagination-footer">
         <div id="database-pagination">
-          <FauxtonComponentsReact.Pagination page={page} total={total} urlPrefix={urlPrefix} />
+          <FauxtonComponentsReact.Pagination page={page} total={totalAmountOfDatabases} urlPrefix={urlPrefix} />
+        </div>
+        <div className="current-databases">
+          Showing <span className="all-db-footer__range">{start}&ndash;{end}</span>
+          of <span className="all-db-footer__total-db-count">{totalAmountOfDatabases}</span>
+          databases.
         </div>
-        <div className="current-databases">Showing {start}&ndash;{end} of {total} databases.</div>
       </footer>
     );
   }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/resources.js b/app/addons/databases/resources.js
index 4ee31cf..6e0720b 100644
--- a/app/addons/databases/resources.js
+++ b/app/addons/databases/resources.js
@@ -18,11 +18,6 @@ var Databases = FauxtonAPI.addon();
 Databases.DocLimit = 100;
 
 Databases.Model = FauxtonAPI.Model.extend({
-  initialize: function (options) {
-    this.status = new Databases.Status({
-      database: this
-    });
-  },
 
   documentation: function () {
     return FauxtonAPI.constants.DOC_URLS.ALL_DBS;
@@ -63,9 +58,7 @@ Databases.Model = FauxtonAPI.Model.extend({
       return app.host + "/" + this.safeID();
     }
   },
-  safeName: function () {
-    return app.utils.safeURLName(this.get("name"));
-  },
+
   safeID: function () {
     return app.utils.safeURLName(this.id);
   },
@@ -109,78 +102,4 @@ Databases.Changes = FauxtonAPI.Collection.extend({
   }
 });
 
-Databases.Status = FauxtonAPI.Model.extend({
-  url: function () {
-    return app.host + "/" + this.database.safeID();
-  },
-
-  initialize: function (options) {
-    this.database = options.database;
-    this.loadSuccess = false;
-  },
-
-  numDocs: function () {
-    return this.get("doc_count");
-  },
-
-  numDeletedDocs: function () {
-    return this.get("doc_del_count");
-  },
-
-  isGraveYard: function () {
-    return this.numDeletedDocs() > this.numDocs();
-  },
-
-  dataSize: function () {
-    return this.get('other').data_size;
-  },
-
-  parse: function (resp) {
-    this.loadSuccess = true;
-    return resp;
-  }
-});
-
-// TODO: shared databases - read from the user doc
-Databases.List = FauxtonAPI.Collection.extend({
-  model: Databases.Model,
-  documentation: function () {
-    return FauxtonAPI.constants.DOC_URLS.ALL_DBS;
-  },
-
-  getDatabaseNames: function () {
-    return _.map(this.toArray(), function (model) {
-      return model.get('name');
-    });
-  },
-
-  cache: {
-    expires: 60
-  },
-
-  url: function (context) {
-    if (context === "apiurl") {
-      return window.location.origin + "/_all_dbs";
-    } else {
-      return app.host + "/_all_dbs";
-    }
-  },
-
-  parse: function (resp) {
-    // TODO: pagination!
-    return _.map(resp, function (database) {
-      return {
-        id: app.utils.safeURLName(database),
-        name: database
-      };
-    });
-  },
-
-  paginated: function (page, perPage) {
-    var start = (page - 1) * perPage;
-    var end = page * perPage;
-    return this.slice(start, end);
-  }
-});
-
 export default Databases;

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/routes.js b/app/addons/databases/routes.js
index 6fa5722..e80935e 100644
--- a/app/addons/databases/routes.js
+++ b/app/addons/databases/routes.js
@@ -12,11 +12,11 @@
 
 import app from "../../app";
 import FauxtonAPI from "../../core/api";
-import Databases from "./resources";
 import Actions from "./actions";
 import Components from "./components.react";
+import Databases from "./resources";
 
-var AllDbsRouteObject = FauxtonAPI.RouteObject.extend({
+const AllDbsRouteObject = FauxtonAPI.RouteObject.extend({
   layout: 'one_pane',
 
   crumbs: [
@@ -33,19 +33,20 @@ var AllDbsRouteObject = FauxtonAPI.RouteObject.extend({
 
   selectedHeader: "Databases",
 
-  initialize: function () {
-    this.databases = new Databases.List();
-  },
+  initialize: function () {},
 
   allDatabases: function () {
-    Actions.init(this.databases);
+    Actions.init();
     this.setComponent("#right-header", Components.RightDatabasesHeader);
     this.setComponent("#dashboard-content", Components.DatabasesController);
     this.setComponent("#footer", Components.DatabasePagination);
   },
 
   apiUrl: function () {
-    return [this.databases.url("apiurl"), this.databases.documentation()];
+    return [
+      FauxtonAPI.urls('allDBs', 'apiurl'),
+      FauxtonAPI.constants.DOC_URLS.ALL_DBS
+    ];
   }
 });
 Databases.RouteObjects = [AllDbsRouteObject];

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/stores.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/stores.js b/app/addons/databases/stores.js
index 7cb3b8d..b4dd647 100644
--- a/app/addons/databases/stores.js
+++ b/app/addons/databases/stores.js
@@ -14,6 +14,9 @@ import app from "../../app";
 import FauxtonAPI from "../../core/api";
 import ActionTypes from "./actiontypes";
 import Resources from "./resources";
+import Helpers from "../../helpers";
+
+const Database = Resources.Model;
 
 var DatabasesStore = FauxtonAPI.Store.extend({
 
@@ -22,26 +25,18 @@ var DatabasesStore = FauxtonAPI.Store.extend({
   },
 
   reset: function () {
-    this._collection = new Backbone.Collection();
     this._loading = false;
     this._promptVisible = false;
-  },
+    this._page = 1;
 
-  init: function (collection, backboneCollection) {
-    this._collection = collection;
-    this._backboneCollection = backboneCollection;
-  },
-
-  setPage: function (page) {
-    this._page = page;
+    this._dbList = [];
+    this._databaseDetails = [];
+    this._failedDbs = [];
+    this._fullDbList = [];
   },
 
   getPage: function () {
-    if (this._page) {
-      return this._page;
-    } else {
-      return 1;
-    }
+    return this._page;
   },
 
   isLoading: function () {
@@ -60,41 +55,54 @@ var DatabasesStore = FauxtonAPI.Store.extend({
     this._promptVisible = promptVisible;
   },
 
-  obtainNewDatabaseModel: function (databaseName, nameAccCallback) {
-    return new this._backboneCollection.model({
+  obtainNewDatabaseModel: function (databaseName) {
+    return new Database({
       id: databaseName,
       name: databaseName
     });
   },
 
-  getCollection: function () {
-    return this._collection;
+  doesDatabaseExist: function (databaseName) {
+    return this._dbList.indexOf(databaseName) !== -1;
   },
 
-  getDatabaseNames: function () {
-    if (!this._backboneCollection || !this._backboneCollection.length) {
-      return [];
-    }
+  getTotalAmountOfDatabases: function () {
+    return this._fullDbList.length;
+  },
+
+  getDbList: function () {
+    return this._dbList.map((db) => {
+
+      const allDetails = this._databaseDetails.filter((el) => { return el.db_name === db; });
+      const data = {
+        id: db,
+        encodedId: encodeURIComponent(db),
+        url: FauxtonAPI.urls('allDocsSanitized', 'app', db),
+        failed: this._failedDbs.indexOf(db) !== -1
+      };
 
-    return this._backboneCollection.toJSON().map((item, key) => {
-      return item.name;
+      const res = Object.assign({}, data, this._getDetails(allDetails[0]));
+      return res;
     });
   },
 
-  doesDatabaseExist: function (databaseName) {
-    return this.getDatabaseNames().indexOf(databaseName) >= 0;
+  _getDetails: function (details) {
+    if (!details) {
+      return {};
+    }
+
+    return {
+      diskSize: Helpers.formatSize(details.disk_size || 0),
+      docCount: details.doc_count,
+      docDelCount: details.doc_del_count,
+      showTombstoneWarning: details.doc_del_count > details.doc_count
+    };
   },
 
   dispatch: function (action) {
     switch (action.type) {
-      case ActionTypes.DATABASES_INIT:
-        this.init(action.options.collection, action.options.backboneCollection);
-        this.setPage(action.options.page);
-        this.setLoading(false);
-      break;
-
       case ActionTypes.DATABASES_SETPAGE:
-        this.setPage(action.options.page);
+        this._page = action.options.page;
       break;
 
       case ActionTypes.DATABASES_SET_PROMPT_VISIBLE:
@@ -109,6 +117,14 @@ var DatabasesStore = FauxtonAPI.Store.extend({
         this.setLoading(false);
       break;
 
+      case ActionTypes.DATABASES_UPDATE:
+        this._fullDbList = action.options.fullDbList;
+        this._dbList = action.options.dbList;
+        this._databaseDetails = action.options.databaseDetails;
+        this._failedDbs = action.options.failedDbs;
+        this.setLoading(false);
+      break;
+
       default:
       return;
     }
@@ -117,7 +133,7 @@ var DatabasesStore = FauxtonAPI.Store.extend({
   }
 });
 
-var databasesStore = new DatabasesStore();
+const databasesStore = new DatabasesStore();
 databasesStore.dispatchToken = FauxtonAPI.dispatcher.register(databasesStore.dispatch.bind(databasesStore));
 
 export default {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/tests/componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/componentsSpec.react.jsx b/app/addons/databases/tests/componentsSpec.react.jsx
index 38b1de8..3554f8d 100644
--- a/app/addons/databases/tests/componentsSpec.react.jsx
+++ b/app/addons/databases/tests/componentsSpec.react.jsx
@@ -23,85 +23,7 @@ import { mount } from 'enzyme';
 
 var assert = utils.assert;
 
-describe('DatabasesController', function () {
-
-  var container, dbEl, oldGetCollection;
-
-  beforeEach(function () {
-    // define our own collection
-    oldGetCollection = Stores.databasesStore.getCollection;
-    Stores.databasesStore.getCollection = function () {
-      return [
-        {
-          "get": function (what) {
-            if ("name" === what) {
-              return "db1";
-            } else {
-              throw "Unknown get('" + what + "')";
-            }
-          },
-          "status": {
-            "loadSuccess": true,
-            "dataSize": function () {
-              return 2 * 1024 * 1024;
-            },
-            "numDocs": function () {
-              return 88;
-            },
-            "isGraveYard": function () {
-              return false;
-            }
-          }
-        },
-        {
-          "get": function (what) {
-            if ("name" === what) {
-              return "db2";
-            } else {
-              throw "Unknown get('" + what + "')";
-            }
-          },
-          "status": {
-            "loadSuccess": true,
-            "dataSize": function () {
-              return 1024;
-            },
-            "numDocs": function () {
-              return 188;
-            },
-            "numDeletedDocs": function () {
-              return 222;
-            },
-            "isGraveYard": function () {
-              return true;
-            }
-          }
-        }
-      ];
-    };
-    container = document.createElement('div');
-    dbEl = ReactDOM.render(React.createElement(Views.DatabasesController, {}), container);
-  });
-
-  afterEach(function () {
-    Stores.databasesStore.getCollection = oldGetCollection;
-    ReactDOM.unmountComponentAtNode(container);
-  });
-
-  it('renders base data of DBs', function () {
-
-    const el = ReactDOM.findDOMNode(dbEl);
-
-    assert.equal(1 + 2, el.getElementsByTagName('tr').length);
-    assert.equal("db1", el.getElementsByTagName('tr')[1].getElementsByTagName('td')[0].innerText.trim());
-    assert.equal("2.0 MB", el.getElementsByTagName('tr')[1].getElementsByTagName('td')[1].innerText.trim());
-    assert.equal("88", el.getElementsByTagName('tr')[1].getElementsByTagName('td')[2].innerText.trim());
-    assert.equal(0, el.getElementsByTagName('tr')[1].getElementsByTagName('td')[2].getElementsByTagName("i").length);
-    assert.equal("db2", el.getElementsByTagName('tr')[2].getElementsByTagName('td')[0].innerText.trim());
-    assert.equal(1, el.getElementsByTagName('tr')[2].getElementsByTagName('td')[2].getElementsByTagName("i").length);
-  });
-
-});
+const store = Stores.databasesStore;
 
 describe('AddDatabaseWidget', function () {
 
@@ -137,6 +59,11 @@ describe('AddDatabaseWidget', function () {
 
 
 describe('DatabasePagination', function () {
+
+  beforeEach(() => {
+    store.reset();
+  });
+
   it('uses custom URL prefix on the navigation if passed through props', function () {
     var container = document.createElement('div');
     var pagination = TestUtils.renderIntoDocument(<Views.DatabasePagination linkPath="_custom_path" />, container);
@@ -149,6 +76,26 @@ describe('DatabasePagination', function () {
 
     ReactDOM.unmountComponentAtNode(container);
   });
+
+  it('renders the database count and range', () => {
+    const controller = mount(<Views.DatabasePagination linkPath="_custom_path" />);
+    const dbList = [];
+
+    for (let i = 0; i < 30; i++) {
+      dbList.push(`db-${i}`);
+    }
+
+    Actions.updateDatabases({
+      dbList: dbList.slice(0, 10),
+      databaseDetails: [],
+      failedDbs: [],
+      fullDbList: dbList
+    });
+
+    assert.equal(controller.find('.all-db-footer__range').text(), '1–20');
+    assert.equal(controller.find('.all-db-footer__total-db-count').text(), '30');
+  });
+
 });
 
 describe('DatabaseTable', function () {
@@ -156,6 +103,12 @@ describe('DatabaseTable', function () {
 
   beforeEach(function () {
     container = document.createElement('div');
+    Actions.updateDatabases({
+      dbList: ['db1'],
+      databaseDetails: [{db_name: 'db1', doc_count: 0, doc_del_count: 0}],
+      failedDbs: ['db1'],
+      fullDbList: ['db1']
+    });
   });
 
   afterEach(function () {
@@ -163,6 +116,7 @@ describe('DatabaseTable', function () {
   });
 
   it('adds multiple extra columns if extended', function () {
+
     var ColHeader1 = React.createClass({
       render: function () { return <th>EXTRA COL 1</th>; }
     });
@@ -178,7 +132,7 @@ describe('DatabaseTable', function () {
     FauxtonAPI.registerExtension('DatabaseTable:head', ColHeader3);
 
     var table = TestUtils.renderIntoDocument(
-      <Views.DatabaseTable showDeleteDatabaseModal={{showModal: false}} loading={false} body={[]} />,
+      <Views.DatabaseTable showDeleteDatabaseModal={{showModal: false}} loading={false} dbList={[]} />,
       container
     );
     var cols = $(ReactDOM.findDOMNode(table)).find('th');
@@ -196,16 +150,17 @@ describe('DatabaseTable', function () {
 
     FauxtonAPI.registerExtension('DatabaseTable:databaseRow', Cell);
 
-    var row = new Backbone.Model({ name: 'db name' });
-    row.status = {
-      loadSuccess: true,
-      dataSize: function () { return 0; },
-      numDocs: function () { return 0; },
-      isGraveYard: function () { return false; }
-    };
+    Actions.updateDatabases({
+      dbList: ['db1'],
+      databaseDetails: [{db_name: 'db1', doc_count: 0, doc_del_count: 0}],
+      failedDbs: [],
+      fullDbList: ['db1']
+    });
+
+    const list = store.getDbList();
 
     var databaseRow = TestUtils.renderIntoDocument(
-      <Views.DatabaseTable showDeleteDatabaseModal={{showModal: false}} body={[row]} />,
+      <Views.DatabaseTable showDeleteDatabaseModal={{showModal: false}} dbList={list} />,
       container
     );
     var links = $(ReactDOM.findDOMNode(databaseRow)).find('td');
@@ -219,32 +174,34 @@ describe('DatabaseTable', function () {
   });
 
   it('shows error message if row marked as failed to load', function () {
-    var row = new Backbone.Model({ name: 'db name' });
-    row.status = {
-      loadSuccess: false,
-      dataSize: function () { return 0; },
-      numDocs: function () { return 0; },
-      isGraveYard: function () { return false; }
-    };
+    Actions.updateDatabases({
+      dbList: ['db1'],
+      databaseDetails: [{db_name: 'db1', doc_count: 0, doc_del_count: 0}],
+      failedDbs: ['db1'],
+      fullDbList: ['db1']
+    });
+
+    const list = store.getDbList();
 
     var databaseRow = TestUtils.renderIntoDocument(
-      <Views.DatabaseTable showDeleteDatabaseModal={{showModal: false}} body={[row]} />,
+      <Views.DatabaseTable showDeleteDatabaseModal={{showModal: false}} dbList={list} />,
       container
     );
     assert.equal($(ReactDOM.findDOMNode(databaseRow)).find('.database-load-fail').length, 1);
   });
 
   it('shows no error if row marked as loaded', function () {
-    var row = new Backbone.Model({ name: 'db name' });
-    row.status = {
-      loadSuccess: true,
-      dataSize: function () { return 0; },
-      numDocs: function () { return 0; },
-      isGraveYard: function () { return false; }
-    };
+    Actions.updateDatabases({
+      dbList: ['db1'],
+      databaseDetails: [{db_name: 'db1', doc_count: 0, doc_del_count: 0}],
+      failedDbs: [],
+      fullDbList: ['db1']
+    });
+
+    const list = store.getDbList();
 
     var databaseRow = TestUtils.renderIntoDocument(
-      <Views.DatabaseTable showDeleteDatabaseModal={{showModal: false}} body={[row]} />,
+      <Views.DatabaseTable showDeleteDatabaseModal={{showModal: false}} dbList={list} />,
       container
     );
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/tests/nightwatch/checkDatabaseTooltip.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/nightwatch/checkDatabaseTooltip.js b/app/addons/databases/tests/nightwatch/checkDatabaseTooltip.js
index 7c54ee6..b2c24b6 100644
--- a/app/addons/databases/tests/nightwatch/checkDatabaseTooltip.js
+++ b/app/addons/databases/tests/nightwatch/checkDatabaseTooltip.js
@@ -28,16 +28,18 @@ module.exports = {
       .loginToGUI()
 
       // delete the document manually. This'll ensure the database page has at least one "!" icon
-      .waitForElementPresent('#dashboard-content a[href="#/database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
-      .click('#dashboard-content a[href="#/database/' + newDatabaseName + '/_all_docs"]')
+      .waitForElementPresent('#dashboard-content a[href="database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
+      .click('#dashboard-content a[href="database/' + newDatabaseName + '/_all_docs"]')
 
       //this opens the alternative header
       .clickWhenVisible('.bulk-action-component-panel input[type="checkbox"]')
       .clickWhenVisible('.bulk-action-component-selector-group button.fonticon-trash', waitTime, false)
       .acceptAlert()
       .waitForElementVisible('#global-notifications .alert.alert-info', waitTime, false)
-      .clickWhenVisible('#nav-links a[href="#/_all_dbs"]')
 
+      .checkForStringPresent(newDatabaseName, '"doc_del_count":1')
+
+      .clickWhenVisible('#nav-links a[href="#/_all_dbs"]')
       // now let's look at the actual UI to confirm the tooltip appears
       .waitForElementPresent('.js-db-graveyard', waitTime, false)
       .moveToElement('.js-db-graveyard', 1, 1)

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/tests/nightwatch/deletesDatabase.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/nightwatch/deletesDatabase.js b/app/addons/databases/tests/nightwatch/deletesDatabase.js
index 23e4094..c015a6f 100644
--- a/app/addons/databases/tests/nightwatch/deletesDatabase.js
+++ b/app/addons/databases/tests/nightwatch/deletesDatabase.js
@@ -42,14 +42,14 @@ module.exports = {
       .loginToGUI()
       .url(baseUrl + '/#/_all_dbs/')
 
-      .waitForElementPresent('a[href="#/database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
-      .assert.elementPresent('a[href="#/database/' + newDatabaseName + '/_all_docs"]')
+      .waitForElementPresent('a[href="database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
+      .assert.elementPresent('a[href="database/' + newDatabaseName + '/_all_docs"]')
       .clickWhenVisible('[title="Delete ' + newDatabaseName + '"]', waitTime, false)
       .setValue('.delete-db-modal input[type="text"]', [newDatabaseName, client.Keys.ENTER])
       .waitForElementNotPresent('.global-notification .fonticon-cancel', waitTime, false)
       .waitForElementPresent('.fauxton-table-list', waitTime, false)
       .checkForDatabaseDeleted(newDatabaseName, waitTime)
-      .assert.elementNotPresent('a[href="#/database/' + newDatabaseName + '/_all_docs"]')
+      .assert.elementNotPresent('a[href="database/' + newDatabaseName + '/_all_docs"]')
 
     .end();
   }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/tests/nightwatch/deletesDatabaseSpecialChars.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/nightwatch/deletesDatabaseSpecialChars.js b/app/addons/databases/tests/nightwatch/deletesDatabaseSpecialChars.js
index c68899d..0839adc 100644
--- a/app/addons/databases/tests/nightwatch/deletesDatabaseSpecialChars.js
+++ b/app/addons/databases/tests/nightwatch/deletesDatabaseSpecialChars.js
@@ -41,14 +41,14 @@ module.exports = {
       .loginToGUI()
       .url(baseUrl + '/#/_all_dbs/')
 
-      .waitForElementPresent('a[href="#/database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
-      .assert.elementPresent('a[href="#/database/' + newDatabaseName + '/_all_docs"]')
+      .waitForElementPresent('a[href="database/' + encodeURIComponent(newDatabaseName) + '/_all_docs"]', waitTime, false)
+      .assert.elementPresent('a[href="database/' + encodeURIComponent(newDatabaseName) + '/_all_docs"]')
       .clickWhenVisible('[title="Delete ' + newDatabaseName + '"]', waitTime, false)
       .setValue('.delete-db-modal input[type="text"]', [newDatabaseName, client.Keys.ENTER])
       .waitForElementNotPresent('.global-notification .fonticon-cancel', waitTime, false)
       .waitForElementPresent('.fauxton-table-list', waitTime, false)
       .checkForDatabaseDeleted(newDatabaseName, waitTime)
-      .assert.elementNotPresent('a[href="#/database/' + newDatabaseName + '/_all_docs"]')
+      .assert.elementNotPresent('a[href="database/' + newDatabaseName + '/_all_docs"]')
 
     .end();
   }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/tests/nightwatch/permissionsDbTable.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/nightwatch/permissionsDbTable.js b/app/addons/databases/tests/nightwatch/permissionsDbTable.js
new file mode 100644
index 0000000..c659aac
--- /dev/null
+++ b/app/addons/databases/tests/nightwatch/permissionsDbTable.js
@@ -0,0 +1,40 @@
+// 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.
+
+
+const helpers = require('../../../../../test/nightwatch_tests/helpers/helpers.js');
+
+module.exports = {
+
+  'lists databases with a 401' : function (client) {
+    const waitTime = client.globals.maxWaitTime;
+    const baseUrl = client.globals.test_settings.launch_url;
+
+    const userDoc = {
+      "_id": "org.couchdb.user:furbie",
+      "name": "furbie",
+      "type": "user",
+      "roles": [],
+      "password": "furbie"
+    };
+
+    client
+      .createDocument('org.couchdb.user:furbie', '_users', userDoc)
+      .loginToGUI('furbie', 'furbie')
+
+      .waitForElementVisible('.database-load-fail', waitTime, false)
+      .waitForElementVisible('[data-name="database-load-fail-name"]', waitTime, false)
+      .assert.containsText('[data-name="database-load-fail-name"]', '_global_changes')
+
+    .end();
+  }
+};

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/tests/nightwatch/specialCharListLinks.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/nightwatch/specialCharListLinks.js b/app/addons/databases/tests/nightwatch/specialCharListLinks.js
new file mode 100644
index 0000000..2954643
--- /dev/null
+++ b/app/addons/databases/tests/nightwatch/specialCharListLinks.js
@@ -0,0 +1,51 @@
+// 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.
+
+
+const testDatabases = [
+  't/t',
+  't/t-/t_f',
+  't/t/_f',
+  't/t-//t_f'
+];
+
+const tests = {};
+
+testDatabases.forEach((db) => {
+  return tests[`Db List works with special chars ${db}`] = createTest(db);
+});
+
+module.exports = tests;
+
+function createTest (db) {
+  return function (client) {
+
+    const waitTime = client.globals.maxWaitTime;
+    const baseUrl = client.globals.test_settings.launch_url;
+
+    client
+      .createDatabase(db)
+      .loginToGUI()
+
+      .url(baseUrl + '#/_all_dbs')
+      .clickWhenVisible(`.fauxton-table-list a[href="database/${encodeURIComponent(db)}/_all_docs"]`)
+
+      .waitForElementVisible('.faux-header__doc-header-title', waitTime, false)
+      .waitForElementVisible('.no-results-screen', waitTime, false)
+
+      .assert.containsText('.no-results-screen', 'No Documents Found')
+      .assert.containsText('.faux-header__doc-header-title', db)
+    .end();
+
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/tests/resourcesSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/resourcesSpec.js b/app/addons/databases/tests/resourcesSpec.js
deleted file mode 100644
index a199f05..0000000
--- a/app/addons/databases/tests/resourcesSpec.js
+++ /dev/null
@@ -1,50 +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.
-import FauxtonAPI from "../../../core/api";
-import Resources from "../resources";
-import testUtils from "../../../../test/mocha/testUtils";
-var assert = testUtils.assert;
-
-describe("Databases: List", function () {
-
-  describe("List items", function () {
-
-    it("detects graveyards", function () {
-      var modelWithGraveYard = new Resources.Status({
-        doc_count: 5,
-        doc_del_count: 6
-      });
-      var modelWithoutGraveYard = new Resources.Status({
-        doc_count: 6,
-        doc_del_count: 5
-      });
-      assert.ok(modelWithGraveYard.isGraveYard());
-      assert.ok(!modelWithoutGraveYard.isGraveYard());
-    });
-
-  });
-
-  describe('List of Databases', function () {
-    it('returns the names of databases in a list in an array', function () {
-      var listCollection = new Resources.List([{
-        name: 'ente'
-      },
-      {
-        name: 'rocko'
-      }]);
-      var databaseNames = listCollection.getDatabaseNames();
-
-      assert.equal(databaseNames[0], 'ente');
-      assert.equal(databaseNames[1], 'rocko');
-    });
-  });
-});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/databases/tests/storesSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/storesSpec.js b/app/addons/databases/tests/storesSpec.js
index c8d8446..d6d8d61 100644
--- a/app/addons/databases/tests/storesSpec.js
+++ b/app/addons/databases/tests/storesSpec.js
@@ -14,51 +14,54 @@ import app from "../../../app";
 import FauxtonAPI from "../../../core/api";
 import utils from "../../../../test/mocha/testUtils";
 import Stores from "../stores";
-import ActionTypes from "../actiontypes";
-import Resources from "../resources";
 
-var assert = utils.assert;
+import DatabaseActions from "../actions";
 
+const assert = utils.assert;
+
+const store = Stores.databasesStore;
 describe('Databases Store', function () {
 
-  var oldColl, oldBackbone;
-  var passedId, doneCallback, errorCallback, navigationTarget;
+  describe('database list storage', function () {
 
-  beforeEach(function () {
-    oldColl = Stores.databasesStore._collection;
-    oldBackbone = Stores.databasesStore._backboneCollection;
-    Stores.databasesStore._backboneCollection = {};
-  });
+    beforeEach(() => {
+      store.reset();
+    });
 
-  afterEach(function () {
-    Stores.databasesStore._collection = oldColl;
-    Stores.databasesStore._backboneCollection = oldBackbone;
-  });
+    it('marks failed detail fetches as failed dbs', () => {
+      DatabaseActions.updateDatabases({
+        dbList: ['db1', 'db2'],
+        databaseDetails: [{db_name: 'db1'}, {db_name: 'db2'}],
+        failedDbs: ['db1']
+      });
 
-  it("inits based on what we pass", function () {
-    Stores.databasesStore.init({"name": "col1"}, {"name": "col2"});
-    assert.equal("col1", Stores.databasesStore.getCollection().name);
-    assert.equal("col2", Stores.databasesStore._backboneCollection.name);
-  });
+      const list = store.getDbList();
 
-  describe("database collection info", function () {
+      assert.ok(list[0].failed);
+    });
 
-    beforeEach(() => {
-      const data = [{"name": "db1"}, {"name": "db2"}];
+    it('unions details', () => {
+      DatabaseActions.updateDatabases({
+        dbList: ['db1'],
+        databaseDetails: [{db_name: 'db1', doc_count: 5, doc_del_count: 3}],
+        failedDbs: []
+      });
 
-      const collection = new Backbone.Collection();
-      collection.add(data);
+      const list = store.getDbList();
 
-      Stores.databasesStore._backboneCollection = collection;
+      assert.equal(list[0].docCount, 5);
+      assert.equal(list[0].docDelCount, 3);
     });
 
-    it("determines database names", function () {
-      assert.ok(JSON.stringify(["db1", "db2"]) === JSON.stringify(Stores.databasesStore.getDatabaseNames().sort()));
-    });
+    it('determines database availability', () => {
+      DatabaseActions.updateDatabases({
+        dbList: ['db1', 'db2'],
+        databaseDetails: [],
+        failedDbs: []
+      });
 
-    it("determines database availability", function () {
-      assert(Stores.databasesStore.doesDatabaseExist("db1"));
-      assert(!Stores.databasesStore.doesDatabaseExist("db3"));
+      assert(store.doesDatabaseExist('db1'));
+      assert(!store.doesDatabaseExist('db3'));
     });
 
   });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/documents/base.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/base.js b/app/addons/documents/base.js
index e2de385..10cf4bd 100644
--- a/app/addons/documents/base.js
+++ b/app/addons/documents/base.js
@@ -24,12 +24,32 @@ function getQueryParam (query) {
 
 FauxtonAPI.registerUrls('allDocs', {
   server: function (id, query) {
+    /** XXX DEPRECATED: use allDocsSanitized **/
     return app.host + '/' + id + '/_all_docs' + getQueryParam(query);
   },
   app: function (id, query) {
+    /** XXX DEPRECATED: use allDocsSanitized **/
     return 'database/' + id + '/_all_docs' + getQueryParam(query);
   },
   apiurl: function (id, query) {
+    /** XXX DEPRECATED: use allDocsSanitized **/
+    return window.location.origin + '/' + id + '/_all_docs' + getQueryParam(query);
+  }
+});
+
+FauxtonAPI.registerUrls('allDocsSanitized', {
+  server: function (id, query) {
+    id = encodeURIComponent(id);
+    return app.host + '/' + id + '/_all_docs' + getQueryParam(query);
+  },
+
+  app: function (id, query) {
+    id = encodeURIComponent(id);
+    return 'database/' + id + '/_all_docs' + getQueryParam(query);
+  },
+
+  apiurl: function (id, query) {
+    id = encodeURIComponent(id);
     return window.location.origin + '/' + id + '/_all_docs' + getQueryParam(query);
   }
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/documents/routes-documents.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-documents.js b/app/addons/documents/routes-documents.js
index e95e339..767453c 100644
--- a/app/addons/documents/routes-documents.js
+++ b/app/addons/documents/routes-documents.js
@@ -57,15 +57,13 @@ var DocumentsRouteObject = BaseRoute.extend({
 
   establish: function () {
     return [
-      this.designDocs.fetch({ reset: true }),
-      this.allDatabases.fetchOnce()
+      this.designDocs.fetch({ reset: true })
     ];
   },
 
   initViews: function (dbName) {
     this.databaseName = dbName;
     this.database = new Databases.Model({id: this.databaseName});
-    this.allDatabases = this.getAllDatabases();
 
     this.createDesignDocsCollection();
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/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 8abed44..c139b67 100644
--- a/app/addons/documents/routes-index-editor.js
+++ b/app/addons/documents/routes-index-editor.js
@@ -54,7 +54,6 @@ var IndexEditorAndResults = BaseRoute.extend({
     var databaseName = options[0];
     this.databaseName = databaseName;
     this.database = new Databases.Model({id: databaseName});
-    this.allDatabases = new Databases.List();
     this.createDesignDocsCollection();
     this.addLeftHeader();
     this.addSidebar();
@@ -66,8 +65,7 @@ var IndexEditorAndResults = BaseRoute.extend({
 
   establish: function () {
     return [
-      this.designDocs.fetch({ reset: true }),
-      this.allDatabases.fetchOnce()
+      this.designDocs.fetch({ reset: true })
     ];
   },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/documents/shared-routes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/shared-routes.js b/app/addons/documents/shared-routes.js
index 9432330..8c66c4b 100644
--- a/app/addons/documents/shared-routes.js
+++ b/app/addons/documents/shared-routes.js
@@ -44,10 +44,6 @@ var BaseRoute = FauxtonAPI.RouteObject.extend({
     });
   },
 
-  getAllDatabases: function () {
-    return new Databases.List();  //getAllDatabases() can be overwritten instead of hard coded into initViews
-  },
-
   showQueryOptions: function (urlParams, ddoc, viewName) {
     var promise = this.designDocs.fetch({reset: true}),
         hasReduceFunction;

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/documents/tests/nightwatch/createsDocument.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/createsDocument.js b/app/addons/documents/tests/nightwatch/createsDocument.js
index 444e915..a04f212 100644
--- a/app/addons/documents/tests/nightwatch/createsDocument.js
+++ b/app/addons/documents/tests/nightwatch/createsDocument.js
@@ -43,14 +43,16 @@ module.exports = {
 
       .clickWhenVisible('#doc-editor-actions-panel .save-doc')
       .checkForDocumentCreated(newDocumentName)
-      .url(baseUrl + '/' + newDatabaseName + '/_all_docs')
-      .waitForElementPresent('body', waitTime, false)
-      .getText('body', function (result) {
-        var data = result.value,
-            createdDocIsPresent = data.indexOf(newDocumentName);
-
-        this.verify.ok(createdDocIsPresent > 0,
-          'Checking if new document shows up in _all_docs.');
+      .url(baseUrl + '#/database/' + newDatabaseName + '/_all_docs')
+      .waitForElementVisible('.prettyprint', waitTime, false)
+      .getText('.prettyprint', function (result) {
+        const data = result.value;
+        const createdDocIsPresent = data.indexOf(newDocumentName) !== -1;
+
+        this.verify.ok(
+          createdDocIsPresent,
+          'Checking if new document shows up in _all_docs.'
+        );
       })
     .end();
   }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/documents/tests/nightwatch/deletesDocuments.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/deletesDocuments.js b/app/addons/documents/tests/nightwatch/deletesDocuments.js
index d867705..721e9a2 100644
--- a/app/addons/documents/tests/nightwatch/deletesDocuments.js
+++ b/app/addons/documents/tests/nightwatch/deletesDocuments.js
@@ -26,8 +26,8 @@ module.exports = {
       .checkForDocumentCreated(newDocumentName)
       .checkForDocumentCreated(newDocumentName + '2')
       .url(baseUrl)
-      .waitForElementPresent('#dashboard-content a[href="#/database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
-      .clickWhenVisible('#dashboard-content a[href="#/database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
+      .waitForElementPresent('#dashboard-content a[href="database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
+      .clickWhenVisible('#dashboard-content a[href="database/' + newDatabaseName + '/_all_docs"]', waitTime, false)
       .waitForElementVisible('label[for="checkbox-' + newDocumentName + '"]', waitTime, false)
       .clickWhenVisible('label[for="checkbox-' + newDocumentName + '"]', waitTime, false)
       .clickWhenVisible('.bulk-action-component-selector-group button.fonticon-trash', waitTime, false)

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/documents/tests/nightwatch/editDocumentsFromView.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/editDocumentsFromView.js b/app/addons/documents/tests/nightwatch/editDocumentsFromView.js
index a57e6e9..06fa981 100644
--- a/app/addons/documents/tests/nightwatch/editDocumentsFromView.js
+++ b/app/addons/documents/tests/nightwatch/editDocumentsFromView.js
@@ -28,12 +28,13 @@ module.exports = {
         };
 
     client
-      .loginToGUI()
       .createDocument(newDocumentName, newDatabaseName, ddocContents)
       .populateDatabase(newDatabaseName)
 
+      .loginToGUI()
+
       //navigate to 'evens' view (declared above), then click on first document's pencil icon
-      .clickWhenVisible('#dashboard-content a[href="#/database/' + newDatabaseName + '/_all_docs"]')
+      .clickWhenVisible('#dashboard-content a[href="database/' + newDatabaseName + '/_all_docs"]')
       .clickWhenVisible('#nav-header-abc')
       .clickWhenVisible('#nav-design-function-abcviews a')
       .clickWhenVisible('#abc_evens')

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/app/addons/permissions/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/permissions/routes.js b/app/addons/permissions/routes.js
index 35b156a..e6460ec 100644
--- a/app/addons/permissions/routes.js
+++ b/app/addons/permissions/routes.js
@@ -36,7 +36,6 @@ var PermissionsRouteObject = BaseRoute.extend({
     this.security = new Resources.Security(null, {
       database: this.database
     });
-    this.allDatabases = new Databases.List();
 
     this.createDesignDocsCollection();
     this.addLeftHeader();
@@ -49,8 +48,7 @@ var PermissionsRouteObject = BaseRoute.extend({
 
   establish: function () {
     return [
-      this.designDocs.fetch({reset: true}),
-      this.allDatabases.fetchOnce()
+      this.designDocs.fetch({reset: true})
     ];
   },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/test/nightwatch_tests/custom-commands/auth/loginToGUI.js
----------------------------------------------------------------------
diff --git a/test/nightwatch_tests/custom-commands/auth/loginToGUI.js b/test/nightwatch_tests/custom-commands/auth/loginToGUI.js
index ee7d1f8..4f8eda2 100644
--- a/test/nightwatch_tests/custom-commands/auth/loginToGUI.js
+++ b/test/nightwatch_tests/custom-commands/auth/loginToGUI.js
@@ -10,13 +10,16 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 
-exports.command = function () {
+exports.command = LoginToGui;
 
-  var client = this,
-      waitTime = client.globals.maxWaitTime,
-      baseUrl = client.globals.test_settings.launch_url,
-      username = client.globals.test_settings.fauxton_username,
-      password = client.globals.test_settings.password;
+function LoginToGui (user, pw) {
+
+  const client = this;
+  const waitTime = client.globals.maxWaitTime;
+  const baseUrl = client.globals.test_settings.launch_url;
+
+  const username = user || client.globals.test_settings.fauxton_username;
+  const password = pw || client.globals.test_settings.password;
 
   client
     .url(baseUrl + '/#login')

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/8b7e186b/test/nightwatch_tests/custom-commands/createDocument.js
----------------------------------------------------------------------
diff --git a/test/nightwatch_tests/custom-commands/createDocument.js b/test/nightwatch_tests/custom-commands/createDocument.js
index 13ae0cd..ffa9fa6 100644
--- a/test/nightwatch_tests/custom-commands/createDocument.js
+++ b/test/nightwatch_tests/custom-commands/createDocument.js
@@ -49,6 +49,7 @@ CreateDocument.prototype.command = function (documentName, databaseName, docCont
     }
 
     const url = [couchUrl, databaseName, documentName].join('/');
+
     checkForDocumentCreated(url, helpers.maxWaitTime, () => {
       this.emit('complete');
     });


Mime
View raw message