aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/layout/Sidebar.js36
-rw-r--r--src/components/settings/navigation/SettingsNavigation.js21
-rw-r--r--src/components/settings/settings/EditSettingsForm.js16
-rw-r--r--src/config.ts9
-rw-r--r--src/containers/settings/EditServiceScreen.js2
-rw-r--r--src/containers/settings/EditSettingsScreen.js18
-rwxr-xr-xsrc/features/settingsWS/actions.ts13
-rwxr-xr-xsrc/features/settingsWS/index.ts28
-rwxr-xr-xsrc/features/settingsWS/state.ts13
-rwxr-xr-xsrc/features/settingsWS/store.js132
-rw-r--r--src/features/todos/index.ts25
-rw-r--r--src/features/todos/store.js9
-rw-r--r--src/features/workspaces/index.ts22
-rw-r--r--src/features/workspaces/store.js8
-rw-r--r--src/internal-server/app/Controllers/Http/StaticController.js20
-rw-r--r--src/internal-server/start/routes.js5
-rw-r--r--src/lib/Menu.js21
-rw-r--r--src/stores.types.ts4
-rw-r--r--src/stores/FeaturesStore.js10
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';
17import { workspaceStore } from '../../features/workspaces';
18import { todosStore } from '../../features/todos'; 17import { todosStore } from '../../features/todos';
19import { todoActions } from '../../features/todos/actions'; 18import { todoActions } from '../../features/todos/actions';
20import AppStore from '../../stores/AppStore'; 19import 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
7import { LOCAL_SERVER, LIVE_FERDI_API, LIVE_FRANZ_API } from '../../../config'; 7import { LOCAL_SERVER, LIVE_FERDI_API, LIVE_FRANZ_API } from '../../../config';
8import Link from '../../ui/Link'; 8import Link from '../../ui/Link';
9import { workspaceStore } from '../../../features/workspaces';
10import UIStore from '../../../stores/UIStore'; 9import UIStore from '../../../stores/UIStore';
11import SettingsStore from '../../../stores/SettingsStore'; 10import SettingsStore from '../../../stores/SettingsStore';
12import UserStore from '../../../stores/UserStore'; 11import 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
141export const iconSizeBias = 20; 141export const iconSizeBias = 20;
142 142
143export const DEFAULT_FEATURES_CONFIG = {
144 isServiceProxyEnabled: true,
145 isWorkspaceEnabled: true,
146 isTodosEnabled: true,
147 isSettingsWSEnabled: false,
148};
149
150export const DEFAULT_WINDOW_OPTIONS = { 143export 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
243export const DEFAULT_SERVICE_SETTINGS = { 236export 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';
8import RecipesStore from '../../stores/RecipesStore'; 8import RecipesStore from '../../stores/RecipesStore';
9import ServicesStore from '../../stores/ServicesStore'; 9import ServicesStore from '../../stores/ServicesStore';
10import SettingsStore from '../../stores/SettingsStore'; 10import SettingsStore from '../../stores/SettingsStore';
11import FeaturesStore from '../../stores/FeaturesStore';
12import Form from '../../lib/Form'; 11import Form from '../../lib/Form';
13 12
14import ServiceError from '../../components/settings/services/ServiceError'; 13import 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 @@
1import PropTypes from 'prop-types';
2import { createActionsFromDefinitions } from '../../actions/lib/actions';
3
4export const settingsWSActions = createActionsFromDefinitions(
5 {
6 greet: {
7 name: PropTypes.string.isRequired,
8 },
9 },
10 PropTypes.checkPropTypes,
11);
12
13export 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 @@
1import { reaction } from 'mobx';
2import { SettingsWSStore } from './store';
3
4const debug = require('debug')('Ferdi:feature:settingsWS');
5
6export const settingsStore = new SettingsWSStore();
7
8export 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 @@
1import { observable } from 'mobx';
2
3const defaultState = {
4 isFeatureActive: false,
5};
6
7export const settingsWSState = observable(defaultState);
8
9export function resetState() {
10 Object.assign(settingsWSState, defaultState);
11}
12
13export 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 @@
1import { observable } from 'mobx';
2import WebSocket from 'ws';
3import ms from 'ms';
4
5import { FeatureStore } from '../utils/FeatureStore';
6import { createReactions } from '../../stores/lib/Reaction';
7import { WS_API } from '../../environment-remote';
8
9const debug = require('debug')('Ferdi:feature:settingsWS:store');
10
11export 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
132export 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 @@
1import { reaction } from 'mobx';
2import TodoStore from './store'; 1import TodoStore from './store';
3 2
4const debug = require('debug')('Ferdi:feature:todos');
5
6export const todosStore = new TodoStore(); 3export const todosStore = new TodoStore();
7 4
8export default function initTodos( 5export 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');
23export default class TodoStore extends FeatureStore { 23export 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 @@
1import { reaction } from 'mobx';
2import WorkspacesStore from './store'; 1import WorkspacesStore from './store';
3import { resetApiRequests } from './api';
4
5const debug = require('debug')('Ferdi:feature:workspaces');
6 2
7export const workspaceStore = new WorkspacesStore(); 3export const workspaceStore = new WorkspacesStore();
8 4
9export default function initWorkspaces(stores, actions) { 5export 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';
18const debug = require('debug')('Ferdi:feature:workspaces:store'); 18const debug = require('debug')('Ferdi:feature:workspaces:store');
19 19
20export default class WorkspacesStore extends FeatureStore { 20export 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
5import { DEFAULT_FEATURES_CONFIG } from '../../../../config';
6
7// TODO: This endpoint and associated code needs to be remoeved as cleanup
8class 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
20export 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';
23import { aboutAppDetails, ferdiVersion } from '../environment-remote'; 23import { aboutAppDetails, ferdiVersion } from '../environment-remote';
24import { todosStore } from '../features/todos';
25import { todoActions } from '../features/todos/actions'; 24import { todoActions } from '../features/todos/actions';
26import { workspaceActions } from '../features/workspaces/actions'; 25import { workspaceActions } from '../features/workspaces/actions';
27import { workspaceStore } from '../features/workspaces/index'; 26import { 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';
9import quickSwitch from '../features/quickSwitch'; 9import quickSwitch from '../features/quickSwitch';
10import nightlyBuilds from '../features/nightlyBuilds'; 10import nightlyBuilds from '../features/nightlyBuilds';
11import publishDebugInfo from '../features/publishDebugInfo'; 11import publishDebugInfo from '../features/publishDebugInfo';
12import settingsWS from '../features/settingsWS';
13import communityRecipes from '../features/communityRecipes'; 12import communityRecipes from '../features/communityRecipes';
14import todos from '../features/todos'; 13import todos from '../features/todos';
15import appearance from '../features/appearance'; 14import appearance from '../features/appearance';
16 15
17import { DEFAULT_FEATURES_CONFIG } from '../config';
18
19export default class FeaturesStore extends Store { 16export 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);