Repository: couchdb-fauxton
Updated Branches:
  refs/heads/master 41967231e -> efc2a1e23


Move all React modals to use ReactBootstrap.Modal

Benefits are less custom code and all modals standardized by
default, so behaviour like clicking outside the modal or clicking
escape will close it. These are configurable, but the “out the
box” modals will be all the same.

Affects:
- Confirmation modal (e.g. full page doc editor, “are you sure you want to 
delete this doc?”)
- Upload file modal
- String Edit modal
- Clone Doc modal


Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/efc2a1e2
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/efc2a1e2
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/efc2a1e2

Branch: refs/heads/master
Commit: efc2a1e23772861a5c7afedc5a4010e4c1575e02
Parents: 4196723
Author: Ben Keen <ben.k...@gmail.com>
Authored: Mon Dec 14 10:39:09 2015 -0800
Committer: Ben Keen <ben.k...@gmail.com>
Committed: Tue Jan 5 08:54:33 2016 -0800

----------------------------------------------------------------------
 .../components/react-components.react.jsx       |  76 ++++++--------
 .../tests/stringEditModalSpec.react.jsx         |  47 +++++----
 .../documents/doc-editor/components.react.jsx   | 104 +++++--------------
 .../tests/doc-editor.componentsSpec.react.jsx   |  27 +++--
 .../tests/nightwatch/createsDocument.js         |   2 +-
 app/addons/fauxton/components.react.jsx         |  33 +++---
 assets/less/fauxton.less                        |   5 +
 7 files changed, 127 insertions(+), 167 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/efc2a1e2/app/addons/components/react-components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/react-components.react.jsx 
