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

wohali pushed a commit to branch 874-update-setup-wizard
in repository https://gitbox.apache.org/repos/asf/couchdb-fauxton.git

commit bec315494c0777f2136f2c337755e7d1fd95d08b
Author: Joan Touzet <jo...@atypical.net>
AuthorDate: Mon Jul 17 02:23:47 2017 -0400

    Update for changes to _cluster_setup endpoint
    
    These changes add support for the new enable_single_node action,
    which tolerates binding a node to 127.0.0.1.
    
    They also add support for the new mandatory node_count parameter
    when setting up a cluster. This parameter in the API call actually
    sets [cluster] n value, so it is set to min(3, <value provided>)
    based on recommendations from @rnewson and personal experience.
    
    Closes #874
---
 app/addons/setup/resources.js         | 11 +++++-
 app/addons/setup/route.js             |  1 +
 app/addons/setup/setup.actions.js     | 31 ++++++++++++---
 app/addons/setup/setup.actiontypes.js |  1 +
 app/addons/setup/setup.js             | 71 +++++++++++++++++++++++++++++++++--
 app/addons/setup/setup.stores.js      | 14 ++++++-
 app/addons/setup/tests/setupSpec.js   | 22 +++++++++++
 7 files changed, 140 insertions(+), 11 deletions(-)

diff --git a/app/addons/setup/resources.js b/app/addons/setup/resources.js
index 1963f04..609ca73 100644
--- a/app/addons/setup/resources.js
+++ b/app/addons/setup/resources.js
@@ -37,13 +37,22 @@ Setup.Model = Backbone.Model.extend({
       return 'Admin password is required';
     }
 
-    if (attrs.bind_address && attrs.bind_address === '127.0.0.1') {
+    if (attrs.bind_address && attrs.bind_address === '127.0.0.1' &&
+        !attrs.singlenode) {
       return 'Bind address can not be 127.0.0.1';
     }
 
     if (attrs.port && _.isNaN(+attrs.port)) {
       return 'Bind port must be a number';
     }
+
+    if (attrs.nodeCount && _.isNaN(+attrs.nodeCount)) {
+      return 'Node count must be a number';
+    }
+
+    if (attrs.nodeCount && attrs.nodeCount < 1) {
+      return 'Node count must be >= 1';
+    }
   }
 
 });
