Sfoglia il codice sorgente

Merge pull request #147 from smiclea/flow-type

Flow type integration
Dorin Paslaru 8 anni fa
parent
commit
d5341c9743
100 ha cambiato i file con 558 aggiunte e 381 eliminazioni
  1. 1 0
      .babelrc
  2. 3 1
      .eslintignore
  3. 62 2
      .eslintrc
  4. 17 0
      .flowconfig
  5. 3 1
      .gitignore
  6. 7 0
      flow-typed/module_vx.x.x.js
  7. 8 2
      package.json
  8. 6 6
      private/storybook/Decorator.jsx
  9. 2 0
      src/actions/EndpointActions.js
  10. 2 0
      src/actions/InstanceActions.js
  11. 2 0
      src/actions/MigrationActions.js
  12. 2 0
      src/actions/NetworkActions.js
  13. 2 0
      src/actions/NotificationActions.js
  14. 2 0
      src/actions/ProjectActions.js
  15. 2 0
      src/actions/ProviderActions.js
  16. 2 0
      src/actions/ReplicaActions.js
  17. 2 0
      src/actions/ScheduleActions.js
  18. 2 0
      src/actions/UserActions.js
  19. 2 0
      src/actions/WizardActions.js
  20. 14 14
      src/components/App.jsx
  21. 11 10
      src/components/atoms/Arrow/index.jsx
  22. 1 1
      src/components/atoms/Arrow/story.jsx
  23. 3 6
      src/components/atoms/Button/index.jsx
  24. 1 1
      src/components/atoms/Button/story.jsx
  25. 1 1
      src/components/atoms/Button/test.jsx
  26. 10 10
      src/components/atoms/Checkbox/index.jsx
  27. 1 1
      src/components/atoms/Checkbox/story.jsx
  28. 1 1
      src/components/atoms/Checkbox/test.jsx
  29. 3 1
      src/components/atoms/CopyButton/index.jsx
  30. 1 1
      src/components/atoms/CopyButton/story.jsx
  31. 1 1
      src/components/atoms/CopyButton/test.jsx
  32. 10 10
      src/components/atoms/CopyValue/index.jsx
  33. 1 1
      src/components/atoms/CopyValue/test.jsx
  34. 14 15
      src/components/atoms/DropdownButton/index.jsx
  35. 1 1
      src/components/atoms/DropdownButton/story.jsx
  36. 1 1
      src/components/atoms/DropdownButton/test.jsx
  37. 9 9
      src/components/atoms/EndpointLogos/index.jsx
  38. 1 1
      src/components/atoms/EndpointLogos/story.jsx
  39. 1 1
      src/components/atoms/EndpointLogos/test.jsx
  40. 5 1
      src/components/atoms/Fonts/index.js
  41. 7 8
      src/components/atoms/InfoIcon/index.jsx
  42. 8 8
      src/components/atoms/Logo/index.jsx
  43. 1 1
      src/components/atoms/Logo/story.jsx
  44. 9 6
      src/components/atoms/PasswordValue/index.jsx
  45. 1 1
      src/components/atoms/PasswordValue/story.jsx
  46. 1 1
      src/components/atoms/PasswordValue/test.jsx
  47. 9 7
      src/components/atoms/ProgressBar/index.jsx
  48. 1 1
      src/components/atoms/ProgressBar/story.jsx
  49. 1 1
      src/components/atoms/ProgressBar/test.jsx
  50. 6 6
      src/components/atoms/RadioInput/index.jsx
  51. 1 1
      src/components/atoms/RadioInput/story.jsx
  52. 1 1
      src/components/atoms/RadioInput/test.jsx
  53. 8 5
      src/components/atoms/ReloadButton/index.jsx
  54. 1 1
      src/components/atoms/ReloadButton/story.jsx
  55. 1 1
      src/components/atoms/ReloadButton/test.jsx
  56. 7 7
      src/components/atoms/SearchButton/index.jsx
  57. 1 1
      src/components/atoms/SearchButton/story.jsx
  58. 1 1
      src/components/atoms/SearchButton/test.jsx
  59. 11 10
      src/components/atoms/StatusIcon/index.jsx
  60. 1 1
      src/components/atoms/StatusIcon/story.jsx
  61. 1 1
      src/components/atoms/StatusIcon/test.jsx
  62. 11 9
      src/components/atoms/StatusImage/index.jsx
  63. 1 1
      src/components/atoms/StatusImage/story.jsx
  64. 1 1
      src/components/atoms/StatusImage/test.jsx
  65. 12 12
      src/components/atoms/StatusPill/index.jsx
  66. 1 1
      src/components/atoms/StatusPill/story.jsx
  67. 1 1
      src/components/atoms/StatusPill/test.jsx
  68. 23 20
      src/components/atoms/Switch/index.jsx
  69. 1 1
      src/components/atoms/Switch/story.jsx
  70. 1 1
      src/components/atoms/Switch/test.jsx
  71. 3 1
      src/components/atoms/TextArea/index.jsx
  72. 16 8
      src/components/atoms/TextInput/index.jsx
  73. 1 1
      src/components/atoms/TextInput/story.jsx
  74. 1 1
      src/components/atoms/TextInput/test.jsx
  75. 9 8
      src/components/atoms/ToggleButtonBar/index.jsx
  76. 1 1
      src/components/atoms/ToggleButtonBar/story.jsx
  77. 1 1
      src/components/atoms/ToggleButtonBar/test.jsx
  78. 3 1
      src/components/atoms/Tooltip/index.jsx
  79. 2 2
      src/components/atoms/Tooltip/story.jsx
  80. 21 13
      src/components/molecules/DatetimePicker/index.jsx
  81. 1 1
      src/components/molecules/DatetimePicker/story.jsx
  82. 1 1
      src/components/molecules/DatetimePicker/test.jsx
  83. 9 9
      src/components/molecules/DetailsNavigation/index.jsx
  84. 1 1
      src/components/molecules/DetailsNavigation/story.jsx
  85. 1 1
      src/components/molecules/DetailsNavigation/test.jsx
  86. 62 49
      src/components/molecules/Dropdown/index.jsx
  87. 1 1
      src/components/molecules/Dropdown/story.jsx
  88. 1 1
      src/components/molecules/Dropdown/test.jsx
  89. 20 10
      src/components/molecules/DropdownLink/index.jsx
  90. 1 1
      src/components/molecules/DropdownLink/story.jsx
  91. 1 1
      src/components/molecules/DropdownLink/test.jsx
  92. 23 25
      src/components/molecules/EndpointField/index.jsx
  93. 1 1
      src/components/molecules/EndpointField/story.jsx
  94. 1 1
      src/components/molecules/EndpointField/test.jsx
  95. 13 11
      src/components/molecules/EndpointListItem/index.jsx
  96. 1 1
      src/components/molecules/EndpointListItem/story.jsx
  97. 1 1
      src/components/molecules/EndpointListItem/test.jsx
  98. 9 9
      src/components/molecules/LoadingButton/index.jsx
  99. 1 1
      src/components/molecules/LoadingButton/story.jsx
  100. 1 1
      src/components/molecules/LoadingButton/test.jsx

+ 1 - 0
.babelrc

@@ -6,6 +6,7 @@
         "modules": false
       }
     ],
+    "flow",
     "react",
     "stage-1"
   ],

+ 3 - 1
.eslintignore

