This is an automated email from the ASF dual-hosted git repository.

garren pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/couchdb-fauxton.git


The following commit(s) were added to refs/heads/master by this push:
     new 2f8de33  Update documents/designdocinfo to use redux (#1135)
2f8de33 is described below

commit 2f8de334c4251dc24985f21f86201dab914811ba
Author: Antonio Maranhao <[email protected]>
AuthorDate: Wed Oct 10 05:34:29 2018 -0400

    Update documents/designdocinfo to use redux (#1135)
    
    * Split components into separate files
    
    * Use redux
    
    * Updated tests
---
 .../__tests__/designdocinfo-action.test.js         | 18 ++---
 app/addons/documents/base.js                       |  4 +-
 app/addons/documents/designdocinfo/actions.js      | 69 ++++++++++--------
 .../{components.js => components/DesignDocInfo.js} | 69 +++++++++---------
 .../components/DesignDocInfoContainer.js           | 31 ++++++++
 app/addons/documents/designdocinfo/reducers.js     | 47 +++++++++++++
 app/addons/documents/designdocinfo/stores.js       | 82 ----------------------
 app/addons/documents/layouts.js                    | 36 ++++++----
 app/addons/documents/routes-documents.js           |  8 +--
 9 files changed, 188 insertions(+), 176 deletions(-)

diff --git a/app/addons/documents/__tests__/designdocinfo-action.test.js 
b/app/addons/documents/__tests__/designdocinfo-action.test.js
index cb64564..f94df9f 100644
--- a/app/addons/documents/__tests__/designdocinfo-action.test.js
+++ b/app/addons/documents/__tests__/designdocinfo-action.test.js
@@ -10,10 +10,11 @@
 // License for the specific language governing permissions and limitations 
under
 // the License.
 
-import FauxtonAPI from "../../../core/api";
-import Actions from "../designdocinfo/actions";
-import testUtils from "../../../../test/mocha/testUtils";
-import sinon from "sinon";
+import sinon from 'sinon';
+import FauxtonAPI from '../../../core/api';
+import testUtils from '../../../../test/mocha/testUtils';
+import Actions from '../designdocinfo/actions';
+
 const {assert, restore} = testUtils;
 
 describe('DesignDocInfo Actions', () => {
@@ -21,10 +22,10 @@ describe('DesignDocInfo Actions', () => {
   describe('fetchDesignDocInfo', () => {
 
     afterEach(() => {
-      restore(Actions.monitorDesignDoc);
+      restore(window.setInterval);
     });
 
-    it('calls monitorDesignDoc on successful fetch', () => {
+    it('schedules regular updates on successful fetch', () => {
       const promise = FauxtonAPI.Deferred();
       promise.resolve();
       const fakeDesignDocInfo = {
@@ -33,12 +34,13 @@ describe('DesignDocInfo Actions', () => {
         }
       };
 
-      const spy = sinon.spy(Actions, 'monitorDesignDoc');
+      const spy = sinon.spy(window, 'setInterval');
+      const dispatch = sinon.stub();
 
       return Actions.fetchDesignDocInfo({
         ddocName: 'test-designdoc-info',
         designDocInfo: fakeDesignDocInfo
-      }).then(() => {
+      })(dispatch).then(() => {
         assert.ok(spy.calledOnce);
       });
     });
diff --git a/app/addons/documents/base.js b/app/addons/documents/base.js
index 6809d5f..090a450 100644
--- a/app/addons/documents/base.js
+++ b/app/addons/documents/base.js
@@ -14,6 +14,7 @@ import app from "../../app";
 import Helpers from "../../helpers";
 import FauxtonAPI from "../../core/api";
 import Documents from "./routes";
+import designDocInfoReducers from "./designdocinfo/reducers";
 import reducers from "./index-results/reducers";
 import mangoReducers from "./mango/mango.reducers";
 import sidebarReducers from "./sidebar/reducers";
@@ -26,7 +27,8 @@ FauxtonAPI.addReducers({
   mangoQuery: mangoReducers,
   sidebar: sidebarReducers,
   revisionBrowser: revisionBrowserReducers,
-  partitionKey: partitionKeyReducers
+  partitionKey: partitionKeyReducers,
+  designDocInfo: designDocInfoReducers
 });
 
 function getQueryParam (query) {
diff --git a/app/addons/documents/designdocinfo/actions.js 
b/app/addons/documents/designdocinfo/actions.js
index dc3920c..79004e6 100644
--- a/app/addons/documents/designdocinfo/actions.js
+++ b/app/addons/documents/designdocinfo/actions.js
@@ -10,42 +10,51 @@
 // License for the specific language governing permissions and limitations 
under
 // the License.
 
-import FauxtonAPI from "../../../core/api";
 import ActionTypes from "./actiontypes";
-import Stores from "./stores";
-var store = Stores.designDocInfoStore;
 
-export default {
-  fetchDesignDocInfo ({ddocName, designDocInfo}) {
-    FauxtonAPI.dispatch({
-      type: ActionTypes.DESIGN_FETCHING
-    });
+const fetchDesignDocInfo = ({designDocName, designDocInfo}) => (dispatch) => {
+  dispatch({
+    type: ActionTypes.DESIGN_FETCHING
+  });
 
-    return designDocInfo.fetch().then(() => {
-      this.monitorDesignDoc({
-        ddocName,
-        designDocInfo
-      });
-    });
-  },
+  return designDocInfo.fetch().then(() => {
+    monitorDesignDoc({
+      designDocName,
+      designDocInfo
+    }, dispatch);
+  });
+};
 
-  monitorDesignDoc (options) {
-    options.intervalId = window.setInterval(_.bind(this.refresh, this), 5000);
-    FauxtonAPI.dispatch({
-      type: ActionTypes.DESIGN_DOC_MONITOR,
-      options: options
-    });
-  },
+let intervalId;
+const monitorDesignDoc = (options, dispatch) => {
+  const refreshDDoc = () => {
+    refresh(options.designDocInfo, dispatch);
+  };
+  stopRefresh();
+  intervalId = window.setInterval(refreshDDoc, 5000);
+  dispatch({
+    type: ActionTypes.DESIGN_DOC_MONITOR,
+    options: options
+  });
+};
 
-  refresh () {
-    store.getDesignDocInfo().fetch().then(() => {
-      FauxtonAPI.dispatch({
-        type: ActionTypes.DESIGN_REFRESH
-      });
+const refresh = (designDocInfo, dispatch) => {
+  designDocInfo.fetch().then(() => {
+    dispatch({
+      type: ActionTypes.DESIGN_REFRESH,
+      designDocInfo
     });
-  },
+  });
+};
 
-  stopRefresh () {
-    window.clearInterval(store.getIntervalId());
+const stopRefresh = () => {
+  if (intervalId) {
+    window.clearInterval(intervalId);
+    intervalId = undefined;
   }
 };
+
+export default {
+  fetchDesignDocInfo,
+  stopRefresh
+};
diff --git a/app/addons/documents/designdocinfo/components.js 
b/app/addons/documents/designdocinfo/components/DesignDocInfo.js
similarity index 69%
rename from app/addons/documents/designdocinfo/components.js
rename to app/addons/documents/designdocinfo/components/DesignDocInfo.js
index 726bc93..70d6050 100644
--- a/app/addons/documents/designdocinfo/components.js
+++ b/app/addons/documents/designdocinfo/components/DesignDocInfo.js
@@ -10,38 +10,38 @@
 // 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 ReactComponents from "../../components/react-components";
-var designDocInfoStore = Stores.designDocInfoStore;
-var LoadLines = ReactComponents.LoadLines;
-var Copy = ReactComponents.Copy;
+import PropTypes from 'prop-types';
+import React from 'react';
 import uuid from 'uuid';
+import FauxtonAPI from '../../../../core/api';
+import ReactComponents from '../../../components/react-components';
 
+const LoadLines = ReactComponents.LoadLines;
+const Copy = ReactComponents.Copy;
 
-class DesignDocInfo extends React.Component {
-  getStoreState = () => {
-    return {
-      viewIndex: designDocInfoStore.getViewIndex(),
-      isLoading: designDocInfoStore.isLoading(),
-      ddocName: designDocInfoStore.getDdocName()
-    };
-  };
+export default class DesignDocInfo extends React.Component {
+
+  constructor(props) {
+    super(props);
+    this.fetchDDocInfo();
+  }
 
-  componentDidMount() {
-    designDocInfoStore.on('change', this.onChange, this);
+  componentDidUpdate(prevProps) {
+    if (this.props.designDocInfo !== prevProps.designDocInfo) {
+      this.fetchDDocInfo();
+    }
   }
 
   componentWillUnmount() {
-    designDocInfoStore.off('change', this.onChange);
-    Actions.stopRefresh();
+    this.props.stopRefresh();
   }
 
-  onChange = () => {
-    this.setState(this.getStoreState());
-  };
+  fetchDDocInfo() {
+    this.props.fetchDesignDocInfo({
+      designDocName: this.props.designDocName,
+      designDocInfo: this.props.designDocInfo
+    });
+  }
 
   showCopiedMessage = () => {
     FauxtonAPI.addNotification({
@@ -51,22 +51,18 @@ class DesignDocInfo extends React.Component {
     });
   };
 
-  state = this.getStoreState();
-
   render() {
-    var viewIndex = this.state.viewIndex;
-
-    if (this.state.isLoading) {
+    if (this.props.isLoading) {
       return <LoadLines />;
     }
-
-    var actualSize = (viewIndex.data_size) ? 
viewIndex.data_size.toLocaleString('en') : 0;
-    var dataSize = (viewIndex.disk_size) ? 
viewIndex.disk_size.toLocaleString('en') : 0;
+    const viewIndex = this.props.viewIndex;
+    const actualSize = (viewIndex.data_size) ? 
viewIndex.data_size.toLocaleString('en') : 0;
+    const dataSize = (viewIndex.disk_size) ? 
viewIndex.disk_size.toLocaleString('en') : 0;
 
     return (
       <div className="metadata-page">
         <header>
-          <h2>_design/{this.state.ddocName} Metadata</h2>
+          <h2>_design/{this.props.designDocName} Metadata</h2>
         </header>
 
         <section className="container">
@@ -131,7 +127,10 @@ class DesignDocInfo extends React.Component {
   }
 }
 
-
-export default {
-  DesignDocInfo: DesignDocInfo
+DesignDocInfo.propTypes = {
+  isLoading: PropTypes.bool.isRequired,
+  viewIndex: PropTypes.object,
+  designDocName: PropTypes.string.isRequired,
+  stopRefresh: PropTypes.func.isRequired,
+  fetchDesignDocInfo: PropTypes.func.isRequired
 };
diff --git 
a/app/addons/documents/designdocinfo/components/DesignDocInfoContainer.js 
b/app/addons/documents/designdocinfo/components/DesignDocInfoContainer.js
new file mode 100644
index 0000000..2984b86
--- /dev/null
+++ b/app/addons/documents/designdocinfo/components/DesignDocInfoContainer.js
@@ -0,0 +1,31 @@
+import { connect } from 'react-redux';
+import DesignDocInfo from './DesignDocInfo';
+import Actions from '../actions';
+
+const mapStateToProps = ({ designDocInfo }, ownProps) => {
+  return {
+    isLoading: designDocInfo.isLoading,
+    viewIndex: designDocInfo.viewIndex,
+    designDocInfo: ownProps.designDocInfo,
+    designDocName: ownProps.designDocName
+  };
+};
+
+const mapDispatchToProps = (dispatch) => {
+  return {
+    fetchDesignDocInfo: (options) => {
+      dispatch(Actions.fetchDesignDocInfo(options));
+    },
+
+    stopRefresh: () => {
+      Actions.stopRefresh();
+    }
+  };
+};
+
+const DesignDocInfoContainer = connect(
+  mapStateToProps,
+  mapDispatchToProps
+)(DesignDocInfo);
+
+export default DesignDocInfoContainer;
diff --git a/app/addons/documents/designdocinfo/reducers.js 
b/app/addons/documents/designdocinfo/reducers.js
new file mode 100644
index 0000000..9b62b91
--- /dev/null
+++ b/app/addons/documents/designdocinfo/reducers.js
@@ -0,0 +1,47 @@
+// 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 = {
+  isLoading: true,
+  viewIndex: undefined
+};
+
+export default function designDocInfo (state = initialState, action) {
+  const { options } = action;
+
+  switch (action.type) {
+
+    case ActionTypes.DESIGN_FETCHING:
+      return {
+        ...state,
+        isLoading: true
+      };
+
+    case ActionTypes.DESIGN_DOC_MONITOR:
+      return {
+        ...state,
+        isLoading: false,
+        viewIndex: options.designDocInfo.get('view_index')
+      };
+
+    case ActionTypes.DESIGN_DOC_REFRESH:
+      return {
+        ...state,
+        viewIndex: options.designDocInfo.get('view_index')
+      };
+
+    default:
+      return state;
+  }
+}
diff --git a/app/addons/documents/designdocinfo/stores.js 
b/app/addons/documents/designdocinfo/stores.js
deleted file mode 100644
index d07f11d..0000000
--- a/app/addons/documents/designdocinfo/stores.js
+++ /dev/null
@@ -1,82 +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 FauxtonAPI from "../../../core/api";
-import ActionTypes from "./actiontypes";
-var Stores = {};
-
-Stores.DesignDocInfoStore = FauxtonAPI.Store.extend({
-
-  initialize: function () {
-    this._isLoading = true;
-  },
-
-  isLoading: function () {
-    return this._isLoading;
-  },
-
-  getDdocName: function () {
-    return this._ddocName;
-  },
-
-  getDesignDocInfo: function () {
-    return this._designDocInfo;
-  },
-
-  monitorDesignDoc: function (options) {
-    this._isLoading = false;
-    this._designDocInfo = options.designDocInfo;
-    this._ddocName = options.ddocName;
-    this._intervalId = options.intervalId;
-  },
-
-  getIntervalId: function () {
-    return this._intervalId;
-  },
-
-  getViewIndex: function () {
-    if (this._isLoading) {
-      return {};
-    }
-
-    return this._designDocInfo.get('view_index');
-  },
-
-  dispatch: function (action) {
-    switch (action.type) {
-      case ActionTypes.DESIGN_FETCHING:
-        this._isLoading = true;
-        this.triggerChange();
-        break;
-
-      case ActionTypes.DESIGN_DOC_MONITOR:
-        this.monitorDesignDoc(action.options);
-        this.triggerChange();
-        break;
-
-      case ActionTypes.DESIGN_DOC_REFRESH:
-        this.triggerChange();
-        break;
-
-      default:
-        return;
-      // do nothing
-    }
-  }
-
-});
-
-Stores.designDocInfoStore = new Stores.DesignDocInfoStore();
-
-Stores.designDocInfoStore.dispatchToken = 
FauxtonAPI.dispatcher.register(Stores.designDocInfoStore.dispatch.bind(Stores.designDocInfoStore));
-
-export default Stores;
diff --git a/app/addons/documents/layouts.js b/app/addons/documents/layouts.js
index bd6f680..bb11d66 100644
--- a/app/addons/documents/layouts.js
+++ b/app/addons/documents/layouts.js
@@ -18,7 +18,7 @@ import SidebarControllerContainer from 
"./sidebar/SidebarControllerContainer";
 import HeaderDocsLeft from './components/header-docs-left';
 import Changes from './changes/components';
 import IndexEditorComponents from "./index-editor/components";
-import DesignDocInfoComponents from './designdocinfo/components';
+import DesignDocInfoContainer from 
'./designdocinfo/components/DesignDocInfoContainer';
 import RightAllDocsHeader from './components/header-docs-right';
 import IndexResultsContainer from 
'./index-results/containers/IndexResultsContainer';
 import PaginationContainer from 
'./index-results/containers/PaginationContainer';
@@ -47,13 +47,16 @@ export const TabsSidebarHeader = ({
   onGlobalModeSelected,
   globalMode
 }) => {
-  const partKeySelector = (<PartitionKeySelectorContainer
-    databaseName={dbName}
-    partitionKey={partitionKey}
-    onPartitionKeySelected={onPartitionKeySelected}
-    onGlobalModeSelected={onGlobalModeSelected}
-    globalMode={globalMode}/>
-  );
+  let partKeySelector = null;
+  if (showPartitionKeySelector) {
+    partKeySelector = (<PartitionKeySelectorContainer
+      databaseName={dbName}
+      partitionKey={partitionKey}
+      onPartitionKeySelected={onPartitionKeySelected}
+      onGlobalModeSelected={onGlobalModeSelected}
+      globalMode={globalMode}/>
+    );
+  }
 
   return (
     <header className="two-panel-header">
@@ -66,7 +69,7 @@ export const TabsSidebarHeader = ({
         </div>
         <div className="right-header-wrapper flex-layout flex-row flex-body">
           <div style={{flex:1, padding: '18px 6px 12px 12px'}}>
-            {showPartitionKeySelector ? partKeySelector : null}
+            {partKeySelector}
           </div>
           <div id="right-header" className="flex-fill">
             <RightAllDocsHeader
@@ -99,9 +102,9 @@ TabsSidebarHeader.propTypes = {
   database: PropTypes.object.isRequired,
   queryDocs: PropTypes.func,
   selectedNavItem: PropTypes.object,
-  showPartitionKeySelector: PropTypes.bool,
+  showPartitionKeySelector: PropTypes.bool.isRequired,
   partitionKey: PropTypes.string,
-  onPartitionKeySelected: PropTypes.func.isRequired,
+  onPartitionKeySelected: PropTypes.func,
   onGlobalModeSelected: PropTypes.bool,
   globalMode: PropTypes.bool
 };
@@ -235,9 +238,13 @@ export const ChangesSidebarLayout = ({ docURL, database, 
endpoint, dbName, dropD
 };
 
 export const ViewsTabsSidebarLayout = ({showEditView, database, docURL, 
endpoint,
-  dbName, dropDownLinks, selectedNavItem }) => {
+  dbName, dropDownLinks, selectedNavItem, designDocInfo }) => {
 
-  const content = showEditView ? <IndexEditorComponents.EditorController /> : 
<DesignDocInfoComponents.DesignDocInfo />;
+  const content = showEditView ?
+    <IndexEditorComponents.EditorController /> :
+    <DesignDocInfoContainer
+      designDocInfo={designDocInfo}
+      designDocName={selectedNavItem.designDocName}/>;
   return (
     <div id="dashboard" className="with-sidebar">
       <TabsSidebarHeader
@@ -268,5 +275,6 @@ ViewsTabsSidebarLayout.propTypes = {
   docURL: PropTypes.string.isRequired,
   endpoint: PropTypes.string,
   dbName: PropTypes.string.isRequired,
-  dropDownLinks: PropTypes.array.isRequired
+  dropDownLinks: PropTypes.array.isRequired,
+  designDocInfo: PropTypes.object
 };
diff --git a/app/addons/documents/routes-documents.js 
b/app/addons/documents/routes-documents.js
index 41c7493..e61fab7 100644
--- a/app/addons/documents/routes-documents.js
+++ b/app/addons/documents/routes-documents.js
@@ -17,7 +17,6 @@ import ChangesActions from './changes/actions';
 import Databases from '../databases/base';
 import Resources from './resources';
 import {SidebarItemSelection} from './sidebar/helpers';
-import DesignDocInfoActions from './designdocinfo/actions';
 import ComponentsActions from '../components/actions';
 import {DocsTabsSidebarLayout, ViewsTabsSidebarLayout, ChangesSidebarLayout} 
from './layouts';
 
@@ -52,11 +51,7 @@ var DocumentsRouteObject = BaseRoute.extend({
   },
 
   designDocMetadata: function (database, ddoc) {
-    var designDocInfo = new Resources.DdocInfo({ _id: "_design/" + ddoc }, { 
database: this.database });
-    DesignDocInfoActions.fetchDesignDocInfo({
-      ddocName: ddoc,
-      designDocInfo: designDocInfo
-    });
+    const designDocInfo = new Resources.DdocInfo({ _id: "_design/" + ddoc }, { 
database: this.database });
     const selectedNavItem = new SidebarItemSelection('designDoc', {
       designDocName: ddoc,
       designDocSection: 'metadata'
@@ -71,6 +66,7 @@ var DocumentsRouteObject = BaseRoute.extend({
       dropDownLinks={dropDownLinks}
       database={this.database}
       selectedNavItem={selectedNavItem}
+      designDocInfo={designDocInfo}
     />;
   },
 

Reply via email to