b/app/addons/components/react-components.react.jsx
index 7154070..c501396 100644
--- a/app/addons/components/react-components.react.jsx
+++ b/app/addons/components/react-components.react.jsx
@@ -25,6 +25,7 @@ function (app, FauxtonAPI, React, Stores, FauxtonComponents, 
ace, beautifyHelper
 
   var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
   var componentStore = Stores.componentStore;
+  var Modal = ReactBootstrap.Modal;
 
 
   var ToggleHeaderButton = React.createClass({
@@ -355,7 +356,7 @@ function (app, FauxtonAPI, React, Stores, 
FauxtonComponents, ace, beautifyHelper
         stringEditModalVisible: false,
         stringEditIconVisible: false,
         stringEditIconStyle: {},
-        stringEditModalDefaultString: ''
+        stringEditModalValue: ''
       };
     },
 
@@ -560,8 +561,10 @@ function (app, FauxtonAPI, React, Stores, 
FauxtonComponents, ace, beautifyHelper
       }
       string = string.substring(1, lastChar);
 
-      this.setState({ stringEditModalVisible: true });
-      this.refs.stringEditModal.setValue(string);
+      this.setState({
+        stringEditModalVisible: true,
+        stringEditModalValue: string
+      });
     },
 
     saveStringEditModal: function (newString) {
@@ -648,6 +651,7 @@ function (app, FauxtonAPI, React, Stores, 
FauxtonComponents, ace, beautifyHelper
           <StringEditModal
             ref="stringEditModal"
             visible={this.state.stringEditModalVisible}
+            value={this.state.stringEditModalValue}
             onSave={this.saveStringEditModal}
             onClose={this.closeStringEditModal} />
         </div>
@@ -660,6 +664,7 @@ function (app, FauxtonAPI, React, Stores, 
FauxtonComponents, ace, beautifyHelper
   var StringEditModal = React.createClass({
 
     propTypes: {
+      value: React.PropTypes.string.isRequired,
       visible: React.PropTypes.bool.isRequired,
       onClose: React.PropTypes.func.isRequired,
       onSave: React.PropTypes.func.isRequired
@@ -673,46 +678,34 @@ function (app, FauxtonAPI, React, Stores, 
FauxtonComponents, ace, beautifyHelper
       };
     },
 
-    componentDidUpdate: function () {
-      var params = (this.props.visible) ? { show: true, backdrop: 'static', 
keyboard: true } : 'hide';
-      $(React.findDOMNode(this)).modal(params);
+    componentDidMount: function () {
+      if (!this.props.visible) {
+        return;
+      }
+      this.initEditor(this.props.value);
+    },
 
-      $(React.findDOMNode(this)).on('shown.bs.modal', function () {
-        this.editor.focus();
+    componentDidUpdate: function (prevProps) {
+      if (!this.props.visible) {
+        return;
+      }
+      var val = '';
+      if (!prevProps.visible && this.props.visible) {
+        val = JSON.parse('"' + this.props.value + '"'); // this ensures 
newlines are converted
+      }
 
-        // re-opening the modal to edit a second string doesn't update the 
content. This forces the editor to redraw
-        // to show the latest content each time it opens
-        this.editor.resize();
-        this.editor.renderer.updateFull();
-      }.bind(this));
+      this.initEditor(val);
     },
 
-    // ensure that if the user clicks ESC to close the window, the store gets 
wind of it
-    componentDidMount: function () {
-      $(React.findDOMNode(this)).on('hidden.bs.modal', function () {
-        this.props.onClose();
-      }.bind(this));
-
+    initEditor: function (val) {
       this.editor = ace.edit(React.findDOMNode(this.refs.stringEditor));
-
-      // suppresses an Ace editor error
-      this.editor.$blockScrolling = Infinity;
-
+      this.editor.$blockScrolling = Infinity; // suppresses an Ace editor error
       this.editor.setShowPrintMargin(false);
       this.editor.setOption('highlightActiveLine', true);
       this.editor.setTheme('ace/theme/idle_fingers');
-    },
-
-    setValue: function (val) {
-      // we do the JSON.parse so the string editor modal shows newlines
-      val = JSON.parse('"' + val + '"');      //returns an object, expects a 
JSON string
       this.editor.setValue(val, -1);
     },
 
-    componentWillUnmount: function () {
-      $(React.findDOMNode(this)).off('hidden.bs.modal shown.bs.modal');
-    },
-
     closeModal: function () {
       this.props.onClose();
     },
@@ -723,22 +716,21 @@ function (app, FauxtonAPI, React, Stores, 
FauxtonComponents, ace, beautifyHelper
 
     render: function () {
       return (
-        <div className="modal hide fade string-editor-modal" tabIndex="-1">
-          <div className="modal-header">
-            <button type="button" className="close" onClick={this.closeModal} 
aria-hidden="true">&times;</button>
-            <h3>Edit text <span id="string-edit-header"></span></h3>
-          </div>
-          <div className="modal-body">
+        <Modal dialogClassName="string-editor-modal" show={this.props.visible} 
onHide={this.closeModal}>
+          <Modal.Header closeButton={true}>
+            <Modal.Title>Edit text <span 
id="string-edit-header"></span></Modal.Title>
+          </Modal.Header>
+          <Modal.Body>
             <div id="modal-error" className="hide alert alert-error"/>
             <div id="string-editor-wrapper"><div ref="stringEditor" 
className="doc-code"></div></div>
-          </div>
-          <div className="modal-footer">
+          </Modal.Body>
+          <Modal.Footer>
             <button className="cancel-button btn" onClick={this.closeModal}><i 
className="icon fonticon-circle-x"></i> Cancel</button>
             <button id="string-edit-save-btn" onClick={this.save} 
className="btn btn-success save">
               <i className="fonticon-circle-check"></i> Save
             </button>
-          </div>
-        </div>
+          </Modal.Footer>
+        </Modal>
       );
     }
   });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/efc2a1e2/app/addons/components/tests/stringEditModalSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/stringEditModalSpec.react.jsx 
b/app/addons/components/tests/stringEditModalSpec.react.jsx
index d67e356..bc1fd71 100644
--- a/app/addons/components/tests/stringEditModalSpec.react.jsx
+++ b/app/addons/components/tests/stringEditModalSpec.react.jsx
@@ -12,15 +12,18 @@
 define([
   'api',
   'addons/components/react-components.react',
+  'libs/react-bootstrap',
   'testUtils',
   'react'
-], function (FauxtonAPI, ReactComponents, utils, React) {
+], function (FauxtonAPI, ReactComponents, ReactBootstrap, utils, React) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
+  var Modal = ReactBootstrap.Modal;
+
 
   describe('String Edit Modal', function () {
-    var container, modalEl;
+    var container, el;
     var stub = function () { };
 
     beforeEach(function () {
@@ -34,52 +37,58 @@ define([
     describe('event methods called', function () {
       it('onClose called by top (x)', function () {
         var spy = sinon.spy();
-        modalEl = TestUtils.renderIntoDocument(
+        el = TestUtils.renderIntoDocument(
           <ReactComponents.StringEditModal visible={true} onClose={spy} 
onSave={stub} />,
           container
         );
-        TestUtils.Simulate.click($(modalEl.getDOMNode()).find('.close')[0]);
+        var modal = TestUtils.findRenderedComponentWithType(el, Modal);
+        var modalEl = React.findDOMNode(modal.refs.modal);
+
+        TestUtils.Simulate.click($(modalEl).find('.close')[0]);
         assert.ok(spy.calledOnce);
       });
 
       it('onClose called by cancel button', function () {
         var spy = sinon.spy();
-        modalEl = TestUtils.renderIntoDocument(
+        el = TestUtils.renderIntoDocument(
           <ReactComponents.StringEditModal visible={true} onClose={spy} 
onSave={stub} />,
           container
         );
-        
TestUtils.Simulate.click($(modalEl.getDOMNode()).find('.cancel-button')[0]);
+        var modal = TestUtils.findRenderedComponentWithType(el, Modal);
+        var modalEl = React.findDOMNode(modal.refs.modal);
+        TestUtils.Simulate.click($(modalEl).find('.cancel-button')[0]);
         assert.ok(spy.calledOnce);
       });
     });
 
-    describe('setValue / onSave', function () {
-      it('setValue ensures same content returns on saving', function () {
+    describe('onSave', function () {
+      it('ensures same content returns on saving', function () {
+        var string = "a string!";
         var spy = sinon.spy();
-        modalEl = TestUtils.renderIntoDocument(
-          <ReactComponents.StringEditModal visible={true} onClose={stub} 
onSave={spy} />,
+        el = TestUtils.renderIntoDocument(
+          <ReactComponents.StringEditModal visible={true} onClose={stub} 
onSave={spy} value={string} />,
           container
         );
+        var modal = TestUtils.findRenderedComponentWithType(el, Modal);
+        var modalEl = React.findDOMNode(modal.refs.modal);
 
-        var string = "a string!";
-
-        modalEl.setValue(string);
-        
TestUtils.Simulate.click($(modalEl.getDOMNode()).find('#string-edit-save-btn')[0]);
+        TestUtils.Simulate.click($(modalEl).find('#string-edit-save-btn')[0]);
         assert.ok(spy.calledOnce);
         assert.ok(spy.calledWith(string));
       });
 
       it('replaces "\\n" with actual newlines', function () {
         var spy = sinon.spy();
-        modalEl = TestUtils.renderIntoDocument(
-          <ReactComponents.StringEditModal visible={true} onSave={spy} />,
+        var string = 'I am a string\\nwith\\nlinebreaks\\nin\\nit';
+        el = TestUtils.renderIntoDocument(
+          <ReactComponents.StringEditModal visible={true} onSave={spy} 
value={string} />,
           container
         );
 
-        var string = 'I am a string\\nwith\\nlinebreaks\\nin\\nit';
+        var modal = TestUtils.findRenderedComponentWithType(el, Modal);
+        var modalEl = React.findDOMNode(modal.refs.modal);
 
-        modalEl.setValue(string);
-        
TestUtils.Simulate.click($(modalEl.getDOMNode()).find('#string-edit-save-btn')[0]);
+        TestUtils.Simulate.click($(modalEl).find('#string-edit-save-btn')[0]);
         assert.ok(spy.calledOnce);
       });
     });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/efc2a1e2/app/addons/documents/doc-editor/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/doc-editor/components.react.jsx 
b/app/addons/documents/doc-editor/components.react.jsx
index 376ef30..462915a 100644
--- a/app/addons/documents/doc-editor/components.react.jsx
+++ b/app/addons/documents/doc-editor/components.react.jsx
@@ -6,11 +6,12 @@ define([
   'addons/documents/doc-editor/stores',
   'addons/fauxton/components.react',
   'addons/components/react-components.react',
+  'libs/react-bootstrap',
   'helpers'
-], function (FauxtonAPI, app, React, Actions, Stores, FauxtonComponents, 
GeneralComponents, Helpers) {
+], function (FauxtonAPI, app, React, Actions, Stores, FauxtonComponents, 
GeneralComponents, ReactBootstrap, Helpers) {
 
   var store = Stores.docEditorStore;
-
+  var Modal = ReactBootstrap.Modal;
 
   var DocEditorController = React.createClass({
 
@@ -281,34 +282,12 @@ define([
       };
     },
 
-    componentDidUpdate: function () {
-      var params = (this.props.visible) ? { show: true, backdrop: 'static', 
keyboard: true } : 'hide';
-      $(React.findDOMNode(this)).modal(params);
-    },
-
-    // ensure that if the user clicks ESC to close the window, the store gets 
wind of it
-    componentDidMount: function () {
-      $(React.findDOMNode(this)).on('hidden.bs.modal', function () {
-        Actions.hideUploadModal();
-      });
-    },
-
-    componentWillUnmount: function () {
-      $(React.findDOMNode(this)).off('hidden.bs.modal');
-    },
-
     closeModal: function () {
       if (this.state.inProgress) {
         Actions.cancelUpload();
       }
       Actions.hideUploadModal();
-
-      // timeout needed to only clear it once the animate close effect is 
done, otherwise the user sees it reset
-      // as it closes, which looks bad
-      setTimeout(function () {
-        Actions.resetUploadModal();
-        React.findDOMNode(this.refs.uploadForm).reset();
-      }.bind(this), 1000);
+      Actions.resetUploadModal();
     },
 
     upload: function () {
@@ -330,14 +309,12 @@ define([
       }
 
       return (
-        <div className="modal hide fade upload-file-modal" tabIndex="-1" 
data-js-visible={this.props.visible}>
-          <div className="modal-header">
-            <button type="button" className="close" onClick={this.closeModal} 
aria-hidden="true">&times;</button>
-            <h3>Upload Attachment</h3>
-          </div>
-          <div className="modal-body">
+        <Modal dialogClassName="upload-file-modal" show={this.props.visible} 
onHide={this.closeModal}>
+          <Modal.Header closeButton={true}>
+            <Modal.Title>Upload Attachment</Modal.Title>
+          </Modal.Header>
+          <Modal.Body>
             <div className={errorClasses}>{this.state.errorMessage}</div>
-
             <div>
               <form ref="uploadForm" className="form" method="post">
                 <p>
@@ -348,21 +325,20 @@ define([
                 <br />
               </form>
 
-              <div ref="loadIndicator" className={loadIndicatorClasses}>
+              <div className={loadIndicatorClasses}>
                 <div className="bar" style={{ width: this.state.loadPercentage 
+ '%'}}></div>
               </div>
             </div>
-
-          </div>
-          <div className="modal-footer">
-             <button href="#" data-bypass="true" className="btn" 
onClick={this.closeModal}>
+          </Modal.Body>
+          <Modal.Footer>
+            <button href="#" data-bypass="true" className="btn" 
onClick={this.closeModal}>
               <i className="icon fonticon-cancel-circled"></i> Cancel
             </button>
             <button href="#" id="upload-btn" data-bypass="true" className="btn 
btn-success save" onClick={this.upload}>
               <i className="icon fonticon-ok-circled"></i> Upload
             </button>
-          </div>
-        </div>
+          </Modal.Footer>
+        </Modal>
       );
     }
   });
@@ -392,34 +368,6 @@ define([
         uuid.fetch().then(function () {
           this.setState({ uuid: uuid.next() });
         }.bind(this));
-        return;
-      }
-
-      var params = (this.props.visible) ? { show: true, backdrop: 'static', 
keyboard: true } : 'hide';
-      $(React.findDOMNode(this)).modal(params);
-      this.clearEvents();
-
-      // ensure that if the user clicks ESC to close the window, the store 
gets wind of it
-      $(React.findDOMNode(this)).on('hidden.bs.modal', function () {
-        Actions.hideCloneDocModal();
-      });
-
-      $(React.findDOMNode(this)).on('shown.bs.modal', function () {
-        this.focus();
-      }.bind(this));
-    },
-
-    focus: function () {
-      $(React.findDOMNode(this.refs.newDocId)).focus();
-    },
-
-    componentWillUnmount: function () {
-      this.clearEvents();
-    },
-
-    clearEvents: function () {
-      if (this.refs.newDocId) {
-        $(React.findDOMNode(this.refs.newDocId)).off('shown.bs.modal 
hidden.bs.modal');
       }
     },
 
@@ -437,28 +385,28 @@ define([
       }
 
       return (
-        <div className="modal hide fade clone-doc-modal" 
data-js-visible={this.props.visible} tabIndex="-1">
-          <div className="modal-header">
-            <button type="button" className="close" onClick={this.closeModal} 
aria-hidden="true">&times;</button>
-            <h3>Clone Document</h3>
-          </div>
-          <div className="modal-body">
+        <Modal dialogClassName="clone-doc-modal" show={this.props.visible} 
onHide={this.closeModal}>
+          <Modal.Header closeButton={true}>
+            <Modal.Title>Clone Document</Modal.Title>
+          </Modal.Header>
+          <Modal.Body>
             <form className="form" method="post">
               <p>
                 Set new document's ID:
               </p>
-              <input ref="newDocId" type="text" className="input-block-level" 
onChange={this.docIDChange} value={this.state.uuid} />
+              <input ref="newDocId" type="text" autoFocus={true} 
className="input-block-level"
+                onChange={this.docIDChange} value={this.state.uuid} />
             </form>
-          </div>
-          <div className="modal-footer">
+          </Modal.Body>
+          <Modal.Footer>
             <button className="btn" onClick={this.closeModal}>
               <i className="icon fonticon-cancel-circled"></i> Cancel
             </button>
             <button className="btn btn-success save" onClick={this.cloneDoc}>
               <i className="fonticon-ok-circled"></i> Clone
             </button>
-          </div>
-        </div>
+          </Modal.Footer>
+        </Modal>
       );
     }
   });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/efc2a1e2/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git 
a/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.react.jsx 
b/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.react.jsx
index eeaf2a2..cdbc192 100644
--- a/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.react.jsx
+++ b/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.react.jsx
@@ -20,9 +20,14 @@ define([
   'addons/documents/doc-editor/actions',
   'addons/documents/doc-editor/actiontypes',
   'addons/databases/base',
-  'testUtils'
-], function (app, FauxtonAPI, React, Documents, Components, Stores, Actions, 
ActionTypes, Databases, utils) {
+  'testUtils',
+  'libs/react-bootstrap'
+], function (app, FauxtonAPI, React, Documents, Components, Stores, Actions, 
ActionTypes, Databases, utils,
+  ReactBoostrap) {
+
   FauxtonAPI.router = new FauxtonAPI.Router([]);
+  var Modal = ReactBoostrap.Modal;
+
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -157,9 +162,15 @@ define([
           doc: doc
         }
       });
-      
assert.ok($(el.getDOMNode()).find('.confirmation-modal')[0].getAttribute('data-js-visible')
 == 'false');
+
+      // this is unfortunate, but I can't find a better way to do it. Refs 
won't work for bootstrap modals because
+      // they add the modal to the page at the top level outside the 
component. There are 3 modals in the
+      // component: the upload modal, clone modal, delete doc modal. We locate 
it by index
+      var modals = TestUtils.scryRenderedComponentsWithType(el, Modal);
+
+      assert.equal(React.findDOMNode(modals[2].refs.modal), null);
       Actions.showDeleteDocModal();
-      
assert.ok($(el.getDOMNode()).find('.confirmation-modal')[0].getAttribute('data-js-visible')
 == 'true');
+      assert.notEqual(React.findDOMNode(modals[2].refs.modal), null);
     });
 
     it('setting uploadDocModal=true in store shows modal', function () {
@@ -171,13 +182,15 @@ define([
           doc: doc
         }
       });
-      
assert.ok($(el.getDOMNode()).find('.upload-file-modal')[0].getAttribute('data-js-visible')
 == 'false');
+      var modals = TestUtils.scryRenderedComponentsWithType(el, Modal);
+
+      assert.equal(React.findDOMNode(modals[1].refs.modal), null);
       Actions.showUploadModal();
-      
assert.ok($(el.getDOMNode()).find('.upload-file-modal')[0].getAttribute('data-js-visible')
 == 'true');
+      assert.notEqual(React.findDOMNode(modals[1].refs.modal), null);
     });
-
   });
 
+
   describe("AttachmentsPanelButton", function () {
     var container, doc;
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/efc2a1e2/app/addons/documents/tests/nightwatch/createsDocument.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/tests/nightwatch/createsDocument.js 
b/app/addons/documents/tests/nightwatch/createsDocument.js
index 1b4e321..ef04bae 100644
--- a/app/addons/documents/tests/nightwatch/createsDocument.js
+++ b/app/addons/documents/tests/nightwatch/createsDocument.js
@@ -26,7 +26,7 @@ module.exports = {
       .clickWhenVisible('#new-all-docs-button a[href="#/database/' + 
newDatabaseName + '/new"]')
       .waitForElementPresent('#editor-container', waitTime, false)
       .verify.urlEquals(baseUrl + '/#/database/' + newDatabaseName + '/new')
-      .waitForElementPresent('.ace_layer.ace_cursor-layer.ace_hidden-cursors', 
waitTime, false)
+      .waitForElementPresent('.ace_gutter-active-line', waitTime, false)
 
       // confirm the header elements are showing up
       .waitForElementVisible('.js-lastelement', waitTime, true)

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/efc2a1e2/app/addons/fauxton/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/fauxton/components.react.jsx 
b/app/addons/fauxton/components.react.jsx
index 784c514..3cae556 100644
--- a/app/addons/fauxton/components.react.jsx
+++ b/app/addons/fauxton/components.react.jsx
@@ -15,12 +15,15 @@ define([
   'api',
   'react',
   'addons/fauxton/dependencies/ZeroClipboard',
+  'libs/react-bootstrap',
 
   // needed to run the test individually. Don't remove
   'velocity.ui'
 ],
 
-function (app, FauxtonAPI, React, ZeroClipboard) {
+function (app, FauxtonAPI, React, ZeroClipboard, ReactBootstrap) {
+
+  var Modal = ReactBootstrap.Modal;
 
 
   // the path to the swf depends on whether we're in a bundled environment 
(e.g. prod) or local
@@ -339,32 +342,22 @@ function (app, FauxtonAPI, React, ZeroClipboard) {
       };
     },
 
-    componentDidUpdate: function () {
-      var params = (this.props.visible) ? { show: true, backdrop: 'static', 
keyboard: true } : 'hide';
-      $(React.findDOMNode(this)).modal(params);
-
-      $(React.findDOMNode(this)).on('hidden.bs.modal', function () {
-        this.props.onClose();
-      }.bind(this));
-    },
-
     render: function () {
       return (
-        <div className="modal hide confirmation-modal fade" tabIndex="-1" 
data-js-visible={this.props.visible}>
-          <div className="modal-header">
-            <button type="button" className="close" 
onClick={this.props.onClose} aria-hidden="true">&times;</button>
-            <h3>{this.props.title}</h3>
-          </div>
-          <div className="modal-body">
+        <Modal dialogClassName="confirmation-modal" show={this.props.visible} 
onHide={this.props.onClose}>
+          <Modal.Header closeButton={true}>
+            <Modal.Title>{this.props.title}</Modal.Title>
+          </Modal.Header>
+          <Modal.Body>
             <p>
               {this.props.text}
             </p>
-          </div>
-          <div className="modal-footer">
+          </Modal.Body>
+          <Modal.Footer>
             <button className="btn" onClick={this.props.onClose}><i 
className="icon fonticon-cancel-circled"></i> Cancel</button>
             <button className="btn btn-success js-btn-success" 
onClick={this.props.onSubmit}><i className="fonticon-ok-circled"></i> 
Okay</button>
-          </div>
-        </div>
+          </Modal.Footer>
+        </Modal>
       );
     }
   });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/efc2a1e2/assets/less/fauxton.less
----------------------------------------------------------------------
diff --git a/assets/less/fauxton.less b/assets/less/fauxton.less
index 2d66676..f71cf57 100644
--- a/assets/less/fauxton.less
+++ b/assets/less/fauxton.less
@@ -601,6 +601,11 @@ footer.pagination-footer {
   z-index: 6;
 }
 
+.modal-title {
+  font-size: 22px;
+  margin: 0;
+  line-height: 30px;
+}
 
 // left navigationbar is opened
 @media (max-width: 780px) {

Reply via email to