diff options
-rw-r--r-- | .eslintrc.js | 6 | ||||
-rw-r--r-- | src/components/AppUpdateInfoBar.tsx | 14 | ||||
-rw-r--r-- | src/components/auth/AuthLayout.tsx (renamed from src/components/auth/AuthLayout.jsx) | 61 | ||||
-rw-r--r-- | src/components/ui/AppLoader/index.tsx | 68 | ||||
-rw-r--r-- | src/components/ui/AppLoader/styles.ts | 9 | ||||
-rw-r--r-- | src/components/ui/InfoBar.tsx (renamed from src/components/ui/InfoBar.js) | 70 | ||||
-rw-r--r-- | src/components/ui/Modal/index.tsx | 36 | ||||
-rw-r--r-- | src/components/ui/headline/index.tsx | 15 | ||||
-rw-r--r-- | src/components/ui/icon/index.tsx | 10 | ||||
-rw-r--r-- | src/components/ui/input/index.tsx | 59 | ||||
-rw-r--r-- | src/containers/auth/AuthLayoutContainer.tsx | 10 | ||||
-rw-r--r-- | src/features/publishDebugInfo/Component.tsx (renamed from src/features/publishDebugInfo/Component.js) | 95 | ||||
-rw-r--r-- | src/features/publishDebugInfo/index.ts | 14 | ||||
-rw-r--r-- | src/routes.tsx | 30 |
14 files changed, 222 insertions, 275 deletions
diff --git a/.eslintrc.js b/.eslintrc.js index bbf0e6022..fd4ff7516 100644 --- a/.eslintrc.js +++ b/.eslintrc.js | |||
@@ -70,14 +70,16 @@ module.exports = { | |||
70 | 'import/no-unresolved': 0, | 70 | 'import/no-unresolved': 0, |
71 | 'import/prefer-default-export': 0, | 71 | 'import/prefer-default-export': 0, |
72 | // eslint-plugin-react | 72 | // eslint-plugin-react |
73 | 'react/default-props-match-prop-types': 1, | 73 | // TODO - [TS DEBT] should remove below config once application converted to TS |
74 | 'react/default-props-match-prop-types': 0, | ||
75 | 'react/require-default-props': 0, | ||
76 | // eslint-plugin-react | ||
74 | 'react/destructuring-assignment': 0, | 77 | 'react/destructuring-assignment': 0, |
75 | 'react/button-has-type': 0, | 78 | 'react/button-has-type': 0, |
76 | 'react/forbid-prop-types': 0, | 79 | 'react/forbid-prop-types': 0, |
77 | 'react/jsx-curly-newline': 0, | 80 | 'react/jsx-curly-newline': 0, |
78 | 'react/no-unused-prop-types': 1, | 81 | 'react/no-unused-prop-types': 1, |
79 | 'react/react-in-jsx-scope': 0, | 82 | 'react/react-in-jsx-scope': 0, |
80 | 'react/require-default-props': 1, | ||
81 | 'react/jsx-no-bind': 0, | 83 | 'react/jsx-no-bind': 0, |
82 | 'react/jsx-no-target-blank': 0, | 84 | 'react/jsx-no-target-blank': 0, |
83 | 'react/jsx-props-no-spreading': 0, | 85 | 'react/jsx-props-no-spreading': 0, |
diff --git a/src/components/AppUpdateInfoBar.tsx b/src/components/AppUpdateInfoBar.tsx index 3ff488b74..ff4a9b9ad 100644 --- a/src/components/AppUpdateInfoBar.tsx +++ b/src/components/AppUpdateInfoBar.tsx | |||
@@ -1,6 +1,7 @@ | |||
1 | import { defineMessages, useIntl } from 'react-intl'; | 1 | import { defineMessages, useIntl } from 'react-intl'; |
2 | 2 | ||
3 | import { mdiInformation } from '@mdi/js'; | 3 | import { mdiInformation } from '@mdi/js'; |
4 | import { MouseEventHandler } from 'react'; | ||
4 | import InfoBar from './ui/InfoBar'; | 5 | import InfoBar from './ui/InfoBar'; |
5 | import Icon from './ui/icon'; | 6 | import Icon from './ui/icon'; |
6 | 7 | ||
@@ -21,17 +22,14 @@ const messages = defineMessages({ | |||
21 | }, | 22 | }, |
22 | }); | 23 | }); |
23 | 24 | ||
24 | type Props = { | 25 | export interface IProps { |
25 | onInstallUpdate: () => void; | 26 | onInstallUpdate: MouseEventHandler<HTMLButtonElement>; |
26 | onHide: () => void; | 27 | onHide: () => void; |
27 | updateVersionParsed: string; | 28 | updateVersionParsed: string; |
28 | }; | 29 | } |
29 | 30 | ||
30 | const AppUpdateInfoBar = ({ | 31 | const AppUpdateInfoBar = (props: IProps) => { |
31 | onInstallUpdate, | 32 | const { onInstallUpdate, updateVersionParsed, onHide } = props; |
32 | updateVersionParsed, | ||
33 | onHide, | ||
34 | }: Props) => { | ||
35 | const intl = useIntl(); | 33 | const intl = useIntl(); |
36 | 34 | ||
37 | return ( | 35 | return ( |
diff --git a/src/components/auth/AuthLayout.jsx b/src/components/auth/AuthLayout.tsx index 5c87c3080..527c2bb74 100644 --- a/src/components/auth/AuthLayout.jsx +++ b/src/components/auth/AuthLayout.tsx | |||
@@ -1,52 +1,53 @@ | |||
1 | import { cloneElement, Component } from 'react'; | 1 | import { |
2 | import PropTypes from 'prop-types'; | 2 | cloneElement, |
3 | Component, | ||
4 | MouseEventHandler, | ||
5 | ReactElement, | ||
6 | } from 'react'; | ||
3 | import { observer } from 'mobx-react'; | 7 | import { observer } from 'mobx-react'; |
4 | import { TitleBar } from 'electron-react-titlebar/renderer'; | 8 | import { TitleBar } from 'electron-react-titlebar/renderer'; |
5 | 9 | import { injectIntl, WrappedComponentProps } from 'react-intl'; | |
6 | import { injectIntl } from 'react-intl'; | ||
7 | import { mdiFlash } from '@mdi/js'; | 10 | import { mdiFlash } from '@mdi/js'; |
11 | import { GlobalError } from '../../@types/ferdium-components.types'; | ||
8 | import Link from '../ui/Link'; | 12 | import Link from '../ui/Link'; |
9 | import InfoBar from '../ui/InfoBar'; | 13 | import InfoBar from '../ui/InfoBar'; |
10 | |||
11 | import { Component as PublishDebugInfo } from '../../features/publishDebugInfo'; | 14 | import { Component as PublishDebugInfo } from '../../features/publishDebugInfo'; |
12 | |||
13 | import { | ||
14 | oneOrManyChildElements, | ||
15 | globalError as globalErrorPropType, | ||
16 | } from '../../prop-types'; | ||
17 | import { updateVersionParse } from '../../helpers/update-helpers'; | 15 | import { updateVersionParse } from '../../helpers/update-helpers'; |
18 | import globalMessages from '../../i18n/globalMessages'; | 16 | import globalMessages from '../../i18n/globalMessages'; |
19 | |||
20 | import { isWindows } from '../../environment'; | 17 | import { isWindows } from '../../environment'; |
21 | import AppUpdateInfoBar from '../AppUpdateInfoBar'; | 18 | import AppUpdateInfoBar from '../AppUpdateInfoBar'; |
22 | import { GITHUB_FERDIUM_URL } from '../../config'; | 19 | import { GITHUB_FERDIUM_URL } from '../../config'; |
23 | import Icon from '../ui/icon'; | 20 | import Icon from '../ui/icon'; |
24 | |||
25 | import { serverName } from '../../api/apiBase'; | 21 | import { serverName } from '../../api/apiBase'; |
26 | 22 | ||
27 | class AuthLayout extends Component { | 23 | export interface IProps extends WrappedComponentProps { |
28 | static propTypes = { | 24 | children: ReactElement; |
29 | children: oneOrManyChildElements.isRequired, | 25 | error: GlobalError; |
30 | error: globalErrorPropType.isRequired, | 26 | isOnline: boolean; |
31 | isOnline: PropTypes.bool.isRequired, | 27 | isAPIHealthy: boolean; |
32 | isAPIHealthy: PropTypes.bool.isRequired, | 28 | retryHealthCheck: MouseEventHandler<HTMLButtonElement>; |
33 | retryHealthCheck: PropTypes.func.isRequired, | 29 | isHealthCheckLoading: boolean; |
34 | isHealthCheckLoading: PropTypes.bool.isRequired, | 30 | isFullScreen: boolean; |
35 | isFullScreen: PropTypes.bool.isRequired, | 31 | installAppUpdate: MouseEventHandler<HTMLButtonElement>; |
36 | installAppUpdate: PropTypes.func.isRequired, | 32 | appUpdateIsDownloaded: boolean; |
37 | appUpdateIsDownloaded: PropTypes.bool.isRequired, | 33 | updateVersion: string; |
38 | updateVersion: PropTypes.string.isRequired, | 34 | } |
39 | }; | 35 | |
36 | interface IState { | ||
37 | shouldShowAppUpdateInfoBar: boolean; | ||
38 | } | ||
40 | 39 | ||
41 | constructor() { | 40 | @observer |
42 | super(); | 41 | class AuthLayout extends Component<IProps, IState> { |
42 | constructor(props: IProps) { | ||
43 | super(props); | ||
43 | 44 | ||
44 | this.state = { | 45 | this.state = { |
45 | shouldShowAppUpdateInfoBar: true, | 46 | shouldShowAppUpdateInfoBar: true, |
46 | }; | 47 | }; |
47 | } | 48 | } |
48 | 49 | ||
49 | render() { | 50 | render(): ReactElement { |
50 | const { | 51 | const { |
51 | children, | 52 | children, |
52 | error, | 53 | error, |
@@ -58,9 +59,9 @@ class AuthLayout extends Component { | |||
58 | installAppUpdate, | 59 | installAppUpdate, |
59 | appUpdateIsDownloaded, | 60 | appUpdateIsDownloaded, |
60 | updateVersion, | 61 | updateVersion, |
62 | intl, | ||
61 | } = this.props; | 63 | } = this.props; |
62 | 64 | ||
63 | const { intl } = this.props; | ||
64 | let serverNameParse = serverName(); | 65 | let serverNameParse = serverName(); |
65 | serverNameParse = | 66 | serverNameParse = |
66 | serverNameParse === 'Custom' ? 'your Custom Server' : serverNameParse; | 67 | serverNameParse === 'Custom' ? 'your Custom Server' : serverNameParse; |
@@ -124,4 +125,4 @@ class AuthLayout extends Component { | |||
124 | } | 125 | } |
125 | } | 126 | } |
126 | 127 | ||
127 | export default injectIntl(observer(AuthLayout)); | 128 | export default injectIntl(AuthLayout); |
diff --git a/src/components/ui/AppLoader/index.tsx b/src/components/ui/AppLoader/index.tsx index caa7e381d..f4d9b8e73 100644 --- a/src/components/ui/AppLoader/index.tsx +++ b/src/components/ui/AppLoader/index.tsx | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Component } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import classnames from 'classnames'; | 2 | import classnames from 'classnames'; |
3 | 3 | import withStyles, { WithStylesProps } from 'react-jss'; | |
4 | import injectStyle from 'react-jss'; | 4 | import { Theme } from '../../../themes'; |
5 | import FullscreenLoader from '../FullscreenLoader'; | 5 | import FullscreenLoader from '../FullscreenLoader'; |
6 | import shuffleArray from '../../../helpers/array-helpers'; | 6 | import shuffleArray from '../../../helpers/array-helpers'; |
7 | 7 | ||
@@ -18,24 +18,27 @@ const textList = shuffleArray([ | |||
18 | 'Fixing bugs', | 18 | 'Fixing bugs', |
19 | ]); | 19 | ]); |
20 | 20 | ||
21 | type Props = { | 21 | interface IProps extends WithStylesProps<typeof styles> { |
22 | classes: typeof styles; | 22 | theme: Theme; |
23 | theme: any; | 23 | texts?: string[]; |
24 | texts: string[]; | 24 | } |
25 | }; | ||
26 | |||
27 | class AppLoader extends Component<Props> { | ||
28 | static defaultProps = { | ||
29 | texts: textList, | ||
30 | }; | ||
31 | 25 | ||
32 | state = { | 26 | interface IState { |
33 | step: 0, | 27 | step: number; |
34 | }; | 28 | } |
35 | 29 | ||
30 | class AppLoader extends Component<IProps, IState> { | ||
36 | interval: NodeJS.Timeout | null = null; | 31 | interval: NodeJS.Timeout | null = null; |
37 | 32 | ||
38 | componentDidMount() { | 33 | constructor(props: IProps) { |
34 | super(props); | ||
35 | |||
36 | this.state = { | ||
37 | step: 0, | ||
38 | }; | ||
39 | } | ||
40 | |||
41 | componentDidMount(): void { | ||
39 | this.interval = setInterval(() => { | 42 | this.interval = setInterval(() => { |
40 | this.setState((prevState: { step: number }) => ({ | 43 | this.setState((prevState: { step: number }) => ({ |
41 | step: prevState.step === textList.length - 1 ? 0 : prevState.step + 1, | 44 | step: prevState.step === textList.length - 1 ? 0 : prevState.step + 1, |
@@ -43,14 +46,14 @@ class AppLoader extends Component<Props> { | |||
43 | }, 2500); | 46 | }, 2500); |
44 | } | 47 | } |
45 | 48 | ||
46 | componentWillUnmount() { | 49 | componentWillUnmount(): void { |
47 | if (this.interval) { | 50 | if (this.interval) { |
48 | clearInterval(this.interval); | 51 | clearInterval(this.interval); |
49 | } | 52 | } |
50 | } | 53 | } |
51 | 54 | ||
52 | render() { | 55 | render(): ReactElement { |
53 | const { classes, theme, texts } = this.props; | 56 | const { classes, theme, texts = textList } = this.props; |
54 | const { step } = this.state; | 57 | const { step } = this.state; |
55 | 58 | ||
56 | return ( | 59 | return ( |
@@ -58,20 +61,21 @@ class AppLoader extends Component<Props> { | |||
58 | className={classes.component} | 61 | className={classes.component} |
59 | spinnerColor={theme.colorAppLoaderSpinner} | 62 | spinnerColor={theme.colorAppLoaderSpinner} |
60 | > | 63 | > |
61 | {texts.map((text, i) => ( | 64 | {texts && |
62 | <span | 65 | texts.map((text, i) => ( |
63 | key={text} | 66 | <span |
64 | className={classnames({ | 67 | key={text} |
65 | [`${classes.slogan}`]: true, | 68 | className={classnames({ |
66 | [`${classes.visible}`]: step === i, | 69 | [`${classes.slogan}`]: true, |
67 | })} | 70 | [`${classes.visible}`]: step === i, |
68 | > | 71 | })} |
69 | {text} | 72 | > |
70 | </span> | 73 | {text} |
71 | ))} | 74 | </span> |
75 | ))} | ||
72 | </FullscreenLoader> | 76 | </FullscreenLoader> |
73 | ); | 77 | ); |
74 | } | 78 | } |
75 | } | 79 | } |
76 | 80 | ||
77 | export default injectStyle(styles, { injectTheme: true })(AppLoader); | 81 | export default withStyles(styles, { injectTheme: true })(AppLoader); |
diff --git a/src/components/ui/AppLoader/styles.ts b/src/components/ui/AppLoader/styles.ts index 9891e0387..6bf3b4f3c 100644 --- a/src/components/ui/AppLoader/styles.ts +++ b/src/components/ui/AppLoader/styles.ts | |||
@@ -1,8 +1,7 @@ | |||
1 | let sloganTransition = 'none'; | 1 | const sloganTransition = |
2 | 2 | window && window.matchMedia('(prefers-reduced-motion: no-preference)') | |
3 | if (window && window.matchMedia('(prefers-reduced-motion: no-preference)')) { | 3 | ? 'opacity 1s ease' |
4 | sloganTransition = 'opacity 1s ease'; | 4 | : 'none'; |
5 | } | ||
6 | 5 | ||
7 | export default { | 6 | export default { |
8 | component: { | 7 | component: { |
diff --git a/src/components/ui/InfoBar.js b/src/components/ui/InfoBar.tsx index d73491da0..ef8f6ad6f 100644 --- a/src/components/ui/InfoBar.js +++ b/src/components/ui/InfoBar.tsx | |||
@@ -1,11 +1,11 @@ | |||
1 | import { Component } from 'react'; | 1 | import { Component, MouseEventHandler, ReactNode } from 'react'; |
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | 2 | import { observer } from 'mobx-react'; |
4 | import classnames from 'classnames'; | 3 | import classnames from 'classnames'; |
5 | import Loader from 'react-loader'; | 4 | import Loader from 'react-loader'; |
6 | import { defineMessages, injectIntl } from 'react-intl'; | 5 | import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl'; |
7 | 6 | ||
8 | import { mdiClose } from '@mdi/js'; | 7 | import { mdiClose } from '@mdi/js'; |
8 | import { noop } from 'lodash'; | ||
9 | import Appear from './effects/Appear'; | 9 | import Appear from './effects/Appear'; |
10 | import Icon from './icon'; | 10 | import Icon from './icon'; |
11 | 11 | ||
@@ -16,51 +16,35 @@ const messages = defineMessages({ | |||
16 | }, | 16 | }, |
17 | }); | 17 | }); |
18 | 18 | ||
19 | // Should this file be converted into the coding style similar to './toggle/index.tsx'? | 19 | interface IProps extends WrappedComponentProps { |
20 | class InfoBar extends Component { | 20 | children: ReactNode; |
21 | static propTypes = { | 21 | onClick?: MouseEventHandler<HTMLButtonElement>; |
22 | // eslint-disable-next-line react/forbid-prop-types | 22 | type?: string; |
23 | children: PropTypes.any.isRequired, | 23 | className?: string; |
24 | onClick: PropTypes.func, | 24 | ctaLabel?: string; |
25 | type: PropTypes.string, | 25 | ctaLoading?: boolean; |
26 | className: PropTypes.string, | 26 | position?: string; |
27 | ctaLabel: PropTypes.string, | 27 | sticky?: boolean; |
28 | ctaLoading: PropTypes.bool, | 28 | onHide?: () => void; |
29 | position: PropTypes.string, | 29 | } |
30 | sticky: PropTypes.bool, | ||
31 | onHide: PropTypes.func, | ||
32 | }; | ||
33 | |||
34 | static defaultProps = { | ||
35 | onClick: () => null, | ||
36 | type: 'primary', | ||
37 | className: '', | ||
38 | ctaLabel: '', | ||
39 | ctaLoading: false, | ||
40 | position: 'bottom', | ||
41 | sticky: false, | ||
42 | onHide: () => null, | ||
43 | }; | ||
44 | 30 | ||
31 | @observer | ||
32 | class InfoBar extends Component<IProps> { | ||
45 | render() { | 33 | render() { |
46 | const { | 34 | const { |
47 | children, | 35 | children, |
48 | type, | 36 | type = 'primary', |
49 | className, | 37 | onClick = noop, |
50 | ctaLabel, | 38 | className = '', |
51 | ctaLoading, | 39 | ctaLabel = '', |
52 | onClick, | 40 | ctaLoading = false, |
53 | position, | 41 | position = 'bottom', |
54 | sticky, | 42 | sticky = false, |
55 | onHide, | 43 | onHide = noop, |
44 | intl, | ||
56 | } = this.props; | 45 | } = this.props; |
57 | 46 | ||
58 | const { intl } = this.props; | 47 | const transitionName = position === 'top' ? 'slideDown' : 'slideUp'; |
59 | |||
60 | let transitionName = 'slideUp'; | ||
61 | if (position === 'top') { | ||
62 | transitionName = 'slideDown'; | ||
63 | } | ||
64 | 48 | ||
65 | return ( | 49 | return ( |
66 | <Appear | 50 | <Appear |
@@ -102,4 +86,4 @@ class InfoBar extends Component { | |||
102 | } | 86 | } |
103 | } | 87 | } |
104 | 88 | ||
105 | export default injectIntl(observer(InfoBar)); | 89 | export default injectIntl(InfoBar); |
diff --git a/src/components/ui/Modal/index.tsx b/src/components/ui/Modal/index.tsx index 7407a686d..154beef0c 100644 --- a/src/components/ui/Modal/index.tsx +++ b/src/components/ui/Modal/index.tsx | |||
@@ -1,41 +1,33 @@ | |||
1 | import { Component, ReactChildren } from 'react'; | 1 | import { Component, ReactNode } from 'react'; |
2 | import ReactModal from 'react-modal'; | 2 | import ReactModal from 'react-modal'; |
3 | import classnames from 'classnames'; | 3 | import classnames from 'classnames'; |
4 | import injectCSS from 'react-jss'; | 4 | import injectCSS, { WithStylesProps } from 'react-jss'; |
5 | import { mdiClose } from '@mdi/js'; | 5 | import { mdiClose } from '@mdi/js'; |
6 | 6 | ||
7 | import Icon from '../icon'; | 7 | import Icon from '../icon'; |
8 | import styles from './styles'; | 8 | import styles from './styles'; |
9 | 9 | ||
10 | type Props = { | 10 | interface IProps extends WithStylesProps<typeof styles> { |
11 | children: ReactChildren; | 11 | children: ReactNode; |
12 | className: string; | ||
13 | classes: any; | ||
14 | isOpen: boolean; | 12 | isOpen: boolean; |
15 | portal: string; | ||
16 | close: () => void; | 13 | close: () => void; |
17 | shouldCloseOnOverlayClick: boolean; | 14 | className?: string | null; |
18 | showClose: boolean; | 15 | portal?: string; |
19 | }; | 16 | shouldCloseOnOverlayClick?: boolean; |
20 | 17 | showClose?: boolean; | |
21 | class Modal extends Component<Props> { | 18 | } |
22 | static defaultProps = { | ||
23 | className: null, | ||
24 | portal: 'modal-portal', | ||
25 | shouldCloseOnOverlayClick: false, | ||
26 | showClose: true, | ||
27 | }; | ||
28 | 19 | ||
20 | class Modal extends Component<IProps> { | ||
29 | render() { | 21 | render() { |
30 | const { | 22 | const { |
31 | children, | 23 | children, |
32 | className, | ||
33 | classes, | 24 | classes, |
34 | isOpen, | 25 | isOpen, |
35 | portal, | ||
36 | close, | 26 | close, |
37 | shouldCloseOnOverlayClick, | 27 | className = null, |
38 | showClose, | 28 | portal = 'modal-portal', |
29 | shouldCloseOnOverlayClick = false, | ||
30 | showClose = true, | ||
39 | } = this.props; | 31 | } = this.props; |
40 | 32 | ||
41 | return ( | 33 | return ( |
diff --git a/src/components/ui/headline/index.tsx b/src/components/ui/headline/index.tsx index b5a5f695f..bebd8adcf 100644 --- a/src/components/ui/headline/index.tsx +++ b/src/components/ui/headline/index.tsx | |||
@@ -1,16 +1,22 @@ | |||
1 | import classnames from 'classnames'; | 1 | import classnames from 'classnames'; |
2 | import { Component, createElement, ReactNode } from 'react'; | 2 | import { |
3 | Component, | ||
4 | createElement, | ||
5 | MouseEventHandler, | ||
6 | ReactElement, | ||
7 | ReactNode, | ||
8 | } from 'react'; | ||
3 | import injectStyle, { WithStylesProps } from 'react-jss'; | 9 | import injectStyle, { WithStylesProps } from 'react-jss'; |
4 | 10 | ||
5 | import { Theme } from '../../../themes'; | 11 | import { Theme } from '../../../themes'; |
6 | import { Omit } from '../typings/generic'; | 12 | import { Omit } from '../typings/generic'; |
7 | 13 | ||
8 | interface IProps extends WithStylesProps<typeof styles> { | 14 | interface IProps extends WithStylesProps<typeof styles> { |
15 | children: ReactNode; | ||
9 | level?: number; | 16 | level?: number; |
10 | className?: string; | 17 | className?: string; |
11 | children: string | ReactNode; | ||
12 | id?: string; | 18 | id?: string; |
13 | onClick?: () => void; | 19 | onClick?: MouseEventHandler<HTMLButtonElement>; |
14 | } | 20 | } |
15 | 21 | ||
16 | const styles = (theme: Theme) => ({ | 22 | const styles = (theme: Theme) => ({ |
@@ -40,7 +46,7 @@ const styles = (theme: Theme) => ({ | |||
40 | }); | 46 | }); |
41 | 47 | ||
42 | class HeadlineComponent extends Component<IProps> { | 48 | class HeadlineComponent extends Component<IProps> { |
43 | render() { | 49 | render(): ReactElement { |
44 | const { classes, level, className, children, id, onClick } = this.props; | 50 | const { classes, level, className, children, id, onClick } = this.props; |
45 | 51 | ||
46 | return createElement( | 52 | return createElement( |
@@ -61,7 +67,6 @@ class HeadlineComponent extends Component<IProps> { | |||
61 | } | 67 | } |
62 | 68 | ||
63 | const Headline = injectStyle(styles, { injectTheme: true })(HeadlineComponent); | 69 | const Headline = injectStyle(styles, { injectTheme: true })(HeadlineComponent); |
64 | |||
65 | const createH = (level: number) => (props: Omit<IProps, 'classes'>) => | 70 | const createH = (level: number) => (props: Omit<IProps, 'classes'>) => |
66 | ( | 71 | ( |
67 | <Headline level={level} {...props}> | 72 | <Headline level={level} {...props}> |
diff --git a/src/components/ui/icon/index.tsx b/src/components/ui/icon/index.tsx index 7e13b98c7..5b432a194 100644 --- a/src/components/ui/icon/index.tsx +++ b/src/components/ui/icon/index.tsx | |||
@@ -1,6 +1,6 @@ | |||
1 | import MdiIcon from '@mdi/react'; | 1 | import MdiIcon from '@mdi/react'; |
2 | import classnames from 'classnames'; | 2 | import classnames from 'classnames'; |
3 | import { Component } from 'react'; | 3 | import { Component, ReactElement } from 'react'; |
4 | import injectStyle, { WithStylesProps } from 'react-jss'; | 4 | import injectStyle, { WithStylesProps } from 'react-jss'; |
5 | 5 | ||
6 | import { Theme } from '../../../themes'; | 6 | import { Theme } from '../../../themes'; |
@@ -18,12 +18,8 @@ const styles = (theme: Theme) => ({ | |||
18 | }); | 18 | }); |
19 | 19 | ||
20 | class IconComponent extends Component<IProps> { | 20 | class IconComponent extends Component<IProps> { |
21 | public static defaultProps = { | 21 | render(): ReactElement { |
22 | size: 1, | 22 | const { classes, icon, size = 1, className } = this.props; |
23 | }; | ||
24 | |||
25 | render() { | ||
26 | const { classes, icon, size, className } = this.props; | ||
27 | 23 | ||
28 | if (!icon) { | 24 | if (!icon) { |
29 | console.warn('No Icon specified'); | 25 | console.warn('No Icon specified'); |
diff --git a/src/components/ui/input/index.tsx b/src/components/ui/input/index.tsx index aa282cce0..b19bb4bc9 100644 --- a/src/components/ui/input/index.tsx +++ b/src/components/ui/input/index.tsx | |||
@@ -3,14 +3,12 @@ import Icon from '@mdi/react'; | |||
3 | import classnames from 'classnames'; | 3 | import classnames from 'classnames'; |
4 | import { Component, createRef, InputHTMLAttributes } from 'react'; | 4 | import { Component, createRef, InputHTMLAttributes } from 'react'; |
5 | import injectSheet, { WithStylesProps } from 'react-jss'; | 5 | import injectSheet, { WithStylesProps } from 'react-jss'; |
6 | 6 | import { noop } from 'lodash'; | |
7 | import { IFormField } from '../typings/generic'; | 7 | import { IFormField } from '../typings/generic'; |
8 | |||
9 | import Error from '../error'; | 8 | import Error from '../error'; |
10 | import Label from '../label'; | 9 | import Label from '../label'; |
11 | import Wrapper from '../wrapper'; | 10 | import Wrapper from '../wrapper'; |
12 | import { scorePasswordFunc } from './scorePassword'; | 11 | import { scorePasswordFunc } from './scorePassword'; |
13 | |||
14 | import styles from './styles'; | 12 | import styles from './styles'; |
15 | 13 | ||
16 | interface IData { | 14 | interface IData { |
@@ -26,7 +24,7 @@ interface IProps | |||
26 | suffix?: string; | 24 | suffix?: string; |
27 | scorePassword?: boolean; | 25 | scorePassword?: boolean; |
28 | showPasswordToggle?: boolean; | 26 | showPasswordToggle?: boolean; |
29 | data: IData; | 27 | data?: IData; |
30 | inputClassName?: string; | 28 | inputClassName?: string; |
31 | onEnterKey?: Function; | 29 | onEnterKey?: Function; |
32 | } | 30 | } |
@@ -37,42 +35,31 @@ interface IState { | |||
37 | } | 35 | } |
38 | 36 | ||
39 | class InputComponent extends Component<IProps, IState> { | 37 | class InputComponent extends Component<IProps, IState> { |
40 | static defaultProps = { | ||
41 | focus: false, | ||
42 | onChange: () => {}, | ||
43 | onBlur: () => {}, | ||
44 | onFocus: () => {}, | ||
45 | scorePassword: false, | ||
46 | showLabel: true, | ||
47 | showPasswordToggle: false, | ||
48 | type: 'text', | ||
49 | disabled: false, | ||
50 | }; | ||
51 | |||
52 | state = { | ||
53 | passwordScore: 0, | ||
54 | showPassword: false, | ||
55 | }; | ||
56 | |||
57 | private inputRef = createRef<HTMLInputElement>(); | 38 | private inputRef = createRef<HTMLInputElement>(); |
58 | 39 | ||
59 | componentDidMount() { | 40 | constructor(props: IProps) { |
60 | const { focus, data } = this.props; | 41 | super(props); |
42 | |||
43 | this.state = { | ||
44 | passwordScore: 0, | ||
45 | showPassword: false, | ||
46 | }; | ||
47 | } | ||
48 | |||
49 | componentDidMount(): void { | ||
50 | const { focus, data = {} } = this.props; | ||
61 | 51 | ||
62 | if (this.inputRef && this.inputRef.current) { | 52 | if (this.inputRef && this.inputRef.current) { |
63 | if (focus) { | 53 | if (focus) { |
64 | this.inputRef.current.focus(); | 54 | this.inputRef.current.focus(); |
65 | } | 55 | } |
66 | 56 | ||
67 | if (data) { | 57 | for (const key of Object.keys(data)) |
68 | Object.keys(data).map( | 58 | this.inputRef.current!.dataset[key] = data[key]; |
69 | key => (this.inputRef.current!.dataset[key] = data[key]), | ||
70 | ); | ||
71 | } | ||
72 | } | 59 | } |
73 | } | 60 | } |
74 | 61 | ||
75 | onChange(e: React.ChangeEvent<HTMLInputElement>) { | 62 | onChange(e: React.ChangeEvent<HTMLInputElement>): void { |
76 | const { scorePassword, onChange } = this.props; | 63 | const { scorePassword, onChange } = this.props; |
77 | 64 | ||
78 | if (onChange) { | 65 | if (onChange) { |
@@ -97,28 +84,28 @@ class InputComponent extends Component<IProps, IState> { | |||
97 | const { | 84 | const { |
98 | classes, | 85 | classes, |
99 | className, | 86 | className, |
100 | disabled, | ||
101 | error, | 87 | error, |
102 | id, | 88 | id, |
103 | inputClassName, | 89 | inputClassName, |
104 | label, | 90 | label, |
105 | prefix, | 91 | prefix, |
106 | scorePassword, | ||
107 | suffix, | 92 | suffix, |
108 | showLabel, | ||
109 | showPasswordToggle, | ||
110 | type, | ||
111 | value, | 93 | value, |
112 | name, | 94 | name, |
113 | placeholder, | 95 | placeholder, |
114 | spellCheck, | 96 | spellCheck, |
115 | onBlur, | ||
116 | onFocus, | ||
117 | min, | 97 | min, |
118 | max, | 98 | max, |
119 | step, | 99 | step, |
120 | required, | 100 | required, |
121 | noMargin, | 101 | noMargin, |
102 | onBlur = noop, | ||
103 | onFocus = noop, | ||
104 | scorePassword = false, | ||
105 | showLabel = true, | ||
106 | showPasswordToggle = false, | ||
107 | type = 'text', | ||
108 | disabled = false, | ||
122 | } = this.props; | 109 | } = this.props; |
123 | 110 | ||
124 | const { showPassword, passwordScore } = this.state; | 111 | const { showPassword, passwordScore } = this.state; |
diff --git a/src/containers/auth/AuthLayoutContainer.tsx b/src/containers/auth/AuthLayoutContainer.tsx index 6fc6713f1..6a1fed0d7 100644 --- a/src/containers/auth/AuthLayoutContainer.tsx +++ b/src/containers/auth/AuthLayoutContainer.tsx | |||
@@ -2,14 +2,15 @@ import { Component, ReactElement } from 'react'; | |||
2 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
3 | import { ThemeProvider } from 'react-jss'; | 3 | import { ThemeProvider } from 'react-jss'; |
4 | import { Outlet } from 'react-router-dom'; | 4 | import { Outlet } from 'react-router-dom'; |
5 | |||
6 | import { StoresProps } from '../../@types/ferdium-components.types'; | 5 | import { StoresProps } from '../../@types/ferdium-components.types'; |
7 | import AuthLayout from '../../components/auth/AuthLayout'; | 6 | import AuthLayout from '../../components/auth/AuthLayout'; |
8 | import AppLoader from '../../components/ui/AppLoader'; | 7 | import AppLoader from '../../components/ui/AppLoader'; |
9 | 8 | ||
10 | interface AuthLayoutContainerProps extends StoresProps {} | 9 | interface IProps extends StoresProps {} |
11 | 10 | ||
12 | class AuthLayoutContainer extends Component<AuthLayoutContainerProps> { | 11 | @inject('stores', 'actions') |
12 | @observer | ||
13 | class AuthLayoutContainer extends Component<IProps> { | ||
13 | render(): ReactElement { | 14 | render(): ReactElement { |
14 | const { stores, actions } = this.props; | 15 | const { stores, actions } = this.props; |
15 | const { app, features, globalError, user } = stores; | 16 | const { app, features, globalError, user } = stores; |
@@ -39,7 +40,6 @@ class AuthLayoutContainer extends Component<AuthLayoutContainerProps> { | |||
39 | <ThemeProvider theme={stores.ui.theme}> | 40 | <ThemeProvider theme={stores.ui.theme}> |
40 | <AuthLayout | 41 | <AuthLayout |
41 | error={globalError.response} | 42 | error={globalError.response} |
42 | pathname={stores.router.location.pathname} | ||
43 | isOnline={app.isOnline} | 43 | isOnline={app.isOnline} |
44 | isAPIHealthy={!app.healthCheckRequest.isError} | 44 | isAPIHealthy={!app.healthCheckRequest.isError} |
45 | retryHealthCheck={actions.app.healthCheck} | 45 | retryHealthCheck={actions.app.healthCheck} |
@@ -58,4 +58,4 @@ class AuthLayoutContainer extends Component<AuthLayoutContainerProps> { | |||
58 | } | 58 | } |
59 | } | 59 | } |
60 | 60 | ||
61 | export default inject('stores', 'actions')(observer(AuthLayoutContainer)); | 61 | export default AuthLayoutContainer; |
diff --git a/src/features/publishDebugInfo/Component.js b/src/features/publishDebugInfo/Component.tsx index 27661d917..e265902dd 100644 --- a/src/features/publishDebugInfo/Component.js +++ b/src/features/publishDebugInfo/Component.tsx | |||
@@ -1,18 +1,15 @@ | |||
1 | import { inject, observer } from 'mobx-react'; | 1 | import { inject, observer } from 'mobx-react'; |
2 | import PropTypes from 'prop-types'; | 2 | import { Component, ReactElement } from 'react'; |
3 | import { Component } from 'react'; | 3 | import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl'; |
4 | import { defineMessages, injectIntl } from 'react-intl'; | 4 | import withStyles, { WithStylesProps } from 'react-jss'; |
5 | import injectSheet from 'react-jss'; | 5 | import { StoresProps } from '../../@types/ferdium-components.types'; |
6 | import { state as ModalState } from './store'; | 6 | import { state as ModalState } from './store'; |
7 | |||
8 | import { H1 } from '../../components/ui/headline'; | 7 | import { H1 } from '../../components/ui/headline'; |
9 | import { sendAuthRequest } from '../../api/utils/auth'; | 8 | import { sendAuthRequest } from '../../api/utils/auth'; |
10 | import Button from '../../components/ui/button'; | 9 | import Button from '../../components/ui/button'; |
11 | import Input from '../../components/ui/input/index'; | 10 | import Input from '../../components/ui/input/index'; |
12 | import Modal from '../../components/ui/Modal'; | 11 | import Modal from '../../components/ui/Modal'; |
13 | import { DEBUG_API } from '../../config'; | 12 | import { DEBUG_API } from '../../config'; |
14 | import AppStore from '../../stores/AppStore'; | ||
15 | import ServicesStore from '../../stores/ServicesStore'; | ||
16 | 13 | ||
17 | const debug = require('../../preload-safe-debug')( | 14 | const debug = require('../../preload-safe-debug')( |
18 | 'Ferdium:feature:publishDebugInfo', | 15 | 'Ferdium:feature:publishDebugInfo', |
@@ -78,30 +75,47 @@ const styles = theme => ({ | |||
78 | }, | 75 | }, |
79 | }); | 76 | }); |
80 | 77 | ||
81 | class PublishDebugLogModal extends Component { | 78 | interface IProps |
82 | state = { | 79 | extends Partial<StoresProps>, |
83 | log: null, | 80 | WithStylesProps<typeof styles>, |
84 | error: false, | 81 | WrappedComponentProps {} |
85 | isSendingLog: false, | 82 | |
86 | }; | 83 | interface IState { |
84 | log: null; | ||
85 | error: boolean; | ||
86 | isSendingLogs: boolean; | ||
87 | } | ||
88 | |||
89 | @inject('stores', 'actions') | ||
90 | @observer | ||
91 | class PublishDebugLogModal extends Component<IProps, IState> { | ||
92 | constructor(props: IProps) { | ||
93 | super(props); | ||
94 | |||
95 | this.state = { | ||
96 | log: null, | ||
97 | error: false, | ||
98 | isSendingLogs: false, | ||
99 | }; | ||
100 | } | ||
87 | 101 | ||
88 | // Close this modal | 102 | // Close this modal |
89 | close() { | 103 | close(): void { |
90 | ModalState.isModalVisible = false; | 104 | ModalState.isModalVisible = false; |
91 | this.setState({ | 105 | this.setState({ |
92 | log: null, | 106 | log: null, |
93 | error: false, | 107 | error: false, |
94 | isSendingLog: false, | 108 | isSendingLogs: false, |
95 | }); | 109 | }); |
96 | } | 110 | } |
97 | 111 | ||
98 | async publishDebugInfo() { | 112 | async publishDebugInfo(): Promise<void> { |
99 | debug('debugInfo: starting publish'); | 113 | debug('debugInfo: starting publish'); |
100 | this.setState({ | 114 | this.setState({ |
101 | isSendingLog: true, | 115 | isSendingLogs: true, |
102 | }); | 116 | }); |
103 | 117 | ||
104 | const debugInfo = JSON.stringify(this.props.stores.app.debugInfo); | 118 | const debugInfo = JSON.stringify(this.props.stores?.app?.debugInfo); |
105 | 119 | ||
106 | const request = await sendAuthRequest( | 120 | const request = await sendAuthRequest( |
107 | `${DEBUG_API}/create`, | 121 | `${DEBUG_API}/create`, |
@@ -118,31 +132,21 @@ class PublishDebugLogModal extends Component { | |||
118 | if (request.status === 200) { | 132 | if (request.status === 200) { |
119 | const response = await request.json(); | 133 | const response = await request.json(); |
120 | if (response.id) { | 134 | if (response.id) { |
121 | this.setState({ | 135 | this.setState({ log: response.id }); |
122 | log: response.id, | ||
123 | }); | ||
124 | } else { | 136 | } else { |
125 | this.setState({ | 137 | this.setState({ error: true }); |
126 | error: true, | ||
127 | }); | ||
128 | } | 138 | } |
129 | } else { | 139 | } else { |
130 | this.setState({ | 140 | this.setState({ error: true }); |
131 | error: true, | ||
132 | }); | ||
133 | } | 141 | } |
134 | 142 | ||
135 | debug('debugInfo: finished publishing'); | 143 | debug('debugInfo: finished publishing'); |
136 | } | 144 | } |
137 | 145 | ||
138 | render() { | 146 | render(): ReactElement { |
139 | const { isModalVisible } = ModalState; | 147 | const { isModalVisible } = ModalState; |
140 | 148 | const { classes, intl } = this.props; | |
141 | const { classes } = this.props; | 149 | const { log, error, isSendingLogs } = this.state; |
142 | |||
143 | const { log, error, isSendingLog } = this.state; | ||
144 | |||
145 | const { intl } = this.props; | ||
146 | 150 | ||
147 | return ( | 151 | return ( |
148 | <Modal | 152 | <Modal |
@@ -159,18 +163,16 @@ class PublishDebugLogModal extends Component { | |||
159 | <p className={classes.info}> | 163 | <p className={classes.info}> |
160 | {intl.formatMessage(messages.published)} | 164 | {intl.formatMessage(messages.published)} |
161 | </p> | 165 | </p> |
162 | <Input showLabel={false} value={`${DEBUG_API}/${log}`} readonly /> | 166 | {/* TODO - [TS DEBT] need to check if <Input/> take readOnly and use it */} |
167 | <Input showLabel={false} value={`${DEBUG_API}/${log}`} readOnly /> | ||
163 | </> | 168 | </> |
164 | )} | 169 | )} |
165 | |||
166 | {error && ( | 170 | {error && ( |
167 | <p className={classes.info}>{intl.formatMessage(messages.error)}</p> | 171 | <p className={classes.info}>{intl.formatMessage(messages.error)}</p> |
168 | )} | 172 | )} |
169 | |||
170 | {!log && !error && ( | 173 | {!log && !error && ( |
171 | <> | 174 | <> |
172 | <p className={classes.info}>{intl.formatMessage(messages.info)}</p> | 175 | <p className={classes.info}>{intl.formatMessage(messages.info)}</p> |
173 | |||
174 | <a | 176 | <a |
175 | href={`${DEBUG_API}/privacy.html`} | 177 | href={`${DEBUG_API}/privacy.html`} |
176 | target="_blank" | 178 | target="_blank" |
@@ -187,13 +189,12 @@ class PublishDebugLogModal extends Component { | |||
187 | > | 189 | > |
188 | {intl.formatMessage(messages.terms)} | 190 | {intl.formatMessage(messages.terms)} |
189 | </a> | 191 | </a> |
190 | |||
191 | <Button | 192 | <Button |
192 | type="button" | 193 | type="button" |
193 | label={intl.formatMessage(messages.publish)} | 194 | label={intl.formatMessage(messages.publish)} |
194 | className={classes.button} | 195 | className={classes.button} |
195 | onClick={() => this.publishDebugInfo()} | 196 | onClick={() => this.publishDebugInfo()} |
196 | disabled={isSendingLog} | 197 | disabled={isSendingLogs} |
197 | /> | 198 | /> |
198 | </> | 199 | </> |
199 | )} | 200 | )} |
@@ -202,18 +203,6 @@ class PublishDebugLogModal extends Component { | |||
202 | } | 203 | } |
203 | } | 204 | } |
204 | 205 | ||
205 | PublishDebugLogModal.propTypes = { | ||
206 | stores: PropTypes.shape({ | ||
207 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
208 | }).isRequired, | ||
209 | actions: PropTypes.shape({ | ||
210 | service: PropTypes.instanceOf(ServicesStore).isRequired, | ||
211 | }).isRequired, | ||
212 | classes: PropTypes.object.isRequired, | ||
213 | }; | ||
214 | |||
215 | export default injectIntl( | 206 | export default injectIntl( |
216 | injectSheet(styles, { injectTheme: true })( | 207 | withStyles(styles, { injectTheme: true })(PublishDebugLogModal), |
217 | inject('stores', 'actions')(observer(PublishDebugLogModal)), | ||
218 | ), | ||
219 | ); | 208 | ); |
diff --git a/src/features/publishDebugInfo/index.ts b/src/features/publishDebugInfo/index.ts index 80714a104..cbbdbc594 100644 --- a/src/features/publishDebugInfo/index.ts +++ b/src/features/publishDebugInfo/index.ts | |||
@@ -1,21 +1,17 @@ | |||
1 | import { state as ModalState } from './store'; | 1 | import { state } from './store'; |
2 | 2 | ||
3 | export { default as Component } from './Component'; | 3 | export { default as Component } from './Component'; |
4 | 4 | ||
5 | const state = ModalState; | ||
6 | const debug = require('../../preload-safe-debug')( | 5 | const debug = require('../../preload-safe-debug')( |
7 | 'Ferdium:feature:publishDebugInfo', | 6 | 'Ferdium:feature:publishDebugInfo', |
8 | ); | 7 | ); |
9 | 8 | ||
10 | export default function initialize() { | 9 | export default function initialize(): void { |
11 | debug('Initialize publishDebugInfo feature'); | 10 | debug('Initialize publishDebugInfo feature'); |
12 | 11 | ||
13 | function showModal() { | 12 | const showModal = (): void => { |
14 | state.isModalVisible = true; | 13 | state.isModalVisible = true; |
15 | } | ||
16 | |||
17 | window['ferdium'].features.publishDebugInfo = { | ||
18 | state, | ||
19 | showModal, | ||
20 | }; | 14 | }; |
15 | |||
16 | window['ferdium'].features.publishDebugInfo = { state, showModal }; | ||
21 | } | 17 | } |
diff --git a/src/routes.tsx b/src/routes.tsx index 478d3dfe8..8150d135e 100644 --- a/src/routes.tsx +++ b/src/routes.tsx | |||
@@ -6,7 +6,7 @@ import { | |||
6 | Routes, | 6 | Routes, |
7 | unstable_HistoryRouter as HistoryRouter, | 7 | unstable_HistoryRouter as HistoryRouter, |
8 | } from 'react-router-dom'; | 8 | } from 'react-router-dom'; |
9 | 9 | import { HashHistory } from 'history'; | |
10 | import AppLayoutContainer from './containers/layout/AppLayoutContainer'; | 10 | import AppLayoutContainer from './containers/layout/AppLayoutContainer'; |
11 | import SettingsWindow from './containers/settings/SettingsWindow'; | 11 | import SettingsWindow from './containers/settings/SettingsWindow'; |
12 | import ReleaseNotesWindow from './containers/settings/ReleaseNotesWindow'; | 12 | import ReleaseNotesWindow from './containers/settings/ReleaseNotesWindow'; |
@@ -33,25 +33,19 @@ import AuthLayoutContainer from './containers/auth/AuthLayoutContainer'; | |||
33 | import WorkspacesScreen from './features/workspaces/containers/WorkspacesScreen'; | 33 | import WorkspacesScreen from './features/workspaces/containers/WorkspacesScreen'; |
34 | import EditWorkspaceScreen from './features/workspaces/containers/EditWorkspaceScreen'; | 34 | import EditWorkspaceScreen from './features/workspaces/containers/EditWorkspaceScreen'; |
35 | import { WORKSPACES_ROUTES } from './features/workspaces/constants'; | 35 | import { WORKSPACES_ROUTES } from './features/workspaces/constants'; |
36 | import { Actions } from './actions/lib/actions'; | 36 | import { StoresProps } from './@types/ferdium-components.types'; |
37 | import { RealStores } from './stores'; | ||
38 | 37 | ||
39 | type Props = { | 38 | interface IProps extends StoresProps { |
40 | stores: RealStores; | 39 | history: HashHistory; |
41 | actions: Actions; | 40 | } |
42 | history: any; | ||
43 | }; | ||
44 | 41 | ||
45 | class FerdiumRoutes extends Component<Props> { | 42 | @inject('stores', 'actions') |
43 | @observer | ||
44 | class FerdiumRoutes extends Component<IProps> { | ||
46 | render(): ReactElement { | 45 | render(): ReactElement { |
47 | const { history } = this.props; | 46 | const { history, stores, actions } = this.props; |
48 | const routeProps = { | 47 | const routeProps: StoresProps = { stores, actions }; |
49 | stores: this.props.stores, | 48 | const errorProps = { error: this.props.stores.globalError.error || {} }; |
50 | actions: this.props.actions, | ||
51 | }; | ||
52 | const errorProps = { | ||
53 | error: this.props.stores.globalError.error || {}, | ||
54 | }; | ||
55 | 49 | ||
56 | return ( | 50 | return ( |
57 | <HistoryRouter history={history}> | 51 | <HistoryRouter history={history}> |
@@ -185,4 +179,4 @@ class FerdiumRoutes extends Component<Props> { | |||
185 | } | 179 | } |
186 | } | 180 | } |
187 | 181 | ||
188 | export default inject('stores', 'actions')(observer(FerdiumRoutes)); | 182 | export default FerdiumRoutes; |