You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@couchdb.apache.org by benkeen <gi...@git.apache.org> on 2016/03/16 22:07:02 UTC

[GitHub] couchdb-fauxton pull request: [WIP] Replication page update

GitHub user benkeen opened a pull request:

    https://github.com/apache/couchdb-fauxton/pull/669

    [WIP] Replication page update

    

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/benkeen/couchdb-fauxton replication-page-update

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/couchdb-fauxton/pull/669.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #669
    
----

----


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72041909
  
    --- Diff: app/addons/replication/components.react.jsx ---
    @@ -0,0 +1,527 @@
    +// 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 React from 'react';
    +import Stores from './stores';
    +import Actions from './actions';
    +import Constants from './constants';
    +import Components from '../components/react-components.react';
    +import base64 from 'base-64';
    +import AuthActions from '../auth/actions';
    +import AuthComponents from '../auth/components.react';
    +
    +const store = Stores.replicationStore;
    +const LoadLines = Components.LoadLines;
    +const TypeaheadField = Components.TypeaheadField;
    +const StyledSelect = Components.StyledSelect;
    +const ConfirmButton = Components.ConfirmButton;
    +const PasswordModal = AuthComponents.PasswordModal;
    +
    +
    +class ReplicationController extends React.Component {
    +  constructor (props) {
    +    super(props);
    +    this.state = this.getStoreState();
    +    this.submit = this.submit.bind(this);
    +    this.clear = this.clear.bind(this);
    +    this.showPasswordModal = this.showPasswordModal.bind(this);
    +  }
    +
    +  getStoreState () {
    +    return {
    +      loading: store.isLoading(),
    +      databases: store.getDatabases(),
    +      authenticated: store.isAuthenticated(),
    +      password: store.getPassword(),
    +
    +      // source fields
    +      replicationSource: store.getReplicationSource(),
    +      sourceDatabase: store.getSourceDatabase(),
    +      localSourceDatabaseKnown: store.isLocalSourceDatabaseKnown(),
    +      remoteSource: store.getRemoteSource(),
    +
    +      // target fields
    +      replicationTarget: store.getReplicationTarget(),
    +      targetDatabase: store.getTargetDatabase(),
    +      localTargetDatabaseKnown: store.isLocalTargetDatabaseKnown(),
    +      remoteTarget: store.getRemoteTarget(),
    +
    +      // other
    +      passwordModalVisible: store.isPasswordModalVisible(),
    +      replicationType: store.getReplicationType(),
    +      replicationDocName: store.getReplicationDocName()
    +    };
    +  }
    +
    +  componentDidMount () {
    +    store.on('change', this.onChange, this);
    +  }
    +
    +  componentWillUnmount () {
    +    store.off('change', this.onChange);
    +  }
    +
    +  onChange () {
    +    this.setState(this.getStoreState());
    +  }
    +
    +  // the four local replication targets all show slightly different fields
    +  getReplicationTargetRow () {
    +    const { replicationTarget, remoteTarget, databases, targetDatabase } = this.state;
    +    if (!replicationTarget) {
    +      return null;
    +    }
    +    return (
    +      <ReplicationTargetRow
    +        remoteTarget={remoteTarget}
    +        replicationTarget={replicationTarget}
    +        databases={databases}
    +        targetDatabase={targetDatabase}/>
    +    );
    +  }
    +
    +  clear (e) {
    +    e.preventDefault();
    +    Actions.clearReplicationForm();
    +  }
    +
    +  showPasswordModal () {
    +    const { replicationSource, replicationTarget } = this.state;
    +
    +    var hasLocalSourceOrTarget = (replicationSource === Constants.REPLICATION_SOURCE.LOCAL ||
    +      replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE ||
    +      replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE);
    +
    +    // if the user is authenticated, or if NEITHER the source nor target are local, just submit. The password
    +    // modal isn't necessary
    +    if (!hasLocalSourceOrTarget || this.state.authenticated) {
    +      this.submit();
    +      return;
    +    }
    +    AuthActions.showPasswordModal();
    +  }
    +
    +  getUsername () {
    +    return app.session.get('userCtx').name;
    +  }
    +
    +  getAuthHeaders () {
    +    const username = this.getUsername();
    +    return {
    +      'Authorization': 'Basic ' + base64.encode(username + ':' + this.state.password)
    +    };
    +  }
    +
    +  submit () {
    +    const { replicationSource, sourceDatabase, remoteSource, remoteTarget, replicationTarget, targetDatabase, replicationType,
    +      replicationDocName} = this.state;
    +
    +    const params = {};
    +
    +    // perform a little validating here
    +    if (!this.validate()) {
    +      return;
    +    }
    +
    +    // source
    +    if (replicationSource === Constants.REPLICATION_SOURCE.LOCAL) {
    +      params.source = {
    +        headers: this.getAuthHeaders(),
    +        url: window.location.origin + '/' + sourceDatabase
    +      };
    +    } else {
    +      params.source = remoteSource;
    +    }
    +
    +    // target
    +    if (replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE) {
    +      params.target = {
    +        headers: this.getAuthHeaders(),
    +        url: window.location.origin + '/' + targetDatabase
    +      };
    +    } else if (replicationTarget === Constants.REPLICATION_TARGET.EXISTING_REMOTE_DATABASE) {
    +      params.target = remoteTarget;
    +    } else if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE) {
    +
    +      // check to see if we really need to send headers here or can just do the ELSE clause in all scenarioe
    +      if (replicationSource === Constants.REPLICATION_SOURCE.LOCAL) {
    +        params.target = {
    +          headers: this.getAuthHeaders(),
    +          url: window.location.origin + '/' + targetDatabase
    +        };
    +      } else {
    +        const port = window.location.port === '' ? '' : ':' + window.location.port;
    +        params.target = window.location.protocol + '//' + this.getUsername() + ':' + this.state.password + '@'
    +          + window.location.hostname + port + '/' + targetDatabase;
    +      }
    +    } else if (replicationTarget === Constants.REPLICATION_TARGET.NEW_REMOTE_DATABASE) {
    +      params.target = remoteTarget;
    +    }
    +
    +    if (_.contains([Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE, Constants.REPLICATION_TARGET.NEW_REMOTE_DATABASE], replicationTarget)) {
    +      params.create_target = true;
    +    }
    +    if (replicationType === Constants.REPLICATION_TYPE.CONTINUOUS) {
    +      params.continuous = true;
    +    }
    +
    +    if (replicationDocName) {
    +      params._id = this.state.replicationDocName;
    +    }
    +
    +    // POSTing to the _replicator DB requires authentication
    +    const user = FauxtonAPI.session.user();
    +    const userName = _.isNull(user) ? '' : FauxtonAPI.session.user().name;
    +    params.user_ctx = {
    +      name: userName,
    +      roles: ['_admin', '_reader', '_writer']
    +    };
    +
    +    Actions.replicate(params);
    +  }
    +
    +  validate () {
    +    const { replicationTarget, targetDatabase, databases } = this.state;
    +
    +    if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE && _.contains(databases, targetDatabase)) {
    +      FauxtonAPI.addNotification({
    +        msg: 'The <code>' + targetDatabase + '</code> database already exists locally. Please enter another database name.',
    +        type: 'error',
    +        escape: false,
    +        clear: true
    +      });
    +      return false;
    +    }
    +    if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE ||
    +        replicationTarget === Constants.REPLICATION_TARGET.NEW_REMOTE_DATABASE) {
    +      let error = '';
    +      if (/\s/.test(targetDatabase)) {
    +        error = 'The target database may not contain any spaces.';
    +      } else if (/^_/.test(targetDatabase)) {
    +        error = 'The target database may not start with an underscore.';
    +      }
    +
    +      if (error) {
    +        FauxtonAPI.addNotification({
    +          msg: error,
    +          type: 'error',
    +          escape: false,
    +          clear: true
    +        });
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  }
    +
    +  getReplicationSourceRow () {
    +    const { replicationSource, databases, sourceDatabase, remoteSource } = this.state;
    +
    +    if (!replicationSource) {
    +      return null;
    +    }
    +
    +    if (replicationSource === Constants.REPLICATION_SOURCE.LOCAL) {
    +      return (
    +        <div className="row">
    +          <div className="span3">
    +            Source Name:
    +          </div>
    +          <div className="span7">
    +            <TypeaheadField
    +              list={databases}
    +              placeholder="Database name"
    +              onChange={(val) => Actions.updateFormField('sourceDatabase', val)}
    +              value={sourceDatabase}/>
    +          </div>
    +        </div>
    +      );
    +    }
    +
    +    return (
    +      <div>
    +        <div className="row">
    +          <div className="span3">Database URL:</div>
    +          <div className="span7">
    +            <input type="text" className="connection-url" placeholder="https://" value={remoteSource}
    +              onChange={(e) => Actions.updateFormField('remoteSource', e.target.value)}/>
    +            <div className="connection-url-example">e.g. https://$REMOTE_USERNAME:$REMOTE_PASSWORD@$REMOTE_SERVER/$DATABASE</div>
    +          </div>
    +        </div>
    +      </div>
    +    );
    +  }
    +
    +  render () {
    +    const { loading, replicationSource, replicationTarget, replicationType, replicationDocName, passwordModalVisible,
    +      localSourceDatabaseKnown, localTargetDatabaseKnown } = this.state;
    +
    +    if (loading) {
    +      return (
    +        <LoadLines />
    +      );
    +    }
    +
    +    let confirmButtonEnabled = true;
    +    if (!replicationSource || !replicationTarget) {
    +      confirmButtonEnabled = false;
    +    }
    +    if (replicationSource === Constants.REPLICATION_SOURCE.LOCAL && !localSourceDatabaseKnown) {
    +      confirmButtonEnabled = false;
    +    }
    +    if (replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE && !localTargetDatabaseKnown) {
    +      confirmButtonEnabled = false;
    +    }
    +
    +    return (
    +      <div className="replication-page">
    +        <div className="row">
    +          <div className="span3">
    +            Replication Source:
    +          </div>
    +          <div className="span7">
    +            <ReplicationSource
    +              value={replicationSource}
    +              onChange={(repSource) => Actions.updateFormField('replicationSource', repSource)}/>
    +          </div>
    +        </div>
    +        {this.getReplicationSourceRow()}
    +
    +        <hr size="1"/>
    +
    +        <div className="row">
    +          <div className="span3">
    +            Replication Target:
    +          </div>
    +          <div className="span7">
    +            <ReplicationTarget
    +              value={replicationTarget}
    +              onChange={(repTarget) => Actions.updateFormField('replicationTarget', repTarget)}/>
    +          </div>
    +        </div>
    +        {this.getReplicationTargetRow()}
    +
    +        <hr size="1"/>
    +
    +        <div className="row">
    +          <div className="span3">
    +            Replication Type:
    +          </div>
    +          <div className="span7">
    +            <ReplicationType
    +              value={replicationType}
    +              onChange={(repType) => Actions.updateFormField('replicationType', repType)}/>
    +          </div>
    +        </div>
    +
    +        <div className="row">
    +          <div className="span3">
    +            Replication Document:
    +          </div>
    +          <div className="span7">
    +            <div className="custom-id-field">
    +              <span className="fonticon fonticon-cancel" title="Clear field"
    +                onClick={(e) => Actions.updateFormField('replicationDocName', '')} />
    +              <input type="text" placeholder="Custom, new ID (optional)" value={replicationDocName}
    +                onChange={(e) => Actions.updateFormField('replicationDocName', e.target.value)}/>
    +            </div>
    +          </div>
    +        </div>
    +
    +        <div className="row buttons-row">
    +          <div className="span3">
    +          </div>
    +          <div className="span7">
    +            <ConfirmButton id="replicate" text="Start Replication" onClick={this.showPasswordModal} disabled={!confirmButtonEnabled}/>
    +            <a href="#" data-bypass="true" onClick={this.clear}>Clear</a>
    +          </div>
    +        </div>
    +
    +        <PasswordModal
    +          visible={passwordModalVisible}
    +          modalMessage={<p>Replication requires authentication.</p>}
    +          submitBtnLabel="Continue Replication"
    +          onSuccess={this.submit} />
    +      </div>
    +    );
    +  }
    +}
    +
    +
    +class ReplicationSource extends React.Component {
    +  getOptions () {
    +    const options = [
    +      { value: '', label: 'Select source' },
    +      { value: Constants.REPLICATION_SOURCE.LOCAL, label: 'Local database' },
    +      { value: Constants.REPLICATION_SOURCE.REMOTE, label: 'Remote database' }
    +    ];
    +    return _.map(options, function (option) {
    +      return (
    +        <option value={option.value} key={option.value}>{option.label}</option>
    +      );
    +    });
    +  }
    +
    +  render () {
    +    return (
    +      <StyledSelect
    +        selectContent={this.getOptions()}
    +        selectChange={(e) => this.props.onChange(e.target.value)}
    +        selectId="replication-source"
    +        selectValue={this.props.value} />
    +    );
    +  }
    +}
    +ReplicationSource.propTypes = {
    +  value: React.PropTypes.string.isRequired,
    +  onChange: React.PropTypes.func.isRequired
    +};
    +
    +
    +class ReplicationTarget extends React.Component {
    +  getOptions () {
    +    const options = [
    +      { value: '', label: 'Select target' },
    +      { value: Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE, label: 'Existing local database' },
    +      { value: Constants.REPLICATION_TARGET.EXISTING_REMOTE_DATABASE, label: 'Existing remote database' },
    +      { value: Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE, label: 'New local database' },
    +      { value: Constants.REPLICATION_TARGET.NEW_REMOTE_DATABASE, label: 'New remote database' }
    +    ];
    +    return _.map(options, function (option) {
    --- End diff --
    
    You can just do `options.map` here.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r73073846
  
    --- Diff: app/addons/auth/actions.js ---
    @@ -28,88 +28,133 @@ var errorHandler = function (xhr, type, msg) {
     };
     
     
    -export default {
    +function login (username, password, urlBack) {
    +  var promise = FauxtonAPI.session.login(username, password);
    +
    +  promise.then(function () {
    +    FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.loggedIn });
    +    if (urlBack) {
    +      return FauxtonAPI.navigate(urlBack);
    +    }
    +    FauxtonAPI.navigate('/');
    +  });
    +  promise.fail(errorHandler);
    +}
     
    -  login: function (username, password, urlBack) {
    -    var promise = FauxtonAPI.session.login(username, password);
    +function changePassword (password, passwordConfirm) {
    +  var nodes = nodesStore.getNodes();
    +  var promise = FauxtonAPI.session.changePassword(password, passwordConfirm, nodes[0].node);
     
    -    promise.then(function () {
    -      FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.loggedIn });
    -      if (urlBack) {
    -        return FauxtonAPI.navigate(urlBack);
    -      }
    -      FauxtonAPI.navigate('/');
    -    });
    -    promise.fail(errorHandler);
    -  },
    +  promise.then(() => {
    +    FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.changePassword });
    +    FauxtonAPI.dispatch({ type: ActionTypes.AUTH_CLEAR_CHANGE_PWD_FIELDS });
    +  });
     
    -  changePassword: function (password, passwordConfirm) {
    -    var nodes = nodesStore.getNodes();
    -    var promise = FauxtonAPI.session.changePassword(password, passwordConfirm, nodes[0].node);
    +  promise.fail(errorHandler);
    --- End diff --
    
    Yeah totally - this is old code, but I can update that too. 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    Too cool about Docker. Sheesh! Step away for 2 months and all this activity happens when you're gone. Can't say I approve! ;) 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    @benkeen this worked was merged in with the other PR. Could you close this PR.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    Hey @robertkowalski or @garrensmith, I think I need an extra pair of eyes on this. This ticket has dragged onnnnn and on and I have supremely limited time to work on it. I just can't get the NW tests to run reliably. Running just the one replication.js file works fine both locally & on travis, but when running all of them, it fails every time on Travis. Possibly it's actually a couch error silently failing to create the new replicated DB...? Maybe you can see something I can't. 
    
    I left all the debugging code in.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72946208
  
    --- Diff: app/addons/auth/actions.js ---
    @@ -28,88 +28,133 @@ var errorHandler = function (xhr, type, msg) {
     };
     
     
    -export default {
    +function login (username, password, urlBack) {
    +  var promise = FauxtonAPI.session.login(username, password);
    +
    +  promise.then(function () {
    +    FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.loggedIn });
    +    if (urlBack) {
    +      return FauxtonAPI.navigate(urlBack);
    +    }
    +    FauxtonAPI.navigate('/');
    +  });
    +  promise.fail(errorHandler);
    --- End diff --
    
    This needs to be changed to the .then


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen closed the pull request at:

    https://github.com/apache/couchdb-fauxton/pull/669


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    Nice, thanks @garrensmith! 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by robertkowalski <gi...@git.apache.org>.
Github user robertkowalski commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    good work! agree with garren on smaller components.
    
    using `const` would be great


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    @benkeen you have done an awesome job. Thanks. I can take a look. I can replicate the failing test locally. I'll try and fix it.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72035155
  
    --- Diff: app/addons/auth/actions.js ---
    @@ -28,88 +28,135 @@ var errorHandler = function (xhr, type, msg) {
     };
     
     
    -export default {
    +function login (username, password, urlBack) {
    +  var promise = FauxtonAPI.session.login(username, password);
    +
    +  promise.then(function () {
    +    FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.loggedIn });
    +    if (urlBack) {
    +      return FauxtonAPI.navigate(urlBack);
    +    }
    +    FauxtonAPI.navigate('/');
    +  });
    +  promise.fail(errorHandler);
    +}
     
    -  login: function (username, password, urlBack) {
    -    var promise = FauxtonAPI.session.login(username, password);
    +function changePassword (password, passwordConfirm) {
    +  var nodes = nodesStore.getNodes();
    +  var promise = FauxtonAPI.session.changePassword(password, passwordConfirm, nodes[0].node);
     
    -    promise.then(function () {
    -      FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.loggedIn });
    -      if (urlBack) {
    -        return FauxtonAPI.navigate(urlBack);
    -      }
    -      FauxtonAPI.navigate('/');
    -    });
    -    promise.fail(errorHandler);
    -  },
    +  promise.done(function () {
    +    FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.changePassword });
    +    FauxtonAPI.dispatch({ type: ActionTypes.AUTH_CLEAR_CHANGE_PWD_FIELDS });
    +  });
     
    -  changePassword: function (password, passwordConfirm) {
    -    var nodes = nodesStore.getNodes();
    -    var promise = FauxtonAPI.session.changePassword(password, passwordConfirm, nodes[0].node);
    +  promise.fail(errorHandler);
    +}
     
    -    promise.done(function () {
    -      FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.changePassword });
    -      FauxtonAPI.dispatch({ type: ActionTypes.AUTH_CLEAR_CHANGE_PWD_FIELDS });
    -    });
    +function updateChangePasswordField (value) {
    +  FauxtonAPI.dispatch({
    +    type: ActionTypes.AUTH_UPDATE_CHANGE_PWD_FIELD,
    +    value: value
    +  });
    +}
    +
    +function updateChangePasswordConfirmField (value) {
    +  FauxtonAPI.dispatch({
    +    type: ActionTypes.AUTH_UPDATE_CHANGE_PWD_CONFIRM_FIELD,
    +    value: value
    +  });
    +}
     
    -    promise.fail(errorHandler);
    -  },
    +function createAdmin (username, password, loginAfter) {
    +  var nodes = nodesStore.getNodes();
    +  var promise = FauxtonAPI.session.createAdmin(username, password, loginAfter, nodes[0].node);
     
    -  updateChangePasswordField: function (value) {
    -    FauxtonAPI.dispatch({
    -      type: ActionTypes.AUTH_UPDATE_CHANGE_PWD_FIELD,
    -      value: value
    -    });
    -  },
    +  promise.then(function () {
    +    FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.adminCreated });
    +    if (loginAfter) {
    +      FauxtonAPI.navigate('/');
    +    } else {
    +      FauxtonAPI.dispatch({ type: ActionTypes.AUTH_CLEAR_CREATE_ADMIN_FIELDS });
    +    }
    +  });
     
    -  updateChangePasswordConfirmField: function (value) {
    +  promise.fail(function (xhr, type, msg) {
    --- End diff --
    
    Could you rather use the second function in the `then` promise to handle the fail case.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    Hey @garrensmith / @robertkowalski  - took a thousand years, but could I get one of you to review this sucker? Hope all is well on your ends. 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    Hey @benkeen this is making good progress. The basic functionality looks great. Just some code clean ups needed. We will need some nightwatch tests before we can merge this in.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72034687
  
    --- Diff: app/addons/components/react-components.react.jsx ---
    @@ -1160,6 +1171,61 @@ const ConfirmButton = React.createClass({
       }
     });
     
    +
    +// A simple, unstyled typeahead widget that can be used for typeahead on any arbitrary strings.
    +// This should replace the more specific <JumpToDatabaseWidget />
    +var TypeaheadField = React.createClass({
    --- End diff --
    
    We have started using React-Select now instead. Could you rather use that. 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72946275
  
    --- Diff: app/addons/auth/actions.js ---
    @@ -28,88 +28,133 @@ var errorHandler = function (xhr, type, msg) {
     };
     
     
    -export default {
    +function login (username, password, urlBack) {
    +  var promise = FauxtonAPI.session.login(username, password);
    +
    +  promise.then(function () {
    +    FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.loggedIn });
    +    if (urlBack) {
    +      return FauxtonAPI.navigate(urlBack);
    +    }
    +    FauxtonAPI.navigate('/');
    +  });
    +  promise.fail(errorHandler);
    +}
     
    -  login: function (username, password, urlBack) {
    -    var promise = FauxtonAPI.session.login(username, password);
    +function changePassword (password, passwordConfirm) {
    +  var nodes = nodesStore.getNodes();
    +  var promise = FauxtonAPI.session.changePassword(password, passwordConfirm, nodes[0].node);
     
    -    promise.then(function () {
    -      FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.loggedIn });
    -      if (urlBack) {
    -        return FauxtonAPI.navigate(urlBack);
    -      }
    -      FauxtonAPI.navigate('/');
    -    });
    -    promise.fail(errorHandler);
    -  },
    +  promise.then(() => {
    +    FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.changePassword });
    +    FauxtonAPI.dispatch({ type: ActionTypes.AUTH_CLEAR_CHANGE_PWD_FIELDS });
    +  });
     
    -  changePassword: function (password, passwordConfirm) {
    -    var nodes = nodesStore.getNodes();
    -    var promise = FauxtonAPI.session.changePassword(password, passwordConfirm, nodes[0].node);
    +  promise.fail(errorHandler);
    --- End diff --
    
    We mustn't use `promise.fail` we cant to eventually move away from jquery and use something else. 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    Hey @benkeen, yes its working. We have changed how it works though. It now runs through docker. So you need to install docker. See (here)[https://github.com/apache/couchdb-fauxton/blob/master/tests.md] and (here)[https://medium.com/@garrensmith/consistent-selenium-testing-with-docker-f2d5a24a1bc5]


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72034996
  
    --- Diff: app/addons/replication/actions.js ---
    @@ -0,0 +1,90 @@
    +// 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 Helpers from './helpers';
    +
    +
    +function initReplicator (sourceDatabase) {
    +  if (sourceDatabase) {
    +    FauxtonAPI.dispatch({
    +      type: ActionTypes.INIT_REPLICATION,
    +      options: {
    +        sourceDatabase: sourceDatabase
    +      }
    +    });
    +  }
    +  $.ajax({
    +    url: app.host + '/_all_dbs',
    +    contentType: 'application/json',
    +    dataType: 'json'
    +  }).then(function (databases) {
    +    FauxtonAPI.dispatch({
    +      type: ActionTypes.REPLICATION_DATABASES_LOADED,
    +      options: {
    +        databases: databases
    +      }
    +    });
    +  });
    +}
    +
    +function replicate (params) {
    +  var promise = $.ajax({
    +    url: window.location.origin + '/_replicator',
    +    contentType: 'application/json',
    +    type: 'POST',
    +    dataType: 'json',
    +    data: JSON.stringify(params)
    +  });
    +
    +  var source = Helpers.getDatabaseLabel(params.source);
    --- End diff --
    
    Can you make these const's


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    @benkeen I've continuing the work in #761 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: [WIP] Replication page update

Posted by justin-mcdavid-ibm <gi...@git.apache.org>.
Github user justin-mcdavid-ibm commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    Hey Ben,
    
    I'm testing this, and it's awesome. Great work on this.  It's a big improvement.
    
    There are a couple of things I'm seeing that we probably should tweak.
    
    The "Select source" and "Select target" in-field explanatory test should be gray, though values selected through those dropdowns should remain the color of regular text.
    
    When you specify a custom replication doc ID, it has to be a new ID (folks might think they can specify an existing doc-- which causes a conflict), so we should elaborate on the explanatory text as [Custom, new ID (optional)]. Also, because you can't use the same custom ID for multiple jobs, can we add a clear (x) inside the custom ID field, so that after starting a replication job, users can easily clear just that field if they're reusing selected dbs or remote creds?
    
    If possible, we should remove the verification step where the account password is entered.  I'm not sure why it's a requirement.  If we do keep it, the button should be "Start Replication" rather than "Continue Replication," and we should specify which password is required, because it could be interpreted as a remote account's password.
    
    Icing, but after selecting from a dropdown, can we make focus automatically change to the following object?
    
    If there are illegal characters (spaces, prohibited symbols), or if the db name starts with something other than a lower-case letter in new-database-name field, can we disable the replicate button? I was able to "trigger" a replication from a local db to a new one called "spa ces" which then failed.
    
    Thanks for your work on this.
    
    



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72034308
  
    --- Diff: app/addons/auth/actions.js ---
    @@ -28,88 +28,135 @@ var errorHandler = function (xhr, type, msg) {
     };
     
     
    -export default {
    +function login (username, password, urlBack) {
    +  var promise = FauxtonAPI.session.login(username, password);
    +
    +  promise.then(function () {
    +    FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.loggedIn });
    +    if (urlBack) {
    +      return FauxtonAPI.navigate(urlBack);
    +    }
    +    FauxtonAPI.navigate('/');
    +  });
    +  promise.fail(errorHandler);
    +}
     
    -  login: function (username, password, urlBack) {
    -    var promise = FauxtonAPI.session.login(username, password);
    +function changePassword (password, passwordConfirm) {
    +  var nodes = nodesStore.getNodes();
    +  var promise = FauxtonAPI.session.changePassword(password, passwordConfirm, nodes[0].node);
     
    -    promise.then(function () {
    -      FauxtonAPI.addNotification({ msg: FauxtonAPI.session.messages.loggedIn });
    -      if (urlBack) {
    -        return FauxtonAPI.navigate(urlBack);
    -      }
    -      FauxtonAPI.navigate('/');
    -    });
    -    promise.fail(errorHandler);
    -  },
    +  promise.done(function () {
    --- End diff --
    
    `promise.done` should be `promise.then` that is more semantic. 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72035066
  
    --- Diff: app/addons/replication/actions.js ---
    @@ -0,0 +1,90 @@
    +// 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 Helpers from './helpers';
    +
    +
    +function initReplicator (sourceDatabase) {
    +  if (sourceDatabase) {
    +    FauxtonAPI.dispatch({
    +      type: ActionTypes.INIT_REPLICATION,
    +      options: {
    +        sourceDatabase: sourceDatabase
    +      }
    +    });
    +  }
    +  $.ajax({
    +    url: app.host + '/_all_dbs',
    +    contentType: 'application/json',
    +    dataType: 'json'
    +  }).then(function (databases) {
    +    FauxtonAPI.dispatch({
    +      type: ActionTypes.REPLICATION_DATABASES_LOADED,
    +      options: {
    +        databases: databases
    +      }
    +    });
    +  });
    +}
    +
    +function replicate (params) {
    +  var promise = $.ajax({
    +    url: window.location.origin + '/_replicator',
    +    contentType: 'application/json',
    +    type: 'POST',
    +    dataType: 'json',
    +    data: JSON.stringify(params)
    +  });
    +
    +  var source = Helpers.getDatabaseLabel(params.source);
    +  var target = Helpers.getDatabaseLabel(params.target);
    +
    +  promise.then(function () {
    --- End diff --
    
    You can also make these all `() =>` functions


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: [WIP] Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    TODO - notes from Justin:
    
    - In-field explanatory text should be gray +1
    - Text on the replication button should be \u201cStart Replication\u201d +1
    - The in-field explanatory text for Remote Sources and Targets should be https://$REMOTE_USERNAME:$REMOTE_PASSWORD@$REMOTE_SERVER/$DATABASE - 
    
    [discussion: oooffff... that's awful verbose. I think REMOTE_* is implicit, no? I mean you already picked "remote source" / "remote target". Don't want to bludgeon them over the head with it. Oddly clarity becomes less clear here.
    I'd be worried about some mistakenly thinking they needed to enter the current account's username and password. Maybe just drop the REMOTE_ on SERVER?]
    
    - Increase the widths of all dropdowns. \u201cExisting remote database\u201d gets cut-off after selection (in FF, but not Chrome, I see). +1
    - The replicate button activates after fields have been clicked on, but not before information is actually entered. Can we have the replication button activate only after the fields are populated? +1
    -  There doesn\u2019t appear to be any checking for the pre-existence of a \u201cnew\u201d database. I selected \u201cnew local database,\u201d and used the same DB for source and target.  Can we put in check in to make sure that users aren\u2019t accidentally overwriting existing DBs? I\u2019m assuming that there are back-end safeguards, but my test-replication job didn\u2019t throw any errors. +1
    - Can we leave the replication button inactive if the DB listed as an existing local source doesn\u2019t actually exist?  I can enter an db that doesn\u2019t exist and still trigger replication. Same for non-existing local targets. +1
    
    Other:
    - A source database that is open to/readable by the public does not require $USERNAME and $PASSWORD in its URL, right? Or do they all now require authentication (I remember something about this in your chats with Bob)? - Not sure... this bit's hard. :) In my trial and error I found you usually had to enter it, but I'll confirm.



---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by robertkowalski <gi...@git.apache.org>.
Github user robertkowalski commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72228440
  
    --- Diff: app/addons/components/react-components.react.jsx ---
    @@ -1160,6 +1171,61 @@ const ConfirmButton = React.createClass({
       }
     });
     
    +
    +// A simple, unstyled typeahead widget that can be used for typeahead on any arbitrary strings.
    +// This should replace the more specific <JumpToDatabaseWidget />
    +var TypeaheadField = React.createClass({
    +  propTypes: {
    +    list: React.PropTypes.array.isRequired,
    +    value: React.PropTypes.string.isRequired,
    +    onChange: React.PropTypes.func.isRequired,
    +    placeholder: React.PropTypes.string,
    +    autoFocus: React.PropTypes.bool
    +  },
    +
    +  getDefaultProps: function () {
    +    return {
    +      placeholder: 'Type ahead',
    +      autoFocus: false
    +    };
    +  },
    +
    +  componentDidMount: function () {
    +    this.updateTypeahead();
    +  },
    +
    +  updateTypeahead: function () {
    +    $(ReactDOM.findDOMNode(this.refs.field)).typeahead({
    --- End diff --
    
    we are removing the jquery typeahed and are using react-select instead.
    
    it is very easy to integrate, here is an example: https://github.com/apache/couchdb-fauxton/blob/5be261085761c5f1d0510f2d28117775ea3e0da2/app/addons/documents/components/jumptodoc.react.jsx


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    Thanks again for the feedback, guys. All fixed up except for the NW test. @garrensmith did you ever get NW running locally? Not sure what I'm missing but I get a "Connection refused! Is selenium server started?" error when running `grunt nightwatch` locally. 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72912803
  
    --- Diff: app/addons/replication/components.react.jsx ---
    @@ -0,0 +1,527 @@
    +// 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 React from 'react';
    +import Stores from './stores';
    +import Actions from './actions';
    +import Constants from './constants';
    +import Components from '../components/react-components.react';
    +import base64 from 'base-64';
    +import AuthActions from '../auth/actions';
    +import AuthComponents from '../auth/components.react';
    +
    +const store = Stores.replicationStore;
    +const LoadLines = Components.LoadLines;
    +const TypeaheadField = Components.TypeaheadField;
    +const StyledSelect = Components.StyledSelect;
    +const ConfirmButton = Components.ConfirmButton;
    +const PasswordModal = AuthComponents.PasswordModal;
    +
    +
    +class ReplicationController extends React.Component {
    +  constructor (props) {
    +    super(props);
    +    this.state = this.getStoreState();
    +    this.submit = this.submit.bind(this);
    +    this.clear = this.clear.bind(this);
    +    this.showPasswordModal = this.showPasswordModal.bind(this);
    +  }
    +
    +  getStoreState () {
    +    return {
    +      loading: store.isLoading(),
    +      databases: store.getDatabases(),
    +      authenticated: store.isAuthenticated(),
    +      password: store.getPassword(),
    +
    +      // source fields
    +      replicationSource: store.getReplicationSource(),
    +      sourceDatabase: store.getSourceDatabase(),
    +      localSourceDatabaseKnown: store.isLocalSourceDatabaseKnown(),
    +      remoteSource: store.getRemoteSource(),
    +
    +      // target fields
    +      replicationTarget: store.getReplicationTarget(),
    +      targetDatabase: store.getTargetDatabase(),
    +      localTargetDatabaseKnown: store.isLocalTargetDatabaseKnown(),
    +      remoteTarget: store.getRemoteTarget(),
    +
    +      // other
    +      passwordModalVisible: store.isPasswordModalVisible(),
    +      replicationType: store.getReplicationType(),
    +      replicationDocName: store.getReplicationDocName()
    +    };
    +  }
    +
    +  componentDidMount () {
    +    store.on('change', this.onChange, this);
    +  }
    +
    +  componentWillUnmount () {
    +    store.off('change', this.onChange);
    +  }
    +
    +  onChange () {
    +    this.setState(this.getStoreState());
    +  }
    +
    +  // the four local replication targets all show slightly different fields
    +  getReplicationTargetRow () {
    +    const { replicationTarget, remoteTarget, databases, targetDatabase } = this.state;
    +    if (!replicationTarget) {
    +      return null;
    +    }
    +    return (
    +      <ReplicationTargetRow
    +        remoteTarget={remoteTarget}
    +        replicationTarget={replicationTarget}
    +        databases={databases}
    +        targetDatabase={targetDatabase}/>
    +    );
    +  }
    +
    +  clear (e) {
    +    e.preventDefault();
    +    Actions.clearReplicationForm();
    +  }
    +
    +  showPasswordModal () {
    +    const { replicationSource, replicationTarget } = this.state;
    +
    +    var hasLocalSourceOrTarget = (replicationSource === Constants.REPLICATION_SOURCE.LOCAL ||
    +      replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE ||
    +      replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE);
    +
    +    // if the user is authenticated, or if NEITHER the source nor target are local, just submit. The password
    +    // modal isn't necessary
    +    if (!hasLocalSourceOrTarget || this.state.authenticated) {
    +      this.submit();
    +      return;
    +    }
    +    AuthActions.showPasswordModal();
    +  }
    +
    +  getUsername () {
    +    return app.session.get('userCtx').name;
    +  }
    +
    +  getAuthHeaders () {
    +    const username = this.getUsername();
    +    return {
    +      'Authorization': 'Basic ' + base64.encode(username + ':' + this.state.password)
    +    };
    +  }
    +
    +  submit () {
    --- End diff --
    
    Done.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72040825
  
    --- Diff: app/addons/replication/components.react.jsx ---
    @@ -0,0 +1,527 @@
    +// 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 React from 'react';
    +import Stores from './stores';
    +import Actions from './actions';
    +import Constants from './constants';
    +import Components from '../components/react-components.react';
    +import base64 from 'base-64';
    +import AuthActions from '../auth/actions';
    +import AuthComponents from '../auth/components.react';
    +
    +const store = Stores.replicationStore;
    +const LoadLines = Components.LoadLines;
    +const TypeaheadField = Components.TypeaheadField;
    +const StyledSelect = Components.StyledSelect;
    +const ConfirmButton = Components.ConfirmButton;
    +const PasswordModal = AuthComponents.PasswordModal;
    +
    +
    +class ReplicationController extends React.Component {
    +  constructor (props) {
    +    super(props);
    +    this.state = this.getStoreState();
    +    this.submit = this.submit.bind(this);
    +    this.clear = this.clear.bind(this);
    +    this.showPasswordModal = this.showPasswordModal.bind(this);
    +  }
    +
    +  getStoreState () {
    +    return {
    +      loading: store.isLoading(),
    +      databases: store.getDatabases(),
    +      authenticated: store.isAuthenticated(),
    +      password: store.getPassword(),
    +
    +      // source fields
    +      replicationSource: store.getReplicationSource(),
    +      sourceDatabase: store.getSourceDatabase(),
    +      localSourceDatabaseKnown: store.isLocalSourceDatabaseKnown(),
    +      remoteSource: store.getRemoteSource(),
    +
    +      // target fields
    +      replicationTarget: store.getReplicationTarget(),
    +      targetDatabase: store.getTargetDatabase(),
    +      localTargetDatabaseKnown: store.isLocalTargetDatabaseKnown(),
    +      remoteTarget: store.getRemoteTarget(),
    +
    +      // other
    +      passwordModalVisible: store.isPasswordModalVisible(),
    +      replicationType: store.getReplicationType(),
    +      replicationDocName: store.getReplicationDocName()
    +    };
    +  }
    +
    +  componentDidMount () {
    +    store.on('change', this.onChange, this);
    +  }
    +
    +  componentWillUnmount () {
    +    store.off('change', this.onChange);
    +  }
    +
    +  onChange () {
    +    this.setState(this.getStoreState());
    +  }
    +
    +  // the four local replication targets all show slightly different fields
    +  getReplicationTargetRow () {
    +    const { replicationTarget, remoteTarget, databases, targetDatabase } = this.state;
    +    if (!replicationTarget) {
    +      return null;
    +    }
    +    return (
    +      <ReplicationTargetRow
    +        remoteTarget={remoteTarget}
    +        replicationTarget={replicationTarget}
    +        databases={databases}
    +        targetDatabase={targetDatabase}/>
    +    );
    +  }
    +
    +  clear (e) {
    +    e.preventDefault();
    +    Actions.clearReplicationForm();
    +  }
    +
    +  showPasswordModal () {
    +    const { replicationSource, replicationTarget } = this.state;
    +
    +    var hasLocalSourceOrTarget = (replicationSource === Constants.REPLICATION_SOURCE.LOCAL ||
    +      replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE ||
    +      replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE);
    +
    +    // if the user is authenticated, or if NEITHER the source nor target are local, just submit. The password
    +    // modal isn't necessary
    +    if (!hasLocalSourceOrTarget || this.state.authenticated) {
    +      this.submit();
    +      return;
    +    }
    +    AuthActions.showPasswordModal();
    +  }
    +
    +  getUsername () {
    +    return app.session.get('userCtx').name;
    +  }
    +
    +  getAuthHeaders () {
    +    const username = this.getUsername();
    +    return {
    +      'Authorization': 'Basic ' + base64.encode(username + ':' + this.state.password)
    +    };
    +  }
    +
    +  submit () {
    --- End diff --
    
    Could you break this `submit` up a bit into different functions depending on if its local etc. This is a pretty large function. Its a little tricky to follow.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    No problem. Hope all's going well, @garrensmith! 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72041835
  
    --- Diff: app/addons/replication/components.react.jsx ---
    @@ -0,0 +1,527 @@
    +// 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 React from 'react';
    +import Stores from './stores';
    +import Actions from './actions';
    +import Constants from './constants';
    +import Components from '../components/react-components.react';
    +import base64 from 'base-64';
    +import AuthActions from '../auth/actions';
    +import AuthComponents from '../auth/components.react';
    +
    +const store = Stores.replicationStore;
    +const LoadLines = Components.LoadLines;
    +const TypeaheadField = Components.TypeaheadField;
    +const StyledSelect = Components.StyledSelect;
    +const ConfirmButton = Components.ConfirmButton;
    +const PasswordModal = AuthComponents.PasswordModal;
    +
    +
    +class ReplicationController extends React.Component {
    +  constructor (props) {
    +    super(props);
    +    this.state = this.getStoreState();
    +    this.submit = this.submit.bind(this);
    +    this.clear = this.clear.bind(this);
    +    this.showPasswordModal = this.showPasswordModal.bind(this);
    +  }
    +
    +  getStoreState () {
    +    return {
    +      loading: store.isLoading(),
    +      databases: store.getDatabases(),
    +      authenticated: store.isAuthenticated(),
    +      password: store.getPassword(),
    +
    +      // source fields
    +      replicationSource: store.getReplicationSource(),
    +      sourceDatabase: store.getSourceDatabase(),
    +      localSourceDatabaseKnown: store.isLocalSourceDatabaseKnown(),
    +      remoteSource: store.getRemoteSource(),
    +
    +      // target fields
    +      replicationTarget: store.getReplicationTarget(),
    +      targetDatabase: store.getTargetDatabase(),
    +      localTargetDatabaseKnown: store.isLocalTargetDatabaseKnown(),
    +      remoteTarget: store.getRemoteTarget(),
    +
    +      // other
    +      passwordModalVisible: store.isPasswordModalVisible(),
    +      replicationType: store.getReplicationType(),
    +      replicationDocName: store.getReplicationDocName()
    +    };
    +  }
    +
    +  componentDidMount () {
    +    store.on('change', this.onChange, this);
    +  }
    +
    +  componentWillUnmount () {
    +    store.off('change', this.onChange);
    +  }
    +
    +  onChange () {
    +    this.setState(this.getStoreState());
    +  }
    +
    +  // the four local replication targets all show slightly different fields
    +  getReplicationTargetRow () {
    +    const { replicationTarget, remoteTarget, databases, targetDatabase } = this.state;
    +    if (!replicationTarget) {
    +      return null;
    +    }
    +    return (
    +      <ReplicationTargetRow
    +        remoteTarget={remoteTarget}
    +        replicationTarget={replicationTarget}
    +        databases={databases}
    +        targetDatabase={targetDatabase}/>
    +    );
    +  }
    +
    +  clear (e) {
    +    e.preventDefault();
    +    Actions.clearReplicationForm();
    +  }
    +
    +  showPasswordModal () {
    +    const { replicationSource, replicationTarget } = this.state;
    +
    +    var hasLocalSourceOrTarget = (replicationSource === Constants.REPLICATION_SOURCE.LOCAL ||
    +      replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE ||
    +      replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE);
    +
    +    // if the user is authenticated, or if NEITHER the source nor target are local, just submit. The password
    +    // modal isn't necessary
    +    if (!hasLocalSourceOrTarget || this.state.authenticated) {
    +      this.submit();
    +      return;
    +    }
    +    AuthActions.showPasswordModal();
    +  }
    +
    +  getUsername () {
    +    return app.session.get('userCtx').name;
    +  }
    +
    +  getAuthHeaders () {
    +    const username = this.getUsername();
    +    return {
    +      'Authorization': 'Basic ' + base64.encode(username + ':' + this.state.password)
    +    };
    +  }
    +
    +  submit () {
    +    const { replicationSource, sourceDatabase, remoteSource, remoteTarget, replicationTarget, targetDatabase, replicationType,
    +      replicationDocName} = this.state;
    +
    +    const params = {};
    +
    +    // perform a little validating here
    +    if (!this.validate()) {
    +      return;
    +    }
    +
    +    // source
    +    if (replicationSource === Constants.REPLICATION_SOURCE.LOCAL) {
    +      params.source = {
    +        headers: this.getAuthHeaders(),
    +        url: window.location.origin + '/' + sourceDatabase
    +      };
    +    } else {
    +      params.source = remoteSource;
    +    }
    +
    +    // target
    +    if (replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE) {
    +      params.target = {
    +        headers: this.getAuthHeaders(),
    +        url: window.location.origin + '/' + targetDatabase
    +      };
    +    } else if (replicationTarget === Constants.REPLICATION_TARGET.EXISTING_REMOTE_DATABASE) {
    +      params.target = remoteTarget;
    +    } else if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE) {
    +
    +      // check to see if we really need to send headers here or can just do the ELSE clause in all scenarioe
    +      if (replicationSource === Constants.REPLICATION_SOURCE.LOCAL) {
    +        params.target = {
    +          headers: this.getAuthHeaders(),
    +          url: window.location.origin + '/' + targetDatabase
    +        };
    +      } else {
    +        const port = window.location.port === '' ? '' : ':' + window.location.port;
    +        params.target = window.location.protocol + '//' + this.getUsername() + ':' + this.state.password + '@'
    +          + window.location.hostname + port + '/' + targetDatabase;
    +      }
    +    } else if (replicationTarget === Constants.REPLICATION_TARGET.NEW_REMOTE_DATABASE) {
    +      params.target = remoteTarget;
    +    }
    +
    +    if (_.contains([Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE, Constants.REPLICATION_TARGET.NEW_REMOTE_DATABASE], replicationTarget)) {
    +      params.create_target = true;
    +    }
    +    if (replicationType === Constants.REPLICATION_TYPE.CONTINUOUS) {
    +      params.continuous = true;
    +    }
    +
    +    if (replicationDocName) {
    +      params._id = this.state.replicationDocName;
    +    }
    +
    +    // POSTing to the _replicator DB requires authentication
    +    const user = FauxtonAPI.session.user();
    +    const userName = _.isNull(user) ? '' : FauxtonAPI.session.user().name;
    +    params.user_ctx = {
    +      name: userName,
    +      roles: ['_admin', '_reader', '_writer']
    +    };
    +
    +    Actions.replicate(params);
    +  }
    +
    +  validate () {
    +    const { replicationTarget, targetDatabase, databases } = this.state;
    +
    +    if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE && _.contains(databases, targetDatabase)) {
    +      FauxtonAPI.addNotification({
    +        msg: 'The <code>' + targetDatabase + '</code> database already exists locally. Please enter another database name.',
    +        type: 'error',
    +        escape: false,
    +        clear: true
    +      });
    +      return false;
    +    }
    +    if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE ||
    +        replicationTarget === Constants.REPLICATION_TARGET.NEW_REMOTE_DATABASE) {
    +      let error = '';
    +      if (/\s/.test(targetDatabase)) {
    +        error = 'The target database may not contain any spaces.';
    +      } else if (/^_/.test(targetDatabase)) {
    +        error = 'The target database may not start with an underscore.';
    +      }
    +
    +      if (error) {
    +        FauxtonAPI.addNotification({
    +          msg: error,
    +          type: 'error',
    +          escape: false,
    +          clear: true
    +        });
    +        return false;
    +      }
    +    }
    +
    +    return true;
    +  }
    +
    +  getReplicationSourceRow () {
    +    const { replicationSource, databases, sourceDatabase, remoteSource } = this.state;
    --- End diff --
    
    Can you break these replication source row into their own react components.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton issue #669: [WIP] Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen commented on the issue:

    https://github.com/apache/couchdb-fauxton/pull/669
  
    Thanks @justin-mcdavid-ibm! Just emailed you - sorry, didn't realize you responded here.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by garrensmith <gi...@git.apache.org>.
Github user garrensmith commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72042083
  
    --- Diff: test/nightwatch_tests/nightwatch.json.underscore ---
    @@ -16,7 +16,7 @@
         "cli_args" : {
           "webdriver.chrome.driver" : "",
           "webdriver.ie.driver" : "",
    -      "webdriver.firefox.profile" : ""
    +      "webdriver.firefox.profile" : "default"
    --- End diff --
    
    Why do you need to set this as default?


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---

[GitHub] couchdb-fauxton pull request #669: Replication page update

Posted by benkeen <gi...@git.apache.org>.
Github user benkeen commented on a diff in the pull request:

    https://github.com/apache/couchdb-fauxton/pull/669#discussion_r72179397
  
    --- Diff: test/nightwatch_tests/nightwatch.json.underscore ---
    @@ -16,7 +16,7 @@
         "cli_args" : {
           "webdriver.chrome.driver" : "",
           "webdriver.ie.driver" : "",
    -      "webdriver.firefox.profile" : ""
    +      "webdriver.firefox.profile" : "default"
    --- End diff --
    
    Doh.


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at infrastructure@apache.org or file a JIRA ticket
with INFRA.
---