diff options
-rw-r--r-- | src/components/layout/Sidebar.js | 36 | ||||
-rw-r--r-- | src/components/settings/navigation/SettingsNavigation.js | 21 | ||||
-rw-r--r-- | src/components/settings/settings/EditSettingsForm.js | 16 | ||||
-rw-r--r-- | src/config.ts | 9 | ||||
-rw-r--r-- | src/containers/settings/EditServiceScreen.js | 2 | ||||
-rw-r--r-- | src/containers/settings/EditSettingsScreen.js | 18 | ||||
-rwxr-xr-x | src/features/settingsWS/actions.ts | 13 | ||||
-rwxr-xr-x | src/features/settingsWS/index.ts | 28 | ||||
-rwxr-xr-x | src/features/settingsWS/state.ts | 13 | ||||
-rwxr-xr-x | src/features/settingsWS/store.js | 132 | ||||
-rw-r--r-- | src/features/todos/index.ts | 25 | ||||
-rw-r--r-- | src/features/todos/store.js | 9 | ||||
-rw-r--r-- | src/features/workspaces/index.ts | 22 | ||||
-rw-r--r-- | src/features/workspaces/store.js | 8 | ||||
-rw-r--r-- | src/internal-server/app/Controllers/Http/StaticController.js | 20 | ||||
-rw-r--r-- | src/internal-server/start/routes.js | 5 | ||||
-rw-r--r-- | src/lib/Menu.js | 21 | ||||
-rw-r--r-- | src/stores.types.ts | 4 | ||||
-rw-r--r-- | src/stores/FeaturesStore.js | 10 |
19 files changed, 50 insertions, 362 deletions
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index 2bae57648..18492be80 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js | |||
@@ -14,7 +14,6 @@ import { | |||
14 | addNewServiceShortcutKey, | 14 | addNewServiceShortcutKey, |
15 | muteFerdiShortcutKey, | 15 | muteFerdiShortcutKey, |
16 | } from '../../environment'; | 16 | } from '../../environment'; |
17 | import { workspaceStore } from '../../features/workspaces'; | ||
18 | import { todosStore } from '../../features/todos'; | 17 | import { todosStore } from '../../features/todos'; |
19 | import { todoActions } from '../../features/todos/actions'; | 18 | import { todoActions } from '../../features/todos/actions'; |
20 | import AppStore from '../../stores/AppStore'; | 19 | import AppStore from '../../stores/AppStore'; |
@@ -160,8 +159,7 @@ class Sidebar extends Component { | |||
160 | <i className="mdi mdi-lock" /> | 159 | <i className="mdi mdi-lock" /> |
161 | </button> | 160 | </button> |
162 | ) : null} | 161 | ) : null} |
163 | {todosStore.isFeatureEnabled && | 162 | {todosStore.isFeatureEnabledByUser ? ( |
164 | todosStore.isFeatureEnabledByUser ? ( | ||
165 | <button | 163 | <button |
166 | type="button" | 164 | type="button" |
167 | onClick={() => { | 165 | onClick={() => { |
@@ -179,23 +177,21 @@ class Sidebar extends Component { | |||
179 | <i className="mdi mdi-check-all" /> | 177 | <i className="mdi mdi-check-all" /> |
180 | </button> | 178 | </button> |
181 | ) : null} | 179 | ) : null} |
182 | {workspaceStore.isFeatureEnabled ? ( | 180 | <button |
183 | <button | 181 | type="button" |
184 | type="button" | 182 | onClick={() => { |
185 | onClick={() => { | 183 | toggleWorkspaceDrawer(); |
186 | toggleWorkspaceDrawer(); | 184 | this.updateToolTip(); |
187 | this.updateToolTip(); | 185 | }} |
188 | }} | 186 | className={`sidebar__button sidebar__button--workspaces ${ |
189 | className={`sidebar__button sidebar__button--workspaces ${ | 187 | isWorkspaceDrawerOpen ? 'is-active' : '' |
190 | isWorkspaceDrawerOpen ? 'is-active' : '' | 188 | }`} |
191 | }`} | 189 | data-tip={`${intl.formatMessage( |
192 | data-tip={`${intl.formatMessage( | 190 | workspaceToggleMessage, |
193 | workspaceToggleMessage, | 191 | )} (${workspaceToggleShortcutKey(false)})`} |
194 | )} (${workspaceToggleShortcutKey(false)})`} | 192 | > |
195 | > | 193 | <i className="mdi mdi-view-grid" /> |
196 | <i className="mdi mdi-view-grid" /> | 194 | </button> |
197 | </button> | ||
198 | ) : null} | ||
199 | <button | 195 | <button |
200 | type="button" | 196 | type="button" |
201 | onClick={() => { | 197 | onClick={() => { |
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index 18a71fdeb..dbb1365b0 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js | |||
@@ -6,7 +6,6 @@ import { RouterStore } from 'mobx-react-router'; | |||
6 | 6 | ||
7 | import { LOCAL_SERVER, LIVE_FERDI_API, LIVE_FRANZ_API } from '../../../config'; | 7 | import { LOCAL_SERVER, LIVE_FERDI_API, LIVE_FRANZ_API } from '../../../config'; |
8 | import Link from '../../ui/Link'; | 8 | import Link from '../../ui/Link'; |
9 | import { workspaceStore } from '../../../features/workspaces'; | ||
10 | import UIStore from '../../../stores/UIStore'; | 9 | import UIStore from '../../../stores/UIStore'; |
11 | import SettingsStore from '../../../stores/SettingsStore'; | 10 | import SettingsStore from '../../../stores/SettingsStore'; |
12 | import UserStore from '../../../stores/UserStore'; | 11 | import UserStore from '../../../stores/UserStore'; |
@@ -117,17 +116,15 @@ class SettingsNavigation extends Component { | |||
117 | {intl.formatMessage(messages.yourServices)}{' '} | 116 | {intl.formatMessage(messages.yourServices)}{' '} |
118 | <span className="badge">{serviceCount}</span> | 117 | <span className="badge">{serviceCount}</span> |
119 | </Link> | 118 | </Link> |
120 | {workspaceStore.isFeatureEnabled ? ( | 119 | <Link |
121 | <Link | 120 | to="/settings/workspaces" |
122 | to="/settings/workspaces" | 121 | className="settings-navigation__link" |
123 | className="settings-navigation__link" | 122 | activeClassName="is-active" |
124 | activeClassName="is-active" | 123 | disabled={!isLoggedIn} |
125 | disabled={!isLoggedIn} | 124 | > |
126 | > | 125 | {intl.formatMessage(messages.yourWorkspaces)}{' '} |
127 | {intl.formatMessage(messages.yourWorkspaces)}{' '} | 126 | <span className="badge">{workspaceCount}</span> |
128 | <span className="badge">{workspaceCount}</span> | 127 | </Link> |
129 | </Link> | ||
130 | ) : null} | ||
131 | {!isUsingWithoutAccount && ( | 128 | {!isUsingWithoutAccount && ( |
132 | <Link | 129 | <Link |
133 | to="/settings/user" | 130 | to="/settings/user" |
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index 60bd91493..54f2025e5 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js | |||
@@ -194,9 +194,7 @@ class EditSettingsForm extends Component { | |||
194 | isClearingAllCache: PropTypes.bool.isRequired, | 194 | isClearingAllCache: PropTypes.bool.isRequired, |
195 | onClearAllCache: PropTypes.func.isRequired, | 195 | onClearAllCache: PropTypes.func.isRequired, |
196 | getCacheSize: PropTypes.func.isRequired, | 196 | getCacheSize: PropTypes.func.isRequired, |
197 | isTodosEnabled: PropTypes.bool.isRequired, | ||
198 | isTodosActivated: PropTypes.bool.isRequired, | 197 | isTodosActivated: PropTypes.bool.isRequired, |
199 | isWorkspaceEnabled: PropTypes.bool.isRequired, | ||
200 | automaticUpdates: PropTypes.bool.isRequired, | 198 | automaticUpdates: PropTypes.bool.isRequired, |
201 | isDarkmodeEnabled: PropTypes.bool.isRequired, | 199 | isDarkmodeEnabled: PropTypes.bool.isRequired, |
202 | isAdaptableDarkModeEnabled: PropTypes.bool.isRequired, | 200 | isAdaptableDarkModeEnabled: PropTypes.bool.isRequired, |
@@ -244,8 +242,6 @@ class EditSettingsForm extends Component { | |||
244 | isClearingAllCache, | 242 | isClearingAllCache, |
245 | onClearAllCache, | 243 | onClearAllCache, |
246 | getCacheSize, | 244 | getCacheSize, |
247 | isTodosEnabled, | ||
248 | isWorkspaceEnabled, | ||
249 | automaticUpdates, | 245 | automaticUpdates, |
250 | isDarkmodeEnabled, | 246 | isDarkmodeEnabled, |
251 | isTodosActivated, | 247 | isTodosActivated, |
@@ -414,14 +410,12 @@ class EditSettingsForm extends Component { | |||
414 | 410 | ||
415 | <Hr /> | 411 | <Hr /> |
416 | 412 | ||
417 | {isWorkspaceEnabled && ( | 413 | <> |
418 | <> | 414 | <Toggle field={form.$('keepAllWorkspacesLoaded')} /> |
419 | <Toggle field={form.$('keepAllWorkspacesLoaded')} /> | 415 | <Hr /> |
420 | <Hr /> | 416 | </> |
421 | </> | ||
422 | )} | ||
423 | 417 | ||
424 | {isTodosEnabled && !hasAddedTodosAsService && ( | 418 | {!hasAddedTodosAsService && ( |
425 | <> | 419 | <> |
426 | <Toggle field={form.$('enableTodos')} /> | 420 | <Toggle field={form.$('enableTodos')} /> |
427 | {isTodosActivated && ( | 421 | {isTodosActivated && ( |
diff --git a/src/config.ts b/src/config.ts index 15567bf66..fb073c062 100644 --- a/src/config.ts +++ b/src/config.ts | |||
@@ -140,13 +140,6 @@ export const ICON_SIZES = { | |||
140 | // The bias should always be the "Normal icons" value | 140 | // The bias should always be the "Normal icons" value |
141 | export const iconSizeBias = 20; | 141 | export const iconSizeBias = 20; |
142 | 142 | ||
143 | export const DEFAULT_FEATURES_CONFIG = { | ||
144 | isServiceProxyEnabled: true, | ||
145 | isWorkspaceEnabled: true, | ||
146 | isTodosEnabled: true, | ||
147 | isSettingsWSEnabled: false, | ||
148 | }; | ||
149 | |||
150 | export const DEFAULT_WINDOW_OPTIONS = { | 143 | export const DEFAULT_WINDOW_OPTIONS = { |
151 | width: 800, | 144 | width: 800, |
152 | height: 600, | 145 | height: 600, |
@@ -237,7 +230,7 @@ export const DEFAULT_APP_SETTINGS = { | |||
237 | liftSingleInstanceLock: false, | 230 | liftSingleInstanceLock: false, |
238 | enableLongPressServiceHint: false, | 231 | enableLongPressServiceHint: false, |
239 | proxyFeatureEnabled: false, | 232 | proxyFeatureEnabled: false, |
240 | onlyShowFavoritesInUnreadCount: false | 233 | onlyShowFavoritesInUnreadCount: false, |
241 | }; | 234 | }; |
242 | 235 | ||
243 | export const DEFAULT_SERVICE_SETTINGS = { | 236 | export const DEFAULT_SERVICE_SETTINGS = { |
diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.js index ef907dcb8..ddf7fab36 100644 --- a/src/containers/settings/EditServiceScreen.js +++ b/src/containers/settings/EditServiceScreen.js | |||
@@ -8,7 +8,6 @@ import UserStore from '../../stores/UserStore'; | |||
8 | import RecipesStore from '../../stores/RecipesStore'; | 8 | import RecipesStore from '../../stores/RecipesStore'; |
9 | import ServicesStore from '../../stores/ServicesStore'; | 9 | import ServicesStore from '../../stores/ServicesStore'; |
10 | import SettingsStore from '../../stores/SettingsStore'; | 10 | import SettingsStore from '../../stores/SettingsStore'; |
11 | import FeaturesStore from '../../stores/FeaturesStore'; | ||
12 | import Form from '../../lib/Form'; | 11 | import Form from '../../lib/Form'; |
13 | 12 | ||
14 | import ServiceError from '../../components/settings/services/ServiceError'; | 13 | import ServiceError from '../../components/settings/services/ServiceError'; |
@@ -445,7 +444,6 @@ EditServiceScreen.wrappedComponent.propTypes = { | |||
445 | recipes: PropTypes.instanceOf(RecipesStore).isRequired, | 444 | recipes: PropTypes.instanceOf(RecipesStore).isRequired, |
446 | services: PropTypes.instanceOf(ServicesStore).isRequired, | 445 | services: PropTypes.instanceOf(ServicesStore).isRequired, |
447 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | 446 | settings: PropTypes.instanceOf(SettingsStore).isRequired, |
448 | features: PropTypes.instanceOf(FeaturesStore).isRequired, | ||
449 | }).isRequired, | 447 | }).isRequired, |
450 | router: PropTypes.instanceOf(RouterStore).isRequired, | 448 | router: PropTypes.instanceOf(RouterStore).isRequired, |
451 | actions: PropTypes.shape({ | 449 | actions: PropTypes.shape({ |
diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js index 76c525045..64f5b2e01 100644 --- a/src/containers/settings/EditSettingsScreen.js +++ b/src/containers/settings/EditSettingsScreen.js | |||
@@ -339,14 +339,12 @@ class EditSettingsScreen extends Component { | |||
339 | }, | 339 | }, |
340 | }); | 340 | }); |
341 | 341 | ||
342 | if (workspaces.isFeatureActive) { | 342 | const { keepAllWorkspacesLoaded } = workspaces.settings; |
343 | const { keepAllWorkspacesLoaded } = workspaces.settings; | 343 | if ( |
344 | if ( | 344 | Boolean(keepAllWorkspacesLoaded) !== |
345 | Boolean(keepAllWorkspacesLoaded) !== | 345 | Boolean(settingsData.keepAllWorkspacesLoaded) |
346 | Boolean(settingsData.keepAllWorkspacesLoaded) | 346 | ) { |
347 | ) { | 347 | workspaceActions.toggleKeepAllWorkspacesLoadedSetting(); |
348 | workspaceActions.toggleKeepAllWorkspacesLoadedSetting(); | ||
349 | } | ||
350 | } | 348 | } |
351 | 349 | ||
352 | if (todos.isFeatureActive) { | 350 | if (todos.isFeatureActive) { |
@@ -696,7 +694,7 @@ class EditSettingsScreen extends Component { | |||
696 | } | 694 | } |
697 | 695 | ||
698 | render() { | 696 | render() { |
699 | const { app, todos, workspaces, services } = this.props.stores; | 697 | const { app, services } = this.props.stores; |
700 | const { | 698 | const { |
701 | updateStatus, | 699 | updateStatus, |
702 | updateStatusTypes, | 700 | updateStatusTypes, |
@@ -721,8 +719,6 @@ class EditSettingsScreen extends Component { | |||
721 | getCacheSize={() => app.cacheSize} | 719 | getCacheSize={() => app.cacheSize} |
722 | isClearingAllCache={isClearingAllCache} | 720 | isClearingAllCache={isClearingAllCache} |
723 | onClearAllCache={clearAllCache} | 721 | onClearAllCache={clearAllCache} |
724 | isTodosEnabled={todos.isFeatureActive} | ||
725 | isWorkspaceEnabled={workspaces.isFeatureActive} | ||
726 | lockingFeatureEnabled={lockingFeatureEnabled} | 722 | lockingFeatureEnabled={lockingFeatureEnabled} |
727 | automaticUpdates={this.props.stores.settings.app.automaticUpdates} | 723 | automaticUpdates={this.props.stores.settings.app.automaticUpdates} |
728 | isDarkmodeEnabled={this.props.stores.settings.app.darkMode} | 724 | isDarkmodeEnabled={this.props.stores.settings.app.darkMode} |
diff --git a/src/features/settingsWS/actions.ts b/src/features/settingsWS/actions.ts deleted file mode 100755 index 03a398eb5..000000000 --- a/src/features/settingsWS/actions.ts +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | import PropTypes from 'prop-types'; | ||
2 | import { createActionsFromDefinitions } from '../../actions/lib/actions'; | ||
3 | |||
4 | export const settingsWSActions = createActionsFromDefinitions( | ||
5 | { | ||
6 | greet: { | ||
7 | name: PropTypes.string.isRequired, | ||
8 | }, | ||
9 | }, | ||
10 | PropTypes.checkPropTypes, | ||
11 | ); | ||
12 | |||
13 | export default settingsWSActions; | ||
diff --git a/src/features/settingsWS/index.ts b/src/features/settingsWS/index.ts deleted file mode 100755 index 9bb206d82..000000000 --- a/src/features/settingsWS/index.ts +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | import { reaction } from 'mobx'; | ||
2 | import { SettingsWSStore } from './store'; | ||
3 | |||
4 | const debug = require('debug')('Ferdi:feature:settingsWS'); | ||
5 | |||
6 | export const settingsStore = new SettingsWSStore(); | ||
7 | |||
8 | export default function initSettingsWebSocket( | ||
9 | stores: { features: any }, | ||
10 | actions: any, | ||
11 | ) { | ||
12 | const { features } = stores; | ||
13 | |||
14 | // Toggle SettingsWebSocket feature | ||
15 | reaction( | ||
16 | () => features.features.isSettingsWSEnabled, | ||
17 | isEnabled => { | ||
18 | if (isEnabled) { | ||
19 | debug('Initializing `settingsWS` feature'); | ||
20 | settingsStore.start(stores, actions); | ||
21 | } else if (settingsStore) { | ||
22 | debug('Disabling `settingsWS` feature'); | ||
23 | settingsStore.stop(); | ||
24 | } | ||
25 | }, | ||
26 | { fireImmediately: true }, | ||
27 | ); | ||
28 | } | ||
diff --git a/src/features/settingsWS/state.ts b/src/features/settingsWS/state.ts deleted file mode 100755 index 7b16b2b6e..000000000 --- a/src/features/settingsWS/state.ts +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | |||
3 | const defaultState = { | ||
4 | isFeatureActive: false, | ||
5 | }; | ||
6 | |||
7 | export const settingsWSState = observable(defaultState); | ||
8 | |||
9 | export function resetState() { | ||
10 | Object.assign(settingsWSState, defaultState); | ||
11 | } | ||
12 | |||
13 | export default settingsWSState; | ||
diff --git a/src/features/settingsWS/store.js b/src/features/settingsWS/store.js deleted file mode 100755 index 3b9e10825..000000000 --- a/src/features/settingsWS/store.js +++ /dev/null | |||
@@ -1,132 +0,0 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | import WebSocket from 'ws'; | ||
3 | import ms from 'ms'; | ||
4 | |||
5 | import { FeatureStore } from '../utils/FeatureStore'; | ||
6 | import { createReactions } from '../../stores/lib/Reaction'; | ||
7 | import { WS_API } from '../../environment-remote'; | ||
8 | |||
9 | const debug = require('debug')('Ferdi:feature:settingsWS:store'); | ||
10 | |||
11 | export class SettingsWSStore extends FeatureStore { | ||
12 | stores = null; | ||
13 | |||
14 | actions = null; | ||
15 | |||
16 | ws = null; | ||
17 | |||
18 | pingTimeout = null; | ||
19 | |||
20 | reconnectTimeout = null; | ||
21 | |||
22 | @observable connected = false; | ||
23 | |||
24 | start(stores, actions) { | ||
25 | this.stores = stores; | ||
26 | this.actions = actions; | ||
27 | |||
28 | this._registerReactions( | ||
29 | createReactions([ | ||
30 | this._initialize.bind(this), | ||
31 | this._reconnect.bind(this), | ||
32 | this._close.bind(this), | ||
33 | ]), | ||
34 | ); | ||
35 | } | ||
36 | |||
37 | connect() { | ||
38 | try { | ||
39 | const wsURL = `${WS_API}/ws/${this.stores.user.data.id}`; | ||
40 | debug('Setting up WebSocket to', wsURL); | ||
41 | |||
42 | this.ws = new WebSocket(wsURL); | ||
43 | |||
44 | this.ws.on('open', () => { | ||
45 | debug('Opened WebSocket'); | ||
46 | this.send({ | ||
47 | action: 'authorize', | ||
48 | token: this.stores.user.authToken, | ||
49 | }); | ||
50 | |||
51 | this.connected = true; | ||
52 | |||
53 | this.heartbeat(); | ||
54 | }); | ||
55 | |||
56 | this.ws.on('message', data => { | ||
57 | const resp = JSON.parse(data); | ||
58 | debug('Received message', resp); | ||
59 | |||
60 | if (resp.id) { | ||
61 | this.stores.user.getUserInfoRequest.patch(result => { | ||
62 | if (!result) return; | ||
63 | |||
64 | debug('Patching user object with new values'); | ||
65 | Object.assign(result, resp); | ||
66 | }); | ||
67 | } | ||
68 | }); | ||
69 | |||
70 | this.ws.on('ping', this.heartbeat.bind(this)); | ||
71 | } catch (error) { | ||
72 | console.error(error); | ||
73 | } | ||
74 | } | ||
75 | |||
76 | heartbeat() { | ||
77 | debug('Heartbeat'); | ||
78 | clearTimeout(this.pingTimeout); | ||
79 | |||
80 | this.pingTimeout = setTimeout(() => { | ||
81 | debug('Terminating connection, reconnecting in 35'); | ||
82 | this.ws.terminate(); | ||
83 | |||
84 | this.connected = false; | ||
85 | }, ms('35s')); | ||
86 | } | ||
87 | |||
88 | send(data) { | ||
89 | if (this.ws && this.ws.readyState === 1) { | ||
90 | this.ws.send(JSON.stringify(data)); | ||
91 | debug('Sending data', data); | ||
92 | } else { | ||
93 | debug('WebSocket is not initialized'); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | // Reactions | ||
98 | |||
99 | _initialize() { | ||
100 | if (this.stores.user.data.id && !this.ws) { | ||
101 | this.connect(); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | _reconnect() { | ||
106 | if (!this.connected) { | ||
107 | debug('Trying to reconnect in 30s'); | ||
108 | this.reconnectTimeout = setInterval(() => { | ||
109 | debug('Trying to reconnect'); | ||
110 | this.connect(); | ||
111 | }, ms('30s')); | ||
112 | } else { | ||
113 | debug('Clearing reconnect interval'); | ||
114 | clearInterval(this.reconnectTimeout); | ||
115 | } | ||
116 | } | ||
117 | |||
118 | _close() { | ||
119 | if (!this.stores.user.isLoggedIn) { | ||
120 | debug('Stopping reactions'); | ||
121 | this._stopReactions(); | ||
122 | |||
123 | if (this.ws) { | ||
124 | debug('Terminating connection'); | ||
125 | this.ws.terminate(); | ||
126 | this.ws = null; | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | export default SettingsWSStore; | ||
diff --git a/src/features/todos/index.ts b/src/features/todos/index.ts index 3665812e6..2fa8c3130 100644 --- a/src/features/todos/index.ts +++ b/src/features/todos/index.ts | |||
@@ -1,29 +1,8 @@ | |||
1 | import { reaction } from 'mobx'; | ||
2 | import TodoStore from './store'; | 1 | import TodoStore from './store'; |
3 | 2 | ||
4 | const debug = require('debug')('Ferdi:feature:todos'); | ||
5 | |||
6 | export const todosStore = new TodoStore(); | 3 | export const todosStore = new TodoStore(); |
7 | 4 | ||
8 | export default function initTodos( | 5 | export default function initTodos(stores: { todos?: any }, actions: any) { |
9 | stores: { todos?: any; features?: any }, | ||
10 | actions: any, | ||
11 | ) { | ||
12 | stores.todos = todosStore; | 6 | stores.todos = todosStore; |
13 | const { features } = stores; | 7 | todosStore.start(stores, actions); |
14 | |||
15 | // Toggle todos feature | ||
16 | reaction( | ||
17 | () => features.features.isTodosEnabled, | ||
18 | isEnabled => { | ||
19 | if (isEnabled) { | ||
20 | debug('Initializing `todos` feature'); | ||
21 | todosStore.start(stores, actions); | ||
22 | } else if (todosStore.isFeatureActive) { | ||
23 | debug('Disabling `todos` feature'); | ||
24 | todosStore.stop(); | ||
25 | } | ||
26 | }, | ||
27 | { fireImmediately: true }, | ||
28 | ); | ||
29 | } | 8 | } |
diff --git a/src/features/todos/store.js b/src/features/todos/store.js index 010a029ff..d158ed480 100644 --- a/src/features/todos/store.js +++ b/src/features/todos/store.js | |||
@@ -23,8 +23,6 @@ const debug = require('debug')('Ferdi:feature:todos:store'); | |||
23 | export default class TodoStore extends FeatureStore { | 23 | export default class TodoStore extends FeatureStore { |
24 | @observable stores = null; | 24 | @observable stores = null; |
25 | 25 | ||
26 | @observable isFeatureEnabled = false; | ||
27 | |||
28 | @observable isFeatureActive = false; | 26 | @observable isFeatureActive = false; |
29 | 27 | ||
30 | @observable webview = null; | 28 | @observable webview = null; |
@@ -123,7 +121,6 @@ export default class TodoStore extends FeatureStore { | |||
123 | // REACTIONS | 121 | // REACTIONS |
124 | 122 | ||
125 | this._allReactions = createReactions([ | 123 | this._allReactions = createReactions([ |
126 | this._setFeatureEnabledReaction, | ||
127 | this._updateTodosConfig, | 124 | this._updateTodosConfig, |
128 | this._firstLaunchReaction, | 125 | this._firstLaunchReaction, |
129 | this._routeCheckReaction, | 126 | this._routeCheckReaction, |
@@ -262,12 +259,6 @@ export default class TodoStore extends FeatureStore { | |||
262 | 259 | ||
263 | // Reactions | 260 | // Reactions |
264 | 261 | ||
265 | _setFeatureEnabledReaction = () => { | ||
266 | const { isTodosEnabled } = this.stores.features.features; | ||
267 | |||
268 | this.isFeatureEnabled = isTodosEnabled; | ||
269 | }; | ||
270 | |||
271 | _updateTodosConfig = () => { | 262 | _updateTodosConfig = () => { |
272 | // Resend the config if any part changes in Franz: | 263 | // Resend the config if any part changes in Franz: |
273 | this._onTodosClientInitialized(); | 264 | this._onTodosClientInitialized(); |
diff --git a/src/features/workspaces/index.ts b/src/features/workspaces/index.ts index ecca64b41..25975936a 100644 --- a/src/features/workspaces/index.ts +++ b/src/features/workspaces/index.ts | |||
@@ -1,28 +1,8 @@ | |||
1 | import { reaction } from 'mobx'; | ||
2 | import WorkspacesStore from './store'; | 1 | import WorkspacesStore from './store'; |
3 | import { resetApiRequests } from './api'; | ||
4 | |||
5 | const debug = require('debug')('Ferdi:feature:workspaces'); | ||
6 | 2 | ||
7 | export const workspaceStore = new WorkspacesStore(); | 3 | export const workspaceStore = new WorkspacesStore(); |
8 | 4 | ||
9 | export default function initWorkspaces(stores, actions) { | 5 | export default function initWorkspaces(stores, actions) { |
10 | stores.workspaces = workspaceStore; | 6 | stores.workspaces = workspaceStore; |
11 | const { features } = stores; | 7 | workspaceStore.start(stores, actions); |
12 | |||
13 | // Toggle workspace feature | ||
14 | reaction( | ||
15 | () => features.features.isWorkspaceEnabled, | ||
16 | isEnabled => { | ||
17 | if (isEnabled && !workspaceStore.isFeatureActive) { | ||
18 | debug('Initializing `workspaces` feature'); | ||
19 | workspaceStore.start(stores, actions); | ||
20 | } else if (workspaceStore.isFeatureActive) { | ||
21 | debug('Disabling `workspaces` feature'); | ||
22 | workspaceStore.stop(); | ||
23 | resetApiRequests(); | ||
24 | } | ||
25 | }, | ||
26 | { fireImmediately: true }, | ||
27 | ); | ||
28 | } | 8 | } |
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 0fa43b723..17ec17b3a 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js | |||
@@ -18,8 +18,6 @@ import { KEEP_WS_LOADED_USID } from '../../config'; | |||
18 | const debug = require('debug')('Ferdi:feature:workspaces:store'); | 18 | const debug = require('debug')('Ferdi:feature:workspaces:store'); |
19 | 19 | ||
20 | export default class WorkspacesStore extends FeatureStore { | 20 | export default class WorkspacesStore extends FeatureStore { |
21 | @observable isFeatureEnabled = true; | ||
22 | |||
23 | @observable isFeatureActive = false; | 21 | @observable isFeatureActive = false; |
24 | 22 | ||
25 | @observable activeWorkspace = null; | 23 | @observable activeWorkspace = null; |
@@ -97,7 +95,6 @@ export default class WorkspacesStore extends FeatureStore { | |||
97 | 95 | ||
98 | this._allReactions = createReactions([ | 96 | this._allReactions = createReactions([ |
99 | this._openDrawerWithSettingsReaction, | 97 | this._openDrawerWithSettingsReaction, |
100 | this._setFeatureEnabledReaction, | ||
101 | this._cleanupInvalidServiceReferences, | 98 | this._cleanupInvalidServiceReferences, |
102 | this._setActiveServiceOnWorkspaceSwitchReaction, | 99 | this._setActiveServiceOnWorkspaceSwitchReaction, |
103 | this._activateLastUsedWorkspaceReaction, | 100 | this._activateLastUsedWorkspaceReaction, |
@@ -251,11 +248,6 @@ export default class WorkspacesStore extends FeatureStore { | |||
251 | 248 | ||
252 | // Reactions | 249 | // Reactions |
253 | 250 | ||
254 | _setFeatureEnabledReaction = () => { | ||
255 | const { isWorkspaceEnabled } = this.stores.features.features; | ||
256 | this.isFeatureEnabled = isWorkspaceEnabled; | ||
257 | }; | ||
258 | |||
259 | _setWorkspaceBeingEditedReaction = () => { | 251 | _setWorkspaceBeingEditedReaction = () => { |
260 | const { pathname } = this.stores.router.location; | 252 | const { pathname } = this.stores.router.location; |
261 | const match = matchRoute('/settings/workspaces/edit/:id', pathname); | 253 | const match = matchRoute('/settings/workspaces/edit/:id', pathname); |
diff --git a/src/internal-server/app/Controllers/Http/StaticController.js b/src/internal-server/app/Controllers/Http/StaticController.js deleted file mode 100644 index 33e0e52d9..000000000 --- a/src/internal-server/app/Controllers/Http/StaticController.js +++ /dev/null | |||
@@ -1,20 +0,0 @@ | |||
1 | /** | ||
2 | * Controller for routes with static responses | ||
3 | */ | ||
4 | |||
5 | import { DEFAULT_FEATURES_CONFIG } from '../../../../config'; | ||
6 | |||
7 | // TODO: This endpoint and associated code needs to be remoeved as cleanup | ||
8 | class StaticController { | ||
9 | // Enable all features | ||
10 | features({ response }) { | ||
11 | return response.send(DEFAULT_FEATURES_CONFIG); | ||
12 | } | ||
13 | |||
14 | // Return an empty array | ||
15 | emptyArray({ response }) { | ||
16 | return response.send([]); | ||
17 | } | ||
18 | } | ||
19 | |||
20 | export default StaticController; | ||
diff --git a/src/internal-server/start/routes.js b/src/internal-server/start/routes.js index 50b9448cf..177035dac 100644 --- a/src/internal-server/start/routes.js +++ b/src/internal-server/start/routes.js | |||
@@ -55,17 +55,12 @@ Route.group(() => { | |||
55 | Route.get('recipes', 'RecipeController.list'); | 55 | Route.get('recipes', 'RecipeController.list'); |
56 | Route.get('recipes/download/:recipe', 'RecipeController.download'); | 56 | Route.get('recipes/download/:recipe', 'RecipeController.download'); |
57 | Route.get('recipes/search', 'RecipeController.search'); | 57 | Route.get('recipes/search', 'RecipeController.search'); |
58 | Route.get('recipes/update', 'StaticController.emptyArray'); | ||
59 | 58 | ||
60 | // Workspaces | 59 | // Workspaces |
61 | Route.put('workspace/:id', 'WorkspaceController.edit'); | 60 | Route.put('workspace/:id', 'WorkspaceController.edit'); |
62 | Route.delete('workspace/:id', 'WorkspaceController.delete'); | 61 | Route.delete('workspace/:id', 'WorkspaceController.delete'); |
63 | Route.post('workspace', 'WorkspaceController.create'); | 62 | Route.post('workspace', 'WorkspaceController.create'); |
64 | Route.get('workspace', 'WorkspaceController.list'); | 63 | Route.get('workspace', 'WorkspaceController.list'); |
65 | |||
66 | // Static responses | ||
67 | Route.get('features/:mode?', 'StaticController.features'); | ||
68 | Route.get('services', 'StaticController.emptyArray'); | ||
69 | }) | 64 | }) |
70 | .prefix(API_VERSION) | 65 | .prefix(API_VERSION) |
71 | .middleware(OnlyAllowFerdi); | 66 | .middleware(OnlyAllowFerdi); |
diff --git a/src/lib/Menu.js b/src/lib/Menu.js index 1495fc80e..7d4c228f5 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js | |||
@@ -21,7 +21,6 @@ import { | |||
21 | muteFerdiShortcutKey, | 21 | muteFerdiShortcutKey, |
22 | } from '../environment'; | 22 | } from '../environment'; |
23 | import { aboutAppDetails, ferdiVersion } from '../environment-remote'; | 23 | import { aboutAppDetails, ferdiVersion } from '../environment-remote'; |
24 | import { todosStore } from '../features/todos'; | ||
25 | import { todoActions } from '../features/todos/actions'; | 24 | import { todoActions } from '../features/todos/actions'; |
26 | import { workspaceActions } from '../features/workspaces/actions'; | 25 | import { workspaceActions } from '../features/workspaces/actions'; |
27 | import { workspaceStore } from '../features/workspaces/index'; | 26 | import { workspaceStore } from '../features/workspaces/index'; |
@@ -479,12 +478,12 @@ const _titleBarTemplateFactory = (intl, locked) => [ | |||
479 | label: intl.formatMessage(menuItems.workspaces), | 478 | label: intl.formatMessage(menuItems.workspaces), |
480 | accelerator: `${altKey()}+W`, | 479 | accelerator: `${altKey()}+W`, |
481 | submenu: [], | 480 | submenu: [], |
482 | visible: !locked && workspaceStore.isFeatureEnabled, | 481 | visible: !locked, |
483 | }, | 482 | }, |
484 | { | 483 | { |
485 | label: intl.formatMessage(menuItems.todos), | 484 | label: intl.formatMessage(menuItems.todos), |
486 | submenu: [], | 485 | submenu: [], |
487 | visible: !locked && todosStore.isFeatureEnabled, | 486 | visible: !locked, |
488 | }, | 487 | }, |
489 | { | 488 | { |
490 | label: intl.formatMessage(menuItems.window), | 489 | label: intl.formatMessage(menuItems.window), |
@@ -698,13 +697,9 @@ class FranzMenu { | |||
698 | tpl[2].submenu = serviceTpl; | 697 | tpl[2].submenu = serviceTpl; |
699 | } | 698 | } |
700 | 699 | ||
701 | if (workspaceStore.isFeatureEnabled) { | 700 | tpl[3].submenu = this.workspacesMenu(); |
702 | tpl[3].submenu = this.workspacesMenu(); | ||
703 | } | ||
704 | 701 | ||
705 | if (todosStore.isFeatureEnabled) { | 702 | tpl[4].submenu = this.todosMenu(); |
706 | tpl[4].submenu = this.todosMenu(); | ||
707 | } | ||
708 | } else { | 703 | } else { |
709 | const touchIdEnabled = isMac | 704 | const touchIdEnabled = isMac |
710 | ? this.stores.settings.app.useTouchIdToUnlock && | 705 | ? this.stores.settings.app.useTouchIdToUnlock && |
@@ -872,13 +867,9 @@ class FranzMenu { | |||
872 | tpl[3].submenu = serviceTpl; | 867 | tpl[3].submenu = serviceTpl; |
873 | } | 868 | } |
874 | 869 | ||
875 | if (workspaceStore.isFeatureEnabled) { | 870 | tpl[4].submenu = this.workspacesMenu(); |
876 | tpl[4].submenu = this.workspacesMenu(); | ||
877 | } | ||
878 | 871 | ||
879 | if (todosStore.isFeatureEnabled) { | 872 | tpl[5].submenu = this.todosMenu(); |
880 | tpl[5].submenu = this.todosMenu(); | ||
881 | } | ||
882 | 873 | ||
883 | tpl[tpl.length - 1].submenu.push( | 874 | tpl[tpl.length - 1].submenu.push( |
884 | { | 875 | { |
diff --git a/src/stores.types.ts b/src/stores.types.ts index e5978a392..c63cdd4b8 100644 --- a/src/stores.types.ts +++ b/src/stores.types.ts | |||
@@ -231,7 +231,6 @@ interface TodosStore { | |||
231 | actions: Actions; | 231 | actions: Actions; |
232 | api: Api; | 232 | api: Api; |
233 | isFeatureActive: () => void; | 233 | isFeatureActive: () => void; |
234 | isFeatureEnabled: () => void; | ||
235 | isInitialized: true; | 234 | isInitialized: true; |
236 | stores: Stores; | 235 | stores: Stores; |
237 | userAgentModel: () => void; | 236 | userAgentModel: () => void; |
@@ -246,7 +245,6 @@ interface TodosStore { | |||
246 | _reactions: any[]; | 245 | _reactions: any[]; |
247 | _reload: () => void; | 246 | _reload: () => void; |
248 | _routeCheckReaction: () => void; | 247 | _routeCheckReaction: () => void; |
249 | _setFeatureEnabledReaction: () => void; | ||
250 | _updateSettings: () => void; | 248 | _updateSettings: () => void; |
251 | _updateTodosConfig: () => void; | 249 | _updateTodosConfig: () => void; |
252 | isFeatureEnabledByUser: () => void; | 250 | isFeatureEnabledByUser: () => void; |
@@ -343,7 +341,6 @@ export interface WorkspacesStore { | |||
343 | saving: boolean; | 341 | saving: boolean; |
344 | filterServicesByActiveWorkspace: () => void; | 342 | filterServicesByActiveWorkspace: () => void; |
345 | isFeatureActive: () => void; | 343 | isFeatureActive: () => void; |
346 | isFeatureEnabled: () => void; | ||
347 | isSettingsRouteActive: () => void; | 344 | isSettingsRouteActive: () => void; |
348 | isSwitchingWorkspace: () => void; | 345 | isSwitchingWorkspace: () => void; |
349 | isWorkspaceDrawerOpen: () => void; | 346 | isWorkspaceDrawerOpen: () => void; |
@@ -359,7 +356,6 @@ export interface WorkspacesStore { | |||
359 | _openDrawerWithSettingsReaction: () => void; | 356 | _openDrawerWithSettingsReaction: () => void; |
360 | _reactions: any[]; | 357 | _reactions: any[]; |
361 | _setActiveServiceOnWorkspaceSwitchReaction: () => void; | 358 | _setActiveServiceOnWorkspaceSwitchReaction: () => void; |
362 | _setFeatureEnabledReaction: () => void; | ||
363 | _setWorkspaceBeingEditedReaction: () => void; | 359 | _setWorkspaceBeingEditedReaction: () => void; |
364 | _toggleKeepAllWorkspacesLoadedSetting: () => void; | 360 | _toggleKeepAllWorkspacesLoadedSetting: () => void; |
365 | _updateSettings: () => void; | 361 | _updateSettings: () => void; |
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index 8e0134d7f..fdb502b6b 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -9,13 +9,10 @@ import workspaces from '../features/workspaces'; | |||
9 | import quickSwitch from '../features/quickSwitch'; | 9 | import quickSwitch from '../features/quickSwitch'; |
10 | import nightlyBuilds from '../features/nightlyBuilds'; | 10 | import nightlyBuilds from '../features/nightlyBuilds'; |
11 | import publishDebugInfo from '../features/publishDebugInfo'; | 11 | import publishDebugInfo from '../features/publishDebugInfo'; |
12 | import settingsWS from '../features/settingsWS'; | ||
13 | import communityRecipes from '../features/communityRecipes'; | 12 | import communityRecipes from '../features/communityRecipes'; |
14 | import todos from '../features/todos'; | 13 | import todos from '../features/todos'; |
15 | import appearance from '../features/appearance'; | 14 | import appearance from '../features/appearance'; |
16 | 15 | ||
17 | import { DEFAULT_FEATURES_CONFIG } from '../config'; | ||
18 | |||
19 | export default class FeaturesStore extends Store { | 16 | export default class FeaturesStore extends Store { |
20 | @observable defaultFeaturesRequest = new CachedRequest( | 17 | @observable defaultFeaturesRequest = new CachedRequest( |
21 | this.api.features, | 18 | this.api.features, |
@@ -27,7 +24,7 @@ export default class FeaturesStore extends Store { | |||
27 | 'features', | 24 | 'features', |
28 | ); | 25 | ); |
29 | 26 | ||
30 | @observable features = { ...DEFAULT_FEATURES_CONFIG }; | 27 | @observable features = { }; |
31 | 28 | ||
32 | async setup() { | 29 | async setup() { |
33 | this.registerReactions([ | 30 | this.registerReactions([ |
@@ -41,12 +38,12 @@ export default class FeaturesStore extends Store { | |||
41 | 38 | ||
42 | @computed get anonymousFeatures() { | 39 | @computed get anonymousFeatures() { |
43 | return ( | 40 | return ( |
44 | this.defaultFeaturesRequest.execute().result || DEFAULT_FEATURES_CONFIG | 41 | this.defaultFeaturesRequest.execute().result || {} |
45 | ); | 42 | ); |
46 | } | 43 | } |
47 | 44 | ||
48 | _updateFeatures = () => { | 45 | _updateFeatures = () => { |
49 | const features = { ...DEFAULT_FEATURES_CONFIG }; | 46 | const features = { }; |
50 | if (this.stores.user.isLoggedIn) { | 47 | if (this.stores.user.isLoggedIn) { |
51 | let requestResult = {}; | 48 | let requestResult = {}; |
52 | try { | 49 | try { |
@@ -77,7 +74,6 @@ export default class FeaturesStore extends Store { | |||
77 | quickSwitch(); | 74 | quickSwitch(); |
78 | nightlyBuilds(); | 75 | nightlyBuilds(); |
79 | publishDebugInfo(); | 76 | publishDebugInfo(); |
80 | settingsWS(this.stores, this.actions); | ||
81 | communityRecipes(this.stores, this.actions); | 77 | communityRecipes(this.stores, this.actions); |
82 | todos(this.stores, this.actions); | 78 | todos(this.stores, this.actions); |
83 | appearance(this.stores); | 79 | appearance(this.stores); |