Selaa lähdekoodia

Cleanup React components constructor

In most situations the constructor does not need to be overridden for
React components. Function binding can be done using an ES6 decorator
and state initialisation can be done outside the constructor.

Also includes an updated React linting package and rules so that the
order / sorting of the React components' functions and variables are
improved.
Sergiu Miclea 7 vuotta sitten
vanhempi
sitoutus
87cc80c137
45 muutettua tiedostoa jossa 319 lisäystä ja 425 poistoa
  1. 50 16
      .eslintrc
  2. 2 1
      package.json
  3. 2 6
      src/components/atoms/PasswordValue/PasswordValue.jsx
  4. 2 6
      src/components/atoms/Switch/Switch.jsx
  5. 10 17
      src/components/molecules/AutocompleteDropdown/AutocompleteDropdown.jsx
  6. 8 15
      src/components/molecules/DatetimePicker/DatetimePicker.jsx
  7. 8 15
      src/components/molecules/Dropdown/Dropdown.jsx
  8. 6 11
      src/components/molecules/DropdownFilter/DropdownFilter.jsx
  9. 7 12
      src/components/molecules/DropdownLink/DropdownLink.jsx
  10. 2 7
      src/components/molecules/Modal/Modal.jsx
  11. 6 11
      src/components/molecules/NewItemDropdown/NewItemDropdown.jsx
  12. 4 9
      src/components/molecules/NotificationDropdown/NotificationDropdown.jsx
  13. 12 16
      src/components/molecules/SearchInput/SearchInput.jsx
  14. 2 6
      src/components/molecules/SideMenu/SideMenu.jsx
  15. 6 11
      src/components/molecules/UserDropdown/UserDropdown.jsx
  16. 5 9
      src/components/organisms/AssessmentMigrationOptions/AssessmentMigrationOptions.jsx
  17. 9 13
      src/components/organisms/Endpoint/Endpoint.jsx
  18. 2 6
      src/components/organisms/Executions/Executions.jsx
  19. 7 10
      src/components/organisms/FilterList/FilterList.jsx
  20. 3 7
      src/components/organisms/LoginForm/LoginForm.jsx
  21. 1 6
      src/components/organisms/Notifications/Notifications.jsx
  22. 9 12
      src/components/organisms/PageHeader/PageHeader.jsx
  23. 2 2
      src/components/organisms/ProjectDetailsContent/ProjectDetailsContent.jsx
  24. 2 6
      src/components/organisms/ReplicaDetailsContent/ReplicaDetailsContent.jsx
  25. 2 6
      src/components/organisms/ReplicaExecutionOptions/ReplicaExecutionOptions.jsx
  26. 18 21
      src/components/organisms/ReplicaMigrationOptions/ReplicaMigrationOptions.jsx
  27. 5 9
      src/components/organisms/Schedule/Schedule.jsx
  28. 4 8
      src/components/organisms/Tasks/Tasks.jsx
  29. 5 9
      src/components/organisms/WizardInstances/WizardInstances.jsx
  30. 2 7
      src/components/organisms/WizardOptions/WizardOptions.jsx
  31. 3 7
      src/components/organisms/WizardPageContent/WizardPageContent.jsx
  32. 8 12
      src/components/pages/AssessmentDetailsPage/AssessmentDetailsPage.jsx
  33. 3 3
      src/components/pages/AssessmentsPage/AssessmentsPage.jsx
  34. 7 11
      src/components/pages/EndpointDetailsPage/EndpointDetailsPage.jsx
  35. 12 16
      src/components/pages/EndpointsPage/EndpointsPage.jsx
  36. 5 9
      src/components/pages/MigrationDetailsPage/MigrationDetailsPage.jsx
  37. 7 11
      src/components/pages/MigrationsPage/MigrationsPage.jsx
  38. 3 3
      src/components/pages/ProjectsPage/ProjectsPage.jsx
  39. 10 14
      src/components/pages/ReplicaDetailsPage/ReplicaDetailsPage.jsx
  40. 6 10
      src/components/pages/ReplicasPage/ReplicasPage.jsx
  41. 3 3
      src/components/pages/UsersPage/UsersPage.jsx
  42. 8 11
      src/components/pages/WizardPage/WizardPage.jsx
  43. 5 9
      src/plugins/endpoint/azure/ContentPlugin.jsx
  44. 5 8
      src/plugins/endpoint/openstack/ContentPlugin.jsx
  45. 31 8
      yarn.lock

+ 50 - 16
.eslintrc

