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();
}
};