@@ -1 +1,3 @@
-server.js
+# flow-typed
+flow-typed/npm/*
+!flow-typed/npm/module_vx.x.x.js

+ 62 - 2
.eslintrc

@@ -22,6 +22,20 @@
     }
   },
   "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"],
     "newline-per-chained-call": 0,
@@ -45,6 +59,52 @@
     "import/prefer-default-export": 0,
     "react/require-default-props": 0,
     "react/forbid-prop-types": 0,
-    "jsx-a11y/href-no-hash": 0
-  }
+    "jsx-a11y/href-no-hash": 0,
+    "flowtype/boolean-style": [
+      "error",
+      "boolean"
+    ],
+    "flowtype/define-flow-type": "warn",
+    "flowtype/delimiter-dangle": [
+      "error",
+      "only-multiline"
+    ],
+    "flowtype/generic-spacing": [
+      "error",
+      "never"
+    ],
+    "flowtype/no-primitive-constructor-types": "error",
+    "flowtype/object-type-delimiter": [
+      "error",
+      "comma"
+    ],
+    "flowtype/require-parameter-type": "off",
+    "flowtype/require-return-type": "off",
+    "flowtype/require-valid-file-annotation": "off",
+    "flowtype/semi": [
+      "error",
+      "never"
+    ],
+    "flowtype/space-after-type-colon": [
+      "error",
+      "always"
+    ],
+    "flowtype/space-before-generic-bracket": [
+      "error",
+      "never"
+    ],
+    "flowtype/space-before-type-colon": [
+      "error",
+      "never"
+    ],
+    "flowtype/union-intersection-spacing": [
+      "error",
+      "always"
+    ],
+    "flowtype/use-flow-type": "error",
+    "flowtype/valid-syntax": "error"
+  },
+  "plugins": [
+    "flowtype"
+  ]
 }

+ 17 - 0
.flowconfig

@@ -0,0 +1,17 @@
+[ignore]
+<PROJECT_ROOT>/node_modules/*
+<PROJECT_ROOT>/dist/.*
+
+[libs]
+
+[options]
+esproposal.class_static_fields=enable
+esproposal.class_instance_fields=enable
+esproposal.export_star_as=enable
+module.name_mapper.extension='css' -> '<PROJECT_ROOT>/internals/flow/CSSModule.js.flow'
+module.name_mapper.extension='styl' -> '<PROJECT_ROOT>/internals/flow/CSSModule.js.flow'
+module.name_mapper.extension='scss' -> '<PROJECT_ROOT>/internals/flow/CSSModule.js.flow'
+module.name_mapper.extension='png' -> '<PROJECT_ROOT>/internals/flow/WebpackAsset.js.flow'
+module.name_mapper.extension='jpg' -> '<PROJECT_ROOT>/internals/flow/WebpackAsset.js.flow'
+suppress_comment=\\(.\\|\n\\)*\\$FlowIssue
+suppress_comment=\\(.\\|\n\\)*\\$FlowIgnore

+ 3 - 1
.gitignore

@@ -3,4 +3,6 @@
 dist
 *.log
 node_modules
-.vscode
+.vscode
+flow-typed/npm/*
+!flow-typed/npm/module_vx.x.x.js

+ 7 - 0
flow-typed/module_vx.x.x.js

@@ -0,0 +1,7 @@
+declare module 'module' {
+  declare module.exports: any;
+}
+
+declare module 'moment/locale/en-gb' {
+  declare module.exports: any;
+}

+ 8 - 2
package.json

@@ -12,7 +12,10 @@
     "build:clean": "rimraf \"dist/!(.git*|Procfile)**\"",
     "build:copy": "copyfiles -u 1 public/* public/**/* dist",
     "prebuild": "npm run build:clean && npm run build:copy",
-    "build": "npm run env:prod -- webpack"
+    "build": "npm run env:prod -- webpack",
+    "postinstall": "npm run flow-typed",
+    "flow": "flow",
+    "flow-typed": "rimraf flow-typed/npm && flow-typed install --overwrite || true"
   },
   "jest": {
     "verbose": true,
@@ -37,9 +40,12 @@
     "enzyme-adapter-react-16": "^1.0.4",
     "eslint": "^4.8.0",
     "eslint-config-airbnb": "^15.1.0",
+    "eslint-plugin-flowtype": "^2.46.1",
     "eslint-plugin-import": "^2.7.0",
     "eslint-plugin-jsx-a11y": "^6.0.2",
     "eslint-plugin-react": "^7.4.0",
+    "flow-bin": "^0.66.0",
+    "flow-typed": "^2.3.0",
     "jest": "^21.2.1",
     "react-test-renderer": "^16.0.0",
     "sinon": "^4.1.2",
@@ -56,6 +62,7 @@
     "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
     "babel-plugin-transform-react-remove-prop-types": "^0.4.9",
     "babel-preset-env": "^1.6.0",
+    "babel-preset-flow": "^6.23.0",
     "babel-preset-react": "^6.24.1",
     "babel-preset-stage-1": "^6.24.1",
     "babel-register": "^6.26.0",
@@ -70,7 +77,6 @@
     "lodash": "^4.17.4",
     "moment": "^2.18.1",
     "path": "^0.12.7",
-    "prop-types": "^15.6.0",
     "raw-loader": "^0.5.1",
     "react": "^16.0.0",
     "react-collapse": "^4.0.3",

+ 6 - 6
private/storybook/Decorator.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from 'react'
+// @flow
+
+import * as React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 import Palette from '../../src/components/styleUtils/Palette'
 
 const Wrapper = styled.div`
@@ -23,10 +24,9 @@ const Wrapper = styled.div`
   padding: 32px;
 `
 
-const Decorator = ({ children }) => <Wrapper>{children}</Wrapper>
-
-Decorator.propTypes = {
-  children: PropTypes.node,
+type Props = {
+  children: React.Node,
 }
+const Decorator = (props: Props) => <Wrapper>{props.children}</Wrapper>
 
 export default Decorator

+ 2 - 0
src/actions/EndpointActions.js

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import alt from '../alt'
 
 import EndpointSource from '../sources/EndpointSource'

+ 2 - 0
src/actions/InstanceActions.js

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import alt from '../alt'
 
 import InstanceSource from '../sources/InstanceSource'

+ 2 - 0
src/actions/MigrationActions.js

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import alt from '../alt'
 
 import MigrationSource from '../sources/MigrationSource'

+ 2 - 0
src/actions/NetworkActions.js

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import alt from '../alt'
 
 import NetworkSource from '../sources/NetworkSource'

+ 2 - 0
src/actions/NotificationActions.js

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import alt from '../alt'
 
 import NotificationSource from '../sources/NotificationSource'

+ 2 - 0
src/actions/ProjectActions.js

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import alt from '../alt'
 
 import PojectSource from '../sources/ProjectSource'

+ 2 - 0
src/actions/ProviderActions.js

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import alt from '../alt'
 
 import ProviderSource from '../sources/ProviderSource'

+ 2 - 0
src/actions/ReplicaActions.js

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import alt from '../alt'
 
 import ReplicaSource from '../sources/ReplicaSource'

+ 2 - 0
src/actions/ScheduleActions.js

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import alt from '../alt'
 
 import ScheduleSource from '../sources/ScheduleSource'

+ 2 - 0
src/actions/UserActions.js

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import alt from '../alt'
 
 import UserSource from '../sources/UserSource'

+ 2 - 0
src/actions/WizardActions.js

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import alt from '../alt'
 
 import WizardSource from '../sources/WizardSource'

+ 14 - 14
src/components/App.jsx

@@ -12,23 +12,23 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import { Switch, Route } from 'react-router-dom'
 import styled, { injectGlobal } from 'styled-components'
 
-import {
-  LoginPage,
-  Fonts,
-  Notifications,
-  NotFoundPage,
-  ReplicasPage,
-  ReplicaDetailsPage,
-  MigrationsPage,
-  MigrationDetailsPage,
-  EndpointsPage,
-  EndpointDetailsPage,
-  WizardPage,
-} from 'components'
+import Fonts from './atoms/Fonts'
+import Notifications from './organisms/Notifications'
+import LoginPage from './pages/LoginPage'
+import ReplicasPage from './pages/ReplicasPage'
+import NotFoundPage from './pages/NotFoundPage'
+import ReplicaDetailsPage from './pages/ReplicaDetailsPage'
+import MigrationsPage from './pages/MigrationsPage'
+import MigrationDetailsPage from './pages/MigrationDetailsPage'
+import EndpointsPage from './pages/EndpointsPage'
+import EndpointDetailsPage from './pages/EndpointDetailsPage'
+import WizardPage from './pages/WizardPage'
 
 import Palette from './styleUtils/Palette'
 import StyleProps from './styleUtils/StyleProps'
@@ -48,7 +48,7 @@ injectGlobal`
 `
 const Wrapper = styled.div``
 
-class App extends React.Component {
+class App extends React.Component<{}> {
   componentWillMount() {
     UserActions.tokenLogin()
   }

+ 11 - 10
src/components/atoms/Arrow/Arrow.jsx → src/components/atoms/Arrow/index.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -39,16 +40,16 @@ const Wrapper = styled.div`
   ${props => getOrientation(props)}
 `
 
-class Arrow extends React.Component {
-  static propTypes = {
-    primary: PropTypes.bool,
-    useDefaultCursor: PropTypes.bool,
-    orientation: PropTypes.string,
-    opacity: PropTypes.number,
-    disabled: PropTypes.bool,
-  }
+type Props = {
+  primary?: boolean,
+  useDefaultCursor?: boolean,
+  orientation: 'left' | 'down' | 'up' | 'right',
+  opacity: number,
+  disabled?: boolean,
+}
 
-  static defaultProps = {
+class Arrow extends React.Component<Props> {
+  static defaultProps: Props = {
     orientation: 'right',
     opacity: 1,
   }

+ 1 - 1
src/components/atoms/Arrow/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import Arrow from './Arrow'
+import Arrow from '.'
 
 storiesOf('Arrow', module)
   .add('default', () => (

+ 3 - 6
src/components/atoms/Button/Button.jsx → src/components/atoms/Button/index.jsx

@@ -12,8 +12,9 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
-import PropTypes from 'prop-types'
 import styled from 'styled-components'
 
 import Palette from '../../styleUtils/Palette'
@@ -106,14 +107,10 @@ const StyledButton = styled.button`
   }
 `
 
-const Button = ({ ...props }) => {
+const Button = (props: any) => {
   return (
     <StyledButton {...props} onFocus={e => { e.target.blur() }} />
   )
 }
 
-Button.propTypes = {
-  children: PropTypes.node,
-}
-
 export default Button

+ 1 - 1
src/components/atoms/Button/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf, action } from '@storybook/react'
-import Button from './Button'
+import Button from '.'
 
 storiesOf('Button', module)
   .add('primary', () => (

+ 1 - 1
src/components/atoms/Button/test.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { shallow } from 'enzyme'
 import sinon from 'sinon'
-import Button from './Button'
+import Button from '.'
 
 const wrap = props => shallow(<Button {...props} />)
 

+ 10 - 10
src/components/atoms/Checkbox/Checkbox.jsx → src/components/atoms/Checkbox/index.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled, { css } from 'styled-components'
-import PropTypes from 'prop-types'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -48,16 +49,15 @@ const Wrapper = styled.div`
   ` : ''}
 `
 