@@ -22,22 +22,56 @@
     }
     }
   },
   },
   "rules": {
   "rules": {
-    "react/sort-comp": [1, {
-      "order": [
-        "static-methods",
-        "type-annotations",
-        "lifecycle",
-        "/^set.+$/",
-        "/^get.+$/",
-        "/^is.+$/",
-        "/^has.+$/",
-        "/^handle.+$/",
-        "everything-else",
-        "render"
-      ]
-    }],
-    "semi": [2, "never"],
-    "comma-dangle": [2, "always-multiline"],
+    "react/sort-comp": [
+      1,
+      {
+        "order": [
+          "static-methods",
+          "displayName",
+          "propTypes",
+          "contextTypes",
+          "childContextTypes",
+          "mixins",
+          "statics",
+          "defaultProps",
+          "state",
+          "type-annotations",
+          "instance-variables",
+          "getters",
+          "setters",
+          "constructor",
+          "getDefaultProps",
+          "getInitialState",
+          "getChildContext",
+          "getDerivedStateFromProps",
+          "lifecycle",
+          "everything-else",
+          "^handle.+$",
+          "render"
+        ],
+        "groups": {
+          "lifecycle": [
+            "componentWillMount",
+            "componentDidMount",
+            "componentWillReceiveProps",
+            "shouldComponentUpdate",
+            "componentWillUpdate",
+            "getSnapshotBeforeUpdate",
+            "componentDidUpdate",
+            "componentDidCatch",
+            "componentWillUnmount"
+          ]
+        }
+      }
+    ],
+    "semi": [
+      2,
+      "never"
+    ],
+    "comma-dangle": [
+      2,
+      "always-multiline"
+    ],
     "newline-per-chained-call": 0,
     "newline-per-chained-call": 0,
     "class-methods-use-this": 0,
     "class-methods-use-this": 0,
     "max-len": 0,
     "max-len": 0,

+ 2 - 1
package.json

@@ -46,7 +46,7 @@
     "eslint-plugin-flowtype": "^2.46.1",
     "eslint-plugin-flowtype": "^2.46.1",
     "eslint-plugin-import": "^2.7.0",
     "eslint-plugin-import": "^2.7.0",
     "eslint-plugin-jsx-a11y": "^6.0.2",
     "eslint-plugin-jsx-a11y": "^6.0.2",
-    "eslint-plugin-react": "^7.4.0",
+    "eslint-plugin-react": "7.10.0",
     "flow-bin": "0.78.0",
     "flow-bin": "0.78.0",
     "flow-typed": "2.5.1",
     "flow-typed": "2.5.1",
     "jest": "^21.2.1",
     "jest": "^21.2.1",
@@ -57,6 +57,7 @@
   },
   },
   "dependencies": {
   "dependencies": {
     "@webpack-blocks/webpack2": "^0.4.0",
     "@webpack-blocks/webpack2": "^0.4.0",
+    "autobind-decorator": "^2.1.0",
     "axios": "^0.18.0",
     "axios": "^0.18.0",
     "babel-core": "^6.26.0",
     "babel-core": "^6.26.0",
     "babel-loader": "^7.1.2",
     "babel-loader": "^7.1.2",

+ 2 - 6
src/components/atoms/PasswordValue/PasswordValue.jsx

@@ -54,12 +54,8 @@ type State = {
 }
 }
 @observer
 @observer
 class PasswordValue extends React.Component<Props, State> {
 class PasswordValue extends React.Component<Props, State> {
-  constructor() {
-    super()
-
-    this.state = {
-      show: false,
-    }
+  state = {
+    show: false,
   }
   }
 
 
   handleShowClick() {
   handleShowClick() {

+ 2 - 6
src/components/atoms/Switch/Switch.jsx

@@ -140,12 +140,8 @@ class Switch extends React.Component<Props, State> {
     height: 24,
     height: 24,
   }
   }
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      lastChecked: null,
-    }
+  state = {
+    lastChecked: null,
   }
   }
 
 
   getLabel() {
   getLabel() {

+ 10 - 17
src/components/molecules/AutocompleteDropdown/AutocompleteDropdown.jsx

@@ -18,6 +18,7 @@ import React from 'react'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
 import styled, { css } from 'styled-components'
 import styled, { css } from 'styled-components'
 import ReactDOM from 'react-dom'
 import ReactDOM from 'react-dom'
+import autobind from 'autobind-decorator'
 
 
 import AutocompleteInput from '../../atoms/AutocompleteInput'
 import AutocompleteInput from '../../atoms/AutocompleteInput'
 import { Tip, updateTipStyle, scrollItemIntoView } from '../Dropdown'
 import { Tip, updateTipStyle, scrollItemIntoView } from '../Dropdown'
@@ -120,6 +121,13 @@ class AutocompleteDropdown extends React.Component<Props, State> {
     noItemsMessage: 'No results found',
     noItemsMessage: 'No results found',
   }
   }
 
 
+  state = {
+    showDropdownList: false,
+    firstItemHover: false,
+    searchValue: '',
+    filteredItems: [],
+  }
+
   buttonRef: HTMLElement
   buttonRef: HTMLElement
   listRef: HTMLElement
   listRef: HTMLElement
   listItemsRef: HTMLElement
   listItemsRef: HTMLElement
@@ -129,23 +137,6 @@ class AutocompleteDropdown extends React.Component<Props, State> {
   buttonRect: ClientRect
   buttonRect: ClientRect
   itemMouseDown: boolean
   itemMouseDown: boolean
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      showDropdownList: false,
-      firstItemHover: false,
-      searchValue: '',
-      filteredItems: [],
-    }
-
-    // $FlowIssue
-    this.handlePageClick = this.handlePageClick.bind(this)
-
-    // $FlowIssue
-    this.handleScroll = this.handleScroll.bind(this)
-  }
-
   componentWillMount() {
   componentWillMount() {
     this.setState({
     this.setState({
       filteredItems: this.props.items,
       filteredItems: this.props.items,
@@ -218,6 +209,7 @@ class AutocompleteDropdown extends React.Component<Props, State> {
     })
     })
   }
   }
 
 
+  @autobind
   handleScroll() {
   handleScroll() {
     if (this.buttonRef) {
     if (this.buttonRef) {
       if (DomUtils.isElementInViewport(this.buttonRef, this.scrollableParent)) {
       if (DomUtils.isElementInViewport(this.buttonRef, this.scrollableParent)) {
@@ -229,6 +221,7 @@ class AutocompleteDropdown extends React.Component<Props, State> {
     }
     }
   }
   }
 
 
+  @autobind
   handlePageClick() {
   handlePageClick() {
     if (!this.itemMouseDown) {
     if (!this.itemMouseDown) {
       this.setState({ showDropdownList: false })
       this.setState({ showDropdownList: false })

+ 8 - 15
src/components/molecules/DatetimePicker/DatetimePicker.jsx

@@ -20,6 +20,7 @@ import { observer } from 'mobx-react'
 import styled, { injectGlobal } from 'styled-components'
 import styled, { injectGlobal } from 'styled-components'
 import Datetime from 'react-datetime'
 import Datetime from 'react-datetime'
 import moment from 'moment'
 import moment from 'moment'
+import autobind from 'autobind-decorator'
 
 
 import DropdownButton from '../../atoms/DropdownButton'
 import DropdownButton from '../../atoms/DropdownButton'
 
 
@@ -63,26 +64,16 @@ type State = {
 }
 }
 @observer
 @observer
 class DatetimePicker extends React.Component<Props, State> {
 class DatetimePicker extends React.Component<Props, State> {
+  state = {
+    showPicker: false,
+    date: null,
+  }
+
   itemMouseDown: boolean
   itemMouseDown: boolean
   portalRef: HTMLElement
   portalRef: HTMLElement
   buttonRef: HTMLElement
   buttonRef: HTMLElement
   scrollableParent: HTMLElement
   scrollableParent: HTMLElement
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      showPicker: false,
-      date: null,
-    }
-
-    // $FlowIssue
-    this.handlePageClick = this.handlePageClick.bind(this)
-
-    // $FlowIssue
-    this.handleScroll = this.handleScroll.bind(this)
-  }
-
   componentWillMount() {
   componentWillMount() {
     if (this.props.value) {
     if (this.props.value) {
       this.setState({ date: moment(this.props.value) })
       this.setState({ date: moment(this.props.value) })
@@ -136,6 +127,7 @@ class DatetimePicker extends React.Component<Props, State> {
     return this.props.isValidDate(currentDate, selectedDate)
     return this.props.isValidDate(currentDate, selectedDate)
   }
   }
 
 
+  @autobind
   handleScroll() {
   handleScroll() {
     if (this.buttonRef) {
     if (this.buttonRef) {
       if (DomUtils.isElementInViewport(this.buttonRef, this.scrollableParent)) {
       if (DomUtils.isElementInViewport(this.buttonRef, this.scrollableParent)) {
@@ -146,6 +138,7 @@ class DatetimePicker extends React.Component<Props, State> {
     }
     }
   }
   }
 
 
+  @autobind
   handlePageClick(e: Event) {
   handlePageClick(e: Event) {
     let path = DomUtils.getEventPath(e)
     let path = DomUtils.getEventPath(e)
 
 

+ 8 - 15
src/components/molecules/Dropdown/Dropdown.jsx

@@ -18,6 +18,7 @@ import React from 'react'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
 import styled, { css } from 'styled-components'
 import styled, { css } from 'styled-components'
 import ReactDOM from 'react-dom'
 import ReactDOM from 'react-dom'
+import autobind from 'autobind-decorator'
 
 
 import DropdownButton from '../../atoms/DropdownButton'
 import DropdownButton from '../../atoms/DropdownButton'
 
 
@@ -203,6 +204,11 @@ class Dropdown extends React.Component<Props, State> {
     noSelectionMessage: 'Select an item',
     noSelectionMessage: 'Select an item',
   }
   }
 
 
+  state = {
+    showDropdownList: false,
+    firstItemHover: false,
+  }
+
   buttonRef: HTMLElement
   buttonRef: HTMLElement
   listRef: HTMLElement
   listRef: HTMLElement
   listItemsRef: HTMLElement
   listItemsRef: HTMLElement
@@ -212,21 +218,6 @@ class Dropdown extends React.Component<Props, State> {
   buttonRect: ClientRect
   buttonRect: ClientRect
   itemMouseDown: boolean
   itemMouseDown: boolean
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      showDropdownList: false,
-      firstItemHover: false,
-    }
-
-    // $FlowIssue
-    this.handlePageClick = this.handlePageClick.bind(this)
-
-    // $FlowIssue
-    this.handleScroll = this.handleScroll.bind(this)
-  }
-
   componentDidMount() {
   componentDidMount() {
     window.addEventListener('mousedown', this.handlePageClick, false)
     window.addEventListener('mousedown', this.handlePageClick, false)
     if (this.buttonRef) {
     if (this.buttonRef) {
@@ -271,6 +262,7 @@ class Dropdown extends React.Component<Props, State> {
     return (item[valueField] != null && item[valueField].toString()) || this.getLabel(item)
     return (item[valueField] != null && item[valueField].toString()) || this.getLabel(item)
   }
   }
 
 
+  @autobind
   handleScroll() {
   handleScroll() {
     if (this.buttonRef) {
     if (this.buttonRef) {
       if (DomUtils.isElementInViewport(this.buttonRef, this.scrollableParent)) {
       if (DomUtils.isElementInViewport(this.buttonRef, this.scrollableParent)) {
@@ -282,6 +274,7 @@ class Dropdown extends React.Component<Props, State> {
     }
     }
   }
   }
 
 
+  @autobind
   handlePageClick() {
   handlePageClick() {
     if (!this.itemMouseDown) {
     if (!this.itemMouseDown) {
       this.setState({ showDropdownList: false })
       this.setState({ showDropdownList: false })

+ 6 - 11
src/components/molecules/DropdownFilter/DropdownFilter.jsx

@@ -17,6 +17,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import React from 'react'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
 import styled from 'styled-components'
 import styled from 'styled-components'
+import autobind from 'autobind-decorator'
 
 
 import SearchInput from '../SearchInput'
 import SearchInput from '../SearchInput'
 
 
@@ -81,19 +82,12 @@ class DropdownFilter extends React.Component<Props, State> {
     searchPlaceholder: 'Filter',
     searchPlaceholder: 'Filter',
   }
   }
 
 
-  itemMouseDown: boolean
-
-  constructor() {
-    super()
-
-    // $FlowIssue
-    this.handlePageClick = this.handlePageClick.bind(this)
-
-    this.state = {
-      showDropdownList: false,
-    }
+  state = {
+    showDropdownList: false,
   }
   }
 
 
+  itemMouseDown: boolean
+
   componentDidMount() {
   componentDidMount() {
     window.addEventListener('mousedown', this.handlePageClick, false)
     window.addEventListener('mousedown', this.handlePageClick, false)
   }
   }
@@ -102,6 +96,7 @@ class DropdownFilter extends React.Component<Props, State> {
     window.removeEventListener('mousedown', this.handlePageClick, false)
     window.removeEventListener('mousedown', this.handlePageClick, false)
   }
   }
 
 
+  @autobind
   handlePageClick() {
   handlePageClick() {
     if (!this.itemMouseDown) {
     if (!this.itemMouseDown) {
       this.setState({ showDropdownList: false })
       this.setState({ showDropdownList: false })

+ 7 - 12
src/components/molecules/DropdownLink/DropdownLink.jsx

@@ -18,6 +18,7 @@ import React from 'react'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
 import styled, { css } from 'styled-components'
 import styled, { css } from 'styled-components'
 import ReactDOM from 'react-dom'
 import ReactDOM from 'react-dom'
+import autobind from 'autobind-decorator'
 
 
 import SearchInput from '../../molecules/SearchInput'
 import SearchInput from '../../molecules/SearchInput'
 
 
@@ -151,6 +152,11 @@ class DropdownLink extends React.Component<Props, State> {
     noItemsLabel: 'No items',
     noItemsLabel: 'No items',
   }
   }
 
 
+  state = {
+    showDropdownList: false,
+    searchText: '',
+  }
+
   itemMouseDown: boolean
   itemMouseDown: boolean
   labelRef: HTMLElement
   labelRef: HTMLElement
   listItemsRef: HTMLElement
   listItemsRef: HTMLElement
@@ -159,18 +165,6 @@ class DropdownLink extends React.Component<Props, State> {
   tipRef: HTMLElement
   tipRef: HTMLElement
   searchInputWrapperRef: HTMLElement
   searchInputWrapperRef: HTMLElement
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      showDropdownList: false,
-      searchText: '',
-    }
-
-    const self: any = this
-    self.handlePageClick = this.handlePageClick.bind(this)
-  }
-
   componentDidMount() {
   componentDidMount() {
     window.addEventListener('mousedown', this.handlePageClick, false)
     window.addEventListener('mousedown', this.handlePageClick, false)
     this.setLabelWidth()
     this.setLabelWidth()
@@ -214,6 +208,7 @@ class DropdownLink extends React.Component<Props, State> {
     )
     )
   }
   }
 
 
+  @autobind
   handlePageClick() {
   handlePageClick() {
     if (!this.itemMouseDown) {
     if (!this.itemMouseDown) {
       this.setState({ showDropdownList: false })
       this.setState({ showDropdownList: false })

+ 2 - 7
src/components/molecules/Modal/Modal.jsx

@@ -18,6 +18,7 @@ import * as React from 'react'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
 import styled from 'styled-components'
 import styled from 'styled-components'
 import Modal from 'react-modal'
 import Modal from 'react-modal'
+import autobind from 'autobind-decorator'
 
 
 import Palette from '../../styleUtils/Palette'
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -52,13 +53,6 @@ class NewModal extends React.Component<Props> {
   windowScrollY: number
   windowScrollY: number
   modalDiv: ?HTMLDivElement
   modalDiv: ?HTMLDivElement
 
 
-  constructor() {
-    super()
-
-    const self: any = this
-    self.positionModal = this.positionModal.bind(this)
-  }
-
   componentWillMount() {
   componentWillMount() {
     if (this.props.componentRef) {
     if (this.props.componentRef) {
       this.props.componentRef(this)
       this.props.componentRef(this)
@@ -122,6 +116,7 @@ class NewModal extends React.Component<Props> {
     window.scroll(0, this.windowScrollY)
     window.scroll(0, this.windowScrollY)
   }
   }
 
 
+  @autobind
   positionModal(scrollOffset: number) {
   positionModal(scrollOffset: number) {
     // $FlowIssue
     // $FlowIssue
     let pageNode = this.modalDiv && this.modalDiv.node.firstChild
     let pageNode = this.modalDiv && this.modalDiv.node.firstChild

+ 6 - 11
src/components/molecules/NewItemDropdown/NewItemDropdown.jsx

@@ -17,6 +17,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import React from 'react'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
 import styled from 'styled-components'
 import styled from 'styled-components'
+import autobind from 'autobind-decorator'
 
 
 import DropdownButton from '../../atoms/DropdownButton'
 import DropdownButton from '../../atoms/DropdownButton'
 
 
@@ -135,19 +136,12 @@ type State = {
 }
 }
 @observer
 @observer
 class NewItemDropdown extends React.Component<Props, State> {
 class NewItemDropdown extends React.Component<Props, State> {
-  itemMouseDown: boolean
-
-  constructor() {
-    super()
-
-    this.state = {
-      showDropdownList: false,
-    }
-
-    // $FlowIssue
-    this.handlePageClick = this.handlePageClick.bind(this)
+  state = {
+    showDropdownList: false,
   }
   }
 
 
+  itemMouseDown: boolean
+
   componentDidMount() {
   componentDidMount() {
     window.addEventListener('mousedown', this.handlePageClick, false)
     window.addEventListener('mousedown', this.handlePageClick, false)
   }
   }
@@ -156,6 +150,7 @@ class NewItemDropdown extends React.Component<Props, State> {
     window.removeEventListener('mousedown', this.handlePageClick, false)
     window.removeEventListener('mousedown', this.handlePageClick, false)
   }
   }
 
 
+  @autobind
   handlePageClick() {
   handlePageClick() {
     if (!this.itemMouseDown) {
     if (!this.itemMouseDown) {
       this.setState({ showDropdownList: false })
       this.setState({ showDropdownList: false })

+ 4 - 9
src/components/molecules/NotificationDropdown/NotificationDropdown.jsx

@@ -17,6 +17,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import React from 'react'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
 import styled, { css } from 'styled-components'
 import styled, { css } from 'styled-components'
+import autobind from 'autobind-decorator'
 
 
 import Palette from '../../styleUtils/Palette'
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -179,19 +180,12 @@ type State = {
 const testId = 'notificationDropdown'
 const testId = 'notificationDropdown'
 @observer
 @observer
 class NotificationDropdown extends React.Component<Props, State> {
 class NotificationDropdown extends React.Component<Props, State> {
-  itemMouseDown: boolean
-
-  constructor() {
-    super()
-
-    // $FlowIssue
-    this.handlePageClick = this.handlePageClick.bind(this)
-  }
-
   state = {
   state = {
     showDropdownList: false,
     showDropdownList: false,
   }
   }
 
 
+  itemMouseDown: boolean
+
   componentDidMount() {
   componentDidMount() {
     window.addEventListener('mousedown', this.handlePageClick, false)
     window.addEventListener('mousedown', this.handlePageClick, false)
   }
   }
@@ -205,6 +199,7 @@ class NotificationDropdown extends React.Component<Props, State> {
     this.props.onClose()
     this.props.onClose()
   }
   }
 
 
+  @autobind
   handlePageClick() {
   handlePageClick() {
     if (!this.itemMouseDown) {
     if (!this.itemMouseDown) {
       if (this.state.showDropdownList) {
       if (this.state.showDropdownList) {

+ 12 - 16
src/components/molecules/SearchInput/SearchInput.jsx

@@ -17,6 +17,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import React from 'react'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
 import styled, { css } from 'styled-components'
 import styled, { css } from 'styled-components'
+import autobind from 'autobind-decorator'
 
 
 import SearchButton from '../../atoms/SearchButton'
 import SearchButton from '../../atoms/SearchButton'
 import TextInput from '../../atoms/TextInput'
 import TextInput from '../../atoms/TextInput'
@@ -24,7 +25,7 @@ import StatusIcon from '../../atoms/StatusIcon'
 
 
 import StyleProps from '../../styleUtils/StyleProps'
 import StyleProps from '../../styleUtils/StyleProps'
 
 
-const Input = styled(TextInput) `
+const Input = styled(TextInput)`
   padding-left: 32px;
   padding-left: 32px;
   ${props => props.loading || (props.showClose && props.value) ? 'padding-right: 32px;' : ''}
   ${props => props.loading || (props.showClose && props.value) ? 'padding-right: 32px;' : ''}
   width: 50px;
   width: 50px;
@@ -42,12 +43,12 @@ const Wrapper = styled.div`
   width: ${props => props.open ? props.width : '50px'};
   width: ${props => props.open ? props.width : '50px'};
   ${props => props.open ? InputAnimation(props) : ''}
   ${props => props.open ? InputAnimation(props) : ''}
 `
 `
-const SearchButtonStyled = styled(SearchButton) `
+const SearchButtonStyled = styled(SearchButton)`
   position: absolute;
   position: absolute;
   top: 8px;
   top: 8px;
   left: 8px;
   left: 8px;
 `
 `
-const StatusIconStyled = styled(StatusIcon) `
+const StatusIconStyled = styled(StatusIcon)`
   position: absolute;
   position: absolute;
   right: 8px;
   right: 8px;
   top: 8px;
   top: 8px;
@@ -69,7 +70,7 @@ type Props = {
 type State = {
 type State = {
   open: boolean,
   open: boolean,
   hover?: boolean,
   hover?: boolean,
-  focus?: boolean,
+  focus: boolean,
 }
 }
 @observer
 @observer
 class SearchInput extends React.Component<Props, State> {
 class SearchInput extends React.Component<Props, State> {
@@ -79,21 +80,15 @@ class SearchInput extends React.Component<Props, State> {
     value: '',
     value: '',
   }
   }
 
 
+  state = {
+    open: false,
+    value: '',
+    focus: false,
+  }
+
   input: HTMLElement
   input: HTMLElement
   itemMouseDown: boolean
   itemMouseDown: boolean
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      open: false,
-      value: '',
-    }
-
-    // $FlowIssue
-    this.handlePageClick = this.handlePageClick.bind(this)
-  }
-
   componentDidMount() {
   componentDidMount() {
     window.addEventListener('mousedown', this.handlePageClick, false)
     window.addEventListener('mousedown', this.handlePageClick, false)
 
 
@@ -104,6 +99,7 @@ class SearchInput extends React.Component<Props, State> {
     window.removeEventListener('mousedown', this.handlePageClick, false)
     window.removeEventListener('mousedown', this.handlePageClick, false)
   }
   }
 
 
+  @autobind
   handlePageClick() {
   handlePageClick() {
     if (!this.itemMouseDown) {
     if (!this.itemMouseDown) {
       this.setState({ open: false })
       this.setState({ open: false })

+ 2 - 6
src/components/molecules/SideMenu/SideMenu.jsx

@@ -91,12 +91,8 @@ type State = {
 }
 }
 @observer
 @observer
 class SideMenu extends React.Component<Props, State> {
 class SideMenu extends React.Component<Props, State> {
-  constructor() {
-    super()
-
-    this.state = {
-      open: false,
-    }
+  state = {
+    open: false,
   }
   }
 
 
   handleHamburgerClick() {
   handleHamburgerClick() {

+ 6 - 11
src/components/molecules/UserDropdown/UserDropdown.jsx

@@ -17,6 +17,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import React from 'react'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
 import styled, { css } from 'styled-components'
 import styled, { css } from 'styled-components'
+import autobind from 'autobind-decorator'
 
 
 import Palette from '../../styleUtils/Palette'
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -114,19 +115,12 @@ type State = {
 }
 }
 @observer
 @observer
 class UserDropdown extends React.Component<Props, State> {
 class UserDropdown extends React.Component<Props, State> {
-  itemMouseDown: boolean
-
-  constructor() {
-    super()
-
-    this.state = {
-      showDropdownList: false,
-    }
-
-    // $FlowIssue
-    this.handlePageClick = this.handlePageClick.bind(this)
+  state = {
+    showDropdownList: false,
   }
   }
 
 
+  itemMouseDown: boolean
+
   componentDidMount() {
   componentDidMount() {
     window.addEventListener('mousedown', this.handlePageClick, false)
     window.addEventListener('mousedown', this.handlePageClick, false)
   }
   }
@@ -143,6 +137,7 @@ class UserDropdown extends React.Component<Props, State> {
     this.setState({ showDropdownList: false })
     this.setState({ showDropdownList: false })
   }
   }
 
 
+  @autobind
   handlePageClick() {
   handlePageClick() {
     if (!this.itemMouseDown) {
     if (!this.itemMouseDown) {
       this.setState({ showDropdownList: false })
       this.setState({ showDropdownList: false })

+ 5 - 9
src/components/organisms/AssessmentMigrationOptions/AssessmentMigrationOptions.jsx

@@ -40,7 +40,7 @@ const Image = styled.div`
 const Fields = styled.div`
 const Fields = styled.div`
   margin-top: 64px;
   margin-top: 64px;
 `
 `
-const WizardOptionsFieldStyled = styled(WizardOptionsField) `
+const WizardOptionsFieldStyled = styled(WizardOptionsField)`
   width: 319px;
   width: 319px;
   justify-content: space-between;
   justify-content: space-between;
   margin-bottom: 32px;
   margin-bottom: 32px;
@@ -91,14 +91,10 @@ type State = {
 }
 }
 @observer
 @observer
 class AssessmentMigrationOptions extends React.Component<Props, State> {
 class AssessmentMigrationOptions extends React.Component<Props, State> {
-  constructor() {
-    super()
-
-    this.state = {
-      generalFields: [...generalFields],
-      migrationFields: [...migrationFields],
-      replicaFields: [...replicaFields],
-    }
+  state = {
+    generalFields: [...generalFields],
+    migrationFields: [...migrationFields],
+    replicaFields: [...replicaFields],
   }
   }
 
 
   handleValueChange(field: Field, value: any) {
   handleValueChange(field: Field, value: any) {

+ 9 - 13
src/components/organisms/Endpoint/Endpoint.jsx

@@ -128,6 +128,14 @@ class Endpoint extends React.Component<Props, State> {
     cancelButtonText: 'Cancel',
     cancelButtonText: 'Cancel',
   }
   }
 
 
+  state = {
+    invalidFields: [],
+    validating: false,
+    showErrorMessage: false,
+    endpoint: null,
+    isNew: null,
+  }
+
   scrollableRef: HTMLElement
   scrollableRef: HTMLElement
   closeTimeout: TimeoutID
   closeTimeout: TimeoutID
   contentPluginRef: DefaultContentPlugin
   contentPluginRef: DefaultContentPlugin
@@ -135,18 +143,6 @@ class Endpoint extends React.Component<Props, State> {
   providerStoreObserver: () => void
   providerStoreObserver: () => void
   endpointValidationObserver: () => void
   endpointValidationObserver: () => void
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      invalidFields: [],
-      validating: false,
-      showErrorMessage: false,
-      endpoint: null,
-      isNew: null,
-    }
-  }
-
   componentWillMount() {
   componentWillMount() {
     this.componentWillReceiveProps(this.props)
     this.componentWillReceiveProps(this.props)
     this.providerStoreObserver = observe(providerStore, 'connectionInfoSchema', () => {
     this.providerStoreObserver = observe(providerStore, 'connectionInfoSchema', () => {
@@ -222,7 +218,7 @@ class Endpoint extends React.Component<Props, State> {
   }
   }
 
 
   handleFieldsChange(items: { field: Field, value: any }[]) {
   handleFieldsChange(items: { field: Field, value: any }[]) {
-    let endpoint: EndpointType = { ...this.state.endpoint }
+    let endpoint: any = { ...this.state.endpoint }
 
 
     items.forEach(item => {
     items.forEach(item => {
       endpoint[item.field.name] = item.value
       endpoint[item.field.name] = item.value

+ 2 - 6
src/components/organisms/Executions/Executions.jsx

@@ -98,12 +98,8 @@ type State = {
 }
 }
 @observer
 @observer
 class Executions extends React.Component<Props, State> {
 class Executions extends React.Component<Props, State> {
-  constructor() {
-    super()
-
-    this.state = {
-      selectedExecution: null,
-    }
+  state = {
+    selectedExecution: null,
   }
   }
 
 
   componentWillMount() {
   componentWillMount() {

+ 7 - 10
src/components/organisms/FilterList/FilterList.jsx

@@ -49,19 +49,16 @@ type State = {
   filterStatus: string,
   filterStatus: string,
   filterText: string,
   filterText: string,
   selectedItems: any[],
   selectedItems: any[],
-  selectAllSelected?: boolean,
+  selectAllSelected: boolean,
 }
 }
 @observer
 @observer
 class FilterList extends React.Component<Props, State> {
 class FilterList extends React.Component<Props, State> {
-  constructor() {
-    super()
-
-    this.state = {
-      items: [],
-      filterStatus: 'all',
-      filterText: '',
-      selectedItems: [],
-    }
+  state = {
+    items: [],
+    filterStatus: 'all',
+    filterText: '',
+    selectedItems: [],
+    selectAllSelected: false,
   }
   }
 
 
   componentWillMount() {
   componentWillMount() {

+ 3 - 7
src/components/organisms/LoginForm/LoginForm.jsx

@@ -99,13 +99,9 @@ class LoginForm extends React.Component<Props, State> {
     className: '',
     className: '',
   }
   }
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      username: '',
-      password: '',
-    }
+  state = {
+    username: '',
+    password: '',
   }
   }
 
 
   handleUsernameChange(username: string) {
   handleUsernameChange(username: string) {

+ 1 - 6
src/components/organisms/Notifications/Notifications.jsx

@@ -33,13 +33,8 @@ const Wrapper = styled.div``
 
 
 @observer
 @observer
 class Notifications extends React.Component<{}> {
 class Notifications extends React.Component<{}> {
-  notificationsCount: number
   notificationSystem: NotificationSystem
   notificationSystem: NotificationSystem
-
-  constructor() {
-    super()
-    this.notificationsCount = 0
-  }
+  notificationsCount = 0
 
 
   componentDidMount() {
   componentDidMount() {
     observe(notificationStore.alerts, change => {
     observe(notificationStore.alerts, change => {

+ 9 - 12
src/components/organisms/PageHeader/PageHeader.jsx

@@ -71,24 +71,21 @@ type State = {
   showEndpointModal: boolean,
   showEndpointModal: boolean,
   showUserModal: boolean,
   showUserModal: boolean,
   showProjectModal: boolean,
   showProjectModal: boolean,
-  providerType?: string,
+  providerType: ?string,
 }
 }
 @observer
 @observer
 class PageHeader extends React.Component<Props, State> {
 class PageHeader extends React.Component<Props, State> {
+  state = {
+    showChooseProviderModal: false,
+    showEndpointModal: false,
+    showUserModal: false,
+    showProjectModal: false,
+    providerType: null,
+  }
+
   pollTimeout: TimeoutID
   pollTimeout: TimeoutID
   stopPolling: boolean
   stopPolling: boolean
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      showChooseProviderModal: false,
-      showEndpointModal: false,
-      showUserModal: false,
-      showProjectModal: false,
-    }
-  }
-
   componentWillMount() {
   componentWillMount() {
     this.stopPolling = false
     this.stopPolling = false
     this.pollData()
     this.pollData()

+ 2 - 2
src/components/organisms/ProjectDetailsContent/ProjectDetailsContent.jsx

@@ -114,13 +114,13 @@ type State = {
 const testName = 'pdContent'
 const testName = 'pdContent'
 @observer
 @observer
 class ProjectDetailsContent extends React.Component<Props, State> {
 class ProjectDetailsContent extends React.Component<Props, State> {
-  selectedUser: ?User
-
   state = {
   state = {
     showRemoveUserAlert: false,
     showRemoveUserAlert: false,
     showDeleteProjectAlert: false,
     showDeleteProjectAlert: false,
   }
   }
 
 
+  selectedUser: ?User
+
   handleRemoveUserAction(user: User) {
   handleRemoveUserAction(user: User) {
     this.selectedUser = user
     this.selectedUser = user
     this.setState({ showRemoveUserAlert: true })
     this.setState({ showRemoveUserAlert: true })

+ 2 - 6
src/components/organisms/ReplicaDetailsContent/ReplicaDetailsContent.jsx

@@ -91,12 +91,8 @@ type State = {
 }
 }
 @observer
 @observer
 class ReplicaDetailsContent extends React.Component<Props, State> {
 class ReplicaDetailsContent extends React.Component<Props, State> {
-  constructor() {
-    super()
-
-    this.state = {
-      timezone: 'local',
-    }
+  state = {
+    timezone: 'local',
   }
   }
 
 
   getLastExecution() {
   getLastExecution() {

+ 2 - 6
src/components/organisms/ReplicaExecutionOptions/ReplicaExecutionOptions.jsx

@@ -69,12 +69,8 @@ class ReplicaExecutionOptions extends React.Component<Props, State> {
     executionLabel: 'Execute',
     executionLabel: 'Execute',
   }
   }
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      fields: [...executionOptions],
-    }
+  state = {
+    fields: [...executionOptions],
   }
   }
 
 
   componentDidMount() {
   componentDidMount() {

+ 18 - 21
src/components/organisms/ReplicaMigrationOptions/ReplicaMigrationOptions.jsx

@@ -50,7 +50,7 @@ const Buttons = styled.div`
   justify-content: space-between;
   justify-content: space-between;
   width: 100%;
   width: 100%;
 `
 `
-const WizardOptionsFieldStyled = styled(WizardOptionsField) `
+const WizardOptionsFieldStyled = styled(WizardOptionsField)`
   width: 319px;
   width: 319px;
   justify-content: space-between;
   justify-content: space-between;
   margin-bottom: 32px;
   margin-bottom: 32px;
@@ -63,28 +63,25 @@ type Props = {
 type State = {
 type State = {
   fields: Field[],
   fields: Field[],
 }
 }
+let defaultFields: Field[] = [
+  {
+    name: 'clone_disks',
+    type: 'strict-boolean',
+    value: true,
+  },
+  {
+    name: 'force',
+    type: 'strict-boolean',
+  },
+  {
+    name: 'skip_os_morphing',
+    type: 'strict-boolean',
+  },
+]
 @observer
 @observer
 class ReplicaMigrationOptions extends React.Component<Props, State> {
 class ReplicaMigrationOptions extends React.Component<Props, State> {
-  constructor() {
-    super()
-
-    this.state = {
-      fields: [
-        {
-          name: 'clone_disks',
-          type: 'strict-boolean',
-          value: true,
-        },
-        {
-          name: 'force',
-          type: 'strict-boolean',
-        },
-        {
-          name: 'skip_os_morphing',
-          type: 'strict-boolean',
-        },
-      ],
-    }
+  state = {
+    fields: defaultFields,
   }
   }
 
 
   componentDidMount() {
   componentDidMount() {

+ 5 - 9
src/components/organisms/Schedule/Schedule.jsx

@@ -134,15 +134,11 @@ class Schedule extends React.Component<Props, State> {
     unsavedSchedules: [],
     unsavedSchedules: [],
   }
   }
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      showOptionsModal: false,
-      showDeleteConfirmation: false,
-      selectedSchedule: null,
-      executionOptions: null,
-    }
+  state = {
+    showOptionsModal: false,
+    showDeleteConfirmation: false,
+    selectedSchedule: null,
+    executionOptions: null,
   }
   }
 
 
   handleDeleteClick(selectedSchedule: ScheduleType) {
   handleDeleteClick(selectedSchedule: ScheduleType) {

+ 4 - 8
src/components/organisms/Tasks/Tasks.jsx

@@ -51,16 +51,12 @@ type State = {
 }
 }
 @observer
 @observer
 class Tasks extends React.Component<Props, State> {
 class Tasks extends React.Component<Props, State> {
-  dragStartPosition: ?{ x: number, y: number }
-
-  constructor() {
-    super()
-
-    this.state = {
-      openedItems: [],
-    }
+  state = {
+    openedItems: [],
   }
   }
 
 
+  dragStartPosition: ?{ x: number, y: number }
+
   componentWillMount() {
   componentWillMount() {
     this.componentWillReceiveProps(this.props)
     this.componentWillReceiveProps(this.props)
   }
   }

+ 5 - 9
src/components/organisms/WizardInstances/WizardInstances.jsx

@@ -62,7 +62,7 @@ const InstanceContent = styled.div`
     background: ${Palette.grayscale[1]};
     background: ${Palette.grayscale[1]};
   }
   }
 `
 `
-const CheckboxStyled = styled(Checkbox) `
+const CheckboxStyled = styled(Checkbox)`
   opacity: 0;
   opacity: 0;
   transition: all ${StyleProps.animations.swift};
   transition: all ${StyleProps.animations.swift};
 `
 `
@@ -201,16 +201,12 @@ type State = {
 }
 }
 @observer
 @observer
 class WizardInstances extends React.Component<Props, State> {
 class WizardInstances extends React.Component<Props, State> {
-  timeout: TimeoutID
-
-  constructor() {
-    super()
-
-    this.state = {
-      searchText: '',
-    }
+  state = {
+    searchText: '',
   }
   }
 
 
+  timeout: TimeoutID
+
   handleSeachInputChange(searchText: string) {
   handleSeachInputChange(searchText: string) {
     this.setState({ searchText })
     this.setState({ searchText })
 
 

+ 2 - 7
src/components/organisms/WizardOptions/WizardOptions.jsx

@@ -17,6 +17,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import React from 'react'
 import styled from 'styled-components'
 import styled from 'styled-components'
 import { observer } from 'mobx-react'
 import { observer } from 'mobx-react'
+import autobind from 'autobind-decorator'
 
 
 import Tooltip from '../../atoms/Tooltip'
 import Tooltip from '../../atoms/Tooltip'
 import StyleProps from '../../styleUtils/StyleProps'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -66,13 +67,6 @@ type Props = {
 }
 }
 @observer
 @observer
 class WizardOptions extends React.Component<Props> {
 class WizardOptions extends React.Component<Props> {
-  constructor() {
-    super()
-
-    // $FlowIssue
-    this.handleResize = this.handleResize.bind(this)
-  }
-
   componentDidMount() {
   componentDidMount() {
     window.addEventListener('resize', this.handleResize)
     window.addEventListener('resize', this.handleResize)
   }
   }
@@ -124,6 +118,7 @@ class WizardOptions extends React.Component<Props> {
     return fieldsSchema
     return fieldsSchema
   }
   }
 
 
+  @autobind
   handleResize() {
   handleResize() {
     this.setState({})
     this.setState({})
   }
   }

+ 3 - 7
src/components/organisms/WizardPageContent/WizardPageContent.jsx

@@ -125,13 +125,9 @@ type State = {
 const testName = 'wpContent'
 const testName = 'wpContent'
 @observer
 @observer
 class WizardPageContent extends React.Component<Props, State> {
 class WizardPageContent extends React.Component<Props, State> {
-  constructor() {
-    super()
-
-    this.state = {
-      useAdvancedOptions: false,
-      timezone: 'local',
-    }
+  state = {
+    useAdvancedOptions: false,
+    timezone: 'local',
   }
   }
 
 
   componentDidMount() {
   componentDidMount() {

+ 8 - 12
src/components/pages/AssessmentDetailsPage/AssessmentDetailsPage.jsx

@@ -57,18 +57,14 @@ type State = {
 }
 }
 @observer
 @observer
 class AssessmentDetailsPage extends React.Component<Props, State> {
 class AssessmentDetailsPage extends React.Component<Props, State> {
-  constructor() {
-    super()
-
-    this.state = {
-      sourceEndpoint: null,
-      selectedVms: [],
-      selectedNetworks: [],
-      showMigrationOptions: false,
-      executeButtonDisabled: false,
-      vmSizes: {},
-      vmSearchValue: '',
-    }
+  state = {
+    sourceEndpoint: null,
+    selectedVms: [],
+    selectedNetworks: [],
+    showMigrationOptions: false,
+    executeButtonDisabled: false,
+    vmSizes: {},
+    vmSearchValue: '',
   }
   }
 
 
   componentWillMount() {
   componentWillMount() {

+ 3 - 3
src/components/pages/AssessmentsPage/AssessmentsPage.jsx

@@ -41,13 +41,13 @@ type Props = {}
 type State = { modalIsOpen: boolean }
 type State = { modalIsOpen: boolean }
 @observer
 @observer
 class AssessmentsPage extends React.Component<Props, State> {
 class AssessmentsPage extends React.Component<Props, State> {
-  disablePolling: boolean
-  pollTimeout: TimeoutID
-
   state = {
   state = {
     modalIsOpen: false,
     modalIsOpen: false,
   }
   }
 
 
+  disablePolling: boolean
+  pollTimeout: TimeoutID
+
   componentWillMount() {
   componentWillMount() {
     document.title = 'Coriolis Planning'
     document.title = 'Coriolis Planning'
 
 

+ 7 - 11
src/components/pages/EndpointDetailsPage/EndpointDetailsPage.jsx

@@ -51,17 +51,13 @@ type State = {
 }
 }
 @observer
 @observer
 class EndpointDetailsPage extends React.Component<Props, State> {
 class EndpointDetailsPage extends React.Component<Props, State> {
-  constructor() {
-    super()
-
-    this.state = {
-      showDeleteEndpointConfirmation: false,
-      showValidationModal: false,
-      showEndpointModal: false,
-      showEndpointInUseModal: false,
-      showEndpointInUseLoadingModal: false,
-      endpointUsage: { replicas: [], migrations: [] },
-    }
+  state = {
+    showDeleteEndpointConfirmation: false,
+    showValidationModal: false,
+    showEndpointModal: false,
+    showEndpointInUseModal: false,
+    showEndpointInUseLoadingModal: false,
+    endpointUsage: { replicas: [], migrations: [] },
   }
   }
 
 
   componentDidMount() {
   componentDidMount() {

+ 12 - 16
src/components/pages/EndpointsPage/EndpointsPage.jsx

@@ -63,25 +63,21 @@ type State = {
 }
 }
 @observer
 @observer
 class EndpointsPage extends React.Component<{}, State> {
 class EndpointsPage extends React.Component<{}, State> {
+  state = {
+    showDeleteEndpointsConfirmation: false,
+    confirmationItems: null,
+    showChooseProviderModal: false,
+    showEndpointModal: false,
+    providerType: null,
+    showEndpointsInUseModal: false,
+    modalIsOpen: false,
+    showDuplicateModal: false,
+    duplicating: false,
+  }
+
   pollTimeout: TimeoutID
   pollTimeout: TimeoutID
   stopPolling: boolean
   stopPolling: boolean
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      showDeleteEndpointsConfirmation: false,
-      confirmationItems: null,
-      showChooseProviderModal: false,
-      showEndpointModal: false,
-      providerType: null,
-      showEndpointsInUseModal: false,
-      modalIsOpen: false,
-      showDuplicateModal: false,
-      duplicating: false,
-    }
-  }
-
   componentDidMount() {
   componentDidMount() {
     document.title = 'Coriolis Endpoints'
     document.title = 'Coriolis Endpoints'
 
 

+ 5 - 9
src/components/pages/MigrationDetailsPage/MigrationDetailsPage.jsx

@@ -43,17 +43,13 @@ type State = {
 }
 }
 @observer
 @observer
 class MigrationDetailsPage extends React.Component<Props, State> {
 class MigrationDetailsPage extends React.Component<Props, State> {
-  pollInterval: IntervalID
-
-  constructor() {
-    super()
-
-    this.state = {
-      showDeleteMigrationConfirmation: false,
-      showCancelConfirmation: false,
-    }
+  state = {
+    showDeleteMigrationConfirmation: false,
+    showCancelConfirmation: false,
   }
   }
 
 
+  pollInterval: IntervalID
+
   componentDidMount() {
   componentDidMount() {
     document.title = 'Migration Details'
     document.title = 'Migration Details'
 
 

+ 7 - 11
src/components/pages/MigrationsPage/MigrationsPage.jsx

@@ -50,20 +50,16 @@ type State = {
 }
 }
 @observer
 @observer
 class MigrationsPage extends React.Component<{}, State> {
 class MigrationsPage extends React.Component<{}, State> {
+  state = {
+    showDeleteMigrationConfirmation: false,
+    showCancelMigrationConfirmation: false,
+    confirmationItems: null,
+    modalIsOpen: false,
+  }
+
   pollTimeout: TimeoutID
   pollTimeout: TimeoutID
   stopPolling: boolean
   stopPolling: boolean
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      showDeleteMigrationConfirmation: false,
-      showCancelMigrationConfirmation: false,
-      confirmationItems: null,
-      modalIsOpen: false,
-    }
-  }
-
   componentDidMount() {
   componentDidMount() {
     document.title = 'Coriolis Migrations'
     document.title = 'Coriolis Migrations'
 
 

+ 3 - 3
src/components/pages/ProjectsPage/ProjectsPage.jsx

@@ -37,13 +37,13 @@ type State = {
 }
 }
 @observer
 @observer
 class ProjectsPage extends React.Component<{}, State> {
 class ProjectsPage extends React.Component<{}, State> {
-  pollTimeout: TimeoutID
-  stopPolling: boolean
-
   state = {
   state = {
     modalIsOpen: false,
     modalIsOpen: false,
   }
   }
 
 
+  pollTimeout: TimeoutID
+  stopPolling: boolean
+
   componentDidMount() {
   componentDidMount() {
     document.title = 'Projects'
     document.title = 'Projects'
 
 

+ 10 - 14
src/components/pages/ReplicaDetailsPage/ReplicaDetailsPage.jsx

@@ -56,22 +56,18 @@ type State = {
 }
 }
 @observer
 @observer
 class ReplicaDetailsPage extends React.Component<Props, State> {
 class ReplicaDetailsPage extends React.Component<Props, State> {
-  pollTimeout: TimeoutID
-
-  constructor() {
-    super()
-
-    this.state = {
-      showOptionsModal: false,
-      showMigrationModal: false,
-      showDeleteExecutionConfirmation: false,
-      showDeleteReplicaConfirmation: false,
-      showDeleteReplicaDisksConfirmation: false,
-      confirmationItem: null,
-      showCancelConfirmation: false,
-    }
+  state = {
+    showOptionsModal: false,
+    showMigrationModal: false,
+    showDeleteExecutionConfirmation: false,
+    showDeleteReplicaConfirmation: false,
+    showDeleteReplicaDisksConfirmation: false,
+    confirmationItem: null,
+    showCancelConfirmation: false,
   }
   }
 
 
+  pollTimeout: TimeoutID
+
   componentDidMount() {
   componentDidMount() {
     document.title = 'Replica Details'
     document.title = 'Replica Details'
 
 

+ 6 - 10
src/components/pages/ReplicasPage/ReplicasPage.jsx

@@ -49,19 +49,15 @@ type State = {
 }
 }
 @observer
 @observer
 class ReplicasPage extends React.Component<{}, State> {
 class ReplicasPage extends React.Component<{}, State> {
+  state = {
+    showDeleteReplicaConfirmation: false,
+    confirmationItems: null,
+    modalIsOpen: false,
+  }
+
   pollTimeout: TimeoutID
   pollTimeout: TimeoutID
   stopPolling: boolean
   stopPolling: boolean
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      showDeleteReplicaConfirmation: false,
-      confirmationItems: null,
-      modalIsOpen: false,
-    }
-  }
-
   componentDidMount() {
   componentDidMount() {
     document.title = 'Coriolis Replicas'
     document.title = 'Coriolis Replicas'
 
 

+ 3 - 3
src/components/pages/UsersPage/UsersPage.jsx

@@ -37,13 +37,13 @@ type State = {
 }
 }
 @observer
 @observer
 class UsersPage extends React.Component<{}, State> {
 class UsersPage extends React.Component<{}, State> {
-  pollTimeout: TimeoutID
-  stopPolling: boolean
-
   state = {
   state = {
     modalIsOpen: false,
     modalIsOpen: false,
   }
   }
 
 
+  pollTimeout: TimeoutID
+  stopPolling: boolean
+
   componentDidMount() {
   componentDidMount() {
     document.title = 'Users'
     document.title = 'Users'
 
 

+ 8 - 11
src/components/pages/WizardPage/WizardPage.jsx

@@ -54,23 +54,20 @@ type State = {
   type: WizardType,
   type: WizardType,
   showNewEndpointModal: boolean,
   showNewEndpointModal: boolean,
   nextButtonDisabled: boolean,
   nextButtonDisabled: boolean,
-  newEndpointType?: string,
+  newEndpointType: ?string,
   newEndpointFromSource?: boolean,
   newEndpointFromSource?: boolean,
 }
 }
 @observer
 @observer
 class WizardPage extends React.Component<Props, State> {
 class WizardPage extends React.Component<Props, State> {
-  contentRef: WizardPageContent
-
-  constructor() {
-    super()
-
-    this.state = {
-      type: 'migration',
-      showNewEndpointModal: false,
-      nextButtonDisabled: false,
-    }
+  state = {
+    type: 'migration',
+    showNewEndpointModal: false,
+    nextButtonDisabled: false,
+    newEndpointType: null,
   }
   }
 
 
+  contentRef: WizardPageContent
+
   componentWillMount() {
   componentWillMount() {
     this.initializeState()
     this.initializeState()
   }
   }

+ 5 - 9
src/plugins/endpoint/azure/ContentPlugin.jsx

@@ -82,18 +82,14 @@ type State = {
   showPasteInput: boolean,
   showPasteInput: boolean,
 }
 }
 class ContentPlugin extends React.Component<Props, State> {
 class ContentPlugin extends React.Component<Props, State> {
+  state = {
+    jsonConfig: '',
+    showPasteInput: false,
+  }
+
   cloudProfileChanged: boolean
   cloudProfileChanged: boolean
   lastBlurValue: string
   lastBlurValue: string
 
 
-  constructor() {
-    super()
-
-    this.state = {
-      jsonConfig: '',
-      showPasteInput: false,
-    }
-  }
-
   componentDidMount() {
   componentDidMount() {
     this.props.onRef(this)
     this.props.onRef(this)
   }
   }

+ 5 - 8
src/plugins/endpoint/openstack/ContentPlugin.jsx

@@ -21,7 +21,7 @@ import ToggleButtonBar from '../../../components/atoms/ToggleButtonBar'
 import type { Field } from '../../../types/Field'
 import type { Field } from '../../../types/Field'
 import { Wrapper, Fields, FieldStyled, Row } from '../default/ContentPlugin'
 import { Wrapper, Fields, FieldStyled, Row } from '../default/ContentPlugin'
 
 
-const ToggleButtonBarStyled = styled(ToggleButtonBar) `
+const ToggleButtonBarStyled = styled(ToggleButtonBar)`
   margin-top: 16px;
   margin-top: 16px;
 `
 `
 
 
@@ -42,13 +42,12 @@ type State = {
   useAdvancedOptions: boolean,
   useAdvancedOptions: boolean,
 }
 }
 class ContentPlugin extends React.Component<Props, State> {
 class ContentPlugin extends React.Component<Props, State> {
-  constructor() {
-    super()
-    this.state = {
-      useAdvancedOptions: false,
-    }
+  state = {
+    useAdvancedOptions: false,
   }
   }
 
 
+  previouslySelectedChoices: string[] = []
+
   componentDidMount() {
   componentDidMount() {
     this.props.onRef(this)
     this.props.onRef(this)
   }
   }
@@ -96,8 +95,6 @@ class ContentPlugin extends React.Component<Props, State> {
     this.setState({ useAdvancedOptions })
     this.setState({ useAdvancedOptions })
   }
   }
 
 
-  previouslySelectedChoices: string[] = []
-
   findInvalidFields = () => {
   findInvalidFields = () => {
     let inputChoices = ['user_domain', 'project_domain']
     let inputChoices = ['user_domain', 'project_domain']
 
 

+ 31 - 8
yarn.lock

@@ -621,6 +621,10 @@ asynckit@^0.4.0:
   version "0.4.0"
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
   resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
 
 
+autobind-decorator@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/autobind-decorator/-/autobind-decorator-2.1.0.tgz#4451240dbfeff46361c506575a63ed40f0e5bc68"
+
 autoprefixer@^6.3.1:
 autoprefixer@^6.3.1:
   version "6.7.7"
   version "6.7.7"
   resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
   resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
@@ -2883,6 +2887,12 @@ doctrine@^2.0.0:
     esutils "^2.0.2"
     esutils "^2.0.2"
     isarray "^1.0.0"
     isarray "^1.0.0"
 
 
+doctrine@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+  dependencies:
+    esutils "^2.0.2"
+
 dom-converter@~0.1:
 dom-converter@~0.1:
   version "0.1.4"
   version "0.1.4"
   resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b"
   resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b"
@@ -3273,14 +3283,14 @@ eslint-plugin-jsx-a11y@^6.0.2:
     emoji-regex "^6.1.0"
     emoji-regex "^6.1.0"
     jsx-ast-utils "^1.4.0"
     jsx-ast-utils "^1.4.0"
 
 
-eslint-plugin-react@^7.4.0:
-  version "7.4.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.4.0.tgz#300a95861b9729c087d362dd64abcc351a74364a"
+eslint-plugin-react@7.10.0:
+  version "7.10.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.10.0.tgz#af5c1fef31c4704db02098f9be18202993828b50"
   dependencies:
   dependencies:
-    doctrine "^2.0.0"
-    has "^1.0.1"
-    jsx-ast-utils "^2.0.0"
-    prop-types "^15.5.10"
+    doctrine "^2.1.0"
+    has "^1.0.3"
+    jsx-ast-utils "^2.0.1"
+    prop-types "^15.6.2"
 
 
 eslint-restricted-globals@^0.1.1:
 eslint-restricted-globals@^0.1.1:
   version "0.1.1"
   version "0.1.1"
@@ -4088,6 +4098,12 @@ has@^1.0.1:
   dependencies:
   dependencies:
     function-bind "^1.0.2"
     function-bind "^1.0.2"
 
 
+has@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+  dependencies:
+    function-bind "^1.1.1"
+
 hash-base@^2.0.0:
 hash-base@^2.0.0:
   version "2.0.2"
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
   resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1"
@@ -5080,7 +5096,7 @@ jsx-ast-utils@^1.4.0:
   version "1.4.1"
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1"
   resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1"
 
 
-jsx-ast-utils@^2.0.0:
+jsx-ast-utils@^2.0.1:
   version "2.0.1"
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f"
   resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f"
   dependencies:
   dependencies:
@@ -6601,6 +6617,13 @@ prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7,
     loose-envify "^1.3.1"
     loose-envify "^1.3.1"
     object-assign "^4.1.1"
     object-assign "^4.1.1"
 
 
+prop-types@^15.6.2:
+  version "15.6.2"
+  resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
+  dependencies:
+    loose-envify "^1.3.1"
+    object-assign "^4.1.1"
+
 proxy-addr@~2.0.2:
 proxy-addr@~2.0.2:
   version "2.0.2"
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec"
   resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.2.tgz#6571504f47bb988ec8180253f85dd7e14952bdec"