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 2023/03/13 15:06:47 UTC
[couchdb-fauxton] branch main updated: Control amount of replications displayed (#1391)
This is an automated email from the ASF dual-hosted git repository.
amaranhao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb-fauxton.git
The following commit(s) were added to refs/heads/main by this push:
new 034f5aaf Control amount of replications displayed (#1391)
034f5aaf is described below
commit 034f5aafcfd35757ab2781f8a97d8cb824b8da0c
Author: Margaret Harrigan <39...@users.noreply.github.com>
AuthorDate: Mon Mar 13 08:06:40 2023 -0700
Control amount of replications displayed (#1391)
---
app/addons/replication/__tests__/actions.test.js | 38 +++++++++--
app/addons/replication/__tests__/api.tests.js | 10 +--
.../__tests__/replication-footer.test.js | 63 ++++++++++++++++++
app/addons/replication/actions.js | 25 +++++---
app/addons/replication/actiontypes.js | 3 +-
app/addons/replication/api.js | 14 ++--
.../replication/assets/less/replication.less | 4 +-
app/addons/replication/components/activity.js | 1 -
.../replication/components/replication-footer.js | 52 +++++++++++++++
app/addons/replication/container.js | 20 +++---
app/addons/replication/controller.js | 23 ++++++-
app/addons/replication/reducers.js | 11 +++-
.../tests/nightwatch/replicationactivity.js | 75 ++++++++++++++++++++++
assets/less/fauxton.less | 3 +-
14 files changed, 301 insertions(+), 41 deletions(-)
diff --git a/app/addons/replication/__tests__/actions.test.js b/app/addons/replication/__tests__/actions.test.js
index b9cfa64f..50eaef10 100644
--- a/app/addons/replication/__tests__/actions.test.js
+++ b/app/addons/replication/__tests__/actions.test.js
@@ -10,7 +10,7 @@
// License for the specific language governing permissions and limitations under
// the License.
-import {replicate, getReplicationStateFrom, deleteDocs} from '../actions';
+import {replicate, getReplicationStateFrom, deleteDocs, setPageLimit} from '../actions';
import ActionTypes from '../actiontypes';
import fetchMock from 'fetch-mock';
import FauxtonAPI from '../../../core/api';
@@ -33,6 +33,7 @@ describe("Replication Actions", () => {
it('creates a new database if it does not exist', () => {
const dispatch = () => {};
+ const pageLimit = 20;
fetchMock.postOnce('./_replicator', {
status: 404,
body: {
@@ -66,7 +67,8 @@ describe("Replication Actions", () => {
replicationTarget: "REPLICATION_TARGET_NEW_LOCAL_DATABASE",
replicationType: "",
username: "tester"
- })(dispatch).then(() => {
+ }, pageLimit)(dispatch).then(() => {
+ finalPost.calls('./_replicator');
expect(finalPost.calls('./_replicator').length).toBe(3);
//fetchMock.done();
@@ -75,6 +77,7 @@ describe("Replication Actions", () => {
it('does not try to create new database if it already exist', () => {
const dispatch = () => {};
+ const pageLimit = 20;
const mockPost = fetchMock.postOnce('./_replicator', {
status: 200,
body: {
@@ -93,7 +96,8 @@ describe("Replication Actions", () => {
replicationTarget: "REPLICATION_TARGET_NEW_LOCAL_DATABASE",
replicationType: "",
username: "tester"
- })(dispatch).then(() => {
+ }, pageLimit)(dispatch).then(() => {
+ mockPost.calls('./_replicator');
expect(mockPost.calls('./_replicator').length).toBe(1);
fetchMock.done();
});
@@ -255,22 +259,44 @@ describe("Replication Actions", () => {
}
}
];
+ const pageLimit = 20;
fetchMock.getOnce('./_scheduler/jobs', 404);
- fetchMock.getOnce('./_replicator/_all_docs?include_docs=true&limit=100', {rows: []});
+ fetchMock.getOnce(`./_replicator/_all_docs?include_docs=true&limit=${pageLimit + 1}`, {rows: []});
fetchMock.postOnce('./_replicator/_bulk_docs', {
status: 200,
body: resp
});
-
const dispatch = ({type}) => {
if (ActionTypes.REPLICATION_CLEAR_SELECTED_DOCS === type) {
done();
}
};
- deleteDocs(docs)(dispatch);
+ deleteDocs(docs, pageLimit)(dispatch);
+ });
+ });
+
+ describe('setPageLimit', () => {
+ afterEach(() => {
+ fetchMock.reset();
+ });
+
+ it('sends request for new replications list', (done) => {
+ const pageLimit = 20;
+
+ fetchMock.getOnce('./_scheduler/jobs', 404);
+ fetchMock.getOnce(`./_replicator/_all_docs?include_docs=true&limit=${pageLimit + 1}`, {rows: []});
+
+ const dispatch = ({type, options}) => {
+ if (ActionTypes.REPLICATION_SET_PAGE_LIMIT === type) {
+ expect(options).toEqual(pageLimit);
+ done();
+ }
+ };
+
+ setPageLimit(pageLimit)(dispatch);
});
});
});
diff --git a/app/addons/replication/__tests__/api.tests.js b/app/addons/replication/__tests__/api.tests.js
index ff2db57e..537424ca 100644
--- a/app/addons/replication/__tests__/api.tests.js
+++ b/app/addons/replication/__tests__/api.tests.js
@@ -577,10 +577,11 @@ describe('Replication API', () => {
});
it("returns parsedReplicationDocs and ignores all design docs", () => {
+ const pageLimit = 20;
fetchMock.getOnce('./_scheduler/jobs', 404);
- fetchMock.get('./_replicator/_all_docs?include_docs=true&limit=100', _repDocs);
+ fetchMock.get(`./_replicator/_all_docs?include_docs=true&limit=${pageLimit + 1}`, _repDocs);
return supportNewApi(true)
- .then(fetchReplicationDocs)
+ .then(() => fetchReplicationDocs(pageLimit))
.then(docs => {
expect(docs.length).toBe(1);
expect(docs[0]._id).toBe("c94d4839d1897105cb75e1251e0003ea");
@@ -594,11 +595,12 @@ describe('Replication API', () => {
});
it("returns parsedReplicationDocs", () => {
+ const pageLimit = 20;
fetchMock.getOnce('./_scheduler/jobs', 200);
- fetchMock.get('./_replicator/_all_docs?include_docs=true&limit=100', _repDocs);
+ fetchMock.get(`./_replicator/_all_docs?include_docs=true&limit=${pageLimit + 1}`, _repDocs);
fetchMock.get('./_scheduler/docs?include_docs=true', _schedDocs);
return supportNewApi(true)
- .then(fetchReplicationDocs)
+ .then(() => fetchReplicationDocs(pageLimit))
.then(docs => {
expect(docs.length).toBe(1);
expect(docs[0]._id).toBe("c94d4839d1897105cb75e1251e0003ea");
diff --git a/app/addons/replication/__tests__/replication-footer.test.js b/app/addons/replication/__tests__/replication-footer.test.js
new file mode 100644
index 00000000..7a3931d4
--- /dev/null
+++ b/app/addons/replication/__tests__/replication-footer.test.js
@@ -0,0 +1,63 @@
+// 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 { mount } from 'enzyme';
+import sinon from 'sinon';
+import { ReplicationFooter } from '../components/replication-footer';
+
+describe('Replication Footer', () =>{
+ it('no replications to display', () => {
+ const footer = mount(<ReplicationFooter
+ statusDocs={[]}
+ pageLimit={5}
+ setPageLimit={() => {}}
+ />);
+
+ expect(footer.find('.current-replications').text()).toBe('Showing 0 replications.');
+ });
+
+ it('display max # of replications', () => {
+ const footer = mount(<ReplicationFooter
+ statusDocs={[1, 2, 3, 4, 5]}
+ pageLimit={5}
+ setPageLimit={() => {}}
+ />);
+
+ expect(footer.find('.current-replications').text()).toBe('Showing replications 1 - 5');
+ });
+
+ it('display replications with less than max #', () => {
+ const footer = mount(<ReplicationFooter
+ statusDocs={[1, 2, 3, 4, 5, 6, 7, 8]}
+ pageLimit={10}
+ setPageLimit={() => {}}
+ />);
+
+ expect(footer.find('.current-replications').text()).toBe('Showing replications 1 - 8');
+ });
+
+ it('change max value with dropdown', () => {
+ const spy = sinon.spy();
+ const footer = mount(<ReplicationFooter
+ statusDocs={[1, 2, 3, 4, 5, 6, 7, 8]}
+ pageLimit={5}
+ setPageLimit={spy}
+ />);
+
+ expect(footer.find('.current-replications').text()).toBe('Showing replications 1 - 5');
+ footer.find('#select-per-page').simulate('change', {
+ target: {value: 10}
+ });
+ sinon.assert.calledOnce(spy);
+ });
+});
diff --git a/app/addons/replication/actions.js b/app/addons/replication/actions.js
index 68ed9bc3..22a04ab8 100644
--- a/app/addons/replication/actions.js
+++ b/app/addons/replication/actions.js
@@ -51,7 +51,7 @@ export const getDatabasesList = () => dispatch => {
});
};
-export const replicate = (params) => dispatch => {
+export const replicate = (params, pageLimit) => dispatch => {
const replicationDoc = createReplicationDoc(params);
const url = MainHelper.getServerUrl("/_replicator");
const promise = post(url, replicationDoc);
@@ -85,12 +85,12 @@ export const replicate = (params) => dispatch => {
clear: true
});
- dispatch(getReplicationActivity());
+ dispatch(getReplicationActivity(pageLimit));
FauxtonAPI.navigate('#/replication');
}).catch(json => {
if (json.error && json.error === "not_found") {
return createReplicatorDB().then(() => {
- return replicate(params)(dispatch);
+ return replicate(params, pageLimit)(dispatch);
}).catch(handleError);
}
handleError(json);
@@ -111,15 +111,12 @@ export const clearReplicationForm = () => {
return { type: ActionTypes.REPLICATION_CLEAR_FORM };
};
-export const getReplicationActivity = () => dispatch => {
+export const getReplicationActivity = (pageLimit) => (dispatch) => {
dispatch({
type: ActionTypes.REPLICATION_FETCHING_STATUS,
});
- supportNewApi()
- .then(supportNewApi => {
- return fetchReplicationDocs(supportNewApi);
- })
+ fetchReplicationDocs(pageLimit)
.then(docs => {
dispatch({
type: ActionTypes.REPLICATION_STATUS,
@@ -201,7 +198,7 @@ export const clearSelectedReplicates = () => {
};
};
-export const deleteDocs = (docs) => dispatch => {
+export const deleteDocs = (docs, pageLimit) => dispatch => {
const bulkDocs = docs.map(({raw: doc}) => {
doc._deleted = true;
return doc;
@@ -237,7 +234,7 @@ export const deleteDocs = (docs) => dispatch => {
});
dispatch(clearSelectedDocs());
- dispatch(getReplicationActivity());
+ dispatch(getReplicationActivity(pageLimit));
})
.catch(resp => {
resp.json()
@@ -420,3 +417,11 @@ export const checkForNewApi = () => dispatch => {
});
});
};
+
+export const setPageLimit = (limit) => dispatch => {
+ dispatch({
+ type: ActionTypes.REPLICATION_SET_PAGE_LIMIT,
+ options: limit,
+ });
+ getReplicationActivity(limit)(dispatch);
+};
diff --git a/app/addons/replication/actiontypes.js b/app/addons/replication/actiontypes.js
index 71438686..8fdabd00 100644
--- a/app/addons/replication/actiontypes.js
+++ b/app/addons/replication/actiontypes.js
@@ -38,5 +38,6 @@ export default {
REPLICATION_CLEAR_SELECTED_REPLICATES: 'REPLICATION_CLEAR_SELECTED_REPLICATES',
REPLICATION_FETCHING_FORM_STATE: 'REPLICATION_FETCHING_FORM_STATE',
REPLICATION_HIDE_PASSWORD_MODAL: 'REPLICATION_HIDE_PASSWORD_MODAL',
- REPLICATION_SHOW_PASSWORD_MODAL: 'REPLICATION_SHOW_PASSWORD_MODAL'
+ REPLICATION_SHOW_PASSWORD_MODAL: 'REPLICATION_SHOW_PASSWORD_MODAL',
+ REPLICATION_SET_PAGE_LIMIT: 'REPLICATION_SET_PAGE_LIMIT'
};
diff --git a/app/addons/replication/api.js b/app/addons/replication/api.js
index 75dee5f0..701b66c5 100644
--- a/app/addons/replication/api.js
+++ b/app/addons/replication/api.js
@@ -16,7 +16,6 @@ import FauxtonAPI from '../../core/api';
import Helpers from '../../helpers';
import {get, post, put} from '../../core/ajax';
import base64 from 'base-64';
-import _ from 'lodash';
let newApiPromise = null;
export const supportNewApi = (forceCheck) => {
@@ -308,19 +307,24 @@ export const combineDocsAndScheduler = (docs, schedulerDocs) => {
});
};
-export const fetchReplicationDocs = () => {
+export const fetchReplicationDocs = (maxItems) => {
return supportNewApi()
.then(newApi => {
- const url = Helpers.getServerUrl('/_replicator/_all_docs?include_docs=true&limit=100');
+ // Increase limit by 1 to account for the design doc in the DB
+ const url = Helpers.getServerUrl(`/_replicator/_all_docs?include_docs=true&limit=${maxItems + 1}`);
const docsPromise = get(url)
.then((res) => {
if (res.error) {
return [];
}
-
- return parseReplicationDocs(res.rows.filter(row => row.id.indexOf("_design/") === -1));
+ const listWithoutDDocs = res.rows.filter(row => row.id.indexOf("_design/") === -1);
+ if (listWithoutDDocs.length > maxItems) {
+ listWithoutDDocs.pop();
+ }
+ return parseReplicationDocs(listWithoutDDocs);
});
+
if (!newApi) {
return docsPromise;
}
diff --git a/app/addons/replication/assets/less/replication.less b/app/addons/replication/assets/less/replication.less
index ec1c0ad6..076346bf 100644
--- a/app/addons/replication/assets/less/replication.less
+++ b/app/addons/replication/assets/less/replication.less
@@ -16,7 +16,7 @@
@replication_input_field_width: 400px;
div.replication__page {
- padding-top: 25px !important;
+ padding: 25px 0 40px 0 !important;
display: flex;
flex-direction: column;
align-items: center;
@@ -179,7 +179,7 @@ div.replication__page {
}
.replication__activity {
- padding: 0 10px 0 10px !important;
+ padding: 0 10px 40px 10px !important;
width:100%;
}
diff --git a/app/addons/replication/components/activity.js b/app/addons/replication/components/activity.js
index b2fc0eeb..0d1ae981 100644
--- a/app/addons/replication/components/activity.js
+++ b/app/addons/replication/components/activity.js
@@ -74,7 +74,6 @@ export default class Activity extends React.Component {
<div className="replication__activity">
<p className="replication__activity-caveat">
Replications must have a replication document to display in the following table.
- Up to about 100 replications are displayed.
</p>
<ReplicationHeader
filter={filter}
diff --git a/app/addons/replication/components/replication-footer.js b/app/addons/replication/components/replication-footer.js
new file mode 100644
index 00000000..d09f9f98
--- /dev/null
+++ b/app/addons/replication/components/replication-footer.js
@@ -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 PropTypes from 'prop-types';
+
+import React from 'react';
+import PerPageSelector from '../../documents/index-results/components/pagination/PerPageSelector';
+
+export class ReplicationFooter extends React.Component {
+
+ getFooterText () {
+ const { statusDocs, pageLimit } = this.props;
+
+ if (statusDocs.length === 0) {
+ return <span>Showing 0 replications.</span>;
+ }
+
+ //either page limit or total # of replications, whichever is smaller
+ return <span>Showing replications 1 - {Math.min(pageLimit, statusDocs.length)}</span>;
+ }
+
+ perPageChange (limit) {
+ this.props.setPageLimit(limit);
+ }
+
+ render() {
+ const { pageLimit } = this.props;
+
+ return (
+ <footer className="pagination-footer">
+ <PerPageSelector label="Max replications displayed:" options={[5, 10, 25, 50, 100, 200, 300, 400, 500]} perPageChange={this.perPageChange.bind(this)} perPage={pageLimit} />
+ <div className="current-replications">
+ {this.getFooterText()}
+ </div>
+ </footer>
+ );
+ }
+}
+
+ReplicationFooter.propTypes = {
+ statusDocs: PropTypes.array.isRequired,
+ pageLimit: PropTypes.number.isRequired,
+ setPageLimit: PropTypes.func.isRequired
+};
diff --git a/app/addons/replication/container.js b/app/addons/replication/container.js
index 5be9079e..5ade93fa 100644
--- a/app/addons/replication/container.js
+++ b/app/addons/replication/container.js
@@ -21,7 +21,8 @@ import {
changeActivitySort,
deleteReplicates,
selectAllReplicates,
- selectReplicate
+ selectReplicate,
+ setPageLimit
} from './actions';
import {
@@ -53,7 +54,8 @@ import {
isReplicateInfoLoading,
getAllReplicateSelected,
getReplicateInfo,
- someReplicateSelected
+ someReplicateSelected,
+ getPageLimit
} from './reducers';
const mapStateToProps = ({replication, databases}, ownProps) => {
@@ -102,11 +104,12 @@ const mapStateToProps = ({replication, databases}, ownProps) => {
replicateLoading: isReplicateInfoLoading(replication),
replicateInfo: getReplicateInfo(replication),
allReplicateSelected: getAllReplicateSelected(replication),
- someReplicateSelected: someReplicateSelected(replication)
+ someReplicateSelected: someReplicateSelected(replication),
+ pageLimit: getPageLimit(replication)
};
};
-const mapDispatchToProps = (dispatch) => {
+const mapDispatchToProps = (dispatch, ownProps) => {
return {
checkForNewApi: () => dispatch(checkForNewApi()),
updateFormField: (fieldName) => (value) => {
@@ -114,22 +117,23 @@ const mapDispatchToProps = (dispatch) => {
},
clearReplicationForm: () => dispatch(clearReplicationForm()),
initReplicator: (localSource) => dispatch(initReplicator(localSource)),
- getReplicationActivity: () => dispatch(getReplicationActivity()),
+ getReplicationActivity: (pageLimit) => dispatch(getReplicationActivity(pageLimit)),
getReplicateActivity: () => dispatch(getReplicateActivity()),
getReplicationStateFrom: (id) => dispatch(getReplicationStateFrom(id)),
getDatabasesList: () => dispatch(getDatabasesList()),
- replicate: (params) => dispatch(replicate(params)),
+ replicate: (params) => dispatch(replicate(params, ownProps.pageLimit)),
showConflictModal: () => dispatch(showConflictModal()),
hideConflictModal: () => dispatch(hideConflictModal()),
filterReplicate: (filter) => dispatch(filterReplicate(filter)),
filterDocs: (filter) => dispatch(filterDocs(filter)),
selectDoc: (doc) => dispatch(selectDoc(doc)),
- deleteDocs: (docs) => dispatch(deleteDocs(docs)),
+ deleteDocs: (docs) => dispatch(deleteDocs(docs, ownProps.pageLimit)),
selectAllDocs: () => dispatch(selectAllDocs()),
changeActivitySort: (sort) => dispatch(changeActivitySort(sort)),
selectAllReplicates: () => dispatch(selectAllReplicates()),
deleteReplicates: (replicates) => dispatch(deleteReplicates(replicates)),
- selectReplicate: (replicate) => dispatch(selectReplicate(replicate))
+ selectReplicate: (replicate) => dispatch(selectReplicate(replicate)),
+ setPageLimit: (limit) => dispatch(setPageLimit(limit))
};
};
diff --git a/app/addons/replication/controller.js b/app/addons/replication/controller.js
index 0c7cc00d..bf3f3235 100644
--- a/app/addons/replication/controller.js
+++ b/app/addons/replication/controller.js
@@ -16,9 +16,10 @@ import Components from '../components/react-components';
import NewReplication from './components/newreplication';
import Activity from './components/activity';
import {checkReplicationDocID} from './api';
-import {OnePane, OnePaneHeader, OnePaneContent} from '../components/layouts';
+import {OnePane, OnePaneHeader, OnePaneContent, OnePaneFooter} from '../components/layouts';
import {TabElementWrapper, TabElement} from '../components/components/tabelement';
import ReplicateActivity from './components/replicate-activity';
+import { ReplicationFooter } from './components/replication-footer';
const {LoadLines, Polling, RefreshBtn} = Components;
@@ -38,7 +39,7 @@ export default class ReplicationController extends React.Component {
}
getAllActivity () {
- this.props.getReplicationActivity();
+ this.props.getReplicationActivity(this.props.pageLimit);
this.props.getReplicateActivity();
}
@@ -220,6 +221,21 @@ export default class ReplicationController extends React.Component {
);
}
+ getFooter () {
+ const { tabSection, statusDocs, pageLimit, setPageLimit } = this.props;
+
+ if (tabSection === 'activity') {
+ return (
+ <ReplicationFooter
+ statusDocs={statusDocs}
+ pageLimit={pageLimit}
+ setPageLimit={setPageLimit}
+ />
+ );
+ }
+ return null;
+ }
+
render () {
const { checkingAPI } = this.props;
@@ -240,6 +256,9 @@ export default class ReplicationController extends React.Component {
</div>
</div>
</OnePaneContent>
+ <OnePaneFooter>
+ {this.getFooter()}
+ </OnePaneFooter>
</OnePane>
);
}
diff --git a/app/addons/replication/reducers.js b/app/addons/replication/reducers.js
index 40a276a1..45b3e62b 100644
--- a/app/addons/replication/reducers.js
+++ b/app/addons/replication/reducers.js
@@ -89,7 +89,8 @@ const initialState = {
replicateInfo: [],
checkingAPI: true,
- activitySort: loadActivitySort()
+ activitySort: loadActivitySort(),
+ pageLimit: 100,
};
const clearForm = (state) => {
@@ -348,6 +349,12 @@ const replication = (state = initialState, {type, options}) => {
allReplicateSelected: false
};
+ case ActionTypes.REPLICATION_SET_PAGE_LIMIT:
+ return {
+ ...state,
+ pageLimit: options
+ };
+
default:
return state;
}
@@ -406,4 +413,6 @@ export const getReplicateInfo = (state) => {
});
};
+export const getPageLimit = (state) => state.pageLimit;
+
export default replication;
diff --git a/app/addons/replication/tests/nightwatch/replicationactivity.js b/app/addons/replication/tests/nightwatch/replicationactivity.js
index e32cfe8a..c5b8fa3d 100644
--- a/app/addons/replication/tests/nightwatch/replicationactivity.js
+++ b/app/addons/replication/tests/nightwatch/replicationactivity.js
@@ -92,6 +92,7 @@ module.exports = {
.waitForElementPresent('a[href="#/database/_replicator/existing-doc-filter2"]', waitTime, true)
.end();
},
+
"Action click doesn't change doc's order": client =>{
const waitTime = client.globals.maxWaitTime;
const baseUrl = client.options.launch_url;
@@ -129,5 +130,79 @@ module.exports = {
'Checking if the order was reserved if no documents were sorted');
})
.end();
+ },
+
+ "Change number of replications displayed": client =>{
+ const waitTime = client.globals.maxWaitTime;
+ const baseUrl = client.options.launch_url;
+
+ const replicatorDoc1 = {
+ _id: 'existing-doc-id-display',
+ source: "http://source-db.com",
+ target: "http://target-db.com"
+ };
+
+ const replicatorDoc2 = {
+ _id: 'existing-doc-id-display2',
+ source: "http://source-db2.com",
+ target: "http://target-db.com"
+ };
+
+ const replicatorDoc3 = {
+ _id: 'existing-doc-id-display3',
+ source: "http://source-db3.com",
+ target: "http://target-db.com"
+ };
+
+ const replicatorDoc4 = {
+ _id: 'existing-doc-id-display4',
+ source: "http://source-db4.com",
+ target: "http://target-db.com"
+ };
+
+ const replicatorDoc5 = {
+ _id: 'existing-doc-id-display5',
+ source: "http://source-db5.com",
+ target: "http://target-db.com"
+ };
+
+ const replicatorDoc6 = {
+ _id: 'existing-doc-id-display6',
+ source: "http://source-db6.com",
+ target: "http://target-db.com"
+ };
+
+ client
+ .deleteDatabase('_replicator')
+ .createDatabase('_replicator')
+ .createDocument(replicatorDoc1._id, '_replicator', replicatorDoc1)
+ .createDocument(replicatorDoc2._id, '_replicator', replicatorDoc2)
+ .createDocument(replicatorDoc3._id, '_replicator', replicatorDoc3)
+ .createDocument(replicatorDoc4._id, '_replicator', replicatorDoc4)
+ .createDocument(replicatorDoc5._id, '_replicator', replicatorDoc5)
+ .createDocument(replicatorDoc6._id, '_replicator', replicatorDoc6)
+ .loginToGUI()
+ .url(baseUrl + '/#replication')
+ .waitForElementNotPresent('.load-lines', waitTime, true)
+ .waitForElementPresent('.replication__table-row', waitTime, true)
+ .getText('.current-replications', function(result) {
+ this.verify.ok(result.value === "Showing replications 1 - 6");
+ })
+ .assert.elementsCount('.replication__table-row', 6)
+ .clickWhenVisible('select[id="select-per-page"] option[value="5"]')
+ .waitForElementNotPresent('.load-lines', waitTime, true)
+ .waitForElementPresent('.replication__table-row', waitTime, true)
+ .getText('.current-replications', function(result) {
+ this.verify.ok(result.value === "Showing replications 1 - 5");
+ })
+ .assert.elementsCount('.replication__table-row', 5)
+ .clickWhenVisible('select[id="select-per-page"] option[value="25"]')
+ .waitForElementNotPresent('.load-lines', waitTime, true)
+ .waitForElementPresent('.replication__table-row', waitTime, true)
+ .getText('.current-replications', function(result) {
+ this.verify.ok(result.value === "Showing replications 1 - 6");
+ })
+ .assert.elementsCount('.replication__table-row', 6)
+ .end();
}
};
diff --git a/assets/less/fauxton.less b/assets/less/fauxton.less
index 96815248..db6b1dbe 100644
--- a/assets/less/fauxton.less
+++ b/assets/less/fauxton.less
@@ -437,7 +437,8 @@ footer.pagination-footer {
}
.current-databases,
- .current-docs {
+ .current-docs,
+ .current-replications {
float: right;
margin: 17px 20px 17px 20px;
}