diff options
Diffstat (limited to 'src')
28 files changed, 295 insertions, 374 deletions
diff --git a/src/@types/ferdium-components.types.ts b/src/@types/ferdium-components.types.ts index df5e2f6ed..c4d1f0696 100644 --- a/src/@types/ferdium-components.types.ts +++ b/src/@types/ferdium-components.types.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { Actions } from 'src/actions/lib/actions'; | 1 | import { Actions } from 'src/actions/lib/actions'; |
2 | import { RealStores } from 'src/stores'; | 2 | import { RealStores } from 'src/stores'; |
3 | 3 | ||
4 | export interface DefaultProps { | 4 | export interface StoresProps { |
5 | actions: Actions; | 5 | actions: Actions; |
6 | stores: RealStores; | 6 | stores: RealStores; |
7 | } | 7 | } |
diff --git a/src/@types/mobx-form.types.ts b/src/@types/mobx-form.types.ts new file mode 100644 index 000000000..6bc20f5e1 --- /dev/null +++ b/src/@types/mobx-form.types.ts | |||
@@ -0,0 +1,20 @@ | |||
1 | export interface FormFieldOptions { | ||
2 | value?: string; | ||
3 | label?: string; | ||
4 | disabled?: boolean; | ||
5 | } | ||
6 | |||
7 | export interface FormFields { | ||
8 | fields: { | ||
9 | [key: string]: { | ||
10 | label?: string; | ||
11 | placeholder?: string; | ||
12 | options?: FormFieldOptions[]; | ||
13 | value?: string | boolean | number | null; | ||
14 | default?: string | boolean | number | null; | ||
15 | type?: string; // todo specifiy probably | ||
16 | disabled?: boolean; | ||
17 | validators?: any; // Not sure yet. | ||
18 | }; | ||
19 | }; | ||
20 | } | ||
diff --git a/src/actions/lib/actions.ts b/src/actions/lib/actions.ts index 378cef574..ea9a8fe46 100644 --- a/src/actions/lib/actions.ts +++ b/src/actions/lib/actions.ts | |||
@@ -10,7 +10,7 @@ export interface Actions { | |||
10 | [key: string]: { | 10 | [key: string]: { |
11 | [key: string]: { | 11 | [key: string]: { |
12 | (...args: any[]): void; | 12 | (...args: any[]): void; |
13 | listeners: Array<Function>; | 13 | listeners: Function[]; |
14 | notify: (params: any) => void; | 14 | notify: (params: any) => void; |
15 | listen: (listener: (params: any) => void) => void; | 15 | listen: (listener: (params: any) => void) => void; |
16 | off: (listener: (params: any) => void) => void; | 16 | off: (listener: (params: any) => void) => void; |
diff --git a/src/config.ts b/src/config.ts index 499f7b9e0..60eb3053b 100644 --- a/src/config.ts +++ b/src/config.ts | |||
@@ -276,6 +276,8 @@ export const DEFAULT_APP_SETTINGS = { | |||
276 | enableLongPressServiceHint: false, | 276 | enableLongPressServiceHint: false, |
277 | proxyFeatureEnabled: false, | 277 | proxyFeatureEnabled: false, |
278 | onlyShowFavoritesInUnreadCount: false, | 278 | onlyShowFavoritesInUnreadCount: false, |
279 | customTodoServer: '', | ||
280 | locale: 'en-US', | ||
279 | }; | 281 | }; |
280 | 282 | ||
281 | export const DEFAULT_SERVICE_SETTINGS = { | 283 | export const DEFAULT_SERVICE_SETTINGS = { |
diff --git a/src/containers/auth/AuthLayoutContainer.tsx b/src/containers/auth/AuthLayoutContainer.tsx index 8d65ec6f4..abe3905e0 100644 --- a/src/containers/auth/AuthLayoutContainer.tsx +++ b/src/containers/auth/AuthLayoutContainer.tsx | |||
@@ -2,14 +2,14 @@ import { Component, ReactElement, ReactNode } 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 | 4 | ||
5 | import { DefaultProps } from 'src/@types/ferdium-components.types'; | 5 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
6 | import { Location } from 'mobx-react-router'; | 6 | import { Location } from 'mobx-react-router'; |
7 | import AuthLayout from '../../components/auth/AuthLayout'; | 7 | import AuthLayout from '../../components/auth/AuthLayout'; |
8 | import AppLoader from '../../components/ui/AppLoader'; | 8 | import AppLoader from '../../components/ui/AppLoader'; |
9 | 9 | ||
10 | interface AuthLayoutContainerProps extends DefaultProps { | 10 | interface AuthLayoutContainerProps extends StoresProps { |
11 | location: Location; | 11 | location: Location; |
12 | children: ReactNode[] | ReactNode; | 12 | children: ReactNode; |
13 | } | 13 | } |
14 | 14 | ||
15 | class AuthLayoutContainer extends Component<AuthLayoutContainerProps> { | 15 | class AuthLayoutContainer extends Component<AuthLayoutContainerProps> { |
diff --git a/src/containers/auth/ChangeServerScreen.tsx b/src/containers/auth/ChangeServerScreen.tsx index 6af87e4a1..6d0feaecb 100644 --- a/src/containers/auth/ChangeServerScreen.tsx +++ b/src/containers/auth/ChangeServerScreen.tsx | |||
@@ -1,10 +1,10 @@ | |||
1 | import { Component, ReactElement } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
3 | import { DefaultProps } from 'src/@types/ferdium-components.types'; | 3 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
4 | import ChangeServer from '../../components/auth/ChangeServer'; | 4 | import ChangeServer from '../../components/auth/ChangeServer'; |
5 | 5 | ||
6 | class ChangeServerScreen extends Component<DefaultProps> { | 6 | class ChangeServerScreen extends Component<StoresProps> { |
7 | constructor(props: DefaultProps) { | 7 | constructor(props: StoresProps) { |
8 | super(props); | 8 | super(props); |
9 | 9 | ||
10 | this.onSubmit = this.onSubmit.bind(this); | 10 | this.onSubmit = this.onSubmit.bind(this); |
diff --git a/src/containers/auth/ImportScreen.tsx b/src/containers/auth/ImportScreen.tsx index c128dec14..3522ce0ce 100644 --- a/src/containers/auth/ImportScreen.tsx +++ b/src/containers/auth/ImportScreen.tsx | |||
@@ -1,9 +1,9 @@ | |||
1 | import { Component, ReactElement } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
3 | import { DefaultProps } from 'src/@types/ferdium-components.types'; | 3 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
4 | import Import from '../../components/auth/Import'; | 4 | import Import from '../../components/auth/Import'; |
5 | 5 | ||
6 | class ImportScreen extends Component<DefaultProps> { | 6 | class ImportScreen extends Component<StoresProps> { |
7 | render(): ReactElement { | 7 | render(): ReactElement { |
8 | const { actions, stores } = this.props; | 8 | const { actions, stores } = this.props; |
9 | 9 | ||
diff --git a/src/containers/auth/InviteScreen.tsx b/src/containers/auth/InviteScreen.tsx index a2c684f41..40ebdba8d 100644 --- a/src/containers/auth/InviteScreen.tsx +++ b/src/containers/auth/InviteScreen.tsx | |||
@@ -1,9 +1,9 @@ | |||
1 | import { Component, ReactElement } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
3 | import { DefaultProps } from 'src/@types/ferdium-components.types'; | 3 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
4 | import Invite from '../../components/auth/Invite'; | 4 | import Invite from '../../components/auth/Invite'; |
5 | 5 | ||
6 | class InviteScreen extends Component<DefaultProps> { | 6 | class InviteScreen extends Component<StoresProps> { |
7 | render(): ReactElement { | 7 | render(): ReactElement { |
8 | const { actions } = this.props; | 8 | const { actions } = this.props; |
9 | 9 | ||
diff --git a/src/containers/auth/LockedScreen.tsx b/src/containers/auth/LockedScreen.tsx index 8e3c1ec49..88f743d02 100644 --- a/src/containers/auth/LockedScreen.tsx +++ b/src/containers/auth/LockedScreen.tsx | |||
@@ -1,16 +1,16 @@ | |||
1 | import { Component, ReactElement } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
3 | import { DefaultProps } from 'src/@types/ferdium-components.types'; | 3 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
4 | import Locked from '../../components/auth/Locked'; | 4 | import Locked from '../../components/auth/Locked'; |
5 | 5 | ||
6 | import { hash } from '../../helpers/password-helpers'; | 6 | import { hash } from '../../helpers/password-helpers'; |
7 | 7 | ||
8 | class LockedScreen extends Component<DefaultProps> { | 8 | class LockedScreen extends Component<StoresProps> { |
9 | state = { | 9 | state = { |
10 | error: false, | 10 | error: false, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | constructor(props: DefaultProps) { | 13 | constructor(props: StoresProps) { |
14 | super(props); | 14 | super(props); |
15 | 15 | ||
16 | this.onSubmit = this.onSubmit.bind(this); | 16 | this.onSubmit = this.onSubmit.bind(this); |
diff --git a/src/containers/auth/LoginScreen.tsx b/src/containers/auth/LoginScreen.tsx index 4c5271fe1..c2efd27eb 100644 --- a/src/containers/auth/LoginScreen.tsx +++ b/src/containers/auth/LoginScreen.tsx | |||
@@ -1,9 +1,9 @@ | |||
1 | import { Component, ReactElement } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
3 | import { DefaultProps, GlobalError } from 'src/@types/ferdium-components.types'; | 3 | import { StoresProps, GlobalError } from 'src/@types/ferdium-components.types'; |
4 | import Login from '../../components/auth/Login'; | 4 | import Login from '../../components/auth/Login'; |
5 | 5 | ||
6 | interface LoginScreenProps extends DefaultProps { | 6 | interface LoginScreenProps extends StoresProps { |
7 | error: GlobalError; | 7 | error: GlobalError; |
8 | } | 8 | } |
9 | 9 | ||
diff --git a/src/containers/auth/PasswordScreen.tsx b/src/containers/auth/PasswordScreen.tsx index 3176e5a8b..313554802 100644 --- a/src/containers/auth/PasswordScreen.tsx +++ b/src/containers/auth/PasswordScreen.tsx | |||
@@ -1,9 +1,9 @@ | |||
1 | import { Component, ReactElement } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
3 | import { DefaultProps } from 'src/@types/ferdium-components.types'; | 3 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
4 | import Password from '../../components/auth/Password'; | 4 | import Password from '../../components/auth/Password'; |
5 | 5 | ||
6 | class PasswordScreen extends Component<DefaultProps> { | 6 | class PasswordScreen extends Component<StoresProps> { |
7 | render(): ReactElement { | 7 | render(): ReactElement { |
8 | const { actions, stores } = this.props; | 8 | const { actions, stores } = this.props; |
9 | 9 | ||
diff --git a/src/containers/auth/SetupAssistantScreen.tsx b/src/containers/auth/SetupAssistantScreen.tsx index 92f12c0bc..f7a353f26 100644 --- a/src/containers/auth/SetupAssistantScreen.tsx +++ b/src/containers/auth/SetupAssistantScreen.tsx | |||
@@ -2,11 +2,11 @@ | |||
2 | import { Component, ReactElement } from 'react'; | 2 | import { Component, ReactElement } from 'react'; |
3 | import { inject, observer } from 'mobx-react'; | 3 | import { inject, observer } from 'mobx-react'; |
4 | 4 | ||
5 | import { DefaultProps } from 'src/@types/ferdium-components.types'; | 5 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
6 | import { sleep } from '../../helpers/async-helpers'; | 6 | import { sleep } from '../../helpers/async-helpers'; |
7 | import SetupAssistant from '../../components/auth/SetupAssistant'; | 7 | import SetupAssistant from '../../components/auth/SetupAssistant'; |
8 | 8 | ||
9 | class SetupAssistantScreen extends Component<DefaultProps> { | 9 | class SetupAssistantScreen extends Component<StoresProps> { |
10 | state = { | 10 | state = { |
11 | isSettingUpServices: false, | 11 | isSettingUpServices: false, |
12 | }; | 12 | }; |
diff --git a/src/containers/auth/SignupScreen.tsx b/src/containers/auth/SignupScreen.tsx index 1dac392ef..04b39df67 100644 --- a/src/containers/auth/SignupScreen.tsx +++ b/src/containers/auth/SignupScreen.tsx | |||
@@ -1,10 +1,10 @@ | |||
1 | import { Component, ReactElement } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
3 | 3 | ||
4 | import { DefaultProps, GlobalError } from 'src/@types/ferdium-components.types'; | 4 | import { StoresProps, GlobalError } from 'src/@types/ferdium-components.types'; |
5 | import Signup from '../../components/auth/Signup'; | 5 | import Signup from '../../components/auth/Signup'; |
6 | 6 | ||
7 | interface SignUpScreenComponents extends DefaultProps { | 7 | interface SignUpScreenComponents extends StoresProps { |
8 | error: GlobalError; | 8 | error: GlobalError; |
9 | } | 9 | } |
10 | 10 | ||
diff --git a/src/containers/auth/WelcomeScreen.tsx b/src/containers/auth/WelcomeScreen.tsx index bbd73f4a2..bbd5b4825 100644 --- a/src/containers/auth/WelcomeScreen.tsx +++ b/src/containers/auth/WelcomeScreen.tsx | |||
@@ -1,10 +1,10 @@ | |||
1 | import { Component, ReactElement } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
3 | 3 | ||
4 | import { DefaultProps } from 'src/@types/ferdium-components.types'; | 4 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
5 | import Welcome from '../../components/auth/Welcome'; | 5 | import Welcome from '../../components/auth/Welcome'; |
6 | 6 | ||
7 | class WelcomeScreen extends Component<DefaultProps> { | 7 | class WelcomeScreen extends Component<StoresProps> { |
8 | render(): ReactElement { | 8 | render(): ReactElement { |
9 | const { user, recipePreviews } = this.props.stores; | 9 | const { user, recipePreviews } = this.props.stores; |
10 | 10 | ||
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.tsx index 1021ab4fa..c6a9dfb0d 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.tsx | |||
@@ -1,34 +1,22 @@ | |||
1 | import { Children, Component } from 'react'; | 1 | import { Children, Component, ReactElement, ReactNode } from 'react'; |
2 | import PropTypes from 'prop-types'; | ||
3 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
4 | import { ThemeProvider } from 'react-jss'; | 3 | import { ThemeProvider } from 'react-jss'; |
5 | 4 | ||
6 | import AppStore from '../../stores/AppStore'; | 5 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
7 | import RecipesStore from '../../stores/RecipesStore'; | ||
8 | import ServicesStore from '../../stores/ServicesStore'; | ||
9 | import FeaturesStore from '../../stores/FeaturesStore'; | ||
10 | import UIStore from '../../stores/UIStore'; | ||
11 | import SettingsStore from '../../stores/SettingsStore'; | ||
12 | import UserStore from '../../stores/UserStore'; | ||
13 | import RequestStore from '../../stores/RequestStore'; | ||
14 | import GlobalErrorStore from '../../stores/GlobalErrorStore'; | ||
15 | |||
16 | import { oneOrManyChildElements } from '../../prop-types'; | ||
17 | import AppLayout from '../../components/layout/AppLayout'; | 6 | import AppLayout from '../../components/layout/AppLayout'; |
18 | import Sidebar from '../../components/layout/Sidebar'; | 7 | import Sidebar from '../../components/layout/Sidebar'; |
19 | import Services from '../../components/services/content/Services'; | 8 | import Services from '../../components/services/content/Services'; |
20 | import AppLoader from '../../components/ui/AppLoader'; | 9 | import AppLoader from '../../components/ui/AppLoader'; |
21 | 10 | ||
22 | import { workspaceActions } from '../../features/workspaces/actions'; | ||
23 | import WorkspaceDrawer from '../../features/workspaces/components/WorkspaceDrawer'; | 11 | import WorkspaceDrawer from '../../features/workspaces/components/WorkspaceDrawer'; |
24 | import { workspaceStore } from '../../features/workspaces'; | 12 | import { workspaceStore } from '../../features/workspaces'; |
25 | 13 | ||
26 | class AppLayoutContainer extends Component { | 14 | interface AppLayoutContainerProps extends StoresProps { |
27 | static defaultProps = { | 15 | children: ReactNode; |
28 | children: null, | 16 | } |
29 | }; | ||
30 | 17 | ||
31 | render() { | 18 | class AppLayoutContainer extends Component<AppLayoutContainerProps> { |
19 | render(): ReactElement { | ||
32 | const { | 20 | const { |
33 | app, | 21 | app, |
34 | features, | 22 | features, |
@@ -38,7 +26,7 @@ class AppLayoutContainer extends Component { | |||
38 | globalError, | 26 | globalError, |
39 | requests, | 27 | requests, |
40 | user, | 28 | user, |
41 | router | 29 | router, |
42 | } = this.props.stores; | 30 | } = this.props.stores; |
43 | 31 | ||
44 | /* HOTFIX for: | 32 | /* HOTFIX for: |
@@ -69,7 +57,8 @@ class AppLayoutContainer extends Component { | |||
69 | 57 | ||
70 | const { retryRequiredRequests } = this.props.actions.requests; | 58 | const { retryRequiredRequests } = this.props.actions.requests; |
71 | 59 | ||
72 | const { installUpdate, toggleMuteApp, toggleCollapseMenu } = this.props.actions.app; | 60 | const { installUpdate, toggleMuteApp, toggleCollapseMenu } = |
61 | this.props.actions.app; | ||
73 | 62 | ||
74 | const { openSettings, closeSettings } = this.props.actions.ui; | 63 | const { openSettings, closeSettings } = this.props.actions.ui; |
75 | 64 | ||
@@ -85,14 +74,10 @@ class AppLayoutContainer extends Component { | |||
85 | 74 | ||
86 | const isLoadingSettings = !settings.loaded; | 75 | const isLoadingSettings = !settings.loaded; |
87 | 76 | ||
88 | if ( | 77 | if (isLoadingSettings || isLoadingFeatures || isLoadingServices) { |
89 | isLoadingSettings || | ||
90 | isLoadingFeatures || | ||
91 | isLoadingServices | ||
92 | ) { | ||
93 | return ( | 78 | return ( |
94 | <ThemeProvider theme={ui.theme}> | 79 | <ThemeProvider theme={ui.theme}> |
95 | <AppLoader /> | 80 | <AppLoader theme={ui.theme} /> |
96 | </ThemeProvider> | 81 | </ThemeProvider> |
97 | ); | 82 | ); |
98 | } | 83 | } |
@@ -127,7 +112,9 @@ class AppLayoutContainer extends Component { | |||
127 | wakeUpService={awake} | 112 | wakeUpService={awake} |
128 | toggleMuteApp={toggleMuteApp} | 113 | toggleMuteApp={toggleMuteApp} |
129 | toggleCollapseMenu={toggleCollapseMenu} | 114 | toggleCollapseMenu={toggleCollapseMenu} |
130 | toggleWorkspaceDrawer={workspaceActions.toggleWorkspaceDrawer} | 115 | toggleWorkspaceDrawer={ |
116 | this.props.actions.workspaces.toggleWorkspaceDrawer | ||
117 | } | ||
131 | isWorkspaceDrawerOpen={workspaceStore.isWorkspaceDrawerOpen} | 118 | isWorkspaceDrawerOpen={workspaceStore.isWorkspaceDrawerOpen} |
132 | showServicesUpdatedInfoBar={ui.showServicesUpdatedInfoBar} | 119 | showServicesUpdatedInfoBar={ui.showServicesUpdatedInfoBar} |
133 | showMessageBadgeWhenMutedSetting={ | 120 | showMessageBadgeWhenMutedSetting={ |
@@ -182,26 +169,4 @@ class AppLayoutContainer extends Component { | |||
182 | } | 169 | } |
183 | } | 170 | } |
184 | 171 | ||
185 | AppLayoutContainer.propTypes = { | ||
186 | stores: PropTypes.shape({ | ||
187 | services: PropTypes.instanceOf(ServicesStore).isRequired, | ||
188 | features: PropTypes.instanceOf(FeaturesStore).isRequired, | ||
189 | recipes: PropTypes.instanceOf(RecipesStore).isRequired, | ||
190 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
191 | ui: PropTypes.instanceOf(UIStore).isRequired, | ||
192 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | ||
193 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
194 | requests: PropTypes.instanceOf(RequestStore).isRequired, | ||
195 | globalError: PropTypes.instanceOf(GlobalErrorStore).isRequired, | ||
196 | }).isRequired, | ||
197 | actions: PropTypes.shape({ | ||
198 | service: PropTypes.instanceOf(ServicesStore).isRequired, | ||
199 | ui: PropTypes.instanceOf(UIStore).isRequired, | ||
200 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
201 | requests: PropTypes.instanceOf(RequestStore).isRequired, | ||
202 | }).isRequired, | ||
203 | // eslint-disable-next-line react/require-default-props | ||
204 | children: oneOrManyChildElements, | ||
205 | }; | ||
206 | |||
207 | export default inject('stores', 'actions')(observer(AppLayoutContainer)); | 172 | export default inject('stores', 'actions')(observer(AppLayoutContainer)); |
diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.tsx index aae230577..480b61f6c 100644 --- a/src/containers/settings/AccountScreen.js +++ b/src/containers/settings/AccountScreen.tsx | |||
@@ -1,36 +1,32 @@ | |||
1 | import { Component } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import PropTypes from 'prop-types'; | ||
3 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
4 | 3 | ||
5 | import UserStore from '../../stores/UserStore'; | 4 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
6 | import AppStore from '../../stores/AppStore'; | ||
7 | import FeaturesStore from '../../stores/FeaturesStore'; | ||
8 | import SettingsStore from '../../stores/SettingsStore'; | ||
9 | 5 | ||
10 | import AccountDashboard from '../../components/settings/account/AccountDashboard'; | 6 | import AccountDashboard from '../../components/settings/account/AccountDashboard'; |
11 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 7 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
12 | import { LIVE_FRANZ_API } from '../../config'; | 8 | import { LIVE_FRANZ_API } from '../../config'; |
13 | import { WEBSITE } from '../../environment-remote'; | 9 | import { WEBSITE } from '../../environment-remote'; |
14 | 10 | ||
15 | class AccountScreen extends Component { | 11 | class AccountScreen extends Component<StoresProps> { |
16 | onCloseWindow() { | 12 | onCloseWindow(): void { |
17 | const { user, features } = this.props.stores; | 13 | const { user, features } = this.props.stores; |
18 | user.getUserInfoRequest.invalidate({ immediately: true }); | 14 | user.getUserInfoRequest.invalidate({ immediately: true }); |
19 | features.featuresRequest.invalidate({ immediately: true }); | 15 | features.featuresRequest.invalidate({ immediately: true }); |
20 | } | 16 | } |
21 | 17 | ||
22 | reloadData() { | 18 | reloadData(): void { |
23 | const { user } = this.props.stores; | 19 | const { user } = this.props.stores; |
24 | 20 | ||
25 | user.getUserInfoRequest.reload(); | 21 | user.getUserInfoRequest.reload(); |
26 | } | 22 | } |
27 | 23 | ||
28 | handleWebsiteLink(route) { | 24 | handleWebsiteLink(route: string): void { |
29 | const { actions, stores } = this.props; | 25 | const { actions, stores } = this.props; |
30 | 26 | ||
31 | const api = stores.settings.all.app.server; | 27 | const api: string = stores.settings.all.app.server; |
32 | 28 | ||
33 | const url = | 29 | const url: string = |
34 | api === LIVE_FRANZ_API | 30 | api === LIVE_FRANZ_API |
35 | ? stores.user.getAuthURL( | 31 | ? stores.user.getAuthURL( |
36 | `${WEBSITE}${route}?utm_source=app&utm_medium=account_dashboard`, | 32 | `${WEBSITE}${route}?utm_source=app&utm_medium=account_dashboard`, |
@@ -40,7 +36,7 @@ class AccountScreen extends Component { | |||
40 | actions.app.openExternalUrl({ url }); | 36 | actions.app.openExternalUrl({ url }); |
41 | } | 37 | } |
42 | 38 | ||
43 | render() { | 39 | render(): ReactElement { |
44 | const { user, settings } = this.props.stores; | 40 | const { user, settings } = this.props.stores; |
45 | const { user: userActions } = this.props.actions; | 41 | const { user: userActions } = this.props.actions; |
46 | 42 | ||
@@ -72,17 +68,4 @@ class AccountScreen extends Component { | |||
72 | } | 68 | } |
73 | } | 69 | } |
74 | 70 | ||
75 | AccountScreen.propTypes = { | ||
76 | stores: PropTypes.shape({ | ||
77 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
78 | features: PropTypes.instanceOf(FeaturesStore).isRequired, | ||
79 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | ||
80 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
81 | }).isRequired, | ||
82 | actions: PropTypes.shape({ | ||
83 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
84 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
85 | }).isRequired, | ||
86 | }; | ||
87 | |||
88 | export default inject('stores', 'actions')(observer(AccountScreen)); | 71 | export default inject('stores', 'actions')(observer(AccountScreen)); |
diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.tsx index 4615a9cdf..6545c3d7d 100644 --- a/src/containers/settings/EditServiceScreen.js +++ b/src/containers/settings/EditServiceScreen.tsx | |||
@@ -1,13 +1,12 @@ | |||
1 | import { Component } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import PropTypes from 'prop-types'; | ||
3 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
4 | import { defineMessages, injectIntl } from 'react-intl'; | 3 | import { defineMessages, injectIntl } from 'react-intl'; |
5 | 4 | ||
6 | import { RouterStore } from 'mobx-react-router'; | 5 | import { RouterStore } from 'mobx-react-router'; |
7 | import UserStore from '../../stores/UserStore'; | 6 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
8 | import RecipesStore from '../../stores/RecipesStore'; | 7 | import { IRecipe } from 'src/models/Recipe'; |
9 | import ServicesStore from '../../stores/ServicesStore'; | 8 | import Service from 'src/models/Service'; |
10 | import SettingsStore from '../../stores/SettingsStore'; | 9 | import { FormFields } from 'src/@types/mobx-form.types'; |
11 | import Form from '../../lib/Form'; | 10 | import Form from '../../lib/Form'; |
12 | 11 | ||
13 | import ServiceError from '../../components/settings/services/ServiceError'; | 12 | import ServiceError from '../../components/settings/services/ServiceError'; |
@@ -119,8 +118,14 @@ const messages = defineMessages({ | |||
119 | }, | 118 | }, |
120 | }); | 119 | }); |
121 | 120 | ||
122 | class EditServiceScreen extends Component { | 121 | interface EditServicesScreenProps extends StoresProps { |
123 | onSubmit(data) { | 122 | router: RouterStore; |
123 | intl: any; | ||
124 | } | ||
125 | |||
126 | class EditServiceScreen extends Component<EditServicesScreenProps> { | ||
127 | onSubmit(data: any) { | ||
128 | // @ts-ignore TODO: This is actually there and we don't have a correct type right now. | ||
124 | const { action } = this.props.router.params; | 129 | const { action } = this.props.router.params; |
125 | const { recipes, services } = this.props.stores; | 130 | const { recipes, services } = this.props.stores; |
126 | const { createService, updateService } = this.props.actions.service; | 131 | const { createService, updateService } = this.props.actions.service; |
@@ -137,17 +142,18 @@ class EditServiceScreen extends Component { | |||
137 | serviceData.isMuted = !serviceData.isMuted; | 142 | serviceData.isMuted = !serviceData.isMuted; |
138 | 143 | ||
139 | if (action === 'edit') { | 144 | if (action === 'edit') { |
140 | updateService({ serviceId: services.activeSettings.id, serviceData }); | 145 | updateService({ serviceId: services.activeSettings?.id, serviceData }); |
141 | } else { | 146 | } else { |
142 | createService({ recipeId: recipes.active.id, serviceData }); | 147 | createService({ recipeId: recipes.active?.id, serviceData }); |
143 | } | 148 | } |
144 | } | 149 | } |
145 | 150 | ||
146 | prepareForm(recipe, service, proxy) { | 151 | prepareForm(recipe: IRecipe, service: Service | null, proxy: any): Form { |
147 | const { intl } = this.props; | 152 | const { intl } = this.props; |
148 | 153 | ||
149 | const { stores, router } = this.props; | 154 | const { stores, router } = this.props; |
150 | 155 | ||
156 | // @ts-ignore TODO: This is actually there and we don't have a correct type right now. | ||
151 | const { action } = router.params; | 157 | const { action } = router.params; |
152 | 158 | ||
153 | let defaultSpellcheckerLanguage = | 159 | let defaultSpellcheckerLanguage = |
@@ -171,16 +177,16 @@ class EditServiceScreen extends Component { | |||
171 | : '', | 177 | : '', |
172 | }); | 178 | }); |
173 | 179 | ||
174 | const config = { | 180 | const config: FormFields = { |
175 | fields: { | 181 | fields: { |
176 | name: { | 182 | name: { |
177 | label: intl.formatMessage(messages.name), | 183 | label: intl.formatMessage(messages.name), |
178 | placeholder: intl.formatMessage(messages.name), | 184 | placeholder: intl.formatMessage(messages.name), |
179 | value: service.id ? service.name : recipe.name, | 185 | value: service?.id ? service.name : recipe.name, |
180 | }, | 186 | }, |
181 | isEnabled: { | 187 | isEnabled: { |
182 | label: intl.formatMessage(messages.enableService), | 188 | label: intl.formatMessage(messages.enableService), |
183 | value: service.isEnabled, | 189 | value: service?.isEnabled, |
184 | default: DEFAULT_SERVICE_SETTINGS.isEnabled, | 190 | default: DEFAULT_SERVICE_SETTINGS.isEnabled, |
185 | }, | 191 | }, |
186 | isHibernationEnabled: { | 192 | isHibernationEnabled: { |
@@ -188,81 +194,81 @@ class EditServiceScreen extends Component { | |||
188 | value: | 194 | value: |
189 | action !== 'edit' | 195 | action !== 'edit' |
190 | ? recipe.autoHibernate | 196 | ? recipe.autoHibernate |
191 | : service.isHibernationEnabled, | 197 | : service?.isHibernationEnabled, |
192 | default: DEFAULT_SERVICE_SETTINGS.isHibernationEnabled, | 198 | default: DEFAULT_SERVICE_SETTINGS.isHibernationEnabled, |
193 | }, | 199 | }, |
194 | isWakeUpEnabled: { | 200 | isWakeUpEnabled: { |
195 | label: intl.formatMessage(messages.enableWakeUp), | 201 | label: intl.formatMessage(messages.enableWakeUp), |
196 | value: service.isWakeUpEnabled, | 202 | value: service?.isWakeUpEnabled, |
197 | default: DEFAULT_SERVICE_SETTINGS.isWakeUpEnabled, | 203 | default: DEFAULT_SERVICE_SETTINGS.isWakeUpEnabled, |
198 | }, | 204 | }, |
199 | isNotificationEnabled: { | 205 | isNotificationEnabled: { |
200 | label: intl.formatMessage(messages.enableNotification), | 206 | label: intl.formatMessage(messages.enableNotification), |
201 | value: service.isNotificationEnabled, | 207 | value: service?.isNotificationEnabled, |
202 | default: DEFAULT_SERVICE_SETTINGS.isNotificationEnabled, | 208 | default: DEFAULT_SERVICE_SETTINGS.isNotificationEnabled, |
203 | }, | 209 | }, |
204 | isBadgeEnabled: { | 210 | isBadgeEnabled: { |
205 | label: intl.formatMessage(messages.enableBadge), | 211 | label: intl.formatMessage(messages.enableBadge), |
206 | value: service.isBadgeEnabled, | 212 | value: service?.isBadgeEnabled, |
207 | default: DEFAULT_SERVICE_SETTINGS.isBadgeEnabled, | 213 | default: DEFAULT_SERVICE_SETTINGS.isBadgeEnabled, |
208 | }, | 214 | }, |
209 | trapLinkClicks: { | 215 | trapLinkClicks: { |
210 | label: intl.formatMessage(messages.trapLinkClicks), | 216 | label: intl.formatMessage(messages.trapLinkClicks), |
211 | value: service.trapLinkClicks, | 217 | value: service?.trapLinkClicks, |
212 | default: DEFAULT_SERVICE_SETTINGS.trapLinkClicks, | 218 | default: DEFAULT_SERVICE_SETTINGS.trapLinkClicks, |
213 | }, | 219 | }, |
214 | isMuted: { | 220 | isMuted: { |
215 | label: intl.formatMessage(messages.enableAudio), | 221 | label: intl.formatMessage(messages.enableAudio), |
216 | value: !service.isMuted, | 222 | value: !service?.isMuted, |
217 | default: DEFAULT_SERVICE_SETTINGS.isMuted, | 223 | default: DEFAULT_SERVICE_SETTINGS.isMuted, |
218 | }, | 224 | }, |
219 | customIcon: { | 225 | customIcon: { |
220 | label: intl.formatMessage(messages.icon), | 226 | label: intl.formatMessage(messages.icon), |
221 | value: service.hasCustomUploadedIcon ? service.icon : false, | 227 | value: service?.hasCustomUploadedIcon ? service?.icon : false, |
222 | default: null, | 228 | default: null, |
223 | type: 'file', | 229 | type: 'file', |
224 | }, | 230 | }, |
225 | isDarkModeEnabled: { | 231 | isDarkModeEnabled: { |
226 | label: intl.formatMessage(messages.enableDarkMode), | 232 | label: intl.formatMessage(messages.enableDarkMode), |
227 | value: service.isDarkModeEnabled, | 233 | value: service?.isDarkModeEnabled, |
228 | default: stores.settings.app.darkMode, | 234 | default: stores.settings.app.darkMode, |
229 | }, | 235 | }, |
230 | darkReaderBrightness: { | 236 | darkReaderBrightness: { |
231 | label: intl.formatMessage(messages.darkReaderBrightness), | 237 | label: intl.formatMessage(messages.darkReaderBrightness), |
232 | value: service.darkReaderSettings | 238 | value: service?.darkReaderSettings |
233 | ? service.darkReaderSettings.brightness | 239 | ? service?.darkReaderSettings.brightness |
234 | : undefined, | 240 | : undefined, |
235 | default: 100, | 241 | default: 100, |
236 | }, | 242 | }, |
237 | darkReaderContrast: { | 243 | darkReaderContrast: { |
238 | label: intl.formatMessage(messages.darkReaderContrast), | 244 | label: intl.formatMessage(messages.darkReaderContrast), |
239 | value: service.darkReaderSettings | 245 | value: service?.darkReaderSettings |
240 | ? service.darkReaderSettings.contrast | 246 | ? service?.darkReaderSettings.contrast |
241 | : undefined, | 247 | : undefined, |
242 | default: 90, | 248 | default: 90, |
243 | }, | 249 | }, |
244 | darkReaderSepia: { | 250 | darkReaderSepia: { |
245 | label: intl.formatMessage(messages.darkReaderSepia), | 251 | label: intl.formatMessage(messages.darkReaderSepia), |
246 | value: service.darkReaderSettings | 252 | value: service?.darkReaderSettings |
247 | ? service.darkReaderSettings.sepia | 253 | ? service?.darkReaderSettings.sepia |
248 | : undefined, | 254 | : undefined, |
249 | default: 10, | 255 | default: 10, |
250 | }, | 256 | }, |
251 | isProgressbarEnabled: { | 257 | isProgressbarEnabled: { |
252 | label: intl.formatMessage(messages.enableProgressbar), | 258 | label: intl.formatMessage(messages.enableProgressbar), |
253 | value: service.isProgressbarEnabled, | 259 | value: service?.isProgressbarEnabled, |
254 | default: DEFAULT_SERVICE_SETTINGS.isProgressbarEnabled, | 260 | default: DEFAULT_SERVICE_SETTINGS.isProgressbarEnabled, |
255 | }, | 261 | }, |
256 | spellcheckerLanguage: { | 262 | spellcheckerLanguage: { |
257 | label: intl.formatMessage(globalMessages.spellcheckerLanguage), | 263 | label: intl.formatMessage(globalMessages.spellcheckerLanguage), |
258 | value: service.spellcheckerLanguage, | 264 | value: service?.spellcheckerLanguage, |
259 | options: spellcheckerLanguage, | 265 | options: spellcheckerLanguage, |
260 | disabled: !stores.settings.app.enableSpellchecking, | 266 | disabled: !stores.settings.app.enableSpellchecking, |
261 | }, | 267 | }, |
262 | userAgentPref: { | 268 | userAgentPref: { |
263 | label: intl.formatMessage(globalMessages.userAgentPref), | 269 | label: intl.formatMessage(globalMessages.userAgentPref), |
264 | placeholder: service.defaultUserAgent, | 270 | placeholder: service?.defaultUserAgent, |
265 | value: service.userAgentPref ? service.userAgentPref : '', | 271 | value: service?.userAgentPref ? service.userAgentPref : '', |
266 | }, | 272 | }, |
267 | }, | 273 | }, |
268 | }; | 274 | }; |
@@ -272,7 +278,7 @@ class EditServiceScreen extends Component { | |||
272 | team: { | 278 | team: { |
273 | label: intl.formatMessage(messages.team), | 279 | label: intl.formatMessage(messages.team), |
274 | placeholder: intl.formatMessage(messages.team), | 280 | placeholder: intl.formatMessage(messages.team), |
275 | value: service.team, | 281 | value: service?.team, |
276 | validators: [required], | 282 | validators: [required], |
277 | }, | 283 | }, |
278 | }); | 284 | }); |
@@ -283,7 +289,7 @@ class EditServiceScreen extends Component { | |||
283 | customUrl: { | 289 | customUrl: { |
284 | label: intl.formatMessage(messages.customUrl), | 290 | label: intl.formatMessage(messages.customUrl), |
285 | placeholder: "'http://' or 'https://' or 'file:///'", | 291 | placeholder: "'http://' or 'https://' or 'file:///'", |
286 | value: service.customUrl || recipe.serviceURL, | 292 | value: service?.customUrl || recipe.serviceURL, |
287 | validators: [required, url], | 293 | validators: [required, url], |
288 | }, | 294 | }, |
289 | }); | 295 | }); |
@@ -312,7 +318,7 @@ class EditServiceScreen extends Component { | |||
312 | Object.assign(config.fields, { | 318 | Object.assign(config.fields, { |
313 | isIndirectMessageBadgeEnabled: { | 319 | isIndirectMessageBadgeEnabled: { |
314 | label: intl.formatMessage(messages.indirectMessages), | 320 | label: intl.formatMessage(messages.indirectMessages), |
315 | value: service.isIndirectMessageBadgeEnabled, | 321 | value: service?.isIndirectMessageBadgeEnabled, |
316 | default: DEFAULT_SERVICE_SETTINGS.hasIndirectMessages, | 322 | default: DEFAULT_SERVICE_SETTINGS.hasIndirectMessages, |
317 | }, | 323 | }, |
318 | }); | 324 | }); |
@@ -322,14 +328,23 @@ class EditServiceScreen extends Component { | |||
322 | Object.assign(config.fields, { | 328 | Object.assign(config.fields, { |
323 | onlyShowFavoritesInUnreadCount: { | 329 | onlyShowFavoritesInUnreadCount: { |
324 | label: intl.formatMessage(messages.onlyShowFavoritesInUnreadCount), | 330 | label: intl.formatMessage(messages.onlyShowFavoritesInUnreadCount), |
325 | value: service.onlyShowFavoritesInUnreadCount, | 331 | value: service?.onlyShowFavoritesInUnreadCount, |
326 | default: DEFAULT_APP_SETTINGS.onlyShowFavoritesInUnreadCount, | 332 | default: DEFAULT_APP_SETTINGS.onlyShowFavoritesInUnreadCount, |
327 | }, | 333 | }, |
328 | }); | 334 | }); |
329 | } | 335 | } |
330 | 336 | ||
331 | if (proxy.isEnabled) { | 337 | if (proxy.isEnabled) { |
332 | const serviceProxyConfig = stores.settings.proxy[service.id] || {}; | 338 | let serviceProxyConfig: { |
339 | isEnabled?: boolean; | ||
340 | host?: string; | ||
341 | port?: number; | ||
342 | user?: string; | ||
343 | password?: string; | ||
344 | } = {}; | ||
345 | if (service) { | ||
346 | serviceProxyConfig = stores.settings.proxy[service.id] || {}; | ||
347 | } | ||
333 | 348 | ||
334 | Object.assign(config.fields, { | 349 | Object.assign(config.fields, { |
335 | proxy: { | 350 | proxy: { |
@@ -367,41 +382,47 @@ class EditServiceScreen extends Component { | |||
367 | }); | 382 | }); |
368 | } | 383 | } |
369 | 384 | ||
385 | // @ts-ignore: Remove this ignore once mobx-react-form v4 with typescript | ||
386 | // support has been released. | ||
370 | return new Form(config); | 387 | return new Form(config); |
371 | } | 388 | } |
372 | 389 | ||
373 | deleteService() { | 390 | deleteService(): void { |
374 | const { deleteService } = this.props.actions.service; | 391 | const { deleteService } = this.props.actions.service; |
392 | // @ts-ignore TODO: This is actually there and we don't have a correct type right now. | ||
375 | const { action } = this.props.router.params; | 393 | const { action } = this.props.router.params; |
376 | 394 | ||
377 | if (action === 'edit') { | 395 | if (action === 'edit') { |
378 | const { activeSettings: service } = this.props.stores.services; | 396 | const { activeSettings: service } = this.props.stores.services; |
379 | deleteService({ | 397 | deleteService({ |
380 | serviceId: service.id, | 398 | serviceId: service?.id, |
381 | redirect: '/settings/services', | 399 | redirect: '/settings/services', |
382 | }); | 400 | }); |
383 | } | 401 | } |
384 | } | 402 | } |
385 | 403 | ||
386 | openRecipeFile(file) { | 404 | openRecipeFile(file: any): void { |
387 | const { openRecipeFile } = this.props.actions.service; | 405 | const { openRecipeFile } = this.props.actions.service; |
406 | // @ts-ignore TODO: This is actually there and we don't have a correct type right now. | ||
388 | const { action } = this.props.router.params; | 407 | const { action } = this.props.router.params; |
389 | 408 | ||
390 | if (action === 'edit') { | 409 | if (action === 'edit') { |
391 | const { activeSettings: service } = this.props.stores.services; | 410 | const { activeSettings: service } = this.props.stores.services; |
392 | openRecipeFile({ | 411 | openRecipeFile({ |
393 | recipe: service.recipe.id, | 412 | recipe: service?.recipe.id, |
394 | file, | 413 | file, |
395 | }); | 414 | }); |
396 | } | 415 | } |
397 | } | 416 | } |
398 | 417 | ||
399 | render() { | 418 | render(): ReactElement { |
400 | const { recipes, services, user } = this.props.stores; | 419 | const { recipes, services, user } = this.props.stores; |
420 | |||
421 | // @ts-ignore TODO: This is actually there and we don't have a correct type right now. | ||
401 | const { action } = this.props.router.params; | 422 | const { action } = this.props.router.params; |
402 | 423 | ||
403 | let recipe; | 424 | let recipe: null | IRecipe = null; |
404 | let service = {}; | 425 | let service: null | Service = null; |
405 | let isLoading = false; | 426 | let isLoading = false; |
406 | 427 | ||
407 | if (action === 'add') { | 428 | if (action === 'add') { |
@@ -454,19 +475,6 @@ class EditServiceScreen extends Component { | |||
454 | } | 475 | } |
455 | } | 476 | } |
456 | 477 | ||
457 | EditServiceScreen.propTypes = { | 478 | export default injectIntl<'intl', EditServicesScreenProps>( |
458 | stores: PropTypes.shape({ | ||
459 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
460 | recipes: PropTypes.instanceOf(RecipesStore).isRequired, | ||
461 | services: PropTypes.instanceOf(ServicesStore).isRequired, | ||
462 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | ||
463 | }).isRequired, | ||
464 | router: PropTypes.instanceOf(RouterStore).isRequired, | ||
465 | actions: PropTypes.shape({ | ||
466 | service: PropTypes.instanceOf(ServicesStore).isRequired, | ||
467 | }).isRequired, | ||
468 | }; | ||
469 | |||
470 | export default injectIntl( | ||
471 | inject('stores', 'actions')(observer(EditServiceScreen)), | 479 | inject('stores', 'actions')(observer(EditServiceScreen)), |
472 | ); | 480 | ); |
diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.tsx index 867db6f08..205c71107 100644 --- a/src/containers/settings/EditSettingsScreen.js +++ b/src/containers/settings/EditSettingsScreen.tsx | |||
@@ -1,13 +1,10 @@ | |||
1 | import { ipcRenderer } from 'electron'; | 1 | import { ipcRenderer } from 'electron'; |
2 | import { Component } from 'react'; | 2 | import { Component, ReactElement } from 'react'; |
3 | import PropTypes from 'prop-types'; | ||
4 | import { inject, observer } from 'mobx-react'; | 3 | import { inject, observer } from 'mobx-react'; |
5 | import { defineMessages, injectIntl } from 'react-intl'; | 4 | import { defineMessages, injectIntl } from 'react-intl'; |
6 | 5 | ||
7 | import AppStore from '../../stores/AppStore'; | 6 | import { FormFields } from 'src/@types/mobx-form.types'; |
8 | import SettingsStore from '../../stores/SettingsStore'; | 7 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
9 | import UserStore from '../../stores/UserStore'; | ||
10 | import TodosStore from '../../features/todos/store'; | ||
11 | import Form from '../../lib/Form'; | 8 | import Form from '../../lib/Form'; |
12 | import { APP_LOCALES, SPELLCHECKER_LOCALES } from '../../i18n/languages'; | 9 | import { APP_LOCALES, SPELLCHECKER_LOCALES } from '../../i18n/languages'; |
13 | import { | 10 | import { |
@@ -36,8 +33,6 @@ import EditSettingsForm from '../../components/settings/settings/EditSettingsFor | |||
36 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 33 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
37 | 34 | ||
38 | import globalMessages from '../../i18n/globalMessages'; | 35 | import globalMessages from '../../i18n/globalMessages'; |
39 | import WorkspacesStore from '../../features/workspaces/store'; | ||
40 | import ServicesStore from '../../stores/ServicesStore'; | ||
41 | 36 | ||
42 | const debug = require('../../preload-safe-debug')('Ferdium:EditSettingsScreen'); | 37 | const debug = require('../../preload-safe-debug')('Ferdium:EditSettingsScreen'); |
43 | 38 | ||
@@ -76,7 +71,8 @@ const messages = defineMessages({ | |||
76 | }, | 71 | }, |
77 | reloadAfterResumeTime: { | 72 | reloadAfterResumeTime: { |
78 | id: 'settings.app.form.reloadAfterResumeTime', | 73 | id: 'settings.app.form.reloadAfterResumeTime', |
79 | defaultMessage: 'Time to consider the system as idle/suspended (in minutes)', | 74 | defaultMessage: |
75 | 'Time to consider the system as idle/suspended (in minutes)', | ||
80 | }, | 76 | }, |
81 | minimizeToSystemTray: { | 77 | minimizeToSystemTray: { |
82 | id: 'settings.app.form.minimizeToSystemTray', | 78 | id: 'settings.app.form.minimizeToSystemTray', |
@@ -296,14 +292,14 @@ const messages = defineMessages({ | |||
296 | }, | 292 | }, |
297 | }); | 293 | }); |
298 | 294 | ||
299 | class EditSettingsScreen extends Component { | 295 | interface EditSettingsScreenProps extends StoresProps { |
300 | constructor(props) { | 296 | intl: any; |
301 | super(props); | 297 | } |
302 | 298 | ||
303 | this.state = { | 299 | class EditSettingsScreen extends Component<EditSettingsScreenProps> { |
304 | lockedPassword: '', | 300 | state = { |
305 | }; | 301 | lockedPassword: '', |
306 | } | 302 | }; |
307 | 303 | ||
308 | onSubmit(settingsData) { | 304 | onSubmit(settingsData) { |
309 | const { todos, workspaces } = this.props.stores; | 305 | const { todos, workspaces } = this.props.stores; |
@@ -348,12 +344,16 @@ class EditSettingsScreen extends Component { | |||
348 | hibernateOnStartup: Boolean(settingsData.hibernateOnStartup), | 344 | hibernateOnStartup: Boolean(settingsData.hibernateOnStartup), |
349 | hibernationStrategy: Number(settingsData.hibernationStrategy), | 345 | hibernationStrategy: Number(settingsData.hibernationStrategy), |
350 | wakeUpStrategy: Number(settingsData.wakeUpStrategy), | 346 | wakeUpStrategy: Number(settingsData.wakeUpStrategy), |
351 | wakeUpHibernationStrategy: Number(settingsData.wakeUpHibernationStrategy), | 347 | wakeUpHibernationStrategy: Number( |
348 | settingsData.wakeUpHibernationStrategy, | ||
349 | ), | ||
352 | wakeUpHibernationSplay: Boolean(settingsData.wakeUpHibernationSplay), | 350 | wakeUpHibernationSplay: Boolean(settingsData.wakeUpHibernationSplay), |
353 | predefinedTodoServer: settingsData.predefinedTodoServer, | 351 | predefinedTodoServer: settingsData.predefinedTodoServer, |
354 | customTodoServer: settingsData.customTodoServer, | 352 | customTodoServer: settingsData.customTodoServer, |
355 | lockingFeatureEnabled: Boolean(settingsData.lockingFeatureEnabled), | 353 | lockingFeatureEnabled: Boolean(settingsData.lockingFeatureEnabled), |
356 | lockedPassword: useOriginalPassword ? this.props.stores.settings.all.app.lockedPassword : hash(String(settingsData.lockedPassword)), | 354 | lockedPassword: useOriginalPassword |
355 | ? this.props.stores.settings.all.app.lockedPassword | ||
356 | : hash(String(settingsData.lockedPassword)), | ||
357 | useTouchIdToUnlock: Boolean(settingsData.useTouchIdToUnlock), | 357 | useTouchIdToUnlock: Boolean(settingsData.useTouchIdToUnlock), |
358 | inactivityLock: Number(settingsData.inactivityLock), | 358 | inactivityLock: Number(settingsData.inactivityLock), |
359 | scheduledDNDEnabled: Boolean(settingsData.scheduledDNDEnabled), | 359 | scheduledDNDEnabled: Boolean(settingsData.scheduledDNDEnabled), |
@@ -492,7 +492,7 @@ class EditSettingsScreen extends Component { | |||
492 | ), | 492 | ), |
493 | }); | 493 | }); |
494 | 494 | ||
495 | const config = { | 495 | const config: FormFields = { |
496 | fields: { | 496 | fields: { |
497 | autoLaunchOnStart: { | 497 | autoLaunchOnStart: { |
498 | label: intl.formatMessage(messages.autoLaunchOnStart), | 498 | label: intl.formatMessage(messages.autoLaunchOnStart), |
@@ -843,10 +843,12 @@ class EditSettingsScreen extends Component { | |||
843 | }; | 843 | }; |
844 | } | 844 | } |
845 | 845 | ||
846 | // @ts-ignore: Remove this ignore once mobx-react-form v4 with typescript | ||
847 | // support has been released. | ||
846 | return new Form(config); | 848 | return new Form(config); |
847 | } | 849 | } |
848 | 850 | ||
849 | render() { | 851 | render(): ReactElement { |
850 | const { app, services } = this.props.stores; | 852 | const { app, services } = this.props.stores; |
851 | const { | 853 | const { |
852 | updateStatus, | 854 | updateStatus, |
@@ -869,7 +871,9 @@ class EditSettingsScreen extends Component { | |||
869 | noUpdateAvailable={updateStatus === updateStatusTypes.NOT_AVAILABLE} | 871 | noUpdateAvailable={updateStatus === updateStatusTypes.NOT_AVAILABLE} |
870 | updateIsReadyToInstall={updateStatus === updateStatusTypes.DOWNLOADED} | 872 | updateIsReadyToInstall={updateStatus === updateStatusTypes.DOWNLOADED} |
871 | updateFailed={updateStatus === updateStatusTypes.FAILED} | 873 | updateFailed={updateStatus === updateStatusTypes.FAILED} |
872 | showServicesUpdatedInfoBar={this.props.stores.ui.showServicesUpdatedInfoBar} | 874 | showServicesUpdatedInfoBar={ |
875 | this.props.stores.ui.showServicesUpdatedInfoBar | ||
876 | } | ||
873 | onSubmit={d => this.onSubmit(d)} | 877 | onSubmit={d => this.onSubmit(d)} |
874 | getCacheSize={() => app.cacheSize} | 878 | getCacheSize={() => app.cacheSize} |
875 | isClearingAllCache={isClearingAllCache} | 879 | isClearingAllCache={isClearingAllCache} |
@@ -880,7 +884,9 @@ class EditSettingsScreen extends Component { | |||
880 | isAdaptableDarkModeEnabled={ | 884 | isAdaptableDarkModeEnabled={ |
881 | this.props.stores.settings.app.adaptableDarkMode | 885 | this.props.stores.settings.app.adaptableDarkMode |
882 | } | 886 | } |
883 | isUseGrayscaleServicesEnabled={this.props.stores.settings.app.useGrayscaleServices} | 887 | isUseGrayscaleServicesEnabled={ |
888 | this.props.stores.settings.app.useGrayscaleServices | ||
889 | } | ||
884 | isSplitModeEnabled={this.props.stores.settings.app.splitMode} | 890 | isSplitModeEnabled={this.props.stores.settings.app.splitMode} |
885 | isTodosActivated={this.props.stores.todos.isFeatureEnabledByUser} | 891 | isTodosActivated={this.props.stores.todos.isFeatureEnabledByUser} |
886 | isUsingCustomTodoService={ | 892 | isUsingCustomTodoService={ |
@@ -895,24 +901,6 @@ class EditSettingsScreen extends Component { | |||
895 | } | 901 | } |
896 | } | 902 | } |
897 | 903 | ||
898 | EditSettingsScreen.propTypes = { | ||
899 | stores: PropTypes.shape({ | ||
900 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
901 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
902 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | ||
903 | services: PropTypes.instanceOf(ServicesStore).isRequired, | ||
904 | todos: PropTypes.instanceOf(TodosStore).isRequired, | ||
905 | workspaces: PropTypes.instanceOf(WorkspacesStore).isRequired, | ||
906 | }).isRequired, | ||
907 | actions: PropTypes.shape({ | ||
908 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
909 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
910 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | ||
911 | todos: PropTypes.instanceOf(TodosStore).isRequired, | ||
912 | workspaces: PropTypes.instanceOf(WorkspacesStore).isRequired, | ||
913 | }).isRequired, | ||
914 | }; | ||
915 | |||
916 | export default injectIntl( | 904 | export default injectIntl( |
917 | inject('stores', 'actions')(observer(EditSettingsScreen)), | 905 | inject('stores', 'actions')(observer(EditSettingsScreen)), |
918 | ); | 906 | ); |
diff --git a/src/containers/settings/EditUserScreen.js b/src/containers/settings/EditUserScreen.tsx index baa2d7b71..6ab288d6f 100644 --- a/src/containers/settings/EditUserScreen.js +++ b/src/containers/settings/EditUserScreen.tsx | |||
@@ -1,9 +1,9 @@ | |||
1 | import { Component } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import PropTypes from 'prop-types'; | ||
3 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
4 | import { defineMessages, injectIntl } from 'react-intl'; | 3 | import { defineMessages, injectIntl } from 'react-intl'; |
5 | 4 | ||
6 | import UserStore from '../../stores/UserStore'; | 5 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
6 | import { FormFields } from 'src/@types/mobx-form.types'; | ||
7 | import Form from '../../lib/Form'; | 7 | import Form from '../../lib/Form'; |
8 | import EditUserForm from '../../components/settings/user/EditUserForm'; | 8 | import EditUserForm from '../../components/settings/user/EditUserForm'; |
9 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 9 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
@@ -49,7 +49,11 @@ const messages = defineMessages({ | |||
49 | }, | 49 | }, |
50 | }); | 50 | }); |
51 | 51 | ||
52 | class EditUserScreen extends Component { | 52 | interface EditUserScreenProps extends StoresProps { |
53 | intl: any; | ||
54 | } | ||
55 | |||
56 | class EditUserScreen extends Component<EditUserScreenProps> { | ||
53 | componentWillUnmount() { | 57 | componentWillUnmount() { |
54 | this.props.actions.user.resetStatus(); | 58 | this.props.actions.user.resetStatus(); |
55 | } | 59 | } |
@@ -59,13 +63,13 @@ class EditUserScreen extends Component { | |||
59 | 63 | ||
60 | update({ userData }); | 64 | update({ userData }); |
61 | 65 | ||
62 | document.querySelector('#form').scrollIntoView({ behavior: 'smooth' }); | 66 | document.querySelector('#form')?.scrollIntoView({ behavior: 'smooth' }); |
63 | } | 67 | } |
64 | 68 | ||
65 | prepareForm(user) { | 69 | prepareForm(user) { |
66 | const { intl } = this.props; | 70 | const { intl } = this.props; |
67 | 71 | ||
68 | const config = { | 72 | const config: FormFields = { |
69 | fields: { | 73 | fields: { |
70 | firstname: { | 74 | firstname: { |
71 | label: intl.formatMessage(messages.firstname), | 75 | label: intl.formatMessage(messages.firstname), |
@@ -122,10 +126,12 @@ class EditUserScreen extends Component { | |||
122 | }, | 126 | }, |
123 | }; | 127 | }; |
124 | 128 | ||
129 | // @ts-ignore: Remove this ignore once mobx-react-form v4 with typescript | ||
130 | // support has been released. | ||
125 | return new Form(config); | 131 | return new Form(config); |
126 | } | 132 | } |
127 | 133 | ||
128 | render() { | 134 | render(): ReactElement { |
129 | const { user } = this.props.stores; | 135 | const { user } = this.props.stores; |
130 | 136 | ||
131 | if (user.getUserInfoRequest.isExecuting) { | 137 | if (user.getUserInfoRequest.isExecuting) { |
@@ -137,7 +143,6 @@ class EditUserScreen extends Component { | |||
137 | return ( | 143 | return ( |
138 | <ErrorBoundary> | 144 | <ErrorBoundary> |
139 | <EditUserForm | 145 | <EditUserForm |
140 | // user={user.data} | ||
141 | status={user.actionStatus} | 146 | status={user.actionStatus} |
142 | form={form} | 147 | form={form} |
143 | isSaving={user.updateUserInfoRequest.isExecuting} | 148 | isSaving={user.updateUserInfoRequest.isExecuting} |
@@ -148,15 +153,6 @@ class EditUserScreen extends Component { | |||
148 | } | 153 | } |
149 | } | 154 | } |
150 | 155 | ||
151 | EditUserScreen.propTypes = { | 156 | export default injectIntl<'intl', EditUserScreenProps>( |
152 | stores: PropTypes.shape({ | ||
153 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
154 | }).isRequired, | ||
155 | actions: PropTypes.shape({ | ||
156 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
157 | }).isRequired, | ||
158 | }; | ||
159 | |||
160 | export default injectIntl( | ||
161 | inject('stores', 'actions')(observer(EditUserScreen)), | 157 | inject('stores', 'actions')(observer(EditUserScreen)), |
162 | ); | 158 | ); |
diff --git a/src/containers/settings/InviteScreen.js b/src/containers/settings/InviteScreen.tsx index 86723554c..ff192783c 100644 --- a/src/containers/settings/InviteScreen.js +++ b/src/containers/settings/InviteScreen.tsx | |||
@@ -1,17 +1,16 @@ | |||
1 | import { Component } from 'react'; | 1 | import { Component, ReactNode } from 'react'; |
2 | import PropTypes from 'prop-types'; | ||
3 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
4 | 3 | ||
4 | import { StoresProps } from 'src/@types/ferdium-components.types'; | ||
5 | import Invite from '../../components/auth/Invite'; | 5 | import Invite from '../../components/auth/Invite'; |
6 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 6 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
7 | import UserStore from '../../stores/UserStore'; | ||
8 | 7 | ||
9 | class InviteScreen extends Component { | 8 | class InviteScreen extends Component<StoresProps> { |
10 | componentWillUnmount() { | 9 | componentWillUnmount(): void { |
11 | this.props.stores.user.inviteRequest.reset(); | 10 | this.props.stores.user.inviteRequest.reset(); |
12 | } | 11 | } |
13 | 12 | ||
14 | render() { | 13 | render(): ReactNode { |
15 | const { actions } = this.props; | 14 | const { actions } = this.props; |
16 | const { user } = this.props.stores; | 15 | const { user } = this.props.stores; |
17 | 16 | ||
@@ -30,13 +29,4 @@ class InviteScreen extends Component { | |||
30 | } | 29 | } |
31 | } | 30 | } |
32 | 31 | ||
33 | InviteScreen.propTypes = { | ||
34 | actions: PropTypes.shape({ | ||
35 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
36 | }).isRequired, | ||
37 | stores: PropTypes.shape({ | ||
38 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
39 | }).isRequired, | ||
40 | }; | ||
41 | |||
42 | export default inject('stores', 'actions')(observer(InviteScreen)); | 32 | export default inject('stores', 'actions')(observer(InviteScreen)); |
diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.tsx index e8f0a7282..c50ff246e 100644 --- a/src/containers/settings/RecipesScreen.js +++ b/src/containers/settings/RecipesScreen.tsx | |||
@@ -1,14 +1,10 @@ | |||
1 | import { readJsonSync } from 'fs-extra'; | 1 | import { readJsonSync } from 'fs-extra'; |
2 | import { Component } from 'react'; | 2 | import { Component, ReactElement } from 'react'; |
3 | import PropTypes from 'prop-types'; | 3 | import { autorun, IReactionDisposer } from 'mobx'; |
4 | import { autorun } from 'mobx'; | ||
5 | import { inject, observer } from 'mobx-react'; | 4 | import { inject, observer } from 'mobx-react'; |
6 | 5 | ||
7 | import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; | 6 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
8 | import RecipeStore from '../../stores/RecipesStore'; | 7 | import Recipe from 'src/models/Recipe'; |
9 | import ServiceStore from '../../stores/ServicesStore'; | ||
10 | import UserStore from '../../stores/UserStore'; | ||
11 | |||
12 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; | 8 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; |
13 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 9 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
14 | import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config'; | 10 | import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config'; |
@@ -16,38 +12,36 @@ import { userDataRecipesPath } from '../../environment-remote'; | |||
16 | import { asarRecipesPath } from '../../helpers/asar-helpers'; | 12 | import { asarRecipesPath } from '../../helpers/asar-helpers'; |
17 | import { communityRecipesStore } from '../../features/communityRecipes'; | 13 | import { communityRecipesStore } from '../../features/communityRecipes'; |
18 | import RecipePreview from '../../models/RecipePreview'; | 14 | import RecipePreview from '../../models/RecipePreview'; |
19 | import AppStore from '../../stores/AppStore'; | ||
20 | import { openPath } from '../../helpers/url-helpers'; | 15 | import { openPath } from '../../helpers/url-helpers'; |
21 | 16 | ||
22 | class RecipesScreen extends Component { | 17 | interface RecipesScreenProps extends StoresProps { |
23 | static propTypes = { | 18 | params: { |
24 | params: PropTypes.shape({ | 19 | filter?: string | null; |
25 | filter: PropTypes.string, | ||
26 | }), | ||
27 | }; | ||
28 | |||
29 | static defaultProps = { | ||
30 | params: { | ||
31 | filter: null, | ||
32 | }, | ||
33 | }; | 20 | }; |
21 | } | ||
34 | 22 | ||
35 | state = { | 23 | class RecipesScreen extends Component<RecipesScreenProps> { |
24 | state: { | ||
25 | needle: string | null; | ||
26 | currentFilter: string; | ||
27 | } = { | ||
36 | needle: null, | 28 | needle: null, |
37 | currentFilter: 'featured', | 29 | currentFilter: 'featured', |
38 | }; | 30 | }; |
39 | 31 | ||
40 | autorunDisposer = null; | 32 | autorunDisposer: IReactionDisposer | null = null; |
41 | 33 | ||
42 | customRecipes = []; | 34 | customRecipes: Recipe[] = []; |
43 | 35 | ||
44 | constructor(props) { | 36 | constructor(props: RecipesScreenProps) { |
45 | super(props); | 37 | super(props); |
46 | 38 | ||
39 | this.props.params.filter = this.props.params.filter || null; | ||
40 | |||
47 | this.customRecipes = readJsonSync(asarRecipesPath('all.json')); | 41 | this.customRecipes = readJsonSync(asarRecipesPath('all.json')); |
48 | } | 42 | } |
49 | 43 | ||
50 | componentDidMount() { | 44 | componentDidMount(): void { |
51 | this.autorunDisposer = autorun(() => { | 45 | this.autorunDisposer = autorun(() => { |
52 | const { filter } = this.props.params; | 46 | const { filter } = this.props.params; |
53 | const { currentFilter } = this.state; | 47 | const { currentFilter } = this.state; |
@@ -62,12 +56,15 @@ class RecipesScreen extends Component { | |||
62 | }); | 56 | }); |
63 | } | 57 | } |
64 | 58 | ||
65 | componentWillUnmount() { | 59 | componentWillUnmount(): void { |
66 | this.props.stores.services.resetStatus(); | 60 | this.props.stores.services.resetStatus(); |
67 | this.autorunDisposer(); | 61 | |
62 | if (typeof this.autorunDisposer === 'function') { | ||
63 | this.autorunDisposer(); | ||
64 | } | ||
68 | } | 65 | } |
69 | 66 | ||
70 | searchRecipes(needle) { | 67 | searchRecipes(needle: string | null): void { |
71 | if (needle === '') { | 68 | if (needle === '') { |
72 | this.resetSearch(); | 69 | this.resetSearch(); |
73 | } else { | 70 | } else { |
@@ -77,7 +74,7 @@ class RecipesScreen extends Component { | |||
77 | } | 74 | } |
78 | } | 75 | } |
79 | 76 | ||
80 | _sortByName(recipe1, recipe2) { | 77 | _sortByName(recipe1, recipe2): number { |
81 | if (recipe1.name.toLowerCase() < recipe2.name.toLowerCase()) { | 78 | if (recipe1.name.toLowerCase() < recipe2.name.toLowerCase()) { |
82 | return -1; | 79 | return -1; |
83 | } | 80 | } |
@@ -87,7 +84,7 @@ class RecipesScreen extends Component { | |||
87 | return 0; | 84 | return 0; |
88 | } | 85 | } |
89 | 86 | ||
90 | prepareRecipes(recipes) { | 87 | prepareRecipes(recipes: RecipePreview[]): RecipePreview[] { |
91 | return ( | 88 | return ( |
92 | recipes | 89 | recipes |
93 | // Filter out duplicate recipes | 90 | // Filter out duplicate recipes |
@@ -102,15 +99,15 @@ class RecipesScreen extends Component { | |||
102 | } | 99 | } |
103 | 100 | ||
104 | // Create an array of RecipePreviews from an array of recipe objects | 101 | // Create an array of RecipePreviews from an array of recipe objects |
105 | createPreviews(recipes) { | 102 | createPreviews(recipes: Recipe[]) { |
106 | return recipes.map(recipe => new RecipePreview(recipe)); | 103 | return recipes.map((recipe: any) => new RecipePreview(recipe)); |
107 | } | 104 | } |
108 | 105 | ||
109 | resetSearch() { | 106 | resetSearch(): void { |
110 | this.setState({ needle: null }); | 107 | this.setState({ needle: null }); |
111 | } | 108 | } |
112 | 109 | ||
113 | render() { | 110 | render(): ReactElement { |
114 | const { recipePreviews, recipes, services } = this.props.stores; | 111 | const { recipePreviews, recipes, services } = this.props.stores; |
115 | 112 | ||
116 | const { app: appActions, service: serviceActions } = this.props.actions; | 113 | const { app: appActions, service: serviceActions } = this.props.actions; |
@@ -130,33 +127,34 @@ class RecipesScreen extends Component { | |||
130 | } | 127 | } |
131 | recipeFilter = recipeFilter.sort(this._sortByName); | 128 | recipeFilter = recipeFilter.sort(this._sortByName); |
132 | 129 | ||
133 | const allRecipes = this.state.needle | 130 | const { needle } = this.state; |
134 | ? this.prepareRecipes([ | 131 | const allRecipes = |
135 | // All search recipes from server | 132 | needle !== null |
136 | ...recipePreviews.searchResults, | 133 | ? this.prepareRecipes([ |
137 | // All search recipes from local recipes | 134 | // All search recipes from server |
138 | ...this.createPreviews( | 135 | ...recipePreviews.searchResults, |
139 | this.customRecipes.filter( | 136 | // All search recipes from local recipes |
140 | service => | 137 | ...this.createPreviews( |
141 | service.name | 138 | this.customRecipes.filter( |
142 | .toLowerCase() | 139 | (recipe: Recipe) => |
143 | .includes(this.state.needle.toLowerCase()) || | 140 | recipe.name.toLowerCase().includes(needle.toLowerCase()) || |
144 | (service.aliases || []).some(alias => | 141 | (recipe.aliases || []).some(alias => |
145 | alias.toLowerCase().includes(this.state.needle.toLowerCase()), | 142 | alias.toLowerCase().includes(needle.toLowerCase()), |
146 | ), | 143 | ), |
144 | ), | ||
147 | ), | 145 | ), |
148 | ), | 146 | ]).sort(this._sortByName) |
149 | ]).sort(this._sortByName) | 147 | : recipeFilter; |
150 | : recipeFilter; | ||
151 | 148 | ||
152 | const customWebsiteRecipe = recipePreviews.all.find( | 149 | const customWebsiteRecipe = recipePreviews.all.find( |
153 | service => service.id === CUSTOM_WEBSITE_RECIPE_ID, | 150 | service => service.id === CUSTOM_WEBSITE_RECIPE_ID, |
154 | ); | 151 | ); |
155 | 152 | ||
156 | const isLoading = recipePreviews.featuredRecipePreviewsRequest.isExecuting | 153 | const isLoading = |
157 | || recipePreviews.allRecipePreviewsRequest.isExecuting | 154 | recipePreviews.featuredRecipePreviewsRequest.isExecuting || |
158 | || recipes.installRecipeRequest.isExecuting | 155 | recipePreviews.allRecipePreviewsRequest.isExecuting || |
159 | || recipePreviews.searchRecipePreviewsRequest.isExecuting; | 156 | recipes.installRecipeRequest.isExecuting || |
157 | recipePreviews.searchRecipePreviewsRequest.isExecuting; | ||
160 | 158 | ||
161 | const recipeDirectory = userDataRecipesPath('dev'); | 159 | const recipeDirectory = userDataRecipesPath('dev'); |
162 | 160 | ||
@@ -167,7 +165,9 @@ class RecipesScreen extends Component { | |||
167 | customWebsiteRecipe={customWebsiteRecipe} | 165 | customWebsiteRecipe={customWebsiteRecipe} |
168 | isLoading={isLoading} | 166 | isLoading={isLoading} |
169 | addedServiceCount={services.all.length} | 167 | addedServiceCount={services.all.length} |
170 | hasLoadedRecipes={recipePreviews.featuredRecipePreviewsRequest.wasExecuted} | 168 | hasLoadedRecipes={ |
169 | recipePreviews.featuredRecipePreviewsRequest.wasExecuted | ||
170 | } | ||
171 | showAddServiceInterface={serviceActions.showAddServiceInterface} | 171 | showAddServiceInterface={serviceActions.showAddServiceInterface} |
172 | searchRecipes={e => this.searchRecipes(e)} | 172 | searchRecipes={e => this.searchRecipes(e)} |
173 | resetSearch={() => this.resetSearch()} | 173 | resetSearch={() => this.resetSearch()} |
@@ -185,20 +185,4 @@ class RecipesScreen extends Component { | |||
185 | } | 185 | } |
186 | } | 186 | } |
187 | 187 | ||
188 | RecipesScreen.propTypes = { | ||
189 | stores: PropTypes.shape({ | ||
190 | recipePreviews: PropTypes.instanceOf(RecipePreviewsStore).isRequired, | ||
191 | recipes: PropTypes.instanceOf(RecipeStore).isRequired, | ||
192 | services: PropTypes.instanceOf(ServiceStore).isRequired, | ||
193 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
194 | }).isRequired, | ||
195 | actions: PropTypes.shape({ | ||
196 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
197 | service: PropTypes.instanceOf(ServiceStore).isRequired, | ||
198 | recipePreview: PropTypes.shape({ | ||
199 | search: PropTypes.func.isRequired, | ||
200 | }).isRequired, | ||
201 | }).isRequired, | ||
202 | }; | ||
203 | |||
204 | export default inject('stores', 'actions')(observer(RecipesScreen)); | 188 | export default inject('stores', 'actions')(observer(RecipesScreen)); |
diff --git a/src/containers/settings/ServicesScreen.js b/src/containers/settings/ServicesScreen.tsx index 2970b2a54..615747382 100644 --- a/src/containers/settings/ServicesScreen.js +++ b/src/containers/settings/ServicesScreen.tsx | |||
@@ -1,27 +1,22 @@ | |||
1 | import { Component } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import PropTypes from 'prop-types'; | ||
3 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
4 | import { RouterStore } from 'mobx-react-router'; | ||
5 | |||
6 | // import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; | ||
7 | import UserStore from '../../stores/UserStore'; | ||
8 | import ServiceStore from '../../stores/ServicesStore'; | ||
9 | 3 | ||
4 | import { StoresProps } from 'src/@types/ferdium-components.types'; | ||
10 | import ServicesDashboard from '../../components/settings/services/ServicesDashboard'; | 5 | import ServicesDashboard from '../../components/settings/services/ServicesDashboard'; |
11 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 6 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
12 | 7 | ||
13 | class ServicesScreen extends Component { | 8 | class ServicesScreen extends Component<StoresProps> { |
14 | componentWillUnmount() { | 9 | componentWillUnmount(): void { |
15 | this.props.actions.service.resetFilter(); | 10 | this.props.actions.service.resetFilter(); |
16 | this.props.actions.service.resetStatus(); | 11 | this.props.actions.service.resetStatus(); |
17 | } | 12 | } |
18 | 13 | ||
19 | deleteService() { | 14 | deleteService(): void { |
20 | this.props.actions.service.deleteService(); | 15 | this.props.actions.service.deleteService(); |
21 | this.props.stores.services.resetFilter(); | 16 | this.props.actions.service.resetFilter(); |
22 | } | 17 | } |
23 | 18 | ||
24 | render() { | 19 | render(): ReactElement { |
25 | const { user, services, router } = this.props.stores; | 20 | const { user, services, router } = this.props.stores; |
26 | const { toggleService, filter, resetFilter } = this.props.actions.service; | 21 | const { toggleService, filter, resetFilter } = this.props.actions.service; |
27 | const isLoading = services.allServicesRequest.isExecuting; | 22 | const isLoading = services.allServicesRequest.isExecuting; |
@@ -55,15 +50,4 @@ class ServicesScreen extends Component { | |||
55 | } | 50 | } |
56 | } | 51 | } |
57 | 52 | ||
58 | ServicesScreen.propTypes = { | ||
59 | stores: PropTypes.shape({ | ||
60 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
61 | services: PropTypes.instanceOf(ServiceStore).isRequired, | ||
62 | router: PropTypes.instanceOf(RouterStore).isRequired, | ||
63 | }).isRequired, | ||
64 | actions: PropTypes.shape({ | ||
65 | service: PropTypes.instanceOf(ServiceStore).isRequired, | ||
66 | }).isRequired, | ||
67 | }; | ||
68 | |||
69 | export default inject('stores', 'actions')(observer(ServicesScreen)); | 53 | export default inject('stores', 'actions')(observer(ServicesScreen)); |
diff --git a/src/containers/settings/SettingsWindow.js b/src/containers/settings/SettingsWindow.tsx index 0e6ce4df3..fb1e2fd2d 100644 --- a/src/containers/settings/SettingsWindow.js +++ b/src/containers/settings/SettingsWindow.tsx | |||
@@ -1,30 +1,39 @@ | |||
1 | import { Component } from 'react'; | 1 | import { Component, ReactNode, ReactPortal } from 'react'; |
2 | import ReactDOM from 'react-dom'; | 2 | import ReactDOM from 'react-dom'; |
3 | import PropTypes from 'prop-types'; | ||
4 | import { observer, inject } from 'mobx-react'; | 3 | import { observer, inject } from 'mobx-react'; |
5 | 4 | ||
6 | import ServicesStore from '../../stores/ServicesStore'; | 5 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
7 | 6 | ||
8 | import Layout from '../../components/settings/SettingsLayout'; | 7 | import Layout from '../../components/settings/SettingsLayout'; |
9 | import Navigation from '../../components/settings/navigation/SettingsNavigation'; | 8 | import Navigation from '../../components/settings/navigation/SettingsNavigation'; |
10 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 9 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
11 | import { workspaceStore } from '../../features/workspaces'; | 10 | import { workspaceStore } from '../../features/workspaces'; |
12 | import UIStore from '../../stores/UIStore'; | ||
13 | 11 | ||
14 | class SettingsContainer extends Component { | 12 | interface SettingsContainerProps extends StoresProps { |
15 | portalRoot = document.querySelector('#portalContainer'); | 13 | children: ReactNode; |
14 | } | ||
15 | |||
16 | class SettingsContainer extends Component<SettingsContainerProps> { | ||
17 | portalRoot: any; | ||
18 | |||
19 | el: HTMLDivElement; | ||
16 | 20 | ||
17 | el = document.createElement('div'); | 21 | constructor(props: SettingsContainerProps) { |
22 | super(props); | ||
18 | 23 | ||
19 | componentDidMount() { | 24 | this.portalRoot = document.querySelector('#portalContainer'); |
25 | this.el = document.createElement('div'); | ||
26 | } | ||
27 | |||
28 | componentDidMount(): void { | ||
20 | this.portalRoot.append(this.el); | 29 | this.portalRoot.append(this.el); |
21 | } | 30 | } |
22 | 31 | ||
23 | componentWillUnmount() { | 32 | componentWillUnmount(): void { |
24 | this.el.remove(); | 33 | this.el.remove(); |
25 | } | 34 | } |
26 | 35 | ||
27 | render() { | 36 | render(): ReactPortal { |
28 | const { children, stores } = this.props; | 37 | const { children, stores } = this.props; |
29 | const { closeSettings } = this.props.actions.ui; | 38 | const { closeSettings } = this.props.actions.ui; |
30 | 39 | ||
@@ -46,14 +55,4 @@ class SettingsContainer extends Component { | |||
46 | } | 55 | } |
47 | } | 56 | } |
48 | 57 | ||
49 | SettingsContainer.propTypes = { | ||
50 | children: PropTypes.element.isRequired, | ||
51 | stores: PropTypes.shape({ | ||
52 | services: PropTypes.instanceOf(ServicesStore).isRequired, | ||
53 | }).isRequired, | ||
54 | actions: PropTypes.shape({ | ||
55 | ui: PropTypes.instanceOf(UIStore).isRequired, | ||
56 | }).isRequired, | ||
57 | }; | ||
58 | |||
59 | export default inject('stores', 'actions')(observer(SettingsContainer)); | 58 | export default inject('stores', 'actions')(observer(SettingsContainer)); |
diff --git a/src/containers/settings/TeamScreen.js b/src/containers/settings/TeamScreen.tsx index 0a8b92b47..5e5223f67 100644 --- a/src/containers/settings/TeamScreen.js +++ b/src/containers/settings/TeamScreen.tsx | |||
@@ -1,17 +1,14 @@ | |||
1 | import { Component } from 'react'; | 1 | import { Component, ReactElement } from 'react'; |
2 | import PropTypes from 'prop-types'; | ||
3 | import { inject, observer } from 'mobx-react'; | 2 | import { inject, observer } from 'mobx-react'; |
4 | 3 | ||
5 | import UserStore from '../../stores/UserStore'; | 4 | import { StoresProps } from 'src/@types/ferdium-components.types'; |
6 | import AppStore from '../../stores/AppStore'; | ||
7 | import SettingsStore from '../../stores/SettingsStore'; | ||
8 | 5 | ||
9 | import TeamDashboard from '../../components/settings/team/TeamDashboard'; | 6 | import TeamDashboard from '../../components/settings/team/TeamDashboard'; |
10 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 7 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
11 | import { DEV_API_FRANZ_WEBSITE } from '../../config'; | 8 | import { DEV_API_FRANZ_WEBSITE } from '../../config'; |
12 | 9 | ||
13 | class TeamScreen extends Component { | 10 | class TeamScreen extends Component<StoresProps> { |
14 | handleWebsiteLink(route) { | 11 | handleWebsiteLink(route: string): void { |
15 | const { actions, stores } = this.props; | 12 | const { actions, stores } = this.props; |
16 | 13 | ||
17 | const url = `${DEV_API_FRANZ_WEBSITE}/${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; | 14 | const url = `${DEV_API_FRANZ_WEBSITE}/${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; |
@@ -19,7 +16,13 @@ class TeamScreen extends Component { | |||
19 | actions.app.openExternalUrl({ url }); | 16 | actions.app.openExternalUrl({ url }); |
20 | } | 17 | } |
21 | 18 | ||
22 | render() { | 19 | reloadData(): void { |
20 | const { user } = this.props.stores; | ||
21 | |||
22 | user.getUserInfoRequest.reload(); | ||
23 | } | ||
24 | |||
25 | render(): ReactElement { | ||
23 | const { user, settings } = this.props.stores; | 26 | const { user, settings } = this.props.stores; |
24 | 27 | ||
25 | const isLoadingUserInfo = user.getUserInfoRequest.isExecuting; | 28 | const isLoadingUserInfo = user.getUserInfoRequest.isExecuting; |
@@ -42,16 +45,4 @@ class TeamScreen extends Component { | |||
42 | } | 45 | } |
43 | } | 46 | } |
44 | 47 | ||
45 | TeamScreen.propTypes = { | ||
46 | stores: PropTypes.shape({ | ||
47 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
48 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
49 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | ||
50 | }).isRequired, | ||
51 | actions: PropTypes.shape({ | ||
52 | app: PropTypes.instanceOf(AppStore).isRequired, | ||
53 | user: PropTypes.instanceOf(UserStore).isRequired, | ||
54 | }).isRequired, | ||
55 | }; | ||
56 | |||
57 | export default inject('stores', 'actions')(observer(TeamScreen)); | 48 | export default inject('stores', 'actions')(observer(TeamScreen)); |
diff --git a/src/helpers/i18n-helpers.ts b/src/helpers/i18n-helpers.ts index 9d48a0cf7..a5d909a4a 100644 --- a/src/helpers/i18n-helpers.ts +++ b/src/helpers/i18n-helpers.ts | |||
@@ -24,7 +24,7 @@ export function getSelectOptions({ | |||
24 | resetToDefaultText = '', | 24 | resetToDefaultText = '', |
25 | automaticDetectionText = '', | 25 | automaticDetectionText = '', |
26 | sort = true, | 26 | sort = true, |
27 | addDefault=false, | 27 | addDefault = false, |
28 | }) { | 28 | }) { |
29 | const options: object[] = []; | 29 | const options: object[] = []; |
30 | 30 | ||
diff --git a/src/models/Service.ts b/src/models/Service.ts index dfc074204..35d573cab 100644 --- a/src/models/Service.ts +++ b/src/models/Service.ts | |||
@@ -14,6 +14,12 @@ import { IRecipe } from './Recipe'; | |||
14 | 14 | ||
15 | const debug = require('../preload-safe-debug')('Ferdium:Service'); | 15 | const debug = require('../preload-safe-debug')('Ferdium:Service'); |
16 | 16 | ||
17 | interface DarkReaderInterface { | ||
18 | brightness: number; | ||
19 | contrast: number; | ||
20 | sepia: number; | ||
21 | } | ||
22 | |||
17 | // TODO: Shouldn't most of these values default to what's defined in DEFAULT_SERVICE_SETTINGS? | 23 | // TODO: Shouldn't most of these values default to what's defined in DEFAULT_SERVICE_SETTINGS? |
18 | export default class Service { | 24 | export default class Service { |
19 | id: string = ''; | 25 | id: string = ''; |
@@ -68,7 +74,7 @@ export default class Service { | |||
68 | 74 | ||
69 | @observable isProgressbarEnabled: boolean = true; | 75 | @observable isProgressbarEnabled: boolean = true; |
70 | 76 | ||
71 | @observable darkReaderSettings: object = { | 77 | @observable darkReaderSettings: DarkReaderInterface = { |
72 | brightness: 100, | 78 | brightness: 100, |
73 | contrast: 90, | 79 | contrast: 90, |
74 | sepia: 10, | 80 | sepia: 10, |
@@ -158,7 +164,7 @@ export default class Service { | |||
158 | data.isDarkModeEnabled, | 164 | data.isDarkModeEnabled, |
159 | this.isDarkModeEnabled, | 165 | this.isDarkModeEnabled, |
160 | ); | 166 | ); |
161 | this.darkReaderSettings = ifUndefined<object>( | 167 | this.darkReaderSettings = ifUndefined<DarkReaderInterface>( |
162 | data.darkReaderSettings, | 168 | data.darkReaderSettings, |
163 | this.darkReaderSettings, | 169 | this.darkReaderSettings, |
164 | ); | 170 | ); |
@@ -309,7 +315,7 @@ export default class Service { | |||
309 | this.userAgentModel.userAgentPref = pref; | 315 | this.userAgentModel.userAgentPref = pref; |
310 | } | 316 | } |
311 | 317 | ||
312 | @computed get defaultUserAgent(): String { | 318 | @computed get defaultUserAgent(): string { |
313 | return this.userAgentModel.defaultUserAgent; | 319 | return this.userAgentModel.defaultUserAgent; |
314 | } | 320 | } |
315 | 321 | ||
diff --git a/src/stores/AppStore.ts b/src/stores/AppStore.ts index 05acbf33d..a949bae1d 100644 --- a/src/stores/AppStore.ts +++ b/src/stores/AppStore.ts | |||
@@ -94,6 +94,10 @@ export default class AppStore extends TypedStore { | |||
94 | 94 | ||
95 | @observable isFocused = true; | 95 | @observable isFocused = true; |
96 | 96 | ||
97 | @observable lockingFeatureEnabled = false; | ||
98 | |||
99 | @observable launchInBackground = false; | ||
100 | |||
97 | dictionaries = []; | 101 | dictionaries = []; |
98 | 102 | ||
99 | fetchDataInterval: null | NodeJS.Timer = null; | 103 | fetchDataInterval: null | NodeJS.Timer = null; |
diff --git a/src/stores/RecipePreviewsStore.ts b/src/stores/RecipePreviewsStore.ts index 099867785..ad9fda4a7 100644 --- a/src/stores/RecipePreviewsStore.ts +++ b/src/stores/RecipePreviewsStore.ts | |||
@@ -4,6 +4,7 @@ import { ApiInterface } from 'src/api'; | |||
4 | import Recipe from 'src/models/Recipe'; | 4 | import Recipe from 'src/models/Recipe'; |
5 | import { Stores } from 'src/@types/stores.types'; | 5 | import { Stores } from 'src/@types/stores.types'; |
6 | 6 | ||
7 | import RecipePreview from 'src/models/RecipePreview'; | ||
7 | import CachedRequest from './lib/CachedRequest'; | 8 | import CachedRequest from './lib/CachedRequest'; |
8 | import Request from './lib/Request'; | 9 | import Request from './lib/Request'; |
9 | import TypedStore from './lib/TypedStore'; | 10 | import TypedStore from './lib/TypedStore'; |
@@ -35,15 +36,15 @@ export default class RecipePreviewsStore extends TypedStore { | |||
35 | // Not implemented | 36 | // Not implemented |
36 | } | 37 | } |
37 | 38 | ||
38 | @computed get all(): Recipe[] { | 39 | @computed get all(): RecipePreview[] { |
39 | return this.allRecipePreviewsRequest.execute().result || []; | 40 | return this.allRecipePreviewsRequest.execute().result || []; |
40 | } | 41 | } |
41 | 42 | ||
42 | @computed get featured(): Recipe[] { | 43 | @computed get featured(): RecipePreview[] { |
43 | return this.featuredRecipePreviewsRequest.execute().result || []; | 44 | return this.featuredRecipePreviewsRequest.execute().result || []; |
44 | } | 45 | } |
45 | 46 | ||
46 | @computed get searchResults(): Recipe[] { | 47 | @computed get searchResults(): RecipePreview[] { |
47 | return this.searchRecipePreviewsRequest.result || []; | 48 | return this.searchRecipePreviewsRequest.result || []; |
48 | } | 49 | } |
49 | 50 | ||