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/02/19 13:59:42 UTC
[2/2] fauxton commit: updated refs/heads/master to e6f089a
Two pane editor
- introduce a editor on the left which changes a resultview on
the right
- delete old unused templates: design_doc_selector.html,
view_editor.html
- introduce styled dropdowns with no round corners
- allow breadcrumbs without mouseover effects
- populateDatabase handler now accepts a doc count and creates a
stubview
Based on a concept and design from Sean Barclay
<fu...@hotmail.com>
Watermark by Jenn Schiffer <je...@pancaketheorem.com> and Sue
Lockwood <de...@apache.org>
Closes #33
Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/e6f089aa
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/e6f089aa
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/e6f089aa
Branch: refs/heads/master
Commit: e6f089aa1ecd28d779d24fad57b118b2f525e9b4
Parents: a014c0b
Author: Robert Kowalski <ro...@apache.org>
Authored: Thu Jan 29 17:04:52 2015 +0100
Committer: Robert Kowalski <ro...@apache.org>
Committed: Thu Feb 19 13:56:14 2015 +0100
----------------------------------------------------------------------
.../databases/tests/nightwatch/createsView.js | 65 -----
app/addons/documents/assets/less/documents.less | 1 +
.../documents/assets/less/index-results.less | 27 ++
.../documents/assets/less/viewEditor.less | 265 +++++++++++++----
app/addons/documents/index-editor/actions.js | 32 +--
.../documents/index-editor/actiontypes.js | 1 -
.../documents/index-editor/components.react.jsx | 240 ++++++++++------
app/addons/documents/index-editor/stores.js | 18 +-
.../index-results.components.react.jsx | 52 ++++
app/addons/documents/routes-documents.js | 287 +------------------
app/addons/documents/routes-index-editor.js | 156 ++++++++++
app/addons/documents/routes.js | 8 +-
app/addons/documents/shared-routes.js | 173 +++++++++++
.../templates/design_doc_selector.html | 36 ---
app/addons/documents/templates/view_editor.html | 86 ------
app/addons/documents/tests/actionsSpec.js | 7 +-
.../tests/nightwatch/navigateToNewView.js | 2 +-
.../documents/tests/nightwatch/viewCreate.js | 94 ++++++
.../documents/tests/nightwatch/viewEdit.js | 89 ++++++
.../tests/nightwatch/viewQueryOptions.js | 34 +++
app/addons/documents/tests/routeSpec.js | 7 -
app/addons/documents/tests/storesSpec.js | 67 -----
.../tests/viewIndex.componentsSpec.react.jsx | 63 ++--
app/addons/documents/views-index.js | 19 +-
app/addons/fauxton/components.js | 13 +-
app/templates/layouts/two_pane.html | 36 ++-
assets/img/couch-watermark.png | Bin 0 -> 7053 bytes
assets/less/fauxton.less | 7 +
assets/less/templates.less | 27 +-
.../custom-commands/populateDatabase.js | 49 +++-
30 files changed, 1172 insertions(+), 789 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/databases/tests/nightwatch/createsView.js
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/nightwatch/createsView.js b/app/addons/databases/tests/nightwatch/createsView.js
deleted file mode 100644
index 0523993..0000000
--- a/app/addons/databases/tests/nightwatch/createsView.js
+++ /dev/null
@@ -1,65 +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.
-
-module.exports = {
- 'Creates a View' : function (client) {
- /*jshint multistr: true */
- var waitTime = 10000,
- newDatabaseName = client.globals.testDatabaseName,
- newDocumentName = 'create_view_doc',
- baseUrl = client.globals.test_settings.launch_url;
-
- var indexFunctionString = function (parity) {
- return 'function (doc) {' +
- ' if (doc.number%2 === '+parity+'){' +
- ' emit(doc._id, doc.number);' +
- ' }' +
- '}';
- };
-
- client
- .loginToGUI()
- .populateDatabase(newDatabaseName)
- .url(baseUrl+'/#/database/'+newDatabaseName+'/_all_docs')
- .waitForElementPresent('#new-design-docs-button', waitTime, false)
- .click('#new-design-docs-button a')
- .click('#new-design-docs-button a[href="#/database/'+newDatabaseName+'/new_view"]')
- .waitForElementPresent('#new-ddoc', waitTime, false)
- .setValue('#new-ddoc','test_design_doc')
- .clearValue('#index-name')
- .setValue('#index-name','even_ids')
- .execute('\
- var editor = ace.edit("map-function");\
- editor.getSession().setValue("'+indexFunctionString(0)+'");\
- ')
- .click('button.btn.btn-success.save')
- .waitForElementPresent('#test_design_doc_even_ids', waitTime, false)
- .click('#test_design_doc_even_ids')
- .waitForElementPresent('#nav-header-test_design_doc', waitTime, false)
- .click('#nav-header-test_design_doc .dropdown-toggle.icon.fonticon-plus-circled')
- .waitForElementPresent('#nav-header-test_design_doc', waitTime, false)
- .click('#nav-header-test_design_doc a[href="#/database/'+newDatabaseName+'/new_view/test_design_doc"]')
- .waitForElementPresent('#db-views-tabs-nav', waitTime, false)
- .click('#db-views-tabs-nav')
- .verify.valueContains('#index-name','new-view')
- .clearValue('#index-name')
- .setValue('#index-name','odd_ids')
- .execute('\
- var editor = ace.edit("map-function");\
- editor.getSession().setValue("'+indexFunctionString(1)+'");\
- ')
- .click('button.btn.btn-success.save')
- .waitForElementPresent('#test_design_doc_even_ids', waitTime, false)
- .waitForElementPresent('#test_design_doc_odd_ids', waitTime, false)
- .end();
- }
-};
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/assets/less/documents.less
----------------------------------------------------------------------
diff --git a/app/addons/documents/assets/less/documents.less b/app/addons/documents/assets/less/documents.less
index a08a191..8e2df47 100644
--- a/app/addons/documents/assets/less/documents.less
+++ b/app/addons/documents/assets/less/documents.less
@@ -17,6 +17,7 @@
@import "viewEditor.less";
@import "changes.less";
@import "sidenav.less";
+@import "index-results.less";
@import "header.less";
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/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
new file mode 100644
index 0000000..7809757
--- /dev/null
+++ b/app/addons/documents/assets/less/index-results.less
@@ -0,0 +1,27 @@
+// 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.
+
+.watermark-logo {
+ background: transparent url('../img/couch-watermark.png') no-repeat 50% 50%;
+ min-height: 400px;
+ padding-top: 60%;
+ text-align: center;
+ margin: 0 20%;
+ h3 {
+ border-bottom: 1px solid #ccc;
+ padding-bottom: 10px;
+ margin-bottom: 20px;
+ }
+ .preview {
+ margin: 0 10px;
+ }
+}
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/assets/less/viewEditor.less
----------------------------------------------------------------------
diff --git a/app/addons/documents/assets/less/viewEditor.less b/app/addons/documents/assets/less/viewEditor.less
index 37fc797..c4d8316 100644
--- a/app/addons/documents/assets/less/viewEditor.less
+++ b/app/addons/documents/assets/less/viewEditor.less
@@ -10,76 +10,223 @@
// License for the specific language governing permissions and limitations under
// the License.
-@import "../../../../../assets/less/animations.less";
@import "../../../../../assets/less/variables.less";
-.keyframes(fadeInDownNoReduce, {
- opacity: 0;
- height: 0px;
-},
-{
- opacity: 1;
- height: 546px;
-});
-
-
-.keyframes(fadeInDownReduce, {
- opacity: 0;
- height: 0px;
-},
-{
- opacity: 1;
- height: 745px;
-});
-
-.keyframes(fadeOutUpReduce, {
- opacity: 1;
- height: 745px;
-},
-{
- opacity: 0;
- height: 0px;
-});
-
-.keyframes(fadeOutUpNoReduce, {
- opacity: 1;
- height: 546px;
-},
-{
- opacity: 0;
- height: 0px;
-});
-
-
-.fadeInDownNoReduce-enter {
- .animation(fadeInDownNoReduce 1s both);
-}
+.editor-wrapper {
-.fadeInDownNoReduce-leave {
- .animation(fadeOutUpNoReduce 1s both);
-}
-.fadeInDownReduce-enter {
- .animation(fadeInDownReduce 1s both);
-}
+ .define-view {
+ padding-bottom: 70px;
+ }
+
+ .define-view {
+ .help-link {
+ margin-left: 3px;
+ }
+ }
+ label {
+ font-size: 16px;
+ }
+ .bordered-box {
+ border-bottom: 1px solid #ccc;
+ }
+ .padded-box {
+ margin: 25px 30px;
+ }
+ .db-title {
+ color: @brandPrimary;
+ line-height: 30px;
+ }
+ .new-ddoc-input {
+ margin-top: 25px;
+ }
-.fadeInDownReduce-leave {
- .animation(fadeOutUpReduce 1s both);
+ .styled-select {
+ width: 250px;
+ }
+ .styled-select label {
+ margin: 0;
+ }
+ .styled-select select {
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
+ background-color: #e6e6e6;
+ border: 1px solid #b3b3b3;
+ height: 45px;
+ width: 250px;
+ }
+ .styled-select select:-moz-focusring {
+ color: transparent;
+ text-shadow: 0 0 0 #000;
+ }
+ .styled-select select::-ms-expand {
+ display: none;
+ }
+ .styled-select i {
+ position: absolute;
+ right: 10px;
+ top: 12px;
+ pointer-events: none;
+ }
}
-#dashboard-upper-content{
- .editor-wrapper {
- padding-bottom: 70px;
+// 940px grid without margin
+// -------------------------
+@gridColumnWidthNoMargin: 60px;
+@gridGutterWidthNoMargin: 0px;
+@gridRowWidthNoMargin: (@gridColumns * @gridColumnWidthNoMargin) + (@gridGutterWidthNoMargin * (@gridColumns - 1));
+
+// 1200px min
+@gridColumnWidth1200NoMargin: 70px;
+@gridGutterWidth1200NoMargin: 0px;
+@gridRowWidth1200NoMargin: (@gridColumns * @gridColumnWidth1200NoMargin) + (@gridGutterWidth1200NoMargin * (@gridColumns - 1));
+
+// 768px-979px
+@gridColumnWidth768NoMargin: 42px;
+@gridGutterWidth768NoMargin: 0px;
+@gridRowWidth768NoMargin: (@gridColumns * @gridColumnWidth768NoMargin) + (@gridGutterWidth768NoMargin * (@gridColumns - 1));
+// Fluid grid
+// -------------------------
+@fluidGridColumnWidthNoMargin: percentage(@gridColumnWidthNoMargin/@gridRowWidthNoMargin);
+@fluidGridGutterWidthNoMargin: percentage(@gridGutterWidthNoMargin/@gridRowWidthNoMargin);
+// 1200px min
+@fluidGridColumnWidth1200NoMargin: percentage(@gridColumnWidth1200NoMargin/@gridRowWidth1200NoMargin);
+@fluidGridGutterWidth1200NoMargin: percentage(@gridGutterWidth1200NoMargin/@gridRowWidth1200NoMargin);
+// 768px-979px
+@fluidGridColumnWidth768NoMargin: percentage(@gridColumnWidth768NoMargin/@gridRowWidth768NoMargin);
+@fluidGridGutterWidth768NoMargin: percentage(@gridGutterWidth768NoMargin/@gridRowWidth768NoMargin);
+
+
+.two-pane > .fluid(@fluidGridColumnWidth1200NoMargin, @fluidGridGutterWidth1200NoMargin);
+
+.two-pane {
+
+ .core (@gridColumnWidth, @gridGutterWidth) {
+
+ .spanX (@index) when (@index > 0) {
+ .span@{index} { .span(@index); }
+ .spanX(@index - 1);
+ }
+ .spanX (0) {}
+
+ .offsetX (@index) when (@index > 0) {
+ .offset@{index} { .offset(@index); }
+ .offsetX(@index - 1);
+ }
+ .offsetX (0) {}
+
+ .offset (@columns) {
+ margin-left: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns + 1));
+ }
+
+ .span (@columns) {
+ width: (@gridColumnWidth * @columns) + (@gridGutterWidth * (@columns - 1));
+ }
+
+ .row {
+ margin-left: @gridGutterWidth * -1;
+ .clearfix();
+ }
+
+ [class*="span"] {
+ float: left;
+ min-height: 1px; // prevent collapsing columns
+ margin-left: @gridGutterWidth;
+ }
+
+ // Set the container width, and override it for fixed navbars in media queries
+ .container,
+ .navbar-static-top .container,
+ .navbar-fixed-top .container,
+ .navbar-fixed-bottom .container { .span(@gridColumns); }
+
+ // generate .spanX and .offsetX
+ .spanX (@gridColumns);
+ .offsetX (@gridColumns);
+
}
- .tab-content {
- height: auto;
- padding-top: 70px;
+ .fluid (@fluidGridColumnWidth, @fluidGridGutterWidth) {
+
+ .spanX (@index) when (@index > 0) {
+ .span@{index} { .span(@index); }
+ .spanX(@index - 1);
+ }
+ .spanX (0) {}
+
+ .offsetX (@index) when (@index > 0) {
+ .offset@{index} { .offset(@index); }
+ .offset@{index}:first-child { .offsetFirstChild(@index); }
+ .offsetX(@index - 1);
+ }
+ .offsetX (0) {}
+
+ .offset (@columns) {
+ margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth*2);
+ *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + (@fluidGridGutterWidth*2) - (.5 / @gridRowWidth * 100 * 1%);
+ }
+
+ .offsetFirstChild (@columns) {
+ margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) + (@fluidGridGutterWidth);
+ *margin-left: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%) + @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%);
+ }
+
+ .span (@columns) {
+ width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1));
+ *width: (@fluidGridColumnWidth * @columns) + (@fluidGridGutterWidth * (@columns - 1)) - (.5 / @gridRowWidth * 100 * 1%);
+ }
+
+ .row-fluid {
+ width: 100%;
+ .clearfix();
+ [class*="span"] {
+ .input-block-level();
+ float: left;
+ margin-left: @fluidGridGutterWidth;
+ *margin-left: @fluidGridGutterWidth - (.5 / @gridRowWidth * 100 * 1%);
+ }
+ [class*="span"]:first-child {
+ margin-left: 0;
+ }
+
+ // Space grid-sized controls properly if multiple per line
+ .controls-row [class*="span"] + [class*="span"] {
+ margin-left: @fluidGridGutterWidth;
+ }
+
+ // generate .spanX and .offsetX
+ .spanX (@gridColumns);
+ .offsetX (@gridColumns);
+ }
+
}
- #define-view {
- .help-link {
- margin-left: 3px;
+ .input(@gridColumnWidth, @gridGutterWidth) {
+
+ .spanX (@index) when (@index > 0) {
+ input.span@{index}, textarea.span@{index}, .uneditable-input.span@{index} { .span(@index); }
+ .spanX(@index - 1);
}
+ .spanX (0) {}
+
+ .span(@columns) {
+ width: ((@gridColumnWidth) * @columns) + (@gridGutterWidth * (@columns - 1)) - 14;
+ }
+
+ input,
+ textarea,
+ .uneditable-input {
+ margin-left: 0; // override margin-left from core grid system
+ }
+
+ // Space grid-sized controls properly if multiple per line
+ .controls-row [class*="span"] + [class*="span"] {
+ margin-left: @gridGutterWidth;
+ }
+
+ // generate .spanX
+ .spanX (@gridColumns);
+
}
}
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/index-editor/actions.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-editor/actions.js b/app/addons/documents/index-editor/actions.js
index c731b90..2dc320f 100644
--- a/app/addons/documents/index-editor/actions.js
+++ b/app/addons/documents/index-editor/actions.js
@@ -39,11 +39,6 @@ function (app, FauxtonAPI, Documents, ActionTypes) {
return {
//helpers are added here for use in testing actions
helpers: ActionHelpers,
- toggleEditor: function () {
- FauxtonAPI.dispatch({
- type: ActionTypes.TOGGLE_EDITOR
- });
- },
selectReduceChanged: function (reduceOption) {
FauxtonAPI.dispatch({
@@ -96,7 +91,6 @@ function (app, FauxtonAPI, Documents, ActionTypes) {
if (viewInfo.newDesignDoc) {
designDoc = ActionHelpers.createNewDesignDoc(viewInfo.designDocId, viewInfo.database);
-
} else {
designDoc = ActionHelpers.findDesignDoc(designDocs, viewInfo.designDocId);
}
@@ -123,30 +117,20 @@ function (app, FauxtonAPI, Documents, ActionTypes) {
clear: true
});
- if (_.any([viewInfo.designDocChanged, viewInfo.newDesignDoc, viewInfo.newView])) {
+ if (_.any([viewInfo.designDocChanged, viewInfo.hasViewNameChanged, viewInfo.newDesignDoc, viewInfo.newView])) {
FauxtonAPI.dispatch({
type: ActionTypes.VIEW_SAVED
});
-
var fragment = '/database/' +
- viewInfo.database.safeID() +
- '/' + designDoc.safeID() +
- '/_view/' +
- app.utils.safeURLName(viewInfo.viewName);
-
- FauxtonAPI.navigate(fragment);
+ viewInfo.database.safeID() +
+ '/' + designDoc.safeID() +
+ '/_view/' +
+ app.utils.safeURLName(viewInfo.viewName);
- //This should be changed to a dispatch once implemented
- FauxtonAPI.triggerRouteEvent('reloadDesignDocs', {
- selectedTab: app.utils.removeSpecialCharacters(designDoc.id.replace(/_design\//,'')) + '_' + app.utils.removeSpecialCharacters(viewInfo.viewName)
- });
- } else {
- FauxtonAPI.dispatch({
- type: ActionTypes.VIEW_SAVED
- });
- //This will should be changed to a dispatch once implemented
- FauxtonAPI.triggerRouteEvent('updateAllDocs', {ddoc: designDoc.id, view: viewInfo.viewName});
+ FauxtonAPI.navigate(fragment, {trigger: true});
}
+
+ FauxtonAPI.triggerRouteEvent('updateAllDocs', {ddoc: designDoc.id, view: viewInfo.viewName});
});
}
},
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/index-editor/actiontypes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-editor/actiontypes.js b/app/addons/documents/index-editor/actiontypes.js
index b2463da..fcce54e 100644
--- a/app/addons/documents/index-editor/actiontypes.js
+++ b/app/addons/documents/index-editor/actiontypes.js
@@ -14,7 +14,6 @@ define([], function () {
return {
EDIT_INDEX: 'EDIT_INDEX',
EDIT_NEW_INDEX: 'EDIT_NEW_INDEX',
- TOGGLE_EDITOR: 'TOGGLE_EDITOR',
SELECT_REDUCE_CHANGE: 'SELECT_REDUCE_CHANGE',
VIEW_SAVED: 'VIEW_SAVED',
VIEW_CREATED: 'VIEW_CREATED',
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/index-editor/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-editor/components.react.jsx b/app/addons/documents/index-editor/components.react.jsx
index c1c81af..6d83683 100644
--- a/app/addons/documents/index-editor/components.react.jsx
+++ b/app/addons/documents/index-editor/components.react.jsx
@@ -24,19 +24,22 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
var indexEditorStore = Stores.indexEditorStore;
var getDocUrl = app.helpers.getDocUrl;
- var ToggleButton = React.createClass({
-
- render: function() {
+ // global component
+ var StyledSelect = React.createClass({
+ render: function () {
return (
- <div className="dashboard-upper-menu">
- <ul className="nav nav-tabs" id="db-views-tabs-nav">
- <li>
- <a ref="toggle" data-bypass="true" id="index-nav" data-toggle="tab" href="#index" onClick={this.props.toggleEditor}>
- <i className="fonticon-wrench fonticon"></i>
- {this.props.title}
- </a>
- </li>
- </ul>
+ <div className="styled-select">
+ <label htmlFor={this.props.selectId}>
+ <i className="fonticon-down-dir"></i>
+ <select
+ value={this.props.selectValue}
+ id={this.props.selectId}
+ className={this.props.selectValue}
+ onChange={this.props.selectChange}
+ >
+ {this.props.selectContent}
+ </select>
+ </label>
</div>
);
}
@@ -58,10 +61,9 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
getNewDesignDocInput: function () {
return (
- <div id="new-ddoc-section" className="span5">
- <label className="control-label" htmlFor="new-ddoc"> _design/ </label>
- <div className="controls">
- <input value={this.state.designDoc} type="text" id="new-ddoc" onChange={this.onDesignDocChange} placeholder="newDesignDoc" />
+ <div className="new-ddoc-section">
+ <div className="new-ddoc-input">
+ <input value={this.state.designDoc} type="text" id="new-ddoc" onChange={this.onDesignDocChange} placeholder="Enter a Design Doc name" />
</div>
</div>
);
@@ -77,8 +79,18 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
});
},
- render: function () {
+ getSelectContent: function () {
var designDocOptions = this.getDesignDocOptions();
+
+ return (
+ <optgroup label="Select a document">
+ <option value="new">New Design Document </option>
+ {designDocOptions}
+ </optgroup>
+ );
+ },
+
+ render: function () {
var designDocInput;
var designDocId = this.state.designDocId;
@@ -88,23 +100,30 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
}
return (
- <div className="control-group design-doc-group">
- <div className="span3">
- <label htmlFor="ddoc">Save to Design Document
- <a className="help-link" data-bypass="true" href={getDocUrl('DESIGN_DOCS')} target="_blank">
- <i className="icon-question-sign">
- </i>
- </a>
- </label>
- <select id="ddoc" value={designDocId} onChange={this.selectChange}>
- <optgroup label="Select a document">
- <option value="new">New Design Document </option>
- {designDocOptions}
- </optgroup>
- </select>
+ <div className="new-ddoc-section">
+ <div className="bordered-box">
+ <div className="padded-box">
+ <div className="control-group design-doc-group">
+ <div className="pull-left">
+ <label htmlFor="ddoc"><strong>Design Document</strong>
+ <a className="help-link" data-bypass="true" href={getDocUrl('DESIGN_DOCS')} target="_blank">
+ <i className="icon-question-sign">
+ </i>
+ </a>
+ </label>
+ <StyledSelect
+ selectContent={this.getSelectContent()}
+ selectChange={this.selectChange}
+ selectId="ddoc"
+ selectValue={designDocId}
+ />
+ </div>
+ <div className="pull-left">
+ {designDocInput}
+ </div>
+ </div>
+ </div>
</div>
-
- {designDocInput}
</div>
);
},
@@ -189,7 +208,7 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
return (
<div className="control-group">
<label htmlFor="ace-function">
- {this.props.title}
+ <strong>{this.props.title}</strong>
{docsLink}
</label>
<div className="js-editor" id={this.props.id}>{this.props.code}</div>
@@ -280,18 +299,28 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
customReduceSection;
if (this.state.hasCustomReduce) {
- //customReduceSection = <CustomReduce ref="reduceEditor" reduce={this.state.reduce} />;
customReduceSection = <CodeEditor ref='reduceEditor' id={'reduce-function'} code={this.state.reduce} docs={false} title={'Custom Reduce function'} />;
}
return (
<div>
<div className="control-group">
- <label htmlFor="reduce-function-selector">Reduce (optional)<a className="help-link" data-bypass="true" href={getDocUrl('REDUCE_FUNCS')} target="_blank"><i className="icon-question-sign"></i></a></label>
-
- <select id="reduce-function-selector" value={this.state.reduceSelectedOption} onChange={this.selectChange}>
- {reduceOptions}
- </select>
+ <label htmlFor="reduce-function-selector">
+ <strong>Reduce (optional)</strong>
+ <a
+ className="help-link"
+ data-bypass="true"
+ href={getDocUrl('REDUCE_FUNCS')}
+ target="_blank"
+ >
+ <i className="icon-question-sign"></i>
+ </a>
+ </label>
+ <StyledSelect
+ selectContent={reduceOptions}
+ selectChange={this.selectChange}
+ selectId="reduce-function-selector"
+ selectValue={this.state.reduceSelectedOption} />
</div>
{customReduceSection}
@@ -363,6 +392,7 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
var Editor = React.createClass({
getStoreState: function () {
return {
+ hasViewNameChanged: indexEditorStore.hasViewNameChanged(),
database: indexEditorStore.getDatabase(),
isNewView: indexEditorStore.isNewView(),
viewName: indexEditorStore.getViewName(),
@@ -400,6 +430,16 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
}, this);
},
+ clearNotifications: function () {
+ ['mapEditor', 'reduceEditor'].forEach(function (editorName) {
+ if (editorName === 'reduceEditor' && !indexEditorStore.hasCustomReduce()) {
+ return;
+ }
+ var editor = this.refs[editorName].getEditor();
+ editor.editSaved();
+ }.bind(this));
+ },
+
saveView: function (event) {
event.preventDefault();
@@ -412,6 +452,8 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
return;
}
+ this.clearNotifications();
+
Actions.saveView({
database: this.state.database,
newView: this.state.isNewView,
@@ -419,6 +461,7 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
designDocId: this.state.designDocId,
newDesignDoc: this.state.newDesignDoc,
designDocChanged: this.state.hasDesignDocChanged,
+ hasViewNameChanged: this.state.hasViewNameChanged,
map: this.refs.mapEditor.getValue(),
reduce: this.refs.reduceEditor.getReduceValue(),
designDocs: this.state.designDocs
@@ -431,29 +474,68 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
render: function () {
return (
- <div className="tab-content" >
- <div className="tab-pane active" id="index">
- <div id="define-view" className="ddoc-alert well">
- <form className="form-horizontal view-query-save" onSubmit={this.saveView}>
-
- <DesignDocSelector />
-
- <div className="control-group">
- <label htmlFor="index-name">Index name<a className="help-link" data-bypass="true" href={getDocUrl('VIEW_FUNCS')} target="_blank"><i className="icon-question-sign"></i></a></label>
- <input type="text" id="index-name" value={this.state.viewName} onChange={this.viewChange} placeholder="Index name" />
- </div>
-
- <CodeEditor id={'map-function'} ref="mapEditor" title={"Map function"} docs={'MAP_FUNCS'} code={this.state.map}/>
- <ReduceEditor ref="reduceEditor"/>
-
- <div className="control-group">
- <button className="btn btn-success save"><i className="icon fonticon-ok-circled"></i> Save & Build Index</button>
- <DeleteView />
- </div>
- </form>
+ <div className="define-view">
+ <div className="bordered-box">
+ <div className="padded-box">
+ Views are the primary tools for querying and reporting.
+ </div>
+ </div>
+ <div className="bordered-box">
+ <div className="padded-box">
+ <strong>Database</strong>
+ <div className="db-title">{this.state.database.id}</div>
</div>
-
</div>
+ <form className="form-horizontal view-query-save" onSubmit={this.saveView}>
+ <DesignDocSelector />
+ <div className="control-group">
+ <div className="bordered-box">
+ <div className="padded-box">
+ <label htmlFor="index-name">
+ <strong>Index name</strong>
+ <a
+ className="help-link"
+ data-bypass="true"
+ href={getDocUrl('VIEW_FUNCS')}
+ target="_blank">
+ <i className="icon-question-sign"></i>
+ </a>
+ </label>
+ <input
+ type="text"
+ id="index-name"
+ value={this.state.viewName}
+ onChange={this.viewChange}
+ placeholder="Index name" />
+ </div>
+ </div>
+ </div>
+ <div className="control-group">
+ <div className="bordered-box">
+ <div className="padded-box">
+ <CodeEditor
+ id={'map-function'}
+ ref="mapEditor"
+ title={"Map function"}
+ docs={'MAP_FUNCS'}
+ code={this.state.map} />
+ </div>
+ </div>
+ </div>
+ <div className="bordered-box">
+ <div className="padded-box">
+ <ReduceEditor ref="reduceEditor" />
+ </div>
+ </div>
+ <div className="padded-box">
+ <div className="control-group">
+ <button type="submit" className="btn btn-success save">
+ <i className="icon fonticon-ok-circled"></i> Save & Build Index
+ </button>
+ <DeleteView />
+ </div>
+ </div>
+ </form>
</div>
);
}
@@ -464,17 +546,10 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
var EditorController = React.createClass({
getInitialState: function () {
return {
- showEditor: indexEditorStore.showEditor(),
- isNewView: indexEditorStore.isNewView(),
- title: indexEditorStore.getTitle(),
- hasCustomReduce: indexEditorStore.hasCustomReduce()
+ title: indexEditorStore.getTitle()
};
},
- onChange: function () {
- this.setState({showEditor: indexEditorStore.showEditor()});
- },
-
componentDidMount: function() {
indexEditorStore.on('change', this.onChange, this);
},
@@ -488,28 +563,9 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
},
render: function () {
- var editor = null;
- //a bit of hack for now.
- var wrapperClassName = 'editor-wrapper';
- var doTransitions = !this.state.isNewView;
- var editorTransitionName = 'fadeInDownNoReduce';
-
- if (this.state.showEditor) {
- //key is needed for animation;
- editor = <Editor key={1} />;
- wrapperClassName = '';
-
- if (this.state.hasCustomReduce) {
- editorTransitionName = 'fadeInDownReduce';
- }
- }
-
return (
- <div className={wrapperClassName}>
- <ToggleButton title={this.state.title} toggleEditor={this.toggleEditor} />
- <ReactCSSTransitionGroup transitionName={editorTransitionName} transitionLeave={doTransitions} transitionEnter={doTransitions}>
- {editor}
- </ReactCSSTransitionGroup>
+ <div className="editor-wrapper span5 scrollable">
+ <Editor />
</div>
);
}
@@ -523,11 +579,11 @@ function(app, FauxtonAPI, React, Stores, Actions, Components, beautifyHelper) {
removeEditor: function (el) {
React.unmountComponentAtNode(el);
},
- ToggleButton: ToggleButton,
ReduceEditor: ReduceEditor,
Editor: Editor,
DesignDocSelector: DesignDocSelector,
- Beautify: Beautify
+ Beautify: Beautify,
+ StyledSelect: StyledSelect
};
return Views;
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/index-editor/stores.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/index-editor/stores.js b/app/addons/documents/index-editor/stores.js
index cff8ba6..198a440 100644
--- a/app/addons/documents/index-editor/stores.js
+++ b/app/addons/documents/index-editor/stores.js
@@ -30,8 +30,8 @@ function(FauxtonAPI, ActionTypes) {
this._viewName = options.viewName || 'viewName';
this._designDocs = options.designDocs;
this._designDocId = options.designDocId;
- this._showEditor = this._newView;
this._designDocChanged = false;
+ this._viewNameChanged = false;
if (!this._newView && !this._newDesignDoc) {
this._view = this.getDesignDoc().get('views')[this._viewName];
@@ -106,14 +106,11 @@ function(FauxtonAPI, ActionTypes) {
setViewName: function (name) {
this._viewName = name;
- },
-
- showEditor: function () {
- return this._showEditor;
+ this._viewNameChanged = true;
},
hasCustomReduce: function () {
- if (!this.hasReduce()) {return false; }
+ if (!this.hasReduce()) { return false; }
return !_.contains(this.builtInReduces(), this.getReduce());
},
@@ -124,6 +121,10 @@ function(FauxtonAPI, ActionTypes) {
return true;
},
+ hasViewNameChanged: function () {
+ return this._viewNameChanged;
+ },
+
builtInReduces: function () {
return ['_sum', '_count', '_stats'];
},
@@ -175,11 +176,6 @@ function(FauxtonAPI, ActionTypes) {
this.triggerChange();
break;
- case ActionTypes.TOGGLE_EDITOR:
- this._showEditor = !this._showEditor;
- this.triggerChange();
- break;
-
case ActionTypes.SELECT_REDUCE_CHANGE:
this.updateReduceFromSelect(action.reduceSelectedOption);
this.triggerChange();
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/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
new file mode 100644
index 0000000..8c77739
--- /dev/null
+++ b/app/addons/documents/index-results/index-results.components.react.jsx
@@ -0,0 +1,52 @@
+// 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([
+ 'app',
+ 'api',
+ 'react'
+],
+
+function (app, FauxtonAPI, React) {
+
+ var NoResultScreen = React.createClass({
+ render: function () {
+ return (
+ <div className="watermark-logo">
+ <h3>No Index Created Yet!</h3>
+ </div>
+ );
+ }
+ });
+
+ var ViewResultListController = React.createClass({
+ render: function () {
+ var view = <NoResultScreen />;
+
+ return (
+ view
+ );
+ }
+ });
+
+ var Views = {
+ renderViewResultList: function (el) {
+ React.render(<ViewResultListController />, el);
+ },
+ removeViewResultList: function (el) {
+ React.unmountComponentAtNode(el);
+ },
+ List: ViewResultListController
+ };
+
+ return Views;
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/routes-documents.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes-documents.js b/app/addons/documents/routes-documents.js
index 5d5e2af..488ff6b 100644
--- a/app/addons/documents/routes-documents.js
+++ b/app/addons/documents/routes-documents.js
@@ -36,39 +36,20 @@ function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor, Datab
route: "allDocs",
roles: ["fx_loggedIn"]
},
- "database/:database/_design/:ddoc/_view/:view": {
- route: "viewFn",
- roles: ['fx_loggedIn']
- },
- "database/:database/_design/:ddoc/_lists/:fn": {
- route: "tempFn",
- roles: ['fx_loggedIn']
- },
- "database/:database/_design/:ddoc/_filters/:fn": {
- route: "tempFn",
- roles: ['fx_loggedIn']
- },
- "database/:database/_design/:ddoc/_show/:fn": {
- route: "tempFn",
- roles: ['fx_loggedIn']
- },
"database/:database/_design/:ddoc/_info": {
route: "designDocMetadata",
roles: ['fx_loggedIn']
},
- "database/:database/new_view": "newViewEditor",
- "database/:database/new_view/:designDoc": "newViewEditor",
"database/:database/_changes(:params)": "changes"
},
events: {
- "route:updateAllDocs": "updateAllDocsFromView",
"route:reloadDesignDocs": "reloadDesignDocs",
- "route:paginate": "paginate",
- "route:perPageChange": "perPageChange",
"route:changesFilterAdd": "addFilter",
"route:changesFilterRemove": "removeFilter",
- "route:updateQueryOptions": "updateQueryOptions"
+ 'route:updateAllDocs': 'updateAllDocsFromView',
+ 'route:paginate': 'paginate',
+ 'route:perPageChange': 'perPageChange',
},
initialize: function (route, masterLayout, options) {
@@ -139,26 +120,6 @@ function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor, Datab
this.apiUrl = [designDocInfo.url('apiurl'), designDocInfo.documentation()];
},
- tempFn: function(databaseName, ddoc, fn){
- this.setView("#dashboard-upper-content", new Documents.Views.temp({}));
- this.crumbs = function () {
- return [
- {"name": this.database.id, "link": Databases.databaseUrl(this.database)},
- ];
- };
- },
-
- createParams: function (options) {
- var urlParams = app.getParams(options),
- params = Documents.QueryParams.parse(urlParams),
- limit = this.getDocPerPageLimit(params, FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE);
-
- return {
- urlParams: urlParams,
- docParams: _.extend(params, {limit: limit})
- };
- },
-
/*
* docParams are the options collection uses to fetch from the server
* urlParams are what are shown in the url and to the user
@@ -236,219 +197,6 @@ function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor, Datab
this.rightHeader.showQueryOptions();
},
- viewFn: function (databaseName, ddoc, viewName) {
- var params = this.createParams(),
- urlParams = params.urlParams,
- docParams = params.docParams,
- decodeDdoc = decodeURIComponent(ddoc);
-
- viewName = viewName.replace(/\?.*$/,'');
-
- this.footer = this.setView('#footer', new Documents.Views.Footer());
-
- this.indexedDocs = new Documents.IndexCollection(null, {
- database: this.database,
- design: decodeDdoc,
- view: viewName,
- params: docParams,
- paging: {
- pageSize: this.getDocPerPageLimit(urlParams, parseInt(docParams.limit, 10))
- }
- });
-
- this.viewEditor = this.setView("#dashboard-upper-content", new Index.ViewEditorReact({
- viewName: viewName,
- newView: false,
- database: this.database,
- designDocs: this.designDocs,
- designDocId: "_design/" + decodeDdoc
- }));
-
- this.toolsView && this.toolsView.remove();
-
- this.documentsView = this.createViewDocumentsView({
- designDoc: decodeDdoc,
- docParams: docParams,
- urlParams: urlParams,
- database: this.database,
- indexedDocs: this.indexedDocs,
- designDocs: this.designDocs,
- view: viewName
- });
-
- this.sidebar.setSelectedTab(app.utils.removeSpecialCharacters(ddoc) + '_' + app.utils.removeSpecialCharacters(viewName));
-
- this.apiUrl = function() {
- return [this.indexedDocs.urlRef("apiurl", urlParams), FauxtonAPI.constants.DOC_URLS.GENERAL];
- };
-
- this.showQueryOptions(urlParams, ddoc, viewName);
- },
-
- showQueryOptions: function (urlParams, ddoc, viewName) {
- var promise = this.designDocs.fetch({reset: true}),
- that = this,
- hasReduceFunction;
-
- promise.then(function(resp) {
- var design = _.findWhere(that.designDocs.models, {id: '_design/'+ddoc});
- !_.isUndefined(hasReduceFunction = design.attributes.doc.views[viewName].reduce);
-
- that.rightHeader.showQueryOptions();
- that.rightHeader.resetQueryOptions({
- queryParams: urlParams,
- showStale: true,
- hasReduce: hasReduceFunction,
- viewName: viewName,
- ddocName: ddoc
- });
- });
- },
-
- ddocInfo: function (designDoc, designDocs, view) {
- return {
- id: "_design/" + designDoc,
- currView: view,
- designDocs: designDocs
- };
- },
-
- createViewDocumentsView: function (options) {
- if (!options.docParams) {
- options.docParams = {};
- }
-
- this.perPageDefault = options.docParams.limit || FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
-
- this.pagination = new Components.IndexPagination({
- collection: options.indexedDocs,
- scrollToSelector: '.scrollable',
- docLimit: options.urlParams.limit,
- perPage: this.perPageDefault
- });
- this.setView('#documents-pagination', this.pagination);
-
- this.allDocsNumber = new Documents.Views.AllDocsNumber({
- collection: options.indexedDocs,
- pagination: this.pagination,
- perPageDefault: this.perPageDefault
- });
-
- this.setView('#item-numbers', this.allDocsNumber);
-
- return this.setView("#dashboard-lower-content", new Documents.Views.AllDocsList({
- pagination: this.pagination,
- allDocsNumber: this.allDocsNumber,
- database: options.database,
- collection: options.indexedDocs,
- viewList: true,
- ddocInfo: this.ddocInfo(options.designDoc, options.designDocs, options.view),
- docParams: options.docParams,
- perPageDefault: this.perPageDefault,
- }));
- },
-
- newViewEditor: function (database, _designDoc) {
- var params = app.getParams();
- var newDesignDoc = true;
- var designDoc;
-
- if (!_.isUndefined(_designDoc)) {
- designDoc = "_design/" + _designDoc;
- newDesignDoc = false;
- }
-
- this.footer && this.footer.remove();
- this.toolsView && this.toolsView.remove();
- this.documentsView && this.documentsView.remove();
-
- this.viewEditor = this.setView("#dashboard-upper-content", new Index.ViewEditorReact({
- viewName: 'new-view',
- newView: true,
- database: this.database,
- designDocs: this.designDocs,
- designDocId: designDoc,
- newDesignDoc: newDesignDoc
- }));
-
- this.sidebar.setSelectedTab("new-view");
- this.rightHeader.hideQueryOptions();
-
- // clear out anything that was in the lower section
- this.removeView("#dashboard-lower-content");
- },
-
- updateAllDocsFromView: function (event) {
- var view = event.view,
- params = this.createParams(),
- urlParams = params.urlParams,
- docParams = params.docParams,
- ddoc = event.ddoc,
- defaultPageSize,
- isLazyInit,
- pageSize,
- collection;
-
- isLazyInit = _.isUndefined(this.documentsView) || _.isUndefined(this.documentsView.allDocsNumber);
- defaultPageSize = isLazyInit ? FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE : this.documentsView.perPage();
- docParams.limit = pageSize = this.getDocPerPageLimit(urlParams, defaultPageSize);
-
- if (event.allDocs) {
- this.eventAllDocs = true; // this is horrible. But I cannot get the trigger not to fire the route!
- this.database.buildAllDocs(docParams);
- collection = this.database.allDocs;
- collection.paging.pageSize = pageSize;
- } else {
- collection = this.indexedDocs = new Documents.IndexCollection(null, {
- database: this.database,
- design: ddoc,
- view: view,
- params: docParams,
- paging: {
- pageSize: pageSize
- }
- });
-
- if (!this.documentsView) {
- this.documentsView = this.createViewDocumentsView({
- designDoc: ddoc,
- docParams: docParams,
- urlParams: urlParams,
- database: this.database,
- indexedDocs: this.indexedDocs,
- designDocs: this.designDocs,
- view: view
- });
- }
- }
-
- this.documentsView.setParams(docParams, urlParams);
-
- // this will lazily initialize all sub-views and render them
- this.documentsView.forceRender();
- },
-
- perPageChange: function (perPage) {
- // We need to restore the collection parameters to the defaults (1st page)
- // and update the page size
- this.perPage = perPage;
- this.documentsView.forceRender();
- this.documentsView.collection.pageSizeReset(perPage, {fetch: false});
- this.allDocsNumber.forceRender();
- this.setDocPerPageLimit(perPage);
- },
-
- paginate: function (options) {
- var collection = this.documentsView.collection;
- this.documentsView.collection.reset(collection);
-
- this.documentsView.forceRender();
- this.allDocsNumber.forceRender();
-
- collection.paging.pageSize = options.perPage;
- var promise = collection[options.direction]({fetch: false});
- },
-
reloadDesignDocs: function (event) {
this.sidebar.forceRender();
@@ -457,31 +205,6 @@ function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor, Datab
}
},
- setDocPerPageLimit: function (perPage) {
- app.utils.localStorageSet('fauxton:perpage', perPage);
- },
-
- getDocPerPageLimit: function (urlParams, perPage) {
- var storedPerPage = perPage;
-
- if (window.localStorage) {
- storedPerPage = app.utils.localStorageGet('fauxton:perpage');
-
- if (!storedPerPage) {
- this.setDocPerPageLimit(perPage);
- storedPerPage = perPage;
- } else {
- storedPerPage = parseInt(storedPerPage, 10);
- }
- }
-
- if (!urlParams.limit || urlParams.limit > storedPerPage) {
- return parseInt(storedPerPage, 10);
- } else {
- return parseInt(urlParams.limit, 10);
- }
- },
-
changes: function () {
var docParams = app.getParams();
this.database.buildChanges(docParams);
@@ -521,10 +244,6 @@ function(app, FauxtonAPI, BaseRoute, Documents, Changes, Index, DocEditor, Datab
this.changesView.render();
},
- updateQueryOptions: function(options) {
- this.rightHeader.updateQueryOptions(options);
- },
-
cleanup: function () {
if (this.reactHeader) {
this.removeView('#react-headerbar');
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/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
new file mode 100644
index 0000000..250dafc
--- /dev/null
+++ b/app/addons/documents/routes-index-editor.js
@@ -0,0 +1,156 @@
+// 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([
+ 'app',
+ 'api',
+
+ // Modules
+ 'addons/documents/shared-routes',
+ 'addons/documents/views',
+ 'addons/documents/views-index',
+ 'addons/databases/base',
+ 'addons/fauxton/components'
+
+],
+
+function (app, FauxtonAPI, BaseRoute, Documents, Index, Databases, Components) {
+
+
+ var IndexEditorAndResults = BaseRoute.extend({
+ layout: 'two_pane',
+ routes: {
+ 'database/:database/new_view': 'newViewEditor',
+ 'database/:database/new_view/:designDoc': 'newViewEditor',
+ 'database/:database/_design/:ddoc/_view/:view': {
+ route: 'viewFn',
+ roles: ['fx_loggedIn']
+ }
+ },
+
+ events: {
+ 'route:updateAllDocs': 'updateAllDocsFromView',
+ 'route:paginate': 'paginate',
+ 'route:perPageChange': 'perPageChange',
+ },
+
+ initialize: function (route, masterLayout, options) {
+ var databaseName = options[0];
+
+ this.databaseName = databaseName;
+ this.database = new Databases.Model({id: databaseName});
+ this.allDatabases = new Databases.List();
+ this.createDesignDocsCollection();
+ },
+
+ establish: function () {
+ return [
+ this.designDocs.fetch({reset: true}),
+ this.allDatabases.fetchOnce()
+ ];
+ },
+
+ viewFn: function (databaseName, ddoc, viewName) {
+ var params = this.createParams(),
+ urlParams = params.urlParams,
+ docParams = params.docParams,
+ decodeDdoc = decodeURIComponent(ddoc);
+
+
+ this.rightHeader = this.setView('#right-header', new Documents.Views.RightAllDocsHeader({
+ database: this.database
+ }));
+
+
+ this.breadcrumbs = this.setView('#breadcrumbs', new Components.Breadcrumbs({
+ toggleDisabled: true,
+ crumbs: [
+ {'type': 'back', 'link': Databases.databaseUrl(this.database)},
+ {'name': this.database.id, 'link': Databases.databaseUrl(this.database) }
+ ]
+ }));
+
+ viewName = viewName.replace(/\?.*$/,'');
+
+ this.footer = this.setView('#footer', new Documents.Views.Footer());
+
+ this.indexedDocs = new Documents.IndexCollection(null, {
+ database: this.database,
+ design: decodeDdoc,
+ view: viewName,
+ params: docParams,
+ paging: {
+ pageSize: this.getDocPerPageLimit(urlParams, parseInt(docParams.limit, 10))
+ }
+ });
+
+ this.viewEditor = this.setView('#left-content', new Index.ViewEditorReact({
+ viewName: viewName,
+ newView: false,
+ database: this.database,
+ designDocs: this.designDocs,
+ designDocId: '_design/' + decodeDdoc
+ }));
+
+ this.documentsView = this.createViewDocumentsView({
+ designDoc: decodeDdoc,
+ docParams: docParams,
+ urlParams: urlParams,
+ database: this.database,
+ indexedDocs: this.indexedDocs,
+ designDocs: this.designDocs,
+ view: viewName
+ });
+
+ this.apiUrl = function () {
+ return [this.indexedDocs.urlRef('apiurl', urlParams), FauxtonAPI.constants.DOC_URLS.GENERAL];
+ };
+
+ this.showQueryOptions(urlParams, ddoc, viewName);
+ },
+
+ newViewEditor: function (database, _designDoc) {
+ var params = app.getParams();
+ var newDesignDoc = true;
+ var designDoc;
+
+ if (_designDoc) {
+ designDoc = '_design/' + _designDoc;
+ newDesignDoc = false;
+ }
+
+ this.breadcrumbs = this.setView('#breadcrumbs', new Components.Breadcrumbs({
+ toggleDisabled: true,
+ crumbs: [
+ {'type': 'back', 'link': Databases.databaseUrl(this.database)},
+ {'name': 'Create new index', 'link': Databases.databaseUrl(this.database) }
+ ]
+ }));
+
+ this.viewEditor = this.setView('#left-content', new Index.ViewEditorReact({
+ viewName: 'new-view',
+ newView: true,
+ database: this.database,
+ designDocs: this.designDocs,
+ designDocId: designDoc,
+ newDesignDoc: newDesignDoc
+ }));
+
+ this.resultList = this.setView('#dashboard-lower-content', new Index.ViewResultListReact({
+ documents: null
+ }));
+ }
+
+ });
+
+ return IndexEditorAndResults;
+});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/routes.js b/app/addons/documents/routes.js
index 4756665..5c1e5a1 100644
--- a/app/addons/documents/routes.js
+++ b/app/addons/documents/routes.js
@@ -13,15 +13,17 @@
define([
"addons/documents/views",
"addons/documents/routes-documents",
- "addons/documents/routes-doc-editor"
+ 'addons/documents/routes-doc-editor',
+ 'addons/documents/routes-index-editor'
],
-function(Documents, DocumentsRouteObject, docEditor) {
+function(Documents, DocumentsRouteObject, docEditor, IndexEditorRouteObject) {
Documents.RouteObjects = [
docEditor.DocEditorRouteObject,
docEditor.NewDocEditorRouteObject,
- DocumentsRouteObject
+ DocumentsRouteObject,
+ IndexEditorRouteObject
];
return Documents;
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/shared-routes.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/shared-routes.js b/app/addons/documents/shared-routes.js
index 9564530..8c0db94 100644
--- a/app/addons/documents/shared-routes.js
+++ b/app/addons/documents/shared-routes.js
@@ -29,6 +29,26 @@ define([
});
},
+ showQueryOptions: function (urlParams, ddoc, viewName) {
+ var promise = this.designDocs.fetch({reset: true}),
+ that = this,
+ hasReduceFunction;
+
+ promise.then(function (resp) {
+ var design = _.findWhere(that.designDocs.models, {id: '_design/'+ddoc});
+ !_.isUndefined(hasReduceFunction = design.attributes.doc.views[viewName].reduce);
+
+ that.rightHeader.showQueryOptions();
+ that.rightHeader.resetQueryOptions({
+ queryParams: urlParams,
+ showStale: true,
+ hasReduce: hasReduceFunction,
+ viewName: viewName,
+ ddocName: ddoc
+ });
+ });
+ },
+
addLeftHeader: function () {
this.leftheader = this.setView('#breadcrumbs', new Components.LeftHeader({
crumbs: this.getCrumbs(this.database),
@@ -62,6 +82,159 @@ define([
{ "type": "back", "link": FauxtonAPI.urls('allDBs', 'app')},
{ "name": database.id, "link": FauxtonAPI.urls('allDocs', 'app', dbname, '?limit=' + Databases.DocLimit), className: "lookahead-tray-link" }
];
+ },
+
+ // document-list
+
+ setDocPerPageLimit: function (perPage) {
+ app.utils.localStorageSet('fauxton:perpage', perPage);
+ },
+
+ createViewDocumentsView: function (options) {
+ if (!options.docParams) {
+ options.docParams = {};
+ }
+
+ this.perPageDefault = options.docParams.limit || FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE;
+
+ this.pagination = new Components.IndexPagination({
+ collection: options.indexedDocs,
+ scrollToSelector: '.scrollable',
+ docLimit: options.urlParams.limit,
+ perPage: this.perPageDefault
+ });
+ this.setView('#documents-pagination', this.pagination);
+
+ this.allDocsNumber = new Documents.Views.AllDocsNumber({
+ collection: options.indexedDocs,
+ pagination: this.pagination,
+ perPageDefault: this.perPageDefault
+ });
+
+ this.setView('#item-numbers', this.allDocsNumber);
+
+ return this.setView("#dashboard-lower-content", new Documents.Views.AllDocsList({
+ pagination: this.pagination,
+ allDocsNumber: this.allDocsNumber,
+ database: options.database,
+ collection: options.indexedDocs,
+ viewList: true,
+ ddocInfo: this.ddocInfo(options.designDoc, options.designDocs, options.view),
+ docParams: options.docParams,
+ perPageDefault: this.perPageDefault,
+ }));
+ },
+
+ ddocInfo: function (designDoc, designDocs, view) {
+ return {
+ id: "_design/" + designDoc,
+ currView: view,
+ designDocs: designDocs
+ };
+ },
+
+ getDocPerPageLimit: function (urlParams, perPage) {
+ var storedPerPage = perPage;
+
+ if (window.localStorage) {
+ storedPerPage = app.utils.localStorageGet('fauxton:perpage');
+
+ if (!storedPerPage) {
+ this.setDocPerPageLimit(perPage);
+ storedPerPage = perPage;
+ } else {
+ storedPerPage = parseInt(storedPerPage, 10);
+ }
+ }
+
+ if (!urlParams.limit || urlParams.limit > storedPerPage) {
+ return parseInt(storedPerPage, 10);
+ } else {
+ return parseInt(urlParams.limit, 10);
+ }
+ },
+
+ createParams: function (options) {
+ var urlParams = app.getParams(options),
+ params = Documents.QueryParams.parse(urlParams),
+ limit = this.getDocPerPageLimit(params, FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE);
+
+ return {
+ urlParams: urlParams,
+ docParams: _.extend(params, {limit: limit})
+ };
+ },
+
+ updateAllDocsFromView: function (event) {
+ var view = event.view,
+ params = this.createParams(),
+ urlParams = params.urlParams,
+ docParams = params.docParams,
+ ddoc = event.ddoc,
+ defaultPageSize,
+ isLazyInit,
+ pageSize,
+ collection;
+
+ isLazyInit = _.isUndefined(this.documentsView) || _.isUndefined(this.documentsView.allDocsNumber);
+ defaultPageSize = isLazyInit ? FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE : this.documentsView.perPage();
+ docParams.limit = pageSize = this.getDocPerPageLimit(urlParams, defaultPageSize);
+
+ if (event.allDocs) {
+ this.eventAllDocs = true; // this is horrible. But I cannot get the trigger not to fire the route!
+ this.database.buildAllDocs(docParams);
+ collection = this.database.allDocs;
+ collection.paging.pageSize = pageSize;
+ } else {
+ collection = this.indexedDocs = new Documents.IndexCollection(null, {
+ database: this.database,
+ design: ddoc,
+ view: view,
+ params: docParams,
+ paging: {
+ pageSize: pageSize
+ }
+ });
+
+ if (!this.documentsView) {
+ this.documentsView = this.createViewDocumentsView({
+ designDoc: ddoc,
+ docParams: docParams,
+ urlParams: urlParams,
+ database: this.database,
+ indexedDocs: this.indexedDocs,
+ designDocs: this.designDocs,
+ view: view
+ });
+ }
+ }
+
+ this.documentsView.setParams(docParams, urlParams);
+
+ // this will lazily initialize all sub-views and render them
+ this.documentsView.forceRender();
+ },
+
+ perPageChange: function (perPage) {
+ // We need to restore the collection parameters to the defaults (1st page)
+ // and update the page size
+ this.perPage = perPage;
+
+ this.documentsView.forceRender();
+ this.documentsView.collection.pageSizeReset(perPage, {fetch: false});
+
+ this.setDocPerPageLimit(perPage);
+ },
+
+ paginate: function (options) {
+ var collection = this.documentsView.collection;
+ this.documentsView.collection.reset(collection);
+
+ this.documentsView.forceRender();
+ this.allDocsNumber.forceRender();
+
+ collection.paging.pageSize = options.perPage;
+ var promise = collection[options.direction]({fetch: false});
}
});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/templates/design_doc_selector.html
----------------------------------------------------------------------
diff --git a/app/addons/documents/templates/design_doc_selector.html b/app/addons/documents/templates/design_doc_selector.html
deleted file mode 100644
index 46435a7..0000000
--- a/app/addons/documents/templates/design_doc_selector.html
+++ /dev/null
@@ -1,36 +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.
--->
-<div class="span3">
- <label for="ddoc">Save to Design Document <a class="help-link" data-bypass="true" href="<%-getDocUrl('DOC_URL_DESIGN_DOCS')%>" target="_blank"><i class="icon-question-sign"></i></a></label>
- <select id="ddoc">
- <optgroup label="Select a document">
- <option value="new-doc">New document</option>
-
- <% ddocs.each(function(ddoc) { %>
- <% if (ddoc.id === ddocName) { %>
- <option selected="selected" value="<%- ddoc.id %>"><%- ddoc.id %></option>
- <% } else { %>
- <option value="<%- ddoc.id %>"><%- ddoc.id %></option>
- <% } %>
- <% }); %>
- </optgroup>
- </select>
-</div>
-
-<div id="new-ddoc-section" class="span5" style="display:none">
- <label class="control-label" for="new-ddoc"> _design/ </label>
- <div class="controls">
- <input type="text" id="new-ddoc" placeholder="newDesignDoc" />
- </div>
-</div>
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/templates/view_editor.html
----------------------------------------------------------------------
diff --git a/app/addons/documents/templates/view_editor.html b/app/addons/documents/templates/view_editor.html
deleted file mode 100644
index 731d2cc..0000000
--- a/app/addons/documents/templates/view_editor.html
+++ /dev/null
@@ -1,86 +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.
--->
-<div class="dashboard-upper-menu">
- <ul class="nav nav-tabs" id="db-views-tabs-nav">
- <li class="active"> <a data-bypass="true" id="index-nav" data-toggle="tab" href="#index">
- <i class="fonticon-wrench fonticon"></i>
- <% if (newView) { %>Create Index <% } else { %>Edit Index <% } %></a>
- </li>
- </ul>
-</div>
- <div class="tab-content">
- <div id="query-options-wrapper"></div>
- <div class="tab-pane active" id="index">
- <div id="define-view" class="ddoc-alert well">
- <form class="form-horizontal view-query-save">
-
- <div class="control-group design-doc-group">
- </div>
-
- <div class="control-group">
- <label for="index-name">Index name <a class="help-link" data-bypass="true" href="<%-getDocUrl('VIEW_FUNCS')%>" target="_blank"><i class="icon-question-sign"></i></a></label>
- <input type="text" id="index-name" value="<%- viewName %>" placeholder="Index name" />
- </div>
-
-
- <div class="control-group">
- <label for="map-function">Map function <a class="help-link" data-bypass="true" href="<%-getDocUrl('MAP_FUNCS')%>" target="_blank"><i class="icon-question-sign"></i></a></label>
- <% if (newView) { %>
- <div class="js-editor" id="map-function"><%= langTemplates.map %></div>
- <% } else { %>
- <div class="js-editor" id="map-function"><%- ddoc.get('views')[viewName].map %></div>
- <button class="beautify beautify_map btn btn-primary btn-large hide beautify-tooltip" type="button" data-toggle="tooltip" title="Reformat your minified code to make edits to it.">beautify this code</button>
- <% } %>
- </div>
-
-
- <div class="control-group">
- <label for="reduce-function-selector">Reduce (optional) <a class="help-link" data-bypass="true" href="<%-getDocUrl('REDUCE_FUNCS')%>" target="_blank"><i class="icon-question-sign"></i></a></label>
-
- <select id="reduce-function-selector">
- <option value="" <%- !reduceFunStr ? 'selected="selected"' : '' %>>None</option>
- <% _.each(["_sum", "_count", "_stats"], function(reduce) { %>
- <option value="<%- reduce %>" <% if (reduce == reduceFunStr) { %>selected<% } %>><%= reduce %></option>
- <% }) %>
- <option value="CUSTOM" <% if (isCustomReduce) { %>selected<% } %>>Custom Reduce function</option>
- </select>
- </div>
-
- <div class="control-group reduce-function">
- <label for="reduce-function">Custom Reduce function</label>
- <% if (newView) { %>
- <div class="js-editor" id="reduce-function"><%- langTemplates.reduce %></div>
- <% } else { %>
- <div class="js-editor" id="reduce-function"><%- ddoc.get('views')[viewName].reduce %></div>
- <button class="beautify beautify_reduce btn btn-primary btn-large hide beautify-tooltip" type="button" data-toggle="tooltip" title="Reformat your minified code to make edits to it.">beautify this code</button>
- <% } %>
- </div>
-
- <div class="control-group">
- <button class="btn btn-success save"><i class="icon fonticon-ok-circled"></i> Save & Build Index</button>
- <% if (!newView) { %>
- <button class="btn btn-danger delete"><i class="icon fonticon-cancel-circled"></i> Delete</button>
- <% } %>
- <span id="viewBtnExtensions"></span>
- </div>
- <div class="clearfix"></div>
- </form>
- </div>
- </div>
- <div class="tab-pane" id="metadata">
- <div id="ddoc-info" class="well"> </div>
- </div>
- <div class="tab-pane" id="query">
- </div>
- </div>
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/tests/actionsSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/actionsSpec.js b/app/addons/documents/tests/actionsSpec.js
index a37c769..594e399 100644
--- a/app/addons/documents/tests/actionsSpec.js
+++ b/app/addons/documents/tests/actionsSpec.js
@@ -158,7 +158,12 @@ define([
reduce: '_sum',
newDesignDoc: false,
newView: false,
- designDocs: designDocs
+ designDocs: designDocs,
+ database: {
+ safeID: function () {
+ return 'foo';
+ }
+ }
};
var designDoc = designDocs.first();
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/tests/nightwatch/navigateToNewView.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/navigateToNewView.js b/app/addons/documents/tests/nightwatch/navigateToNewView.js
index 9bbdccf..4f93e94 100644
--- a/app/addons/documents/tests/nightwatch/navigateToNewView.js
+++ b/app/addons/documents/tests/nightwatch/navigateToNewView.js
@@ -26,7 +26,7 @@ module.exports = {
.click('#new-all-docs-button a')
.waitForElementPresent('#new-all-docs-button a[href="#/database/' + newDatabaseName + '/new_view"]', waitTime, false)
.click('#new-all-docs-button a[href="#/database/' + newDatabaseName + '/new_view"]')
- .waitForElementPresent('#define-view', waitTime, false)
+ .waitForElementPresent('.define-view', waitTime, false)
.verify.urlEquals(baseUrl+'/#/database/' + newDatabaseName + '/new_view')
// now redirect back to the database page and check it's loaded properly
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/tests/nightwatch/viewCreate.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/viewCreate.js b/app/addons/documents/tests/nightwatch/viewCreate.js
new file mode 100644
index 0000000..8857af0
--- /dev/null
+++ b/app/addons/documents/tests/nightwatch/viewCreate.js
@@ -0,0 +1,94 @@
+// 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.
+
+var waitTime = 10000,
+ baseUrl,
+ newDatabaseName,
+ newDocumentName,
+ modifier;
+
+var tests = {
+
+ 'Creates a Design Doc using the dropdown at "all documents"': function (client) {
+ /*jshint multistr: true */
+ openDifferentDropdownsAndClick(client, '#header-dropdown-menu')
+ .setValue('#new-ddoc', 'test_design_doc-selenium-1')
+ .clearValue('#index-name')
+ .setValue('#index-name', 'hasenindex')
+ .execute('\
+ var editor = ace.edit("map-function");\
+ editor.getSession().setValue("function (doc) { emit(\'hasehase\'); }");\
+ ')
+ .click('button.btn.btn-success.save')
+ .waitForElementPresent('.prettyprint', waitTime, false)
+ .assert.containsText('.prettyprint', 'hasehase')
+ .end();
+ },
+
+
+ 'Creates a Design Doc using the dropdown at "the upper dropdown in the header"': function (client) {
+ /*jshint multistr: true */
+ openDifferentDropdownsAndClick(client, '#header-dropdown-menu')
+ .setValue('#new-ddoc', 'test_design_doc-selenium-2')
+ .clearValue('#index-name')
+ .setValue('#index-name', 'gaenseindex')
+ .execute('\
+ var editor = ace.edit("map-function");\
+ editor.getSession().setValue("function (doc) { emit(\'gansgans\'); }");\
+ ')
+ .execute('$(".save")[0].scrollIntoView();')
+ .click('button.btn-success.save')
+ .waitForElementPresent('.prettyprint', waitTime, false)
+ .assert.containsText('.prettyprint', 'gansgans')
+ .end();
+ },
+
+ 'Adds a View to a DDoc using an existing DDoc': function (client) {
+ /*jshint multistr: true */
+
+ openDifferentDropdownsAndClick(client, '[data-target="#testdesigndoc"]')
+ .clearValue('#index-name')
+ .setValue('#index-name', 'test-new-view')
+ .execute('\
+ var editor = ace.edit("map-function");\
+ editor.getSession().setValue("function (doc) { emit(\'enteente\', 1); }");\
+ ')
+ .execute('$(".save")[0].scrollIntoView();')
+ .click('button.btn-success.save')
+ .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
+ .waitForElementPresent('[data-target="#testdesigndoc"]', waitTime, false)
+ .click('[data-target="#testdesigndoc"]')
+ .clickWhenVisible('[data-target="#testdesigndocviews"]', waitTime, false)
+ .clickWhenVisible('#testdesigndoc_testnewview', waitTime, false)
+ .waitForElementPresent('.prettyprint', waitTime, false)
+ .assert.containsText('.prettyprint', 'enteente')
+ .end();
+ },
+};
+
+function openDifferentDropdownsAndClick (client, dropDownElement) {
+ modifier = + dropDownElement.slice(1);
+ newDatabaseName = client.globals.testDatabaseName;
+ newDocumentName = 'create_view_doc' + modifier;
+ baseUrl = client.globals.test_settings.launch_url;
+
+ return client
+ .loginToGUI()
+ .populateDatabase(newDatabaseName)
+ .url(baseUrl + '/#/database/' + newDatabaseName + '/_all_docs')
+ .waitForElementPresent(dropDownElement, waitTime, false)
+ .click(dropDownElement + ' a')
+ .click(dropDownElement + ' a[href*="new_view"]')
+ .waitForElementPresent('.editor-wrapper', waitTime, false);
+}
+
+module.exports = tests;
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/tests/nightwatch/viewEdit.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/viewEdit.js b/app/addons/documents/tests/nightwatch/viewEdit.js
new file mode 100644
index 0000000..f3ea6da
--- /dev/null
+++ b/app/addons/documents/tests/nightwatch/viewEdit.js
@@ -0,0 +1,89 @@
+// 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.
+
+module.exports = {
+
+ 'Edits a design doc - set new index name': function (client) {
+ /*jshint multistr: true */
+ var waitTime = 10000,
+ newDatabaseName = client.globals.testDatabaseName,
+ baseUrl = client.globals.test_settings.launch_url;
+
+ client
+ .populateDatabase(newDatabaseName)
+ .loginToGUI()
+ .url(baseUrl + '/#/database/' + newDatabaseName + '/_design/testdesigndoc/_view/stubview')
+ .waitForElementPresent('.prettyprint', waitTime, false)
+ .assert.containsText('.prettyprint', 'stub')
+ .clearValue('#index-name')
+ .setValue('#index-name', 'hasenindex5000')
+ .execute('\
+ var editor = ace.edit("map-function");\
+ editor.getSession().setValue("function (doc) { emit(\'hasehase5000\', 1); }");\
+ ')
+ .execute('$(".save")[0].scrollIntoView();')
+ .click('button.btn-success.save')
+
+ .waitForElementNotVisible('.global-notification', waitTime, false)
+ .assert.containsText('.prettyprint', 'hasehase5000')
+ .end();
+ },
+
+ 'Edits a design doc': function (client) {
+ /*jshint multistr: true */
+ var waitTime = 10000,
+ newDatabaseName = client.globals.testDatabaseName,
+ baseUrl = client.globals.test_settings.launch_url;
+
+ client
+ .populateDatabase(newDatabaseName)
+ .loginToGUI()
+ .url(baseUrl + '/#/database/' + newDatabaseName + '/_design/testdesigndoc/_view/stubview')
+ .waitForElementPresent('.prettyprint', waitTime, false)
+ .assert.containsText('.prettyprint', 'stub')
+
+ .execute('\
+ var editor = ace.edit("map-function");\
+ editor.getSession().setValue("function (doc) { emit(\'hasehase5000\', 1); }");\
+ ')
+ .execute('$(".save")[0].scrollIntoView();')
+ .click('button.btn-success.save')
+
+ .waitForElementNotVisible('.global-notification', waitTime, false)
+ .assert.containsText('.prettyprint', 'hasehase5000')
+ .end();
+ },
+
+ 'Query Options are kept after a new reduce method is chosen': function (client) {
+ /*jshint multistr: true */
+ var waitTime = 10000,
+ newDatabaseName = client.globals.testDatabaseName,
+ baseUrl = client.globals.test_settings.launch_url;
+
+ client
+ .populateDatabase(newDatabaseName)
+ .loginToGUI()
+ .url(baseUrl + '/#/database/' + newDatabaseName + '/_design/testdesigndoc/_view/stubview?reduce=true&group_level=0')
+ .waitForElementPresent('.prettyprint', waitTime, false)
+ .assert.containsText('.prettyprint', '20')
+ .clickWhenVisible('#reduce-function-selector option[value="_sum"]')
+ .execute('\
+ var editor = ace.edit("map-function");\
+ editor.getSession().setValue("function (doc) { emit(\'newstub\', 2); }");\
+ ')
+ .execute('$(".save")[0].scrollIntoView();')
+ .click('button.btn-success.save')
+ .waitForElementNotVisible('.global-notification', waitTime, false)
+ .assert.containsText('.prettyprint', '40')
+ .end();
+ }
+};
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/tests/nightwatch/viewQueryOptions.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/viewQueryOptions.js b/app/addons/documents/tests/nightwatch/viewQueryOptions.js
new file mode 100644
index 0000000..245b89d
--- /dev/null
+++ b/app/addons/documents/tests/nightwatch/viewQueryOptions.js
@@ -0,0 +1,34 @@
+// 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.
+
+module.exports = {
+ 'Edit view: Queryoptions work': function (client) {
+ /*jshint multistr: true */
+ var waitTime = 10000,
+ newDatabaseName = client.globals.testDatabaseName,
+ baseUrl = client.globals.test_settings.launch_url;
+
+ client
+ .populateDatabase(newDatabaseName, 3)
+ .loginToGUI()
+ .url(baseUrl + '/#/database/' + newDatabaseName + '/_design/keyview/_view/keyview')
+ .clickWhenVisible('#toggle-query')
+ .clickWhenVisible('[data-action="showByKeys"]')
+ .setValue('#keys-input', '["document_1"]')
+ .click('#query-options .btn-success')
+ .waitForElementNotPresent('#right-content [data-id="document_2"]', waitTime, false)
+ .assert.elementNotPresent('#right-content [data-id="document_2"]')
+ .assert.elementNotPresent('#right-content [data-id="document_0"]')
+ .assert.elementPresent('#right-content [data-id="document_1"]')
+ .end();
+ }
+};
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/tests/routeSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/routeSpec.js b/app/addons/documents/tests/routeSpec.js
index c59003a..1e14302 100644
--- a/app/addons/documents/tests/routeSpec.js
+++ b/app/addons/documents/tests/routeSpec.js
@@ -26,13 +26,6 @@ define([
assert.equal(typeof routeObj.rightHeader, 'object');
});
- it('the view that shows a view has a right header', function () {
- var routeObj = new DocumentRoute(null, null, ['test']);
-
- routeObj.viewFn('newdatabase', 'ads', 'newView');
- assert.equal(typeof routeObj.rightHeader, 'object');
- });
-
// after saving a new CouchDB-View we are calling the updateAllDocsFromView function.
// The backbone-view AllDocsList is lazily initializing other views, in particular the
// view AllDocsNumber and the pagination in the beforeRender method.
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/tests/storesSpec.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/storesSpec.js b/app/addons/documents/tests/storesSpec.js
index 5511a8e..89adfaa 100644
--- a/app/addons/documents/tests/storesSpec.js
+++ b/app/addons/documents/tests/storesSpec.js
@@ -33,44 +33,6 @@ define([
FauxtonAPI.dispatcher.unregister(dispatchToken);
});
- describe('TOGGLE EDITOR', function () {
-
- it('toggles editor', function () {
- var designDoc = {
- _id: '_design/test-doc',
- views: {
- 'test-view': {
- map: 'boom'
- }
- }
- };
-
- var designDocs = new Documents.AllDocs([designDoc], {
- params: { limit: 10 },
- database: {
- safeID: function () { return 'id';}
- }
- });
-
- FauxtonAPI.dispatch({
- type: ActionTypes.EDIT_NEW_INDEX,
- options: {
- newView: false,
- designDocs: designDocs,
- designDocId: '_design/test-doc'
- }
- });
-
-
- FauxtonAPI.dispatch({
- type: ActionTypes.TOGGLE_EDITOR
- });
-
- assert.ok(store.showEditor());
- });
-
- });
-
describe('map editor', function () {
describe('new view', function () {
@@ -346,35 +308,6 @@ define([
assert.equal(store.getReduce(), '_sum');
});
- it('showEditor() is false for editing index', function () {
- FauxtonAPI.dispatch({
- type: ActionTypes.EDIT_INDEX,
- options: {
- newView: false,
- viewName: 'test-view',
- designDocs: designDocs,
- designDocId: designDoc._id
- }
- });
-
- assert.notOk(store.showEditor());
- });
-
- it('showEditor() is true for creating index', function () {
- FauxtonAPI.dispatch({
- type: ActionTypes.EDIT_INDEX,
- options: {
- newView: true,
- viewName: 'test-view',
- newDesignDoc: false,
- designDocs: designDocs,
- designDocId: designDoc._id
- }
- });
-
- assert.ok(store.showEditor());
- });
-
});
});
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/tests/viewIndex.componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/viewIndex.componentsSpec.react.jsx b/app/addons/documents/tests/viewIndex.componentsSpec.react.jsx
index 74eddca..7f3eee9 100644
--- a/app/addons/documents/tests/viewIndex.componentsSpec.react.jsx
+++ b/app/addons/documents/tests/viewIndex.componentsSpec.react.jsx
@@ -32,6 +32,7 @@ define([
});
Actions.editIndex({
+ database: {id: 'rockos-db'},
newView: false,
viewName: 'test-view',
designDocs: designDocs,
@@ -39,30 +40,6 @@ define([
});
};
- describe('View editor', function () {
-
- describe('Toggle button', function () {
- var container, toggleEl, toggleEditor;
-
- beforeEach(function () {
- toggleEditor = sinon.spy();
- container = document.createElement('div');
- toggleEl = TestUtils.renderIntoDocument(<Views.ToggleButton toggleEditor={toggleEditor} />, container);
- });
-
- afterEach(function () {
- React.unmountComponentAtNode(container);
- });
-
- it('should toggle editor on click', function () {
- TestUtils.Simulate.click($(toggleEl.getDOMNode()).find('a')[0]);
- assert.ok(toggleEditor.calledOnce);
- });
-
- });
-
- });
-
describe('reduce editor', function () {
var container, reduceEl;
@@ -123,6 +100,44 @@ define([
});
});
+ describe('styled select', function () {
+ var container, selectorEl, spy = sinon.spy();
+
+ beforeEach(function () {
+ container = document.createElement('div');
+
+ var selectContent = (
+ <optgroup label="Select a document">
+ <option value="new">New Design Document</option>
+ <option value="foo">New Design Document</option>
+ </optgroup>
+ );
+
+ selectorEl = TestUtils.renderIntoDocument(
+ <Views.StyledSelect
+ selectId="new-ddoc"
+ selectClass=""
+ selectContent={selectContent}
+ selectChange={spy} />,
+ container
+ );
+ });
+
+ afterEach(function () {
+ React.unmountComponentAtNode(container);
+ });
+
+ it('calls the callback on select', function () {
+ TestUtils.Simulate.change($(selectorEl.getDOMNode()).find('#new-ddoc')[0], {
+ target: {
+ value: 'new'
+ }
+ });
+ assert.ok(spy.calledOnce);
+ });
+
+ });
+
describe('design Doc Selector', function () {
var container, selectorEl;
http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6f089aa/app/addons/documents/views-index.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/views-index.js b/app/addons/documents/views-index.js
index eb24944..e64963f 100644
--- a/app/addons/documents/views-index.js
+++ b/app/addons/documents/views-index.js
@@ -14,9 +14,10 @@ define([
"api",
"addons/documents/index-editor/components.react",
"addons/documents/index-editor/actions",
+ 'addons/documents/index-results/index-results.components.react'
],
-function(FauxtonAPI, ViewEditor, Actions) {
+function (FauxtonAPI, ViewEditor, ActionsIndexEditor, ViewResultList) {
var Views = {};
@@ -26,7 +27,7 @@ function(FauxtonAPI, ViewEditor, Actions) {
},
afterRender: function () {
- Actions.editIndex(this.options);
+ ActionsIndexEditor.editIndex(this.options);
ViewEditor.renderEditor(this.el);
},
@@ -35,5 +36,19 @@ function(FauxtonAPI, ViewEditor, Actions) {
}
});
+ Views.ViewResultListReact = FauxtonAPI.View.extend({
+ initialize: function (options) {
+ this.options = options;
+ },
+
+ afterRender: function () {
+ ViewResultList.renderViewResultList(this.el);
+ },
+
+ cleanup: function () {
+ ViewResultList.removeViewResultList(this.el);
+ }
+ });
+
return Views;
});