couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gar...@apache.org
Subject [couchdb-fauxton] 02/02: convert createClass to class Components
Date Wed, 04 Oct 2017 16:49:45 GMT
This is an automated email from the ASF dual-hosted git repository.

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

commit 9502ee937090e6ad097019154567013190b09f7a
Author: Garren Smith <garren.smith@gmail.com>
AuthorDate: Tue Oct 3 14:45:06 2017 +0200

    convert createClass to class Components
---
 app/addons/activetasks/components.js               | 227 +++++++++----------
 app/addons/cluster/cluster.js                      |  29 ++-
 app/addons/components/components/badge.js          |  51 ++---
 app/addons/components/components/beautify.js       |  26 +--
 app/addons/components/components/bulkaction.js     |  51 ++---
 app/addons/components/components/codeeditor.js     | 244 ++++++++++----------
 .../components/components/codeeditorpanel.js       |  93 ++++----
 app/addons/components/components/confirmbutton.js  |  34 ++-
 .../components/components/deletedatabasemodal.js   |  47 ++--
 app/addons/components/components/document.js       |  44 ++--
 app/addons/components/components/menudropdown.js   |  31 ++-
 .../components/components/paddedborderbox.js       |   6 +-
 .../components/components/stringeditmodal.js       |  43 ++--
 app/addons/components/components/styledselect.js   |  10 +-
 .../components/components/toggleheaderbutton.js    |  30 ++-
 app/addons/components/components/tray.js           |  95 ++++----
 app/addons/components/components/zenmodeoverlay.js |  71 +++---
 app/addons/config/components.js                    | 221 +++++++++---------
 app/addons/databases/components.js                 | 155 ++++++-------
 app/addons/databases/tests/componentsSpec.js       |  25 ++-
 app/addons/documents/designdocinfo/components.js   |  32 ++-
 app/addons/documents/doc-editor/components.js      | 197 ++++++++---------
 .../doc-editor/tests/doc-editor.componentsSpec.js  |   7 +-
 app/addons/documents/sidebar/sidebar.js            | 181 +++++++--------
 app/addons/fauxton/components.js                   | 109 +++++----
 app/addons/fauxton/navigation/container/NavBar.js  |  30 ++-
 app/addons/fauxton/notifications/notifications.js  | 169 +++++++-------
 .../permissions/components/PermissionsSection.js   |  67 +++---
 app/addons/setup/setup.js                          | 246 ++++++++++-----------
 app/addons/verifyinstall/components.js             |  58 +++--
 assets/less/fauxton.less                           |  11 +
 31 files changed, 1252 insertions(+), 1388 deletions(-)

diff --git a/app/addons/activetasks/components.js b/app/addons/activetasks/components.js
index f17b56e..91b477e 100644
--- a/app/addons/activetasks/components.js
+++ b/app/addons/activetasks/components.js
@@ -22,9 +22,8 @@ const {TabElement, TabElementWrapper, Polling} = Components;
 
 const activeTasksStore = Stores.activeTasksStore;
 
