You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@couchdb.apache.org by GitBox <gi...@apache.org> on 2018/04/06 18:18:04 UTC

[GitHub] Antonio-Maranhao closed pull request #1070: Replication redux

Antonio-Maranhao closed pull request #1070: Replication redux
URL: https://github.com/apache/couchdb-fauxton/pull/1070
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/app/addons/auth/actions.js b/app/addons/auth/actions.js
index 9742bc977..a58cd0915 100644
--- a/app/addons/auth/actions.js
+++ b/app/addons/auth/actions.js
@@ -16,7 +16,6 @@ import ActionTypes from './actiontypes';
 import Api from './api';
 
 const {
-  AUTH_SHOW_PASSWORD_MODAL,
   AUTH_HIDE_PASSWORD_MODAL,
 } = ActionTypes;
 
@@ -119,24 +118,20 @@ export const authenticate = (username, password, onSuccess) => {
     name: username,
     password: password
   })
-    .then(
-      () => {
-        hidePasswordModal();
-        onSuccess(username, password);
-      },
-      () => {
-        FauxtonAPI.addNotification({
-          msg: "Your username or password is incorrect.",
-          type: "error",
-          clear: true
-        });
+    .then((resp) => {
+      if (resp.error) {
+        throw (resp);
       }
-    );
-};
-
-//This is used in the replication store
-export const showPasswordModal = () => {
-  FauxtonAPI.dispatch({ type: AUTH_SHOW_PASSWORD_MODAL });
+      hidePasswordModal();
+      onSuccess(username, password);
+    })
+    .catch(() => {
+      FauxtonAPI.addNotification({
+        msg: "Your username or password is incorrect.",
+        type: "error",
+        clear: true
+      });
+    });
 };
 
 export const hidePasswordModal = () => {
diff --git a/app/addons/documents/rev-browser/actions.js b/app/addons/documents/rev-browser/actions.js
index 7e9fcee72..116af0e13 100644
--- a/app/addons/documents/rev-browser/actions.js
+++ b/app/addons/documents/rev-browser/actions.js
@@ -26,7 +26,6 @@ export const initDiffEditor = (dbName, docId) => dispatch => {
   const url = FauxtonAPI.urls('databaseBaseURL', 'server', dbName);
   db = PouchDB(url);
 
-  // XXX: we need spec compliant promise support and get rid of jQ "deferreds"
   Promise.all([db.get(docId), getTree(db, docId)])
     .then(([doc, tree]) => {
       const conflictingRevs = getConflictingRevs(tree.paths, tree.winner, Object.keys(tree.deleted));
diff --git a/app/addons/replication/__tests__/actions.test.js b/app/addons/replication/__tests__/actions.test.js
index f12851a0c..2e090e846 100644
--- a/app/addons/replication/__tests__/actions.test.js
+++ b/app/addons/replication/__tests__/actions.test.js
@@ -36,6 +36,7 @@ describe("Replication Actions", () => {
     afterEach(fetchMock.restore);
 
     it('creates a new database if it does not exist', (done) => {
+      const dispatch = () => {};
       fetchMock.postOnce('/_replicator', {
         status: 404,
         body: {
@@ -69,7 +70,7 @@ describe("Replication Actions", () => {
         replicationTarget: "REPLICATION_TARGET_NEW_LOCAL_DATABASE",
         replicationType: "",
         username: "tester"
-      });
+      })(dispatch);
 
       //this is not pretty, and might cause some false errors. But its tricky to tell when this test has completed
       setTimeout(() => {
@@ -119,15 +120,15 @@ describe("Replication Actions", () => {
     };
 
     it('builds up correct state', (done) => {
-      FauxtonAPI.dispatcher.register(({type, options}) => {
+      const dispatch = ({type, options}) => {
         if (ActionTypes.REPLICATION_SET_STATE_FROM_DOC === type) {
           assert.deepEqual(docState, options);
           setTimeout(done);
         }
-      });
+      };
 
       fetchMock.getOnce('/_replicator/7dcea9874a8fcb13c6630a1547001559', doc);
-      getReplicationStateFrom(doc._id);
+      getReplicationStateFrom(doc._id)(dispatch);
     });
   });
 
@@ -171,13 +172,15 @@ describe("Replication Actions", () => {
         status: 200,
         body: resp
       });
-      deleteDocs(docs);
 
-      FauxtonAPI.dispatcher.register(({type}) => {
+
+      const dispatch = ({type}) => {
         if (ActionTypes.REPLICATION_CLEAR_SELECTED_DOCS === type) {
           setTimeout(done);
         }
-      });
+      };
+
+      deleteDocs(docs)(dispatch);
     });
   });
 });
diff --git a/app/addons/replication/__tests__/stores.tests.js b/app/addons/replication/__tests__/stores.tests.js
deleted file mode 100644
index bd5fa360f..000000000
--- a/app/addons/replication/__tests__/stores.tests.js
+++ /dev/null
@@ -1,59 +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.
-import utils from '../../../../test/mocha/testUtils';
-import Stores from '../stores';
-import Constants from '../constants';
-
-const assert = utils.assert;
-const store = Stores.replicationStore;
-
-describe('Replication Store', function () {
-
-  afterEach(function () {
-    store.reset();
-  });
-
-  it('confirm updateFormField updates all fields', function () {
-    assert.equal(store.getRemoteSource(), '');
-    store.updateFormField('remoteSource', 'SOURCE');
-    assert.equal(store.getRemoteSource(), 'SOURCE');
-
-    assert.equal(store.getRemoteTarget(), '');
-    store.updateFormField('remoteTarget', 'TARGET');
-    assert.equal(store.getRemoteTarget(), 'TARGET');
-
-    assert.equal(store.getlocalTarget(), '');
-    store.updateFormField('localTarget', 'db');
-    assert.equal(store.getlocalTarget(), 'db');
-
-    assert.equal(store.getReplicationType(), Constants.REPLICATION_TYPE.ONE_TIME);
-    store.updateFormField('replicationType', Constants.REPLICATION_TYPE.CONTINUOUS);
-    assert.equal(store.getReplicationType(), Constants.REPLICATION_TYPE.CONTINUOUS);
-
-    assert.equal(store.getReplicationDocName(), '');
-    store.updateFormField('replicationDocName', 'doc-name');
-    assert.equal(store.getReplicationDocName(), 'doc-name');
-
-    assert.equal(store.getReplicationSource(), '');
-    store.updateFormField('replicationSource', 'rsource');
-    assert.equal(store.getReplicationSource(), 'rsource');
-
-    assert.equal(store.getReplicationTarget(), '');
-    store.updateFormField('replicationTarget', 'rtarget');
-    assert.equal(store.getReplicationTarget(), 'rtarget');
-
-    assert.equal(store.getlocalSource(), '');
-    store.updateFormField('localSource', 'source-db');
-    assert.equal(store.getlocalSource(), 'source-db');
-  });
-
-});
diff --git a/app/addons/replication/actions.js b/app/addons/replication/actions.js
index b12ffd709..ba8199c63 100644
--- a/app/addons/replication/actions.js
+++ b/app/addons/replication/actions.js
@@ -10,6 +10,7 @@
 // License for the specific language governing permissions and limitations under
 // the License.
 import FauxtonAPI from '../../core/api';
+import {get, post} from '../../core/ajax';
 import ActionTypes from './actiontypes';
 import Helpers from './helpers';
 import Constants from './constants';
@@ -22,55 +23,40 @@ import {
   deleteReplicatesApi,
   createReplicatorDB
 } from './api';
-import 'whatwg-fetch';
 
 
-function initReplicator (localSource) {
-  if (localSource) {
-    FauxtonAPI.dispatch({
+export const initReplicator = (routeLocalSource, localSource) => dispatch => {
+  if (routeLocalSource && routeLocalSource !== localSource) {
+    dispatch({
       type: ActionTypes.INIT_REPLICATION,
       options: {
-        localSource: localSource
+        localSource: routeLocalSource
       }
     });
   }
+};
 
-  fetch('/_all_dbs', {
-    credentials: 'include',
-    headers: {
-      'Accept': 'application/json; charset=utf-8',
-      'Content-Type': 'application/json'
-    },
-  })
-    .then(resp => resp.json())
+export const getDatabasesList = () => dispatch => {
+  get('/_all_dbs')
     .then((databases) => {
-      FauxtonAPI.dispatch({
+      dispatch({
         type: ActionTypes.REPLICATION_DATABASES_LOADED,
         options: {
-          databases: databases
+          databases
         }
       });
     });
-}
+};
 
-export const replicate = (params) => {
+export const replicate = (params) => dispatch => {
   const replicationDoc = createReplicationDoc(params);
 
-  const promise = fetch('/_replicator', {
-    method: 'POST',
-    credentials: 'include',
-    headers: {
-      'Accept': 'application/json; charset=utf-8',
-      'Content-Type': 'application/json'
-    },
-    body: JSON.stringify(replicationDoc)
-  })
-    .then(res => res.json());
+  const promise = post('/_replicator', replicationDoc);
 
   const source = Helpers.getDatabaseLabel(replicationDoc.source);
   const target = Helpers.getDatabaseLabel(replicationDoc.target);
 
-  FauxtonAPI.dispatch({
+  dispatch({
     type: ActionTypes.REPLICATION_STARTING,
   });
 
@@ -82,18 +68,21 @@ export const replicate = (params) => {
     });
   };
 
-  promise.then(json => {
-    if (!json.ok) {
-      throw json;
-    }
+  promise
+    .then(json => {
+      if (!json.ok) {
+        throw json;
+      }
 
-    FauxtonAPI.addNotification({
-      msg: `Replication from <code>${decodeURIComponent(source)}</code> to <code>${decodeURIComponent(target)}</code> has been scheduled.`,
-      type: 'success',
-      escape: false,
-      clear: true
-    });
-  })
+      FauxtonAPI.addNotification({
+        msg: `Replication from <code>${decodeURIComponent(source)}</code> to <code>${decodeURIComponent(target)}</code> has been scheduled.`,
+        type: 'success',
+        escape: false,
+        clear: true
+      });
+
+      dispatch(getReplicationActivity());
+    })
     .catch(json => {
       if (json.error && json.error === "not_found") {
         return createReplicatorDB().then(() => {
@@ -106,47 +95,51 @@ export const replicate = (params) => {
     });
 };
 
-function updateFormField (fieldName, value) {
-  FauxtonAPI.dispatch({
+export const updateFormField = (fieldName, value) => {
+  return {
     type: ActionTypes.REPLICATION_UPDATE_FORM_FIELD,
     options: {
       fieldName: fieldName,
       value: value
     }
-  });
-}
+  };
+};
 
-function clearReplicationForm () {
-  FauxtonAPI.dispatch({ type: ActionTypes.REPLICATION_CLEAR_FORM });
-}
+export const clearReplicationForm = () => {
+  return { type: ActionTypes.REPLICATION_CLEAR_FORM };
+};
 
-const getReplicationActivity = (supportNewApi) => {
-  FauxtonAPI.dispatch({
+export const getReplicationActivity = () => dispatch => {
+  dispatch({
     type: ActionTypes.REPLICATION_FETCHING_STATUS,
   });
 
-  fetchReplicationDocs(supportNewApi).then(docs => {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.REPLICATION_STATUS,
-      options: docs
+  supportNewApi()
+    .then(supportNewApi => {
+      return fetchReplicationDocs(supportNewApi);
+    })
+    .then(docs => {
+      dispatch({
+        type: ActionTypes.REPLICATION_STATUS,
+        options: docs
+      });
     });
-  });
 };
 
-const getReplicateActivity = () => {
+export const getReplicateActivity = () => dispatch => {
   supportNewApi()
     .then(newApi => {
       if (!newApi) {
         return;
       }
 
-      FauxtonAPI.dispatch({
+      dispatch({
         type: ActionTypes.REPLICATION_FETCHING_REPLICATE_STATUS,
       });
 
       fetchReplicateInfo()
         .then(replicateInfo => {
-          FauxtonAPI.dispatch({
+          dispatch({
             type: ActionTypes.REPLICATION_REPLICATE_STATUS,
             options: replicateInfo
           });
@@ -154,59 +147,59 @@ const getReplicateActivity = () => {
     });
 };
 
-const filterDocs = (filter) => {
-  FauxtonAPI.dispatch({
+export const filterDocs = (filter) => {
+  return {
     type: ActionTypes.REPLICATION_FILTER_DOCS,
     options: filter
-  });
+  };
 };
 
-const filterReplicate = (filter) => {
-  FauxtonAPI.dispatch({
+export const filterReplicate = (filter) => {
+  return {
     type: ActionTypes.REPLICATION_FILTER_REPLICATE,
     options: filter
-  });
+  };
 };
 
-const selectAllDocs = () => {
-  FauxtonAPI.dispatch({
+export const selectAllDocs = () => {
+  return {
     type: ActionTypes.REPLICATION_TOGGLE_ALL_DOCS
-  });
+  };
 };
 
-const selectDoc = (id) => {
-  FauxtonAPI.dispatch({
+export const selectDoc = (id) => {
+  return {
     type: ActionTypes.REPLICATION_TOGGLE_DOC,
     options: id
-  });
+  };
 };
 
-const selectAllReplicates = () => {
-  FauxtonAPI.dispatch({
+export const selectAllReplicates = () => {
+  return {
     type: ActionTypes.REPLICATION_TOGGLE_ALL_REPLICATE
-  });
+  };
 };
 
-const selectReplicate = (id) => {
-  FauxtonAPI.dispatch({
+export const selectReplicate = (id) => {
+  return {
     type: ActionTypes.REPLICATION_TOGGLE_REPLICATE,
     options: id
-  });
+  };
 };
 
-const clearSelectedDocs = () => {
-  FauxtonAPI.dispatch({
+export const clearSelectedDocs = () => {
+  return {
     type: ActionTypes.REPLICATION_CLEAR_SELECTED_DOCS
-  });
+  };
 };
 
-const clearSelectedReplicates = () => {
-  FauxtonAPI.dispatch({
+export const clearSelectedReplicates = () => {
+  return {
     type: ActionTypes.REPLICATION_CLEAR_SELECTED_REPLICATES
-  });
+  };
 };
 
-export const deleteDocs = (docs) => {
+export const deleteDocs = (docs) => dispatch => {
   const bulkDocs = docs.map(({raw: doc}) => {
     doc._deleted = true;
     return doc;
@@ -219,20 +212,12 @@ export const deleteDocs = (docs) => {
     clear: true
   });
 
-  fetch('/_replicator/_bulk_docs', {
-    credentials: 'include',
-    headers: {
-      'Accept': 'application/json; charset=utf-8',
-      'Content-Type': 'application/json'
-    },
-    method: 'POST',
-    body: JSON.stringify({docs: bulkDocs})
-  })
+  post('/_replicator/_bulk_docs', {docs: bulkDocs}, {raw: true})
     .then(resp => {
       if (!resp.ok) {
         throw resp;
       }
-      return resp.json();
+      return resp;
     })
     .then(() => {
 
@@ -248,8 +233,8 @@ export const deleteDocs = (docs) => {
         clear: true
       });
 
-      clearSelectedDocs();
-      getReplicationActivity();
+      dispatch(clearSelectedDocs());
+      dispatch(getReplicationActivity());
     })
     .catch(resp => {
       resp.json()
@@ -264,7 +249,7 @@ export const deleteDocs = (docs) => {
     });
 };
 
-const deleteReplicates = (replicates) => {
+export const deleteReplicates = (replicates) => dispatch => {
   FauxtonAPI.addNotification({
     msg: `Deleting _replicate${replicates.length > 1 ? 's' : ''}.`,
     type: 'success',
@@ -279,8 +264,8 @@ const deleteReplicates = (replicates) => {
         msg = `Replication <code>${replicates[0]._id}</code> has been deleted`;
       }
 
-      clearSelectedReplicates();
-      getReplicateActivity();
+      dispatch(clearSelectedReplicates());
+      dispatch(getReplicateActivity());
 
       FauxtonAPI.addNotification({
         msg: msg,
@@ -298,19 +283,12 @@ const deleteReplicates = (replicates) => {
     });
 };
 
-export const getReplicationStateFrom = (id) => {
-  FauxtonAPI.dispatch({
+export const getReplicationStateFrom = (id) => dispatch => {
+  dispatch({
     type: ActionTypes.REPLICATION_FETCHING_FORM_STATE
   });
 
-  fetch(`/_replicator/${encodeURIComponent(id)}`, {
-    credentials: 'include',
-    headers: {
-      'Accept': 'application/json; charset=utf-8',
-    },
-    method: 'GET'
-  })
-    .then(resp => resp.json())
+  get(`/_replicator/${encodeURIComponent(id)}`)
     .then((doc) => {
       const stateDoc = {
         replicationDocName: doc._id,
@@ -338,7 +316,7 @@ export const getReplicationStateFrom = (id) => {
         stateDoc.remoteTarget = decodeFullUrl(targetUrl);
       }
 
-      FauxtonAPI.dispatch({
+      dispatch({
         type: ActionTypes.REPLICATION_SET_STATE_FROM_DOC,
         options: stateDoc
       });
@@ -353,65 +331,42 @@ export const getReplicationStateFrom = (id) => {
     });
 };
 
-const showConflictModal = () => {
-  FauxtonAPI.dispatch({
+export const showConflictModal = () => {
+  return {
     type: ActionTypes.REPLICATION_SHOW_CONFLICT_MODAL
-  });
+  };
 };
 
-const hideConflictModal = () => {
-  FauxtonAPI.dispatch({
+export const hideConflictModal = () => {
+  return {
     type: ActionTypes.REPLICATION_HIDE_CONFLICT_MODAL
-  });
+  };
 };
 
-const changeActivitySort = (sort) => {
-  FauxtonAPI.dispatch({
+export const changeActivitySort = (sort) => {
+  return {
     type: ActionTypes.REPLICATION_CHANGE_ACTIVITY_SORT,
     options: sort
-  });
-};
-
-const changeTabSection = (newSection, url) => {
-  FauxtonAPI.dispatch({
-    type: ActionTypes.REPLICATION_CHANGE_TAB_SECTION,
-    options: newSection
-  });
-
-  if (url) {
-    FauxtonAPI.navigate(url, {trigger: false});
-  }
+  };
 };
 
-const checkForNewApi = () => {
+export const checkForNewApi = () => dispatch => {
   supportNewApi().then(newApi => {
-    FauxtonAPI.dispatch({
+    dispatch({
       type: ActionTypes.REPLICATION_SUPPORT_NEW_API,
       options: newApi
     });
   });
 };
 
-export default {
-  checkForNewApi,
-  initReplicator,
-  replicate,
-  updateFormField,
-  clearReplicationForm,
-  getReplicationActivity,
-  filterDocs,
-  selectAllDocs,
-  selectDoc,
-  deleteDocs,
-  getReplicationStateFrom,
-  showConflictModal,
-  hideConflictModal,
-  changeActivitySort,
-  clearSelectedDocs,
-  changeTabSection,
-  getReplicateActivity,
-  filterReplicate,
-  selectReplicate,
-  selectAllReplicates,
-  deleteReplicates
+export const showPasswordModal = () => {
+  return {
+    type: ActionTypes.REPLICATION_SHOW_PASSWORD_MODAL
+  };
+};
+
+export const hidePasswordModal = () => {
+  return {
+    type: ActionTypes.REPLICATION_HIDE_PASSWORD_MODAL
+  };
 };
diff --git a/app/addons/replication/actiontypes.js b/app/addons/replication/actiontypes.js
index 5089ea4ca..714386863 100644
--- a/app/addons/replication/actiontypes.js
+++ b/app/addons/replication/actiontypes.js
@@ -36,5 +36,7 @@ export default {
   REPLICATION_TOGGLE_ALL_REPLICATE: 'REPLICATION_TOGGLE_ALL_REPLICATE',
   REPLICATION_TOGGLE_REPLICATE: 'REPLICATION_TOGGLE_REPLICATE',
   REPLICATION_CLEAR_SELECTED_REPLICATES: 'REPLICATION_CLEAR_SELECTED_REPLICATES',
-  REPLICATION_FETCHING_FORM_STATE: 'REPLICATION_FETCHING_FORM_STATE'
+  REPLICATION_FETCHING_FORM_STATE: 'REPLICATION_FETCHING_FORM_STATE',
+  REPLICATION_HIDE_PASSWORD_MODAL: 'REPLICATION_HIDE_PASSWORD_MODAL',
+  REPLICATION_SHOW_PASSWORD_MODAL: 'REPLICATION_SHOW_PASSWORD_MODAL'
 };
diff --git a/app/addons/replication/base.js b/app/addons/replication/base.js
index 54c8f85cb..e4b966b5a 100644
--- a/app/addons/replication/base.js
+++ b/app/addons/replication/base.js
@@ -13,22 +13,23 @@
 import FauxtonAPI from '../../core/api';
 import replication from './route';
 import './assets/less/replication.less';
-import Actions from './actions';
+import { checkForNewApi } from './actions';
+import replicationReducer from './reducers';
 
 replication.initialize = function () {
   FauxtonAPI.addHeaderLink({ title: 'Replication', href: '#/replication', icon: 'fonticon-replicate' });
   FauxtonAPI.session.isAuthenticated().then(() => {
-    Actions.checkForNewApi();
+    checkForNewApi();
   });
 };
 
+FauxtonAPI.addReducers({
+  replication: replicationReducer
+});
+
 FauxtonAPI.registerUrls('replication', {
-  app: (db) => {
-    return '#/replication/_create/' + db;
-  },
-  api: () => {
-    return window.location.origin + '/_replicator';
-  }
+  app: (db) => '#/replication/_create/' + db,
+  api: () => window.location.origin + '/_replicator'
 });
 
 export default replication;
diff --git a/app/addons/replication/components/newreplication.js b/app/addons/replication/components/newreplication.js
index 1b64008e5..f1a82a0da 100644
--- a/app/addons/replication/components/newreplication.js
+++ b/app/addons/replication/components/newreplication.js
@@ -156,6 +156,7 @@ export default class NewReplicationController extends React.Component {
       }
     }
 
+    this.props.hidePasswordModal();
     this.props.replicate({
       replicationTarget,
       replicationSource,
@@ -263,6 +264,7 @@ export default class NewReplicationController extends React.Component {
           modalMessage={<p>{app.i18n.en_US['replication-password-modal-text']}</p>}
           submitBtnLabel="Start Replication"
           headerTitle={app.i18n.en_US['replication-password-modal-header']}
+          onClose={this.props.hidePasswordModal}
           onSuccess={this.submit} />
         <ConflictModal
           visible={conflictModalVisible}
diff --git a/app/addons/replication/container.js b/app/addons/replication/container.js
new file mode 100644
index 000000000..7320ae3fd
--- /dev/null
+++ b/app/addons/replication/container.js
@@ -0,0 +1,138 @@
+import { connect } from 'react-redux';
+import ReplicationController from './controller';
+
+import {
+  checkForNewApi,
+  updateFormField,
+  clearReplicationForm,
+  initReplicator,
+  getReplicationStateFrom,
+  getReplicateActivity,
+  getReplicationActivity,
+  getDatabasesList,
+  showPasswordModal,
+  hidePasswordModal,
+  showConflictModal,
+  hideConflictModal,
+  replicate,
+  filterReplicate,
+  filterDocs,
+  selectDoc,
+  deleteDocs,
+  selectAllDocs,
+  changeActivitySort,
+  deleteReplicates,
+  selectAllReplicates,
+  selectReplicate
+} from './actions';
+
+import {
+  isLoading,
+  isActivityLoading,
+  getDatabases,
+  isAuthenticated,
+  getReplicationSource,
+  getLocalSource,
+  isLocalSourceKnown,
+  getRemoteSource,
+  getReplicationTarget,
+  getLocalTarget,
+  isLocalTargetKnown,
+  getRemoteTarget,
+  isPasswordModalVisible,
+  isConflictModalVisible,
+  getReplicationType,
+  getReplicationDocName,
+  getSubmittedNoChange,
+  getFilteredReplicationStatus,
+  getStatusFilter,
+  getReplicateFilter,
+  getAllDocsSelected,
+  getSomeDocsSelected,
+  getUsername,
+  getPassword,
+  getActivitySort,
+  getCheckingApi,
+  supportNewApi,
+  isReplicateInfoLoading,
+  getAllReplicateSelected,
+  getReplicateInfo,
+  someReplicateSelected
+} from './reducers';
+
+const mapStateToProps = ({replication}, ownProps) => {
+  return {
+    routeLocalSource: ownProps.routeLocalSource,
+    replicationId: ownProps.replicationId,
+    tabSection: ownProps.section,
+    loading: isLoading(replication),
+    activityLoading: isActivityLoading(replication),
+    databases: getDatabases(replication),
+    authenticated: isAuthenticated(replication),
+
+    // source fields
+    replicationSource: getReplicationSource(replication),
+    localSource: getLocalSource(replication),
+    localSourceKnown: isLocalSourceKnown(replication),
+    remoteSource: getRemoteSource(replication),
+
+    // target fields
+    replicationTarget: getReplicationTarget(replication),
+    localTarget: getLocalTarget(replication),
+    localTargetKnown: isLocalTargetKnown(replication),
+    remoteTarget: getRemoteTarget(replication),
+
+    // other
+    passwordModalVisible: isPasswordModalVisible(replication),
+    isConflictModalVisible: isConflictModalVisible(replication),
+    replicationType: getReplicationType(replication),
+    replicationDocName: getReplicationDocName(replication),
+    submittedNoChange: getSubmittedNoChange(replication),
+    statusDocs: getFilteredReplicationStatus(replication),
+    statusFilter: getStatusFilter(replication),
+    replicateFilter: getReplicateFilter(replication),
+    allDocsSelected: getAllDocsSelected(replication),
+    someDocsSelected:  getSomeDocsSelected(replication),
+    username: getUsername(replication),
+    password: getPassword(replication),
+    activitySort: getActivitySort(replication),
+    checkingApi: getCheckingApi(replication),
+    supportNewApi: supportNewApi(replication),
+    replicateLoading: isReplicateInfoLoading(replication),
+    replicateInfo: getReplicateInfo(replication),
+    allReplicateSelected: getAllReplicateSelected(replication),
+    someReplicateSelected: someReplicateSelected(replication)
+  };
+};
+
+const mapDispatchToProps = (dispatch) => {
+  return {
+    checkForNewApi: () => dispatch(checkForNewApi()),
+    updateFormField: (fieldName) => (value) => {
+      dispatch(updateFormField(fieldName, value));
+    },
+    clearReplicationForm: () => dispatch(clearReplicationForm()),
+    initReplicator: (localSource) => dispatch(initReplicator(localSource)),
+    getReplicationActivity: () => dispatch(getReplicationActivity()),
+    getReplicateActivity: () => dispatch(getReplicateActivity()),
+    getReplicationStateFrom: (id) => dispatch(getReplicationStateFrom(id)),
+    getDatabasesList: () => dispatch(getDatabasesList()),
+    showPasswordModal: () => dispatch(showPasswordModal()),
+    hidePasswordModal: () => dispatch(hidePasswordModal()),
+    replicate: (params) => dispatch(replicate(params)),
+    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)),
+    selectAllDocs: () => dispatch(selectAllDocs()),
+    changeActivitySort: (sort) => dispatch(changeActivitySort(sort)),
+    selectAllReplicates: () => dispatch(selectAllReplicates()),
+    deleteReplicates: (replicates) => dispatch(deleteReplicates(replicates)),
+    selectReplicate: (replicate) => dispatch(selectReplicate(replicate))
+  };
+};
+
+
+export default connect(mapStateToProps, mapDispatchToProps)(ReplicationController);
diff --git a/app/addons/replication/controller.js b/app/addons/replication/controller.js
index dfefabcb1..117714a44 100644
--- a/app/addons/replication/controller.js
+++ b/app/addons/replication/controller.js
@@ -9,11 +9,9 @@
 // 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 FauxtonAPI from '../../core/api';
 import React from 'react';
-import Stores from './stores';
-import Actions from './actions';
 import Helpers from '../../helpers';
-import {showPasswordModal} from '../auth/actions';
 import Components from '../components/react-components';
 import NewReplication from './components/newreplication';
 import Activity from './components/activity';
@@ -24,87 +22,41 @@ import ReplicateActivity from './components/replicate-activity';
 
 const {LoadLines, Polling, RefreshBtn} = Components;
 
-const store = Stores.replicationStore;
-
 export default class ReplicationController extends React.Component {
-  constructor (props) {
-    super(props);
-    this.state = this.getStoreState();
-  }
-
-  getStoreState () {
-    return {
-      loading: store.isLoading(),
-      activityLoading: store.isActivityLoading(),
-      databases: store.getDatabases(),
-      authenticated: store.isAuthenticated(),
-
-      // source fields
-      replicationSource: store.getReplicationSource(),
-      localSource: store.getlocalSource(),
-      localSourceKnown: store.isLocalSourceKnown(),
-      remoteSource: store.getRemoteSource(),
-
-      // target fields
-      replicationTarget: store.getReplicationTarget(),
-      localTarget: store.getlocalTarget(),
-      localTargetKnown: store.isLocalTargetKnown(),
-      remoteTarget: store.getRemoteTarget(),
-
-      // other
-      passwordModalVisible: store.isPasswordModalVisible(),
-      showConflictModal: store.isConflictModalVisible(),
-      replicationType: store.getReplicationType(),
-      replicationDocName: store.getReplicationDocName(),
-      submittedNoChange: store.getSubmittedNoChange(),
-      statusDocs: store.getFilteredReplicationStatus(),
-      statusFilter: store.getStatusFilter(),
-      replicateFilter: store.getReplicateFilter(),
-      allDocsSelected: store.getAllDocsSelected(),
-      someDocsSelected:  store.someDocsSelected(),
-      username: store.getUsername(),
-      password: store.getPassword(),
-      activitySort: store.getActivitySort(),
-      tabSection: store.getTabSection(),
-      checkingApi: store.checkingAPI(),
-      supportNewApi: store.supportNewApi(),
-      replicateLoading: store.isReplicateInfoLoading(),
-      replicateInfo: store.getReplicateInfo(),
-      allReplicateSelected: store.getAllReplicateSelected(),
-      someReplicateSelected: store.someReplicateSelected()
-    };
-  }
 
   loadReplicationInfo (props, oldProps) {
-    Actions.initReplicator(props.localSource);
+    this.props.initReplicator(props.routeLocalSource, props.localSource);
     this.getAllActivity();
+    this.loadReplicationStateFrom(props, oldProps);
+  }
+
+  loadReplicationStateFrom (props, oldProps) {
     if (props.replicationId && props.replicationId !== oldProps.replicationId) {
-      Actions.clearReplicationForm();
-      Actions.getReplicationStateFrom(props.replicationId);
+      this.props.clearReplicationForm();
+      this.props.getReplicationStateFrom(props.replicationId);
     }
   }
 
   getAllActivity () {
-    Actions.getReplicationActivity();
-    Actions.getReplicateActivity();
+    this.props.getReplicationActivity();
+    this.props.getReplicateActivity();
   }
 
   componentDidMount () {
-    store.on('change', this.onChange, this);
+    this.props.checkForNewApi();
+    this.props.getDatabasesList();
     this.loadReplicationInfo(this.props, {});
   }
 
   componentWillReceiveProps (nextProps) {
-    this.loadReplicationInfo(nextProps, this.props);
+    this.loadReplicationStateFrom(nextProps, this.props);
+    if (this.props.tabSection !== 'new replication' && nextProps.tabSection === 'new replication') {
+      this.props.clearReplicationForm();
+    }
   }
 
   componentWillUnmount () {
-    store.off('change', this.onChange);
-    Actions.clearReplicationForm();
-  }
-
-  onChange () {
-    this.setState(this.getStoreState());
+    this.props.clearReplicationForm();
   }
 
   showSection () {
@@ -112,28 +64,25 @@ export default class ReplicationController extends React.Component {
       replicationSource, replicationTarget, replicationType, replicationDocName,
       passwordModalVisible, databases, localSource, remoteSource, remoteTarget,
       localTarget, statusDocs, statusFilter, loading, allDocsSelected,
-      someDocsSelected, showConflictModal, localSourceKnown, localTargetKnown,
+      someDocsSelected, showConflictModal, localSourceKnown, localTargetKnown, updateFormField,
       username, password, authenticated, activityLoading, submittedNoChange, activitySort, tabSection,
-      replicateInfo, replicateLoading, replicateFilter, allReplicateSelected, someReplicateSelected
-    } = this.state;
+      replicateInfo, replicateLoading, replicateFilter, allReplicateSelected, someReplicateSelected,
+      showPasswordModal, hidePasswordModal, hideConflictModal, isConflictModalVisible, filterDocs,
+      filterReplicate, replicate, clearReplicationForm, selectAllDocs, changeActivitySort, selectDoc,
+      deleteDocs, deleteReplicates, selectAllReplicates, selectReplicate
+    } = this.props;
 
     if (tabSection === 'new replication') {
       if (loading) {
         return <LoadLines/>;
       }
 
-      const updateFormField = (field) => {
-        return (value) => {
-          Actions.updateFormField(field, value);
-        };
-      };
-
       return <NewReplication
         docs={statusDocs}
         localTargetKnown={localTargetKnown}
         localSourceKnown={localSourceKnown}
-        clearReplicationForm={Actions.clearReplicationForm}
-        replicate={Actions.replicate}
+        clearReplicationForm={clearReplicationForm}
+        replicate={replicate}
         showPasswordModal={showPasswordModal}
         replicationSource={replicationSource}
         replicationTarget={replicationTarget}
@@ -146,14 +95,15 @@ export default class ReplicationController extends React.Component {
         remoteTarget={remoteTarget}
         localTarget={localTarget}
         updateFormField={updateFormField}
-        conflictModalVisible={showConflictModal}
-        hideConflictModal={Actions.hideConflictModal}
-        showConflictModal={Actions.showConflictModal}
+        conflictModalVisible={isConflictModalVisible}
+        hideConflictModal={hideConflictModal}
+        showConflictModal={showConflictModal}
         checkReplicationDocID={checkReplicationDocID}
         authenticated={authenticated}
         username={username}
         password={password}
         submittedNoChange={submittedNoChange}
+        hidePasswordModal={hidePasswordModal}
       />;
     }
 
@@ -165,14 +115,14 @@ export default class ReplicationController extends React.Component {
       return <ReplicateActivity
         docs={replicateInfo}
         filter={replicateFilter}
-        onFilterChange={Actions.filterReplicate}
-        selectDoc={Actions.selectReplicate}
-        selectAllDocs={Actions.selectAllReplicates}
+        onFilterChange={filterReplicate}
+        selectDoc={selectReplicate}
+        selectAllDocs={selectAllReplicates}
         allDocsSelected={allReplicateSelected}
         someDocsSelected={someReplicateSelected}
         activitySort={activitySort}
-        changeActivitySort={Actions.changeActivitySort}
-        deleteDocs={Actions.deleteReplicates}
+        changeActivitySort={changeActivitySort}
+        deleteDocs={deleteReplicates}
       />;
     }
 
@@ -183,19 +133,19 @@ export default class ReplicationController extends React.Component {
     return <Activity
       docs={statusDocs}
       filter={statusFilter}
-      onFilterChange={Actions.filterDocs}
-      selectAllDocs={Actions.selectAllDocs}
-      selectDoc={Actions.selectDoc}
+      onFilterChange={filterDocs}
+      selectAllDocs={selectAllDocs}
+      selectDoc={selectDoc}
       allDocsSelected={allDocsSelected}
       someDocsSelected={someDocsSelected}
-      deleteDocs={Actions.deleteDocs}
+      deleteDocs={deleteDocs}
       activitySort={activitySort}
-      changeActivitySort={Actions.changeActivitySort}
+      changeActivitySort={changeActivitySort}
     />;
   }
 
   getHeaderComponents () {
-    if (this.state.tabSection === 'new replication') {
+    if (this.props.tabSection === 'new replication') {
       return null;
     }
     let rightHeaderclass = "right-header-flex";
@@ -220,7 +170,7 @@ export default class ReplicationController extends React.Component {
   }
 
   getTabElements () {
-    const {tabSection} = this.state;
+    const {tabSection} = this.props;
     const elements = [
       <TabElement
         key={1}
@@ -230,7 +180,7 @@ export default class ReplicationController extends React.Component {
       />
     ];
 
-    if (this.state.supportNewApi) {
+    if (this.props.supportNewApi) {
       elements.push(
         <TabElement
           key={2}
@@ -245,18 +195,19 @@ export default class ReplicationController extends React.Component {
   }
 
   onTabChange (section, url) {
-    Actions.changeTabSection(section, url);
+    // this.props.changeTabSection(section, url);
+    FauxtonAPI.navigate(url);
   }
 
   getCrumbs () {
-    if (this.state.tabSection === 'new replication') {
+    if (this.props.tabSection === 'new replication') {
       return [{'name': 'Job Configuration'}];
     }
     return [{'name': 'Replication'}];
   }
 
   getTabs () {
-    if (this.state.tabSection === 'new replication') {
+    if (this.props.tabSection === 'new replication') {
       return null;
     }
 
@@ -268,7 +219,7 @@ export default class ReplicationController extends React.Component {
   }
 
   render () {
-    const { checkingAPI } = this.state;
+    const { checkingAPI } = this.props;
 
     if (checkingAPI) {
       return <LoadLines />;
diff --git a/app/addons/replication/reducers.js b/app/addons/replication/reducers.js
new file mode 100644
index 000000000..545e98d05
--- /dev/null
+++ b/app/addons/replication/reducers.js
@@ -0,0 +1,381 @@
+// 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';
+import Constants from './constants';
+import app from "../../app";
+
+const setActivitySort = (sort) => {
+  app.utils.localStorageSet('replication-activity-sort', sort);
+};
+
+const loadActivitySort = () => {
+  const defaultSort = {
+    descending: false,
+    column: 'statusTime'
+
+  };
+  let sort = app.utils.localStorageGet('replication-activity-sort');
+
+  if (!sort) {
+    sort = defaultSort;
+  }
+
+  setActivitySort(sort);
+  return sort;
+};
+
+const validFieldMap = {
+  remoteSource: 'remoteSource',
+  remoteTarget: 'remoteTarget',
+  localTarget: 'localTarget',
+  replicationType: 'replicationType',
+  replicationDocName: 'replicationDocName',
+  replicationSource: 'replicationSource',
+  replicationTarget: 'replicationTarget',
+  localSource: 'localSource'
+};
+
+const initialState = {
+  loading: false,
+  databases: [],
+  authenticated: false,
+
+  // source fields
+  replicationSource: '',
+  localSource: '',
+  remoteSource: '',
+
+  // target fields
+  replicationTarget: '',
+  localTarget: '',
+  remoteTarget: '',
+
+  // other
+  isPasswordModalVisible: false,
+  isConflictModalVisible: false,
+  replicationType: Constants.REPLICATION_TYPE.ONE_TIME,
+  replicationDocName: '',
+  submittedNoChange: false,
+  statusDocs: [],
+  statusFilteredStatusDocs: [],
+  statusFilter: '',
+  replicateFilter: '',
+  allDocsSelected: false,
+  allReplicateSelected: false,
+  username: '',
+  password: '',
+  activityLoading: false,
+  tabSection: 'new replication',
+  supportNewApi: false,
+  fetchingReplicateInfo: false,
+  replicateInfo: [],
+
+  checkingAPI: true,
+  activitySort: loadActivitySort()
+};
+
+const clearForm = (state) => {
+  const newState = {
+    ...state
+  };
+  Object.values(validFieldMap).forEach(field => newState[field] = '');
+  return newState;
+};
+
+const updateFormField = (state, fieldName, value) => {
+  const updateState = {
+    ...state,
+    submittedNoChange: false,
+  };
+
+  updateState[validFieldMap[fieldName]] = value;
+
+  return updateState;
+};
+
+const toggleDoc = (state, id) => {
+  const doc = state.statusDocs.find(doc => doc._id === id);
+  if (!doc) {
+    return state;
+  }
+
+  doc.selected = !doc.selected;
+
+  return {
+    ...state,
+    allDocsSelected: false
+  };
+};
+
+const selectAllDocs = (state) => {
+  const newState = {
+    ...state,
+    allDocsSelected: !state.allDocsSelected
+  };
+
+  getFilteredReplicationStatus(newState)
+    .forEach(doc => doc.selected = newState.allDocsSelected);
+
+  return newState;
+};
+
+const selectReplicate = (state, id) => {
+  const newState = {
+    ...state
+  };
+
+  const doc = newState._replicateInfo.find(doc => doc._id === id);
+
+  if (!doc) {
+    return newState;
+  }
+
+  doc.selected = !doc.selected;
+  newState._allReplicateSelected = false;
+};
+
+const selectAllReplicate = (state) => {
+  const newState = {
+    ...state,
+    allReplicateSelected: !state.allReplicateSelected
+  };
+
+  getReplicateInfo(newState).forEach(doc => doc.selected = newState.allReplicateSelected);
+  return newState;
+};
+
+const setStateFromDoc = (state, doc) => {
+  let newState = {
+    ...state,
+    loading: false
+  };
+
+  return Object.keys(doc).reduce((state, key) => {
+    return updateFormField(state, key, doc[key]);
+  }, newState);
+};
+
+
+const replication = (state = initialState, {type, options}) => {
+  switch (type) {
+
+    case ActionTypes.INIT_REPLICATION:
+      const newState = {
+        ...state,
+        loading: true
+      };
+
+      if (options.localSource) {
+        newState.localSource = options.localSource;
+        newState.replicationSource = Constants.REPLICATION_SOURCE.LOCAL;
+        newState.remoteSource = '';
+        newState.replicationTarget = '';
+        newState.localTarget = '';
+        newState.remoteTarget = '';
+      }
+      return newState;
+
+    case ActionTypes.REPLICATION_DATABASES_LOADED:
+      return {
+        ...state,
+        loading: false,
+        databases: options.databases
+      };
+
+    case ActionTypes.REPLICATION_FETCHING_FORM_STATE:
+      return {
+        ...state,
+        loading: true
+      };
+
+    case ActionTypes.REPLICATION_UPDATE_FORM_FIELD:
+      return updateFormField(state, options.fieldName, options.value);
+
+    case ActionTypes.REPLICATION_CLEAR_FORM:
+      return clearForm(state);
+
+    case ActionTypes.REPLICATION_STARTING:
+      return {
+        ...state,
+        submittedNoChange: true
+      };
+
+    case ActionTypes.REPLICATION_FETCHING_STATUS:
+      return {
+        ...state,
+        activityLoading: true
+      };
+
+    case ActionTypes.REPLICATION_STATUS:
+      return {
+        ...state,
+        activityLoading: false,
+        statusDocs: options
+      };
+
+    case ActionTypes.REPLICATION_FILTER_DOCS:
+      return {
+        ...state,
+        statusFilter: options
+      };
+
+    case ActionTypes.REPLICATION_FILTER_REPLICATE:
+      return {
+        ...state,
+        replicateFilter: options
+      };
+
+    case ActionTypes.REPLICATION_TOGGLE_DOC:
+      return toggleDoc(state, options);
+
+    case ActionTypes.REPLICATION_TOGGLE_ALL_DOCS:
+      return selectAllDocs(state);
+
+    case ActionTypes.REPLICATION_TOGGLE_REPLICATE:
+      return selectReplicate(state, options);
+
+    case ActionTypes.REPLICATION_TOGGLE_ALL_REPLICATE:
+      return selectAllReplicate(state);
+
+    case ActionTypes.REPLICATION_SET_STATE_FROM_DOC:
+      return setStateFromDoc(state, options);
+
+    case ActionTypes.REPLICATION_SHOW_CONFLICT_MODAL:
+      return {
+        ...state,
+        isConflictModalVisible: true
+      };
+
+    case ActionTypes.REPLICATION_HIDE_CONFLICT_MODAL:
+      return {
+        ...state,
+        isConflictModalVisible: false
+      };
+
+    case ActionTypes.REPLICATION_CHANGE_ACTIVITY_SORT:
+      setActivitySort(options);
+      return {
+        ...state,
+        activitySort: loadActivitySort()
+      };
+
+    case ActionTypes.REPLICATION_CLEAR_SELECTED_DOCS:
+      return {
+        ...state,
+        allDocsSelected: false
+      };
+
+    case ActionTypes.REPLICATION_CHANGE_TAB_SECTION:
+      return {
+        ...state,
+        tabSection: options
+      };
+
+    case ActionTypes.REPLICATION_SUPPORT_NEW_API:
+      return {
+        ...state,
+        checkingApi: false,
+        supportNewApi: options
+      };
+
+    case ActionTypes.REPLICATION_FETCHING_REPLICATE_STATUS:
+      return {
+        ...state,
+        fetchingReplicateInfo: true,
+      };
+
+    case ActionTypes.REPLICATION_REPLICATE_STATUS:
+      return {
+        ...state,
+        fetchingReplicateInfo: false,
+        replicateInfo: options
+      };
+
+    case ActionTypes.REPLICATION_CLEAR_SELECTED_REPLICATES:
+      return {
+        ...state,
+        allReplicateSelected: false
+      };
+
+    case ActionTypes.REPLICATION_SHOW_PASSWORD_MODAL:
+      return {
+        ...state,
+        isPasswordModalVisible: true
+      };
+
+    case ActionTypes.REPLICATION_HIDE_PASSWORD_MODAL:
+      return {
+        ...state,
+        isPasswordModalVisible: false
+      };
+
+    default:
+      return state;
+  }
+};
+
+
+export const isLoading = (state) => state.isLoading;
+export const isActivityLoading = (state) => state.activityLoading;
+export const getDatabases = (state) => state.databases;
+export const isAuthenticated = (state) => state.authenticated;
+
+export const getReplicationSource = (state) => state.replicationSource;
+export const getLocalSource = (state) => state.localSource;
+export const isLocalSourceKnown = (state) => _.includes(state.databases, state.localSource);
+export const getRemoteSource = (state) => state.remoteSource;
+
+
+export const getReplicationTarget = (state) => state.replicationTarget;
+export const getLocalTarget = (state) => state.localTarget;
+export const isLocalTargetKnown = (state) => _.includes(state.databases, state.localTarget);
+export const getRemoteTarget = (state) => state.remoteTarget;
+
+export const isPasswordModalVisible = (state) => state.isPasswordModalVisible;
+export const isConflictModalVisible = (state) => state.isConflictModalVisible;
+export const getReplicationType = (state) => state.replicationType;
+export const getReplicationDocName = (state) => state.replicationDocName;
+export const getSubmittedNoChange = (state) => state.submittedNoChange;
+
+export const getFilteredReplicationStatus = (state) => {
+  return state.statusDocs.filter(doc => {
+    return Object.values(doc).filter(item => {
+      if (!item) {return null;}
+      return item.toString().toLowerCase().match(state.statusFilter);
+    }).length > 0;
+  });
+};
+
+export const getStatusFilter = (state) => state.statusFilter;
+export const getReplicateFilter = (state) => state.replicateFilter;
+export const getAllDocsSelected = (state) => state.allDocsSelected;
+export const getSomeDocsSelected = (state) => getFilteredReplicationStatus(state).some(doc => doc.selected);
+export const getUsername = (state) => state.username;
+export const getPassword = (state) => state.password;
+export const getActivitySort = (state) => state.activitySort;
+export const getTabSection = (state) => state.tabSection;
+export const getCheckingApi = (state) => state.checkingAPI;
+export const supportNewApi = (state) => state.supportNewApi;
+export const isReplicateInfoLoading = (state) => state.fetchingReplicateInfo;
+export const getAllReplicateSelected = (state) => state.allReplicateSelected;
+export const someReplicateSelected = (state) => getReplicateInfo(state).some(doc => doc.selected);
+
+export const getReplicateInfo = (state) => {
+  return state.replicateInfo.filter(doc => {
+    return Object.values(doc).filter(item => {
+      if (!item) {return false;}
+      return item.toString().toLowerCase().match(state._replicateFilter);
+    }).length > 0;
+  });
+};
+
+export default replication;
diff --git a/app/addons/replication/route.js b/app/addons/replication/route.js
index 187c5e0d0..efcd01bf2 100644
--- a/app/addons/replication/route.js
+++ b/app/addons/replication/route.js
@@ -12,14 +12,13 @@
 
 import React from 'react';
 import FauxtonAPI from '../../core/api';
-import ReplicationController from './controller';
-import Actions from './actions';
+import ReplicationController from './container';
 
 const ReplicationRouteObject = FauxtonAPI.RouteObject.extend({
   routes: {
-    'replication/_create': 'defaultView',
-    'replication/_create/:dbname': 'defaultView',
-    'replication/id/:id': 'fromId',
+    'replication/_create': 'createView',
+    'replication/_create/:dbname': 'createView',
+    'replication/id/:id': 'createViewFromId',
     'replication': 'activityView',
     'replication/_replicate': 'replicateView'
   },
@@ -40,32 +39,32 @@ const ReplicationRouteObject = FauxtonAPI.RouteObject.extend({
     ];
   },
 
-  defaultView: function (databaseName) {
+  createView: function (databaseName) {
     const localSource = databaseName || '';
-    Actions.changeTabSection('new replication');
-    Actions.clearReplicationForm();
 
     return <ReplicationController
-      localSource={localSource}
+      routeLocalSource={localSource}
+      section={'new replication'}
     />;
   },
 
-  fromId: function (replicationId) {
-    Actions.clearReplicationForm();
-    Actions.changeTabSection('new replication');
+  createViewFromId: function (replicationId) {
     return <ReplicationController
       replicationId={replicationId}
+      section={'new replication'}
     />;
   },
 
   activityView: function () {
-    Actions.changeTabSection('activity');
-    return <ReplicationController/>;
+    return <ReplicationController
+      section={"activity"}
+    />;
   },
 
   replicateView: function () {
-    Actions.changeTabSection('_replicate');
-    return <ReplicationController/>;
+    return <ReplicationController
+      section={"_replicate"}
+    />;
   }
 });
 
diff --git a/app/addons/replication/stores.js b/app/addons/replication/stores.js
deleted file mode 100644
index 52865500d..000000000
--- a/app/addons/replication/stores.js
+++ /dev/null
@@ -1,459 +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.
-import app from "../../app";
-import FauxtonAPI from '../../core/api';
-import ActionTypes from './actiontypes';
-import Constants from './constants';
-import AccountActionTypes from '../auth/actiontypes';
-import _ from 'lodash';
-
-// I know this could be done by just adding the _ prefix to the passed field name, I just don't much like relying
-// on the var names like that...
-const validFieldMap = {
-  remoteSource: '_remoteSource',
-  remoteTarget: '_remoteTarget',
-  localTarget: '_localTarget',
-  replicationType: '_replicationType',
-  replicationDocName: '_replicationDocName',
-  replicationSource: '_replicationSource',
-  replicationTarget: '_replicationTarget',
-  localSource: '_localSource'
-};
-
-const ReplicationStore = FauxtonAPI.Store.extend({
-  initialize () {
-    this.reset();
-  },
-
-  reset () {
-    this._loading = false;
-    this._databases = [];
-    this._authenticated = false;
-    this._password = '';
-
-    // source fields
-    this._replicationSource = '';
-    this._localSource = '';
-    this._remoteSource = '';
-
-    // target fields
-    this._replicationTarget = '';
-    this._localTarget = '';
-    this._remoteTarget = '';
-
-    // other
-    this._isPasswordModalVisible = false;
-    this._isConflictModalVisible = false;
-    this._replicationType = Constants.REPLICATION_TYPE.ONE_TIME;
-    this._replicationDocName = '';
-    this._submittedNoChange = false;
-    this._statusDocs = [];
-    this._statusFilteredStatusDocs = [];
-    this._statusFilter = '';
-    this._replicateFilter = '';
-    this._allDocsSelected = false;
-    this._allReplicateSelected = false;
-    this._username = '';
-    this._password = '';
-    this._activityLoading = false;
-    this._tabSection = 'new replication';
-    this._supportNewApi = true;
-
-    this.loadActivitySort();
-
-    this._fetchingReplicateInfo = false;
-    this._replicateInfo = [];
-
-    this._checkingAPI = true;
-    this._supportNewApi = false;
-  },
-
-  supportNewApi () {
-    return this._supportNewApi;
-  },
-
-  checkingAPI () {
-    return this._checkingAPI;
-  },
-
-  getActivitySort () {
-    return this._activitySort;
-  },
-
-  loadActivitySort () {
-    const defaultSort = {
-      descending: false,
-      column: 'statusTime'
-    };
-    let sort = app.utils.localStorageGet('replication-activity-sort');
-
-    if (!sort) {
-      sort = defaultSort;
-      this.setActivitySort(sort);
-    }
-
-    this._activitySort = sort;
-  },
-
-  setActivitySort (sort) {
-    app.utils.localStorageSet('replication-activity-sort', sort);
-    this._activitySort = sort;
-  },
-
-  isReplicateInfoLoading () {
-    return this._fetchingReplicateInfo;
-  },
-
-  getReplicateInfo () {
-    return this._replicateInfo.filter(doc => {
-      return _.values(doc).filter(item => {
-        if (!item) {return false;}
-        return item.toString().toLowerCase().match(this._replicateFilter);
-      }).length > 0;
-    });
-  },
-
-  setReplicateInfo (info) {
-    this._replicateInfo = info;
-  },
-
-  setCredentials (username, password) {
-    this._username = username;
-    this._password = password;
-  },
-
-  getUsername () {
-    return this._username;
-  },
-
-  getPassword () {
-    return this._password;
-  },
-
-  getSubmittedNoChange () {
-    return this._submittedNoChange;
-  },
-
-  changeAfterSubmit () {
-    this._submittedNoChange = false;
-  },
-
-  isLoading () {
-    return this._loading;
-  },
-
-  isActivityLoading () {
-    return this._activityLoading;
-  },
-
-  isAuthenticated () {
-    return this._authenticated;
-  },
-
-  getReplicationSource () {
-    return this._replicationSource;
-  },
-
-  getlocalSource () {
-    return this._localSource;
-  },
-
-  isLocalSourceKnown () {
-    return _.includes(this._databases, this._localSource);
-  },
-
-  isLocalTargetKnown () {
-    return _.includes(this._databases, this._localTarget);
-  },
-
-  getReplicationTarget () {
-    return this._replicationTarget;
-  },
-
-  getDatabases () {
-    return this._databases;
-  },
-
-  setDatabases (databases) {
-    this._databases = databases;
-  },
-
-  getReplicationType () {
-    return this._replicationType;
-  },
-
-  getlocalTarget () {
-    return this._localTarget;
-  },
-
-  getReplicationDocName () {
-    return this._replicationDocName;
-  },
-
-  setReplicationStatus (docs) {
-    this._statusDocs = docs;
-  },
-
-  getReplicationStatus () {
-    return this._statusDocs;
-  },
-
-  getFilteredReplicationStatus () {
-    return this._statusDocs.filter(doc => {
-      return _.values(doc).filter(item => {
-        if (!item) {return null;}
-        return item.toString().toLowerCase().match(this._statusFilter);
-      }).length > 0;
-    });
-  },
-
-  selectDoc (id) {
-    const doc = this._statusDocs.find(doc => doc._id === id);
-    if (!doc) {
-      return;
-    }
-
-    doc.selected = !doc.selected;
-    this._allDocsSelected = false;
-  },
-
-  selectReplicate (id) {
-    const doc = this._replicateInfo.find(doc => doc._id === id);
-    if (!doc) {
-      return;
-    }
-
-    doc.selected = !doc.selected;
-    this._allReplicateSelected = false;
-  },
-
-  selectAllReplicate () {
-    this._allReplicateSelected = !this._allReplicateSelected;
-    this.getReplicateInfo().forEach(doc => doc.selected = this._allReplicateSelected);
-  },
-
-  someReplicateSelected () {
-    return this.getReplicateInfo().some(doc => doc.selected);
-  },
-
-  getAllReplicateSelected () {
-    return this._allReplicateSelected;
-  },
-
-  selectAllDocs () {
-    this._allDocsSelected = !this._allDocsSelected;
-    this.getFilteredReplicationStatus().forEach(doc => doc.selected = this._allDocsSelected);
-  },
-
-  someDocsSelected () {
-    return this.getFilteredReplicationStatus().some(doc => doc.selected);
-  },
-
-  getAllDocsSelected () {
-    return this._allDocsSelected;
-  },
-
-  setStatusFilter (filter) {
-    this._statusFilter = filter;
-  },
-
-  getStatusFilter () {
-    return this._statusFilter;
-  },
-
-  setReplicateFilter (filter) {
-    this._replicateFilter = filter;
-  },
-
-  getReplicateFilter () {
-    return this._replicateFilter;
-  },
-  // to cut down on boilerplate
-  updateFormField (fieldName, value) {
-    this[validFieldMap[fieldName]] = value;
-  },
-
-  clearReplicationForm () {
-    _.values(validFieldMap).forEach(fieldName => this[fieldName] = '');
-  },
-
-  getRemoteSource () {
-    return this._remoteSource;
-  },
-
-  getRemoteTarget () {
-    return this._remoteTarget;
-  },
-
-  isPasswordModalVisible () {
-    return this._isPasswordModalVisible;
-  },
-
-  isConflictModalVisible () {
-    return this._isConflictModalVisible;
-  },
-
-  setStateFromDoc (doc) {
-    Object.keys(doc).forEach(key => {
-      this.updateFormField(key, doc[key]);
-    });
-  },
-
-  getTabSection () {
-    return this._tabSection;
-  },
-
-  dispatch ({type, options}) {
-    switch (type) {
-
-      case ActionTypes.INIT_REPLICATION:
-        this._loading = true;
-        this._localSource = options.localSource;
-
-        if (this._localSource) {
-          this._replicationSource = Constants.REPLICATION_SOURCE.LOCAL;
-          this._remoteSource = '';
-          this._replicationTarget = '';
-          this._localTarget = '';
-          this._remoteTarget = '';
-        }
-        break;
-
-      case ActionTypes.REPLICATION_DATABASES_LOADED:
-        this.setDatabases(options.databases);
-        this._loading = false;
-        break;
-
-      case ActionTypes.REPLICATION_FETCHING_FORM_STATE:
-        this._loading = true;
-        break;
-
-      case ActionTypes.REPLICATION_UPDATE_FORM_FIELD:
-        this.changeAfterSubmit();
-        this.updateFormField(options.fieldName, options.value);
-        break;
-
-      case ActionTypes.REPLICATION_CLEAR_FORM:
-        this.clearReplicationForm();
-        break;
-
-      case ActionTypes.REPLICATION_STARTING:
-        this._submittedNoChange = true;
-        break;
-
-      case ActionTypes.REPLICATION_FETCHING_STATUS:
-        this._activityLoading = true;
-        break;
-
-      case ActionTypes.REPLICATION_STATUS:
-        this._activityLoading = false;
-        this.setReplicationStatus(options);
-        break;
-
-      case ActionTypes.REPLICATION_FILTER_DOCS:
-        this.setStatusFilter(options);
-        break;
-
-      case ActionTypes.REPLICATION_FILTER_REPLICATE:
-        this.setReplicateFilter(options);
-        break;
-
-      case ActionTypes.REPLICATION_TOGGLE_DOC:
-        this.selectDoc(options);
-        break;
-
-      case ActionTypes.REPLICATION_TOGGLE_ALL_DOCS:
-        this.selectAllDocs();
-        break;
-
-      case ActionTypes.REPLICATION_TOGGLE_REPLICATE:
-        this.selectReplicate(options);
-        break;
-
-      case ActionTypes.REPLICATION_TOGGLE_ALL_REPLICATE:
-        this.selectAllReplicate();
-        break;
-
-      case ActionTypes.REPLICATION_SET_STATE_FROM_DOC:
-        this._loading = false;
-        this.setStateFromDoc(options);
-        break;
-
-      case ActionTypes.REPLICATION_SHOW_CONFLICT_MODAL:
-        this._isConflictModalVisible = true;
-        break;
-
-      case ActionTypes.REPLICATION_HIDE_CONFLICT_MODAL:
-        this._isConflictModalVisible = false;
-        break;
-
-      case ActionTypes.REPLICATION_CHANGE_ACTIVITY_SORT:
-        this.setActivitySort(options);
-        break;
-
-      case ActionTypes.REPLICATION_CLEAR_SELECTED_DOCS:
-        this._allDocsSelected = false;
-        break;
-
-      case ActionTypes.REPLICATION_CHANGE_TAB_SECTION:
-        this._tabSection = options;
-        break;
-
-      case ActionTypes.REPLICATION_SUPPORT_NEW_API:
-        this._checkingAPI = false;
-        this._supportNewApi = options;
-        break;
-
-      case ActionTypes.REPLICATION_FETCHING_REPLICATE_STATUS:
-        this._fetchingReplicateInfo = true;
-        break;
-
-      case ActionTypes.REPLICATION_REPLICATE_STATUS:
-        this._fetchingReplicateInfo = false;
-        this.setReplicateInfo(options);
-        break;
-
-      case ActionTypes.REPLICATION_CLEAR_SELECTED_REPLICATES:
-        this._allReplicateSelected = false;
-        break;
-
-      case AccountActionTypes.AUTH_SHOW_PASSWORD_MODAL:
-        this._isPasswordModalVisible = true;
-        break;
-
-      case AccountActionTypes.AUTH_HIDE_PASSWORD_MODAL:
-        this._isPasswordModalVisible = false;
-        break;
-
-      case AccountActionTypes.AUTH_CREDS_VALID:
-        this._authenticated = true;
-        this.setCredentials(options.username, options.password);
-        break;
-
-      case AccountActionTypes.AUTH_CREDS_INVALID:
-        this._authenticated = false;
-        break;
-
-      default:
-        return;
-    }
-
-    this.triggerChange();
-  }
-});
-
-const replicationStore = new ReplicationStore();
-replicationStore.dispatchToken = FauxtonAPI.dispatcher.register(replicationStore.dispatch);
-
-export default {
-  replicationStore
-};


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services