-class Checkbox extends React.Component {
-  static propTypes = {
-    className: PropTypes.string,
-    checked: PropTypes.bool,
-    disabled: PropTypes.bool,
-    onChange: PropTypes.func.isRequired,
-  }
-
+type Props = {
+  className?: string,
+  checked?: boolean,
+  disabled?: boolean,
+  onChange?: (checked: boolean) => void,
+}
+class Checkbox extends React.Component<Props> {
   handleClick() {
-    if (this.props.disabled) {
+    if (this.props.disabled || !this.props.onChange) {
       return
     }
 

+ 1 - 1
src/components/atoms/Checkbox/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import Checkbox from './Checkbox'
+import Checkbox from '.'
 
 class Wrapper extends React.Component {
   constructor() {

+ 1 - 1
src/components/atoms/Checkbox/test.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { shallow } from 'enzyme'
 import sinon from 'sinon'
-import Checkbox from './Checkbox'
+import Checkbox from '.'
 
 const wrap = props => shallow(<Checkbox {...props} />)
 

+ 3 - 1
src/components/atoms/CopyButton/CopyButton.jsx → src/components/atoms/CopyButton/index.jsx

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
 
@@ -29,7 +31,7 @@ const Wrapper = styled.span`
   transition: all ${StyleProps.animations.swift};
 `
 
-class CopyButton extends React.Component {
+class CopyButton extends React.Component<{}> {
   render() {
     return (
       <Wrapper {...this.props} />

+ 1 - 1
src/components/atoms/CopyButton/story.jsx

@@ -16,7 +16,7 @@ import React from 'react'
 import { storiesOf } from '@storybook/react'
 import styled from 'styled-components'
 
-import CopyButton from './CopyButton'
+import CopyButton from '.'
 
 const Wrapper = styled.div`
   cursor: pointer;

+ 1 - 1
src/components/atoms/CopyButton/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import CopyButton from './CopyButton'
+import CopyButton from '.'
 
 const wrap = props => shallow(<CopyButton {...props} />).dive()
 

+ 10 - 10
src/components/atoms/CopyValue/CopyValue.jsx → src/components/atoms/CopyValue/index.jsx

@@ -12,11 +12,12 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
-import { CopyButton } from 'components'
+import CopyButton from '../CopyButton'
 import NotificationActions from '../../../actions/NotificationActions'
 import DomUtils from '../../../utils/DomUtils'
 
@@ -37,14 +38,13 @@ const Value = styled.span`
   margin-right: 4px;
 `
 
-class CopyValue extends React.Component {
-  static propTypes = {
-    value: PropTypes.string,
-    width: PropTypes.string,
-    maxWidth: PropTypes.string,
-  }
-
-  handleCopyIdClick(e) {
+type Props = {
+  value: string,
+  width?: string,
+  maxWidth?: string,
+}
+class CopyValue extends React.Component<Props> {
+  handleCopyIdClick(e: Event) {
     e.stopPropagation()
 
     let succesful = DomUtils.copyTextToClipboard(this.props.value)

+ 1 - 1
src/components/atoms/CopyValue/test.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { shallow } from 'enzyme'
 import sinon from 'sinon'
-import CopyValue from './CopyValue'
+import CopyValue from '.'
 
 const wrap = props => shallow(<CopyValue {...props} />).dive()
 

+ 14 - 15
src/components/atoms/DropdownButton/DropdownButton.jsx → src/components/atoms/DropdownButton/index.jsx

@@ -12,8 +12,9 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
-import PropTypes from 'prop-types'
 import styled from 'styled-components'
 
 import arrowImage from './images/arrow.js'
@@ -112,26 +113,24 @@ const Arrow = styled.div`
   top: 12px;
   display: flex;
 `
-
-const DropdownButton = ({ value, onClick, className, disabled, ...props }) => {
+type Props = {
+  value: string,
+  onClick?: (event: Event) => void,
+  className?: string,
+  disabled?: boolean,
+}
+const DropdownButton = (props: Props) => {
   return (
     <Wrapper
-      onClick={e => { disabled ? null : onClick(e) }}
-      className={className}
-      disabled={disabled}
+      onClick={e => { props.disabled ? null : props.onClick && props.onClick(e) }}
+      className={props.className}
+      disabled={props.disabled}
       {...props}
     >
-      <Label {...props} disabled={disabled}>{value}</Label>
-      <Arrow {...props} disabled={disabled} dangerouslySetInnerHTML={{ __html: arrowImage }} />
+      <Label {...props} disabled={props.disabled}>{props.value}</Label>
+      <Arrow {...props} disabled={props.disabled} dangerouslySetInnerHTML={{ __html: arrowImage }} />
     </Wrapper>
   )
 }
 
-DropdownButton.propTypes = {
-  value: PropTypes.string,
-  className: PropTypes.string,
-  onClick: PropTypes.func,
-  disabled: PropTypes.bool,
-}
-
 export default DropdownButton

+ 1 - 1
src/components/atoms/DropdownButton/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf, action } from '@storybook/react'
-import DropdownButton from './DropdownButton'
+import DropdownButton from '.'
 
 storiesOf('DropdownButton', module)
   .add('default', () => (

+ 1 - 1
src/components/atoms/DropdownButton/test.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { shallow } from 'enzyme'
 import sinon from 'sinon'
-import DropdownButton from './DropdownButton'
+import DropdownButton from '.'
 
 const wrap = props => shallow(<DropdownButton {...props} />).dive()
 

+ 9 - 9
src/components/atoms/EndpointLogos/EndpointLogos.jsx → src/components/atoms/EndpointLogos/index.jsx

@@ -12,8 +12,9 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
-import PropTypes from 'prop-types'
 import styled from 'styled-components'
 
 import aws32Image from './images/aws-32.svg'
@@ -108,14 +109,13 @@ const widthHeights = [
   { w: 192, h: 64 },
 ]
 
-class EndpointLogos extends React.Component {
-  static propTypes = {
-    endpoint: PropTypes.string,
-    height: PropTypes.number,
-    disabled: PropTypes.bool,
-  }
-
-  static defaultProps = {
+type Props = {
+  endpoint?: string,
+  height: number,
+  disabled?: boolean,
+}
+class EndpointLogos extends React.Component<Props> {
+  static defaultProps: Props = {
     height: 64,
   }
 

+ 1 - 1
src/components/atoms/EndpointLogos/story.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { storiesOf } from '@storybook/react'
 import styled from 'styled-components'
-import EndpointLogos from './EndpointLogos'
+import EndpointLogos from '.'
 
 const Wrapper = styled.div`
   display: flex;

+ 1 - 1
src/components/atoms/EndpointLogos/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import EndpointLogos from './EndpointLogos'
+import EndpointLogos from '.'
 
 const wrap = props => shallow(<EndpointLogos {...props} />).dive()
 

+ 5 - 1
src/components/atoms/Fonts/Fonts.js → src/components/atoms/Fonts/index.js

@@ -12,6 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
+import { css } from 'styled-components'
+
 import RubikRegular from './Rubik-Regular.woff'
 import RubikItalic from './Rubik-Italic.woff'
 import RubikBold from './Rubik-Bold.woff'
@@ -20,7 +24,7 @@ import RubikLightItalic from './Rubik-LightItalic.woff'
 import RubikMedium from './Rubik-Medium.woff'
 import RubikMediumItalic from './Rubik-MediumItalic.woff'
 
-const Fonts = `
+const Fonts = css`
   @font-face {
     font-family: 'Rubik';
     src: url('${RubikRegular}') format('woff');

+ 7 - 8
src/components/atoms/InfoIcon/InfoIcon.jsx → src/components/atoms/InfoIcon/index.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
 import questionImage from './images/question.svg'
 
@@ -26,13 +27,11 @@ const Wrapper = styled.div`
   margin-bottom: -4px;
   margin-left: ${props => props.marginLeft ? `${props.marginLeft}px` : '4px'};
 `
-
-class InfoIcon extends React.Component {
-  static propTypes = {
-    text: PropTypes.string,
-    marginLeft: PropTypes.number,
-  }
-
+type Props = {
+  text: string,
+  marginLeft: number,
+}
+class InfoIcon extends React.Component<Props> {
   render() {
     return (
       <Wrapper data-tip={this.props.text} marginLeft={this.props.marginLeft} />

+ 8 - 8
src/components/atoms/Logo/Logo.jsx → src/components/atoms/Logo/index.jsx

@@ -12,8 +12,9 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
-import PropTypes from 'prop-types'
 import styled, { css } from 'styled-components'
 
 import StyleProps from '../../styleUtils/StyleProps'
@@ -42,17 +43,16 @@ const Coriolis = styled.div`
   ` : ''}
 `
 
-const Logo = ({ large, small, ...props }) => {
+type Props = {
+  large?: boolean,
+  small?: boolean,
+}
+const Logo = (props: Props) => {
   return (
     <Wrapper {...props}>
-      <Coriolis large={large} small={small} />
+      <Coriolis large={props.large} small={props.small} />
     </Wrapper>
   )
 }
 
-Logo.propTypes = {
-  large: PropTypes.bool,
-  small: PropTypes.bool,
-}
-
 export default Logo

+ 1 - 1
src/components/atoms/Logo/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import Logo from './Logo'
+import Logo from '.'
 
 storiesOf('Logo', module)
   .add('default', () => (

+ 9 - 6
src/components/atoms/PasswordValue/PasswordValue.jsx → src/components/atoms/PasswordValue/index.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
 import StyleProps from '../../styleUtils/StyleProps'
 
@@ -44,11 +45,13 @@ const Value = styled.span`
   margin-right: 4px;
 `
 
-class PasswordValue extends React.Component {
-  static propTypes = {
-    value: PropTypes.string,
-  }
-
+type Props = {
+  value: string,
+}
+type State = {
+  show: boolean,
+}
+class PasswordValue extends React.Component<Props, State> {
   constructor() {
     super()
 

+ 1 - 1
src/components/atoms/PasswordValue/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import PasswordValue from './PasswordValue'
+import PasswordValue from '.'
 
 storiesOf('PasswordValue', module)
   .add('default', () => (

+ 1 - 1
src/components/atoms/PasswordValue/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import PasswordValue from './PasswordValue'
+import PasswordValue from '.'
 
 const wrap = props => shallow(<PasswordValue {...props} />)
 const text = html => html.substring(html.indexOf('>') + 1, html.lastIndexOf('<'))

+ 9 - 7
src/components/atoms/ProgressBar/ProgressBar.jsx → src/components/atoms/ProgressBar/index.jsx

@@ -12,13 +12,19 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
 
+type Props = {
+  progress: number,
+  width?: number,
+}
+
 const Wrapper = styled.div`
   background: white;
 `
@@ -26,14 +32,10 @@ const Progress = styled.div`
   height: 2px;
   background: ${Palette.primary};
   transition: all ${StyleProps.animations.swift};
-  width: ${props => props.width}%;
+  width: ${(props: Props) => props.width}%;
 `
 
-class ProgressBar extends React.Component {
-  static propTypes = {
-    progress: PropTypes.number,
-  }
-
+class ProgressBar extends React.Component<Props> {
   render() {
     return (
       <Wrapper {...this.props}>

+ 1 - 1
src/components/atoms/ProgressBar/story.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { storiesOf } from '@storybook/react'
 
-import ProgressBar from './ProgressBar'
+import ProgressBar from '.'
 
 let Wrapper = props => <div style={{ width: '800px' }}><ProgressBar {...props} /></div>
 

+ 1 - 1
src/components/atoms/ProgressBar/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import ProgressBar from './ProgressBar'
+import ProgressBar from '.'
 
 const wrap = props => shallow(<ProgressBar {...props} />).dive()
 

+ 6 - 6
src/components/atoms/RadioInput/RadioInput.jsx → src/components/atoms/RadioInput/index.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -49,11 +50,10 @@ const InputStyled = styled.input`
   }
 `
 
-class RadioInput extends React.Component {
-  static propTypes = {
-    label: PropTypes.string,
-  }
-
+type Props = {
+  label: string,
+}
+class RadioInput extends React.Component<Props> {
   render() {
     return (
       <Wrapper {...this.props}>

+ 1 - 1
src/components/atoms/RadioInput/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import RadioInput from './RadioInput'
+import RadioInput from '.'
 
 storiesOf('RadioInput', module)
   .add('default', () => (

+ 1 - 1
src/components/atoms/RadioInput/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import RadioInput from './RadioInput'
+import RadioInput from '.'
 
 const wrap = props => shallow(<RadioInput {...props} />)
 

+ 8 - 5
src/components/atoms/ReloadButton/ReloadButton.jsx → src/components/atoms/ReloadButton/index.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled, { injectGlobal } from 'styled-components'
-import PropTypes from 'prop-types'
 
 import reloadImage from './images/reload.svg'
 
@@ -32,10 +33,12 @@ injectGlobal`
   }
 `
 
-class ReloadButton extends React.Component {
-  static propTypes = {
-    onClick: PropTypes.func,
-  }
+type Props = {
+  onClick: () => void,
+}
+class ReloadButton extends React.Component<Props> {
+  wrapper: HTMLElement
+  timeout: ?TimeoutID
 
   onClick() {
     if (this.timeout) {

+ 1 - 1
src/components/atoms/ReloadButton/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import ReloadButton from './ReloadButton'
+import ReloadButton from '.'
 
 storiesOf('ReloadButton', module)
   .add('default', () => (

+ 1 - 1
src/components/atoms/ReloadButton/test.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { shallow } from 'enzyme'
 import sinon from 'sinon'
-import ReloadButton from './ReloadButton'
+import ReloadButton from '.'
 
 const wrap = props => shallow(<ReloadButton {...props} />)
 

+ 7 - 7
src/components/atoms/SearchButton/SearchButton.jsx → src/components/atoms/SearchButton/index.jsx

@@ -12,8 +12,9 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
-import PropTypes from 'prop-types'
 import styled from 'styled-components'
 
 import Palette from '../../styleUtils/Palette'
@@ -31,12 +32,11 @@ const Icon = styled.div`
   align-items: center;
 `
 
-class SearchButton extends React.Component {
-  static propTypes = {
-    className: PropTypes.string,
-    primary: PropTypes.bool,
-  }
-
+type Props = {
+  className: string,
+  primary: boolean,
+}
+class SearchButton extends React.Component<Props> {
   render() {
     return (
       <Wrapper className={this.props.className} {...this.props}>

+ 1 - 1
src/components/atoms/SearchButton/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import SearchButton from './SearchButton'
+import SearchButton from '.'
 
 storiesOf('SearchButton', module)
   .add('default', () => (

+ 1 - 1
src/components/atoms/SearchButton/test.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { shallow } from 'enzyme'
 import sinon from 'sinon'
-import SearchButton from './SearchButton'
+import SearchButton from '.'
 
 const wrap = props => shallow(<SearchButton {...props} />)
 

+ 11 - 10
src/components/atoms/StatusIcon/StatusIcon.jsx → src/components/atoms/StatusIcon/index.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled, { css } from 'styled-components'
-import PropTypes from 'prop-types'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -26,14 +27,19 @@ import successImage from './images/success.svg'
 import warningImage from './images/warning.svg'
 import pendingImage from './images/pending.svg'
 
-const getRunningImageUrl = props => {
+type Props = {
+  status: string,
+  useBackground?: boolean,
+}
+
+const getRunningImageUrl = (props: Props) => {
   const smallCircleColor = props.secondary ? Palette.grayscale[0] : Palette.primary
 
   if (props.useBackground) {
-    return `url('${progressWithBackgroundImage}')`
+    return css`url('${progressWithBackgroundImage}')`
   }
 
-  return `url('data:image/svg+xml;utf8,${encodeURIComponent(progressImage(Palette.grayscale[3], smallCircleColor))}')`
+  return css`url('data:image/svg+xml;utf8,${encodeURIComponent(progressImage(Palette.grayscale[3], smallCircleColor))}')`
 }
 
 const statuses = props => {
@@ -69,12 +75,7 @@ const Wrapper = styled.div`
   ${props => statuses(props)[props.status]}
 `
 
-class StatusIcon extends React.Component {
-  static propTypes = {
-    status: PropTypes.string.isRequired,
-    useBackground: PropTypes.bool,
-  }
-
+class StatusIcon extends React.Component<Props> {
   render() {
     return (
       <Wrapper {...this.props} />

+ 1 - 1
src/components/atoms/StatusIcon/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import StatusIcon from './StatusIcon'
+import StatusIcon from '.'
 
 storiesOf('StatusIcon', module)
   .add('completed', () => (

+ 1 - 1
src/components/atoms/StatusIcon/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import StatusIcon from './StatusIcon'
+import StatusIcon from '.'
 
 const wrap = props => shallow(<StatusIcon {...props} />)
 

+ 11 - 9
src/components/atoms/StatusImage/StatusImage.jsx → src/components/atoms/StatusImage/index.jsx

@@ -12,15 +12,21 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled, { css } from 'styled-components'
-import PropTypes from 'prop-types'
 import StyleProps from '../../styleUtils/StyleProps'
 
 import errorImage from './images/error.svg'
 import successImage from './images/success.svg'
 import loadingImage from './images/loading.svg'
 
+type Props = {
+  status?: string,
+  loading?: boolean,
+}
+
 const statuses = () => {
   return {
     ERROR: css`
@@ -45,16 +51,12 @@ const Wrapper = styled.div`
   ${StyleProps.exactSize('96px')}
   background-repeat: no-repeat;
   background-position: center;
-  ${props => statuses(props)[props.status]}
+  ${ // $FlowIssue
+  (props: Props) => statuses()[props.status]}
 `
 
-class StatusImage extends React.Component {
-  static propTypes = {
-    status: PropTypes.string,
-    loading: PropTypes.bool,
-  }
-
-  static defaultPropTypes = {
+class StatusImage extends React.Component<Props> {
+  static defaultProps: $Shape<Props> = {
     status: 'RUNNING',
   }
 

+ 1 - 1
src/components/atoms/StatusImage/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import StatusImage from './StatusImage'
+import StatusImage from '.'
 
 storiesOf('StatusImage', module)
   .add('completed', () => (

+ 1 - 1
src/components/atoms/StatusImage/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import StatusImage from './StatusImage'
+import StatusImage from '.'
 
 const wrap = props => shallow(<StatusImage {...props} />)
 

+ 12 - 12
src/components/atoms/StatusPill/StatusPill.jsx → src/components/atoms/StatusPill/index.jsx

@@ -12,8 +12,9 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
-import PropTypes from 'prop-types'
 import styled, { css } from 'styled-components'
 
 import Palette from '../../styleUtils/Palette'
@@ -93,17 +94,16 @@ const Wrapper = styled.div`
   ${props => props.status === 'INFO' ? getInfoStatusColor(props) : ''}
 `
 
-class StatusPill extends React.Component {
-  static propTypes = {
-    status: PropTypes.string,
-    label: PropTypes.string,
-    primary: PropTypes.bool,
-    secondary: PropTypes.bool,
-    alert: PropTypes.bool,
-    small: PropTypes.bool,
-  }
-
-  static defaultProps = {
+type Props = {
+  status: ?string,
+  label: string,
+  primary: boolean,
+  secondary: boolean,
+  alert: boolean,
+  small: boolean,
+}
+class StatusPill extends React.Component<Props> {
+  static defaultProps: $Shape<Props> = {
     status: 'INFO',
   }
 

+ 1 - 1
src/components/atoms/StatusPill/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import StatusPill from './StatusPill'
+import StatusPill from '.'
 
 storiesOf('StatusPill', module)
   .add('completed', () => (

+ 1 - 1
src/components/atoms/StatusPill/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import StatusPill from './StatusPill'
+import StatusPill from '.'
 
 const wrap = props => shallow(<StatusPill {...props} />)
 

+ 23 - 20
src/components/atoms/Switch/Switch.jsx → src/components/atoms/Switch/index.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -110,25 +111,27 @@ const LeftLabel = styled.div`
   white-space: nowrap;
 `
 
-class Switch extends React.Component {
-  static propTypes = {
-    onChange: PropTypes.func,
-    checked: PropTypes.bool,
-    disabled: PropTypes.bool,
-    triState: PropTypes.bool,
-    leftLabel: PropTypes.bool,
-    secondary: PropTypes.bool,
-    noLabel: PropTypes.bool,
-    height: PropTypes.number,
-    width: PropTypes.string,
-    justifyContent: PropTypes.string,
-    big: PropTypes.bool,
-    checkedLabel: PropTypes.string,
-    uncheckedLabel: PropTypes.string,
-    style: PropTypes.object,
-  }
-
-  static defaultProps = {
+type Props = {
+  onChange: (checked: ?boolean) => void,
+  checked: boolean,
+  disabled: boolean,
+  triState: boolean,
+  leftLabel: boolean,
+  secondary: boolean,
+  noLabel: boolean,
+  height: number,
+  width: string,
+  justifyContent: string,
+  big: boolean,
+  checkedLabel: string,
+  uncheckedLabel: string,
+  style: {[string]: mixed},
+}
+type State = {
+  lastChecked: ?boolean,
+}
+class Switch extends React.Component<Props, State> {
+  static defaultProps: $Shape<Props> = {
     checkedLabel: 'Yes',
     uncheckedLabel: 'No',
     height: 24,

+ 1 - 1
src/components/atoms/Switch/story.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { storiesOf } from '@storybook/react'
 import PropTypes from 'prop-types'
-import Switch from './Switch'
+import Switch from '.'
 
 class Wrapper extends React.Component {
   static propTypes = {

+ 1 - 1
src/components/atoms/Switch/test.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { shallow } from 'enzyme'
 import sinon from 'sinon'
-import Switch from './Switch'
+import Switch from '.'
 
 const wrap = props => shallow(<Switch {...props} />)
 

+ 3 - 1
src/components/atoms/TextArea/TextArea.jsx → src/components/atoms/TextArea/index.jsx

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
 import Palette from '../../styleUtils/Palette'
@@ -58,7 +60,7 @@ const Input = styled.textarea`
   }
 `
 
-class TextArea extends React.Component {
+class TextArea extends React.Component<{}> {
   render() {
     return (
       <Input {...this.props} />

+ 16 - 8
src/components/atoms/TextInput/TextInput.jsx → src/components/atoms/TextInput/index.jsx

@@ -12,8 +12,9 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from 'react'
-import PropTypes from 'prop-types'
+// @flow
+
+import * as React from 'react'
 import styled from 'styled-components'
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -72,7 +73,19 @@ const Required = styled.div`
   background: url('${starImage}') center no-repeat;
 `
 
-const TextInput = ({ _ref, required, ...props }) => {
+type Props = {
+  _ref?: (ref: HTMLElement) => void,
+  required?: boolean,
+  disabled?: boolean,
+  highlight?: boolean,
+  large?: boolean,
+  onChange?: (e: SyntheticInputEvent<EventTarget>) => void,
+  placeholder?: string,
+  type?: string,
+  value?: string,
+}
+const TextInput = (props: Props) => {
+  const { _ref, required } = props
   return (
     <Wrapper>
       <Input innerRef={_ref} type="text" customRequired={required} {...props} />
@@ -81,9 +94,4 @@ const TextInput = ({ _ref, required, ...props }) => {
   )
 }
 
-TextInput.propTypes = {
-  _ref: PropTypes.func,
-  required: PropTypes.bool,
-}
-
 export default TextInput

+ 1 - 1
src/components/atoms/TextInput/story.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { storiesOf } from '@storybook/react'
 import styled from 'styled-components'
-import TextInput from './TextInput'
+import TextInput from '.'
 
 const Wrapper = styled.div`
   display: inline-block;

+ 1 - 1
src/components/atoms/TextInput/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import TextInput from './TextInput'
+import TextInput from '.'
 
 const wrap = props => shallow(<TextInput {...props} />)
 

+ 9 - 8
src/components/atoms/ToggleButtonBar/ToggleButtonBar.jsx → src/components/atoms/ToggleButtonBar/index.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -49,13 +50,13 @@ const Item = styled.div`
   }
 `
 
-class ToggleButtonBar extends React.Component {
-  static propTypes = {
-    items: PropTypes.array,
-    selectedValue: PropTypes.string,
-    onChange: PropTypes.func,
-  }
-
+type ItemType = { value: string, label: string }
+type Props = {
+  items: Array<ItemType>,
+  selectedValue: string,
+  onChange: (item: ItemType) => void,
+}
+class ToggleButtonBar extends React.Component<Props> {
   render() {
     if (!this.props.items) {
       return null

+ 1 - 1
src/components/atoms/ToggleButtonBar/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import ToggleButtonBar from './ToggleButtonBar'
+import ToggleButtonBar from '.'
 
 class Wrapper extends React.Component {
   constructor() {

+ 1 - 1
src/components/atoms/ToggleButtonBar/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import ToggleButtonBar from './ToggleButtonBar'
+import ToggleButtonBar from '.'
 
 const wrap = props => shallow(<ToggleButtonBar {...props} />)
 const items = [

+ 3 - 1
src/components/atoms/Tooltip/Tooltip.jsx → src/components/atoms/Tooltip/index.jsx

@@ -12,6 +12,8 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import { injectGlobal } from 'styled-components'
 import ReactTooltip from 'react-tooltip'
@@ -38,7 +40,7 @@ injectGlobal`
   }
 `
 
-class Tooltip extends React.Component {
+class Tooltip extends React.Component<{}> {
   static rebuild = () => {
     ReactTooltip.rebuild()
   }

+ 2 - 2
src/components/atoms/Tooltip/story.jsx

@@ -14,9 +14,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import { WizardOptionsField } from 'components'
+import WizardOptionsField from '../../molecules/WizardOptionsField'
 
-import Tooltip from './Tooltip'
+import Tooltip from '.'
 
 storiesOf('Tooltip', module)
   .add('default', () => (

+ 21 - 13
src/components/molecules/DatetimePicker/DatetimePicker.jsx → src/components/molecules/DatetimePicker/index.jsx

@@ -12,13 +12,14 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled, { injectGlobal } from 'styled-components'
 import Datetime from 'react-datetime'
-import PropTypes from 'prop-types'
 import moment from 'moment'
 
-import { DropdownButton } from 'components'
+import DropdownButton from '../../atoms/DropdownButton'
 
 import DomUtils from '../../../utils/DomUtils'
 import DateUtils from '../../../utils/DateUtils'
@@ -48,13 +49,18 @@ const DatetimeStyled = styled(Datetime)`
   }
 `
 
-class DatetimePicker extends React.Component {
-  static propTypes = {
-    value: PropTypes.object,
-    onChange: PropTypes.func.isRequired,
-    isValidDate: PropTypes.func,
-    timezone: PropTypes.string,
-  }
+type Props = {
+  value: ?Date,
+  onChange: (date: Date) => void,
+  isValidDate: (currentDate: Date, selectedDate: Date) => boolean,
+  timezone: 'utc' | 'local'
+}
+type State = {
+  showPicker: boolean,
+  date: ?Date,
+}
+class DatetimePicker extends React.Component<Props, State> {
+  itemMouseDown: boolean
 
   constructor() {
     super()
@@ -63,7 +69,9 @@ class DatetimePicker extends React.Component {
       showPicker: false,
       date: null,
     }
-    this.handlePageClick = this.handlePageClick.bind(this)
+
+    const self: any = this
+    self.handlePageClick = this.handlePageClick.bind(this)
   }
 
   componentWillMount() {
@@ -78,7 +86,7 @@ class DatetimePicker extends React.Component {
     window.removeEventListener('mousedown', this.handlePageClick, false)
   }
 
-  isValidDate(currentDate, selectedDate) {
+  isValidDate(currentDate: Date, selectedDate: Date): boolean {
     if (!this.props.isValidDate) {
       return true
     }
@@ -86,7 +94,7 @@ class DatetimePicker extends React.Component {
     return this.props.isValidDate(currentDate, selectedDate)
   }
 
-  handlePageClick(e) {
+  handlePageClick(e: Event) {
     let path = DomUtils.getEventPath(e)
 
     if (!this.itemMouseDown && !path.find(n => n.className === 'rdtPicker')) {
@@ -105,7 +113,7 @@ class DatetimePicker extends React.Component {
     this.setState({ showPicker: !this.state.showPicker })
   }
 
-  handleChange(date) {
+  handleChange(date: Date) {
     if (this.props.timezone === 'utc') {
       date = DateUtils.getLocalTime(date)
     }

+ 1 - 1
src/components/molecules/DatetimePicker/story.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { storiesOf } from '@storybook/react'
 import moment from 'moment'
-import DatetimePicker from './DatetimePicker'
+import DatetimePicker from '.'
 
 class Wrapper extends React.Component {
   render() {

+ 1 - 1
src/components/molecules/DatetimePicker/test.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { shallow } from 'enzyme'
 import sinon from 'sinon'
-import DatetimePicker from './DatetimePicker'
+import DatetimePicker from '.'
 
 const wrap = props => shallow(<DatetimePicker {...props} />)
 

+ 9 - 9
src/components/molecules/DetailsNavigation/DetailsNavigation.jsx → src/components/molecules/DetailsNavigation/index.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -32,14 +33,13 @@ const Item = styled.a`
   text-decoration: none;
 `
 
-class DetailsNavigation extends React.Component {
-  static propTypes = {
-    items: PropTypes.array.isRequired,
-    selectedValue: PropTypes.string,
-    itemId: PropTypes.string,
-    itemType: PropTypes.string,
-  }
-
+type Props = {
+  items: { label: string, value: string }[],
+  selectedValue: string,
+  itemId: string,
+  itemType: string,
+}
+class DetailsNavigation extends React.Component<Props> {
   renderItems() {
     return (
       this.props.items.map(item => (

+ 1 - 1
src/components/molecules/DetailsNavigation/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import DetailsNavigation from './DetailsNavigation'
+import DetailsNavigation from '.'
 
 const items = [
   { label: 'Item 1', value: 'item-1' },

+ 1 - 1
src/components/molecules/DetailsNavigation/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import DetailsNavigation from './DetailsNavigation'
+import DetailsNavigation from '.'
 
 const wrap = props => shallow(<DetailsNavigation {...props} />)
 const items = [

+ 62 - 49
src/components/molecules/Dropdown/Dropdown.jsx → src/components/molecules/Dropdown/index.jsx

@@ -12,12 +12,13 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
-import PropTypes from 'prop-types'
 import styled from 'styled-components'
 import ReactDOM from 'react-dom'
 
-import { DropdownButton } from 'components'
+import DropdownButton from '../../atoms/DropdownButton'
 
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -87,31 +88,42 @@ const ListItem = styled.div`
   }
 `
 
-class Dropdown extends React.Component {
-  static propTypes = {
-    selectedItem: PropTypes.any,
-    items: PropTypes.array,
-    labelField: PropTypes.string,
-    className: PropTypes.string,
-    onChange: PropTypes.func,
-    noItemsMessage: PropTypes.string,
-    noSelectionMessage: PropTypes.string,
-    disabled: PropTypes.bool,
-    width: PropTypes.number,
-  }
-
-  static defaultProps = {
+type Props = {
+  selectedItem: any,
+  items: any[],
+  labelField: string,
+  className: string,
+  onChange: (item: any) => void,
+  noItemsMessage: string,
+  noSelectionMessage: string,
+  disabled: boolean,
+  width: number,
+}
+type State = {
+  showDropdownList: boolean,
+  firstItemHover: boolean
+}
+class Dropdown extends React.Component<Props, State> {
+  static defaultProps: $Shape<Props> = {
     noSelectionMessage: 'Select an item',
   }
 
+  buttonRef: HTMLElement
+  listRef: HTMLElement
+  tipRef: HTMLElement
+  buttonRect: ClientRect
+  itemMouseDown: boolean
+
   constructor() {
     super()
 
     this.state = {
       showDropdownList: false,
+      firstItemHover: false,
     }
 
-    this.handlePageClick = this.handlePageClick.bind(this)
+    const self: any = this
+    self.handlePageClick = this.handlePageClick.bind(this)
   }
 
   componentDidMount() {
@@ -131,7 +143,7 @@ class Dropdown extends React.Component {
     window.removeEventListener('mousedown', this.handlePageClick, false)
   }
 
-  getLabel(item) {
+  getLabel(item: any) {
     let labelField = this.props.labelField || 'label'
 
     if (item === null || item === undefined) {
@@ -141,33 +153,6 @@ class Dropdown extends React.Component {
     return (item[labelField] !== null && item[labelField] !== undefined && item[labelField].toString()) || item.toString()
   }
 
-  updateListPosition() {
-    if (!this.state.showDropdownList || !this.listRef || !this.buttonRef) {
-      return
-    }
-
-    let buttonHeight = this.buttonRef.offsetHeight
-    let tipHeight = 8
-    let listTop = this.buttonRect.top + buttonHeight + tipHeight
-    let listHeight = this.listRef.offsetHeight
-
-    if (listTop + listHeight > window.innerHeight) {
-      listTop = window.innerHeight - listHeight - 10
-      this.tipRef.style.display = 'none'
-    } else {
-      this.tipRef.style.display = 'block'
-    }
-
-    // If a modal is opened, body scroll is removed and body top is set to replicate scroll position
-    let scrollOffset = 0
-    if (parseInt(document.body.style.top, 10) < 0) {
-      scrollOffset = -parseInt(document.body.style.top, 10)
-    }
-
-    this.listRef.style.top = `${listTop + (window.pageYOffset || scrollOffset)}px`
-    this.listRef.style.left = `${this.buttonRect.left}px`
-  }
-
   handlePageClick() {
     if (!this.itemMouseDown) {
       this.setState({ showDropdownList: false })
@@ -182,7 +167,7 @@ class Dropdown extends React.Component {
     this.setState({ showDropdownList: !this.state.showDropdownList })
   }
 
-  handleItemClick(item) {
+  handleItemClick(item: any) {
     this.setState({ showDropdownList: false, firstItemHover: false })
 
     if (this.props.onChange) {
@@ -190,23 +175,51 @@ class Dropdown extends React.Component {
     }
   }
 
-  handleItemMouseEnter(index) {
+  handleItemMouseEnter(index: number) {
     if (index === 0) {
       this.setState({ firstItemHover: true })
     }
   }
 
-  handleItemMouseLeave(index) {
+  handleItemMouseLeave(index: number) {
     if (index === 0) {
       this.setState({ firstItemHover: false })
     }
   }
 
+  updateListPosition() {
+    if (!this.state.showDropdownList || !this.listRef || !this.buttonRef || !document.body) {
+      return
+    }
+
+    let buttonHeight = this.buttonRef.offsetHeight
+    let tipHeight = 8
+    let listTop = this.buttonRect.top + buttonHeight + tipHeight
+    let listHeight = this.listRef.offsetHeight
+
+    if (listTop + listHeight > window.innerHeight) {
+      listTop = window.innerHeight - listHeight - 10
+      this.tipRef.style.display = 'none'
+    } else {
+      this.tipRef.style.display = 'block'
+    }
+
+    // If a modal is opened, body scroll is removed and body top is set to replicate scroll position
+    let scrollOffset = 0
+    if (parseInt(document.body.style.top, 10) < 0) {
+      scrollOffset = -parseInt(document.body && document.body.style.top, 10)
+    }
+
+    this.listRef.style.top = `${listTop + (window.pageYOffset || scrollOffset)}px`
+    this.listRef.style.left = `${this.buttonRect.left}px`
+  }
+
   renderList() {
     if (!this.props.items || this.props.items.length === 0 || !this.state.showDropdownList) {
       return null
     }
 
+    const body: any = document.body
     let selectedLabel = this.getLabel(this.props.selectedItem)
     let list = ReactDOM.createPortal((
       <List {...this.props} innerRef={ref => { this.listRef = ref }}>
@@ -231,7 +244,7 @@ class Dropdown extends React.Component {
           })}
         </ListItems>
       </List>
-    ), document.body)
+    ), body)
 
     return list
   }

+ 1 - 1
src/components/molecules/Dropdown/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import Dropdown from './Dropdown'
+import Dropdown from '.'
 
 const items = [
   { label: 'Item 1', value: 'item-1' },

+ 1 - 1
src/components/molecules/Dropdown/test.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { shallow } from 'enzyme'
 // import sinon from 'sinon'
-import Dropdown from './Dropdown'
+import Dropdown from '.'
 
 const wrap = props => shallow(<Dropdown {...props} />)
 const items = [

+ 20 - 10
src/components/molecules/DropdownLink/DropdownLink.jsx → src/components/molecules/DropdownLink/index.jsx

@@ -12,9 +12,10 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
 import Palette from '../../styleUtils/Palette'
 
@@ -87,12 +88,18 @@ const Arrow = styled.div`
   margin-top: -1px;
 `
 
-class DropdownLink extends React.Component {
-  static propTypes = {
-    selectedItem: PropTypes.string.isRequired,
-    items: PropTypes.array.isRequired,
-    onChange: PropTypes.func.isRequired,
-  }
+type ItemType = {
+  label: string,
+  value: string
+}
+type Props = {
+  selectedItem: string,
+  items: ItemType[],
+  onChange: (item: ItemType) => void
+}
+type State = {showDropdownList: boolean}
+class DropdownLink extends React.Component<Props, State> {
+  itemMouseDown: boolean
 
   constructor() {
     super()
@@ -101,7 +108,8 @@ class DropdownLink extends React.Component {
       showDropdownList: false,
     }
 
-    this.handlePageClick = this.handlePageClick.bind(this)
+    const self: any = this
+    self.handlePageClick = this.handlePageClick.bind(this)
   }
 
   componentDidMount() {
@@ -122,7 +130,7 @@ class DropdownLink extends React.Component {
     this.setState({ showDropdownList: !this.state.showDropdownList })
   }
 
-  handleItemClick(item) {
+  handleItemClick(item: ItemType) {
     this.setState({ showDropdownList: false })
 
     if (this.props.onChange) {
@@ -158,6 +166,8 @@ class DropdownLink extends React.Component {
   }
 
   render() {
+    let selectedItem = this.props.items.find(i => i.value === this.props.selectedItem)
+
     return (
       <Wrapper>
         <LinkButton
@@ -165,7 +175,7 @@ class DropdownLink extends React.Component {
           onMouseUp={() => { this.itemMouseDown = false }}
           onClick={() => this.handleButtonClick()}
         >
-          <Label>{this.props.items.find(i => i.value === this.props.selectedItem).label}</Label>
+          <Label>{selectedItem ? selectedItem.label : ''}</Label>
           <Arrow />
         </LinkButton>
         {this.renderList()}

+ 1 - 1
src/components/molecules/DropdownLink/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import DropdownLink from './DropdownLink'
+import DropdownLink from '.'
 
 class Wrapper extends React.Component {
   constructor() {

+ 1 - 1
src/components/molecules/DropdownLink/test.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { shallow } from 'enzyme'
 import sinon from 'sinon'
-import DropdownLink from './DropdownLink'
+import DropdownLink from '.'
 
 const wrap = props => shallow(<DropdownLink {...props} />)
 

+ 23 - 25
src/components/molecules/EndpointField/EndpointField.jsx → src/components/molecules/EndpointField/index.jsx

@@ -12,17 +12,16 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
-import {
-  Switch,
-  TextInput,
-  Dropdown,
-  RadioInput,
-  InfoIcon,
-} from 'components'
+import Switch from '../../atoms/Switch'
+import TextInput from '../../atoms/TextInput'
+import RadioInput from '../../atoms/RadioInput'
+import InfoIcon from '../../atoms/InfoIcon'
+import Dropdown from '../../molecules/Dropdown'
 
 import LabelDictionary from '../../../utils/LabelDictionary'
 import StyleProps from '../../styleUtils/StyleProps'
@@ -40,23 +39,22 @@ const LabelText = styled.span`
   margin-right: 24px;
 `
 
-class Field extends React.Component {
-  static propTypes = {
-    name: PropTypes.string,
-    type: PropTypes.string,
-    value: PropTypes.any,
-    onChange: PropTypes.func,
-    className: PropTypes.string,
-    minimum: PropTypes.number,
-    maximum: PropTypes.number,
-    password: PropTypes.bool,
-    required: PropTypes.bool,
-    large: PropTypes.bool,
-    highlight: PropTypes.bool,
-    disabled: PropTypes.bool,
-    enum: PropTypes.array,
-  }
-
+type Props = {
+  name: string,
+  type: string,
+  value: any,
+  onChange: (value: any) => void,
+  className: string,
+  minimum: number,
+  maximum: number,
+  password: boolean,
+  required: boolean,
+  large: boolean,
+  highlight: boolean,
+  disabled: boolean,
+  enum: string[],
+}
+class Field extends React.Component<Props> {
   renderSwitch() {
     return (
       <Switch

+ 1 - 1
src/components/molecules/EndpointField/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import EndpointField from './EndpointField'
+import EndpointField from '.'
 
 class Wrapper extends React.Component {
   constructor() {

+ 1 - 1
src/components/molecules/EndpointField/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import EndpointField from './EndpointField'
+import EndpointField from '.'
 
 const wrap = props => shallow(<EndpointField {...props} />)
 

+ 13 - 11
src/components/molecules/EndpointListItem/EndpointListItem.jsx → src/components/molecules/EndpointListItem/index.jsx

@@ -12,11 +12,14 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+// @flow
+
 import React from 'react'
-import PropTypes from 'prop-types'
 import styled from 'styled-components'
 
-import { Checkbox, EndpointLogos } from 'components'
+import type { Endpoint } from '../../../types/Endpoint'
+import Checkbox from '../../atoms/Checkbox'
+import EndpointLogos from '../../atoms/EndpointLogos'
 import Palette from '../../styleUtils/Palette'
 import StyleProps from '../../styleUtils/StyleProps'
 import DateUtils from '../../../utils/DateUtils'
@@ -89,15 +92,14 @@ const Created = styled.div`
 const Usage = styled.div`
   min-width: 244px;
 `
-class EndpointListItem extends React.Component {
-  static propTypes = {
-    item: PropTypes.object.isRequired,
-    onClick: PropTypes.func,
-    selected: PropTypes.bool,
-    onSelectedChange: PropTypes.func,
-    getUsage: PropTypes.func.isRequired,
-  }
-
+type Props = {
+  item: Endpoint,
+  onClick: () => void,
+  selected: boolean,
+  onSelectedChange: (value: boolean) => void,
+  getUsage: (item: Endpoint) => { replicasCount: number, migrationsCount: number },
+}
+class EndpointListItem extends React.Component<Props> {
   render() {
     return (
       <Wrapper>

+ 1 - 1
src/components/molecules/EndpointListItem/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import EndpointListItem from './EndpointListItem'
+import EndpointListItem from '.'
 
 storiesOf('EnpointListItem', module)
   .add('openstack', () => (

+ 1 - 1
src/components/molecules/EndpointListItem/test.jsx

@@ -15,7 +15,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 import React from 'react'
 import { shallow } from 'enzyme'
 import sinon from 'sinon'
-import EndpointListItem from './EndpointListItem'
+import EndpointListItem from '.'
 
 const wrap = props => shallow(<EndpointListItem {...props} />)
 

+ 9 - 9
src/components/molecules/LoadingButton/LoadingButton.jsx → src/components/molecules/LoadingButton/index.jsx

@@ -12,18 +12,19 @@ You should have received a copy of the GNU Affero General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
-import React from 'react'
+// @flow
+
+import * as React from 'react'
 import styled from 'styled-components'
-import PropTypes from 'prop-types'
 
-import { Button } from 'components'
+import Button from '../../atoms/Button'
 
 import StyleProps from '../../styleUtils/StyleProps'
 
 import loadingImage from './images/loading.svg'
 
 const ButtonStyled = styled(Button)`
-  position: relative
+  position: relative;
 `
 const Loading = styled.span`
   position: absolute;
@@ -35,11 +36,10 @@ const Loading = styled.span`
   ${StyleProps.animations.rotation}
 `
 
-class LoadingButton extends React.Component {
-  static propTypes = {
-    children: PropTypes.node,
-  }
-
+type Props = {
+  children: React.Node,
+}
+class LoadingButton extends React.Component<Props> {
   render() {
     return (
       <ButtonStyled {...this.props} disabled>

+ 1 - 1
src/components/molecules/LoadingButton/story.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { storiesOf } from '@storybook/react'
-import LoadingButton from './LoadingButton'
+import LoadingButton from '.'
 
 storiesOf('LoadingButton', module)
   .add('default', () => (

+ 1 - 1
src/components/molecules/LoadingButton/test.jsx

@@ -14,7 +14,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import React from 'react'
 import { shallow } from 'enzyme'
-import LoadingButton from './LoadingButton'
+import LoadingButton from '.'
 
 it('renders disabled with given label', () => {
   let wrapper = shallow(<LoadingButton>Loading ...</LoadingButton>)

Some files were not shown because too many files changed in this diff