[partitioned-dbs] Partition key selector (#1128)
* Set partitionedDatabasesAvailable flag on redux store
* Add PartitionKeySelector component
* Set up PartitionKeySelector based on routes
* Add tests
diff --git a/app/addons/databases/actions.js b/app/addons/databases/actions.js
index 6b1c570..1935491 100644
--- a/app/addons/databases/actions.js
+++ b/app/addons/databases/actions.js
@@ -199,12 +199,14 @@
},
setPartitionedDatabasesAvailable(available) {
- FauxtonAPI.dispatch({
+ const action = {
type: ActionTypes.DATABASES_PARTITIONED_DB_AVAILABLE,
options: {
available
}
- });
+ };
+ FauxtonAPI.dispatch(action);
+ FauxtonAPI.reduxDispatch(action);
},
checkPartitionedQueriesIsAvailable() {
diff --git a/app/addons/databases/base.js b/app/addons/databases/base.js
index 92f2e75..c4218d4 100644
--- a/app/addons/databases/base.js
+++ b/app/addons/databases/base.js
@@ -32,7 +32,7 @@
// Checks if the CouchDB server supports Partitioned Databases
return get(Helpers.getServerUrl("/")).then((couchdb) => {
//TODO: needs to be updated with the correct feature name
- return couchdb.features && couchdb.features.includes('partitioned-dbs');
+ return couchdb.features && couchdb.features.includes('partitions');
}).catch(() => {
return false;
});
diff --git a/app/addons/databases/reducers.js b/app/addons/databases/reducers.js
new file mode 100644
index 0000000..74da7c4
--- /dev/null
+++ b/app/addons/databases/reducers.js
@@ -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.
+
+import ActionTypes from './actiontypes';
+const initialState = {
+ partitionedDatabasesAvailable: false
+};
+export default function databases(state = initialState, action) {
+ switch (action.type) {
+ case ActionTypes.DATABASES_PARTITIONED_DB_AVAILABLE:
+ return {
+ ...state,
+ partitionedDatabasesAvailable: action.options.available
+ };
+ default:
+ return state;
+ }
+}
diff --git a/app/addons/documents/__tests__/partition-key.js b/app/addons/documents/__tests__/partition-key.js
new file mode 100644
index 0000000..75005e9
--- /dev/null
+++ b/app/addons/documents/__tests__/partition-key.js
@@ -0,0 +1,122 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { shallow } from 'enzyme';
+import PartitionKeySelector from '../partition-key/PartitionKeySelector';
+import sinon from 'sinon';
+
+describe('PartitionKeySelector', () => {
+ // const props = {
+ // includeDocs: false,
+ // queryOptionsToggleIncludeDocs: () => {},
+ // reduce: false,
+ // contentVisible: true,
+ // perPage: 10,
+ // queryOptionsToggleStable: () => {},
+ // queryOptionsChangeUpdate: () => {},
+ // stable: false,
+ // update: 'true'
+ // };
+
+ const defaultProps = {
+ selectorVisible: true,
+ partitionKey: '',
+ checkDbPartitioned: () => {},
+ onPartitionKeySelected: () => {}
+ };
+
+ it('is only rendered when selectorVisible is set to true', () => {
+ const wrapper = shallow(<PartitionKeySelector
+ {...defaultProps}
+ selectorVisible={false}
+ />);
+ expect(wrapper.find('div.partition-selector').exists()).toBe(false);
+
+ const wrapper2 = shallow(<PartitionKeySelector
+ {...defaultProps}
+ selectorVisible={true}
+ />);
+ expect(wrapper2.find('div.partition-selector').exists()).toBe(true);
+ });
+
+ it('uses global mode by default', () => {
+ const wrapper = shallow(<PartitionKeySelector
+ {...defaultProps}
+ partitionKey='part1'
+ />);
+
+ const btLabel = wrapper.find('div').text();
+ expect(btLabel).toMatch('No partition selected');
+ });
+
+ it('switches from global mode to partition mode when a key is already set', () => {
+ const spyOnKeySelected = sinon.spy();
+ const wrapper = shallow(<PartitionKeySelector
+ {...defaultProps}
+ partitionKey='part1'
+ globalMode={true}
+ onPartitionKeySelected={spyOnKeySelected}
+ />);
+
+ wrapper.find('button').simulate('click');
+ expect(spyOnKeySelected.calledOnce).toBe(true);
+ });
+
+ it('if a key is not set switching from global mode shows the text input', () => {
+ const spyOnKeySelected = sinon.spy();
+ const wrapper = shallow(<PartitionKeySelector
+ {...defaultProps}
+ partitionKey=''
+ globalMode={true}
+ onPartitionKeySelected={spyOnKeySelected}
+ />);
+
+ expect(wrapper.state().editMode).toBe(false);
+ wrapper.find('button').simulate('click');
+ expect(wrapper.state().editMode).toBe(true);
+ expect(spyOnKeySelected.calledOnce).toBe(false);
+ });
+
+ it('switches from partition mode to global mode', () => {
+ const spyOnGlobalSelected = sinon.spy();
+ const wrapper = shallow(<PartitionKeySelector
+ {...defaultProps}
+ partitionKey='part1'
+ globalMode={false}
+ onGlobalModeSelected={spyOnGlobalSelected}
+ />);
+
+ wrapper.find('button').simulate('click');
+ expect(spyOnGlobalSelected.calledOnce).toBe(true);
+ });
+
+ it('calls onPartitionKeySelected when a new value is set in the text input', () => {
+ const spyOnKeySelected = sinon.spy();
+ const wrapper = shallow(<PartitionKeySelector
+ {...defaultProps}
+ partitionKey=''
+ globalMode={true}
+ onPartitionKeySelected={spyOnKeySelected}
+ />);
+
+ // Start edit mode
+ wrapper.find('button').simulate('click');
+ expect(wrapper.state().editMode).toBe(true);
+ // Set new value
+ wrapper.find('input').simulate('change', { target: { value: 'new_part_key' } });
+ wrapper.find('input').simulate('keypress', {key: 'Enter'});
+ expect(spyOnKeySelected.calledOnce).toBe(true);
+ });
+
+});
diff --git a/app/addons/documents/assets/less/documents.less b/app/addons/documents/assets/less/documents.less
index be7f460..c161e9b 100644
--- a/app/addons/documents/assets/less/documents.less
+++ b/app/addons/documents/assets/less/documents.less
@@ -22,6 +22,7 @@
@import "header.less";
@import "revision-browser.less";
@import "header-docs-left.less";
+@import "partition-key.less";
button.beautify {
diff --git a/app/addons/documents/assets/less/partition-key.less b/app/addons/documents/assets/less/partition-key.less
new file mode 100644
index 0000000..bf8d1a9
--- /dev/null
+++ b/app/addons/documents/assets/less/partition-key.less
@@ -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.
+
+@import "../../../../../assets/less/variables.less";
+
+.partition-selector {
+ display: flex;
+ align-items: center;
+ padding: 0;
+ min-height: 30px;
+}
+
+.partition-selector__switch {
+ background-color: transparent;
+ border: none;
+ color: #666;
+ font-size: 1rem;
+ .fonticon-filter {
+ font-size: 1.25rem;
+ padding-right: 6px;
+ }
+ &:hover {
+ color: @hoverHighlight;
+ }
+}
+
+.partition-selector__switch--active {
+ color: @brandHighlight;
+ padding-right: 0px;
+}
+
+.partition-selector__key {
+ flex: 1;
+ color: #666;
+}
+
+.partition-selector__key--active {
+ color: @brandHighlight;
+}
+
+.partition-selector__global {
+ color: #666;
+}
diff --git a/app/addons/documents/base.js b/app/addons/documents/base.js
index 144be20..6809d5f 100644
--- a/app/addons/documents/base.js
+++ b/app/addons/documents/base.js
@@ -17,6 +17,7 @@
import reducers from "./index-results/reducers";
import mangoReducers from "./mango/mango.reducers";
import sidebarReducers from "./sidebar/reducers";
+import partitionKeyReducers from "./partition-key/reducers";
import revisionBrowserReducers from './rev-browser/reducers';
import "./assets/less/documents.less";
@@ -24,7 +25,8 @@
indexResults: reducers,
mangoQuery: mangoReducers,
sidebar: sidebarReducers,
- revisionBrowser: revisionBrowserReducers
+ revisionBrowser: revisionBrowserReducers,
+ partitionKey: partitionKeyReducers
});
function getQueryParam (query) {
@@ -49,6 +51,12 @@
}
});
+FauxtonAPI.registerUrls('partitioned_allDocs', {
+ app: function (databaseName, partitionKey, query) {
+ return 'database/' + databaseName + '/_partition/' + partitionKey + '/_all_docs' + getQueryParam(query);
+ }
+});
+
FauxtonAPI.registerUrls('allDocsSanitized', {
server: function (id, query) {
id = encodeURIComponent(id);
@@ -124,6 +132,18 @@
}
});
+FauxtonAPI.registerUrls('partitioned_view', {
+ server: function (database, partitionKey, designDoc, viewName) {
+ return Helpers.getServerUrl('/' + database + '/_partition/' + partitionKey + '/_design/' + designDoc + '/_view/' + viewName);
+ },
+ app: function (database, partitionKey, designDoc) {
+ return 'database/' + database + '/_partition/' + partitionKey + '/_design/' + designDoc + '/_view/';
+ },
+ apiurl: function (database, partitionKey, designDoc, viewName) {
+ return Helpers.getApiUrl('/' + database + '/_partition/' + partitionKey + '/_design/' + designDoc + '/_view/' + viewName);
+ }
+});
+
FauxtonAPI.registerUrls('document', {
server: function (database, doc, query) {
if (_.isUndefined(query)) {
diff --git a/app/addons/documents/layouts.js b/app/addons/documents/layouts.js
index 8a0c05c..bd6f680 100644
--- a/app/addons/documents/layouts.js
+++ b/app/addons/documents/layouts.js
@@ -24,6 +24,7 @@
import PaginationContainer from './index-results/containers/PaginationContainer';
import ApiBarContainer from './index-results/containers/ApiBarContainer';
import { queryAllDocs, queryMapReduceView } from './index-results/api';
+import PartitionKeySelectorContainer from './partition-key/container';
import Constants from './constants';
import Helpers from './helpers';
@@ -39,8 +40,21 @@
fetchUrl,
ddocsOnly,
queryDocs,
- selectedNavItem
+ selectedNavItem,
+ showPartitionKeySelector,
+ partitionKey,
+ onPartitionKeySelected,
+ onGlobalModeSelected,
+ globalMode
}) => {
+ const partKeySelector = (<PartitionKeySelectorContainer
+ databaseName={dbName}
+ partitionKey={partitionKey}
+ onPartitionKeySelected={onPartitionKeySelected}
+ onGlobalModeSelected={onGlobalModeSelected}
+ globalMode={globalMode}/>
+ );
+
return (
<header className="two-panel-header">
<div className="flex-layout flex-row">
@@ -51,6 +65,9 @@
/>
</div>
<div className="right-header-wrapper flex-layout flex-row flex-body">
+ <div style={{flex:1, padding: '18px 6px 12px 12px'}}>
+ {showPartitionKeySelector ? partKeySelector : null}
+ </div>
<div id="right-header" className="flex-fill">
<RightAllDocsHeader
hideQueryOptions={hideQueryOptions}
@@ -81,11 +98,17 @@
hideJumpToDoc: PropTypes.bool,
database: PropTypes.object.isRequired,
queryDocs: PropTypes.func,
- selectedNavItem: PropTypes.object
+ selectedNavItem: PropTypes.object,
+ showPartitionKeySelector: PropTypes.bool,
+ partitionKey: PropTypes.string,
+ onPartitionKeySelected: PropTypes.func.isRequired,
+ onGlobalModeSelected: PropTypes.bool,
+ globalMode: PropTypes.bool
};
TabsSidebarHeader.defaultProps = {
- hideHeaderBar: false
+ hideHeaderBar: false,
+ showPartitionKeySelector: false
};
export const TabsSidebarContent = ({
@@ -140,7 +163,11 @@
fetchUrl,
ddocsOnly,
deleteEnabled = true,
- selectedNavItem
+ selectedNavItem,
+ partitionKey,
+ onPartitionKeySelected,
+ onGlobalModeSelected,
+ globalMode
}) => {
let queryDocs = (params) => { return queryAllDocs(fetchUrl, params); };
if (Helpers.isViewSelected(selectedNavItem)) {
@@ -169,6 +196,11 @@
ddocsOnly={ddocsOnly}
queryDocs={queryDocs}
selectedNavItem={selectedNavItem}
+ showPartitionKeySelector={!ddocsOnly}
+ partitionKey={partitionKey}
+ onPartitionKeySelected={onPartitionKeySelected}
+ onGlobalModeSelected={onGlobalModeSelected}
+ globalMode={globalMode}
/>
<TabsSidebarContent
lowerContent={lowerContent}
diff --git a/app/addons/documents/partition-key/PartitionKeySelector.js b/app/addons/documents/partition-key/PartitionKeySelector.js
new file mode 100644
index 0000000..1bd8b5f
--- /dev/null
+++ b/app/addons/documents/partition-key/PartitionKeySelector.js
@@ -0,0 +1,139 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+import PropTypes from 'prop-types';
+import React from "react";
+import ReactDOM from "react-dom";
+
+
+export default class PartitionKeySelector extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ editorValue: '',
+ editMode: false
+ };
+ this.onModeSwitchClick = this.onModeSwitchClick.bind(this);
+ this.onBlur = this.onBlur.bind(this);
+ this.startEdit = this.startEdit.bind(this);
+ this.onKeyPress = this.onKeyPress.bind(this);
+ this.onChange = this.onChange.bind(this);
+ this.props.checkDbPartitioned(this.props.databaseName);
+ }
+
+ onModeSwitchClick(e) {
+ if (e && e.preventDefault) {
+ e.preventDefault();
+ }
+ if (!this.props.globalMode && this.props.onGlobalModeSelected) {
+ this.props.onGlobalModeSelected();
+ } else if (this.props.partitionKey) {
+ this.props.onPartitionKeySelected(this.state.editorValue);
+ } else {
+ this.startEdit();
+ }
+ }
+
+ startEdit() {
+ this.setState({editMode: true, editorValue: this.props.partitionKey});
+ setTimeout(() => this.textInput.focus());
+ }
+
+ onBlur(e) {
+ if (e && e.preventDefault) {
+ e.preventDefault();
+ }
+ this.setState({editMode: false});
+ }
+
+ onKeyPress(e) {
+ if (e.key === 'Enter') {
+ this.setState({
+ editMode: false
+ });
+ this.props.onPartitionKeySelected(this.state.editorValue);
+ }
+ }
+
+ isPartitionSelected() {
+ return !this.state.global && (this.props.partitionKey.trim().length > 0);
+ }
+
+ onChange(e) {
+ this.setState({editorValue: e.target.value});
+ }
+
+ globalHeader() {
+ return (
+ <button onClick={this.onModeSwitchClick} title="Partition Key Selector" className="button partition-selector__switch">
+ <i className="fonticon-filter"></i>
+ No partition selected
+ </button>
+ );
+ }
+
+ partitionHeader() {
+ const editor = (
+ <input type="text"
+ style={{padding:2, fontSize:16, margin: 0, display: this.state.editMode ? 'block' : 'none'}}
+ onKeyPress={this.onKeyPress}
+ onChange={this.onChange}
+ onBlur={this.onBlur}
+ value={this.state.editorValue}
+ ref={(input) => { this.textInput = input; }} />
+ );
+ let partName = 'Click to select a partition';
+ let className = 'partition-selector__key';
+ if (this.props.partitionKey !== '') {
+ partName = this.props.partitionKey;
+ className += ' partition-selector__key--active';
+ }
+ return (
+ <React.Fragment>
+ <button onClick={this.onModeSwitchClick} title="Partition Key Selector" className="button partition-selector__switch button partition-selector__switch--active">
+ <i className="fonticon-filter"></i>
+ </button>
+ <div className={className}>
+ <span onClick={this.startEdit} style={{display: this.state.editMode ? 'none' : 'block'}}>{partName}</span>
+ {editor}
+ </div>
+ </React.Fragment>
+ );
+ }
+
+ render() {
+ if (!this.props.selectorVisible) {
+ return null;
+ }
+ const global = this.props.globalMode && !this.state.editMode;
+ return (
+ <div className="partition-selector" >
+ {global ? this.globalHeader() : this.partitionHeader()}
+ </div>
+ );
+ }
+}
+
+PartitionKeySelector.defaultProps = {
+ partitionKey: '',
+ globalMode: true
+};
+
+PartitionKeySelector.propTypes = {
+ selectorVisible: PropTypes.bool.isRequired,
+ partitionKey: PropTypes.string.isRequired,
+ checkDbPartitioned: PropTypes.func.isRequired,
+ onPartitionKeySelected: PropTypes.func.isRequired,
+ onGlobalModeSelected: PropTypes.func,
+ globalMode: PropTypes.bool
+};
diff --git a/app/addons/documents/partition-key/actions.js b/app/addons/documents/partition-key/actions.js
new file mode 100644
index 0000000..ebf076c
--- /dev/null
+++ b/app/addons/documents/partition-key/actions.js
@@ -0,0 +1,29 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+import * as API from './api';
+import ActionTypes from './actiontypes';
+
+export const checkDbPartitioned = (databaseName) => (dispatch) => {
+ //Reset visibility to false
+ dispatch({
+ type: ActionTypes.PARTITON_KEY_HIDE_SELECTOR
+ });
+
+ API.fetchDatabaseInfo(databaseName).then(dbInfo => {
+ if (dbInfo.props && dbInfo.props.partitioned === true) {
+ dispatch({
+ type: ActionTypes.PARTITON_KEY_SHOW_SELECTOR
+ });
+ }
+ });
+};
diff --git a/app/addons/documents/partition-key/actiontypes.js b/app/addons/documents/partition-key/actiontypes.js
new file mode 100644
index 0000000..76368ef
--- /dev/null
+++ b/app/addons/documents/partition-key/actiontypes.js
@@ -0,0 +1,15 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+export default {
+ PARTITON_KEY_SHOW_SELECTOR: 'PARTITON_KEY_SHOW_SELECTOR',
+ PARTITON_KEY_HIDE_SELECTOR: 'PARTITON_KEY_HIDE_SELECTOR'
+};
diff --git a/app/addons/documents/partition-key/api.js b/app/addons/documents/partition-key/api.js
new file mode 100644
index 0000000..720d69f
--- /dev/null
+++ b/app/addons/documents/partition-key/api.js
@@ -0,0 +1,20 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+import '@webcomponents/url';
+import {get} from '../../../core/ajax';
+import Helpers from "../../../helpers";
+
+export const fetchDatabaseInfo = (databaseName) => {
+ const url = Helpers.getServerUrl("/" + encodeURIComponent(databaseName));
+ return get(url);
+};
diff --git a/app/addons/documents/partition-key/container.js b/app/addons/documents/partition-key/container.js
new file mode 100644
index 0000000..0a1d373
--- /dev/null
+++ b/app/addons/documents/partition-key/container.js
@@ -0,0 +1,49 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import PartitionKeySelector from './PartitionKeySelector';
+import { checkDbPartitioned } from './actions';
+
+const mapStateToProps = ({ partitionKey }, ownProps) => {
+ return {
+ selectorVisible: partitionKey.selectorVisible,
+ databaseName: ownProps.databaseName,
+ partitionKey: ownProps.partitionKey,
+ onPartitionKeySelected: ownProps.onPartitionKeySelected,
+ globalMode: ownProps.globalMode
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ checkDbPartitioned: (databaseName) => {
+ dispatch(checkDbPartitioned(databaseName));
+ }
+ };
+};
+
+const PartitionKeySelectorContainer = connect (
+ mapStateToProps,
+ mapDispatchToProps
+)(PartitionKeySelector);
+
+export default PartitionKeySelectorContainer;
+
+PartitionKeySelectorContainer.propTypes = {
+ databaseName: PropTypes.string.isRequired,
+ partitionKey: PropTypes.string.isRequired,
+ onPartitionKeySelected: PropTypes.func.isRequired,
+ onGlobalModeSelected: PropTypes.func.isRequired,
+ globalMode: PropTypes.bool
+};
diff --git a/app/addons/documents/partition-key/reducers.js b/app/addons/documents/partition-key/reducers.js
new file mode 100644
index 0000000..8da4ad3
--- /dev/null
+++ b/app/addons/documents/partition-key/reducers.js
@@ -0,0 +1,37 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+import ActionTypes from './actiontypes';
+
+const initialState = {
+ selectorVisible: false
+};
+
+export default function partitionKey(state = initialState, action) {
+ switch (action.type) {
+
+ case ActionTypes.PARTITON_KEY_SHOW_SELECTOR:
+ return {
+ ...state,
+ selectorVisible: true
+ };
+
+ case ActionTypes.PARTITON_KEY_HIDE_SELECTOR:
+ return {
+ ...state,
+ selectorVisible: false
+ };
+
+ default:
+ return state;
+ }
+}
diff --git a/app/addons/documents/routes-documents.js b/app/addons/documents/routes-documents.js
index 453003a..41c7493 100644
--- a/app/addons/documents/routes-documents.js
+++ b/app/addons/documents/routes-documents.js
@@ -23,8 +23,12 @@
var DocumentsRouteObject = BaseRoute.extend({
routes: {
+ "database/:database/_partition/:partitionkey/_all_docs": {
+ route: "partitionedAllDocs",
+ roles: ["fx_loggedIn"]
+ },
"database/:database/_all_docs(:extra)": {
- route: "allDocs",
+ route: "globalAllDocs",
roles: ["fx_loggedIn"]
},
"database/:database/_design/:ddoc/_info": {
@@ -70,12 +74,20 @@
/>;
},
+ globalAllDocs: function (databaseName, options) {
+ return this.allDocs(databaseName, '', options);
+ },
+
+ partitionedAllDocs: function (databaseName, partitionKey) {
+ return this.allDocs(databaseName, partitionKey);
+ },
+
/*
* docParams are the options fauxton uses to fetch from the server
* urlParams are what are shown in the url and to the user
* They are not the same when paginating
*/
- allDocs: function (databaseName, options) {
+ allDocs: function (databaseName, partitionKey, options) {
const params = this.createParams(options),
docParams = params.docParams;
@@ -95,7 +107,15 @@
const endpoint = this.database.allDocs.urlRef("apiurl", {});
const docURL = FauxtonAPI.constants.DOC_URLS.GENERAL;
-
+ const navigateToPartitionedAllDocs = (partKey) => {
+ const baseUrl = FauxtonAPI.urls('partitioned_allDocs', 'app', encodeURIComponent(databaseName),
+ encodeURIComponent(partKey));
+ FauxtonAPI.navigate('#/' + baseUrl);
+ };
+ const navigateToGlobalAllDocs = () => {
+ const baseUrl = FauxtonAPI.urls('allDocs', 'app', encodeURIComponent(databaseName));
+ FauxtonAPI.navigate('#/' + baseUrl);
+ };
const dropDownLinks = this.getCrumbs(this.database);
return <DocsTabsSidebarLayout
docURL={docURL}
@@ -107,6 +127,10 @@
fetchUrl={url}
ddocsOnly={onlyShowDdocs}
selectedNavItem={selectedNavItem}
+ partitionKey={partitionKey}
+ onPartitionKeySelected={navigateToPartitionedAllDocs}
+ onGlobalModeSelected={navigateToGlobalAllDocs}
+ globalMode={partitionKey === ''}
/>;
},
diff --git a/app/addons/documents/routes-index-editor.js b/app/addons/documents/routes-index-editor.js
index 935ff47..1485b56 100644
--- a/app/addons/documents/routes-index-editor.js
+++ b/app/addons/documents/routes-index-editor.js
@@ -29,8 +29,12 @@
route: 'createView',
roles: ['fx_loggedIn']
},
+ 'database/:database/_partition/:partitionkey/_design/:ddoc/_view/:view': {
+ route: 'showPartitionedView',
+ roles: ['fx_loggedIn']
+ },
'database/:database/_design/:ddoc/_view/:view': {
- route: 'showView',
+ route: 'showGlobalView',
roles: ['fx_loggedIn']
},
'database/:database/_design/:ddoc/_view/:view/edit': {
@@ -47,8 +51,15 @@
this.addSidebar();
},
- showView: function (databaseName, ddoc, viewName) {
+ showGlobalView: function (databaseName, ddoc, viewName) {
+ return this.showView(databaseName, '', ddoc, viewName);
+ },
+ showPartitionedView: function (databaseName, partitionKey, ddoc, viewName) {
+ return this.showView(databaseName, partitionKey, ddoc, viewName);
+ },
+
+ showView: function (databaseName, partitionKey, ddoc, viewName) {
viewName = viewName.replace(/\?.*$/, '');
ActionsIndexEditor.clearIndex();
@@ -72,7 +83,11 @@
const endpoint = FauxtonAPI.urls('view', 'apiurl', encodeURIComponent(databaseName),
encodeURIComponent(ddoc), encodeURIComponent(viewName));
const docURL = FauxtonAPI.constants.DOC_URLS.GENERAL;
-
+ const navigateToPartitionedView = (partKey) => {
+ const baseUrl = FauxtonAPI.urls('partitioned_view', 'app', encodeURIComponent(databaseName),
+ encodeURIComponent(partKey), encodeURIComponent(ddoc));
+ FauxtonAPI.navigate('#/' + baseUrl + encodeURIComponent(viewName));
+ };
const dropDownLinks = this.getCrumbs(this.database);
return <DocsTabsSidebarLayout
docURL={docURL}
@@ -84,6 +99,9 @@
ddocsOnly={false}
deleteEnabled={false}
selectedNavItem={selectedNavItem}
+ partitionKey={partitionKey}
+ onPartitionKeySelected={navigateToPartitionedView}
+ globalMode={partitionKey === ''}
/>;
},