blob: f1a82a0da8a18d4a91a75cb0c4054f5c14d40a06 [file] [log] [blame]
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
import React from 'react';
import app from '../../../app';
import FauxtonAPI from '../../../core/api';
import {ReplicationSource} from './source';
import {ReplicationTarget} from './target';
import {ReplicationOptions} from './options';
import {ReplicationSubmit} from './submit';
import AuthComponents from '../../auth/components';
import Constants from '../constants';
import {ConflictModal} from './modals';
import {isEmpty} from 'lodash';
const {PasswordModal} = AuthComponents;
export default class NewReplicationController extends React.Component {
constructor (props) {
super(props);
this.submit = this.submit.bind(this);
this.clear = this.clear.bind(this);
this.showPasswordModal = this.showPasswordModal.bind(this);
this.runReplicationChecks = this.runReplicationChecks.bind(this);
}
clear (e) {
e.preventDefault();
this.props.clearReplicationForm();
}
showPasswordModal () {
this.props.hideConflictModal();
const { replicationSource, replicationTarget } = this.props;
const 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 or if couchdb is in admin party mode
if (!hasLocalSourceOrTarget || this.props.authenticated || FauxtonAPI.session.isAdminParty()) {
this.submit(this.props.username, this.props.password);
return;
}
this.props.showPasswordModal();
}
checkReplicationDocID () {
const {showConflictModal, replicationDocName, checkReplicationDocID} = this.props;
checkReplicationDocID(replicationDocName).then(existingDoc => {
if (existingDoc) {
showConflictModal();
return;
}
this.showPasswordModal();
});
}
runReplicationChecks () {
const {replicationDocName} = this.props;
if (!this.validate()) {
return;
}
if (replicationDocName) {
this.checkReplicationDocID();
return;
}
this.showPasswordModal();
}
validate () {
const {
remoteTarget,
remoteSource,
replicationTarget,
localTarget,
localSource,
databases
} = this.props;
if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE && _.includes(databases, localTarget)) {
FauxtonAPI.addNotification({
msg: 'The <code>' + localTarget + '</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(localTarget)) {
error = 'The target database may not contain any spaces.';
} else if (/^_/.test(localTarget)) {
error = 'The target database may not start with an underscore.';
}
if (error) {
FauxtonAPI.addNotification({
msg: error,
type: 'error',
escape: false,
clear: true
});
return false;
}
}
//check that source and target are not the same. They can trigger a false positive if they are ""
if ((remoteTarget === remoteSource && !isEmpty(remoteTarget))
|| (localSource === localTarget && !isEmpty(localSource))) {
FauxtonAPI.addNotification({
msg: 'Cannot replicate a database to itself',
type: 'error',
escape: false,
clear: true
});
return false;
}
return true;
}
submit (username, password) {
const {
replicationTarget,
replicationSource,
replicationType,
replicationDocName,
remoteTarget,
remoteSource,
localTarget,
localSource
} = this.props;
let _rev;
if (replicationDocName) {
const doc = this.props.docs.find(doc => doc._id === replicationDocName);
if (doc) {
_rev = doc._rev;
}
}
this.props.hidePasswordModal();
this.props.replicate({
replicationTarget,
replicationSource,
replicationType,
replicationDocName,
username,
password,
localTarget,
localSource,
remoteTarget,
remoteSource,
_rev
});
}
confirmButtonEnabled () {
const {
remoteSource,
localSourceKnown,
replicationSource,
replicationTarget,
localTargetKnown,
localTarget,
submittedNoChange,
} = this.props;
if (submittedNoChange) {
return false;
}
if (!replicationSource || !replicationTarget) {
return false;
}
if (replicationSource === Constants.REPLICATION_SOURCE.LOCAL && !localSourceKnown) {
return false;
}
if (replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE && !localTargetKnown) {
return false;
}
if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE && !localTarget) {
return false;
}
if (replicationSource === Constants.REPLICATION_SOURCE.REMOTE && remoteSource === "") {
return false;
}
return true;
}
render () {
const {
replicationSource,
replicationTarget,
replicationType,
replicationDocName,
passwordModalVisible,
conflictModalVisible,
databases,
localSource,
remoteSource,
remoteTarget,
localTarget,
updateFormField,
clearReplicationForm
} = this.props;
return (
<div>
<ReplicationSource
replicationSource={replicationSource}
localSource={localSource}
databases={databases}
remoteSource={remoteSource}
onSourceSelect={updateFormField('replicationSource')}
onRemoteSourceChange={updateFormField('remoteSource')}
onLocalSourceChange={updateFormField('localSource')}
/>
<hr className="replication__seperator" size="1"/>
<ReplicationTarget
replicationTarget={replicationTarget}
onTargetChange={updateFormField('replicationTarget')}
databases={databases}
localTarget={localTarget}
remoteTarget={remoteTarget}
onRemoteTargetChange={updateFormField('remoteTarget')}
onLocalTargetChange={updateFormField('localTarget')}
/>
<hr className="replication__seperator" size="1"/>
<ReplicationOptions
replicationType={replicationType}
replicationDocName={replicationDocName}
onDocChange={updateFormField('replicationDocName')}
onTypeChange={updateFormField('replicationType')}
/>
<ReplicationSubmit
disabled={!this.confirmButtonEnabled()}
onClick={this.runReplicationChecks}
onClear={clearReplicationForm}
/>
<PasswordModal
visible={passwordModalVisible}
modalMessage={<p>{app.i18n.en_US['replication-password-modal-text']}</p>}
submitBtnLabel="Start Replication"
headerTitle={app.i18n.en_US['replication-password-modal-header']}
onClose={this.props.hidePasswordModal}
onSuccess={this.submit} />
<ConflictModal
visible={conflictModalVisible}
onClick={this.showPasswordModal}
onClose={this.props.hideConflictModal}
docId={replicationDocName}
/>
</div>
);
}
}