aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/@types/ferdium-components.types.ts6
-rw-r--r--src/@types/ferdium.types.ts2
-rw-r--r--src/I18n.tsx1
-rw-r--r--src/api/apiBase.ts3
-rw-r--r--src/api/server/ServerApi.ts4
-rw-r--r--src/app.jsx12
-rw-r--r--src/components/auth/Import.js2
-rw-r--r--src/components/auth/Invite.js2
-rw-r--r--src/components/auth/Login.js2
-rw-r--r--src/components/auth/Welcome.jsx (renamed from src/components/auth/Welcome.js)7
-rw-r--r--src/components/layout/AppLayout.js9
-rw-r--r--src/components/services/content/ServiceWebview.js4
-rw-r--r--src/components/services/content/Services.jsx (renamed from src/components/services/content/Services.js)20
-rw-r--r--src/components/services/tabs/TabItem.js5
-rw-r--r--src/components/settings/SettingsLayout.jsx (renamed from src/components/settings/SettingsLayout.js)8
-rw-r--r--src/components/settings/navigation/SettingsNavigation.jsx (renamed from src/components/settings/navigation/SettingsNavigation.js)96
-rw-r--r--src/components/settings/recipes/RecipesDashboard.jsx (renamed from src/components/settings/recipes/RecipesDashboard.js)67
-rw-r--r--src/components/settings/services/EditServiceForm.js2
-rw-r--r--src/components/settings/services/ServiceError.js2
-rw-r--r--src/components/settings/services/ServicesDashboard.js5
-rw-r--r--src/components/settings/user/EditUserForm.js2
-rw-r--r--src/components/ui/Link.js2
-rw-r--r--src/components/ui/button/index.tsx22
-rw-r--r--src/components/ui/infobox/index.tsx4
-rw-r--r--src/components/ui/select/index.tsx15
-rw-r--r--src/components/ui/textarea/index.tsx2
-rw-r--r--src/components/ui/toggle/index.tsx4
-rw-r--r--src/components/util/ErrorBoundary/index.tsx3
-rw-r--r--src/components/util/WithParams.tsx8
-rw-r--r--src/containers/auth/AuthLayoutContainer.tsx15
-rw-r--r--src/containers/layout/AppLayoutContainer.tsx12
-rw-r--r--src/containers/settings/EditServiceScreen.tsx30
-rw-r--r--src/containers/settings/RecipesScreen.tsx17
-rw-r--r--src/containers/settings/SettingsWindow.tsx19
-rw-r--r--src/electron/Settings.ts4
-rw-r--r--src/features/communityRecipes/store.ts4
-rw-r--r--src/features/todos/store.js8
-rw-r--r--src/features/webControls/containers/WebControlsScreen.js8
-rw-r--r--src/features/workspaces/components/EditWorkspaceForm.js2
-rw-r--r--src/features/workspaces/components/WorkspaceDrawer.jsx (renamed from src/features/workspaces/components/WorkspaceDrawer.js)4
-rw-r--r--src/features/workspaces/containers/EditWorkspaceScreen.tsx13
-rw-r--r--src/features/workspaces/containers/WorkspacesScreen.tsx10
-rw-r--r--src/features/workspaces/models/Workspace.ts4
-rw-r--r--src/features/workspaces/store.js8
-rw-r--r--src/index.ts1
-rw-r--r--src/lib/Menu.js4
-rw-r--r--src/models/Service.ts4
-rw-r--r--src/models/User.ts4
-rw-r--r--src/models/UserAgent.ts4
-rw-r--r--src/routes.tsx159
-rw-r--r--src/stores/AppStore.ts6
-rw-r--r--src/stores/FeaturesStore.ts25
-rw-r--r--src/stores/GlobalErrorStore.ts4
-rw-r--r--src/stores/RecipePreviewsStore.ts5
-rw-r--r--src/stores/RecipesStore.ts4
-rw-r--r--src/stores/RequestStore.ts4
-rw-r--r--src/stores/ServicesStore.ts4
-rw-r--r--src/stores/SettingsStore.ts7
-rw-r--r--src/stores/UIStore.ts5
-rw-r--r--src/stores/UserStore.ts4
-rw-r--r--src/stores/index.ts2
-rw-r--r--src/stores/lib/Request.js4
-rw-r--r--src/stores/lib/TypedStore.ts20
-rw-r--r--src/webview/recipe.js4
64 files changed, 461 insertions, 292 deletions
diff --git a/src/@types/ferdium-components.types.ts b/src/@types/ferdium-components.types.ts
index 03cfdc3b7..516ef9dd7 100644
--- a/src/@types/ferdium-components.types.ts
+++ b/src/@types/ferdium-components.types.ts
@@ -7,7 +7,7 @@ export interface StoresProps {
7} 7}
8 8
9export interface GlobalError { 9export interface GlobalError {
10 status: number; 10 status?: number;
11 message: string; 11 message?: string;
12 code: string; 12 code?: string;
13} 13}
diff --git a/src/@types/ferdium.types.ts b/src/@types/ferdium.types.ts
index 0747f8e14..db8711cd3 100644
--- a/src/@types/ferdium.types.ts
+++ b/src/@types/ferdium.types.ts
@@ -19,4 +19,4 @@ declare global {
19 * Workaround to make TS recognize this file as a module. 19 * Workaround to make TS recognize this file as a module.
20 * https://fettblog.eu/typescript-augmenting-global-lib-dom/ 20 * https://fettblog.eu/typescript-augmenting-global-lib-dom/
21 */ 21 */
22export { }; 22export {};
diff --git a/src/I18n.tsx b/src/I18n.tsx
index 5f725eebc..1a69ed1a2 100644
--- a/src/I18n.tsx
+++ b/src/I18n.tsx
@@ -24,6 +24,7 @@ class I18N extends Component<Props> {
24 render(): ReactNode { 24 render(): ReactNode {
25 const { stores, children } = this.props; 25 const { stores, children } = this.props;
26 const { locale } = stores.app; 26 const { locale } = stores.app;
27
27 return ( 28 return (
28 <IntlProvider 29 <IntlProvider
29 {...{ locale, key: locale, messages: translations[locale] }} 30 {...{ locale, key: locale, messages: translations[locale] }}
diff --git a/src/api/apiBase.ts b/src/api/apiBase.ts
index 918213542..701919785 100644
--- a/src/api/apiBase.ts
+++ b/src/api/apiBase.ts
@@ -23,6 +23,7 @@ export default function apiBase(withVersion = true) {
23 // Stores have not yet been loaded - return SERVER_NOT_LOADED to force a retry when stores are loaded 23 // Stores have not yet been loaded - return SERVER_NOT_LOADED to force a retry when stores are loaded
24 return SERVER_NOT_LOADED; 24 return SERVER_NOT_LOADED;
25 } 25 }
26
26 const url = 27 const url =
27 (window as any).ferdium.stores.settings.all.app.server === LOCAL_SERVER 28 (window as any).ferdium.stores.settings.all.app.server === LOCAL_SERVER
28 ? `http://${LOCAL_HOSTNAME}:${ 29 ? `http://${LOCAL_HOSTNAME}:${
@@ -34,7 +35,6 @@ export default function apiBase(withVersion = true) {
34}; 35};
35 36
36export function serverBase() { 37export function serverBase() {
37
38 const serverType = (window as any).ferdium.stores.settings.all.app.server; 38 const serverType = (window as any).ferdium.stores.settings.all.app.server;
39 const noServer = 'You are using Ferdium without a server'; 39 const noServer = 'You are using Ferdium without a server';
40 40
@@ -54,7 +54,6 @@ export function serverBase() {
54} 54}
55 55
56export function serverName(): string { 56export function serverName(): string {
57
58 const serverType = (window as any).ferdium.stores.settings.all.app.server; 57 const serverType = (window as any).ferdium.stores.settings.all.app.server;
59 const noServer = 'You are using Ferdium without a server'; 58 const noServer = 'You are using Ferdium without a server';
60 59
diff --git a/src/api/server/ServerApi.ts b/src/api/server/ServerApi.ts
index a636f3e0d..77a759b3e 100644
--- a/src/api/server/ServerApi.ts
+++ b/src/api/server/ServerApi.ts
@@ -291,6 +291,10 @@ export default class ServerApi {
291 291
292 // Features 292 // Features
293 async getDefaultFeatures() { 293 async getDefaultFeatures() {
294 if (apiBase() === SERVER_NOT_LOADED) {
295 throw new Error('Server not loaded');
296 }
297
294 const request = await sendAuthRequest(`${apiBase()}/features/default`); 298 const request = await sendAuthRequest(`${apiBase()}/features/default`);
295 if (!request.ok) { 299 if (!request.ok) {
296 throw new Error(request.statusText); 300 throw new Error(request.statusText);
diff --git a/src/app.jsx b/src/app.jsx
index db0dee392..87297c664 100644
--- a/src/app.jsx
+++ b/src/app.jsx
@@ -2,8 +2,8 @@ import { webFrame } from 'electron';
2 2
3import { render } from 'react-dom'; 3import { render } from 'react-dom';
4import { Provider } from 'mobx-react'; 4import { Provider } from 'mobx-react';
5import { syncHistoryWithStore, RouterStore } from 'mobx-react-router'; 5import { RouterStore } from '@superwf/mobx-react-router';
6import { hashHistory } from 'react-router'; 6import { createHashHistory } from 'history';
7 7
8import ServerApi from './api/server/ServerApi'; 8import ServerApi from './api/server/ServerApi';
9import LocalApi from './api/server/LocalApi'; 9import LocalApi from './api/server/LocalApi';
@@ -14,7 +14,7 @@ import MenuFactory from './lib/Menu';
14import TouchBarFactory from './lib/TouchBar'; 14import TouchBarFactory from './lib/TouchBar';
15 15
16import I18N from './I18n'; 16import I18N from './I18n';
17import Routes from './routes'; 17import FerdiumRoutes from './routes';
18 18
19// Basic electron Setup 19// Basic electron Setup
20webFrame.setVisualZoomLevelLimits(1, 1); 20webFrame.setVisualZoomLevelLimits(1, 1);
@@ -22,9 +22,9 @@ webFrame.setVisualZoomLevelLimits(1, 1);
22window.addEventListener('load', () => { 22window.addEventListener('load', () => {
23 const serverApi = new ServerApi(); 23 const serverApi = new ServerApi();
24 const api = apiFactory(serverApi, new LocalApi()); 24 const api = apiFactory(serverApi, new LocalApi());
25 const router = new RouterStore(); 25 const history = createHashHistory();
26 const router = new RouterStore(history);
26 const stores = storeFactory(api, actions, router); 27 const stores = storeFactory(api, actions, router);
27 const history = syncHistoryWithStore(hashHistory, router);
28 const menu = new MenuFactory(stores, actions); 28 const menu = new MenuFactory(stores, actions);
29 const touchBar = new TouchBarFactory(stores, actions); 29 const touchBar = new TouchBarFactory(stores, actions);
30 30
@@ -39,7 +39,7 @@ window.addEventListener('load', () => {
39 const preparedApp = ( 39 const preparedApp = (
40 <Provider stores={stores} actions={actions}> 40 <Provider stores={stores} actions={actions}>
41 <I18N stores={{ app: stores.app, user: stores.user }}> 41 <I18N stores={{ app: stores.app, user: stores.user }}>
42 <Routes history={history} /> 42 <FerdiumRoutes history={history} />
43 </I18N> 43 </I18N>
44 </Provider> 44 </Provider>
45 ); 45 );
diff --git a/src/components/auth/Import.js b/src/components/auth/Import.js
index e43be07a8..41b887974 100644
--- a/src/components/auth/Import.js
+++ b/src/components/auth/Import.js
@@ -2,7 +2,7 @@ import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, injectIntl } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { Link } from 'react-router'; 5import { Link } from 'react-router-dom';
6import classnames from 'classnames'; 6import classnames from 'classnames';
7 7
8import Form from '../../lib/Form'; 8import Form from '../../lib/Form';
diff --git a/src/components/auth/Invite.js b/src/components/auth/Invite.js
index 8e1ab514e..9eca924cd 100644
--- a/src/components/auth/Invite.js
+++ b/src/components/auth/Invite.js
@@ -2,7 +2,7 @@ import { Component, Fragment } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, injectIntl } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { Link } from 'react-router'; 5import { Link } from 'react-router-dom';
6import classnames from 'classnames'; 6import classnames from 'classnames';
7 7
8import Infobox from '../ui/Infobox'; 8import Infobox from '../ui/Infobox';
diff --git a/src/components/auth/Login.js b/src/components/auth/Login.js
index 3de576ca6..eb184f1ee 100644
--- a/src/components/auth/Login.js
+++ b/src/components/auth/Login.js
@@ -178,7 +178,7 @@ class Login extends Component {
178 <Link to={signupRoute}> 178 <Link to={signupRoute}>
179 {intl.formatMessage(messages.signupLink)} 179 {intl.formatMessage(messages.signupLink)}
180 </Link> 180 </Link>
181 <Link 181 <Link
182 // to={passwordRoute} // TODO: Uncomment this line after fixing password recovery in-app 182 // to={passwordRoute} // TODO: Uncomment this line after fixing password recovery in-app
183 to={`${serverBase()}/user/forgot`} // TODO: Remove this line after fixing password recovery in-app 183 to={`${serverBase()}/user/forgot`} // TODO: Remove this line after fixing password recovery in-app
184 target='_blank' // TODO: Remove this line after fixing password recovery in-app 184 target='_blank' // TODO: Remove this line after fixing password recovery in-app
diff --git a/src/components/auth/Welcome.js b/src/components/auth/Welcome.jsx
index c9d592a88..c784b75c3 100644
--- a/src/components/auth/Welcome.js
+++ b/src/components/auth/Welcome.jsx
@@ -25,7 +25,7 @@ const messages = defineMessages({
25 }, 25 },
26 changeServer: { 26 changeServer: {
27 id: 'login.changeServer', 27 id: 'login.changeServer',
28 defaultMessage: 'Change here!' 28 defaultMessage: 'Change here!',
29 }, 29 },
30 serverless: { 30 serverless: {
31 id: 'services.serverless', 31 id: 'services.serverless',
@@ -65,7 +65,6 @@ class Welcome extends Component {
65 className="welcome__logo" 65 className="welcome__logo"
66 alt="" 66 alt=""
67 /> 67 />
68 {/* <img src="./assets/images/welcome.png" className="welcome__services" alt="" /> */}
69 </div> 68 </div>
70 <div className="welcome__text"> 69 <div className="welcome__text">
71 <H1>Ferdium</H1> 70 <H1>Ferdium</H1>
@@ -82,9 +81,7 @@ class Welcome extends Component {
82 {intl.formatMessage(messages.changeServerMessage, { serverNameParse })} 81 {intl.formatMessage(messages.changeServerMessage, { serverNameParse })}
83 </span> 82 </span>
84 <Link to={changeServerRoute} className="button__change-server"> 83 <Link to={changeServerRoute} className="button__change-server">
85 <span> 84 <span>{intl.formatMessage(messages.changeServer)}</span>
86 {intl.formatMessage(messages.changeServer)}
87 </span>
88 </Link> 85 </Link>
89 </div> 86 </div>
90 <br /> 87 <br />
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index e22d4eb50..f7860afc6 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -7,6 +7,7 @@ import injectSheet from 'react-jss';
7import { ipcRenderer } from 'electron'; 7import { ipcRenderer } from 'electron';
8 8
9import { mdiFlash, mdiPowerPlug } from '@mdi/js'; 9import { mdiFlash, mdiPowerPlug } from '@mdi/js';
10import { Outlet } from 'react-router-dom';
10import InfoBar from '../ui/InfoBar'; 11import InfoBar from '../ui/InfoBar';
11import { Component as BasicAuth } from '../../features/basicAuth'; 12import { Component as BasicAuth } from '../../features/basicAuth';
12import { Component as QuickSwitch } from '../../features/quickSwitch'; 13import { Component as QuickSwitch } from '../../features/quickSwitch';
@@ -83,7 +84,6 @@ class AppLayout extends Component {
83 sidebar: PropTypes.element.isRequired, 84 sidebar: PropTypes.element.isRequired,
84 workspacesDrawer: PropTypes.element.isRequired, 85 workspacesDrawer: PropTypes.element.isRequired,
85 services: PropTypes.element.isRequired, 86 services: PropTypes.element.isRequired,
86 children: PropTypes.element,
87 showServicesUpdatedInfoBar: PropTypes.bool.isRequired, 87 showServicesUpdatedInfoBar: PropTypes.bool.isRequired,
88 appUpdateIsDownloaded: PropTypes.bool.isRequired, 88 appUpdateIsDownloaded: PropTypes.bool.isRequired,
89 authRequestFailed: PropTypes.bool.isRequired, 89 authRequestFailed: PropTypes.bool.isRequired,
@@ -99,10 +99,6 @@ class AppLayout extends Component {
99 shouldShowServicesUpdatedInfoBar: true, 99 shouldShowServicesUpdatedInfoBar: true,
100 }; 100 };
101 101
102 static defaultProps = {
103 children: [],
104 };
105
106 render() { 102 render() {
107 const { 103 const {
108 classes, 104 classes,
@@ -110,7 +106,6 @@ class AppLayout extends Component {
110 workspacesDrawer, 106 workspacesDrawer,
111 sidebar, 107 sidebar,
112 services, 108 services,
113 children,
114 showServicesUpdatedInfoBar, 109 showServicesUpdatedInfoBar,
115 appUpdateIsDownloaded, 110 appUpdateIsDownloaded,
116 authRequestFailed, 111 authRequestFailed,
@@ -205,7 +200,7 @@ class AppLayout extends Component {
205 <QuickSwitch /> 200 <QuickSwitch />
206 <PublishDebugInfo /> 201 <PublishDebugInfo />
207 {services} 202 {services}
208 {children} 203 <Outlet />
209 </div> 204 </div>
210 <Todos /> 205 <Todos />
211 </div> 206 </div>
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js
index 66dc8af41..502f87225 100644
--- a/src/components/services/content/ServiceWebview.js
+++ b/src/components/services/content/ServiceWebview.js
@@ -1,7 +1,7 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { observable, reaction } from 'mobx'; 4import { makeObservable, observable, reaction } from 'mobx';
5import ElectronWebView from 'react-electron-web-view'; 5import ElectronWebView from 'react-electron-web-view';
6import { join } from 'path'; 6import { join } from 'path';
7 7
@@ -22,6 +22,8 @@ class ServiceWebview extends Component {
22 constructor(props) { 22 constructor(props) {
23 super(props); 23 super(props);
24 24
25 makeObservable(this);
26
25 reaction( 27 reaction(
26 () => this.webview, 28 () => this.webview,
27 () => { 29 () => {
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.jsx
index b38b0e3c3..da700b5b1 100644
--- a/src/components/services/content/Services.js
+++ b/src/components/services/content/Services.jsx
@@ -1,7 +1,7 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes, inject } from 'mobx-react';
4import { Link } from 'react-router'; 4import { Link } from 'react-router-dom';
5import { defineMessages, injectIntl } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6import Confetti from 'react-confetti'; 6import Confetti from 'react-confetti';
7import ms from 'ms'; 7import ms from 'ms';
@@ -50,6 +50,7 @@ class Services extends Component {
50 openSettings: PropTypes.func.isRequired, 50 openSettings: PropTypes.func.isRequired,
51 update: PropTypes.func.isRequired, 51 update: PropTypes.func.isRequired,
52 userHasCompletedSignup: PropTypes.bool.isRequired, 52 userHasCompletedSignup: PropTypes.bool.isRequired,
53 // eslint-disable-next-line react/forbid-prop-types
53 classes: PropTypes.object.isRequired, 54 classes: PropTypes.object.isRequired,
54 isSpellcheckerEnabled: PropTypes.bool.isRequired, 55 isSpellcheckerEnabled: PropTypes.bool.isRequired,
55 }; 56 };
@@ -58,12 +59,16 @@ class Services extends Component {
58 services: [], 59 services: [],
59 }; 60 };
60 61
61 state = {
62 showConfetti: true,
63 };
64
65 _confettiTimeout = null; 62 _confettiTimeout = null;
66 63
64 constructor() {
65 super();
66
67 this.state = {
68 showConfetti: true,
69 };
70 }
71
67 componentDidMount() { 72 componentDidMount() {
68 this._confettiTimeout = window.setTimeout(() => { 73 this._confettiTimeout = window.setTimeout(() => {
69 this.setState({ 74 this.setState({
@@ -117,10 +122,7 @@ class Services extends Component {
117 style={{ maxHeight: '50vh' }} 122 style={{ maxHeight: '50vh' }}
118 /> 123 />
119 <Appear timeout={300} transitionName="slideUp"> 124 <Appear timeout={300} transitionName="slideUp">
120 <Link 125 <Link to="/settings/recipes" className="button">
121 to='/settings/recipes'
122 className="button"
123 >
124 {intl.formatMessage(messages.getStarted)} 126 {intl.formatMessage(messages.getStarted)}
125 </Link> 127 </Link>
126 </Appear> 128 </Appear>
diff --git a/src/components/services/tabs/TabItem.js b/src/components/services/tabs/TabItem.js
index 9d2b6b333..a996990b5 100644
--- a/src/components/services/tabs/TabItem.js
+++ b/src/components/services/tabs/TabItem.js
@@ -8,7 +8,7 @@ import { SortableElement } from 'react-sortable-hoc';
8import injectSheet from 'react-jss'; 8import injectSheet from 'react-jss';
9import ms from 'ms'; 9import ms from 'ms';
10 10
11import { observable, autorun, reaction } from 'mobx'; 11import { observable, autorun, reaction, makeObservable } from 'mobx';
12import { mdiExclamation } from '@mdi/js'; 12import { mdiExclamation } from '@mdi/js';
13import ServiceModel from '../../../models/Service'; 13import ServiceModel from '../../../models/Service';
14import { cmdOrCtrlShortcutKey, shiftKey, altKey } from '../../../environment'; 14import { cmdOrCtrlShortcutKey, shiftKey, altKey } from '../../../environment';
@@ -144,6 +144,9 @@ class TabItem extends Component {
144 144
145 constructor(props) { 145 constructor(props) {
146 super(props); 146 super(props);
147
148 makeObservable(this);
149
147 this.state = { 150 this.state = {
148 showShortcutIndex: false, 151 showShortcutIndex: false,
149 }; 152 };
diff --git a/src/components/settings/SettingsLayout.js b/src/components/settings/SettingsLayout.jsx
index d70f471d5..dea4bb387 100644
--- a/src/components/settings/SettingsLayout.js
+++ b/src/components/settings/SettingsLayout.jsx
@@ -4,8 +4,8 @@ import { observer } from 'mobx-react';
4import { defineMessages, injectIntl } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5 5
6import { mdiClose } from '@mdi/js'; 6import { mdiClose } from '@mdi/js';
7import { Outlet } from 'react-router-dom';
7import ErrorBoundary from '../util/ErrorBoundary'; 8import ErrorBoundary from '../util/ErrorBoundary';
8import { oneOrManyChildElements } from '../../prop-types';
9import Appear from '../ui/effects/Appear'; 9import Appear from '../ui/effects/Appear';
10import Icon from '../ui/icon'; 10import Icon from '../ui/icon';
11 11
@@ -19,7 +19,6 @@ const messages = defineMessages({
19class SettingsLayout extends Component { 19class SettingsLayout extends Component {
20 static propTypes = { 20 static propTypes = {
21 navigation: PropTypes.element.isRequired, 21 navigation: PropTypes.element.isRequired,
22 children: oneOrManyChildElements.isRequired,
23 closeSettings: PropTypes.func.isRequired, 22 closeSettings: PropTypes.func.isRequired,
24 }; 23 };
25 24
@@ -44,7 +43,7 @@ class SettingsLayout extends Component {
44 } 43 }
45 44
46 render() { 45 render() {
47 const { navigation, children, closeSettings } = this.props; 46 const { navigation, closeSettings } = this.props;
48 47
49 const { intl } = this.props; 48 const { intl } = this.props;
50 49
@@ -60,7 +59,8 @@ class SettingsLayout extends Component {
60 /> 59 />
61 <div className="settings franz-form"> 60 <div className="settings franz-form">
62 {navigation} 61 {navigation}
63 {children} 62
63 <Outlet />
64 <button 64 <button
65 type="button" 65 type="button"
66 className="settings__close" 66 className="settings__close"
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.jsx
index ad1cef1e4..bbbe8d888 100644
--- a/src/components/settings/navigation/SettingsNavigation.js
+++ b/src/components/settings/navigation/SettingsNavigation.jsx
@@ -2,10 +2,10 @@ import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { defineMessages, injectIntl } from 'react-intl'; 3import { defineMessages, injectIntl } from 'react-intl';
4import { inject, observer } from 'mobx-react'; 4import { inject, observer } from 'mobx-react';
5import { RouterStore } from 'mobx-react-router'; 5import { RouterStore } from '@superwf/mobx-react-router';
6 6
7import { NavLink } from 'react-router-dom';
7import { LOCAL_SERVER, LIVE_FERDIUM_API, LIVE_FRANZ_API } from '../../../config'; 8import { LOCAL_SERVER, LIVE_FERDIUM_API, LIVE_FRANZ_API } from '../../../config';
8import Link from '../../ui/Link';
9import UIStore from '../../../stores/UIStore'; 9import UIStore from '../../../stores/UIStore';
10import SettingsStore from '../../../stores/SettingsStore'; 10import SettingsStore from '../../../stores/SettingsStore';
11import UserStore from '../../../stores/UserStore'; 11import UserStore from '../../../stores/UserStore';
@@ -90,70 +90,94 @@ class SettingsNavigation extends Component {
90 90
91 return ( 91 return (
92 <div className="settings-navigation"> 92 <div className="settings-navigation">
93 <Link 93 <NavLink
94 to="/settings/recipes" 94 to="/settings/recipes"
95 className="settings-navigation__link" 95 className={({ isActive }) =>
96 activeClassName="is-active" 96 isActive
97 ? 'settings-navigation__link is-active'
98 : 'settings-navigation__link'
99 }
97 > 100 >
98 {intl.formatMessage(messages.availableServices)} 101 {intl.formatMessage(messages.availableServices)}
99 </Link> 102 </NavLink>
100 <Link 103 <NavLink
101 to="/settings/services" 104 to="/settings/services"
102 className="settings-navigation__link" 105 className={({ isActive }) =>
103 activeClassName="is-active" 106 isActive
107 ? 'settings-navigation__link is-active'
108 : 'settings-navigation__link'
109 }
104 > 110 >
105 {intl.formatMessage(messages.yourServices)}{' '} 111 {intl.formatMessage(messages.yourServices)}{' '}
106 <span className="badge">{serviceCount}</span> 112 <span className="badge">{serviceCount}</span>
107 </Link> 113 </NavLink>
108 <Link 114 <NavLink
109 to="/settings/workspaces" 115 to="/settings/workspaces"
110 className="settings-navigation__link" 116 className={({ isActive }) =>
111 activeClassName="is-active" 117 isActive
118 ? 'settings-navigation__link is-active'
119 : 'settings-navigation__link'
120 }
112 > 121 >
113 {intl.formatMessage(messages.yourWorkspaces)}{' '} 122 {intl.formatMessage(messages.yourWorkspaces)}{' '}
114 <span className="badge">{workspaceCount}</span> 123 <span className="badge">{workspaceCount}</span>
115 </Link> 124 </NavLink>
116 {!isUsingWithoutAccount && ( 125 {!isUsingWithoutAccount && (
117 <Link 126 <NavLink
118 to="/settings/user" 127 to="/settings/user"
119 className="settings-navigation__link" 128 className={({ isActive }) =>
120 activeClassName="is-active" 129 isActive
130 ? 'settings-navigation__link is-active'
131 : 'settings-navigation__link'
132 }
121 > 133 >
122 {intl.formatMessage(messages.account)} 134 {intl.formatMessage(messages.account)}
123 </Link> 135 </NavLink>
124 )} 136 )}
125 {isUsingFranzServer && ( 137 {isUsingFranzServer && (
126 <Link 138 <NavLink
127 to="/settings/team" 139 to="/settings/team"
128 className="settings-navigation__link" 140 className={({ isActive }) =>
129 activeClassName="is-active" 141 isActive
142 ? 'settings-navigation__link is-active'
143 : 'settings-navigation__link'
144 }
130 > 145 >
131 {intl.formatMessage(messages.team)} 146 {intl.formatMessage(messages.team)}
132 </Link> 147 </NavLink>
133 )} 148 )}
134 <Link 149 <NavLink
135 to="/settings/app" 150 to="/settings/app"
136 className="settings-navigation__link" 151 className={({ isActive }) =>
137 activeClassName="is-active" 152 isActive
153 ? 'settings-navigation__link is-active'
154 : 'settings-navigation__link'
155 }
138 > 156 >
139 {intl.formatMessage(globalMessages.settings)} 157 {intl.formatMessage(globalMessages.settings)}
140 {stores.settings.app.automaticUpdates && (stores.ui.showServicesUpdatedInfoBar || 158 {stores.settings.app.automaticUpdates &&
141 (stores.app.updateStatus === stores.app.updateStatusTypes.AVAILABLE || 159 (stores.ui.showServicesUpdatedInfoBar ||
142 stores.app.updateStatus === stores.app.updateStatusTypes.DOWNLOADED)) && ( 160 stores.app.updateStatus ===
143 <span className="update-available">•</span> 161 stores.app.updateStatusTypes.AVAILABLE ||
144 )} 162 stores.app.updateStatus ===
145 </Link> 163 stores.app.updateStatusTypes.DOWNLOADED) && (
146 <Link 164 <span className="update-available">•</span>
165 )}
166 </NavLink>
167 <NavLink
147 to="/settings/support" 168 to="/settings/support"
148 className="settings-navigation__link" 169 className={({ isActive }) =>
149 activeClassName="is-active" 170 isActive
171 ? 'settings-navigation__link is-active'
172 : 'settings-navigation__link'
173 }
150 > 174 >
151 {intl.formatMessage(messages.supportFerdium)} 175 {intl.formatMessage(messages.supportFerdium)}
152 </Link> 176 </NavLink>
153 <span className="settings-navigation__expander" /> 177 <span className="settings-navigation__expander" />
154 <button 178 <button
155 type="button" 179 type="button"
156 to='/auth/logout' 180 to="/auth/logout"
157 className="settings-navigation__link" 181 className="settings-navigation__link"
158 onClick={this.handleLogout.bind(this)} 182 onClick={this.handleLogout.bind(this)}
159 > 183 >
diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.jsx
index c05144117..589b97ecd 100644
--- a/src/components/settings/recipes/RecipesDashboard.js
+++ b/src/components/settings/recipes/RecipesDashboard.jsx
@@ -2,7 +2,7 @@ import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, injectIntl } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { Link } from 'react-router'; 5import { NavLink } from 'react-router-dom';
6 6
7import injectSheet from 'react-jss'; 7import injectSheet from 'react-jss';
8 8
@@ -179,30 +179,33 @@ class RecipesDashboard extends Component {
179 throttle 179 throttle
180 /> 180 />
181 <div className="recipes__navigation"> 181 <div className="recipes__navigation">
182 <Link 182 <NavLink
183 to="/settings/recipes" 183 to="/settings/recipes"
184 className="badge" 184 className={() =>
185 activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`} 185 recipeFilter === 'featured' ? 'badge badge--primary' : 'badge'
186 }
186 onClick={() => resetSearch()} 187 onClick={() => resetSearch()}
187 > 188 >
188 {intl.formatMessage(messages.ferdiumPicksRecipes)} 189 {intl.formatMessage(messages.ferdiumPicksRecipes)}
189 </Link> 190 </NavLink>
190 <Link 191 <NavLink
191 to="/settings/recipes/all" 192 to="/settings/recipes/all"
192 className="badge" 193 className={({ isActive }) =>
193 activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`} 194 isActive && recipeFilter === 'all' ? 'badge badge--primary' : 'badge'
195 }
194 onClick={() => resetSearch()} 196 onClick={() => resetSearch()}
195 > 197 >
196 {intl.formatMessage(messages.allRecipes)} 198 {intl.formatMessage(messages.allRecipes)}
197 </Link> 199 </NavLink>
198 <Link 200 <NavLink
199 to="/settings/recipes/dev" 201 to="/settings/recipes/dev"
200 className="badge" 202 className={({ isActive }) =>
201 activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`} 203 isActive && !searchNeedle ? 'badge badge--primary' : 'badge'
204 }
202 onClick={() => resetSearch()} 205 onClick={() => resetSearch()}
203 > 206 >
204 {intl.formatMessage(messages.customRecipes)} 207 {intl.formatMessage(messages.customRecipes)}
205 </Link> 208 </NavLink>
206 <a 209 <a
207 href={FERDIUM_SERVICE_REQUEST} 210 href={FERDIUM_SERVICE_REQUEST}
208 target="_blank" 211 target="_blank"
@@ -257,24 +260,26 @@ class RecipesDashboard extends Component {
257 /> 260 />
258 ))} 261 ))}
259 </div> 262 </div>
260 {hasLoadedRecipes && recipes.length === 0 && recipeFilter !== 'dev' && ( 263 {hasLoadedRecipes &&
261 <div className="align-middle settings__empty-state"> 264 recipes.length === 0 &&
262 {customWebsiteRecipe && customWebsiteRecipe.id && ( 265 recipeFilter !== 'dev' && (
263 <RecipeItem 266 <div className="align-middle settings__empty-state">
264 key={customWebsiteRecipe.id} 267 {customWebsiteRecipe && customWebsiteRecipe.id && (
265 recipe={customWebsiteRecipe} 268 <RecipeItem
266 onClick={() => 269 key={customWebsiteRecipe.id}
267 showAddServiceInterface({ 270 recipe={customWebsiteRecipe}
268 recipeId: customWebsiteRecipe.id, 271 onClick={() =>
269 }) 272 showAddServiceInterface({
270 } 273 recipeId: customWebsiteRecipe.id,
271 /> 274 })
272 )} 275 }
273 <p className="settings__empty-state-text"> 276 />
274 {intl.formatMessage(messages.nothingFound)} 277 )}
275 </p> 278 <p className="settings__empty-state-text">
276 </div> 279 {intl.formatMessage(messages.nothingFound)}
277 )} 280 </p>
281 </div>
282 )}
278 {recipeFilter === 'dev' && devRecipes.length > 0 && ( 283 {recipeFilter === 'dev' && devRecipes.length > 0 && (
279 <div className={classes.devRecipeList}> 284 <div className={classes.devRecipeList}>
280 <H3>{intl.formatMessage(messages.headlineDevRecipes)}</H3> 285 <H3>{intl.formatMessage(messages.headlineDevRecipes)}</H3>
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js
index f69d86726..73136529a 100644
--- a/src/components/settings/services/EditServiceForm.js
+++ b/src/components/settings/services/EditServiceForm.js
@@ -1,7 +1,7 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { Link } from 'react-router'; 4import { Link } from 'react-router-dom';
5import { defineMessages, injectIntl } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6import normalizeUrl from 'normalize-url'; 6import normalizeUrl from 'normalize-url';
7 7
diff --git a/src/components/settings/services/ServiceError.js b/src/components/settings/services/ServiceError.js
index 991817175..fdcdb54c9 100644
--- a/src/components/settings/services/ServiceError.js
+++ b/src/components/settings/services/ServiceError.js
@@ -1,6 +1,6 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import { observer } from 'mobx-react'; 2import { observer } from 'mobx-react';
3import { Link } from 'react-router'; 3import { Link } from 'react-router-dom';
4import { defineMessages, injectIntl } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5 5
6import Infobox from '../../ui/Infobox'; 6import Infobox from '../../ui/Infobox';
diff --git a/src/components/settings/services/ServicesDashboard.js b/src/components/settings/services/ServicesDashboard.js
index c5bb1433c..ac1c30ecb 100644
--- a/src/components/settings/services/ServicesDashboard.js
+++ b/src/components/settings/services/ServicesDashboard.js
@@ -1,7 +1,7 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { Link } from 'react-router'; 4import { Link } from 'react-router-dom';
5import { defineMessages, injectIntl } from 'react-intl'; 5import { defineMessages, injectIntl } from 'react-intl';
6 6
7import SearchInput from '../../ui/SearchInput'; 7import SearchInput from '../../ui/SearchInput';
@@ -27,8 +27,7 @@ const messages = defineMessages({
27 }, 27 },
28 noServiceFound: { 28 noServiceFound: {
29 id: 'settings.services.nothingFound', 29 id: 'settings.services.nothingFound',
30 defaultMessage: 30 defaultMessage: 'Sorry, but no service matched your search term.',
31 'Sorry, but no service matched your search term.',
32 }, 31 },
33 discoverServices: { 32 discoverServices: {
34 id: 'settings.services.discoverServices', 33 id: 'settings.services.discoverServices',
diff --git a/src/components/settings/user/EditUserForm.js b/src/components/settings/user/EditUserForm.js
index 436a6b76b..c2773a47d 100644
--- a/src/components/settings/user/EditUserForm.js
+++ b/src/components/settings/user/EditUserForm.js
@@ -2,7 +2,7 @@ import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, injectIntl } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { Link } from 'react-router'; 5import { Link } from 'react-router-dom';
6 6
7import Input from '../../ui/input/index'; 7import Input from '../../ui/input/index';
8import Form from '../../../lib/Form'; 8import Form from '../../../lib/Form';
diff --git a/src/components/ui/Link.js b/src/components/ui/Link.js
index 5ab19bf74..714fc5a68 100644
--- a/src/components/ui/Link.js
+++ b/src/components/ui/Link.js
@@ -1,7 +1,7 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { inject, observer } from 'mobx-react'; 3import { inject, observer } from 'mobx-react';
4import { RouterStore } from 'mobx-react-router'; 4import { RouterStore } from '@superwf/mobx-react-router';
5import classnames from 'classnames'; 5import classnames from 'classnames';
6 6
7import { oneOrManyChildElements } from '../../prop-types'; 7import { oneOrManyChildElements } from '../../prop-types';
diff --git a/src/components/ui/button/index.tsx b/src/components/ui/button/index.tsx
index 26fd6bcfe..a8bbfe730 100644
--- a/src/components/ui/button/index.tsx
+++ b/src/components/ui/button/index.tsx
@@ -169,20 +169,18 @@ class ButtonComponent extends Component<IProps> {
169 busy: false, 169 busy: false,
170 }; 170 };
171 171
172 componentWillMount() { 172 constructor(props: IProps) {
173 this.setState({ busy: this.props.busy }); 173 super(props);
174
175 this.state = {
176 busy: props.busy || false,
177 };
174 } 178 }
175 179
176 componentWillReceiveProps(nextProps: IProps) { 180 static getDerivedStateFromProps(nextProps: IProps) {
177 if (nextProps.busy !== this.props.busy) { 181 return {
178 if (this.props.busy) { 182 busy: nextProps.busy,
179 setTimeout(() => { 183 };
180 this.setState({ busy: nextProps.busy });
181 }, 300);
182 } else {
183 this.setState({ busy: nextProps.busy });
184 }
185 }
186 } 184 }
187 185
188 render() { 186 render() {
diff --git a/src/components/ui/infobox/index.tsx b/src/components/ui/infobox/index.tsx
index 976ed5bc4..d1d7ef6cd 100644
--- a/src/components/ui/infobox/index.tsx
+++ b/src/components/ui/infobox/index.tsx
@@ -199,6 +199,4 @@ class InfoboxComponent extends Component<IProps, IState> {
199 } 199 }
200} 200}
201 201
202export default injectStyle(styles, { injectTheme: true })( 202export default injectStyle(styles, { injectTheme: true })(InfoboxComponent);
203 InfoboxComponent,
204);
diff --git a/src/components/ui/select/index.tsx b/src/components/ui/select/index.tsx
index c3b5314e3..1ce6c674b 100644
--- a/src/components/ui/select/index.tsx
+++ b/src/components/ui/select/index.tsx
@@ -177,12 +177,16 @@ class SelectComponent extends Component<IProps> {
177 177
178 private keyListener: any; 178 private keyListener: any;
179 179
180 componentWillReceiveProps(nextProps: IProps) { 180 static getDerivedStateFromProps(nextProps: IProps, prevState: IProps) {
181 if (nextProps.value && nextProps.value !== this.props.value) { 181 if (nextProps.value && nextProps.value !== prevState.value) {
182 this.setState({ 182 return {
183 value: nextProps.value, 183 value: nextProps.value,
184 }); 184 };
185 } 185 }
186
187 return {
188 value: prevState.value,
189 };
186 } 190 }
187 191
188 componentDidUpdate() { 192 componentDidUpdate() {
@@ -199,6 +203,7 @@ class SelectComponent extends Component<IProps> {
199 203
200 if (data) { 204 if (data) {
201 Object.keys(data).map( 205 Object.keys(data).map(
206 // eslint-disable-next-line no-return-assign
202 key => (this.inputRef.current!.dataset[key] = data[key]), 207 key => (this.inputRef.current!.dataset[key] = data[key]),
203 ); 208 );
204 } 209 }
@@ -458,6 +463,6 @@ class SelectComponent extends Component<IProps> {
458 } 463 }
459} 464}
460 465
461export const Select = injectStyle(styles, { injectTheme: true })( 466export default injectStyle(styles, { injectTheme: true })(
462 SelectComponent, 467 SelectComponent,
463); 468);
diff --git a/src/components/ui/textarea/index.tsx b/src/components/ui/textarea/index.tsx
index e005767f8..6796ab83d 100644
--- a/src/components/ui/textarea/index.tsx
+++ b/src/components/ui/textarea/index.tsx
@@ -121,6 +121,6 @@ class TextareaComponent extends Component<IProps> {
121 } 121 }
122} 122}
123 123
124export const Textarea = injectSheet(styles, { injectTheme: true })( 124export default injectSheet(styles, { injectTheme: true })(
125 TextareaComponent, 125 TextareaComponent,
126); 126);
diff --git a/src/components/ui/toggle/index.tsx b/src/components/ui/toggle/index.tsx
index 0629d1a2c..d478cbba5 100644
--- a/src/components/ui/toggle/index.tsx
+++ b/src/components/ui/toggle/index.tsx
@@ -122,6 +122,4 @@ class ToggleComponent extends Component<IProps> {
122 } 122 }
123} 123}
124 124
125export default injectStyle(styles, { injectTheme: true })( 125export default injectStyle(styles, { injectTheme: true })(ToggleComponent);
126 ToggleComponent,
127);
diff --git a/src/components/util/ErrorBoundary/index.tsx b/src/components/util/ErrorBoundary/index.tsx
index 846d6dc3f..b042e62c8 100644
--- a/src/components/util/ErrorBoundary/index.tsx
+++ b/src/components/util/ErrorBoundary/index.tsx
@@ -32,8 +32,7 @@ class ErrorBoundary extends Component<ErrorBoundaryProps> {
32 } 32 }
33 33
34 render(): ReactNode { 34 render(): ReactNode {
35 const { classes } = this.props; 35 const { classes, intl } = this.props;
36 const { intl } = this.props;
37 36
38 if (this.state.hasError) { 37 if (this.state.hasError) {
39 return ( 38 return (
diff --git a/src/components/util/WithParams.tsx b/src/components/util/WithParams.tsx
new file mode 100644
index 000000000..6fc0957ff
--- /dev/null
+++ b/src/components/util/WithParams.tsx
@@ -0,0 +1,8 @@
1import { useParams } from 'react-router-dom';
2
3export default function withParams(Component: any) {
4 return (props: any) => {
5 const params = useParams();
6 return <Component {...props} params={params} />;
7 };
8}
diff --git a/src/containers/auth/AuthLayoutContainer.tsx b/src/containers/auth/AuthLayoutContainer.tsx
index 1f2753a66..8d31cfb48 100644
--- a/src/containers/auth/AuthLayoutContainer.tsx
+++ b/src/containers/auth/AuthLayoutContainer.tsx
@@ -1,20 +1,17 @@
1import { Component, ReactElement, ReactNode } from 'react'; 1import { Component, ReactElement } from 'react';
2import { inject, observer } from 'mobx-react'; 2import { inject, observer } from 'mobx-react';
3import { ThemeProvider } from 'react-jss'; 3import { ThemeProvider } from 'react-jss';
4import { Outlet } from 'react-router-dom';
4 5
5import { Location } from 'mobx-react-router';
6import { StoresProps } from '../../@types/ferdium-components.types'; 6import { StoresProps } from '../../@types/ferdium-components.types';
7import AuthLayout from '../../components/auth/AuthLayout'; 7import AuthLayout from '../../components/auth/AuthLayout';
8import AppLoader from '../../components/ui/AppLoader'; 8import AppLoader from '../../components/ui/AppLoader';
9 9
10interface AuthLayoutContainerProps extends StoresProps { 10interface AuthLayoutContainerProps extends StoresProps {}
11 location: Location;
12 children: ReactNode;
13}
14 11
15class AuthLayoutContainer extends Component<AuthLayoutContainerProps> { 12class AuthLayoutContainer extends Component<AuthLayoutContainerProps> {
16 render(): ReactElement { 13 render(): ReactElement {
17 const { stores, actions, children, location } = this.props; 14 const { stores, actions } = this.props;
18 const { app, features, globalError, user } = stores; 15 const { app, features, globalError, user } = stores;
19 16
20 const isLoadingBaseFeatures = 17 const isLoadingBaseFeatures =
@@ -42,7 +39,7 @@ class AuthLayoutContainer extends Component<AuthLayoutContainerProps> {
42 <ThemeProvider theme={stores.ui.theme}> 39 <ThemeProvider theme={stores.ui.theme}>
43 <AuthLayout 40 <AuthLayout
44 error={globalError.response} 41 error={globalError.response}
45 pathname={location.pathname} 42 pathname={stores.router.location.pathname}
46 isOnline={app.isOnline} 43 isOnline={app.isOnline}
47 isAPIHealthy={!app.healthCheckRequest.isError} 44 isAPIHealthy={!app.healthCheckRequest.isError}
48 retryHealthCheck={actions.app.healthCheck} 45 retryHealthCheck={actions.app.healthCheck}
@@ -53,7 +50,7 @@ class AuthLayoutContainer extends Component<AuthLayoutContainerProps> {
53 app.updateStatus === app.updateStatusTypes.DOWNLOADED 50 app.updateStatus === app.updateStatusTypes.DOWNLOADED
54 } 51 }
55 > 52 >
56 {children} 53 <Outlet />
57 </AuthLayout> 54 </AuthLayout>
58 </ThemeProvider> 55 </ThemeProvider>
59 ); 56 );
diff --git a/src/containers/layout/AppLayoutContainer.tsx b/src/containers/layout/AppLayoutContainer.tsx
index 984ea8b68..a4857a426 100644
--- a/src/containers/layout/AppLayoutContainer.tsx
+++ b/src/containers/layout/AppLayoutContainer.tsx
@@ -1,19 +1,17 @@
1import { Children, Component, ReactElement, ReactNode } from 'react'; 1import { Component, ReactElement } from 'react';
2import { inject, observer } from 'mobx-react'; 2import { inject, observer } from 'mobx-react';
3import { ThemeProvider } from 'react-jss'; 3import { ThemeProvider } from 'react-jss';
4import { Outlet } from 'react-router-dom';
4 5
5import { StoresProps } from '../../@types/ferdium-components.types'; 6import { StoresProps } from '../../@types/ferdium-components.types';
6import AppLayout from '../../components/layout/AppLayout'; 7import AppLayout from '../../components/layout/AppLayout';
7import Sidebar from '../../components/layout/Sidebar'; 8import Sidebar from '../../components/layout/Sidebar';
8import Services from '../../components/services/content/Services'; 9import Services from '../../components/services/content/Services';
9import AppLoader from '../../components/ui/AppLoader'; 10import AppLoader from '../../components/ui/AppLoader';
10
11import WorkspaceDrawer from '../../features/workspaces/components/WorkspaceDrawer'; 11import WorkspaceDrawer from '../../features/workspaces/components/WorkspaceDrawer';
12import { workspaceStore } from '../../features/workspaces'; 12import { workspaceStore } from '../../features/workspaces';
13 13
14interface AppLayoutContainerProps extends StoresProps { 14interface AppLayoutContainerProps extends StoresProps {}
15 children: ReactNode;
16}
17 15
18class AppLayoutContainer extends Component<AppLayoutContainerProps> { 16class AppLayoutContainer extends Component<AppLayoutContainerProps> {
19 render(): ReactElement { 17 render(): ReactElement {
@@ -62,8 +60,6 @@ class AppLayoutContainer extends Component<AppLayoutContainerProps> {
62 60
63 const { openSettings, closeSettings } = this.props.actions.ui; 61 const { openSettings, closeSettings } = this.props.actions.ui;
64 62
65 const { children } = this.props;
66
67 const isLoadingFeatures = 63 const isLoadingFeatures =
68 features.featuresRequest.isExecuting && 64 features.featuresRequest.isExecuting &&
69 !features.featuresRequest.wasExecuted; 65 !features.featuresRequest.wasExecuted;
@@ -162,7 +158,7 @@ class AppLayoutContainer extends Component<AppLayoutContainerProps> {
162 retryRequiredRequests={retryRequiredRequests} 158 retryRequiredRequests={retryRequiredRequests}
163 areRequiredRequestsLoading={requests.areRequiredRequestsLoading} 159 areRequiredRequestsLoading={requests.areRequiredRequestsLoading}
164 > 160 >
165 {Children.count(children) > 0 ? children : null} 161 <Outlet />
166 </AppLayout> 162 </AppLayout>
167 </ThemeProvider> 163 </ThemeProvider>
168 ); 164 );
diff --git a/src/containers/settings/EditServiceScreen.tsx b/src/containers/settings/EditServiceScreen.tsx
index f8532a7b4..ba8f374c3 100644
--- a/src/containers/settings/EditServiceScreen.tsx
+++ b/src/containers/settings/EditServiceScreen.tsx
@@ -2,7 +2,7 @@ import { Component, ReactElement } from 'react';
2import { inject, observer } from 'mobx-react'; 2import { inject, observer } from 'mobx-react';
3import { defineMessages, injectIntl } from 'react-intl'; 3import { defineMessages, injectIntl } from 'react-intl';
4 4
5import { RouterStore } from 'mobx-react-router'; 5import { Params } from 'react-router-dom';
6import { StoresProps } from '../../@types/ferdium-components.types'; 6import { StoresProps } from '../../@types/ferdium-components.types';
7import { IRecipe } from '../../models/Recipe'; 7import { IRecipe } from '../../models/Recipe';
8import Service from '../../models/Service'; 8import Service from '../../models/Service';
@@ -22,6 +22,7 @@ import { SPELLCHECKER_LOCALES } from '../../i18n/languages';
22 22
23import globalMessages from '../../i18n/globalMessages'; 23import globalMessages from '../../i18n/globalMessages';
24import { DEFAULT_APP_SETTINGS, DEFAULT_SERVICE_SETTINGS } from '../../config'; 24import { DEFAULT_APP_SETTINGS, DEFAULT_SERVICE_SETTINGS } from '../../config';
25import withParams from '../../components/util/WithParams';
25 26
26const messages = defineMessages({ 27const messages = defineMessages({
27 name: { 28 name: {
@@ -119,14 +120,13 @@ const messages = defineMessages({
119}); 120});
120 121
121interface EditServicesScreenProps extends StoresProps { 122interface EditServicesScreenProps extends StoresProps {
122 router: RouterStore;
123 intl: any; 123 intl: any;
124 params: Params;
124} 125}
125 126
126class EditServiceScreen extends Component<EditServicesScreenProps> { 127class EditServiceScreen extends Component<EditServicesScreenProps> {
127 onSubmit(data: any) { 128 onSubmit(data: any) {
128 // @ts-ignore TODO: This is actually there and we don't have a correct type right now. 129 const { action } = this.props.params;
129 const { action } = this.props.router.params;
130 const { recipes, services } = this.props.stores; 130 const { recipes, services } = this.props.stores;
131 const { createService, updateService } = this.props.actions.service; 131 const { createService, updateService } = this.props.actions.service;
132 data.darkReaderSettings = { 132 data.darkReaderSettings = {
@@ -151,10 +151,9 @@ class EditServiceScreen extends Component<EditServicesScreenProps> {
151 prepareForm(recipe: IRecipe, service: Service | null, proxy: any): Form { 151 prepareForm(recipe: IRecipe, service: Service | null, proxy: any): Form {
152 const { intl } = this.props; 152 const { intl } = this.props;
153 153
154 const { stores, router } = this.props; 154 const { stores } = this.props;
155 155
156 // @ts-ignore TODO: This is actually there and we don't have a correct type right now. 156 const { action } = stores.router.pathValue;
157 const { action } = router.params;
158 157
159 let defaultSpellcheckerLanguage = 158 let defaultSpellcheckerLanguage =
160 SPELLCHECKER_LOCALES[stores.settings.app.spellcheckerLanguage]; 159 SPELLCHECKER_LOCALES[stores.settings.app.spellcheckerLanguage];
@@ -389,8 +388,7 @@ class EditServiceScreen extends Component<EditServicesScreenProps> {
389 388
390 deleteService(): void { 389 deleteService(): void {
391 const { deleteService } = this.props.actions.service; 390 const { deleteService } = this.props.actions.service;
392 // @ts-ignore TODO: This is actually there and we don't have a correct type right now. 391 const { action } = this.props.params;
393 const { action } = this.props.router.params;
394 392
395 if (action === 'edit') { 393 if (action === 'edit') {
396 const { activeSettings: service } = this.props.stores.services; 394 const { activeSettings: service } = this.props.stores.services;
@@ -403,8 +401,7 @@ class EditServiceScreen extends Component<EditServicesScreenProps> {
403 401
404 openRecipeFile(file: any): void { 402 openRecipeFile(file: any): void {
405 const { openRecipeFile } = this.props.actions.service; 403 const { openRecipeFile } = this.props.actions.service;
406 // @ts-ignore TODO: This is actually there and we don't have a correct type right now. 404 const { action } = this.props.params;
407 const { action } = this.props.router.params;
408 405
409 if (action === 'edit') { 406 if (action === 'edit') {
410 const { activeSettings: service } = this.props.stores.services; 407 const { activeSettings: service } = this.props.stores.services;
@@ -417,9 +414,7 @@ class EditServiceScreen extends Component<EditServicesScreenProps> {
417 414
418 render(): ReactElement { 415 render(): ReactElement {
419 const { recipes, services, user } = this.props.stores; 416 const { recipes, services, user } = this.props.stores;
420 417 const { action } = this.props.params;
421 // @ts-ignore TODO: This is actually there and we don't have a correct type right now.
422 const { action } = this.props.router.params;
423 418
424 let recipe: null | IRecipe = null; 419 let recipe: null | IRecipe = null;
425 let service: null | Service = null; 420 let service: null | Service = null;
@@ -427,7 +422,6 @@ class EditServiceScreen extends Component<EditServicesScreenProps> {
427 422
428 if (action === 'add') { 423 if (action === 'add') {
429 recipe = recipes.active; 424 recipe = recipes.active;
430
431 // TODO: render error message when recipe is `null` 425 // TODO: render error message when recipe is `null`
432 if (!recipe) { 426 if (!recipe) {
433 return <ServiceError />; 427 return <ServiceError />;
@@ -475,6 +469,8 @@ class EditServiceScreen extends Component<EditServicesScreenProps> {
475 } 469 }
476} 470}
477 471
478export default injectIntl<'intl', EditServicesScreenProps>( 472export default withParams(
479 inject('stores', 'actions')(observer(EditServiceScreen)), 473 injectIntl<'intl', EditServicesScreenProps>(
474 inject('stores', 'actions')(observer(EditServiceScreen)),
475 ),
480); 476);
diff --git a/src/containers/settings/RecipesScreen.tsx b/src/containers/settings/RecipesScreen.tsx
index bc7fa9ba0..fffdd39fa 100644
--- a/src/containers/settings/RecipesScreen.tsx
+++ b/src/containers/settings/RecipesScreen.tsx
@@ -3,6 +3,7 @@ import { Component, ReactElement } from 'react';
3import { autorun, IReactionDisposer } from 'mobx'; 3import { autorun, IReactionDisposer } from 'mobx';
4import { inject, observer } from 'mobx-react'; 4import { inject, observer } from 'mobx-react';
5 5
6import { Params } from 'react-router-dom';
6import Recipe from '../../models/Recipe'; 7import Recipe from '../../models/Recipe';
7import { StoresProps } from '../../@types/ferdium-components.types'; 8import { StoresProps } from '../../@types/ferdium-components.types';
8import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; 9import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard';
@@ -13,11 +14,10 @@ import { asarRecipesPath } from '../../helpers/asar-helpers';
13import { communityRecipesStore } from '../../features/communityRecipes'; 14import { communityRecipesStore } from '../../features/communityRecipes';
14import RecipePreview from '../../models/RecipePreview'; 15import RecipePreview from '../../models/RecipePreview';
15import { openPath } from '../../helpers/url-helpers'; 16import { openPath } from '../../helpers/url-helpers';
17import withParams from '../../components/util/WithParams';
16 18
17interface RecipesScreenProps extends StoresProps { 19interface RecipesScreenProps extends StoresProps {
18 params: { 20 params: Params;
19 filter?: string | null;
20 };
21} 21}
22 22
23class RecipesScreen extends Component<RecipesScreenProps> { 23class RecipesScreen extends Component<RecipesScreenProps> {
@@ -36,8 +36,6 @@ class RecipesScreen extends Component<RecipesScreenProps> {
36 constructor(props: RecipesScreenProps) { 36 constructor(props: RecipesScreenProps) {
37 super(props); 37 super(props);
38 38
39 this.props.params.filter = this.props.params.filter || null;
40
41 this.customRecipes = readJsonSync(asarRecipesPath('all.json')); 39 this.customRecipes = readJsonSync(asarRecipesPath('all.json'));
42 } 40 }
43 41
@@ -104,7 +102,7 @@ class RecipesScreen extends Component<RecipesScreenProps> {
104 } 102 }
105 103
106 resetSearch(): void { 104 resetSearch(): void {
107 this.setState({ needle: null }); 105 this.setState({ needle: null, currentFilter: 'featured' });
108 } 106 }
109 107
110 render(): ReactElement { 108 render(): ReactElement {
@@ -112,7 +110,8 @@ class RecipesScreen extends Component<RecipesScreenProps> {
112 110
113 const { app: appActions, service: serviceActions } = this.props.actions; 111 const { app: appActions, service: serviceActions } = this.props.actions;
114 112
115 const { filter } = this.props.params; 113 const filter = this.state.currentFilter;
114
116 let recipeFilter; 115 let recipeFilter;
117 116
118 if (filter === 'all') { 117 if (filter === 'all') {
@@ -125,7 +124,7 @@ class RecipesScreen extends Component<RecipesScreenProps> {
125 } else { 124 } else {
126 recipeFilter = recipePreviews.featured; 125 recipeFilter = recipePreviews.featured;
127 } 126 }
128 recipeFilter = recipeFilter.sort(this._sortByName); 127 recipeFilter = [...recipeFilter].sort(this._sortByName);
129 128
130 const { needle } = this.state; 129 const { needle } = this.state;
131 const allRecipes = 130 const allRecipes =
@@ -185,4 +184,4 @@ class RecipesScreen extends Component<RecipesScreenProps> {
185 } 184 }
186} 185}
187 186
188export default inject('stores', 'actions')(observer(RecipesScreen)); 187export default withParams(inject('stores', 'actions')(observer(RecipesScreen)));
diff --git a/src/containers/settings/SettingsWindow.tsx b/src/containers/settings/SettingsWindow.tsx
index 2192a6f69..93bb08c7c 100644
--- a/src/containers/settings/SettingsWindow.tsx
+++ b/src/containers/settings/SettingsWindow.tsx
@@ -1,23 +1,20 @@
1import { Component, ReactNode, ReactPortal } from 'react'; 1import { inject, observer } from 'mobx-react';
2import { Component, ReactPortal } from 'react';
2import ReactDOM from 'react-dom'; 3import ReactDOM from 'react-dom';
3import { observer, inject } from 'mobx-react'; 4import { Outlet } from 'react-router-dom';
4 5
5import { StoresProps } from '../../@types/ferdium-components.types'; 6import { StoresProps } from '../../@types/ferdium-components.types';
6import Layout from '../../components/settings/SettingsLayout';
7import Navigation from '../../components/settings/navigation/SettingsNavigation'; 7import Navigation from '../../components/settings/navigation/SettingsNavigation';
8import Layout from '../../components/settings/SettingsLayout';
8import ErrorBoundary from '../../components/util/ErrorBoundary'; 9import ErrorBoundary from '../../components/util/ErrorBoundary';
9import { workspaceStore } from '../../features/workspaces'; 10import { workspaceStore } from '../../features/workspaces';
10 11
11interface SettingsContainerProps extends StoresProps { 12class SettingsContainer extends Component<StoresProps> {
12 children: ReactNode;
13}
14
15class SettingsContainer extends Component<SettingsContainerProps> {
16 portalRoot: any; 13 portalRoot: any;
17 14
18 el: HTMLDivElement; 15 el: HTMLDivElement;
19 16
20 constructor(props: SettingsContainerProps) { 17 constructor(props: StoresProps) {
21 super(props); 18 super(props);
22 19
23 this.portalRoot = document.querySelector('#portalContainer'); 20 this.portalRoot = document.querySelector('#portalContainer');
@@ -33,7 +30,7 @@ class SettingsContainer extends Component<SettingsContainerProps> {
33 } 30 }
34 31
35 render(): ReactPortal { 32 render(): ReactPortal {
36 const { children, stores } = this.props; 33 const { stores } = this.props;
37 const { closeSettings } = this.props.actions.ui; 34 const { closeSettings } = this.props.actions.ui;
38 35
39 const navigation = ( 36 const navigation = (
@@ -46,7 +43,7 @@ class SettingsContainer extends Component<SettingsContainerProps> {
46 return ReactDOM.createPortal( 43 return ReactDOM.createPortal(
47 <ErrorBoundary> 44 <ErrorBoundary>
48 <Layout navigation={navigation} closeSettings={closeSettings}> 45 <Layout navigation={navigation} closeSettings={closeSettings}>
49 {children} 46 <Outlet />
50 </Layout> 47 </Layout>
51 </ErrorBoundary>, 48 </ErrorBoundary>,
52 this.el, 49 this.el,
diff --git a/src/electron/Settings.ts b/src/electron/Settings.ts
index d09ac7fb6..3e9c6ed99 100644
--- a/src/electron/Settings.ts
+++ b/src/electron/Settings.ts
@@ -1,4 +1,4 @@
1import { observable, toJS } from 'mobx'; 1import { makeObservable, observable, toJS } from 'mobx';
2import { pathExistsSync, outputJsonSync, readJsonSync } from 'fs-extra'; 2import { pathExistsSync, outputJsonSync, readJsonSync } from 'fs-extra';
3import { userDataPath } from '../environment-remote'; 3import { userDataPath } from '../environment-remote';
4 4
@@ -12,6 +12,8 @@ export default class Settings {
12 @observable store: object = {}; 12 @observable store: object = {};
13 13
14 constructor(type: string, defaultState = {}) { 14 constructor(type: string, defaultState = {}) {
15 makeObservable(this);
16
15 this.type = type; 17 this.type = type;
16 this.store = defaultState; 18 this.store = defaultState;
17 this.defaultState = defaultState; 19 this.defaultState = defaultState;
diff --git a/src/features/communityRecipes/store.ts b/src/features/communityRecipes/store.ts
index 34e6cd92c..d3b3318fa 100644
--- a/src/features/communityRecipes/store.ts
+++ b/src/features/communityRecipes/store.ts
@@ -1,7 +1,9 @@
1import { computed } from 'mobx'; 1import { computed } from 'mobx';
2import FeatureStore from '../utils/FeatureStore'; 2import FeatureStore from '../utils/FeatureStore';
3 3
4const debug = require('../../preload-safe-debug')('Ferdium:feature:communityRecipes:store'); 4const debug = require('../../preload-safe-debug')(
5 'Ferdium:feature:communityRecipes:store',
6);
5 7
6export class CommunityRecipesStore extends FeatureStore { 8export class CommunityRecipesStore extends FeatureStore {
7 stores: any; 9 stores: any;
diff --git a/src/features/todos/store.js b/src/features/todos/store.js
index 1a3d6c1e7..0f195f10d 100644
--- a/src/features/todos/store.js
+++ b/src/features/todos/store.js
@@ -1,4 +1,4 @@
1import { computed, action, observable } from 'mobx'; 1import { computed, action, observable, makeObservable } from 'mobx';
2import localStorage from 'mobx-localstorage'; 2import localStorage from 'mobx-localstorage';
3 3
4import { ThemeType } from '../../themes'; 4import { ThemeType } from '../../themes';
@@ -33,6 +33,12 @@ export default class TodoStore extends FeatureStore {
33 33
34 isInitialized = false; 34 isInitialized = false;
35 35
36 constructor() {
37 super();
38
39 makeObservable(this);
40 }
41
36 @computed get width() { 42 @computed get width() {
37 const width = this.settings.width || DEFAULT_TODOS_WIDTH; 43 const width = this.settings.width || DEFAULT_TODOS_WIDTH;
38 44
diff --git a/src/features/webControls/containers/WebControlsScreen.js b/src/features/webControls/containers/WebControlsScreen.js
index 3dac6997c..e5567eec5 100644
--- a/src/features/webControls/containers/WebControlsScreen.js
+++ b/src/features/webControls/containers/WebControlsScreen.js
@@ -2,7 +2,7 @@ import { Component } from 'react';
2import { observer, inject } from 'mobx-react'; 2import { observer, inject } from 'mobx-react';
3import PropTypes from 'prop-types'; 3import PropTypes from 'prop-types';
4 4
5import { autorun, observable } from 'mobx'; 5import { autorun, makeObservable, observable } from 'mobx';
6import WebControls from '../components/WebControls'; 6import WebControls from '../components/WebControls';
7import ServicesStore from '../../../stores/ServicesStore'; 7import ServicesStore from '../../../stores/ServicesStore';
8import Service from '../../../models/Service'; 8import Service from '../../../models/Service';
@@ -27,6 +27,12 @@ class WebControlsScreen extends Component {
27 27
28 autorunDisposer = null; 28 autorunDisposer = null;
29 29
30 constructor(props) {
31 super(props);
32
33 makeObservable(this);
34 }
35
30 componentDidMount() { 36 componentDidMount() {
31 const { service } = this.props; 37 const { service } = this.props;
32 38
diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js
index 3c7c36a3d..7e8541c44 100644
--- a/src/features/workspaces/components/EditWorkspaceForm.js
+++ b/src/features/workspaces/components/EditWorkspaceForm.js
@@ -2,7 +2,7 @@ import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, injectIntl } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { Link } from 'react-router'; 5import { Link } from 'react-router-dom';
6import injectSheet from 'react-jss'; 6import injectSheet from 'react-jss';
7 7
8import Infobox from '../../../components/ui/infobox/index'; 8import Infobox from '../../../components/ui/infobox/index';
diff --git a/src/features/workspaces/components/WorkspaceDrawer.js b/src/features/workspaces/components/WorkspaceDrawer.jsx
index 3454fdbe9..b0b0e639a 100644
--- a/src/features/workspaces/components/WorkspaceDrawer.js
+++ b/src/features/workspaces/components/WorkspaceDrawer.jsx
@@ -12,9 +12,7 @@ import Icon from '../../../components/ui/icon';
12import WorkspaceDrawerItem from './WorkspaceDrawerItem'; 12import WorkspaceDrawerItem from './WorkspaceDrawerItem';
13import workspaceActions from '../actions'; 13import workspaceActions from '../actions';
14import { workspaceStore } from '../index'; 14import { workspaceStore } from '../index';
15import { 15import { getUserWorkspacesRequest } from '../api';
16 getUserWorkspacesRequest,
17} from '../api';
18 16
19const messages = defineMessages({ 17const messages = defineMessages({
20 headline: { 18 headline: {
diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.tsx b/src/features/workspaces/containers/EditWorkspaceScreen.tsx
index f0c7e4574..0b66db0d0 100644
--- a/src/features/workspaces/containers/EditWorkspaceScreen.tsx
+++ b/src/features/workspaces/containers/EditWorkspaceScreen.tsx
@@ -1,23 +1,14 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import { inject, observer } from 'mobx-react'; 2import { inject, observer } from 'mobx-react';
3 3
4import { StoresProps } from '../../../@types/ferdium-components.types';
4import ErrorBoundary from '../../../components/util/ErrorBoundary'; 5import ErrorBoundary from '../../../components/util/ErrorBoundary';
5import EditWorkspaceForm from '../components/EditWorkspaceForm'; 6import EditWorkspaceForm from '../components/EditWorkspaceForm';
6import Workspace from '../models/Workspace'; 7import Workspace from '../models/Workspace';
7import { workspaceStore } from '../index'; 8import { workspaceStore } from '../index';
8import { deleteWorkspaceRequest, updateWorkspaceRequest } from '../api'; 9import { deleteWorkspaceRequest, updateWorkspaceRequest } from '../api';
9import { ServicesStore, WorkspacesStore } from '../../../@types/stores.types';
10 10
11type Props = { 11class EditWorkspaceScreen extends Component<StoresProps> {
12 actions: {
13 workspaces: WorkspacesStore;
14 };
15 stores: {
16 services: ServicesStore;
17 };
18};
19
20class EditWorkspaceScreen extends Component<Props> {
21 // @ts-expect-error Not all code paths return a value. 12 // @ts-expect-error Not all code paths return a value.
22 onDelete = () => { 13 onDelete = () => {
23 const { workspaceBeingEdited } = workspaceStore; 14 const { workspaceBeingEdited } = workspaceStore;
diff --git a/src/features/workspaces/containers/WorkspacesScreen.tsx b/src/features/workspaces/containers/WorkspacesScreen.tsx
index 5b153fb50..d43dc5efa 100644
--- a/src/features/workspaces/containers/WorkspacesScreen.tsx
+++ b/src/features/workspaces/containers/WorkspacesScreen.tsx
@@ -1,5 +1,6 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import { inject, observer } from 'mobx-react'; 2import { inject, observer } from 'mobx-react';
3import { StoresProps } from '../../../@types/ferdium-components.types';
3import WorkspacesDashboard from '../components/WorkspacesDashboard'; 4import WorkspacesDashboard from '../components/WorkspacesDashboard';
4import ErrorBoundary from '../../../components/util/ErrorBoundary'; 5import ErrorBoundary from '../../../components/util/ErrorBoundary';
5import { workspaceStore } from '../index'; 6import { workspaceStore } from '../index';
@@ -9,15 +10,8 @@ import {
9 getUserWorkspacesRequest, 10 getUserWorkspacesRequest,
10 updateWorkspaceRequest, 11 updateWorkspaceRequest,
11} from '../api'; 12} from '../api';
12import { WorkspacesStore } from '../../../@types/stores.types';
13 13
14type Props = { 14class WorkspacesScreen extends Component<StoresProps> {
15 actions: {
16 workspaces: WorkspacesStore;
17 };
18};
19
20class WorkspacesScreen extends Component<Props> {
21 render() { 15 render() {
22 const { actions } = this.props; 16 const { actions } = this.props;
23 return ( 17 return (
diff --git a/src/features/workspaces/models/Workspace.ts b/src/features/workspaces/models/Workspace.ts
index bc636011d..98086289f 100644
--- a/src/features/workspaces/models/Workspace.ts
+++ b/src/features/workspaces/models/Workspace.ts
@@ -1,4 +1,4 @@
1import { observable } from 'mobx'; 1import { makeObservable, observable } from 'mobx';
2 2
3import { KEEP_WS_LOADED_USID } from '../../../config'; 3import { KEEP_WS_LOADED_USID } from '../../../config';
4 4
@@ -18,6 +18,8 @@ export default class Workspace {
18 throw new Error('Workspace requires Id'); 18 throw new Error('Workspace requires Id');
19 } 19 }
20 20
21 makeObservable(this);
22
21 this.id = data.id; 23 this.id = data.id;
22 this.name = data.name; 24 this.name = data.name;
23 this.order = data.order; 25 this.order = data.order;
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js
index 9b4c4e928..e8c5d0590 100644
--- a/src/features/workspaces/store.js
+++ b/src/features/workspaces/store.js
@@ -1,4 +1,4 @@
1import { computed, observable, action } from 'mobx'; 1import { computed, observable, action, makeObservable } from 'mobx';
2import localStorage from 'mobx-localstorage'; 2import localStorage from 'mobx-localstorage';
3import matchRoute from '../../helpers/routing-helpers'; 3import matchRoute from '../../helpers/routing-helpers';
4import workspaceActions from './actions'; 4import workspaceActions from './actions';
@@ -32,6 +32,12 @@ export default class WorkspacesStore extends FeatureStore {
32 32
33 @observable isSettingsRouteActive = null; 33 @observable isSettingsRouteActive = null;
34 34
35 constructor() {
36 super();
37
38 makeObservable(this);
39 }
40
35 @computed get workspaces() { 41 @computed get workspaces() {
36 if (!this.isFeatureActive) return []; 42 if (!this.isFeatureActive) return [];
37 return getUserWorkspacesRequest.result || []; 43 return getUserWorkspacesRequest.result || [];
diff --git a/src/index.ts b/src/index.ts
index 7ca364a2e..739f653d4 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -626,7 +626,6 @@ ipcMain.on('set-spellchecker-locales', (_e, { locale, serviceId }) => {
626 serviceSession.setSpellCheckerLanguages(locales); 626 serviceSession.setSpellCheckerLanguages(locales);
627}); 627});
628 628
629
630ipcMain.handle('get-desktop-capturer-sources', () => desktopCapturer.getSources({ 629ipcMain.handle('get-desktop-capturer-sources', () => desktopCapturer.getSources({
631 types: ['screen', 'window'], 630 types: ['screen', 'window'],
632})); 631}));
diff --git a/src/lib/Menu.js b/src/lib/Menu.js
index 0272f39c3..c2b43bd5c 100644
--- a/src/lib/Menu.js
+++ b/src/lib/Menu.js
@@ -7,7 +7,7 @@ import {
7 systemPreferences, 7 systemPreferences,
8 getCurrentWindow, 8 getCurrentWindow,
9} from '@electron/remote'; 9} from '@electron/remote';
10import { autorun, observable } from 'mobx'; 10import { autorun, makeObservable, observable } from 'mobx';
11import { defineMessages } from 'react-intl'; 11import { defineMessages } from 'react-intl';
12import osName from 'os-name'; 12import osName from 'os-name';
13import { 13import {
@@ -626,6 +626,8 @@ class FranzMenu {
626 this.stores = stores; 626 this.stores = stores;
627 this.actions = actions; 627 this.actions = actions;
628 628
629 makeObservable(this);
630
629 setTimeout(() => { 631 setTimeout(() => {
630 autorun(this._build.bind(this)); 632 autorun(this._build.bind(this));
631 }, 10); 633 }, 10);
diff --git a/src/models/Service.ts b/src/models/Service.ts
index 35d573cab..92b8ee64c 100644
--- a/src/models/Service.ts
+++ b/src/models/Service.ts
@@ -1,4 +1,4 @@
1import { autorun, computed, observable } from 'mobx'; 1import { autorun, computed, makeObservable, observable } from 'mobx';
2import { ipcRenderer } from 'electron'; 2import { ipcRenderer } from 'electron';
3import { webContents } from '@electron/remote'; 3import { webContents } from '@electron/remote';
4import normalizeUrl from 'normalize-url'; 4import normalizeUrl from 'normalize-url';
@@ -132,6 +132,8 @@ export default class Service {
132 throw new Error('Service recipe not valid'); 132 throw new Error('Service recipe not valid');
133 } 133 }
134 134
135 makeObservable(this);
136
135 this.recipe = recipe; 137 this.recipe = recipe;
136 138
137 this.userAgentModel = new UserAgent(recipe.overrideUserAgent); 139 this.userAgentModel = new UserAgent(recipe.overrideUserAgent);
diff --git a/src/models/User.ts b/src/models/User.ts
index 14481fbb6..6540a14e9 100644
--- a/src/models/User.ts
+++ b/src/models/User.ts
@@ -1,4 +1,4 @@
1import { observable } from 'mobx'; 1import { makeObservable, observable } from 'mobx';
2 2
3interface IUser { 3interface IUser {
4 id: string | null; 4 id: string | null;
@@ -42,6 +42,8 @@ export default class User {
42 @observable team = {}; 42 @observable team = {};
43 43
44 constructor(data: IUser) { 44 constructor(data: IUser) {
45 makeObservable(this);
46
45 if (!data) { 47 if (!data) {
46 throw new Error('User config not valid'); 48 throw new Error('User config not valid');
47 } 49 }
diff --git a/src/models/UserAgent.ts b/src/models/UserAgent.ts
index 1d06d72b0..d54286ee8 100644
--- a/src/models/UserAgent.ts
+++ b/src/models/UserAgent.ts
@@ -1,4 +1,4 @@
1import { action, computed, observe, observable } from 'mobx'; 1import { action, computed, makeObservable, observable, observe } from 'mobx';
2 2
3import ElectronWebView from 'react-electron-web-view'; 3import ElectronWebView from 'react-electron-web-view';
4import defaultUserAgent from '../helpers/userAgent-helpers'; 4import defaultUserAgent from '../helpers/userAgent-helpers';
@@ -21,6 +21,8 @@ export default class UserAgent {
21 @observable overrideUserAgent = (): string => ''; 21 @observable overrideUserAgent = (): string => '';
22 22
23 constructor(overrideUserAgent: any = null) { 23 constructor(overrideUserAgent: any = null) {
24 makeObservable(this);
25
24 if (typeof overrideUserAgent === 'function') { 26 if (typeof overrideUserAgent === 'function') {
25 this.overrideUserAgent = overrideUserAgent; 27 this.overrideUserAgent = overrideUserAgent;
26 } 28 }
diff --git a/src/routes.tsx b/src/routes.tsx
index 490d13ee8..1f929531e 100644
--- a/src/routes.tsx
+++ b/src/routes.tsx
@@ -1,6 +1,11 @@
1import { Component, ReactElement } from 'react'; 1import { Component, ReactElement } from 'react';
2import { inject, observer } from 'mobx-react'; 2import { inject, observer } from 'mobx-react';
3import { Router, Route, IndexRedirect } from 'react-router'; 3import { Route } from 'react-router';
4import {
5 Navigate,
6 Routes,
7 unstable_HistoryRouter as HistoryRouter,
8} from 'react-router-dom';
4 9
5import AppLayoutContainer from './containers/layout/AppLayoutContainer'; 10import AppLayoutContainer from './containers/layout/AppLayoutContainer';
6import SettingsWindow from './containers/settings/SettingsWindow'; 11import SettingsWindow from './containers/settings/SettingsWindow';
@@ -25,59 +30,137 @@ import AuthLayoutContainer from './containers/auth/AuthLayoutContainer';
25import WorkspacesScreen from './features/workspaces/containers/WorkspacesScreen'; 30import WorkspacesScreen from './features/workspaces/containers/WorkspacesScreen';
26import EditWorkspaceScreen from './features/workspaces/containers/EditWorkspaceScreen'; 31import EditWorkspaceScreen from './features/workspaces/containers/EditWorkspaceScreen';
27import { WORKSPACES_ROUTES } from './features/workspaces/constants'; 32import { WORKSPACES_ROUTES } from './features/workspaces/constants';
33import { Actions } from './actions/lib/actions';
34import { RealStores } from './stores';
28 35
29type Props = { 36type Props = {
37 stores: RealStores;
38 actions: Actions;
30 history: any; 39 history: any;
31}; 40};
32 41
33class Routes extends Component<Props> { 42class FerdiumRoutes extends Component<Props> {
34 render(): ReactElement { 43 render(): ReactElement {
35 const { history } = this.props; 44 const { history } = this.props;
45 const routeProps = {
46 stores: this.props.stores,
47 actions: this.props.actions,
48 };
49 const errorProps = {
50 error: this.props.stores.globalError.error || {},
51 };
36 52
37 return ( 53 return (
38 <Router history={history}> 54 <HistoryRouter history={history}>
39 <Route path="/" component={AppLayoutContainer}> 55 <Routes>
40 <Route path="/settings" component={SettingsWindow}> 56 <Route path="/auth" element={<AuthLayoutContainer {...routeProps} />}>
41 <IndexRedirect to="/settings/recipes" />
42 <Route path="/settings/recipes" component={RecipesScreen} />
43 <Route path="/settings/recipes/:filter" component={RecipesScreen} />
44 <Route path="/settings/services" component={ServicesScreen} />
45 <Route 57 <Route
46 path="/settings/services/:action/:id" 58 path="/auth"
47 component={EditServiceScreen} 59 element={<Navigate to="/auth/welcome" replace />}
48 /> 60 />
49 <Route path={WORKSPACES_ROUTES.ROOT} component={WorkspacesScreen} />
50 <Route 61 <Route
51 path={WORKSPACES_ROUTES.EDIT} 62 path="/auth/welcome"
52 component={EditWorkspaceScreen} 63 element={<WelcomeScreen {...routeProps} />}
64 />
65 <Route
66 path="/auth/login"
67 element={<LoginScreen {...routeProps} {...errorProps} />}
68 />
69 <Route
70 path="/auth/server"
71 element={<ChangeServerScreen {...routeProps} />}
72 />
73 <Route path="/auth/signup">
74 <Route
75 path="/auth/signup"
76 element={<Navigate to="/auth/signup/form" replace />}
77 />
78 <Route
79 path="/auth/signup/form"
80 element={<SignupScreen {...routeProps} {...errorProps} />}
81 />
82 <Route
83 path="/auth/signup/import"
84 element={<ImportScreen {...routeProps} />}
85 />
86 <Route
87 path="/auth/signup/setup"
88 element={<SetupAssistentScreen {...routeProps} />}
89 />
90 <Route
91 path="/auth/signup/invite"
92 element={<InviteScreen {...routeProps} />}
93 />
94 </Route>
95 <Route
96 path="/auth/password"
97 element={<PasswordScreen {...routeProps} />}
98 />
99 <Route
100 path="/auth/logout"
101 element={<LoginScreen {...routeProps} {...errorProps} />}
53 /> 102 />
54 <Route path="/settings/user" component={AccountScreen} />
55 <Route path="/settings/user/edit" component={EditUserScreen} />
56 <Route path="/settings/team" component={TeamScreen} />
57 <Route path="/settings/app" component={EditSettingsScreen} />
58 <Route path="/settings/invite" component={InviteSettingsScreen} />
59 <Route path="/settings/support" component={SupportFerdiumScreen} />
60 </Route> 103 </Route>
61 </Route> 104
62 <Route path="/auth" component={AuthLayoutContainer}> 105 <Route path="/" element={<AppLayoutContainer {...routeProps} />}>
63 <IndexRedirect to="/auth/welcome" /> 106 <Route
64 <Route path="/auth/welcome" component={WelcomeScreen} /> 107 path="/settings"
65 <Route path="/auth/login" component={LoginScreen} /> 108 element={<SettingsWindow {...this.props} />}
66 <Route path="/auth/server" component={ChangeServerScreen} /> 109 >
67 <Route path="/auth/signup"> 110 <Route
68 <IndexRedirect to="/auth/signup/form" /> 111 path="/settings/recipes"
69 <Route path="/auth/signup/form" component={SignupScreen} /> 112 element={<RecipesScreen {...this.props} />}
70 <Route path="/auth/signup/import" component={ImportScreen} /> 113 />
71 <Route path="/auth/signup/setup" component={SetupAssistentScreen} /> 114 <Route
72 <Route path="/auth/signup/invite" component={InviteScreen} /> 115 path="/settings/recipes/:filter"
116 element={<RecipesScreen {...this.props} />}
117 />
118 <Route
119 path="/settings/services"
120 element={<ServicesScreen {...this.props} />}
121 />
122 <Route
123 path="/settings/services/:action/:id"
124 element={<EditServiceScreen {...this.props} />}
125 />
126 <Route
127 path={WORKSPACES_ROUTES.ROOT}
128 element={<WorkspacesScreen {...this.props} />}
129 />
130 <Route
131 path={WORKSPACES_ROUTES.EDIT}
132 element={<EditWorkspaceScreen {...this.props} />}
133 />
134 <Route
135 path="/settings/user"
136 element={<AccountScreen {...this.props} />}
137 />
138 <Route
139 path="/settings/user/edit"
140 element={<EditUserScreen {...this.props} />}
141 />
142 <Route
143 path="/settings/team"
144 element={<TeamScreen {...this.props} />}
145 />
146 <Route
147 path="/settings/app"
148 element={<EditSettingsScreen {...this.props} />}
149 />
150 <Route
151 path="/settings/invite"
152 element={<InviteSettingsScreen {...this.props} />}
153 />
154 <Route
155 path="/settings/support"
156 element={<SupportFerdiumScreen {...this.props} />}
157 />
158 </Route>
73 </Route> 159 </Route>
74 <Route path="/auth/password" component={PasswordScreen} /> 160 </Routes>
75 <Route path="/auth/logout" component={LoginScreen} /> 161 </HistoryRouter>
76 </Route>
77 <Route path="*" component={AppLayoutContainer} />
78 </Router>
79 ); 162 );
80 } 163 }
81} 164}
82 165
83export default inject('stores', 'actions')(observer(Routes)); 166export default inject('stores', 'actions')(observer(FerdiumRoutes));
diff --git a/src/stores/AppStore.ts b/src/stores/AppStore.ts
index 0ecfdb7c0..ed6d0e263 100644
--- a/src/stores/AppStore.ts
+++ b/src/stores/AppStore.ts
@@ -7,7 +7,7 @@ import {
7 getCurrentWindow, 7 getCurrentWindow,
8 process as remoteProcess, 8 process as remoteProcess,
9} from '@electron/remote'; 9} from '@electron/remote';
10import { action, computed, observable } from 'mobx'; 10import { action, computed, makeObservable, observable } from 'mobx';
11import moment from 'moment'; 11import moment from 'moment';
12import AutoLaunch from 'auto-launch'; 12import AutoLaunch from 'auto-launch';
13import ms from 'ms'; 13import ms from 'ms';
@@ -105,6 +105,8 @@ export default class AppStore extends TypedStore {
105 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 105 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
106 super(stores, api, actions); 106 super(stores, api, actions);
107 107
108 makeObservable(this);
109
108 // Register action handlers 110 // Register action handlers
109 this.actions.app.notify.listen(this._notify.bind(this)); 111 this.actions.app.notify.listen(this._notify.bind(this));
110 this.actions.app.setBadge.listen(this._setBadge.bind(this)); 112 this.actions.app.setBadge.listen(this._setBadge.bind(this));
@@ -510,7 +512,7 @@ export default class AppStore extends TypedStore {
510 } 512 }
511 513
512 _setLocale() { 514 _setLocale() {
513 if (this.stores.user.isLoggedIn && this.stores.user.data.locale) { 515 if (this.stores.user?.isLoggedIn && this.stores.user?.data.locale) {
514 this.locale = this.stores.user.data.locale; 516 this.locale = this.stores.user.data.locale;
515 } else if (!this.locale) { 517 } else if (!this.locale) {
516 this.locale = this._getDefaultLocale(); 518 this.locale = this._getDefaultLocale();
diff --git a/src/stores/FeaturesStore.ts b/src/stores/FeaturesStore.ts
index b63c252df..ed0c6c17b 100644
--- a/src/stores/FeaturesStore.ts
+++ b/src/stores/FeaturesStore.ts
@@ -1,5 +1,14 @@
1import { computed, observable, runInAction } from 'mobx'; 1import {
2 action,
3 computed,
4 makeObservable,
5 observable,
6 runInAction,
7} from 'mobx';
2 8
9import { Stores } from '../@types/stores.types';
10import { ApiInterface } from '../api';
11import { Actions } from '../actions/lib/actions';
3import CachedRequest from './lib/CachedRequest'; 12import CachedRequest from './lib/CachedRequest';
4import serviceProxy from '../features/serviceProxy'; 13import serviceProxy from '../features/serviceProxy';
5import basicAuth from '../features/basicAuth'; 14import basicAuth from '../features/basicAuth';
@@ -24,6 +33,12 @@ export default class FeaturesStore extends TypedStore {
24 33
25 @observable features = {}; 34 @observable features = {};
26 35
36 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
37 super(stores, api, actions);
38
39 makeObservable(this);
40 }
41
27 async setup(): Promise<void> { 42 async setup(): Promise<void> {
28 this.registerReactions([ 43 this.registerReactions([
29 this._updateFeatures, 44 this._updateFeatures,
@@ -49,9 +64,11 @@ export default class FeaturesStore extends TypedStore {
49 } 64 }
50 Object.assign(features, requestResult); 65 Object.assign(features, requestResult);
51 } 66 }
52 runInAction('FeaturesStore::_updateFeatures', () => { 67 runInAction(
53 this.features = features; 68 action('FeaturesStore::_updateFeatures', () => {
54 }); 69 this.features = features;
70 }),
71 );
55 }; 72 };
56 73
57 _monitorLoginStatus(): void { 74 _monitorLoginStatus(): void {
diff --git a/src/stores/GlobalErrorStore.ts b/src/stores/GlobalErrorStore.ts
index 8c6317c91..c42e9a4af 100644
--- a/src/stores/GlobalErrorStore.ts
+++ b/src/stores/GlobalErrorStore.ts
@@ -1,4 +1,4 @@
1import { observable, action } from 'mobx'; 1import { observable, action, makeObservable } from 'mobx';
2import { Actions } from '../actions/lib/actions'; 2import { Actions } from '../actions/lib/actions';
3import { ApiInterface } from '../api'; 3import { ApiInterface } from '../api';
4import { Stores } from '../@types/stores.types'; 4import { Stores } from '../@types/stores.types';
@@ -34,6 +34,8 @@ export default class GlobalErrorStore extends TypedStore {
34 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 34 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
35 super(stores, api, actions); 35 super(stores, api, actions);
36 36
37 makeObservable(this);
38
37 window.addEventListener('error', (...errorArgs: any[]): void => { 39 window.addEventListener('error', (...errorArgs: any[]): void => {
38 // @ts-ignore ts-message: Expected 5 arguments, but got 2. 40 // @ts-ignore ts-message: Expected 5 arguments, but got 2.
39 this._handleConsoleError.call(this, ['error', ...errorArgs]); 41 this._handleConsoleError.call(this, ['error', ...errorArgs]);
diff --git a/src/stores/RecipePreviewsStore.ts b/src/stores/RecipePreviewsStore.ts
index b1d50c8b8..1c95e6b54 100644
--- a/src/stores/RecipePreviewsStore.ts
+++ b/src/stores/RecipePreviewsStore.ts
@@ -1,4 +1,5 @@
1import { action, computed, observable } from 'mobx'; 1import { action, computed, makeObservable, observable } from 'mobx';
2
2import { Actions } from '../actions/lib/actions'; 3import { Actions } from '../actions/lib/actions';
3import { ApiInterface } from '../api'; 4import { ApiInterface } from '../api';
4import Recipe from '../models/Recipe'; 5import Recipe from '../models/Recipe';
@@ -28,6 +29,8 @@ export default class RecipePreviewsStore extends TypedStore {
28 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 29 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
29 super(stores, api, actions); 30 super(stores, api, actions);
30 31
32 makeObservable(this);
33
31 // Register action handlers 34 // Register action handlers
32 this.actions.recipePreview.search.listen(this._search.bind(this)); 35 this.actions.recipePreview.search.listen(this._search.bind(this));
33 } 36 }
diff --git a/src/stores/RecipesStore.ts b/src/stores/RecipesStore.ts
index 364d56dd2..25304e97c 100644
--- a/src/stores/RecipesStore.ts
+++ b/src/stores/RecipesStore.ts
@@ -1,4 +1,4 @@
1import { action, computed, observable } from 'mobx'; 1import { action, computed, makeObservable, observable } from 'mobx';
2import { readJSONSync } from 'fs-extra'; 2import { readJSONSync } from 'fs-extra';
3import semver from 'semver'; 3import semver from 'semver';
4 4
@@ -24,6 +24,8 @@ export default class RecipesStore extends TypedStore {
24 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 24 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
25 super(stores, api, actions); 25 super(stores, api, actions);
26 26
27 makeObservable(this);
28
27 // Register action handlers 29 // Register action handlers
28 this.actions.recipe.install.listen(this._install.bind(this)); 30 this.actions.recipe.install.listen(this._install.bind(this));
29 this.actions.recipe.update.listen(this._update.bind(this)); 31 this.actions.recipe.update.listen(this._update.bind(this));
diff --git a/src/stores/RequestStore.ts b/src/stores/RequestStore.ts
index e5df1292d..a964c5d12 100644
--- a/src/stores/RequestStore.ts
+++ b/src/stores/RequestStore.ts
@@ -1,5 +1,5 @@
1import { ipcRenderer } from 'electron'; 1import { ipcRenderer } from 'electron';
2import { action, computed, observable } from 'mobx'; 2import { action, computed, makeObservable, observable } from 'mobx';
3import ms from 'ms'; 3import ms from 'ms';
4 4
5import { Actions } from '../actions/lib/actions'; 5import { Actions } from '../actions/lib/actions';
@@ -28,6 +28,8 @@ export default class RequestStore extends TypedStore {
28 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 28 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
29 super(stores, api, actions); 29 super(stores, api, actions);
30 30
31 makeObservable(this);
32
31 this.actions.requests.retryRequiredRequests.listen( 33 this.actions.requests.retryRequiredRequests.listen(
32 this._retryRequiredRequests.bind(this), 34 this._retryRequiredRequests.bind(this),
33 ); 35 );
diff --git a/src/stores/ServicesStore.ts b/src/stores/ServicesStore.ts
index 4c1b4116c..7812d5aee 100644
--- a/src/stores/ServicesStore.ts
+++ b/src/stores/ServicesStore.ts
@@ -1,5 +1,5 @@
1import { shell } from 'electron'; 1import { shell } from 'electron';
2import { action, reaction, computed, observable } from 'mobx'; 2import { action, reaction, computed, observable, makeObservable } from 'mobx';
3import { debounce, remove } from 'lodash'; 3import { debounce, remove } from 'lodash';
4import ms from 'ms'; 4import ms from 'ms';
5import { ensureFileSync, pathExistsSync, writeFileSync } from 'fs-extra'; 5import { ensureFileSync, pathExistsSync, writeFileSync } from 'fs-extra';
@@ -67,6 +67,8 @@ export default class ServicesStore extends TypedStore {
67 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 67 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
68 super(stores, api, actions); 68 super(stores, api, actions);
69 69
70 makeObservable(this);
71
70 // Register action handlers 72 // Register action handlers
71 this.actions.service.setActive.listen(this._setActive.bind(this)); 73 this.actions.service.setActive.listen(this._setActive.bind(this));
72 this.actions.service.blurActive.listen(this._blurActive.bind(this)); 74 this.actions.service.blurActive.listen(this._blurActive.bind(this));
diff --git a/src/stores/SettingsStore.ts b/src/stores/SettingsStore.ts
index 0296ba0e7..a03d3c188 100644
--- a/src/stores/SettingsStore.ts
+++ b/src/stores/SettingsStore.ts
@@ -1,6 +1,7 @@
1
1import { ipcRenderer } from 'electron'; 2import { ipcRenderer } from 'electron';
2import { getCurrentWindow } from '@electron/remote'; 3import { getCurrentWindow } from '@electron/remote';
3import { action, computed, observable, reaction } from 'mobx'; 4import { action, computed, makeObservable, observable, reaction } from 'mobx';
4import localStorage from 'mobx-localstorage'; 5import localStorage from 'mobx-localstorage';
5import { Stores } from '../@types/stores.types'; 6import { Stores } from '../@types/stores.types';
6import { ApiInterface } from '../api'; 7import { ApiInterface } from '../api';
@@ -22,7 +23,7 @@ export default class SettingsStore extends TypedStore {
22 'updateAppSettings', 23 'updateAppSettings',
23 ); 24 );
24 25
25 loaded = false; 26 @observable loaded: boolean = false;
26 27
27 fileSystemSettingsTypes = FILE_SYSTEM_SETTINGS_TYPES; 28 fileSystemSettingsTypes = FILE_SYSTEM_SETTINGS_TYPES;
28 29
@@ -34,6 +35,8 @@ export default class SettingsStore extends TypedStore {
34 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 35 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
35 super(stores, api, actions); 36 super(stores, api, actions);
36 37
38 makeObservable(this);
39
37 // Register action handlers 40 // Register action handlers
38 this.actions.settings.update.listen(this._update.bind(this)); 41 this.actions.settings.update.listen(this._update.bind(this));
39 this.actions.settings.remove.listen(this._remove.bind(this)); 42 this.actions.settings.remove.listen(this._remove.bind(this));
diff --git a/src/stores/UIStore.ts b/src/stores/UIStore.ts
index c43c6d8c7..e0589729f 100644
--- a/src/stores/UIStore.ts
+++ b/src/stores/UIStore.ts
@@ -1,4 +1,4 @@
1import { action, observable, computed, reaction } from 'mobx'; 1import { action, observable, computed, reaction, makeObservable } from 'mobx';
2import { nativeTheme } from '@electron/remote'; 2import { nativeTheme } from '@electron/remote';
3 3
4import { Stores } from '../@types/stores.types'; 4import { Stores } from '../@types/stores.types';
@@ -14,6 +14,9 @@ export default class UIStore extends TypedStore {
14 14
15 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 15 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
16 super(stores, api, actions); 16 super(stores, api, actions);
17
18 makeObservable(this);
19
17 // Register action handlers 20 // Register action handlers
18 this.actions.ui.openSettings.listen(this._openSettings.bind(this)); 21 this.actions.ui.openSettings.listen(this._openSettings.bind(this));
19 this.actions.ui.closeSettings.listen(this._closeSettings.bind(this)); 22 this.actions.ui.closeSettings.listen(this._closeSettings.bind(this));
diff --git a/src/stores/UserStore.ts b/src/stores/UserStore.ts
index b9c3c7576..c5e67c966 100644
--- a/src/stores/UserStore.ts
+++ b/src/stores/UserStore.ts
@@ -1,4 +1,4 @@
1import { observable, computed, action } from 'mobx'; 1import { observable, computed, action, makeObservable } from 'mobx';
2import moment from 'moment'; 2import moment from 'moment';
3import jwt from 'jsonwebtoken'; 3import jwt from 'jsonwebtoken';
4import localStorage from 'mobx-localstorage'; 4import localStorage from 'mobx-localstorage';
@@ -93,6 +93,8 @@ export default class UserStore extends TypedStore {
93 constructor(stores: Stores, api: ApiInterface, actions: Actions) { 93 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
94 super(stores, api, actions); 94 super(stores, api, actions);
95 95
96 makeObservable(this);
97
96 // Register action handlers 98 // Register action handlers
97 this.actions.user.login.listen(this._login.bind(this)); 99 this.actions.user.login.listen(this._login.bind(this));
98 this.actions.user.retrievePassword.listen( 100 this.actions.user.retrievePassword.listen(
diff --git a/src/stores/index.ts b/src/stores/index.ts
index d31f2c933..8836f2892 100644
--- a/src/stores/index.ts
+++ b/src/stores/index.ts
@@ -1,4 +1,4 @@
1import { RouterStore } from 'mobx-react-router'; 1import { RouterStore } from '@superwf/mobx-react-router';
2import { ApiInterface } from '../api'; 2import { ApiInterface } from '../api';
3import { Actions } from '../actions/lib/actions'; 3import { Actions } from '../actions/lib/actions';
4import AppStore from './AppStore'; 4import AppStore from './AppStore';
diff --git a/src/stores/lib/Request.js b/src/stores/lib/Request.js
index 0ac36a218..e58341790 100644
--- a/src/stores/lib/Request.js
+++ b/src/stores/lib/Request.js
@@ -1,4 +1,4 @@
1import { observable, action, computed } from 'mobx'; 1import { observable, action, computed, makeObservable } from 'mobx';
2import { isEqual } from 'lodash/fp'; 2import { isEqual } from 'lodash/fp';
3 3
4export default class Request { 4export default class Request {
@@ -29,6 +29,8 @@ export default class Request {
29 _currentApiCall = null; 29 _currentApiCall = null;
30 30
31 constructor(api, method) { 31 constructor(api, method) {
32 makeObservable(this);
33
32 this._api = api; 34 this._api = api;
33 this._method = method; 35 this._method = method;
34 } 36 }
diff --git a/src/stores/lib/TypedStore.ts b/src/stores/lib/TypedStore.ts
index c97ae1aa5..e44eadd32 100644
--- a/src/stores/lib/TypedStore.ts
+++ b/src/stores/lib/TypedStore.ts
@@ -1,4 +1,4 @@
1import { computed, IReactionPublic, observable } from 'mobx'; 1import { computed, IReactionPublic, makeObservable, observable } from 'mobx';
2import { Actions } from '../../actions/lib/actions'; 2import { Actions } from '../../actions/lib/actions';
3import { ApiInterface } from '../../api'; 3import { ApiInterface } from '../../api';
4import { Stores } from '../../@types/stores.types'; 4import { Stores } from '../../@types/stores.types';
@@ -9,6 +9,12 @@ export default abstract class TypedStore {
9 9
10 @observable _status: any = null; 10 @observable _status: any = null;
11 11
12 stores: Stores;
13
14 api: ApiInterface;
15
16 actions: Actions;
17
12 @computed get actionStatus() { 18 @computed get actionStatus() {
13 return this._status || []; 19 return this._status || [];
14 } 20 }
@@ -17,11 +23,13 @@ export default abstract class TypedStore {
17 this._status = status; 23 this._status = status;
18 } 24 }
19 25
20 constructor( 26 constructor(stores: Stores, api: ApiInterface, actions: Actions) {
21 public readonly stores: Stores, 27 makeObservable(this);
22 public readonly api: ApiInterface, 28
23 public readonly actions: Actions, 29 this.stores = stores;
24 ) {} 30 this.api = api;
31 this.actions = actions;
32 }
25 33
26 registerReactions(reactions: { (r: IReactionPublic): void }[]): void { 34 registerReactions(reactions: { (r: IReactionPublic): void }[]): void {
27 for (const reaction of reactions) { 35 for (const reaction of reactions) {
diff --git a/src/webview/recipe.js b/src/webview/recipe.js
index 3c8a5326f..102d93642 100644
--- a/src/webview/recipe.js
+++ b/src/webview/recipe.js
@@ -2,7 +2,7 @@
2/* eslint-disable import/first */ 2/* eslint-disable import/first */
3import { contextBridge, ipcRenderer } from 'electron'; 3import { contextBridge, ipcRenderer } from 'electron';
4import { join } from 'path'; 4import { join } from 'path';
5import { autorun, computed, observable } from 'mobx'; 5import { autorun, computed, makeObservable, observable } from 'mobx';
6import { pathExistsSync, readFileSync } from 'fs-extra'; 6import { pathExistsSync, readFileSync } from 'fs-extra';
7import { debounce } from 'lodash'; 7import { debounce } from 'lodash';
8 8
@@ -154,6 +154,8 @@ class RecipeController {
154 hasUpdatedBeforeRecipeLoaded = false; 154 hasUpdatedBeforeRecipeLoaded = false;
155 155
156 constructor() { 156 constructor() {
157 makeObservable(this);
158
157 this.initialize(); 159 this.initialize();
158 } 160 }
159 161