You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by am...@apache.org on 2019/03/14 18:28:59 UTC
[couchdb-fauxton] branch master updated: Disable stable query
option for partitioned views (#1193)
This is an automated email from the ASF dual-hosted git repository.
amaranhao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-fauxton.git
The following commit(s) were added to refs/heads/master by this push:
new c8d938f Disable stable query option for partitioned views (#1193)
c8d938f is described below
commit c8d938fc8c5ad1751f4b29286804acd821c57485
Author: Antonio Maranhao <30...@users.noreply.github.com>
AuthorDate: Thu Mar 14 14:28:55 2019 -0400
Disable stable query option for partitioned views (#1193)
---
app/addons/documents/__tests__/helpers.test.js | 78 +++++++++++++++++++
.../documents/__tests__/main-fields-view.test.js | 4 +-
.../documents/__tests__/query-options.test.js | 56 ++++++++++++-
.../documents/assets/less/query-options.less | 3 +-
app/addons/documents/helpers.js | 17 ++++
.../components/queryoptions/MainFieldsView.js | 91 ++++++++++++++--------
.../components/queryoptions/QueryOptions.js | 1 +
.../containers/QueryOptionsContainer.js | 11 ++-
8 files changed, 222 insertions(+), 39 deletions(-)
diff --git a/app/addons/documents/__tests__/helpers.test.js b/app/addons/documents/__tests__/helpers.test.js
index 195584f..d586f34 100644
--- a/app/addons/documents/__tests__/helpers.test.js
+++ b/app/addons/documents/__tests__/helpers.test.js
@@ -42,4 +42,82 @@ describe('Helpers', () => {
});
+ describe('selectedItemIsPartitionedView', () => {
+ const ddocs = {
+ find: () => { return {_id: '_design/ddoc1' }; }
+ };
+ const selectedView = {
+ navItem: 'designDoc',
+ designDocSection: 'Views',
+ indexName: 'view1'
+ };
+ const selectedAllDocs = {
+ navItem: 'all-docs'
+ };
+
+ it('returns false if no item is selected', () => {
+ const isPartitionedView = Helpers.selectedItemIsPartitionedView(ddocs, null, true);
+ expect(isPartitionedView).toBe(false);
+ });
+
+ it('returns false if selected item is not a view', () => {
+ const isPartitionedView = Helpers.selectedItemIsPartitionedView(ddocs, selectedAllDocs, true);
+ expect(isPartitionedView).toBe(false);
+ });
+
+ it('returns false if selected item is a global view', () => {
+ const isPartitionedView = Helpers.selectedItemIsPartitionedView(ddocs, selectedView, false);
+ expect(isPartitionedView).toBe(false);
+ });
+
+ it('returns true if selected item is a partitioned view', () => {
+ const isPartitionedView = Helpers.selectedItemIsPartitionedView(ddocs, selectedView, true);
+ expect(isPartitionedView).toBe(true);
+ });
+
+ });
+
+ describe('isDDocPartitioned', () => {
+ const ddocNoOptions = {
+ _id: '_design/ddoc1'
+ };
+ const ddocPartitionedTrue = {
+ _id: '_design/ddoc1',
+ options: {
+ partitioned: true
+ }
+ };
+ const ddocPartitionedFalse = {
+ _id: '_design/ddoc1',
+ options: {
+ partitioned: false
+ }
+ };
+
+ it('returns false if database is not partitioned', () => {
+ let isPartitionedDdoc = Helpers.isDDocPartitioned(ddocNoOptions, false);
+ expect(isPartitionedDdoc).toBe(false);
+
+ isPartitionedDdoc = Helpers.isDDocPartitioned(ddocPartitionedFalse, false);
+ expect(isPartitionedDdoc).toBe(false);
+
+ isPartitionedDdoc = Helpers.isDDocPartitioned(ddocPartitionedTrue, false);
+ expect(isPartitionedDdoc).toBe(false);
+ });
+
+ it('returns true if database is partitioned and ddoc partitioned option is not set to false', () => {
+ let isPartitionedDdoc = Helpers.isDDocPartitioned(ddocNoOptions, true);
+ expect(isPartitionedDdoc).toBe(true);
+
+ isPartitionedDdoc = Helpers.isDDocPartitioned(ddocPartitionedTrue, true);
+ expect(isPartitionedDdoc).toBe(true);
+ });
+
+ it('returns false if database is partitioned but ddoc is set as non-partitioned', () => {
+ const isPartitionedDdoc = Helpers.isDDocPartitioned(ddocPartitionedFalse, true);
+ expect(isPartitionedDdoc).toBe(false);
+ });
+
+ });
+
});
diff --git a/app/addons/documents/__tests__/main-fields-view.test.js b/app/addons/documents/__tests__/main-fields-view.test.js
index fe108ca..3a5b960 100644
--- a/app/addons/documents/__tests__/main-fields-view.test.js
+++ b/app/addons/documents/__tests__/main-fields-view.test.js
@@ -21,7 +21,8 @@ describe('MainFieldsView', () => {
stable: false,
toggleStable: () => {},
update: 'true',
- changeUpdateField: () => {}
+ changeUpdateField: () => {},
+ enableStable: false
};
const docURL = 'http://foo.com';
it('does not render reduce when showReduce is false', () => {
@@ -110,6 +111,7 @@ describe('MainFieldsView', () => {
toggleIncludeDocs={() => {}}
toggleStable={spy}
docURL={docURL}
+ enableStable={true}
/>);
wrapper.find('#qoStable').simulate('change');
diff --git a/app/addons/documents/__tests__/query-options.test.js b/app/addons/documents/__tests__/query-options.test.js
index 90d5256..4459ba0 100644
--- a/app/addons/documents/__tests__/query-options.test.js
+++ b/app/addons/documents/__tests__/query-options.test.js
@@ -10,11 +10,10 @@
// License for the specific language governing permissions and limitations under
// the License.
+import { shallow, mount } from 'enzyme';
import React from 'react';
-import ReactDOM from 'react-dom';
-import { shallow } from 'enzyme';
-import QueryOptions from '../index-results/components/queryoptions/QueryOptions';
import sinon from 'sinon';
+import QueryOptions from '../index-results/components/queryoptions/QueryOptions';
import Constants from '../constants';
describe('QueryOptions', () => {
@@ -27,7 +26,10 @@ describe('QueryOptions', () => {
queryOptionsToggleStable: () => {},
queryOptionsChangeUpdate: () => {},
stable: false,
- update: 'true'
+ update: 'true',
+ betweenKeys: {},
+ showReduce: true,
+ enableStable: true
};
it('calls resetPagination and queryOptionsExecute on submit', () => {
@@ -300,4 +302,50 @@ describe('QueryOptions', () => {
const isHighlighted = wrapper.find('ToggleHeaderButton').prop('active');
expect(isHighlighted).toBe(false);
});
+
+ it('stable option is only enabled when enableStable is true', () => {
+ const wrapper = mount(<QueryOptions
+ {...props}
+ ddocsOnly={true}
+ update='true'
+ queryOptionsRemoveFilterOnlyDdocs={() => {}}
+ queryOptionsApplyFilterOnlyDdocs={() => {}}
+ queryOptionsExecute={() => {}}
+ resetPagination={() => {}}
+ queryOptionsToggleVisibility={() => {}}
+ queryOptionsParams={{}}
+ selectedLayout={Constants.LAYOUT_ORIENTATION.METADATA}
+ changeLayout={() => {}}
+ showReduce={true}
+ enableStable={true}
+ />);
+
+ expect(wrapper.find('input#qoStable').prop("disabled")).toBe(false);
+ wrapper.setProps({enableStable: false});
+ expect(wrapper.find('input#qoStable').prop("disabled")).toBe(true);
+ });
+
+ it('reduce option is only displayed when showReduce is true', () => {
+ const wrapper = mount(<QueryOptions
+ {...props}
+ ddocsOnly={true}
+ update='true'
+ queryOptionsRemoveFilterOnlyDdocs={() => {}}
+ queryOptionsApplyFilterOnlyDdocs={() => {}}
+ queryOptionsExecute={() => {}}
+ resetPagination={() => {}}
+ queryOptionsToggleVisibility={() => {}}
+ queryOptionsParams={{}}
+ selectedLayout={Constants.LAYOUT_ORIENTATION.METADATA}
+ changeLayout={() => {}}
+ showReduce={true}
+ enableStable={true}
+ />);
+
+ expect(wrapper.find('input#qoReduce').exists()).toBe(true);
+
+ wrapper.setProps({showReduce: false});
+ expect(wrapper.find('input#qoReduce').exists()).toBe(false);
+ });
+
});
diff --git a/app/addons/documents/assets/less/query-options.less b/app/addons/documents/assets/less/query-options.less
index 27e9cc0..f2ace1a 100644
--- a/app/addons/documents/assets/less/query-options.less
+++ b/app/addons/documents/assets/less/query-options.less
@@ -130,7 +130,8 @@
-webkit-user-select: none;
}
label.disabled {
- color: #777777;
+ cursor: not-allowed;
+ opacity: .5;
}
div.controls-group.well{
height: 156px;
diff --git a/app/addons/documents/helpers.js b/app/addons/documents/helpers.js
index c438969..27623a9 100644
--- a/app/addons/documents/helpers.js
+++ b/app/addons/documents/helpers.js
@@ -122,6 +122,22 @@ const selectedViewContainsReduceFunction = (designDocs, selectedNavItem) => {
return showReduce;
};
+const selectedItemIsPartitionedView = (designDocs, selectedNavItem, isDbPartitioned) => {
+ if (!selectedNavItem) {
+ return false;
+ }
+
+ let isPartitioned = false;
+ if (designDocs && isViewSelected(selectedNavItem)) {
+ const ddocID = '_design/' + selectedNavItem.designDocName;
+ const ddoc = designDocs.find(ddoc => ddoc._id === ddocID);
+ if (ddoc) {
+ isPartitioned = isDDocPartitioned(ddoc, isDbPartitioned);
+ }
+ }
+ return isPartitioned;
+};
+
const isViewSelected = (selectedNavItem) => {
return (selectedNavItem.navItem === 'designDoc'
&& selectedNavItem.designDocSection === 'Views'
@@ -147,5 +163,6 @@ export default {
parseJSON,
truncateDoc,
selectedViewContainsReduceFunction,
+ selectedItemIsPartitionedView,
isViewSelected
};
diff --git a/app/addons/documents/index-results/components/queryoptions/MainFieldsView.js b/app/addons/documents/index-results/components/queryoptions/MainFieldsView.js
index f36f652..179acf7 100644
--- a/app/addons/documents/index-results/components/queryoptions/MainFieldsView.js
+++ b/app/addons/documents/index-results/components/queryoptions/MainFieldsView.js
@@ -18,6 +18,7 @@ export default class MainFieldsView extends React.Component {
super(props);
this.toggleStable = this.toggleStable.bind(this);
this.onUpdateChange = this.onUpdateChange.bind(this);
+ this.toggleIncludeDocs = this.toggleIncludeDocs.bind(this);
this.updateOptions = [
{value: 'true', label: 'true'},
@@ -72,8 +73,21 @@ export default class MainFieldsView extends React.Component {
this.props.toggleStable(this.props.stable);
}
- reduce() {
- if (!this.props.showReduce) {
+ includeDocsOption() {
+ const {includeDocs, reduce} = this.props;
+ return (
+ <div className="checkbox inline">
+ <input disabled={reduce} onChange={this.toggleIncludeDocs} id="qoIncludeDocs"
+ name="include_docs" type="checkbox" checked={includeDocs}/>
+ <label className={reduce ? 'disabled' : ''} htmlFor="qoIncludeDocs" id="qoIncludeDocsLabel">Include
+ Docs</label>
+ </div>
+ );
+ }
+
+ reduceOption() {
+ const {showReduce, reduce} = this.props;
+ if (!showReduce) {
return null;
}
@@ -81,7 +95,7 @@ export default class MainFieldsView extends React.Component {
<span>
<div className="checkbox inline">
<input id="qoReduce" name="reduce" onChange={this.toggleReduce.bind(this)} type="checkbox"
- checked={this.props.reduce}/>
+ checked={reduce}/>
<label htmlFor="qoReduce">Reduce</label>
</div>
{this.groupLevel()}
@@ -89,12 +103,41 @@ export default class MainFieldsView extends React.Component {
);
}
- getUpdateOptions() {
- return this.updateOptions.map(option => <option key={option.value} value={option.value}>{option.label}</option>);
+ stableOption() {
+ let {enableStable, stable} = this.props;
+
+ if (!enableStable) {
+ // makes sure Stable option always appears unchecked when disabled
+ stable = false;
+ }
+
+ return (
+ <div className="checkbox inline">
+ <input onChange={this.toggleStable} id="qoStable" name="stable"
+ type="checkbox" checked={stable} disabled={!enableStable}/>
+ <label className={enableStable ? '' : 'disabled'} htmlFor="qoStable" id="qoStableLabel">Stable</label>
+ </div>
+ );
+ }
+
+ updateOption() {
+ const { update } = this.props;
+ const selectOptions = this.updateOptions.map(option => {
+ return <option key={option.value} value={option.value}>{option.label}</option>;
+ });
+ return (
+ <div className="dropdown inline">
+ <label className="drop-down">
+ Update
+ <select className="input-small" id="qoUpdate" value={update} onChange={this.onUpdateChange}>
+ {selectOptions}
+ </select>
+ </label>
+ </div>
+ );
}
render() {
- let {includeDocs, stable, update} = this.props;
return (
<div className="query-group" id="query-options-main-fields">
<span className="add-on">
@@ -103,31 +146,13 @@ export default class MainFieldsView extends React.Component {
<i className="icon-question-sign"/>
</a>
</span>
- <div className="controls-group qo-main-fields-row">
- <div className="row-fluid fieldsets">
- <div className="checkbox inline">
- <input disabled={this.props.reduce} onChange={this.toggleIncludeDocs.bind(this)} id="qoIncludeDocs"
- name="include_docs" type="checkbox" checked={includeDocs}/>
- <label className={this.props.reduce ? 'disabled' : ''} htmlFor="qoIncludeDocs" id="qoIncludeDocsLabel">Include
- Docs</label>
- </div>
- {this.reduce()}
- </div>
- <div className="row-fluid fieldsets">
- <div className="checkbox inline">
- <input onChange={this.toggleStable} id="qoStable"
- name="include_docs" type="checkbox" checked={stable}/>
- <label htmlFor="qoStable" id="qoStableLabel">Stable</label>
- </div>
- <div className="dropdown inline">
- <label className="drop-down">
- Update
- <select className="input-small" id="qoUpdate" value={update} onChange={this.onUpdateChange}>
- {this.getUpdateOptions()}
- </select>
- </label>
- </div>
- </div>
+ <div className="row-fluid fieldsets">
+ {this.includeDocsOption()}
+ {this.reduceOption()}
+ </div>
+ <div className="row-fluid fieldsets">
+ {this.stableOption()}
+ {this.updateOption()}
</div>
</div>
);
@@ -145,5 +170,7 @@ MainFieldsView.propTypes = {
stable: PropTypes.bool.isRequired,
toggleStable: PropTypes.func.isRequired,
update: PropTypes.string.isRequired,
- changeUpdateField: PropTypes.func.isRequired
+ changeUpdateField: PropTypes.func.isRequired,
+ showReduce: PropTypes.bool.isRequired,
+ enableStable: PropTypes.bool.isRequired
};
diff --git a/app/addons/documents/index-results/components/queryoptions/QueryOptions.js b/app/addons/documents/index-results/components/queryoptions/QueryOptions.js
index bbcab32..9b36447 100644
--- a/app/addons/documents/index-results/components/queryoptions/QueryOptions.js
+++ b/app/addons/documents/index-results/components/queryoptions/QueryOptions.js
@@ -113,6 +113,7 @@ export default class QueryOptions extends React.Component {
groupLevel={this.props.groupLevel}
updateGroupLevel={this.props.queryOptionsUpdateGroupLevel}
docURL={FauxtonAPI.constants.DOC_URLS.GENERAL}
+ enableStable={this.props.enableStable}
stable={this.props.stable}
toggleStable={this.props.queryOptionsToggleStable}
update={this.props.update}
diff --git a/app/addons/documents/index-results/containers/QueryOptionsContainer.js b/app/addons/documents/index-results/containers/QueryOptionsContainer.js
index 344e9e4..2c1d4fa 100644
--- a/app/addons/documents/index-results/containers/QueryOptionsContainer.js
+++ b/app/addons/documents/index-results/containers/QueryOptionsContainer.js
@@ -46,7 +46,15 @@ const showReduce = (designDocs, selectedNavItem) => {
return DocHelpers.selectedViewContainsReduceFunction(designDocs, selectedNavItem);
};
-const mapStateToProps = ({indexResults, sidebar}, ownProps) => {
+const enableStable = (designDocs, selectedNavItem, isDbPartitioned) => {
+ if (DocHelpers.isViewSelected(selectedNavItem)) {
+ const enableStable = !DocHelpers.selectedItemIsPartitionedView(designDocs, selectedNavItem, isDbPartitioned);
+ return enableStable;
+ }
+ return true;
+};
+
+const mapStateToProps = ({indexResults, sidebar, databases}, ownProps) => {
const queryOptionsPanel = getQueryOptionsPanel(indexResults);
return {
contentVisible: queryOptionsPanel.isVisible,
@@ -61,6 +69,7 @@ const mapStateToProps = ({indexResults, sidebar}, ownProps) => {
descending: queryOptionsPanel.descending,
skip: queryOptionsPanel.skip,
limit: queryOptionsPanel.limit,
+ enableStable: enableStable(sidebar.designDocList, ownProps.selectedNavItem, databases.isDbPartitioned),
stable: queryOptionsPanel.stable,
update: queryOptionsPanel.update,
fetchParams: getFetchParams(indexResults),