diff --git a/app/addons/setup/route.js b/app/addons/setup/route.js
index e2b487e..b8845bb 100644
--- a/app/addons/setup/route.js
+++ b/app/addons/setup/route.js
@@ -72,6 +72,7 @@ var RouteObject = FauxtonAPI.RouteObject.extend({
 
   finishView: function () {
     const setup = new Setup.Model();
+    SetupActions.getClusterStateFromCouch();
     return <OnePaneSimpleLayout
       component={<SetupComponents.ClusterConfiguredScreen/>}
       endpoint={setup.url('apiurl')}
diff --git a/app/addons/setup/setup.actions.js 
b/app/addons/setup/setup.actions.js
index 79d9ef9..45213aa 100644
--- a/app/addons/setup/setup.actions.js
+++ b/app/addons/setup/setup.actions.js
@@ -66,11 +66,12 @@ export default {
     var password = setupStore.getPassword();
 
     var setupModel = new SetupResources.Model({
-      action: 'enable_cluster',
+      action: 'enable_single_node',
       username: username,
       password: password,
       bind_address: setupStore.getBindAdressForSetupNode(),
-      port: setupStore.getPortForSetupNode()
+      port: setupStore.getPortForSetupNode(),
+      singlenode: true
     });
 
     setupModel.on('invalid', function (model, error) {
@@ -87,7 +88,13 @@ export default {
         return FauxtonAPI.session.login(username, password);
       })
       .then(function () {
-        return this.finishClusterSetup('CouchDB is set up!');
+      FauxtonAPI.addNotification({
+        msg: 'Single node setup successful.',
+        type: 'success',
+        fade: false,
+        clear: true
+      });
+      FauxtonAPI.navigate('#setup/finish');
       }.bind(this));
   },
 
@@ -96,6 +103,7 @@ export default {
     var password = setupStore.getPassword();
     var portForSetupNode = setupStore.getPortForSetupNode();
     var bindAddressForSetupNode = setupStore.getBindAdressForSetupNode();
+    var nodeCountForSetupNode = setupStore.getNodeCountForSetupNode();
 
     var bindAddressForAdditionalNode = 
setupStore.getAdditionalNode().bindAddress;
     var remoteAddressForAdditionalNode = 
setupStore.getAdditionalNode().remoteAddress;
@@ -107,7 +115,9 @@ export default {
       username: username,
       password: password,
       bind_address: bindAddressForSetupNode,
-      port: portForSetupNode
+      port: portForSetupNode,
+      node_count: nodeCountForSetupNode,
+      singlenode: false
     });
 
     setupNode.on('invalid', function (model, error) {
@@ -125,6 +135,7 @@ export default {
       password: password,
       bind_address: bindAddressForAdditionalNode,
       port: portForForAdditionalNode,
+      node_count: nodeCountForSetupNode,
       remote_node: remoteAddressForAdditionalNode,
       remote_current_user: username,
       remote_current_password: password
@@ -159,7 +170,8 @@ export default {
         username: username,
         password: password,
         host: remoteAddressForAdditionalNode,
-        port: portForForAdditionalNode
+        port: portForForAdditionalNode,
+        singlenode: false
       });
 
       additionalNode
@@ -263,5 +275,14 @@ export default {
         value: value
       }
     });
+  },
+
+  setNodeCount: function (value) {
+    FauxtonAPI.dispatch({
+      type: ActionTypes.SETUP_NODE_COUNT,
+      options: {
+        value: value
+      }
+    });
   }
 };
diff --git a/app/addons/setup/setup.actiontypes.js 
b/app/addons/setup/setup.actiontypes.js
index a7ef0eb..0353cc2 100644
--- a/app/addons/setup/setup.actiontypes.js
+++ b/app/addons/setup/setup.actiontypes.js
@@ -21,4 +21,5 @@ export default {
   SETUP_REMOTE_ADDRESS_ADDITIONAL_NODE: 'SETUP_REMOTE_ADDRESS_ADDITIONAL_NODE',
   SETUP_RESET_ADDITIONAL_NODE: 'SETUP_RESET_ADDITIONAL_NODE',
   SETUP_ADD_NODE_TO_LIST: 'SETUP_ADD_NODE_TO_LIST',
+  SETUP_NODE_COUNT: 'SETUP_NODE_COUNT',
 };
diff --git a/app/addons/setup/setup.js b/app/addons/setup/setup.js
index 7c4a7b2..5f7b790 100644
--- a/app/addons/setup/setup.js
+++ b/app/addons/setup/setup.js
@@ -22,11 +22,41 @@ var ConfirmButton = ReactComponents.ConfirmButton;
 
 
 var ClusterConfiguredScreen = React.createClass({
+  getInitialState: function () {
+    return this.getStoreState();
+  },
+
+  getStoreState: function () {
+    return {
+      clusterState: setupStore.getClusterState()
+    };
+  },
+
+  componentDidMount: function () {
+    setupStore.on('change', this.onChange, this);
+  },
+
+  componentWillUnmount: function () {
+    setupStore.off('change', this.onChange);
+  },
+
+  onChange: function () {
+    this.setState(this.getStoreState());
+  },
 
   render: function () {
+    var nodetype;
+
+    if (this.state.clusterState === 'cluster_finished') {
+      nodetype = 'clustered';
+    } else if (this.state.clusterState === 'single_node_enabled') {
+      nodetype = 'single';
+    } else {
+      nodetype = 'unknown state';
+    }
     return (
       <div className="setup-screen">
-        {app.i18n.en_US['couchdb-productname']} is configured for production 
usage!
+        {app.i18n.en_US['couchdb-productname']} is configured for production 
usage as a {nodetype} node!
         <br />
         <br/>
         Do you want to <a href="#replication">replicate data</a>?
@@ -66,6 +96,32 @@ var SetupCurrentAdminPassword = React.createClass({
 
 });
 
+var SetupNodeCountSetting = React.createClass({
+  getInitialState: function () {
+    return {
+      nodeCountValue: this.props.nodeCountValue
+    };
+  },
+
+  handleNodeCountChange: function (event) {
+    this.props.onAlterNodeCount(event);
+    this.setState({nodeCountValue: event.target.value});
+  },
+
+  render: function () {
+    return (
+      <div className="setup-node-count">
+        <p>Number of nodes to be added to the cluster (including this one)</p>
+        <input
+          className="setup-input-nodecount"
+          value={this.state.nodeCountValue}
+          onChange={this.handleNodeCountChange}
+          placeholder="Value of cluster n"
+          type="text" />
+      </div>
+    );
+  }
+});
 
 var SetupOptionalSettings = React.createClass({
   getInitialState: function () {
@@ -179,6 +235,10 @@ var SetupMultipleNodesController = React.createClass({
     SetupActions.setPortForSetupNode(e.target.value);
   },
 
+  alterNodeCount: function (e) {
+    SetupActions.setNodeCount(e.target.value);
+  },
+
   finishClusterSetup: function () {
     SetupActions.finishClusterSetup('CouchDB Cluster set up!');
   },
@@ -197,6 +257,8 @@ var SetupMultipleNodesController = React.createClass({
           <SetupOptionalSettings
             onAlterPort={this.alterPortSetupNode}
             onAlterBindAddress={this.alterBindAddressSetupNode} />
+          <SetupNodeCountSetting
+            onAlterNodeCount={this.alterNodeCount} />
           </div>
         <hr/>
         <div className="setup-add-nodes-section">
@@ -323,7 +385,8 @@ var SetupFirstStepController = React.createClass({
   },
 
   render: function () {
-    if (this.state.clusterState === 'cluster_finished') {
+    if (this.state.clusterState === 'cluster_finished' ||
+        this.state.clusterState === 'single_node_enabled') {
       return (<ClusterConfiguredScreen />);
     }
 
@@ -340,12 +403,12 @@ var SetupFirstStepController = React.createClass({
           <ConfirmButton
             onClick={this.redirectToMultiNodeSetup}
             showIcon={false}
-            text="Configure    a Cluster" />
+            text="Configure a Cluster" />
           <ConfirmButton
             onClick={this.redirectToSingleNodeSetup}
             showIcon={false}
             id="setup-btn-no-thanks"
-            text="Configure    a Single Node" />
+            text="Configure a Single Node" />
         </div>
       </div>
     );
diff --git a/app/addons/setup/setup.stores.js b/app/addons/setup/setup.stores.js
index b033ca8..1ba83f7 100644
--- a/app/addons/setup/setup.stores.js
+++ b/app/addons/setup/setup.stores.js
@@ -27,7 +27,8 @@ var SetupStore = FauxtonAPI.Store.extend({
 
     this._setupNode = {
       bindAddress: '0.0.0.0',
-      port: 5984
+      port: 5984,
+      nodeCount: 3
     };
 
     this.resetAddtionalNode();
@@ -91,6 +92,14 @@ var SetupStore = FauxtonAPI.Store.extend({
     return this._setupNode.bindAddress;
   },
 
+  setNodeCountForSetupNode: function (options) {
+    this._setupNode.nodeCount = Math.min(options.value, 3);
+  },
+
+  getNodeCountForSetupNode: function () {
+    return this._setupNode.nodeCount;
+  },
+
   setBindAdressForAdditionalNode: function (options) {
     this._additionalNode.bindAddress = options.value;
   },
@@ -159,6 +168,9 @@ var SetupStore = FauxtonAPI.Store.extend({
         this.resetAddtionalNode();
       break;
 
+      case ActionTypes.SETUP_NODE_COUNT:
+        this.setNodeCountForSetupNode(action.options);
+      break;
 
       default:
       return;
diff --git a/app/addons/setup/tests/setupSpec.js 
b/app/addons/setup/tests/setupSpec.js
index 0e0b2d1..27372bc 100644
--- a/app/addons/setup/tests/setupSpec.js
+++ b/app/addons/setup/tests/setupSpec.js
@@ -66,4 +66,26 @@ describe('Setup: verify input', function () {
     assert.ok(error);
   });
 
+  it('Node count must be a number', function () {
+    var error = model.validate({
+      admin: {
+        user: 'rocko',
+        password: 'ente'
+      },
+      nodeCount: 'abc'
+    });
+    assert.ok(error);
+  });
+
+  it('Node count must be >= 1', function () {
+    var error = model.validate({
+      admin: {
+        user: 'rocko',
+        password: 'ente'
+      },
+      nodeCount: 0
+    });
+    assert.ok(error);
+  });
+
 });

-- 
To stop receiving notification emails like this one, please contact
"commits@couchdb.apache.org" <commits@couchdb.apache.org>.

Reply via email to