-export const ActiveTasksController = React.createClass({
-
-  getStoreState () {
+export class ActiveTasksController extends React.Component {
+  getStoreState = () => {
     return {
       collection: activeTasksStore.getCollection(),
       searchTerm: activeTasksStore.getSearchTerm(),
@@ -34,38 +33,36 @@ export const ActiveTasksController = React.createClass({
       headerIsAscending: activeTasksStore.getHeaderIsAscending()
 
     };
-  },
-
-  getInitialState () {
-    return this.getStoreState();
-  },
+  };
 
-  componentDidMount () {
+  componentDidMount() {
     Actions.init(new Resources.AllTasks());
     activeTasksStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount () {
+  componentWillUnmount() {
     activeTasksStore.off('change', this.onChange, this);
-  },
+  }
 
-  onChange () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
 
-  setNewSearchTerm (searchTerm) {
+  setNewSearchTerm = (searchTerm) => {
     Actions.setSearchTerm(searchTerm);
-  },
+  };
 
-  switchTab (newRadioButton) {  //tabs buttons
+  switchTab = (newRadioButton) => {  //tabs buttons
     Actions.switchTab(newRadioButton);
-  },
+  };
 
-  tableHeaderOnClick (headerClicked) {
+  tableHeaderOnClick = (headerClicked) => {
     Actions.sortByColumnHeader(headerClicked);
-  },
+  };
+
+  state = this.getStoreState();
 
-  render () {
+  render() {
     const {collection, searchTerm, selectedRadio, sortByHeader, headerIsAscending} = this.state;
 
     const setSearchTerm = this.setNewSearchTerm;
@@ -90,31 +87,29 @@ export const ActiveTasksController = React.createClass({
       </div>
     );
   }
-});
-
-var ActiveTasksFilterTabs = React.createClass({
-  getDefaultProps () {
-    return {
-      radioNames : [
-        'All Tasks',
-        'Replication',
-        'Database Compaction',
-        'Indexer',
-        'View Compaction'
-      ]
-    };
-  },
-
-  checked (radioName) {
+}
+
+class ActiveTasksFilterTabs extends React.Component {
+  static defaultProps = {
+    radioNames : [
+      'All Tasks',
+      'Replication',
+      'Database Compaction',
+      'Indexer',
+      'View Compaction'
+    ]
+  };
+
+  checked = (radioName) => {
     return this.props.selectedRadio === radioName;
-  },
+  };
 
-  onRadioClick (e) {
+  onRadioClick = (e) => {
     var radioName = e.target.value;
     this.props.onRadioClick(radioName);
-  },
+  };
 
-  createFilterTabs () {
+  createFilterTabs = () => {
     return (
       this.props.radioNames.map((radioName, i) => {
         const checked = this.checked(radioName);
@@ -128,14 +123,14 @@ var ActiveTasksFilterTabs = React.createClass({
         );
       })
     );
-  },
+  };
 
-  searchTermChange (e) {
+  searchTermChange = (e) => {
     var searchTerm = e.target.value;
     this.props.onSearch(searchTerm);
-  },
+  };
 
-  render () {
+  render() {
     const filterTabs = this.createFilterTabs();
     return (
       <TabElementWrapper>
@@ -153,10 +148,10 @@ var ActiveTasksFilterTabs = React.createClass({
       </TabElementWrapper>
     );
   }
-});
+}
 
-var ActiveTaskTable = React.createClass({
-  render () {
+class ActiveTaskTable extends React.Component {
+  render() {
     var collection = this.props.collection;
     var selectedRadio = this.props.selectedRadio;
     var searchTerm = this.props.searchTerm;
@@ -179,23 +174,21 @@ var ActiveTaskTable = React.createClass({
       </div>
     );
   }
-});
-
-var ActiveTasksTableHeader = React.createClass({
-  getDefaultProps () {
-    return {
-      headerNames : [
-        ['type', 'Type'],
-        ['database', 'Database'],
-        ['started-on', 'Started on'],
-        ['updated-on', 'Updated on'],
-        ['pid', 'PID'],
-        ['progress', 'Status']
-      ]
-    };
-  },
-
-  createTableHeadingFields () {
+}
+
+class ActiveTasksTableHeader extends React.Component {
+  static defaultProps = {
+    headerNames : [
+      ['type', 'Type'],
+      ['database', 'Database'],
+      ['started-on', 'Started on'],
+      ['updated-on', 'Updated on'],
+      ['pid', 'PID'],
+      ['progress', 'Status']
+    ]
+  };
+
+  createTableHeadingFields = () => {
     var onTableHeaderClick = this.props.onTableHeaderClick;
     var sortByHeader = this.props.sortByHeader;
     var headerIsAscending = this.props.headerIsAscending;
@@ -208,19 +201,19 @@ var ActiveTasksTableHeader = React.createClass({
         sortByHeader={sortByHeader}
         headerIsAscending={headerIsAscending} />;
     });
-  },
+  };
 
-  render () {
+  render() {
     return (
       <thead>
         <tr>{this.createTableHeadingFields()}</tr>
       </thead>
     );
   }
-});
+}
 
-var TableHeader = React.createClass({
-  arrow () {
+class TableHeader extends React.Component {
+  arrow = () => {
     var sortBy = this.props.sortByHeader;
     var currentName = this.props.headerName;
     var headerIsAscending = this.props.headerIsAscending;
@@ -229,14 +222,14 @@ var TableHeader = React.createClass({
     if (sortBy === currentName) {
       return <i className={arrow}></i>;
     }
-  },
+  };
 
-  onTableHeaderClick (e) {
+  onTableHeaderClick = (e) => {
     var headerSelected = e.target.value;
     this.props.onTableHeaderClick(headerSelected);
-  },
+  };
 
-  render () {
+  render() {
     var arrow = this.arrow();
     var th_class = 'header-field ' + this.props.headerName;
 
@@ -257,27 +250,22 @@ var TableHeader = React.createClass({
       </td>
     );
   }
-});
-
-var ActiveTasksTableBody = React.createClass({
+}
 
-  getStoreState () {
+class ActiveTasksTableBody extends React.Component {
+  getStoreState = () => {
     return {
       filteredTable: activeTasksStore.getFilteredTable(this.props.collection)
     };
-  },
-
-  getInitialState () {
-    return this.getStoreState();
-  },
+  };
 
-  componentWillReceiveProps () {
+  componentWillReceiveProps() {
     this.setState({
       filteredTable: activeTasksStore.getFilteredTable(this.props.collection)
     });
-  },
+  }
 
-  createRows () {
+  createRows = () => {
     var isThereASearchTerm = this.props.searchTerm.trim() === "";
 
     if (this.state.filteredTable.length === 0) {
@@ -287,9 +275,9 @@ var ActiveTasksTableBody = React.createClass({
     return _.map(this.state.filteredTable, function (item, key) {
       return <ActiveTaskTableBodyContents key={key} item={item} />;
     });
-  },
+  };
 
-  noActiveTasks () {
+  noActiveTasks = () => {
     var type = this.props.selectedRadio;
     if (type === "All Tasks") {
       type = "";
@@ -300,9 +288,9 @@ var ActiveTasksTableBody = React.createClass({
         <td  colSpan="6">No active {type} tasks.</td>
       </tr>
     );
-  },
+  };
 
-  noActiveTasksMatchFilter () {
+  noActiveTasksMatchFilter = () => {
     var type = this.props.selectedRadio;
     if (type === "All Tasks") {
       type = "";
@@ -313,19 +301,21 @@ var ActiveTasksTableBody = React.createClass({
         <td colSpan="6">No active {type} tasks match with filter: "{this.props.searchTerm}"</td>
       </tr>
     );
-  },
+  };
+
+  state = this.getStoreState();
 
-  render () {
+  render() {
     return (
       <tbody className="js-tasks-go-here">
       {this.createRows()}
       </tbody>
     );
   }
-});
+}
 
-var ActiveTaskTableBodyContents = React.createClass({
-  getInfo (item) {
+class ActiveTaskTableBodyContents extends React.Component {
+  getInfo = (item) => {
     return {
       type : item.type,
       objectField: activeTasksHelpers.getDatabaseFieldMessage(item),
@@ -334,9 +324,9 @@ var ActiveTaskTableBodyContents = React.createClass({
       pid: item.pid.replace(/[<>]/g, ''),
       progress: activeTasksHelpers.getProgressMessage(item),
     };
-  },
+  };
 
-  multilineMessage (messageArray, optionalClassName) {
+  multilineMessage = (messageArray, optionalClassName) => {
 
     if (!optionalClassName) {
       optionalClassName = '';
@@ -346,9 +336,9 @@ var ActiveTaskTableBodyContents = React.createClass({
     return messageArray.map(function (msgLine, iterator) {
       return <p key={iterator} className={cssClasses}>{msgLine}</p>;
     });
-  },
+  };
 
-  render () {
+  render() {
     var rowData =  this.getInfo(this.props.item);
     var objectFieldMsg = this.multilineMessage(rowData.objectField, 'to-from-database');
     var startedOnMsg = this.multilineMessage(rowData.started_on, 'time');
@@ -366,41 +356,38 @@ var ActiveTaskTableBodyContents = React.createClass({
       </tr>
     );
   }
-});
-
-export const ActiveTasksPollingWidgetController = React.createClass({
+}
 
-  getStoreState () {
+export class ActiveTasksPollingWidgetController extends React.Component {
+  getStoreState = () => {
     return {
       collection:  activeTasksStore.getBackboneCollection()
     };
-  },
+  };
 
-  getInitialState () {
-    return this.getStoreState();
-  },
-
-  componentDidMount () {
+  componentDidMount() {
     activeTasksStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount () {
+  componentWillUnmount() {
     activeTasksStore.off('change', this.onChange, this);
-  },
+  }
 
-  onChange () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
 
-  runPollingUpdate () {
+  runPollingUpdate = () => {
     Actions.runPollingUpdate(this.state.collection);
-  },
+  };
 
-  getPluralForLabel () {
+  getPluralForLabel = () => {
     return this.state.pollingInterval === "1" ? '' : 's';
-  },
+  };
+
+  state = this.getStoreState();
 
-  render () {
+  render() {
     return (
       <div className="active-tasks__polling-wrapper">
         <Polling
@@ -414,7 +401,7 @@ export const ActiveTasksPollingWidgetController = React.createClass({
       </div>
     );
   }
-});
+}
 
 var activeTasksHelpers = {
   getTimeInfo (timeStamp) {
diff --git a/app/addons/cluster/cluster.js b/app/addons/cluster/cluster.js
index 609e866..625e866 100644
--- a/app/addons/cluster/cluster.js
+++ b/app/addons/cluster/cluster.js
@@ -16,31 +16,28 @@ import ClusterStore from "./cluster.stores";
 var nodesStore = ClusterStore.nodesStore;
 
 
-var DisabledConfigController = React.createClass({
-
-  getStoreState: function () {
+class DisabledConfigController extends React.Component {
+  getStoreState = () => {
     return {
       nodes: nodesStore.getNodes()
     };
-  },
-
-  getInitialState: function () {
-    return this.getStoreState();
-  },
+  };
 
-  componentDidMount: function () {
+  componentDidMount() {
     nodesStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount: function () {
+  componentWillUnmount() {
     nodesStore.off('change', this.onChange);
-  },
+  }
 
-  onChange: function () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
+
+  state = this.getStoreState();
 
-  render: function () {
+  render() {
     return (
       <div className="config-warning-cluster-wrapper">
         <div className="config-warning-cluster-container">
@@ -62,7 +59,7 @@ var DisabledConfigController = React.createClass({
       </div>
     );
   }
-});
+}
 
 var Views = {
   DisabledConfigController: DisabledConfigController
diff --git a/app/addons/components/components/badge.js b/app/addons/components/components/badge.js
index 356d0fb..47dd2e5 100644
--- a/app/addons/components/components/badge.js
+++ b/app/addons/components/components/badge.js
@@ -15,26 +15,23 @@ import PropTypes from 'prop-types';
 import React from "react";
 import ReactDOM from "react-dom";
 
-export const BadgeList = React.createClass({
-
-  propTypes: {
+export class BadgeList extends React.Component {
+  static propTypes = {
     elements: PropTypes.array.isRequired,
     removeBadge: PropTypes.func.isRequired
-  },
+  };
 
-  getDefaultProps () {
-    return {
-      getLabel (el) {
-        return el;
-      },
+  static defaultProps = {
+    getLabel (el) {
+      return el;
+    },
 
-      getId (el) {
-        return el;
-      }
-    };
-  },
+    getId (el) {
+      return el;
+    }
+  };
 
-  getBadges () {
+  getBadges = () => {
     return this.props.elements.map(function (el, i) {
       return <Badge
         label={this.props.getLabel(el)}
@@ -42,33 +39,33 @@ export const BadgeList = React.createClass({
         id={el}
         remove={this.removeBadge} />;
     }.bind(this));
-  },
+  };
 
-  removeBadge (label, el) {
+  removeBadge = (label, el) => {
     this.props.removeBadge(label, el);
-  },
+  };
 
-  render () {
+  render() {
     return (
       <ul className="component-badgelist">
         {this.getBadges()}
       </ul>
     );
   }
-});
+}
 
-export const Badge = React.createClass({
-  propTypes: {
+export class Badge extends React.Component {
+  static propTypes = {
     label: PropTypes.string.isRequired,
     remove: PropTypes.func.isRequired
-  },
+  };
 
-  remove (e) {
+  remove = (e) => {
     e.preventDefault();
     this.props.remove(this.props.label, this.props.id);
-  },
+  };
 
-  render () {
+  render() {
     return (
       <li className="component-badge">
         <span className="label label-info">{this.props.label}</span>
@@ -82,4 +79,4 @@ export const Badge = React.createClass({
       </li>
     );
   }
-});
+}
diff --git a/app/addons/components/components/beautify.js b/app/addons/components/components/beautify.js
index 8773cf2..1da7901 100644
--- a/app/addons/components/components/beautify.js
+++ b/app/addons/components/components/beautify.js
@@ -13,33 +13,33 @@ import React from "react";
 import ReactDOM from "react-dom";
 import beautifyHelper from "../../../../assets/js/plugins/beautify";
 
-export const Beautify = React.createClass({
-  noOfLines () {
+export class Beautify extends React.Component {
+  noOfLines = () => {
     return this.props.code.split(/\r\n|\r|\n/).length;
-  },
+  };
 
-  canBeautify () {
+  canBeautify = () => {
     return this.noOfLines() === 1;
-  },
+  };
 
-  addTooltip () {
+  addTooltip = () => {
     if (this.canBeautify) {
       $('.beautify-tooltip').tooltip({ placement: 'right' });
     }
-  },
+  };
 
-  componentDidMount () {
+  componentDidMount() {
     this.addTooltip();
-  },
+  }
 
-  beautify (event) {
+  beautify = (event) => {
     event.preventDefault();
     var beautifiedCode = beautifyHelper(this.props.code);
     this.props.beautifiedCode(beautifiedCode);
     $('.beautify-tooltip').tooltip('hide');
-  },
+  };
 
-  render () {
+  render() {
     if (!this.canBeautify()) {
       return null;
     }
@@ -56,4 +56,4 @@ export const Beautify = React.createClass({
       </button>
     );
   }
-});
+}
diff --git a/app/addons/components/components/bulkaction.js b/app/addons/components/components/bulkaction.js
index 6c2ea8a..12958be 100644
--- a/app/addons/components/components/bulkaction.js
+++ b/app/addons/components/components/bulkaction.js
@@ -16,29 +16,26 @@ import React from "react";
 import ReactDOM from "react-dom";
 import {OverlayTrigger, Popover} from "react-bootstrap";
 
-export const BulkActionComponent = React.createClass({
-
-  propTypes: {
+export class BulkActionComponent extends React.Component {
+  static propTypes = {
     hasSelectedItem: PropTypes.bool.isRequired,
     removeItem: PropTypes.func.isRequired,
     selectAll: PropTypes.func,
     toggleSelect: PropTypes.func.isRequired,
     isChecked: PropTypes.bool.isRequired,
     disabled: PropTypes.bool
-  },
+  };
 
-  getDefaultProps () {
-    return {
-      disabled: false,
-      title: 'Select rows that can be...',
-      bulkIcon: 'fonticon-trash',
-      buttonTitle: 'Delete all selected',
-      dropdownContentText: 'Deleted',
-      enableOverlay: false
-    };
-  },
+  static defaultProps = {
+    disabled: false,
+    title: 'Select rows that can be...',
+    bulkIcon: 'fonticon-trash',
+    buttonTitle: 'Delete all selected',
+    dropdownContentText: 'Deleted',
+    enableOverlay: false
+  };
 
-  render () {
+  render() {
     return (
       <div className="bulk-action-component">
         <div className="bulk-action-component-selector-group">
@@ -47,9 +44,9 @@ export const BulkActionComponent = React.createClass({
         </div>
       </div>
     );
-  },
+  }
 
-  getMultiSelectOptions () {
+  getMultiSelectOptions = () => {
     if (!this.props.hasSelectedItem) {
       return null;
     }
@@ -60,9 +57,9 @@ export const BulkActionComponent = React.createClass({
         className={'fonticon ' + this.props.bulkIcon}
         title={this.props.buttonTitle} />
     );
-  },
+  };
 
-  getPopupContent () {
+  getPopupContent = () => {
     return (
       <ul className="bulk-action-component-popover-actions">
         <li onClick={this.selectAll} >
@@ -70,14 +67,14 @@ export const BulkActionComponent = React.createClass({
         </li>
       </ul>
     );
-  },
+  };
 
-  selectAll () {
+  selectAll = () => {
     this.refs.bulkActionPopover.hide();
     this.props.selectAll();
-  },
+  };
 
-  getOverlay () {
+  getOverlay = () => {
     return (
       <OverlayTrigger
         ref="bulkActionPopover"
@@ -94,9 +91,9 @@ export const BulkActionComponent = React.createClass({
         </div>
       </OverlayTrigger>
     );
-  },
+  };
 
-  getMasterSelector () {
+  getMasterSelector = () => {
     return (
       <div className="bulk-action-component-panel">
         <input type="checkbox"
@@ -107,5 +104,5 @@ export const BulkActionComponent = React.createClass({
         {this.props.enableOverlay ? this.getOverlay() : null}
       </div>
     );
-  },
-});
+  };
+}
diff --git a/app/addons/components/components/codeeditor.js b/app/addons/components/components/codeeditor.js
index 010ab42..b2bd8b6 100644
--- a/app/addons/components/components/codeeditor.js
+++ b/app/addons/components/components/codeeditor.js
@@ -19,69 +19,65 @@ require('brace/mode/javascript');
 require('brace/mode/json');
 require('brace/theme/idle_fingers');
 
-export const CodeEditor = React.createClass({
-  getDefaultProps () {
-    return {
-      id: 'code-editor',
-      mode: 'javascript',
-      theme: 'idle_fingers',
-      fontSize: 13,
-
-      // this sets the default value for the editor. On the fly changes are stored in state in this component only. To
-      // change the editor content after initial construction use CodeEditor.setValue()
-      defaultCode: '',
-
-      showGutter: true,
-      highlightActiveLine: true,
-      showPrintMargin: false,
-      autoScrollEditorIntoView: true,
-      autoFocus: false,
-      stringEditModalEnabled: false,
-
-      // these two options create auto-resizeable code editors, with a maximum number of lines
-      setHeightToLineCount: false,
-      maxLines: 10,
-      minLines: 11, // show double digits in sidebar
-
-      // optional editor key commands (e.g. specific save action)
-      editorCommands: [],
-
-      // notifies users that there is unsaved changes in the editor when navigating away from the page
-      notifyUnsavedChanges: false,
-
-      // an optional array of ignorable Ace errors. Lets us filter out errors based on context
-      ignorableErrors: [],
-
-      // un-Reacty, but the code editor is a self-contained component and it's helpful to be able to tie into
-      // editor specific events like content changes and leaving the editor
-      change () {},
-      blur () {}
-    };
-  },
-
-  getInitialState () {
-    return {
-      originalCode: this.props.defaultCode,
-
-      // these are all related to the (optional) string edit modal
-      stringEditModalVisible: false,
-      stringEditIconVisible: false,
-      stringEditIconStyle: {},
-      stringEditModalValue: ''
-    };
-  },
-
-  hasChanged () {
+export class CodeEditor extends React.Component {
+  static defaultProps = {
+    id: 'code-editor',
+    mode: 'javascript',
+    theme: 'idle_fingers',
+    fontSize: 13,
+
+    // this sets the default value for the editor. On the fly changes are stored in state in this component only. To
+    // change the editor content after initial construction use CodeEditor.setValue()
+    defaultCode: '',
+
+    showGutter: true,
+    highlightActiveLine: true,
+    showPrintMargin: false,
+    autoScrollEditorIntoView: true,
+    autoFocus: false,
+    stringEditModalEnabled: false,
+
+    // these two options create auto-resizeable code editors, with a maximum number of lines
+    setHeightToLineCount: false,
+    maxLines: 10,
+    minLines: 11, // show double digits in sidebar
+
+    // optional editor key commands (e.g. specific save action)
+    editorCommands: [],
+
+    // notifies users that there is unsaved changes in the editor when navigating away from the page
+    notifyUnsavedChanges: false,
+
+    // an optional array of ignorable Ace errors. Lets us filter out errors based on context
+    ignorableErrors: [],
+
+    // un-Reacty, but the code editor is a self-contained component and it's helpful to be able to tie into
+    // editor specific events like content changes and leaving the editor
+    change () {},
+    blur () {}
+  };
+
+  state = {
+    originalCode: this.props.defaultCode,
+
+    // these are all related to the (optional) string edit modal
+    stringEditModalVisible: false,
+    stringEditIconVisible: false,
+    stringEditIconStyle: {},
+    stringEditModalValue: ''
+  };
+
+  hasChanged = () => {
     return !_.isEqual(this.state.originalCode, this.getValue());
-  },
+  };
 
-  clearChanges () {
+  clearChanges = () => {
     this.setState({
       originalCode: this.getValue()
     });
-  },
+  };
 
-  setupAce (props, shouldUpdateCode) {
+  setupAce = (props, shouldUpdateCode) => {
     this.editor = ace.edit(ReactDOM.findDOMNode(this.refs.ace));
 
     // suppresses an Ace editor error
@@ -114,15 +110,15 @@ export const CodeEditor = React.createClass({
     if (this.props.autoFocus) {
       this.editor.focus();
     }
-  },
+  };
 
-  addCommands () {
+  addCommands = () => {
     _.each(this.props.editorCommands, function (command) {
       this.editor.commands.addCommand(command);
     }, this);
-  },
+  };
 
-  setupEvents () {
+  setupEvents = () => {
     this.editor.on('blur', _.bind(this.onBlur, this));
     this.editor.on('change', _.bind(this.onContentChange, this));
 
@@ -136,68 +132,68 @@ export const CodeEditor = React.createClass({
       $(window).on('beforeunload.editor_' + this.props.id, _.bind(this.quitWarningMsg));
       FauxtonAPI.beforeUnload('editor_' + this.props.id, _.bind(this.quitWarningMsg, this));
     }
-  },
+  };
 
-  onBlur () {
+  onBlur = () => {
     this.props.blur(this.getValue());
-  },
+  };
 
-  onContentChange () {
+  onContentChange = () => {
     if (this.props.setHeightToLineCount) {
       this.setHeightToLineCount();
     }
     this.props.change(this.getValue());
-  },
+  };
 
-  quitWarningMsg () {
+  quitWarningMsg = () => {
     if (this.hasChanged()) {
       return 'Your changes have not been saved. Click Cancel to return to the document, or OK to proceed.';
     }
-  },
+  };
 
-  removeEvents () {
+  removeEvents = () => {
     if (this.props.notifyUnsavedChanges) {
       $(window).off('beforeunload.editor_' + this.props.id);
       FauxtonAPI.removeBeforeUnload('editor_' + this.props.id);
     }
-  },
+  };
 
-  setHeightToLineCount () {
+  setHeightToLineCount = () => {
     var numLines = this.editor.getSession().getDocument().getLength();
     var maxLines = (numLines > this.props.maxLines) ? this.props.maxLines : numLines;
     this.editor.setOptions({
       maxLines: maxLines,
       minLines: this.props.minLines
     });
-  },
+  };
 
-  componentDidMount () {
+  componentDidMount() {
     this.setupAce(this.props, true);
     this.setupEvents();
 
     if (this.props.autoFocus) {
       this.editor.focus();
     }
-  },
+  }
 
-  componentWillUnmount () {
+  componentWillUnmount() {
     this.removeEvents();
     this.editor.destroy();
-  },
+  }
 
-  componentWillReceiveProps (nextProps) {
+  componentWillReceiveProps(nextProps) {
     this.setupAce(nextProps, false);
-  },
+  }
 
-  getAnnotations () {
+  getAnnotations = () => {
     return this.editor.getSession().getAnnotations();
-  },
+  };
 
-  isIgnorableError (msg) {
+  isIgnorableError = (msg) => {
     return _.includes(this.props.ignorableErrors, msg);
-  },
+  };
 
-  removeIgnorableAnnotations () {
+  removeIgnorableAnnotations = () => {
     var isIgnorableError = this.isIgnorableError;
     this.editor.getSession().on('changeAnnotation', function () {
       var annotations = this.editor.getSession().getAnnotations();
@@ -212,9 +208,9 @@ export const CodeEditor = React.createClass({
         this.editor.getSession().setAnnotations(newAnnotations);
       }
     }.bind(this));
-  },
+  };
 
-  showHideEditStringGutterIcon () {
+  showHideEditStringGutterIcon = () => {
     if (this.hasErrors() || !this.parseLineForStringMatch()) {
       this.setState({ stringEditIconVisible: false });
       return false;
@@ -228,9 +224,9 @@ export const CodeEditor = React.createClass({
     });
 
     return true;
-  },
+  };
 
-  updateEditStringGutterIconPosition () {
+  updateEditStringGutterIconPosition = () => {
     if (!this.state.stringEditIconVisible) {
       return;
     }
@@ -239,16 +235,16 @@ export const CodeEditor = React.createClass({
         top: this.getGutterIconPosition()
       }
     });
-  },
+  };
 
-  getGutterIconPosition () {
+  getGutterIconPosition = () => {
     var rowHeight = this.getRowHeight();
     var scrollTop = this.editor.session.getScrollTop();
     var positionFromTop = (rowHeight * this.documentToScreenRow(this.getSelectionStart().row)) - scrollTop;
     return positionFromTop + 'px';
-  },
+  };
 
-  parseLineForStringMatch () {
+  parseLineForStringMatch = () => {
     var selStart = this.getSelectionStart().row;
     var selEnd   = this.getSelectionEnd().row;
 
@@ -262,9 +258,9 @@ export const CodeEditor = React.createClass({
       }
     }
     return false;
-  },
+  };
 
-  openStringEditModal () {
+  openStringEditModal = () => {
     var matches = this.parseLineForStringMatch();
     var string = matches[3];
     var lastChar = string.length - 1;
@@ -277,9 +273,9 @@ export const CodeEditor = React.createClass({
       stringEditModalVisible: true,
       stringEditModalValue: string
     });
-  },
+  };
 
-  saveStringEditModal (newString) {
+  saveStringEditModal = (newString) => {
     // replace the string on the selected line
     var line = this.parseLineForStringMatch();
     var indent = line[1] || '',
@@ -291,68 +287,68 @@ export const CodeEditor = React.createClass({
     }
     this.replaceCurrentLine(indent + key + JSON.stringify(newString) + comma + '\n');
     this.closeStringEditModal();
-  },
+  };
 
-  closeStringEditModal () {
+  closeStringEditModal = () => {
     this.setState({
       stringEditModalVisible: false
     });
-  },
+  };
 
-  hasErrors () {
+  hasErrors = () => {
     return !_.every(this.getAnnotations(), function (error) {
       return this.isIgnorableError(error.raw);
     }, this);
-  },
+  };
 
-  setReadOnly (readonly) {
+  setReadOnly = (readonly) => {
     this.editor.setReadOnly(readonly);
-  },
+  };
 
-  setValue (code, lineNumber) {
+  setValue = (code, lineNumber) => {
     lineNumber = lineNumber ? lineNumber : -1;
     this.editor.setValue(code, lineNumber);
-  },
+  };
 
-  getValue () {
+  getValue = () => {
     return this.editor.getValue();
-  },
+  };
 
-  getEditor () {
+  getEditor = () => {
     return this;
-  },
+  };
 
-  getLine (lineNum) {
+  getLine = (lineNum) => {
     return this.editor.session.getLine(lineNum);
-  },
+  };
 
-  getSelectionStart () {
+  getSelectionStart = () => {
     return this.editor.getSelectionRange().start;
-  },
+  };
 
-  getSelectionEnd () {
+  getSelectionEnd = () => {
     return this.editor.getSelectionRange().end;
-  },
+  };
 
-  getRowHeight () {
+  getRowHeight = () => {
     return this.editor.renderer.layerConfig.lineHeight;
-  },
+  };
 
-  isRowExpanded (row) {
+  isRowExpanded = (row) => {
     return !this.editor.getSession().isRowFolded(row);
-  },
+  };
 
-  documentToScreenRow (row) {
+  documentToScreenRow = (row) => {
     return this.editor.getSession().documentToScreenRow(row, 0);
-  },
+  };
 
-  replaceCurrentLine (replacement) {
+  replaceCurrentLine = (replacement) => {
     this.editor.getSelection().selectLine();
     this.editor.insert(replacement);
     this.editor.getSelection().moveCursorUp();
-  },
+  };
 
-  render () {
+  render() {
     return (
       <div>
         <div ref="ace" className="js-editor" id={this.props.id}></div>
@@ -369,4 +365,4 @@ export const CodeEditor = React.createClass({
       </div>
     );
   }
-});
+}
diff --git a/app/addons/components/components/codeeditorpanel.js b/app/addons/components/components/codeeditorpanel.js
index 4ee89f5..714304d 100644
--- a/app/addons/components/components/codeeditorpanel.js
+++ b/app/addons/components/components/codeeditorpanel.js
@@ -15,53 +15,48 @@ import {CodeEditor} from './codeeditor';
 import {Beautify} from './beautify';
 import {ZenModeOverlay} from './zenmodeoverlay';
 
+
+  // list of JSHINT errors to ignore: gets around problem of anonymous functions not being valid
+const ignorableErrors = [
+    'Missing name in function declaration.',
+    "['{a}'] is better written in dot notation."
+  ];
+
 /**
  * A pre-packaged JS editor panel for use on the Edit Index / Mango pages. Includes options for a title, zen mode
  * icon and beautify button.
  */
-export const CodeEditorPanel = React.createClass({
-  getDefaultProps () {
-    return {
-      id: 'code-editor',
-      className: '',
-      defaultCode: '',
-      title: '',
-      docLink: '',
-      allowZenMode: true,
-      blur () {}
-    };
-  },
+export class CodeEditorPanel extends React.Component {
+  static defaultProps = {
+    id: 'code-editor',
+    className: '',
+    defaultCode: '',
+    title: '',
+    docLink: '',
+    allowZenMode: true,
+    blur () {}
+  };
 
-  getInitialState () {
-    return this.getStoreState();
-  },
-
-  getStoreState () {
+  getStoreState = () => {
     return {
       zenModeEnabled: false,
       code: this.props.defaultCode
     };
-  },
+  };
 
-  componentWillReceiveProps (nextProps) {
+  componentWillReceiveProps(nextProps) {
     if (nextProps.defaultCode !== this.props.defaultCode) {
       this.setState({ code: nextProps.defaultCode });
     }
-  },
-
-  // list of JSHINT errors to ignore: gets around problem of anonymous functions not being valid
-  ignorableErrors: [
-    'Missing name in function declaration.',
-    "['{a}'] is better written in dot notation."
-  ],
+  }
 
-  getZenModeIcon () {
+  getZenModeIcon = () => {
     if (this.props.allowZenMode) {
       return <span className="fonticon fonticon-resize-full zen-editor-icon" title="Enter Zen mode" onClick={this.enterZenMode}></span>;
     }
-  },
+  };
 
-  getDocIcon () {
+  getDocIcon = () => {
     if (this.props.docLink) {
       return (
         <a className="help-link"
@@ -73,50 +68,52 @@ export const CodeEditorPanel = React.createClass({
         </a>
       );
     }
-  },
+  };
 
-  getZenModeOverlay () {
+  getZenModeOverlay = () => {
     if (this.state.zenModeEnabled) {
       return (
         <ZenModeOverlay
           defaultCode={this.state.code}
           mode={this.props.mode}
-          ignorableErrors={this.ignorableErrors}
+          ignorableErrors={ignorableErrors}
           onExit={this.exitZenMode} />
       );
     }
-  },
+  };
 
-  enterZenMode () {
+  enterZenMode = () => {
     this.setState({
       zenModeEnabled: true,
       code: this.refs.codeEditor.getValue()
     });
-  },
+  };
 
-  exitZenMode (content) {
+  exitZenMode = (content) => {
     this.setState({ zenModeEnabled: false });
     this.getEditor().setValue(content);
-  },
+  };
 
-  getEditor () {
+  getEditor = () => {
     return this.refs.codeEditor;
-  },
+  };
 
-  getValue () {
+  getValue = () => {
     return this.getEditor().getValue();
-  },
+  };
 
-  beautify (code) {
+  beautify = (code) => {
     this.setState({ code: code });
     this.getEditor().setValue(code);
-  },
+  };
 
-  update () {
+  update = () => {
     this.getEditor().setValue(this.state.code);
-  },
+  };
+
+  state = this.getStoreState();
 
-  render () {
+  render() {
     var classes = 'control-group';
     if (this.props.className) {
       classes += ' ' + this.props.className;
@@ -134,7 +131,7 @@ export const CodeEditorPanel = React.createClass({
           mode="javascript"
           defaultCode={this.state.code}
           showGutter={true}
-          ignorableErrors={this.ignorableErrors}
+          ignorableErrors={ignorableErrors}
           setHeightToLineCount={true}
           maxLines={10000}
           blur={this.props.blur}
@@ -144,4 +141,4 @@ export const CodeEditorPanel = React.createClass({
       </div>
     );
   }
-});
+}
diff --git a/app/addons/components/components/confirmbutton.js b/app/addons/components/components/confirmbutton.js
index 29538e6..1846592 100644
--- a/app/addons/components/components/confirmbutton.js
+++ b/app/addons/components/components/confirmbutton.js
@@ -15,8 +15,8 @@ import PropTypes from 'prop-types';
 import React from "react";
 import ReactDOM from "react-dom";
 
-export const ConfirmButton = React.createClass({
-  propTypes: {
+export class ConfirmButton extends React.Component {
+  static propTypes = {
     showIcon: PropTypes.bool,
     id: PropTypes.string,
     customIcon: PropTypes.string,
@@ -25,30 +25,28 @@ export const ConfirmButton = React.createClass({
     'data-id': PropTypes.string,
     onClick: PropTypes.func,
     disabled: PropTypes.bool,
-  },
+  };
 
-  getDefaultProps () {
-    return {
-      disabled: false,
-      showIcon: true,
-      customIcon: 'fonticon-ok-circled',
-      buttonType: 'btn-primary',
-      style: {},
-      'data-id': null,
-      onClick () { }
-    };
-  },
+  static defaultProps = {
+    disabled: false,
+    showIcon: true,
+    customIcon: 'fonticon-ok-circled',
+    buttonType: 'btn-primary',
+    style: {},
+    'data-id': null,
+    onClick () { }
+  };
 
-  getIcon () {
+  getIcon = () => {
     if (!this.props.showIcon) {
       return null;
     }
     return (
       <i className={"icon " + this.props.customIcon} />
     );
-  },
+  };
 
-  render () {
+  render() {
     const { onClick, buttonType, id, style, text, disabled } = this.props;
     return (
       <button
@@ -65,4 +63,4 @@ export const ConfirmButton = React.createClass({
       </button>
     );
   }
-});
+}
diff --git a/app/addons/components/components/deletedatabasemodal.js b/app/addons/components/components/deletedatabasemodal.js
index bb8e429..e8213fe 100644
--- a/app/addons/components/components/deletedatabasemodal.js
+++ b/app/addons/components/components/deletedatabasemodal.js
@@ -17,21 +17,18 @@ import ReactDOM from "react-dom";
 import {Modal} from "react-bootstrap";
 import Actions from "../actions";
 
-export const DeleteDatabaseModal = React.createClass({
-
-  getInitialState () {
-    return {
-      inputValue: '',
-      disableSubmit: true
-    };
-  },
-
-  propTypes: {
+export class DeleteDatabaseModal extends React.Component {
+  static propTypes = {
     showHide: PropTypes.func.isRequired,
     modalProps: PropTypes.object
-  },
+  };
+
+  state = {
+    inputValue: '',
+    disableSubmit: true
+  };
 
-  close (e) {
+  close = (e) => {
     if (e) {
       e.preventDefault();
     }
@@ -42,17 +39,17 @@ export const DeleteDatabaseModal = React.createClass({
     });
 
     this.props.showHide({showModal: false});
-  },
+  };
 
-  open () {
+  open = () => {
     this.props.showHide({showModal: true});
-  },
+  };
 
-  getDatabaseName () {
+  getDatabaseName = () => {
     return this.props.modalProps.dbId.trim();
-  },
+  };
 
-  onInputChange (e) {
+  onInputChange = (e) => {
     const val = e.target.value.trim();
 
     this.setState({
@@ -62,21 +59,21 @@ export const DeleteDatabaseModal = React.createClass({
     this.setState({
       disableSubmit: val !== this.getDatabaseName()
     });
-  },
+  };
 
-  onDeleteClick (e) {
+  onDeleteClick = (e) => {
     e.preventDefault();
 
     Actions.deleteDatabase(this.getDatabaseName());
-  },
+  };
 
-  onInputKeypress (e) {
+  onInputKeypress = (e) => {
     if (e.keyCode === 13 && this.state.disableSubmit !== true) {
       Actions.deleteDatabase(this.getDatabaseName());
     }
-  },
+  };
 
-  render () {
+  render() {
     var isSystemDatabase = this.props.modalProps.isSystemDatabase;
     var showDeleteModal = this.props.modalProps.showDeleteModal;
     var dbId = this.props.modalProps.dbId;
@@ -118,4 +115,4 @@ export const DeleteDatabaseModal = React.createClass({
       </Modal>
     );
   }
-});
+}
diff --git a/app/addons/components/components/document.js b/app/addons/components/components/document.js
index 68a0b11..6635ee6 100644
--- a/app/addons/components/components/document.js
+++ b/app/addons/components/components/document.js
@@ -16,27 +16,25 @@ import ReactDOM from "react-dom";
 import FauxtonAPI from "../../../core/api";
 import Helpers from "../../documents/helpers";
 
-export const Document = React.createClass({
-  propTypes: {
+export class Document extends React.Component {
+  static propTypes = {
     docIdentifier: PropTypes.string.isRequired,
     docChecked: PropTypes.func.isRequired,
     truncate: PropTypes.bool,
     maxRows: PropTypes.number
-  },
+  };
 
-  getDefaultProps () {
-    return {
-      truncate: true,
-      maxRows: 500
-    };
-  },
+  static defaultProps = {
+    truncate: true,
+    maxRows: 500
+  };
 
-  onChange (e) {
+  onChange = (e) => {
     e.preventDefault();
     this.props.docChecked(this.props.doc.id, this.props.doc._rev);
-  },
+  };
 
-  getUrlFragment () {
+  getUrlFragment = () => {
     if (!this.props.children) {
       return '';
     }
@@ -46,16 +44,16 @@ export const Document = React.createClass({
         {this.props.children}
       </div>
     );
-  },
+  };
 
-  getExtensionIcons () {
+  getExtensionIcons = () => {
     var extensions = FauxtonAPI.getExtensions('DocList:icons');
     return _.map(extensions, function (Extension, i) {
       return (<Extension doc={this.props.doc} key={i} />);
     }, this);
-  },
+  };
 
-  getCheckbox () {
+  getCheckbox = () => {
     if (!this.props.isDeletable) {
       return <div className="checkbox-dummy"></div>;
     }
@@ -74,13 +72,13 @@ export const Document = React.createClass({
           htmlFor={'checkbox-' + this.props.docIdentifier} />
       </div>
     );
-  },
+  };
 
-  onClick (e) {
+  onClick = (e) => {
     this.props.onClick(this.props.docIdentifier, this.props.doc, e);
-  },
+  };
 
-  getDocContent () {
+  getDocContent = () => {
     if (_.isEmpty(this.props.docContent)) {
       return null;
     }
@@ -100,9 +98,9 @@ export const Document = React.createClass({
         {isTruncated ? <div className="doc-content-truncated">(truncated)</div> : null}
       </div>
     );
-  },
+  };
 
-  render () {
+  render() {
     return (
       <div data-id={this.props.docIdentifier} className="doc-row">
         <div className="custom-inputs">
@@ -125,4 +123,4 @@ export const Document = React.createClass({
       </div>
     );
   }
-});
+}
diff --git a/app/addons/components/components/menudropdown.js b/app/addons/components/components/menudropdown.js
index 18127a1..5ef8e7f 100644
--- a/app/addons/components/components/menudropdown.js
+++ b/app/addons/components/components/menudropdown.js
@@ -12,23 +12,20 @@
 import React from "react";
 import ReactDOM from "react-dom";
 
-export const MenuDropDown = React.createClass({
+export class MenuDropDown extends React.Component {
+  static defaultProps = {
+    icon: 'fonticon-plus-circled'
+  };
 
-  getDefaultProps () {
-    return {
-      icon: 'fonticon-plus-circled'
-    };
-  },
-
-  createSectionLinks (links) {
+  createSectionLinks = (links) => {
     if (!links) { return null; }
 
     return links.map((link, key) => {
       return this.createEntry(link, key);
     });
-  },
+  };
 
-  createEntry (link, key) {
+  createEntry = (link, key) => {
     return (
       <li key={key}>
         <a className={link.icon ? 'icon ' + link.icon : ''}
@@ -40,9 +37,9 @@ export const MenuDropDown = React.createClass({
         </a>
       </li>
     );
-  },
+  };
 
-  createSectionTitle (title) {
+  createSectionTitle = (title) => {
     if (!title) {
       return null;
     }
@@ -50,9 +47,9 @@ export const MenuDropDown = React.createClass({
     return (
       <li className="header-label">{title}</li>
     );
-  },
+  };
 
-  createSection () {
+  createSection = () => {
     return this.props.links.map((linkSection, key) => {
       if (linkSection.title && linkSection.links) {
         return ([
@@ -64,9 +61,9 @@ export const MenuDropDown = React.createClass({
       return this.createEntry(linkSection, 'el' + key);
 
     });
-  },
+  };
 
-  render () {
+  render() {
     return (
       <div className="dropdown">
         <a className={"dropdown-toggle icon " + this.props.icon}
@@ -79,4 +76,4 @@ export const MenuDropDown = React.createClass({
       </div>
     );
   }
-});
+}
diff --git a/app/addons/components/components/paddedborderbox.js b/app/addons/components/components/paddedborderbox.js
index 22541fd..2605061 100644
--- a/app/addons/components/components/paddedborderbox.js
+++ b/app/addons/components/components/paddedborderbox.js
@@ -12,8 +12,8 @@
 import React from "react";
 import ReactDOM from "react-dom";
 
-export const PaddedBorderedBox = React.createClass({
-  render: function () {
+export class PaddedBorderedBox extends React.Component {
+  render() {
     return (
       <div className="bordered-box">
         <div className="padded-box">
@@ -22,4 +22,4 @@ export const PaddedBorderedBox = React.createClass({
       </div>
     );
    }
- });
+}
diff --git a/app/addons/components/components/stringeditmodal.js b/app/addons/components/components/stringeditmodal.js
index e718d59..9b8f06f 100644
--- a/app/addons/components/components/stringeditmodal.js
+++ b/app/addons/components/components/stringeditmodal.js
@@ -22,31 +22,28 @@ require('brace/mode/json');
 require('brace/theme/idle_fingers');
 
 // this appears when the cursor is over a string. It shows an icon in the gutter that opens the modal.
-export const StringEditModal = React.createClass({
-
-  propTypes: {
+export class StringEditModal extends React.Component {
+  static propTypes = {
     value: PropTypes.string.isRequired,
     visible: PropTypes.bool.isRequired,
     onClose: PropTypes.func.isRequired,
     onSave: PropTypes.func.isRequired
-  },
+  };
 
-  getDefaultProps () {
-    return {
-      visible: false,
-      onClose () { },
-      onSave () { }
-    };
-  },
+  static defaultProps = {
+    visible: false,
+    onClose () { },
+    onSave () { }
+  };
 
-  componentDidMount () {
+  componentDidMount() {
     if (!this.props.visible) {
       return;
     }
     this.initEditor(this.props.value);
-  },
+  }
 
-  componentDidUpdate (prevProps) {
+  componentDidUpdate(prevProps) {
     if (!this.props.visible) {
       return;
     }
@@ -56,26 +53,26 @@ export const StringEditModal = React.createClass({
     }
 
     this.initEditor(val);
-  },
+  }
 
-  initEditor (val) {
+  initEditor = (val) => {
     this.editor = ace.edit(ReactDOM.findDOMNode(this.refs.stringEditor));
     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');
     this.editor.setValue(val, -1);
-  },
+  };
 
-  closeModal () {
+  closeModal = () => {
     this.props.onClose();
-  },
+  };
 
-  save () {
+  save = () => {
     this.props.onSave(this.editor.getValue());
-  },
+  };
 
-  render () {
+  render() {
     return (
       <Modal dialogClassName="string-editor-modal" show={this.props.visible} onHide={this.closeModal}>
         <Modal.Header closeButton={true}>
@@ -94,4 +91,4 @@ export const StringEditModal = React.createClass({
       </Modal>
     );
   }
-});
+}
diff --git a/app/addons/components/components/styledselect.js b/app/addons/components/components/styledselect.js
index 6cab5be..5a4d5c5 100644
--- a/app/addons/components/components/styledselect.js
+++ b/app/addons/components/components/styledselect.js
@@ -14,14 +14,14 @@ import PropTypes from 'prop-types';
 import React from "react";
 import ReactDOM from "react-dom";
 
-export const StyledSelect = React.createClass({
-  propTypes: {
+export class StyledSelect extends React.Component {
+  static propTypes = {
     selectValue: PropTypes.string.isRequired,
     selectId: PropTypes.string.isRequired,
     selectChange: PropTypes.func.isRequired
-  },
+  };
 
-  render: function () {
+  render() {
     return (
       <div className="styled-select">
         <label htmlFor={this.props.selectId}>
@@ -39,4 +39,4 @@ export const StyledSelect = React.createClass({
       </div>
     );
   }
-});
+}
diff --git a/app/addons/components/components/toggleheaderbutton.js b/app/addons/components/components/toggleheaderbutton.js
index baaf9c4..b092784 100644
--- a/app/addons/components/components/toggleheaderbutton.js
+++ b/app/addons/components/components/toggleheaderbutton.js
@@ -13,22 +13,20 @@
 import React from "react";
 import ReactDOM from "react-dom";
 
-export const ToggleHeaderButton = React.createClass({
-  getDefaultProps () {
-    return {
-      innerClasses: '',
-      fonticon: '',
-      containerClasses: '',
-      selected: false,
-      title: '',
-      disabled: false,
-      toggleCallback: null,
-      text: '',
-      iconDefaultClass: 'icon'
-    };
-  },
+export class ToggleHeaderButton extends React.Component {
+  static defaultProps = {
+    innerClasses: '',
+    fonticon: '',
+    containerClasses: '',
+    selected: false,
+    title: '',
+    disabled: false,
+    toggleCallback: null,
+    text: '',
+    iconDefaultClass: 'icon'
+  };
 
-  render () {
+  render() {
     const { iconDefaultClass, fonticon, innerClasses, selected, containerClasses, title, disabled, text, toggleCallback, active } = this.props;
     const selectedBtnClass = (selected || active) ? 'js-headerbar-togglebutton-selected' : '';
 
@@ -43,4 +41,4 @@ export const ToggleHeaderButton = React.createClass({
       </button>
     );
   }
-});
+}
diff --git a/app/addons/components/components/tray.js b/app/addons/components/components/tray.js
index a106409..41be571 100644
--- a/app/addons/components/components/tray.js
+++ b/app/addons/components/components/tray.js
@@ -17,47 +17,49 @@ import ReactDOM from "react-dom";
 import {Overlay} from 'react-bootstrap';
 import {TransitionMotion, spring} from 'react-motion';
 
-export const TrayContents = React.createClass({
-  propTypes: {
+export class TrayContents extends React.Component {
+  static propTypes = {
     contentVisible: PropTypes.bool.isRequired,
     closeTray: PropTypes.func.isRequired,
     onEnter: PropTypes.func,
     container: PropTypes.object
-  },
+  };
 
-  defaultProps: {
-    onEnter: () => {},
-    container: this
-  },
+  defaultProps = () => {
+    return {
+      onEnter: () => {},
+      container: this
+    };
+  };
 
-  getChildren (items) {
+  getChildren = (items) => {
     const {style} = items[0];
     var className = "tray show-tray " + this.props.className;
     return (
       <div key={'1'} id={this.props.id} style={{opacity: style.opacity, top: style.top + 'px'}} className={className}>
         {this.props.children}
       </div>);
-  },
+  };
 
-  willEnter () {
+  willEnter = () => {
     return {
       opacity: spring(1),
       top: spring(55)
     };
-  },
+  };
 
-  willLeave () {
+  willLeave = () => {
     return {
       opacity: spring(0),
       top: spring(30)
     };
-  },
+  };
 
-  getDefaultStyles () {
+  getDefaultStyles = () => {
     return [{key: '1', style: {opacity: 0, top: 30}}];
-  },
+  };
 
-  getStyles (prevStyle) {
+  getStyles = (prevStyle) => {
     if (!prevStyle) {
       return [{
         key: '1',
@@ -70,9 +72,9 @@ export const TrayContents = React.createClass({
         style: item.style
       };
     });
-  },
+  };
 
-  render () {
+  render() {
     return (
       <Overlay
        show={this.props.contentVisible}
@@ -94,55 +96,48 @@ export const TrayContents = React.createClass({
       </Overlay>
     );
   }
-});
+}
 
 
 export const connectToStores = (Component, stores, getStateFromStores) => {
+  class WrappingElement extends React.Component {
+    state = getStateFromStores(this.props);
 
-  var WrappingElement = React.createClass({
-
-    componentDidMount () {
-      stores.forEach(function (store) {
+    componentDidMount() {
+      stores.forEach(store => {
         store.on('change', this.onChange, this);
-      }.bind(this));
-    },
+      });
+    }
 
-    componentWillUnmount () {
+    componentWillUnmount() {
       stores.forEach(function (store) {
         store.off('change', this.onChange);
       }.bind(this));
-    },
-
-    getInitialState () {
-      return getStateFromStores(this.props);
-    },
+    }
 
-    onChange () {
+    onChange = () => {
       this.setState(getStateFromStores(this.props));
-    },
+    };
 
-    handleStoresChanged () {
+    handleStoresChanged = () => {
       this.setState(getStateFromStores(this.props));
-    },
+    };
 
-    render () {
+    render() {
       return <Component {...this.state} {...this.props} />;
     }
-
-  });
+  }
 
   return WrappingElement;
 };
 
-export const TrayWrapper = React.createClass({
-  getDefaultProps () {
-    return {
-      className: ''
-    };
-  },
+export class TrayWrapper extends React.Component {
+  static defaultProps = {
+    className: ''
+  };
 
-  renderChildren () {
-    return React.Children.map(this.props.children, function (child) {
+  renderChildren = () => {
+    return React.Children.map(this.props.children, (child) => {
 
       const props = {};
       Object.keys(this.props).filter((k) => {
@@ -152,14 +147,14 @@ export const TrayWrapper = React.createClass({
       });
 
       return React.cloneElement(child, props);
-    }.bind(this));
-  },
+    });
+  };
 
-  render () {
+  render() {
     return (
       <div>
         {this.renderChildren()}
       </div>
     );
   }
-});
+}
diff --git a/app/addons/components/components/zenmodeoverlay.js b/app/addons/components/components/zenmodeoverlay.js
index 8490d92..813c258 100644
--- a/app/addons/components/components/zenmodeoverlay.js
+++ b/app/addons/components/components/zenmodeoverlay.js
@@ -16,75 +16,70 @@ import {CodeEditor} from './codeeditor';
 
 require('brace/theme/dawn');
 
+ const themes = {
+    dark: 'idle_fingers',
+    light: 'dawn'
+  };
 // Zen mode editing has very few options:
 // - It covers the full screen, hiding everything else
 // - Two themes: light & dark (choice stored in local storage)
 // - No save option, but has a 1-1 map with a <CodeEditor /> element which gets updated when the user leaves
 // - [Escape] closes the mode, as does clicking the shrink icon at the top right
-export const ZenModeOverlay = React.createClass({
-  getDefaultProps () {
-    return {
-      mode: 'javascript',
-      defaultCode: '',
-      ignorableErrors: [],
-      onExit: null,
-      highlightActiveLine: false
-    };
-  },
-
-  themes: {
-    dark: 'idle_fingers',
-    light: 'dawn'
-  },
-
-  getInitialState () {
-    return this.getStoreState();
-  },
+export class ZenModeOverlay extends React.Component {
+  static defaultProps = {
+    mode: 'javascript',
+    defaultCode: '',
+    ignorableErrors: [],
+    onExit: null,
+    highlightActiveLine: false
+  };
 
-  getStoreState () {
+  getStoreState = () => {
     return {
       theme: this.getZenTheme(),
       code: this.props.defaultCode
     };
-  },
+  };
 
-  getZenTheme () {
+  getZenTheme = () => {
     var selectedTheme = app.utils.localStorageGet('zenTheme');
     return _.isUndefined(selectedTheme) ? 'dark' : selectedTheme;
-  },
+  };
 
-  onChange () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
 
-  componentDidMount () {
+  componentDidMount() {
     $(ReactDOM.findDOMNode(this.refs.exit)).tooltip({ placement: 'left' });
     $(ReactDOM.findDOMNode(this.refs.theme)).tooltip({ placement: 'left' });
-  },
+  }
 
-  exitZenMode () {
+  exitZenMode = () => {
     this.props.onExit(this.getValue());
-  },
+  };
 
-  getValue () {
+  getValue = () => {
     return this.refs.ace.getValue();
-  },
+  };
 
-  toggleTheme () {
+  toggleTheme = () => {
     var newTheme = (this.state.theme === 'dark') ? 'light' : 'dark';
     this.setState({
       theme: newTheme,
       code: this.getValue()
     });
     app.utils.localStorageSet('zenTheme', newTheme);
-  },
+  };
 
-  setValue (code, lineNumber) {
+  setValue = (code, lineNumber) => {
     lineNumber = lineNumber ? lineNumber : -1;
     this.editor.setValue(code, lineNumber);
-  },
+  };
+
+  state = this.getStoreState();
 
-  render () {
+  render() {
     var classes = 'full-page-editor-modal-wrapper zen-theme-' + this.state.theme;
 
     var editorCommands = [{
@@ -119,7 +114,7 @@ export const ZenModeOverlay = React.createClass({
         <CodeEditor
           ref="ace"
           autoFocus={true}
-          theme={this.themes[this.state.theme]}
+          theme={themes[this.state.theme]}
           defaultCode={this.props.defaultCode}
           editorCommands={editorCommands}
           ignorableErrors={this.props.ignorableErrors}
@@ -128,4 +123,4 @@ export const ZenModeOverlay = React.createClass({
       </div>
     );
   }
-});
+}
diff --git a/app/addons/config/components.js b/app/addons/config/components.js
index c57d713..3bd0d68 100644
--- a/app/addons/config/components.js
+++ b/app/addons/config/components.js
@@ -22,47 +22,45 @@ import FauxtonComponents from "../fauxton/components";
 
 const configStore = Stores.configStore;
 
-var ConfigTableController = React.createClass({
-  getStoreState () {
+class ConfigTableController extends React.Component {
+  getStoreState = () => {
     return {
       options: configStore.getOptions(),
       loading: configStore.isLoading()
     };
-  },
+  };
 
-  getInitialState () {
-    return this.getStoreState();
-  },
-
-  componentDidMount () {
+  componentDidMount() {
     configStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount () {
+  componentWillUnmount() {
     configStore.off('change', this.onChange);
-  },
+  }
 
-  onChange () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
 
-  saveOption (option) {
+  saveOption = (option) => {
     Actions.saveOption(this.props.node, option);
-  },
+  };
 
-  deleteOption (option) {
+  deleteOption = (option) => {
     Actions.deleteOption(this.props.node, option);
-  },
+  };
 
-  editOption (option) {
+  editOption = (option) => {
     Actions.editOption(option);
-  },
+  };
 
-  cancelEdit () {
+  cancelEdit = () => {
     Actions.cancelEdit();
-  },
+  };
 
-  render () {
+  state = this.getStoreState();
+
+  render() {
     if (this.state.loading) {
       return (
         <div className="view">
@@ -80,10 +78,10 @@ var ConfigTableController = React.createClass({
       );
     }
   }
-});
+}
 
-var ConfigTable = React.createClass({
-  createOptions () {
+class ConfigTable extends React.Component {
+  createOptions = () => {
     return _.map(this.props.options, (option) => (
       <ConfigOption
         option={option}
@@ -94,9 +92,9 @@ var ConfigTable = React.createClass({
         key={`${option.sectionName}/${option.optionName}`}
       />
     ));
-  },
+  };
 
-  render () {
+  render() {
     var options = this.createOptions();
 
     return (
@@ -115,24 +113,24 @@ var ConfigTable = React.createClass({
       </table>
     );
   }
-});
+}
 
-var ConfigOption = React.createClass({
-  onSave (value) {
+class ConfigOption extends React.Component {
+  onSave = (value) => {
     var option = this.props.option;
     option.value = value;
     this.props.onSave(option);
-  },
+  };
 
-  onDelete () {
+  onDelete = () => {
     this.props.onDelete(this.props.option);
-  },
+  };
 
-  onEdit () {
+  onEdit = () => {
     this.props.onEdit(this.props.option);
-  },
+  };
 
-  render () {
+  render() {
     return (
       <tr className="config-item">
         <th>{this.props.option.header && this.props.option.sectionName}</th>
@@ -151,48 +149,44 @@ var ConfigOption = React.createClass({
       </tr>
     );
   }
-});
-
-var ConfigOptionValue = React.createClass({
-  getInitialState () {
-    return {
-      value: this.props.value,
-      editing: this.props.editing,
-      saving: this.props.saving
-    };
-  },
-
-  getDefaultProps () {
-    return {
-      value: '',
-      editing: false,
-      saving: false,
-      onSave: () => null,
-      onEdit: () => null,
-      onCancelEdit: () => null
-    };
-  },
-
-  componentWillReceiveProps (nextProps) {
+}
+
+class ConfigOptionValue extends React.Component {
+  static defaultProps = {
+    value: '',
+    editing: false,
+    saving: false,
+    onSave: () => null,
+    onEdit: () => null,
+    onCancelEdit: () => null
+  };
+
+  state = {
+    value: this.props.value,
+    editing: this.props.editing,
+    saving: this.props.saving
+  };
+
+  componentWillReceiveProps(nextProps) {
     if (this.props.value !== nextProps.value) {
       this.setState({ saving: false });
     }
-  },
+  }
 
-  onChange (event) {
+  onChange = (event) => {
     this.setState({ value: event.target.value });
-  },
+  };
 
-  onSave () {
+  onSave = () => {
     if (this.state.value !== this.props.value) {
       this.setState({ saving: true });
       this.props.onSave(this.state.value);
     } else {
       this.props.onCancelEdit();
     }
-  },
+  };
 
-  getButtons () {
+  getButtons = () => {
     if (this.state.saving) {
       return null;
     } else {
@@ -200,7 +194,7 @@ var ConfigOptionValue = React.createClass({
         <span>
           <button
             className="btn btn-primary fonticon-ok-circled btn-small btn-config-save"
-            onClick={this.onSave}
+            onClick={this.onSave.bind(this)}
           />
           <button
             className="btn fonticon-cancel-circled btn-small btn-config-cancel"
@@ -209,15 +203,15 @@ var ConfigOptionValue = React.createClass({
         </span>
       );
     }
-  },
+  };
 
-  render () {
+  render() {
     if (this.props.editing) {
       return (
         <td>
           <div className="config-value-form">
             <input
-              onChange={this.onChange}
+              onChange={this.onChange.bind(this)}
               defaultValue={this.props.value}
               disabled={this.state.saving}
               autoFocus type="text" className="config-value-input"
@@ -234,55 +228,58 @@ var ConfigOptionValue = React.createClass({
       );
     }
   }
-});
+}
 
-var ConfigOptionTrash = React.createClass({
-  getInitialState () {
-    return {
-      show: false
-    };
-  },
+class ConfigOptionTrash extends React.Component {
+  state = {
+    show: false
+  };
 
-  onDelete () {
+  onDelete = () => {
     this.props.onDelete();
-  },
+  };
 
-  showModal () {
+  showModal = () => {
     this.setState({ show: true });
-  },
+  };
 
-  hideModal () {
-    this.setState({ hide: false });
-  },
+  hideModal = () => {
+    this.setState({ show: false });
+  };
 
-  render () {
+  render() {
     return (
       <td className="text-center config-item-trash config-delete-value"
-          onClick={this.showModal}>
+          onClick={this.showModal.bind(this)}>
         <i className="icon icon-trash"></i>
         <FauxtonComponents.ConfirmationModal
           text={`Are you sure you want to delete ${this.props.sectionName}/${this.props.optionName}?`}
-          onClose={this.hideModal}
-          onSubmit={this.onDelete}
+          onClose={this.hideModal.bind(this)}
+          onSubmit={this.onDelete.bind(this)}
           visible={this.state.show}/>
       </td>
     );
   }
-});
+}
 
-var AddOptionController = React.createClass({
-  addOption (option) {
+class AddOptionController extends React.Component {
+  addOption = (option) => {
     Actions.addOption(this.props.node, option);
-  },
+  };
 
-  render () {
+  render() {
     return (
       <AddOptionButton onAdd={this.addOption}/>
     );
   }
-});
+}
+
+class AddOptionButton extends React.Component {
+  constructor(props) {
+    super(props);
+    this.state = this.getInitialState();
+  }
 
-var AddOptionButton = React.createClass({
   getInitialState () {
     return {
       sectionName: '',
@@ -290,7 +287,7 @@ var AddOptionButton = React.createClass({
       value: '',
       show: false
     };
-  },
+  }
 
   isInputValid () {
     if (this.state.sectionName !== ''
@@ -300,23 +297,23 @@ var AddOptionButton = React.createClass({
     }
 
     return false;
-  },
+  }
 
   updateSectionName (event) {
     this.setState({ sectionName: event.target.value });
-  },
+  }
 
   updateOptionName (event) {
     this.setState({ optionName: event.target.value });
-  },
+  }
 
   updateValue (event) {
     this.setState({ value: event.target.value });
-  },
+  }
 
   reset () {
     this.setState(this.getInitialState());
-  },
+  }
 
   onAdd () {
     if (this.isInputValid()) {
@@ -329,46 +326,46 @@ var AddOptionButton = React.createClass({
       this.setState({ show: false });
       this.props.onAdd(option);
     }
-  },
+  }
 
   togglePopover () {
     this.setState({ show: !this.state.show });
-  },
+  }
 
   hidePopover () {
     this.setState({ show: false });
-  },
+  }
 
   getPopover () {
     return (
       <Popover className="tray" id="add-option-popover" title="Add Option">
         <input
           className="input-section-name"
-          onChange={this.updateSectionName}
-          type="text" name="section" placeholder="Section" autocomplete="off" autoFocus/>
+          onChange={this.updateSectionName.bind(this)}
+          type="text" name="section" placeholder="Section" autoComplete="off" autoFocus/>
         <input
           className="input-option-name"
-          onChange={this.updateOptionName}
+          onChange={this.updateOptionName.bind(this)}
           type="text" name="name" placeholder="Name"/>
         <input
           className="input-value"
-          onChange={this.updateValue}
+          onChange={this.updateValue.bind(this)}
           type="text" name="value" placeholder="Value"/>
         <a
           className="btn btn-create"
-          onClick={this.onAdd}>
+          onClick={this.onAdd.bind(this)}>
           Create
         </a>
       </Popover>
     );
-  },
+  }
 
   render () {
     return (
       <div id="add-option-panel">
         <Button
           id="add-option-button"
-          onClick={this.togglePopover}
+          onClick={this.togglePopover.bind(this)}
           ref="target">
           <i className="icon icon-plus header-icon"></i>
           Add Option
@@ -376,7 +373,7 @@ var AddOptionButton = React.createClass({
 
         <Overlay
           show={this.state.show}
-          onHide={this.hidePopover}
+          onHide={this.hidePopover.bind(this)}
           placement="bottom"
           rootClose={true}
           target={() => ReactDOM.findDOMNode(this.refs.target)}>
@@ -385,7 +382,7 @@ var AddOptionButton = React.createClass({
       </div>
     );
   }
-});
+}
 
 const TabItem = ({active, link, title}) => {
   return (
diff --git a/app/addons/databases/components.js b/app/addons/databases/components.js
index 04d1af1..0bb9c31 100644
--- a/app/addons/databases/components.js
+++ b/app/addons/databases/components.js
@@ -32,35 +32,32 @@ const deleteDbModalStore = ComponentsStore.deleteDbModalStore;
 const {DeleteDatabaseModal, ToggleHeaderButton, TrayContents} = Components;
 
 
-var DatabasesController = React.createClass({
-
-  getStoreState () {
+class DatabasesController extends React.Component {
+  getStoreState = () => {
     return {
       dbList: databasesStore.getDbList(),
       loading: databasesStore.isLoading(),
       showDeleteDatabaseModal: deleteDbModalStore.getShowDeleteDatabaseModal()
     };
-  },
-
-  getInitialState () {
-    return this.getStoreState();
-  },
+  };
 
-  componentDidMount () {
+  componentDidMount() {
     databasesStore.on('change', this.onChange, this);
     deleteDbModalStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount () {
+  componentWillUnmount() {
     databasesStore.off('change', this.onChange, this);
     deleteDbModalStore.off('change', this.onChange, this);
-  },
+  }
 
-  onChange () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
+
+  state = this.getStoreState();
 
-  render () {
+  render() {
     const {loading, dbList} = this.state;
 
     return (
@@ -70,38 +67,37 @@ var DatabasesController = React.createClass({
         loading={loading} />
     );
   }
-});
+}
 
-const DatabaseTable = React.createClass({
-
-  propTypes: {
+class DatabaseTable extends React.Component {
+  static propTypes = {
     dbList: PropTypes.array.isRequired,
     showDeleteDatabaseModal: PropTypes.object.isRequired,
     loading: PropTypes.bool.isRequired,
-  },
+  };
 
-  createRows (dbList) {
+  createRows = (dbList) => {
     return dbList.map((item, k) => {
       return (
         <DatabaseRow item={item} key={k} />
       );
     });
-  },
+  };
 
-  getExtensionColumns () {
+  getExtensionColumns = () => {
     var cols = FauxtonAPI.getExtensions('DatabaseTable:head');
     return _.map(cols, function (Item, index) {
       return <Item key={index} />;
     });
-  },
+  };
 
-  showDeleteDatabaseModal () {
+  showDeleteDatabaseModal = () => {
     ComponentsActions.showDeleteDatabaseModal({
       showDeleteModal: !this.props.showDeleteDatabaseModal.showDeleteModal
     });
-  },
+  };
 
-  render () {
+  render() {
     if (this.props.loading) {
       return (
         <div className="view">
@@ -133,26 +129,25 @@ const DatabaseTable = React.createClass({
       </div>
     );
   }
-});
-
-var DatabaseRow = React.createClass({
+}
 
-  propTypes: {
+class DatabaseRow extends React.Component {
+  static propTypes = {
     row: PropTypes.object
-  },
+  };
 
-  getExtensionColumns (row) {
+  getExtensionColumns = (row) => {
     var cols = FauxtonAPI.getExtensions('DatabaseTable:databaseRow');
     return _.map(cols, function (Item, index) {
       return <Item row={row} key={index} />;
     });
-  },
+  };
 
-  showDeleteDatabaseModal (name) {
+  showDeleteDatabaseModal = (name) => {
     ComponentsActions.showDeleteDatabaseModal({showDeleteModal: true, dbId: name});
-  },
+  };
 
-  render () {
+  render() {
     const {
       item
     } = this.props;
@@ -195,7 +190,7 @@ var DatabaseRow = React.createClass({
       </tr>
     );
   }
-});
+}
 
 const GraveyardInfo = ({docCount, docDelCount}) => {
   const graveyardTitle = `This database has just ${docCount} docs and ${docDelCount} deleted docs`;
@@ -217,42 +212,39 @@ const RightDatabasesHeader = () => {
   );
 };
 
-var AddDatabaseWidget = React.createClass({
+class AddDatabaseWidget extends React.Component {
+  state = {
+    isPromptVisible: false,
+    databaseName: ''
+  };
 
-  onTrayToggle () {
+  onTrayToggle = () => {
     this.setState({isPromptVisible: !this.state.isPromptVisible});
-  },
+  };
 
-  closeTray () {
+  closeTray = () => {
     this.setState({isPromptVisible: false});
-  },
+  };
 
-  focusInput () {
+  focusInput = () => {
     ReactDOM.findDOMNode(this.refs.newDbName).focus();
-  },
+  };
 
-  onKeyUpInInput (e) {
+  onKeyUpInInput = (e) => {
     if (e.which === 13) {
       this.onAddDatabase();
     }
-  },
-
-  getInitialState () {
-    return {
-      isPromptVisible: false,
-      databaseName: ''
-    };
-  },
+  };
 
-  onChange (e) {
+  onChange = (e) => {
     this.setState({databaseName: e.target.value});
-  },
+  };
 
-  onAddDatabase () {
+  onAddDatabase = () => {
     Actions.createNewDatabase(this.state.databaseName);
-  },
+  };
 
-  render () {
+  render() {
     return (
       <div>
         <ToggleHeaderButton
@@ -278,7 +270,7 @@ var AddDatabaseWidget = React.createClass({
       </div>
     );
   }
-});
+}
 
 const JumpToDatabaseWidget = ({loadOptions}) => {
   return (
@@ -301,50 +293,45 @@ JumpToDatabaseWidget.propTypes = {
   loadOptions: PropTypes.func.isRequired
 };
 
-var DatabasePagination = React.createClass({
+class DatabasePagination extends React.Component {
+  static defaultProps = {
+    linkPath: '_all_dbs',
+    store: databasesStore
+  };
 
-  getDefaultProps () {
-    return {
-      linkPath: '_all_dbs',
-      store: databasesStore
-    };
-  },
-
-  getStoreState (props) {
+  getStoreState = (props) => {
     const {store} = props;
 
     return {
       totalAmountOfDatabases: store.getTotalAmountOfDatabases(),
       page: store.getPage()
     };
-  },
-
-  getInitialState () {
-    return this.getStoreState(this.props);
-  },
+  };
 
-  componentDidMount () {
+  componentDidMount() {
     const {store} = this.props;
 
     store.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillReceiveProps (nextProps) {
+  componentWillReceiveProps(nextProps) {
     this.setState(this.getStoreState(nextProps));
     const {store} = nextProps;
     store.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount () {
+  componentWillUnmount() {
     const {store} = this.props;
     store.off('change', this.onChange, this);
-  },
+  }
 
-  onChange () {
+  onChange = () => {
     this.setState(this.getStoreState(this.props));
-  },
+  };
+
+  state = this.getStoreState(this.props);
 
-  render () {
+  render() {
     const {page, totalAmountOfDatabases} = this.state;
 
     const urlPrefix = `#/${this.props.linkPath}?page=`;
@@ -364,7 +351,7 @@ var DatabasePagination = React.createClass({
       </footer>
     );
   }
-});
+}
 
 export default {
   DatabasesController: DatabasesController,
diff --git a/app/addons/databases/tests/componentsSpec.js b/app/addons/databases/tests/componentsSpec.js
index 037b6d4..3c86b41 100644
--- a/app/addons/databases/tests/componentsSpec.js
+++ b/app/addons/databases/tests/componentsSpec.js
@@ -111,16 +111,17 @@ describe('DatabaseTable', function () {
   });
 
   it('adds multiple extra columns if extended', function () {
+    class ColHeader1 extends React.Component {
+      render() { return <th>EXTRA COL 1</th>; }
+    }
 
-    var ColHeader1 = React.createClass({
-      render: function () { return <th>EXTRA COL 1</th>; }
-    });
-    var ColHeader2 = React.createClass({
-      render: function () { return <th>EXTRA COL 2</th>; }
-    });
-    var ColHeader3 = React.createClass({
-      render: function () { return <th>EXTRA COL 3</th>; }
-    });
+    class ColHeader2 extends React.Component {
+      render() { return <th>EXTRA COL 2</th>; }
+    }
+
+    class ColHeader3 extends React.Component {
+      render() { return <th>EXTRA COL 3</th>; }
+    }
 
     FauxtonAPI.registerExtension('DatabaseTable:head', ColHeader1);
     FauxtonAPI.registerExtension('DatabaseTable:head', ColHeader2);
@@ -139,9 +140,9 @@ describe('DatabaseTable', function () {
   });
 
   it('adds multiple extra column in DatabaseRow if extended', function () {
-    var Cell = React.createClass({
-      render: function () { return <td>EXTRA CELL</td>; }
-    });
+    class Cell extends React.Component {
+      render() { return <td>EXTRA CELL</td>; }
+    }
 
     FauxtonAPI.registerExtension('DatabaseTable:databaseRow', Cell);
 
diff --git a/app/addons/documents/designdocinfo/components.js b/app/addons/documents/designdocinfo/components.js
index df0f481..726bc93 100644
--- a/app/addons/documents/designdocinfo/components.js
+++ b/app/addons/documents/designdocinfo/components.js
@@ -21,41 +21,39 @@ var Copy = ReactComponents.Copy;
 import uuid from 'uuid';
 
 
-var DesignDocInfo = React.createClass({
-  getStoreState: function () {
+class DesignDocInfo extends React.Component {
+  getStoreState = () => {
     return {
       viewIndex: designDocInfoStore.getViewIndex(),
       isLoading: designDocInfoStore.isLoading(),
       ddocName: designDocInfoStore.getDdocName()
     };
-  },
+  };
 
-  getInitialState: function () {
-    return this.getStoreState();
-  },
-
-  componentDidMount: function () {
+  componentDidMount() {
     designDocInfoStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount: function () {
+  componentWillUnmount() {
     designDocInfoStore.off('change', this.onChange);
     Actions.stopRefresh();
-  },
+  }
 
-  onChange: function () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
 
-  showCopiedMessage: function () {
+  showCopiedMessage = () => {
     FauxtonAPI.addNotification({
       type: 'success',
       msg: 'The MD5 sha has been copied to your clipboard.',
       clear: true
     });
-  },
+  };
+
+  state = this.getStoreState();
 
-  render: function () {
+  render() {
     var viewIndex = this.state.viewIndex;
 
     if (this.state.isLoading) {
@@ -131,7 +129,7 @@ var DesignDocInfo = React.createClass({
       </div>
     );
   }
-});
+}
 
 
 export default {
diff --git a/app/addons/documents/doc-editor/components.js b/app/addons/documents/doc-editor/components.js
index 251e087..fd96b49 100644
--- a/app/addons/documents/doc-editor/components.js
+++ b/app/addons/documents/doc-editor/components.js
@@ -29,13 +29,13 @@ import DocumentResources from '../resources';
 
 var store = Stores.docEditorStore;
 
-var DocEditorController = React.createClass({
+class DocEditorController extends React.Component {
+  static defaultProps = {
+    database: {},
+    isNewDoc: false
+  };
 
-  getInitialState: function () {
-    return this.getStoreState();
-  },
-
-  getStoreState: function () {
+  getStoreState = () => {
     return {
       isLoading: store.isLoading(),
       doc: store.getDoc(),
@@ -45,16 +45,9 @@ var DocEditorController = React.createClass({
       numFilesUploaded: store.getNumFilesUploaded(),
       conflictCount: store.getDocConflictCount()
     };
-  },
-
-  getDefaultProps: function () {
-    return {
-      database: {},
-      isNewDoc: false
-    };
-  },
+  };
 
-  getCodeEditor: function () {
+  getCodeEditor = () => {
     if (this.state.isLoading) {
       return (<GeneralComponents.LoadLines />);
     }
@@ -77,17 +70,17 @@ var DocEditorController = React.createClass({
         notifyUnsavedChanges={true}
         stringEditModalEnabled={true} />
     );
-  },
+  };
 
-  componentDidMount: function () {
+  componentDidMount() {
     store.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount: function () {
+  componentWillUnmount() {
     store.off('change', this.onChange);
-  },
+  }
 
-  componentWillUpdate: function (nextProps, nextState) {
+  componentWillUpdate(nextProps, nextState) {
     // Update the editor whenever a file is uploaded, a doc is cloned, or a new doc is loaded
     if (this.state.numFilesUploaded !== nextState.numFilesUploaded ||
         this.state.doc && this.state.doc.hasChanged() ||
@@ -95,34 +88,34 @@ var DocEditorController = React.createClass({
       this.getEditor().setValue(JSON.stringify(nextState.doc.attributes, null, '  '));
       this.onSaveComplete();
     }
-  },
+  }
 
-  onChange: function () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
 
-  saveDoc: function () {
+  saveDoc = () => {
     Actions.saveDoc(this.state.doc, this.checkDocIsValid(), this.onSaveComplete);
-  },
+  };
 
-  onSaveComplete: function () {
+  onSaveComplete = () => {
     this.getEditor().clearChanges();
-  },
+  };
 
-  hideDeleteDocModal: function () {
+  hideDeleteDocModal = () => {
     Actions.hideDeleteDocModal();
-  },
+  };
 
-  deleteDoc: function () {
+  deleteDoc = () => {
     Actions.hideDeleteDocModal();
     Actions.deleteDoc(this.state.doc);
-  },
+  };
 
-  getEditor: function () {
+  getEditor = () => {
     return (this.refs.docEditor) ? this.refs.docEditor.getEditor() : null;
-  },
+  };
 
-  checkDocIsValid: function () {
+  checkDocIsValid = () => {
     if (this.getEditor().hasErrors()) {
       return false;
     }
@@ -130,20 +123,20 @@ var DocEditorController = React.createClass({
     this.state.doc.clear().set(json, { validate: true });
 
     return !this.state.doc.validationError;
-  },
+  };
 
-  clearChanges: function () {
+  clearChanges = () => {
     this.refs.docEditor.clearChanges();
-  },
+  };
 
-  getExtensionIcons: function () {
+  getExtensionIcons = () => {
     var extensions = FauxtonAPI.getExtensions('DocEditor:icons');
     return _.map(extensions, function (Extension, i) {
       return (<Extension doc={this.state.doc} key={i} database={this.props.database} />);
     }, this);
-  },
+  };
 
-  getButtonRow: function () {
+  getButtonRow = () => {
     if (this.props.isNewDoc) {
       return false;
     }
@@ -163,9 +156,11 @@ var DocEditorController = React.createClass({
         <PanelButton title="Delete" iconClass="icon-trash" onClick={Actions.showDeleteDocModal} />
       </div>
     );
-  },
+  };
+
+  state = this.getStoreState();
 
-  render: function () {
+  render() {
     var saveButtonLabel = (this.props.isNewDoc) ? 'Create Document' : 'Save Changes';
     let endpoint = FauxtonAPI.urls('allDocs', 'app', FauxtonAPI.url.encode(this.props.database.id));
     return (
@@ -209,23 +204,20 @@ var DocEditorController = React.createClass({
       </div>
     );
   }
-});
-
-var AttachmentsPanelButton = React.createClass({
+}
 
-  propTypes: {
+class AttachmentsPanelButton extends React.Component {
+  static propTypes = {
     isLoading: PropTypes.bool.isRequired,
     doc: PropTypes.object
-  },
+  };
 
-  getDefaultProps: function () {
-    return {
-      isLoading: true,
-      doc: {}
-    };
-  },
+  static defaultProps = {
+    isLoading: true,
+    doc: {}
+  };
 
-  getAttachmentList: function () {
+  getAttachmentList = () => {
     var db = this.props.doc.database.get('id');
     var doc = this.props.doc.get('_id');
 
@@ -240,9 +232,9 @@ var AttachmentsPanelButton = React.createClass({
         </li>
       );
     });
-  },
+  };
 
-  render: function () {
+  render() {
     if (this.props.isLoading || !this.props.doc.get('_attachments')) {
       return false;
     }
@@ -261,26 +253,23 @@ var AttachmentsPanelButton = React.createClass({
       </div>
     );
   }
-});
+}
 
-
-var PanelButton = React.createClass({
-  propTypes: {
+class PanelButton extends React.Component {
+  static propTypes = {
     title: PropTypes.string.isRequired,
     onClick: PropTypes.func.isRequired,
     className: PropTypes.string
-  },
+  };
 
-  getDefaultProps: function () {
-    return {
-      title: '',
-      iconClass: '',
-      onClick: function () { },
-      className: ''
-    };
-  },
+  static defaultProps = {
+    title: '',
+    iconClass: '',
+    onClick: function () { },
+    className: ''
+  };
 
-  render: function () {
+  render() {
     var iconClasses = 'icon ' + this.props.iconClass;
     return (
       <div className="panel-section">
@@ -291,28 +280,23 @@ var PanelButton = React.createClass({
       </div>
     );
   }
-});
+}
 
-
-var UploadModal = React.createClass({
-  propTypes: {
+class UploadModal extends React.Component {
+  static propTypes = {
     visible: PropTypes.bool.isRequired,
     doc: PropTypes.object
-  },
-
-  getInitialState: function () {
-    return this.getStoreState();
-  },
+  };
 
-  getStoreState: function () {
+  getStoreState = () => {
     return {
       inProgress: store.isUploadInProgress(),
       loadPercentage: store.getUploadLoadPercentage(),
       errorMessage: store.getFileUploadErrorMsg()
     };
-  },
+  };
 
-  closeModal: function (e) {
+  closeModal = (e) => {
     if (e) {
       e.preventDefault();
     }
@@ -322,17 +306,19 @@ var UploadModal = React.createClass({
     }
     Actions.hideUploadModal();
     Actions.resetUploadModal();
-  },
+  };
 
-  upload: function () {
+  upload = () => {
     Actions.uploadAttachment({
       doc: this.props.doc,
       rev: this.props.doc.get('_rev'),
       files: $(ReactDOM.findDOMNode(this.refs.attachments))[0].files
     });
-  },
+  };
 
-  render: function () {
+  state = this.getStoreState();
+
+  render() {
     var errorClasses = 'alert alert-error';
     if (this.state.errorMessage === '') {
       errorClasses += ' hide';
@@ -373,32 +359,29 @@ var UploadModal = React.createClass({
       </Modal>
     );
   }
-});
-
+}
 
-const CloneDocModal = React.createClass({
-  propTypes: {
+class CloneDocModal extends React.Component {
+  static propTypes = {
     visible: PropTypes.bool.isRequired,
     doc: PropTypes.object,
     database: PropTypes.object.isRequired,
     onSubmit: PropTypes.func.isRequired
-  },
+  };
 
-  getInitialState: function () {
-    return {
-      uuid: null
-    };
-  },
+  state = {
+    uuid: null
+  };
 
-  cloneDoc: function () {
+  cloneDoc = () => {
     if (this.props.onSubmit) {
       this.props.onSubmit();
     }
 
     Actions.cloneDoc(this.props.database, this.props.doc, this.state.uuid);
-  },
+  };
 
-  componentDidUpdate: function () {
+  componentDidUpdate() {
     //XXX model-code in component
     if (this.state.uuid === null) {
       var uuid = new DocumentResources.UUID();
@@ -406,20 +389,20 @@ const CloneDocModal = React.createClass({
         this.setState({ uuid: uuid.next() });
       }.bind(this));
     }
-  },
+  }
 
-  closeModal: function (e) {
+  closeModal = (e) => {
     if (e) {
       e.preventDefault();
     }
     Actions.hideCloneDocModal();
-  },
+  };
 
-  docIDChange: function (e) {
+  docIDChange = (e) => {
     this.setState({ uuid: e.target.value });
-  },
+  };
 
-  render: function () {
+  render() {
     if (this.state.uuid === null) {
       return false;
     }
@@ -450,7 +433,7 @@ const CloneDocModal = React.createClass({
       </Modal>
     );
   }
-});
+}
 
 
 export default {
diff --git a/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.js b/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.js
index 9048f3d..754a71e 100644
--- a/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.js
+++ b/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.js
@@ -210,8 +210,8 @@ describe("AttachmentsPanelButton", function () {
 
 describe("Custom Extension Buttons", function () {
   it('supports buttons', function () {
-    var CustomButton = React.createClass({
-      render: function () {
+    class CustomButton extends React.Component {
+      render() {
         return (
           <div>
             <button>Oh no she di'n't!</button>
@@ -219,7 +219,8 @@ describe("Custom Extension Buttons", function () {
           </div>
         );
       }
-    });
+    }
+
     FauxtonAPI.registerExtension('DocEditor:icons', CustomButton);
 
     var container = document.createElement('div');
diff --git a/app/addons/documents/sidebar/sidebar.js b/app/addons/documents/sidebar/sidebar.js
index 23826e0..b65398d 100644
--- a/app/addons/documents/sidebar/sidebar.js
+++ b/app/addons/documents/sidebar/sidebar.js
@@ -39,16 +39,16 @@ var DeleteDatabaseModal = Components.DeleteDatabaseModal;
 var deleteDbModalStore = ComponentsStore.deleteDbModalStore;
 
 
-var MainSidebar = React.createClass({
-  propTypes: {
+class MainSidebar extends React.Component {
+  static propTypes = {
     selectedNavItem: PropTypes.string.isRequired
-  },
+  };
 
-  getNewButtonLinks: function () {  // these are links for the sidebar '+' on All Docs and All Design Docs
+  getNewButtonLinks = () => {  // these are links for the sidebar '+' on All Docs and All Design Docs
     return DocumentHelper.getNewButtonLinks(this.props.databaseName);
-  },
+  };
 
-  buildDocLinks: function () {
+  buildDocLinks = () => {
     const base = FauxtonAPI.urls('base', 'app', this.props.databaseName);
     return FauxtonAPI.getExtensions('docLinks').map(function (link) {
       return (
@@ -57,13 +57,13 @@ var MainSidebar = React.createClass({
         </li>
       );
     }, this);
-  },
+  };
 
-  getNavItemClass: function (navItem) {
+  getNavItemClass = (navItem) => {
     return (navItem === this.props.selectedNavItem) ? 'active' : '';
-  },
+  };
 
-  render: function () {
+  render() {
     var docLinks = this.buildDocLinks();
     var dbEncoded = FauxtonAPI.url.encode(this.props.databaseName);
     var changesUrl     = '#' + FauxtonAPI.urls('changes', 'app', dbEncoded, '');
@@ -114,12 +114,10 @@ var MainSidebar = React.createClass({
       </ul>
     );
   }
-});
+}
 
-
-var IndexSection = React.createClass({
-
-  propTypes: {
+class IndexSection extends React.Component {
+  static propTypes = {
     urlNamespace: PropTypes.string.isRequired,
     indexLabel: PropTypes.string.isRequired,
     database: PropTypes.object.isRequired,
@@ -129,24 +127,22 @@ var IndexSection = React.createClass({
     selectedIndex: PropTypes.string.isRequired,
     onDelete: PropTypes.func.isRequired,
     onClone: PropTypes.func.isRequired
-  },
+  };
 
-  getInitialState: function () {
-    return {
-      placement: 'bottom'
-    };
-  },
+  state = {
+    placement: 'bottom'
+  };
 
   // this dynamically changes the placement of the menu (top/bottom) to prevent it going offscreen and causing some
   // unsightly shifting
-  setPlacement: function (rowId) {
+  setPlacement = (rowId) => {
     var rowTop = document.getElementById(rowId).getBoundingClientRect().top;
     var toggleHeight = 150; // the height of the menu overlay, arrow, view row
     var placement = (rowTop + toggleHeight > window.innerHeight) ? 'top' : 'bottom';
     this.setState({ placement: placement });
-  },
+  };
 
-  createItems: function () {
+  createItems = () => {
 
     // sort the indexes alphabetically
     var sortedItems = this.props.items.sort();
@@ -192,9 +188,9 @@ var IndexSection = React.createClass({
         </li>
       );
     }, this);
-  },
+  };
 
-  indexAction: function (action, params, e) {
+  indexAction = (action, params, e) => {
     e.preventDefault();
 
     // ensures the menu gets closed. The hide() on the ref doesn't consistently close it
@@ -211,17 +207,17 @@ var IndexSection = React.createClass({
         params.onEdit(this.props.database.id, this.props.designDocName, params.indexName);
       break;
     }
-  },
+  };
 
-  toggle: function (e) {
+  toggle = (e) => {
     e.preventDefault();
     var newToggleState = !this.props.isExpanded;
     var state = newToggleState ? 'show' : 'hide';
     $(ReactDOM.findDOMNode(this)).find('.accordion-body').collapse(state);
     this.props.toggle(this.props.designDocName, this.props.title);
-  },
+  };
 
-  render: function () {
+  render() {
 
     // if this section has no content, omit it to prevent clutter. Otherwise it would show a toggle option that
     // would hide/show nothing
@@ -252,26 +248,23 @@ var IndexSection = React.createClass({
       </li>
     );
   }
-});
-
+}
 
-var DesignDoc = React.createClass({
-  propTypes: {
+class DesignDoc extends React.Component {
+  static propTypes = {
     database: PropTypes.object.isRequired,
     sidebarListTypes: PropTypes.array.isRequired,
     isExpanded: PropTypes.bool.isRequired,
     selectedNavInfo: PropTypes.object.isRequired,
     toggledSections: PropTypes.object.isRequired,
     designDocName:  PropTypes.string.isRequired
-  },
+  };
 
-  getInitialState: function () {
-    return {
-      updatedSidebarListTypes: this.props.sidebarListTypes
-    };
-  },
+  state = {
+    updatedSidebarListTypes: this.props.sidebarListTypes
+  };
 
-  componentWillMount: function () {
+  componentWillMount() {
     if (_.isEmpty(this.state.updatedSidebarListTypes) ||
       (_.has(this.state.updatedSidebarListTypes[0], 'selector') && this.state.updatedSidebarListTypes[0].selector !== 'views')) {
 
@@ -287,9 +280,9 @@ var DesignDoc = React.createClass({
       });
       this.setState({ updatedSidebarListTypes: newList });
     }
-  },
+  }
 
-  indexList: function () {
+  indexList = () => {
     return _.map(this.state.updatedSidebarListTypes, function (index, key) {
       var expanded = _.has(this.props.toggledSections, index.name) && this.props.toggledSections[index.name];
 
@@ -318,17 +311,17 @@ var DesignDoc = React.createClass({
           items={_.keys(this.props.designDoc[index.selector])} />
       );
     }.bind(this));
-  },
+  };
 
-  toggle: function (e) {
+  toggle = (e) => {
     e.preventDefault();
     var newToggleState = !this.props.isExpanded;
     var state = newToggleState ? 'show' : 'hide';
     $(ReactDOM.findDOMNode(this)).find('#' + Helpers.escapeJQuerySelector(this.props.designDocName)).collapse(state);
     this.props.toggle(this.props.designDocName);
-  },
+  };
 
-  getNewButtonLinks: function () {
+  getNewButtonLinks = () => {
     var newUrlPrefix = FauxtonAPI.urls('databaseBaseURL', 'app', encodeURIComponent(this.props.database.id));
     var designDocName = this.props.designDocName;
 
@@ -349,9 +342,9 @@ var DesignDoc = React.createClass({
       title: 'Add New',
       links: addNewLinks
     }];
-  },
+  };
 
-  render: function () {
+  render() {
     var buttonLinks = this.getNewButtonLinks();
     var toggleClassNames = 'design-doc-section accordion-header';
     var toggleBodyClassNames = 'design-doc-body accordion-body collapse';
@@ -388,16 +381,15 @@ var DesignDoc = React.createClass({
       </li>
     );
   }
-});
-
+}
 
-var DesignDocList = React.createClass({
-  componentWillMount: function () {
+class DesignDocList extends React.Component {
+  componentWillMount() {
     var list = FauxtonAPI.getExtensions('sidebar:list');
     this.sidebarListTypes = _.isUndefined(list) ? [] : list;
-  },
+  }
 
-  designDocList: function () {
+  designDocList = () => {
     return _.map(this.props.designDocs, function (designDoc, key) {
       var ddName = decodeURIComponent(designDoc.safeId);
 
@@ -427,19 +419,19 @@ var DesignDocList = React.createClass({
           database={this.props.database} />
       );
     }.bind(this));
-  },
+  };
 
-  render: function () {
+  render() {
     return (
       <ul className="nav nav-list">
         {this.designDocList()}
       </ul>
     );
   }
-});
+}
 
-var SidebarController = React.createClass({
-  getStoreState: function () {
+class SidebarController extends React.Component {
+  getStoreState = () => {
     return {
       database: store.getDatabase(),
       selectedNav: store.getSelected(),
@@ -467,23 +459,19 @@ var SidebarController = React.createClass({
       cloneIndexSourceDesignDocName: store.getCloneIndexModalSourceDesignDocName(),
       cloneIndexModalIndexLabel: store.getCloneIndexModalIndexLabel()
     };
-  },
-
-  getInitialState: function () {
-    return this.getStoreState();
-  },
+  };
 
-  componentDidMount: function () {
+  componentDidMount() {
     store.on('change', this.onChange, this);
     deleteDbModalStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount: function () {
+  componentWillUnmount() {
     store.off('change', this.onChange);
     deleteDbModalStore.off('change', this.onChange, this);
-  },
+  }
 
-  onChange: function () {
+  onChange = () => {
 
     const newState = this.getStoreState();
     // Workaround to signal Redux store that the design doc list was updated
@@ -494,15 +482,15 @@ var SidebarController = React.createClass({
     }
 
     this.setState(newState);
-  },
+  };
 
-  showDeleteDatabaseModal: function (payload) {
+  showDeleteDatabaseModal = (payload) => {
     ComponentsActions.showDeleteDatabaseModal(payload);
-  },
+  };
 
   // handles deleting of any index regardless of type. The delete handler and all relevant info is set when the user
   // clicks the delete action for a particular index
-  deleteIndex: function () {
+  deleteIndex = () => {
 
     // if the user is currently on the index that's being deleted, pass that info along to the delete handler. That can
     // be used to redirect the user to somewhere appropriate
@@ -517,9 +505,9 @@ var SidebarController = React.createClass({
       designDocs: this.state.designDocs,
       database: this.state.database
     });
-  },
+  };
 
-  cloneIndex: function () {
+  cloneIndex = () => {
     this.state.cloneIndexModalOnSubmit({
       sourceIndexName: this.state.cloneIndexSourceIndexName,
       sourceDesignDocName: this.state.cloneIndexSourceDesignDocName,
@@ -530,9 +518,11 @@ var SidebarController = React.createClass({
       database: this.state.database,
       onComplete: Actions.hideCloneIndexModal
     });
-  },
+  };
 
-  render: function () {
+  state = this.getStoreState();
+
+  render() {
     if (this.state.isLoading) {
       return <LoadLines />;
     }
@@ -572,11 +562,10 @@ var SidebarController = React.createClass({
       </nav>
     );
   }
-});
-
+}
 
-var CloneIndexModal = React.createClass({
-  propTypes: {
+class CloneIndexModal extends React.Component {
+  static propTypes = {
     visible: PropTypes.bool.isRequired,
     title: PropTypes.string,
     close: PropTypes.func.isRequired,
@@ -586,16 +575,14 @@ var CloneIndexModal = React.createClass({
     newDesignDocName: PropTypes.string.isRequired,
     newIndexName: PropTypes.string.isRequired,
     indexLabel: PropTypes.string.isRequired
-  },
+  };
 
-  getDefaultProps: function () {
-    return {
-      title: 'Clone Index',
-      visible: false
-    };
-  },
+  static defaultProps = {
+    title: 'Clone Index',
+    visible: false
+  };
 
-  submit: function () {
+  submit = () => {
     if (!this.refs.designDocSelector.validate()) {
       return;
     }
@@ -608,20 +595,20 @@ var CloneIndexModal = React.createClass({
       return;
     }
     this.props.submit();
-  },
+  };
 
-  close: function (e) {
+  close = (e) => {
     if (e) {
       e.preventDefault();
     }
     this.props.close();
-  },
+  };
 
-  setNewIndexName: function (e) {
+  setNewIndexName = (e) => {
     Actions.setNewCloneIndexName(e.target.value);
-  },
+  };
 
-  render: function () {
+  render() {
     return (
       <Modal dialogClassName="clone-index-modal" show={this.props.visible} onHide={this.close}>
         <Modal.Header closeButton={true}>
@@ -661,7 +648,7 @@ var CloneIndexModal = React.createClass({
       </Modal>
     );
   }
-});
+}
 
 export default {
   SidebarController: SidebarController,
diff --git a/app/addons/fauxton/components.js b/app/addons/fauxton/components.js
index ec2e03e..fb6d9fd 100644
--- a/app/addons/fauxton/components.js
+++ b/app/addons/fauxton/components.js
@@ -17,19 +17,18 @@ import PropTypes from 'prop-types';
 import React from "react";
 import ReactDOM from "react-dom";
 import { Modal } from "react-bootstrap";
+
 // import "velocity-animate/velocity";
 // import "velocity-animate/velocity.ui";
 
 
 // formats a block of code and pretty-prints it in the page. Currently uses the prettyPrint plugin
-var CodeFormat = React.createClass({
-  getDefaultProps: function () {
-    return {
-      lang: "js"
-    };
-  },
+class CodeFormat extends React.Component {
+  static defaultProps = {
+    lang: "js"
+  };
 
-  getClasses: function () {
+  getClasses = () => {
     // added for forward compatibility. This component defines an api via it's props so you can pass lang="N" and
     // not the class that prettyprint requires for that lang. If (when, hopefully!) we drop prettyprint we won't
     // have any change this component's props API and break things
@@ -42,37 +41,34 @@ var CodeFormat = React.createClass({
       classNames += ' ' + classMap[this.props.lang];
     }
     return classNames;
-  },
+  };
 
-  componentDidMount: function () {
+  componentDidMount() {
     // this one function is all the lib offers. It parses the entire page and pretty-prints anything with
     // a .prettyprint class; only executes on an element once
     prettyPrint();
-  },
+  }
 
-  render: function () {
+  render() {
     const code = JSON.stringify(this.props.code, null, " ");
     return (
       <div><pre className={this.getClasses()}>{code}</pre></div>
     );
   }
-});
-
-var Pagination = React.createClass({
-
-  getDefaultProps: function () {
-    return {
-      perPage: FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE,
-      onClick: null,
-      page: 1,
-      total: 0,
-      urlPrefix: '',
-      urlSuffix: '',
-      maxNavPages: 10
-    };
-  },
-
-  getVisiblePages: function (page, totalPages) {
+}
+
+class Pagination extends React.Component {
+  static defaultProps = {
+    perPage: FauxtonAPI.constants.MISC.DEFAULT_PAGE_SIZE,
+    onClick: null,
+    page: 1,
+    total: 0,
+    urlPrefix: '',
+    urlSuffix: '',
+    maxNavPages: 10
+  };
+
+  getVisiblePages = (page, totalPages) => {
     var from, to;
     if (totalPages < this.props.maxNavPages) {
       from = 1;
@@ -94,9 +90,9 @@ var Pagination = React.createClass({
       from: from,
       to: to
     };
-  },
+  };
 
-  createItemsForPage: function (visiblePages) {
+  createItemsForPage = (visiblePages) => {
     return _.range(visiblePages.from, visiblePages.to).map(function (i) {
       return (
         <li key={i} className={(this.props.page === i ? 'active' : null)}>
@@ -104,9 +100,9 @@ var Pagination = React.createClass({
         </li>
       );
     }.bind(this));
-  },
+  };
 
-  getLink: function (i, label) {
+  getLink = (i, label) => {
     if (this.props.onClick) {
       return (
         <a onClick={this.props.onClick.bind(null, i)} dangerouslySetInnerHTML={{__html: label}}></a>
@@ -115,13 +111,13 @@ var Pagination = React.createClass({
     return (
       <a href={this.props.urlPrefix + i + this.props.urlSuffix} dangerouslySetInnerHTML={{__html: label}}></a>
     );
-  },
+  };
 
-  getTotalPages: function () {
+  getTotalPages = () => {
     return this.props.total === 0 ? 1 : Math.ceil(this.props.total / this.props.perPage);
-  },
+  };
 
-  render: function () {
+  render() {
     var totalPages = this.getTotalPages();
     var visiblePages = this.getVisiblePages(this.props.page, totalPages);
     var rangeItems = this.createItemsForPage(visiblePages);
@@ -140,12 +136,11 @@ var Pagination = React.createClass({
       </ul>
     );
   }
-});
-
+}
 
 // a super-simple replacement for window.confirm()
-var ConfirmationModal = React.createClass({
-  propTypes: {
+class ConfirmationModal extends React.Component {
+  static propTypes = {
     visible: PropTypes.bool.isRequired,
     text: PropTypes.oneOfType([
       PropTypes.string,
@@ -153,28 +148,26 @@ var ConfirmationModal = React.createClass({
     ]).isRequired,
     onClose: PropTypes.func.isRequired,
     onSubmit: PropTypes.func.isRequired
-  },
-
-  getDefaultProps: function () {
-    return {
-      visible: false,
-      title: 'Please confirm',
-      text: '',
-      successButtonLabel: 'Okay',
-      buttonClass: 'btn-primary',
-      onClose: function () { },
-      onSubmit: function () { }
-    };
-  },
-
-  close: function (e) {
+  };
+
+  static defaultProps = {
+    visible: false,
+    title: 'Please confirm',
+    text: '',
+    successButtonLabel: 'Okay',
+    buttonClass: 'btn-primary',
+    onClose: function () { },
+    onSubmit: function () { }
+  };
+
+  close = (e) => {
     if (e) {
       e.preventDefault();
     }
     this.props.onClose();
-  },
+  };
 
-  render: function () {
+  render() {
     var content = <p>{this.props.text}</p>;
     if (!_.isString(this.props.text)) {
       content = this.props.text;
@@ -198,7 +191,7 @@ var ConfirmationModal = React.createClass({
       </Modal>
     );
   }
-});
+}
 
 
 export default {
diff --git a/app/addons/fauxton/navigation/container/NavBar.js b/app/addons/fauxton/navigation/container/NavBar.js
index c96fcfa..d5efb13 100644
--- a/app/addons/fauxton/navigation/container/NavBar.js
+++ b/app/addons/fauxton/navigation/container/NavBar.js
@@ -20,9 +20,8 @@ import NavBar from '../components/NavBar';
 
 const navBarStore = Stores.navBarStore;
 
-const NavBarContainer = React.createClass({
-
-  getStoreState () {
+class NavBarContainer extends React.Component {
+  getStoreState = () => {
     return {
       navLinks: navBarStore.getNavLinks(),
       bottomNavLinks: navBarStore.getBottomNavLinks(),
@@ -35,25 +34,23 @@ const NavBarContainer = React.createClass({
       isLoginSectionVisible: navBarStore.getIsLoginSectionVisible(),
       isLoginVisibleInsteadOfLogout: navBarStore.getIsLoginVisibleInsteadOfLogout()
     };
-  },
-
-  getInitialState () {
-    return this.getStoreState();
-  },
+  };
 
-  onChange () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
+
+  state = this.getStoreState();
 
-  componentDidMount () {
+  componentDidMount() {
     navBarStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount () {
+  componentWillUnmount() {
     navBarStore.off('change', this.onChange);
-  },
+  }
 
-  render () {
+  render() {
     const user = FauxtonAPI.session.user();
 
     const username =  (user && user.name) ? user.name : '';
@@ -61,8 +58,7 @@ const NavBarContainer = React.createClass({
       <NavBar {...this.state} username={username} />
     );
   }
-
-});
+}
 
 
 export default NavBarContainer;
diff --git a/app/addons/fauxton/notifications/notifications.js b/app/addons/fauxton/notifications/notifications.js
index 81c61ab..745cb2f 100644
--- a/app/addons/fauxton/notifications/notifications.js
+++ b/app/addons/fauxton/notifications/notifications.js
@@ -25,33 +25,28 @@ const {Copy} = Components;
 
 // The one-stop-shop for Fauxton notifications. This controller handler the header notifications and the rightmost
 // notification center panel
-export const NotificationController = React.createClass({
-
-  getInitialState () {
-    return this.getStoreState();
-  },
-
-  getStoreState () {
+export class NotificationController extends React.Component {
+  getStoreState = () => {
     return {
       notificationCenterVisible: store.isNotificationCenterVisible(),
       notificationCenterFilter: store.getNotificationFilter(),
       notifications: store.getNotifications()
     };
-  },
+  };
 
-  componentDidMount () {
+  componentDidMount() {
     store.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount () {
+  componentWillUnmount() {
     store.off('change', this.onChange);
-  },
+  }
 
-  onChange () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
 
-  getStyles () {
+  getStyles = () => {
     const isVisible = this.state.notificationCenterVisible;
     let item = {
       key: '1',
@@ -72,9 +67,9 @@ export const NotificationController = React.createClass({
       };
     }
     return [item];
-  },
+  };
 
-  getNotificationCenterPanel (items) {
+  getNotificationCenterPanel = (items) => {
     const panel = items.map(({style}) => {
       return <NotificationCenterPanel
         key={'1'}
@@ -88,9 +83,11 @@ export const NotificationController = React.createClass({
         {panel}
       </span>
     );
-  },
+  };
 
-  render () {
+  state = this.getStoreState();
+
+  render() {
     return (
       <div>
         <GlobalNotifications
@@ -102,30 +99,30 @@ export const NotificationController = React.createClass({
       </div>
     );
   }
-});
+}
 
 
-var GlobalNotifications = React.createClass({
-  propTypes: {
+class GlobalNotifications extends React.Component {
+  static propTypes = {
     notifications: PropTypes.array.isRequired
-  },
+  };
 
-  componentDidMount () {
+  componentDidMount() {
     $(document).on('keydown.notificationClose', this.onKeyDown);
-  },
+  }
 
-  componentWillUnmount () {
+  componentWillUnmount() {
     $(document).off('keydown.notificationClose', this.onKeyDown);
-  },
+  }
 
-  onKeyDown (e) {
+  onKeyDown = (e) => {
     var code = e.keyCode || e.which;
     if (code === 27) {
       Actions.hideAllVisibleNotifications();
     }
-  },
+  };
 
-  getNotifications () {
+  getNotifications = () => {
     if (!this.props.notifications.length) {
       return null;
     }
@@ -149,9 +146,9 @@ var GlobalNotifications = React.createClass({
           onHideComplete={Actions.hideNotification} />
       );
     }, this);
-  },
+  };
 
-  getchildren (items) {
+  getchildren = (items) => {
     const notifications = items.map(({key, data, style}) => {
       const notification = data;
       return (
@@ -173,9 +170,9 @@ var GlobalNotifications = React.createClass({
         {notifications}
       </div>
     );
-  },
+  };
 
-  getStyles (prevItems) {
+  getStyles = (prevItems) => {
     if (!prevItems) {
       prevItems = [];
     }
@@ -204,9 +201,9 @@ var GlobalNotifications = React.createClass({
           data: notification
         };
       });
-  },
+  };
 
-  render () {
+  render() {
     return (
       <div id="global-notifications">
         <TransitionMotion
@@ -217,11 +214,10 @@ var GlobalNotifications = React.createClass({
       </div>
     );
   }
-});
-
+}
 
-var Notification = React.createClass({
-  propTypes: {
+class Notification extends React.Component {
+  static propTypes = {
     msg: PropTypes.string.isRequired,
     onStartHide: PropTypes.func.isRequired,
     onHideComplete: PropTypes.func.isRequired,
@@ -229,48 +225,46 @@ var Notification = React.createClass({
     escape: PropTypes.bool,
     isHiding: PropTypes.bool.isRequired,
     visibleTime: PropTypes.number
-  },
+  };
 
-  getDefaultProps () {
-    return {
-      type: 'info',
-      visibleTime: 8000,
-      escape: true
-    };
-  },
+  static defaultProps = {
+    type: 'info',
+    visibleTime: 8000,
+    escape: true
+  };
 
-  componentWillUnmount () {
+  componentWillUnmount() {
     if (this.timeout) {
       window.clearTimeout(this.timeout);
     }
-  },
+  }
 
-  componentDidMount () {
+  componentDidMount() {
     this.timeout = setTimeout(this.hide, this.props.visibleTime);
-  },
+  }
 
-  hide (e) {
+  hide = (e) => {
     if (e) {
       e.preventDefault();
     }
     this.props.onStartHide(this.props.notificationId);
-  },
+  };
 
   // many messages contain HTML, hence the need for dangerouslySetInnerHTML
-  getMsg () {
+  getMsg = () => {
     var msg = (this.props.escape) ? _.escape(this.props.msg) : this.props.msg;
     return {
       __html: msg
     };
-  },
+  };
 
-  onAnimationComplete () {
+  onAnimationComplete = () => {
     if (this.props.isHiding) {
       window.setTimeout(() => this.props.onHideComplete(this.props.notificationId));
     }
-  },
+  };
 
-  render () {
+  render() {
     const {style, notificationId} = this.props;
     const iconMap = {
       error: 'fonticon-attention-circled',
@@ -296,41 +290,39 @@ var Notification = React.createClass({
       </div>
     );
   }
-});
+}
 
 
-export const NotificationCenterButton = React.createClass({
-  getInitialState () {
-    return {
-      visible: true
-    };
-  },
+export class NotificationCenterButton extends React.Component {
+  state = {
+    visible: true
+  };
 
-  hide () {
+  hide = () => {
     this.setState({ visible: false });
-  },
+  };
 
-  show () {
+  show = () => {
     this.setState({ visible: true });
-  },
+  };
 
-  render () {
+  render() {
     var classes = 'fonticon fonticon-bell' + ((!this.state.visible) ? ' hide' : '');
     return (
       <div className={classes} onClick={Actions.showNotificationCenter}></div>
     );
   }
-});
+}
 
 
-var NotificationCenterPanel = React.createClass({
-  propTypes: {
+class NotificationCenterPanel extends React.Component {
+  static propTypes = {
     visible: PropTypes.bool.isRequired,
     filter: PropTypes.string.isRequired,
     notifications: PropTypes.array.isRequired
-  },
+  };
 
-  getNotifications (items) {
+  getNotifications = (items) => {
     let notifications;
     if (!items.length && !this.props.notifications.length) {
         notifications = <li className="no-notifications">
@@ -356,9 +348,9 @@ var NotificationCenterPanel = React.createClass({
         {notifications}
       </ul>
     );
-  },
+  };
 
-  getStyles (prevItems = []) {
+  getStyles = (prevItems = []) => {
     return this.props.notifications
     .map(notification => {
       let item = prevItems.find(style => style.key === (notification.notificationId.toString()));
@@ -382,9 +374,9 @@ var NotificationCenterPanel = React.createClass({
         data: notification
       };
     });
-  },
+  };
 
-  render () {
+  render() {
     if (!this.props.visible && this.props.style.x === 0) {
       // panelClasses += ' visible';
       return null;
@@ -446,20 +438,19 @@ var NotificationCenterPanel = React.createClass({
       </div>
     );
   }
-});
-
+}
 
-var NotificationPanelRow = React.createClass({
-  propTypes: {
+class NotificationPanelRow extends React.Component {
+  static propTypes = {
     item: PropTypes.object.isRequired
-  },
+  };
 
-  clearNotification () {
+  clearNotification = () => {
     const {notificationId} = this.props.item;
     Actions.clearSingleNotification(notificationId);
-  },
+  };
 
-  render () {
+  render() {
     const iconMap = {
       success: 'fonticon-ok-circled',
       error: 'fonticon-attention-circled',
@@ -495,7 +486,7 @@ var NotificationPanelRow = React.createClass({
       </li>
     );
   }
-});
+}
 
 export class PermanentNotification extends React.Component {
   constructor (props) {
diff --git a/app/addons/permissions/components/PermissionsSection.js b/app/addons/permissions/components/PermissionsSection.js
index ba8958a..73f9577 100644
--- a/app/addons/permissions/components/PermissionsSection.js
+++ b/app/addons/permissions/components/PermissionsSection.js
@@ -21,30 +21,26 @@ import PermissionsItem from './PermissionsItem';
 
 const getDocUrl = app.helpers.getDocUrl;
 
-const PermissionsSection = React.createClass({
-  getInitialState: function () {
-    return {
-      newRole: '',
-      newName: ''
-    };
-  },
-
-  getDefaultProps: function () {
-    return {
-      names: [],
-      roles: []
-    };
-  },
-
-  getHelp: function () {
+class PermissionsSection extends React.Component {
+  static defaultProps = {
+    names: [],
+    roles: []
+  };
+
+  state = {
+    newRole: '',
+    newName: ''
+  };
+
+  getHelp = () => {
     if (this.props.section === 'admins') {
       return 'Database members can access the database. If no members are defined, the database is public. ';
     }
 
     return 'Database members can access the database. If no members are defined, the database is public. ';
-  },
+  };
 
-  isEmptyValue: function (value, type) {
+  isEmptyValue = (value, type) => {
     if (!_.isEmpty(value)) {
       return false;
     }
@@ -54,9 +50,9 @@ const PermissionsSection = React.createClass({
     });
 
     return true;
-  },
+  };
 
-  addNames: function (e) {
+  addNames = (e) => {
     e.preventDefault();
     if (this.isEmptyValue(this.state.newName, 'names')) {
       return;
@@ -68,9 +64,9 @@ const PermissionsSection = React.createClass({
     });
 
     this.setState({newName: ''});
-  },
+  };
 
-  addRoles: function (e) {
+  addRoles = (e) => {
     e.preventDefault();
     if (this.isEmptyValue(this.state.newRole, 'roles')) {
       return;
@@ -82,9 +78,9 @@ const PermissionsSection = React.createClass({
     });
 
     this.setState({newRole: ''});
-  },
+  };
 
-  getItems: function (items, type) {
+  getItems = (items, type) => {
     return items.map((item, i) => {
       return <PermissionsItem
         key={i}
@@ -93,25 +89,25 @@ const PermissionsSection = React.createClass({
         type={type}
         removeItem={this.props.removeItem} />;
     });
-  },
+  };
 
-  getNames: function () {
+  getNames = () => {
     return this.getItems(this.props.names, 'names');
-  },
+  };
 
-  getRoles: function () {
+  getRoles = () => {
     return this.getItems(this.props.roles, 'roles');
-  },
+  };
 
-  nameChange: function (e) {
+  nameChange = (e) => {
     this.setState({newName: e.target.value});
-  },
+  };
 
-  roleChange: function (e) {
+  roleChange = (e) => {
     this.setState({newRole: e.target.value});
-  },
+  };
 
-  render: function () {
+  render() {
 
     const { section } = this.props;
 
@@ -157,7 +153,6 @@ const PermissionsSection = React.createClass({
     </div>
     );
   }
-
-});
+}
 
 export default PermissionsSection;
diff --git a/app/addons/setup/setup.js b/app/addons/setup/setup.js
index 4b7bd41..d48d29a 100644
--- a/app/addons/setup/setup.js
+++ b/app/addons/setup/setup.js
@@ -21,30 +21,26 @@ var setupStore = SetupStores.setupStore;
 var ConfirmButton = ReactComponents.ConfirmButton;
 
 
-var ClusterConfiguredScreen = React.createClass({
-  getInitialState: function () {
-    return this.getStoreState();
-  },
-
-  getStoreState: function () {
+class ClusterConfiguredScreen extends React.Component {
+  getStoreState = () => {
     return {
       clusterState: setupStore.getClusterState()
     };
-  },
+  };
 
-  componentDidMount: function () {
+  componentDidMount() {
     setupStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount: function () {
+  componentWillUnmount() {
     setupStore.off('change', this.onChange);
-  },
+  }
 
-  onChange: function () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
 
-  getNodeType: function() {
+  getNodeType = () => {
     if (this.state.clusterState === 'cluster_finished') {
       return 'clustered';
     } else if (this.state.clusterState === 'single_node_enabled') {
@@ -52,9 +48,11 @@ var ClusterConfiguredScreen = React.createClass({
     } else {
       return 'unknown state';
     }
-  },
+  };
+
+  state = this.getStoreState();
 
-  render: function () {
+  render() {
     var nodetype = this.getNodeType();
 
     return (
@@ -66,11 +64,10 @@ var ClusterConfiguredScreen = React.createClass({
       </div>
     );
   }
-});
+}
 
-var SetupCurrentAdminPassword = React.createClass({
-
-  render: function () {
+class SetupCurrentAdminPassword extends React.Component {
+  render() {
     var text = 'Specify your Admin credentials';
 
     if (this.props.adminParty) {
@@ -94,24 +91,20 @@ var SetupCurrentAdminPassword = React.createClass({
           type="password" />
       </div>
     );
-  },
-
+  }
+}
 
-});
+class SetupNodeCountSetting extends React.Component {
+  state = {
+    nodeCountValue: this.props.nodeCountValue
+  };
 
-var SetupNodeCountSetting = React.createClass({
-  getInitialState: function () {
-    return {
-      nodeCountValue: this.props.nodeCountValue
-    };
-  },
-
-  handleNodeCountChange: function (event) {
+  handleNodeCountChange = (event) => {
     this.props.onAlterNodeCount(event);
     this.setState({nodeCountValue: event.target.value});
-  },
+  };
 
-  render: function () {
+  render() {
     return (
       <div className="setup-node-count">
         <p>Number of nodes to be added to the cluster (including this one)</p>
@@ -124,27 +117,25 @@ var SetupNodeCountSetting = React.createClass({
       </div>
     );
   }
-});
+}
 
-var SetupOptionalSettings = React.createClass({
-  getInitialState: function () {
-    return {
-      ipValue: this.props.ipInitialValue,
-      portValue: this.props.portValue
-    };
-  },
+class SetupOptionalSettings extends React.Component {
+  state = {
+    ipValue: this.props.ipInitialValue,
+    portValue: this.props.portValue
+  };
 
-  handleIpChange: function (event) {
+  handleIpChange = (event) => {
     this.props.onAlterBindAddress(event);
     this.setState({ipValue: event.target.value});
-  },
+  };
 
-  handlePortChange: function (event) {
+  handlePortChange = (event) => {
     this.props.onAlterPort(event);
     this.setState({portValue: event.target.value});
-  },
+  };
 
-  render: function () {
+  render() {
     return (
       <div className="setup-opt-settings">
         <p>Bind address the node will listen on</p>
@@ -167,36 +158,31 @@ var SetupOptionalSettings = React.createClass({
       </div>
     );
   }
-});
+}
 
-var SetupMultipleNodesController = React.createClass({
-
-  getInitialState: function () {
-    return this.getStoreState();
-  },
-
-  getStoreState: function () {
+class SetupMultipleNodesController extends React.Component {
+  getStoreState = () => {
     return {
       nodeList: setupStore.getNodeList(),
       isAdminParty: setupStore.getIsAdminParty(),
       remoteAddress: setupStore.getAdditionalNode().remoteAddress
     };
-  },
+  };
 
-  componentDidMount: function () {
+  componentDidMount() {
     this.isAdminParty = setupStore.getIsAdminParty();
     setupStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount: function () {
+  componentWillUnmount() {
     setupStore.off('change', this.onChange);
-  },
+  }
 
-  onChange: function () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
 
-  getNodeList: function () {
+  getNodeList = () => {
     return this.state.nodeList.map(function (el, i) {
       return (
         <div key={i} className="node-item">
@@ -204,49 +190,51 @@ var SetupMultipleNodesController = React.createClass({
         </div>
       );
     }, this);
-  },
+  };
 
-  addNode: function () {
+  addNode = () => {
     SetupActions.addNode(this.isAdminParty);
-  },
+  };
 
-  alterPortAdditionalNode: function (e) {
+  alterPortAdditionalNode = (e) => {
     SetupActions.alterPortAdditionalNode(e.target.value);
-  },
+  };
 
-  alterBindAddressAdditionalNode: function (e) {
+  alterBindAddressAdditionalNode = (e) => {
     SetupActions.alterBindAddressAdditionalNode(e.target.value);
-  },
+  };
 
-  alterRemoteAddressAdditionalNode: function (e) {
+  alterRemoteAddressAdditionalNode = (e) => {
     SetupActions.alterRemoteAddressAdditionalNode(e.target.value);
-  },
+  };
 
-  alterUsername: function (e) {
+  alterUsername = (e) => {
     SetupActions.setUsername(e.target.value);
-  },
+  };
 
-  alterPassword: function (e) {
+  alterPassword = (e) => {
     SetupActions.setPassword(e.target.value);
-  },
+  };
 
-  alterBindAddressSetupNode: function (e) {
+  alterBindAddressSetupNode = (e) => {
     SetupActions.setBindAddressForSetupNode(e.target.value);
-  },
+  };
 
-  alterPortSetupNode: function (e) {
+  alterPortSetupNode = (e) => {
     SetupActions.setPortForSetupNode(e.target.value);
-  },
+  };
 
-  alterNodeCount: function (e) {
+  alterNodeCount = (e) => {
     SetupActions.setNodeCount(e.target.value);
-  },
+  };
 
-  finishClusterSetup: function () {
+  finishClusterSetup = () => {
     SetupActions.finishClusterSetup('CouchDB Cluster set up!');
-  },
+  };
+
+  state = this.getStoreState();
 
-  render: function () {
+  render() {
 
     return (
       <div className="setup-nodes">
@@ -296,49 +284,44 @@ var SetupMultipleNodesController = React.createClass({
       </div>
     );
   }
-});
-
-var SetupSingleNodeController = React.createClass({
-
-  getInitialState: function () {
-    return this.getStoreState();
-  },
+}
 
-  getStoreState: function () {
+class SetupSingleNodeController extends React.Component {
+  getStoreState = () => {
     return {
       isAdminParty: setupStore.getIsAdminParty()
     };
-  },
+  };
 
-  componentDidMount: function () {
+  componentDidMount() {
     setupStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount: function () {
+  componentWillUnmount() {
     setupStore.off('change', this.onChange);
-  },
+  }
 
-  onChange: function () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
 
-  alterUsername: function (e) {
+  alterUsername = (e) => {
     SetupActions.setUsername(e.target.value);
-  },
+  };
 
-  alterPassword: function (e) {
+  alterPassword = (e) => {
     SetupActions.setPassword(e.target.value);
-  },
+  };
 
-  alterBindAddress: function (e) {
+  alterBindAddress = (e) => {
     SetupActions.setBindAddressForSetupNode(e.target.value);
-  },
+  };
 
-  alterPort: function (e) {
+  alterPort = (e) => {
     SetupActions.setPortForSetupNode(e.target.value);
-  },
+  };
 
-  render: function () {
+  render() {
     return (
       <div className="setup-nodes">
         <div className="setup-setupnode-section">
@@ -355,39 +338,36 @@ var SetupSingleNodeController = React.createClass({
         </div>
       </div>
     );
-  },
+  }
 
-  finishSingleNode: function (e) {
+  finishSingleNode = (e) => {
     e.preventDefault();
     SetupActions.setupSingleNode();
-  }
-});
-
-var SetupFirstStepController = React.createClass({
+  };
 
-  getInitialState: function () {
-    return this.getStoreState();
-  },
+  state = this.getStoreState();
+}
 
-  getStoreState: function () {
+class SetupFirstStepController extends React.Component {
+  getStoreState = () => {
     return {
       clusterState: setupStore.getClusterState()
     };
-  },
+  };
 
-  componentDidMount: function () {
+  componentDidMount() {
     setupStore.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount: function () {
+  componentWillUnmount() {
     setupStore.off('change', this.onChange);
-  },
+  }
 
-  onChange: function () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
 
-  render: function () {
+  render() {
     if (this.state.clusterState === 'cluster_finished' ||
         this.state.clusterState === 'single_node_enabled') {
       return (<ClusterConfiguredScreen />);
@@ -415,18 +395,20 @@ var SetupFirstStepController = React.createClass({
         </div>
       </div>
     );
-  },
+  }
 
-  redirectToSingleNodeSetup: function (e) {
+  redirectToSingleNodeSetup = (e) => {
     e.preventDefault();
     FauxtonAPI.navigate('#setup/singlenode');
-  },
+  };
 
-  redirectToMultiNodeSetup: function (e) {
+  redirectToMultiNodeSetup = (e) => {
     e.preventDefault();
     FauxtonAPI.navigate('#setup/multinode');
-  }
-});
+  };
+
+  state = this.getStoreState();
+}
 
 export default {
   SetupMultipleNodesController: SetupMultipleNodesController,
diff --git a/app/addons/verifyinstall/components.js b/app/addons/verifyinstall/components.js
index 909a12a..16f74ed 100644
--- a/app/addons/verifyinstall/components.js
+++ b/app/addons/verifyinstall/components.js
@@ -19,35 +19,33 @@ import Stores from "./stores";
 
 const store = Stores.verifyInstallStore;
 
-const VerifyInstallController = React.createClass({
-  getInitialState: function () {
-    return this.getStoreState();
-  },
-
-  getStoreState: function () {
+class VerifyInstallController extends React.Component {
+  getStoreState = () => {
     return {
       isVerifying: store.checkIsVerifying(),
       testResults: store.getTestResults()
     };
-  },
+  };
 
-  startVerification: function () {
+  startVerification = () => {
     Actions.startVerification();
-  },
+  };
 
-  onChange: function () {
+  onChange = () => {
     this.setState(this.getStoreState());
-  },
+  };
+
+  state = this.getStoreState();
 
-  componentDidMount: function () {
+  componentDidMount() {
     store.on('change', this.onChange, this);
-  },
+  }
 
-  componentWillUnmount: function () {
+  componentWillUnmount() {
     store.off('change', this.onChange);
-  },
+  }
 
-  render: function () {
+  render() {
     return (
       <div>
         <VerifyInstallButton verify={this.startVerification} isVerifying={this.state.isVerifying} />
@@ -55,31 +53,29 @@ const VerifyInstallController = React.createClass({
       </div>
     );
   }
-});
-
+}
 
-var VerifyInstallButton = React.createClass({
-  propTypes: {
+class VerifyInstallButton extends React.Component {
+  static propTypes = {
     verify: PropTypes.func.isRequired,
     isVerifying: PropTypes.bool.isRequired
-  },
+  };
 
-  render: function () {
+  render() {
     return (
       <button id="start" className="btn btn-primary" onClick={this.props.verify} disabled={this.props.isVerifying}>
         {this.props.isVerifying ? 'Verifying' : 'Verify Installation'}
       </button>
     );
   }
-});
-
+}
 
-var VerifyInstallResults = React.createClass({
-  propTypes: {
+class VerifyInstallResults extends React.Component {
+  static propTypes = {
     testResults: PropTypes.object.isRequired
-  },
+  };
 
-  showTestResult: function (test) {
+  showTestResult = (test) => {
     if (!this.props.testResults[test].complete) {
       return '';
     }
@@ -87,9 +83,9 @@ var VerifyInstallResults = React.createClass({
       return <span>&#10003;</span>;
     }
     return <span>&#x2717;</span>;
-  },
+  };
 
-  render: function () {
+  render() {
     return (
       <table className="table table-striped table-bordered">
         <thead>
@@ -127,7 +123,7 @@ var VerifyInstallResults = React.createClass({
       </table>
     );
   }
-});
+}
 
 export default {
   VerifyInstallController: VerifyInstallController,
diff --git a/assets/less/fauxton.less b/assets/less/fauxton.less
index d2c3e9b..06eb2a4 100644
--- a/assets/less/fauxton.less
+++ b/assets/less/fauxton.less
@@ -685,3 +685,14 @@ body .control-toggle-include-docs span {
 .btn-space {
   margin-right: 5px;
 }
+
+.sr-only {
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  margin: -1px;
+  padding: 0;
+  overflow: hidden;
+  clip: rect(0,0,0,0);
+  border: 0;
+}

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

Mime
View raw message