diff options
Diffstat (limited to 'src/stores')
-rw-r--r-- | src/stores/AppStore.js | 32 | ||||
-rw-r--r-- | src/stores/FeaturesStore.js | 16 | ||||
-rw-r--r-- | src/stores/GlobalErrorStore.js | 10 | ||||
-rw-r--r-- | src/stores/RecipesStore.js | 51 | ||||
-rw-r--r-- | src/stores/RequestStore.js | 18 | ||||
-rw-r--r-- | src/stores/ServicesStore.js | 291 | ||||
-rw-r--r-- | src/stores/SettingsStore.js | 60 | ||||
-rw-r--r-- | src/stores/UserStore.js | 78 | ||||
-rw-r--r-- | src/stores/index.ts | 4 | ||||
-rw-r--r-- | src/stores/lib/CachedRequest.js | 96 | ||||
-rw-r--r-- | src/stores/lib/Request.js | 2 | ||||
-rw-r--r-- | src/stores/lib/Store.js | 6 |
12 files changed, 365 insertions, 299 deletions
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index 469e7519e..85f74a91e 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -251,16 +251,14 @@ export default class AppStore extends Store { | |||
251 | // macOS catalina notifications hack | 251 | // macOS catalina notifications hack |
252 | // notifications got stuck after upgrade but forcing a notification | 252 | // notifications got stuck after upgrade but forcing a notification |
253 | // via `new Notification` triggered the permission request | 253 | // via `new Notification` triggered the permission request |
254 | if (isMac) { | 254 | if (isMac && !localStorage.getItem(CATALINA_NOTIFICATION_HACK_KEY)) { |
255 | if (!localStorage.getItem(CATALINA_NOTIFICATION_HACK_KEY)) { | 255 | debug('Triggering macOS Catalina notification permission trigger'); |
256 | debug('Triggering macOS Catalina notification permission trigger'); | 256 | // eslint-disable-next-line no-new |
257 | // eslint-disable-next-line no-new | 257 | new window.Notification('Welcome to Ferdi 5', { |
258 | new window.Notification('Welcome to Ferdi 5', { | 258 | body: 'Have a wonderful day & happy messaging.', |
259 | body: 'Have a wonderful day & happy messaging.', | 259 | }); |
260 | }); | ||
261 | 260 | ||
262 | localStorage.setItem(CATALINA_NOTIFICATION_HACK_KEY, true); | 261 | localStorage.setItem(CATALINA_NOTIFICATION_HACK_KEY, true); |
263 | } | ||
264 | } | 262 | } |
265 | } | 263 | } |
266 | 264 | ||
@@ -325,7 +323,7 @@ export default class AppStore extends Store { | |||
325 | 323 | ||
326 | debug('New notification', title, options); | 324 | debug('New notification', title, options); |
327 | 325 | ||
328 | notification.onclick = () => { | 326 | notification.addEventListener('click', () => { |
329 | if (serviceId) { | 327 | if (serviceId) { |
330 | this.actions.service.sendIPCMessage({ | 328 | this.actions.service.sendIPCMessage({ |
331 | channel: `notification-onclick:${notificationId}`, | 329 | channel: `notification-onclick:${notificationId}`, |
@@ -346,7 +344,7 @@ export default class AppStore extends Store { | |||
346 | 344 | ||
347 | debug('Notification click handler'); | 345 | debug('Notification click handler'); |
348 | } | 346 | } |
349 | }; | 347 | }); |
350 | } | 348 | } |
351 | 349 | ||
352 | @action _setBadge({ unreadDirectMessageCount, unreadIndirectMessageCount }) { | 350 | @action _setBadge({ unreadDirectMessageCount, unreadIndirectMessageCount }) { |
@@ -360,7 +358,7 @@ export default class AppStore extends Store { | |||
360 | ) { | 358 | ) { |
361 | indicator = 0; | 359 | indicator = 0; |
362 | } else { | 360 | } else { |
363 | indicator = parseInt(indicator, 10); | 361 | indicator = Number.parseInt(indicator, 10); |
364 | } | 362 | } |
365 | 363 | ||
366 | ipcRenderer.send('updateAppIndicator', { | 364 | ipcRenderer.send('updateAppIndicator', { |
@@ -379,8 +377,8 @@ export default class AppStore extends Store { | |||
379 | debug('disabling launch on startup'); | 377 | debug('disabling launch on startup'); |
380 | autoLauncher.disable(); | 378 | autoLauncher.disable(); |
381 | } | 379 | } |
382 | } catch (err) { | 380 | } catch (error) { |
383 | console.warn(err); | 381 | console.warn(error); |
384 | } | 382 | } |
385 | } | 383 | } |
386 | 384 | ||
@@ -438,7 +436,7 @@ export default class AppStore extends Store { | |||
438 | const allServiceIds = await getServiceIdsFromPartitions(); | 436 | const allServiceIds = await getServiceIdsFromPartitions(); |
439 | const allOrphanedServiceIds = allServiceIds.filter( | 437 | const allOrphanedServiceIds = allServiceIds.filter( |
440 | id => | 438 | id => |
441 | !this.stores.services.all.find( | 439 | !this.stores.services.all.some( |
442 | s => id.replace('service-', '') === s.id, | 440 | s => id.replace('service-', '') === s.id, |
443 | ), | 441 | ), |
444 | ); | 442 | ); |
@@ -447,8 +445,8 @@ export default class AppStore extends Store { | |||
447 | await Promise.all( | 445 | await Promise.all( |
448 | allOrphanedServiceIds.map(id => removeServicePartitionDirectory(id)), | 446 | allOrphanedServiceIds.map(id => removeServicePartitionDirectory(id)), |
449 | ); | 447 | ); |
450 | } catch (ex) { | 448 | } catch (error) { |
451 | console.log('Error while deleting service partition directory - ', ex); | 449 | console.log('Error while deleting service partition directory -', error); |
452 | } | 450 | } |
453 | await Promise.all( | 451 | await Promise.all( |
454 | this.stores.services.all.map(s => | 452 | this.stores.services.all.map(s => |
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index 1d50dd714..8e0134d7f 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -51,7 +51,9 @@ export default class FeaturesStore extends Store { | |||
51 | let requestResult = {}; | 51 | let requestResult = {}; |
52 | try { | 52 | try { |
53 | requestResult = this.featuresRequest.execute().result; | 53 | requestResult = this.featuresRequest.execute().result; |
54 | } catch (e) {} // eslint-disable-line no-empty | 54 | } catch (error) { |
55 | console.error(error); | ||
56 | } | ||
55 | Object.assign(features, requestResult); | 57 | Object.assign(features, requestResult); |
56 | } | 58 | } |
57 | runInAction('FeaturesStore::_updateFeatures', () => { | 59 | runInAction('FeaturesStore::_updateFeatures', () => { |
@@ -69,15 +71,15 @@ export default class FeaturesStore extends Store { | |||
69 | } | 71 | } |
70 | 72 | ||
71 | _setupFeatures() { | 73 | _setupFeatures() { |
72 | serviceProxy(this.stores, this.actions); | 74 | serviceProxy(this.stores); |
73 | basicAuth(this.stores, this.actions); | 75 | basicAuth(); |
74 | workspaces(this.stores, this.actions); | 76 | workspaces(this.stores, this.actions); |
75 | quickSwitch(this.stores, this.actions); | 77 | quickSwitch(); |
76 | nightlyBuilds(this.stores, this.actions); | 78 | nightlyBuilds(); |
77 | publishDebugInfo(this.stores, this.actions); | 79 | publishDebugInfo(); |
78 | settingsWS(this.stores, this.actions); | 80 | settingsWS(this.stores, this.actions); |
79 | communityRecipes(this.stores, this.actions); | 81 | communityRecipes(this.stores, this.actions); |
80 | todos(this.stores, this.actions); | 82 | todos(this.stores, this.actions); |
81 | appearance(this.stores, this.actions); | 83 | appearance(this.stores); |
82 | } | 84 | } |
83 | } | 85 | } |
diff --git a/src/stores/GlobalErrorStore.js b/src/stores/GlobalErrorStore.js index aacaa247f..7cbfdc608 100644 --- a/src/stores/GlobalErrorStore.js +++ b/src/stores/GlobalErrorStore.js | |||
@@ -12,9 +12,9 @@ export default class GlobalErrorStore extends Store { | |||
12 | constructor(...args) { | 12 | constructor(...args) { |
13 | super(...args); | 13 | super(...args); |
14 | 14 | ||
15 | window.onerror = (...errorArgs) => { | 15 | window.addEventListener('error', (...errorArgs) => { |
16 | this._handleConsoleError.call(this, ['error', ...errorArgs]); | 16 | this._handleConsoleError.call(this, ['error', ...errorArgs]); |
17 | }; | 17 | }); |
18 | 18 | ||
19 | const origConsoleError = console.error; | 19 | const origConsoleError = console.error; |
20 | window.console.error = (...errorArgs) => { | 20 | window.console.error = (...errorArgs) => { |
@@ -38,7 +38,7 @@ export default class GlobalErrorStore extends Store { | |||
38 | } | 38 | } |
39 | 39 | ||
40 | _handleConsoleError(type, error, url, line) { | 40 | _handleConsoleError(type, error, url, line) { |
41 | if (typeof type === 'object' && type.length && type.length >= 1) { | 41 | if (typeof type === 'object' && type.length > 0) { |
42 | this.messages.push({ | 42 | this.messages.push({ |
43 | type: type[0], | 43 | type: type[0], |
44 | info: type, | 44 | info: type, |
@@ -53,14 +53,14 @@ export default class GlobalErrorStore extends Store { | |||
53 | } | 53 | } |
54 | } | 54 | } |
55 | 55 | ||
56 | _handleRequests = action(async (request) => { | 56 | _handleRequests = action(async request => { |
57 | if (request.isError) { | 57 | if (request.isError) { |
58 | this.error = request.error; | 58 | this.error = request.error; |
59 | 59 | ||
60 | if (request.error.json) { | 60 | if (request.error.json) { |
61 | try { | 61 | try { |
62 | this.response = await request.error.json(); | 62 | this.response = await request.error.json(); |
63 | } catch (error) { | 63 | } catch { |
64 | this.response = {}; | 64 | this.response = {}; |
65 | } | 65 | } |
66 | if (this.error.status === 401) { | 66 | if (this.error.status === 401) { |
diff --git a/src/stores/RecipesStore.js b/src/stores/RecipesStore.js index d2acebb75..bfbdc57a8 100644 --- a/src/stores/RecipesStore.js +++ b/src/stores/RecipesStore.js | |||
@@ -25,9 +25,7 @@ export default class RecipesStore extends Store { | |||
25 | this.actions.recipe.update.listen(this._update.bind(this)); | 25 | this.actions.recipe.update.listen(this._update.bind(this)); |
26 | 26 | ||
27 | // Reactions | 27 | // Reactions |
28 | this.registerReactions([ | 28 | this.registerReactions([this._checkIfRecipeIsInstalled.bind(this)]); |
29 | this._checkIfRecipeIsInstalled.bind(this), | ||
30 | ]); | ||
31 | } | 29 | } |
32 | 30 | ||
33 | setup() { | 31 | setup() { |
@@ -39,7 +37,10 @@ export default class RecipesStore extends Store { | |||
39 | } | 37 | } |
40 | 38 | ||
41 | @computed get active() { | 39 | @computed get active() { |
42 | const match = matchRoute('/settings/services/add/:id', this.stores.router.location.pathname); | 40 | const match = matchRoute( |
41 | '/settings/services/add/:id', | ||
42 | this.stores.router.location.pathname, | ||
43 | ); | ||
43 | if (match) { | 44 | if (match) { |
44 | const activeRecipe = this.one(match.id); | 45 | const activeRecipe = this.one(match.id); |
45 | if (activeRecipe) { | 46 | if (activeRecipe) { |
@@ -53,11 +54,11 @@ export default class RecipesStore extends Store { | |||
53 | } | 54 | } |
54 | 55 | ||
55 | @computed get recipeIdForServices() { | 56 | @computed get recipeIdForServices() { |
56 | return this.stores.services.all.map((s) => s.recipe.id); | 57 | return this.stores.services.all.map(s => s.recipe.id); |
57 | } | 58 | } |
58 | 59 | ||
59 | one(id) { | 60 | one(id) { |
60 | return this.all.find((recipe) => recipe.id === id); | 61 | return this.all.find(recipe => recipe.id === id); |
61 | } | 62 | } |
62 | 63 | ||
63 | isInstalled(id) { | 64 | isInstalled(id) { |
@@ -77,41 +78,43 @@ export default class RecipesStore extends Store { | |||
77 | const recipes = {}; | 78 | const recipes = {}; |
78 | 79 | ||
79 | // Hackfix, reference this.all to fetch services | 80 | // Hackfix, reference this.all to fetch services |
80 | debug(`Check Recipe updates for ${this.all.map((recipe) => recipe.id)}`); | 81 | debug(`Check Recipe updates for ${this.all.map(recipe => recipe.id)}`); |
81 | 82 | ||
82 | recipeIds.forEach((r) => { | 83 | for (const r of recipeIds) { |
83 | const recipe = this.one(r); | 84 | const recipe = this.one(r); |
84 | recipes[r] = recipe.version; | 85 | recipes[r] = recipe.version; |
85 | }); | 86 | } |
86 | 87 | ||
87 | if (Object.keys(recipes).length === 0) return; | 88 | if (Object.keys(recipes).length === 0) return; |
88 | 89 | ||
89 | const remoteUpdates = await this.getRecipeUpdatesRequest.execute(recipes)._promise; | 90 | const remoteUpdates = await this.getRecipeUpdatesRequest.execute(recipes) |
91 | ._promise; | ||
90 | 92 | ||
91 | // Check for local updates | 93 | // Check for local updates |
92 | const allJsonFile = asarRecipesPath('all.json'); | 94 | const allJsonFile = asarRecipesPath('all.json'); |
93 | const allJson = readJSONSync(allJsonFile); | 95 | const allJson = readJSONSync(allJsonFile); |
94 | const localUpdates = []; | 96 | const localUpdates = []; |
95 | 97 | ||
96 | Object.keys(recipes).forEach((recipe) => { | 98 | for (const recipe of Object.keys(recipes)) { |
97 | const version = recipes[recipe]; | 99 | const version = recipes[recipe]; |
98 | 100 | ||
99 | // Find recipe in local recipe repository | 101 | // Find recipe in local recipe repository |
100 | const localRecipe = allJson.find((r) => r.id === recipe); | 102 | const localRecipe = allJson.find(r => r.id === recipe); |
101 | 103 | ||
102 | if (localRecipe && semver.lt(version, localRecipe.version)) { | 104 | if (localRecipe && semver.lt(version, localRecipe.version)) { |
103 | localUpdates.push(recipe); | 105 | localUpdates.push(recipe); |
104 | } | 106 | } |
105 | }); | 107 | } |
106 | 108 | ||
107 | const updates = [ | 109 | const updates = [...remoteUpdates, ...localUpdates]; |
108 | ...remoteUpdates, | 110 | debug( |
109 | ...localUpdates, | 111 | 'Got update information (local, remote):', |
110 | ]; | 112 | localUpdates, |
111 | debug('Got update information (local, remote):', localUpdates, remoteUpdates); | 113 | remoteUpdates, |
114 | ); | ||
112 | 115 | ||
113 | const length = updates.length - 1; | 116 | const length = updates.length - 1; |
114 | const syncUpdate = async (i) => { | 117 | const syncUpdate = async i => { |
115 | const update = updates[i]; | 118 | const update = updates[i]; |
116 | 119 | ||
117 | this.actions.recipe.install({ recipeId: update }); | 120 | this.actions.recipe.install({ recipeId: update }); |
@@ -134,7 +137,9 @@ export default class RecipesStore extends Store { | |||
134 | async _checkIfRecipeIsInstalled() { | 137 | async _checkIfRecipeIsInstalled() { |
135 | const { router } = this.stores; | 138 | const { router } = this.stores; |
136 | 139 | ||
137 | const match = router.location && matchRoute('/settings/services/add/:id', router.location.pathname); | 140 | const match = |
141 | router.location && | ||
142 | matchRoute('/settings/services/add/:id', router.location.pathname); | ||
138 | if (match) { | 143 | if (match) { |
139 | const recipeId = match.id; | 144 | const recipeId = match.id; |
140 | 145 | ||
@@ -142,9 +147,11 @@ export default class RecipesStore extends Store { | |||
142 | router.push('/settings/recipes'); | 147 | router.push('/settings/recipes'); |
143 | debug(`Recipe ${recipeId} is not installed, trying to install it`); | 148 | debug(`Recipe ${recipeId} is not installed, trying to install it`); |
144 | 149 | ||
145 | const recipe = await this.installRecipeRequest.execute(recipeId)._promise; | 150 | const recipe = await this.installRecipeRequest.execute(recipeId) |
151 | ._promise; | ||
146 | if (recipe) { | 152 | if (recipe) { |
147 | await this.allRecipesRequest.invalidate({ immediately: true })._promise; | 153 | await this.allRecipesRequest.invalidate({ immediately: true }) |
154 | ._promise; | ||
148 | router.push(`/settings/services/add/${recipeId}`); | 155 | router.push(`/settings/services/add/${recipeId}`); |
149 | } else { | 156 | } else { |
150 | router.push('/settings/recipes'); | 157 | router.push('/settings/recipes'); |
diff --git a/src/stores/RequestStore.js b/src/stores/RequestStore.js index a92f4c685..6d2f2ef91 100644 --- a/src/stores/RequestStore.js +++ b/src/stores/RequestStore.js | |||
@@ -13,7 +13,7 @@ export default class RequestStore extends Store { | |||
13 | 13 | ||
14 | @observable showRequiredRequestsError = false; | 14 | @observable showRequiredRequestsError = false; |
15 | 15 | ||
16 | @observable localServerPort = 45569; | 16 | @observable localServerPort = 45_569; |
17 | 17 | ||
18 | retries = 0; | 18 | retries = 0; |
19 | 19 | ||
@@ -22,11 +22,11 @@ export default class RequestStore extends Store { | |||
22 | constructor(...args) { | 22 | constructor(...args) { |
23 | super(...args); | 23 | super(...args); |
24 | 24 | ||
25 | this.actions.requests.retryRequiredRequests.listen(this._retryRequiredRequests.bind(this)); | 25 | this.actions.requests.retryRequiredRequests.listen( |
26 | this._retryRequiredRequests.bind(this), | ||
27 | ); | ||
26 | 28 | ||
27 | this.registerReactions([ | 29 | this.registerReactions([this._autoRetry.bind(this)]); |
28 | this._autoRetry.bind(this), | ||
29 | ]); | ||
30 | } | 30 | } |
31 | 31 | ||
32 | setup() { | 32 | setup() { |
@@ -41,13 +41,11 @@ export default class RequestStore extends Store { | |||
41 | } | 41 | } |
42 | 42 | ||
43 | @computed get areRequiredRequestsSuccessful() { | 43 | @computed get areRequiredRequestsSuccessful() { |
44 | return !this.userInfoRequest.isError | 44 | return !this.userInfoRequest.isError && !this.servicesRequest.isError; |
45 | && !this.servicesRequest.isError; | ||
46 | } | 45 | } |
47 | 46 | ||
48 | @computed get areRequiredRequestsLoading() { | 47 | @computed get areRequiredRequestsLoading() { |
49 | return this.userInfoRequest.isExecuting | 48 | return this.userInfoRequest.isExecuting || this.servicesRequest.isExecuting; |
50 | || this.servicesRequest.isExecuting; | ||
51 | } | 49 | } |
52 | 50 | ||
53 | @action _retryRequiredRequests() { | 51 | @action _retryRequiredRequests() { |
@@ -67,7 +65,7 @@ export default class RequestStore extends Store { | |||
67 | } | 65 | } |
68 | 66 | ||
69 | this._autoRetry(); | 67 | this._autoRetry(); |
70 | debug(`Retry required requests delayed in ${(delay) / 1000}s`); | 68 | debug(`Retry required requests delayed in ${delay / 1000}s`); |
71 | }, delay); | 69 | }, delay); |
72 | } | 70 | } |
73 | } | 71 | } |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 75bc71388..67fd4103f 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -10,7 +10,10 @@ import Request from './lib/Request'; | |||
10 | import CachedRequest from './lib/CachedRequest'; | 10 | import CachedRequest from './lib/CachedRequest'; |
11 | import { matchRoute } from '../helpers/routing-helpers'; | 11 | import { matchRoute } from '../helpers/routing-helpers'; |
12 | import { isInTimeframe } from '../helpers/schedule-helpers'; | 12 | import { isInTimeframe } from '../helpers/schedule-helpers'; |
13 | import { getRecipeDirectory, getDevRecipeDirectory } from '../helpers/recipe-helpers'; | 13 | import { |
14 | getRecipeDirectory, | ||
15 | getDevRecipeDirectory, | ||
16 | } from '../helpers/recipe-helpers'; | ||
14 | import { workspaceStore } from '../features/workspaces'; | 17 | import { workspaceStore } from '../features/workspaces'; |
15 | import { KEEP_WS_LOADED_USID } from '../config'; | 18 | import { KEEP_WS_LOADED_USID } from '../config'; |
16 | import { SPELLCHECKER_LOCALES } from '../i18n/languages'; | 19 | import { SPELLCHECKER_LOCALES } from '../i18n/languages'; |
@@ -125,63 +128,49 @@ export default class ServicesStore extends Store { | |||
125 | setup() { | 128 | setup() { |
126 | // Single key reactions for the sake of your CPU | 129 | // Single key reactions for the sake of your CPU |
127 | reaction( | 130 | reaction( |
128 | () => ( | 131 | () => this.stores.settings.app.enableSpellchecking, |
129 | this.stores.settings.app.enableSpellchecking | ||
130 | ), | ||
131 | () => { | 132 | () => { |
132 | this._shareSettingsWithServiceProcess(); | 133 | this._shareSettingsWithServiceProcess(); |
133 | }, | 134 | }, |
134 | ); | 135 | ); |
135 | 136 | ||
136 | reaction( | 137 | reaction( |
137 | () => ( | 138 | () => this.stores.settings.app.spellcheckerLanguage, |
138 | this.stores.settings.app.spellcheckerLanguage | ||
139 | ), | ||
140 | () => { | 139 | () => { |
141 | this._shareSettingsWithServiceProcess(); | 140 | this._shareSettingsWithServiceProcess(); |
142 | }, | 141 | }, |
143 | ); | 142 | ); |
144 | 143 | ||
145 | reaction( | 144 | reaction( |
146 | () => ( | 145 | () => this.stores.settings.app.darkMode, |
147 | this.stores.settings.app.darkMode | ||
148 | ), | ||
149 | () => { | 146 | () => { |
150 | this._shareSettingsWithServiceProcess(); | 147 | this._shareSettingsWithServiceProcess(); |
151 | }, | 148 | }, |
152 | ); | 149 | ); |
153 | 150 | ||
154 | reaction( | 151 | reaction( |
155 | () => ( | 152 | () => this.stores.settings.app.adaptableDarkMode, |
156 | this.stores.settings.app.adaptableDarkMode | ||
157 | ), | ||
158 | () => { | 153 | () => { |
159 | this._shareSettingsWithServiceProcess(); | 154 | this._shareSettingsWithServiceProcess(); |
160 | }, | 155 | }, |
161 | ); | 156 | ); |
162 | 157 | ||
163 | reaction( | 158 | reaction( |
164 | () => ( | 159 | () => this.stores.settings.app.universalDarkMode, |
165 | this.stores.settings.app.universalDarkMode | ||
166 | ), | ||
167 | () => { | 160 | () => { |
168 | this._shareSettingsWithServiceProcess(); | 161 | this._shareSettingsWithServiceProcess(); |
169 | }, | 162 | }, |
170 | ); | 163 | ); |
171 | 164 | ||
172 | reaction( | 165 | reaction( |
173 | () => ( | 166 | () => this.stores.settings.app.searchEngine, |
174 | this.stores.settings.app.searchEngine | ||
175 | ), | ||
176 | () => { | 167 | () => { |
177 | this._shareSettingsWithServiceProcess(); | 168 | this._shareSettingsWithServiceProcess(); |
178 | }, | 169 | }, |
179 | ); | 170 | ); |
180 | 171 | ||
181 | reaction( | 172 | reaction( |
182 | () => ( | 173 | () => this.stores.settings.app.clipboardNotifications, |
183 | this.stores.settings.app.clipboardNotifications | ||
184 | ), | ||
185 | () => { | 174 | () => { |
186 | this._shareSettingsWithServiceProcess(); | 175 | this._shareSettingsWithServiceProcess(); |
187 | }, | 176 | }, |
@@ -215,12 +204,12 @@ export default class ServicesStore extends Store { | |||
215 | * Run various maintenance tasks on services | 204 | * Run various maintenance tasks on services |
216 | */ | 205 | */ |
217 | _serviceMaintenance() { | 206 | _serviceMaintenance() { |
218 | this.enabled.forEach(service => { | 207 | for (const service of this.enabled) { |
219 | // Defines which services should be hibernated or woken up | 208 | // Defines which services should be hibernated or woken up |
220 | if (!service.isActive) { | 209 | if (!service.isActive) { |
221 | if ( | 210 | if ( |
222 | !service.lastHibernated && | 211 | !service.lastHibernated && |
223 | (Date.now() - service.lastUsed) > | 212 | Date.now() - service.lastUsed > |
224 | ms(`${this.stores.settings.all.app.hibernationStrategy}s`) | 213 | ms(`${this.stores.settings.all.app.hibernationStrategy}s`) |
225 | ) { | 214 | ) { |
226 | // If service is stale, hibernate it. | 215 | // If service is stale, hibernate it. |
@@ -230,8 +219,8 @@ export default class ServicesStore extends Store { | |||
230 | if ( | 219 | if ( |
231 | service.lastHibernated && | 220 | service.lastHibernated && |
232 | Number(this.stores.settings.all.app.wakeUpStrategy) > 0 && | 221 | Number(this.stores.settings.all.app.wakeUpStrategy) > 0 && |
233 | (Date.now() - service.lastHibernated) > | 222 | Date.now() - service.lastHibernated > |
234 | ms(`${this.stores.settings.all.app.wakeUpStrategy}s`) | 223 | ms(`${this.stores.settings.all.app.wakeUpStrategy}s`) |
235 | ) { | 224 | ) { |
236 | // If service is in hibernation and the wakeup time has elapsed, wake it. | 225 | // If service is in hibernation and the wakeup time has elapsed, wake it. |
237 | this._awake({ serviceId: service.id }); | 226 | this._awake({ serviceId: service.id }); |
@@ -240,7 +229,7 @@ export default class ServicesStore extends Store { | |||
240 | 229 | ||
241 | if ( | 230 | if ( |
242 | service.lastPoll && | 231 | service.lastPoll && |
243 | (service.lastPoll - service.lastPollAnswer) > ms('1m') | 232 | service.lastPoll - service.lastPollAnswer > ms('1m') |
244 | ) { | 233 | ) { |
245 | // If service did not reply for more than 1m try to reload. | 234 | // If service did not reply for more than 1m try to reload. |
246 | if (!service.isActive) { | 235 | if (!service.isActive) { |
@@ -261,7 +250,7 @@ export default class ServicesStore extends Store { | |||
261 | service.lostRecipeConnection = false; | 250 | service.lostRecipeConnection = false; |
262 | service.lostRecipeReloadAttempt = 0; | 251 | service.lostRecipeReloadAttempt = 0; |
263 | } | 252 | } |
264 | }); | 253 | } |
265 | } | 254 | } |
266 | 255 | ||
267 | // Computed props | 256 | // Computed props |
@@ -270,8 +259,7 @@ export default class ServicesStore extends Store { | |||
270 | const services = this.allServicesRequest.execute().result; | 259 | const services = this.allServicesRequest.execute().result; |
271 | if (services) { | 260 | if (services) { |
272 | return observable( | 261 | return observable( |
273 | services | 262 | [...services] |
274 | .slice() | ||
275 | .slice() | 263 | .slice() |
276 | .sort((a, b) => a.order - b.order) | 264 | .sort((a, b) => a.order - b.order) |
277 | .map((s, index) => { | 265 | .map((s, index) => { |
@@ -318,11 +306,11 @@ export default class ServicesStore extends Store { | |||
318 | // Check if workspace needs to be kept loaded | 306 | // Check if workspace needs to be kept loaded |
319 | if (workspace.services.includes(KEEP_WS_LOADED_USID)) { | 307 | if (workspace.services.includes(KEEP_WS_LOADED_USID)) { |
320 | // Get services for workspace | 308 | // Get services for workspace |
321 | const serviceIDs = workspace.services.filter( | 309 | const serviceIDs = new Set( |
322 | i => i !== KEEP_WS_LOADED_USID, | 310 | workspace.services.filter(i => i !== KEEP_WS_LOADED_USID), |
323 | ); | 311 | ); |
324 | const wsServices = filteredServices.filter(service => | 312 | const wsServices = filteredServices.filter(service => |
325 | serviceIDs.includes(service.id), | 313 | serviceIDs.has(service.id), |
326 | ); | 314 | ); |
327 | 315 | ||
328 | displayedServices = [...displayedServices, ...wsServices]; | 316 | displayedServices = [...displayedServices, ...wsServices]; |
@@ -410,12 +398,14 @@ export default class ServicesStore extends Store { | |||
410 | customIcon: false, | 398 | customIcon: false, |
411 | isDarkModeEnabled: false, | 399 | isDarkModeEnabled: false, |
412 | spellcheckerLanguage: | 400 | spellcheckerLanguage: |
413 | SPELLCHECKER_LOCALES[this.stores.settings.app.spellcheckerLanguage], | 401 | SPELLCHECKER_LOCALES[this.stores.settings.app.spellcheckerLanguage], |
414 | userAgentPref: '', | 402 | userAgentPref: '', |
415 | ...serviceData, | 403 | ...serviceData, |
416 | }; | 404 | }; |
417 | 405 | ||
418 | const data = skipCleanup ? serviceData : this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); | 406 | const data = skipCleanup |
407 | ? serviceData | ||
408 | : this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); | ||
419 | 409 | ||
420 | const response = await this.createServiceRequest.execute(recipeId, data) | 410 | const response = await this.createServiceRequest.execute(recipeId, data) |
421 | ._promise; | 411 | ._promise; |
@@ -562,7 +552,8 @@ export default class ServicesStore extends Store { | |||
562 | // Write your scripts here | 552 | // Write your scripts here |
563 | console.log("Hello, World!", config); | 553 | console.log("Hello, World!", config); |
564 | }; | 554 | }; |
565 | `); | 555 | `, |
556 | ); | ||
566 | } | 557 | } |
567 | } else { | 558 | } else { |
568 | ensureFileSync(filePath); | 559 | ensureFileSync(filePath); |
@@ -580,9 +571,9 @@ export default class ServicesStore extends Store { | |||
580 | if (!keepActiveRoute) this.stores.router.push('/'); | 571 | if (!keepActiveRoute) this.stores.router.push('/'); |
581 | const service = this.one(serviceId); | 572 | const service = this.one(serviceId); |
582 | 573 | ||
583 | this.all.forEach(s => { | 574 | for (const s of this.all) { |
584 | s.isActive = false; | 575 | s.isActive = false; |
585 | }); | 576 | } |
586 | service.isActive = true; | 577 | service.isActive = true; |
587 | this._awake({ serviceId: service.id }); | 578 | this._awake({ serviceId: service.id }); |
588 | 579 | ||
@@ -618,9 +609,9 @@ export default class ServicesStore extends Store { | |||
618 | this.allDisplayed.length, | 609 | this.allDisplayed.length, |
619 | ); | 610 | ); |
620 | 611 | ||
621 | this.all.forEach(s => { | 612 | for (const s of this.all) { |
622 | s.isActive = false; | 613 | s.isActive = false; |
623 | }); | 614 | } |
624 | this.allDisplayed[nextIndex].isActive = true; | 615 | this.allDisplayed[nextIndex].isActive = true; |
625 | } | 616 | } |
626 | 617 | ||
@@ -631,9 +622,9 @@ export default class ServicesStore extends Store { | |||
631 | this.allDisplayed.length, | 622 | this.allDisplayed.length, |
632 | ); | 623 | ); |
633 | 624 | ||
634 | this.all.forEach(s => { | 625 | for (const s of this.all) { |
635 | s.isActive = false; | 626 | s.isActive = false; |
636 | }); | 627 | } |
637 | this.allDisplayed[prevIndex].isActive = true; | 628 | this.allDisplayed[prevIndex].isActive = true; |
638 | } | 629 | } |
639 | 630 | ||
@@ -699,101 +690,128 @@ export default class ServicesStore extends Store { | |||
699 | @action _handleIPCMessage({ serviceId, channel, args }) { | 690 | @action _handleIPCMessage({ serviceId, channel, args }) { |
700 | const service = this.one(serviceId); | 691 | const service = this.one(serviceId); |
701 | 692 | ||
702 | if (channel === 'hello') { | 693 | // eslint-disable-next-line default-case |
703 | debug('Received hello event from', serviceId); | 694 | switch (channel) { |
704 | 695 | case 'hello': { | |
705 | this._initRecipePolling(service.id); | 696 | debug('Received hello event from', serviceId); |
706 | this._initializeServiceRecipeInWebview(serviceId); | ||
707 | this._shareSettingsWithServiceProcess(); | ||
708 | } else if (channel === 'alive') { | ||
709 | service.lastPollAnswer = Date.now(); | ||
710 | } else if (channel === 'message-counts') { | ||
711 | debug(`Received unread message info from '${serviceId}'`, args[0]); | ||
712 | 697 | ||
713 | this.actions.service.setUnreadMessageCount({ | 698 | this._initRecipePolling(service.id); |
714 | serviceId, | 699 | this._initializeServiceRecipeInWebview(serviceId); |
715 | count: { | 700 | this._shareSettingsWithServiceProcess(); |
716 | direct: args[0].direct, | ||
717 | indirect: args[0].indirect, | ||
718 | }, | ||
719 | }); | ||
720 | } else if (channel === 'notification') { | ||
721 | const { options } = args[0]; | ||
722 | 701 | ||
723 | // Check if we are in scheduled Do-not-Disturb time | 702 | break; |
724 | const { scheduledDNDEnabled, scheduledDNDStart, scheduledDNDEnd } = | 703 | } |
725 | this.stores.settings.all.app; | 704 | case 'alive': { |
705 | service.lastPollAnswer = Date.now(); | ||
726 | 706 | ||
727 | if ( | 707 | break; |
728 | scheduledDNDEnabled && | ||
729 | isInTimeframe(scheduledDNDStart, scheduledDNDEnd) | ||
730 | ) { | ||
731 | return; | ||
732 | } | 708 | } |
709 | case 'message-counts': { | ||
710 | debug(`Received unread message info from '${serviceId}'`, args[0]); | ||
733 | 711 | ||
734 | if ( | 712 | this.actions.service.setUnreadMessageCount({ |
735 | service.recipe.hasNotificationSound || | 713 | serviceId, |
736 | service.isMuted || | 714 | count: { |
737 | this.stores.settings.all.app.isAppMuted | 715 | direct: args[0].direct, |
738 | ) { | 716 | indirect: args[0].indirect, |
739 | Object.assign(options, { | 717 | }, |
740 | silent: true, | ||
741 | }); | 718 | }); |
719 | |||
720 | break; | ||
742 | } | 721 | } |
722 | case 'notification': { | ||
723 | const { options } = args[0]; | ||
743 | 724 | ||
744 | if (service.isNotificationEnabled) { | 725 | // Check if we are in scheduled Do-not-Disturb time |
745 | let title = `Notification from ${service.name}`; | 726 | const { scheduledDNDEnabled, scheduledDNDStart, scheduledDNDEnd } = |
746 | if (!this.stores.settings.all.app.privateNotifications) { | 727 | this.stores.settings.all.app; |
747 | options.body = typeof options.body === 'string' ? options.body : ''; | 728 | |
748 | title = | 729 | if ( |
749 | typeof args[0].title === 'string' ? args[0].title : service.name; | 730 | scheduledDNDEnabled && |
750 | } else { | 731 | isInTimeframe(scheduledDNDStart, scheduledDNDEnd) |
751 | // Remove message data from notification in private mode | 732 | ) { |
752 | options.body = ''; | 733 | return; |
753 | options.icon = '/assets/img/notification-badge.gif'; | ||
754 | } | 734 | } |
755 | 735 | ||
756 | console.log(title, options); | 736 | if ( |
737 | service.recipe.hasNotificationSound || | ||
738 | service.isMuted || | ||
739 | this.stores.settings.all.app.isAppMuted | ||
740 | ) { | ||
741 | Object.assign(options, { | ||
742 | silent: true, | ||
743 | }); | ||
744 | } | ||
757 | 745 | ||
758 | this.actions.app.notify({ | 746 | if (service.isNotificationEnabled) { |
759 | notificationId: args[0].notificationId, | 747 | let title = `Notification from ${service.name}`; |
760 | title, | 748 | if (!this.stores.settings.all.app.privateNotifications) { |
761 | options, | 749 | options.body = typeof options.body === 'string' ? options.body : ''; |
762 | serviceId, | 750 | title = |
763 | }); | 751 | typeof args[0].title === 'string' ? args[0].title : service.name; |
752 | } else { | ||
753 | // Remove message data from notification in private mode | ||
754 | options.body = ''; | ||
755 | options.icon = '/assets/img/notification-badge.gif'; | ||
756 | } | ||
757 | |||
758 | console.log(title, options); | ||
759 | |||
760 | this.actions.app.notify({ | ||
761 | notificationId: args[0].notificationId, | ||
762 | title, | ||
763 | options, | ||
764 | serviceId, | ||
765 | }); | ||
766 | } | ||
767 | |||
768 | break; | ||
764 | } | 769 | } |
765 | } else if (channel === 'avatar') { | 770 | case 'avatar': { |
766 | const url = args[0]; | 771 | const url = args[0]; |
767 | if (service.iconUrl !== url && !service.hasCustomUploadedIcon) { | 772 | if (service.iconUrl !== url && !service.hasCustomUploadedIcon) { |
768 | service.customIconUrl = url; | 773 | service.customIconUrl = url; |
774 | |||
775 | this.actions.service.updateService({ | ||
776 | serviceId, | ||
777 | serviceData: { | ||
778 | customIconUrl: url, | ||
779 | }, | ||
780 | redirect: false, | ||
781 | }); | ||
782 | } | ||
769 | 783 | ||
770 | this.actions.service.updateService({ | 784 | break; |
771 | serviceId, | ||
772 | serviceData: { | ||
773 | customIconUrl: url, | ||
774 | }, | ||
775 | redirect: false, | ||
776 | }); | ||
777 | } | 785 | } |
778 | } else if (channel === 'new-window') { | 786 | case 'new-window': { |
779 | const url = args[0]; | 787 | const url = args[0]; |
780 | 788 | ||
781 | this.actions.app.openExternalUrl({ url }); | 789 | this.actions.app.openExternalUrl({ url }); |
782 | } else if (channel === 'set-service-spellchecker-language') { | 790 | |
783 | if (!args) { | 791 | break; |
784 | console.warn('Did not receive locale'); | 792 | } |
785 | } else { | 793 | case 'set-service-spellchecker-language': { |
786 | this.actions.service.updateService({ | 794 | if (!args) { |
787 | serviceId, | 795 | console.warn('Did not receive locale'); |
788 | serviceData: { | 796 | } else { |
789 | spellcheckerLanguage: args[0] === 'reset' ? '' : args[0], | 797 | this.actions.service.updateService({ |
790 | }, | 798 | serviceId, |
791 | redirect: false, | 799 | serviceData: { |
792 | }); | 800 | spellcheckerLanguage: args[0] === 'reset' ? '' : args[0], |
801 | }, | ||
802 | redirect: false, | ||
803 | }); | ||
804 | } | ||
805 | |||
806 | break; | ||
807 | } | ||
808 | case 'feature:todos': { | ||
809 | Object.assign(args[0].data, { serviceId }); | ||
810 | this.actions.todos.handleHostMessage(args[0]); | ||
811 | |||
812 | break; | ||
793 | } | 813 | } |
794 | } else if (channel === 'feature:todos') { | 814 | // No default |
795 | Object.assign(args[0].data, { serviceId }); | ||
796 | this.actions.todos.handleHostMessage(args[0]); | ||
797 | } | 815 | } |
798 | } | 816 | } |
799 | 817 | ||
@@ -809,13 +827,13 @@ export default class ServicesStore extends Store { | |||
809 | } | 827 | } |
810 | 828 | ||
811 | @action _sendIPCMessageToAllServices({ channel, args }) { | 829 | @action _sendIPCMessageToAllServices({ channel, args }) { |
812 | this.all.forEach(s => | 830 | for (const s of this.all) { |
813 | this.actions.service.sendIPCMessage({ | 831 | this.actions.service.sendIPCMessage({ |
814 | serviceId: s.id, | 832 | serviceId: s.id, |
815 | channel, | 833 | channel, |
816 | args, | 834 | args, |
817 | }), | 835 | }); |
818 | ); | 836 | } |
819 | } | 837 | } |
820 | 838 | ||
821 | @action _openWindow({ event }) { | 839 | @action _openWindow({ event }) { |
@@ -863,11 +881,11 @@ export default class ServicesStore extends Store { | |||
863 | } | 881 | } |
864 | 882 | ||
865 | @action _reloadAll() { | 883 | @action _reloadAll() { |
866 | this.enabled.forEach(s => | 884 | for (const s of this.enabled) { |
867 | this._reload({ | 885 | this._reload({ |
868 | serviceId: s.id, | 886 | serviceId: s.id, |
869 | }), | 887 | }); |
870 | ); | 888 | } |
871 | } | 889 | } |
872 | 890 | ||
873 | @action _reloadUpdatedServices() { | 891 | @action _reloadUpdatedServices() { |
@@ -901,17 +919,17 @@ export default class ServicesStore extends Store { | |||
901 | 919 | ||
902 | const services = {}; | 920 | const services = {}; |
903 | // TODO: simplify this | 921 | // TODO: simplify this |
904 | this.all.forEach((s, index) => { | 922 | for (const [index] of this.all.entries()) { |
905 | services[this.all[index].id] = index; | 923 | services[this.all[index].id] = index; |
906 | }); | 924 | } |
907 | 925 | ||
908 | this.reorderServicesRequest.execute(services); | 926 | this.reorderServicesRequest.execute(services); |
909 | this.allServicesRequest.patch(data => { | 927 | this.allServicesRequest.patch(data => { |
910 | data.forEach(s => { | 928 | for (const s of data) { |
911 | const service = s; | 929 | const service = s; |
912 | 930 | ||
913 | service.order = services[s.id]; | 931 | service.order = services[s.id]; |
914 | }); | 932 | } |
915 | }); | 933 | }); |
916 | } | 934 | } |
917 | 935 | ||
@@ -1001,13 +1019,14 @@ export default class ServicesStore extends Store { | |||
1001 | }`, | 1019 | }`, |
1002 | ); | 1020 | ); |
1003 | 1021 | ||
1022 | // eslint-disable-next-line unicorn/consistent-function-scoping | ||
1004 | const resetTimer = service => { | 1023 | const resetTimer = service => { |
1005 | service.lastPollAnswer = Date.now(); | 1024 | service.lastPollAnswer = Date.now(); |
1006 | service.lastPoll = Date.now(); | 1025 | service.lastPoll = Date.now(); |
1007 | }; | 1026 | }; |
1008 | 1027 | ||
1009 | if (!serviceId) { | 1028 | if (!serviceId) { |
1010 | this.allDisplayed.forEach(service => resetTimer(service)); | 1029 | for (const service of this.allDisplayed) resetTimer(service); |
1011 | } else { | 1030 | } else { |
1012 | const service = this.one(serviceId); | 1031 | const service = this.one(serviceId); |
1013 | if (service) { | 1032 | if (service) { |
@@ -1043,7 +1062,7 @@ export default class ServicesStore extends Store { | |||
1043 | 1062 | ||
1044 | _mapActiveServiceToServiceModelReaction() { | 1063 | _mapActiveServiceToServiceModelReaction() { |
1045 | const { activeService } = this.stores.settings.all.service; | 1064 | const { activeService } = this.stores.settings.all.service; |
1046 | if (this.allDisplayed.length) { | 1065 | if (this.allDisplayed.length > 0) { |
1047 | this.allDisplayed.map(service => | 1066 | this.allDisplayed.map(service => |
1048 | Object.assign(service, { | 1067 | Object.assign(service, { |
1049 | isActive: activeService | 1068 | isActive: activeService |
@@ -1102,14 +1121,14 @@ export default class ServicesStore extends Store { | |||
1102 | const { enabled } = this; | 1121 | const { enabled } = this; |
1103 | const { isAppMuted } = this.stores.settings.app; | 1122 | const { isAppMuted } = this.stores.settings.app; |
1104 | 1123 | ||
1105 | enabled.forEach(service => { | 1124 | for (const service of enabled) { |
1106 | const { isAttached } = service; | 1125 | const { isAttached } = service; |
1107 | const isMuted = isAppMuted || service.isMuted; | 1126 | const isMuted = isAppMuted || service.isMuted; |
1108 | 1127 | ||
1109 | if (isAttached) { | 1128 | if (isAttached) { |
1110 | service.webview.audioMuted = isMuted; | 1129 | service.webview.audioMuted = isMuted; |
1111 | } | 1130 | } |
1112 | }); | 1131 | } |
1113 | } | 1132 | } |
1114 | 1133 | ||
1115 | _shareSettingsWithServiceProcess() { | 1134 | _shareSettingsWithServiceProcess() { |
@@ -1151,7 +1170,7 @@ export default class ServicesStore extends Store { | |||
1151 | 1170 | ||
1152 | if ( | 1171 | if ( |
1153 | this.allDisplayed.findIndex(service => service.isActive) === -1 && | 1172 | this.allDisplayed.findIndex(service => service.isActive) === -1 && |
1154 | this.allDisplayed.length !== 0 | 1173 | this.allDisplayed.length > 0 |
1155 | ) { | 1174 | ) { |
1156 | debug('No active service found, setting active service to index 0'); | 1175 | debug('No active service found, setting active service to index 0'); |
1157 | 1176 | ||
diff --git a/src/stores/SettingsStore.js b/src/stores/SettingsStore.js index 9aade974c..690a18374 100644 --- a/src/stores/SettingsStore.js +++ b/src/stores/SettingsStore.js | |||
@@ -1,11 +1,11 @@ | |||
1 | import { ipcRenderer } from 'electron'; | 1 | import { ipcRenderer } from 'electron'; |
2 | import { getCurrentWindow } from '@electron/remote'; | 2 | import { getCurrentWindow } from '@electron/remote'; |
3 | import { | 3 | import { action, computed, observable, reaction } from 'mobx'; |
4 | action, computed, observable, reaction, | ||
5 | } from 'mobx'; | ||
6 | import localStorage from 'mobx-localstorage'; | 4 | import localStorage from 'mobx-localstorage'; |
7 | import { | 5 | import { |
8 | FILE_SYSTEM_SETTINGS_TYPES, LOCAL_SERVER, SEARCH_ENGINE_DDG, | 6 | FILE_SYSTEM_SETTINGS_TYPES, |
7 | LOCAL_SERVER, | ||
8 | SEARCH_ENGINE_DDG, | ||
9 | } from '../config'; | 9 | } from '../config'; |
10 | import { API, DEFAULT_APP_SETTINGS } from '../environment'; | 10 | import { API, DEFAULT_APP_SETTINGS } from '../environment'; |
11 | import { getLocale } from '../helpers/i18n-helpers'; | 11 | import { getLocale } from '../helpers/i18n-helpers'; |
@@ -17,7 +17,10 @@ import Store from './lib/Store'; | |||
17 | const debug = require('debug')('Ferdi:SettingsStore'); | 17 | const debug = require('debug')('Ferdi:SettingsStore'); |
18 | 18 | ||
19 | export default class SettingsStore extends Store { | 19 | export default class SettingsStore extends Store { |
20 | @observable updateAppSettingsRequest = new Request(this.api.local, 'updateAppSettings'); | 20 | @observable updateAppSettingsRequest = new Request( |
21 | this.api.local, | ||
22 | 'updateAppSettings', | ||
23 | ); | ||
21 | 24 | ||
22 | startup = true; | 25 | startup = true; |
23 | 26 | ||
@@ -40,9 +43,7 @@ export default class SettingsStore extends Store { | |||
40 | await this._migrate(); | 43 | await this._migrate(); |
41 | 44 | ||
42 | reaction( | 45 | reaction( |
43 | () => ( | 46 | () => this.all.app.autohideMenuBar, |
44 | this.all.app.autohideMenuBar | ||
45 | ), | ||
46 | () => { | 47 | () => { |
47 | const currentWindow = getCurrentWindow(); | 48 | const currentWindow = getCurrentWindow(); |
48 | currentWindow.setMenuBarVisibility(!this.all.app.autohideMenuBar); | 49 | currentWindow.setMenuBarVisibility(!this.all.app.autohideMenuBar); |
@@ -51,10 +52,8 @@ export default class SettingsStore extends Store { | |||
51 | ); | 52 | ); |
52 | 53 | ||
53 | reaction( | 54 | reaction( |
54 | () => ( | 55 | () => this.all.app.server, |
55 | this.all.app.server | 56 | server => { |
56 | ), | ||
57 | (server) => { | ||
58 | if (server === LOCAL_SERVER) { | 57 | if (server === LOCAL_SERVER) { |
59 | ipcRenderer.send('startLocalServer'); | 58 | ipcRenderer.send('startLocalServer'); |
60 | } | 59 | } |
@@ -65,7 +64,10 @@ export default class SettingsStore extends Store { | |||
65 | // Inactivity lock timer | 64 | // Inactivity lock timer |
66 | let inactivityTimer; | 65 | let inactivityTimer; |
67 | getCurrentWindow().on('blur', () => { | 66 | getCurrentWindow().on('blur', () => { |
68 | if (this.all.app.lockingFeatureEnabled && this.all.app.inactivityLock !== 0) { | 67 | if ( |
68 | this.all.app.lockingFeatureEnabled && | ||
69 | this.all.app.inactivityLock !== 0 | ||
70 | ) { | ||
69 | inactivityTimer = setTimeout(() => { | 71 | inactivityTimer = setTimeout(() => { |
70 | this.actions.settings.update({ | 72 | this.actions.settings.update({ |
71 | type: 'app', | 73 | type: 'app', |
@@ -84,7 +86,11 @@ export default class SettingsStore extends Store { | |||
84 | 86 | ||
85 | ipcRenderer.on('appSettings', (event, resp) => { | 87 | ipcRenderer.on('appSettings', (event, resp) => { |
86 | // Lock on startup if enabled in settings | 88 | // Lock on startup if enabled in settings |
87 | if (this.startup && resp.type === 'app' && resp.data.lockingFeatureEnabled) { | 89 | if ( |
90 | this.startup && | ||
91 | resp.type === 'app' && | ||
92 | resp.data.lockingFeatureEnabled | ||
93 | ) { | ||
88 | this.startup = false; | 94 | this.startup = false; |
89 | process.nextTick(() => { | 95 | process.nextTick(() => { |
90 | if (!this.all.app.locked) { | 96 | if (!this.all.app.locked) { |
@@ -97,9 +103,9 @@ export default class SettingsStore extends Store { | |||
97 | ipcRenderer.send('initialAppSettings', resp); | 103 | ipcRenderer.send('initialAppSettings', resp); |
98 | }); | 104 | }); |
99 | 105 | ||
100 | this.fileSystemSettingsTypes.forEach((type) => { | 106 | for (const type of this.fileSystemSettingsTypes) { |
101 | ipcRenderer.send('getAppSettings', type); | 107 | ipcRenderer.send('getAppSettings', type); |
102 | }); | 108 | } |
103 | } | 109 | } |
104 | 110 | ||
105 | @computed get app() { | 111 | @computed get app() { |
@@ -111,15 +117,19 @@ export default class SettingsStore extends Store { | |||
111 | } | 117 | } |
112 | 118 | ||
113 | @computed get service() { | 119 | @computed get service() { |
114 | return localStorage.getItem('service') || { | 120 | return ( |
115 | activeService: '', | 121 | localStorage.getItem('service') || { |
116 | }; | 122 | activeService: '', |
123 | } | ||
124 | ); | ||
117 | } | 125 | } |
118 | 126 | ||
119 | @computed get stats() { | 127 | @computed get stats() { |
120 | return localStorage.getItem('stats') || { | 128 | return ( |
121 | activeService: '', | 129 | localStorage.getItem('stats') || { |
122 | }; | 130 | activeService: '', |
131 | } | ||
132 | ); | ||
123 | } | 133 | } |
124 | 134 | ||
125 | @computed get migration() { | 135 | @computed get migration() { |
@@ -230,9 +240,7 @@ export default class SettingsStore extends Store { | |||
230 | }); | 240 | }); |
231 | 241 | ||
232 | this._ensureMigrationAndMarkDone('5.4.4-beta.2-settings', () => { | 242 | this._ensureMigrationAndMarkDone('5.4.4-beta.2-settings', () => { |
233 | const { | 243 | const { showServiceNavigationBar } = this.all.app; |
234 | showServiceNavigationBar, | ||
235 | } = this.all.app; | ||
236 | 244 | ||
237 | this.actions.settings.update({ | 245 | this.actions.settings.update({ |
238 | type: 'app', | 246 | type: 'app', |
@@ -248,7 +256,7 @@ export default class SettingsStore extends Store { | |||
248 | data: { | 256 | data: { |
249 | todoServer: 'isUsingCustomTodoService', | 257 | todoServer: 'isUsingCustomTodoService', |
250 | customTodoServer: legacySettings.todoServer, | 258 | customTodoServer: legacySettings.todoServer, |
251 | automaticUpdates: !(legacySettings.noUpdates), | 259 | automaticUpdates: !legacySettings.noUpdates, |
252 | }, | 260 | }, |
253 | }); | 261 | }); |
254 | 262 | ||
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index 2e009893a..e3d57c662 100644 --- a/src/stores/UserStore.js +++ b/src/stores/UserStore.js | |||
@@ -46,7 +46,10 @@ export default class UserStore extends Store { | |||
46 | 46 | ||
47 | @observable updateUserInfoRequest = new Request(this.api.user, 'updateInfo'); | 47 | @observable updateUserInfoRequest = new Request(this.api.user, 'updateInfo'); |
48 | 48 | ||
49 | @observable getLegacyServicesRequest = new CachedRequest(this.api.user, 'getLegacyServices'); | 49 | @observable getLegacyServicesRequest = new CachedRequest( |
50 | this.api.user, | ||
51 | 'getLegacyServices', | ||
52 | ); | ||
50 | 53 | ||
51 | @observable deleteAccountRequest = new CachedRequest(this.api.user, 'delete'); | 54 | @observable deleteAccountRequest = new CachedRequest(this.api.user, 'delete'); |
52 | 55 | ||
@@ -81,13 +84,17 @@ export default class UserStore extends Store { | |||
81 | 84 | ||
82 | // Register action handlers | 85 | // Register action handlers |
83 | this.actions.user.login.listen(this._login.bind(this)); | 86 | this.actions.user.login.listen(this._login.bind(this)); |
84 | this.actions.user.retrievePassword.listen(this._retrievePassword.bind(this)); | 87 | this.actions.user.retrievePassword.listen( |
88 | this._retrievePassword.bind(this), | ||
89 | ); | ||
85 | this.actions.user.logout.listen(this._logout.bind(this)); | 90 | this.actions.user.logout.listen(this._logout.bind(this)); |
86 | this.actions.user.signup.listen(this._signup.bind(this)); | 91 | this.actions.user.signup.listen(this._signup.bind(this)); |
87 | this.actions.user.invite.listen(this._invite.bind(this)); | 92 | this.actions.user.invite.listen(this._invite.bind(this)); |
88 | this.actions.user.update.listen(this._update.bind(this)); | 93 | this.actions.user.update.listen(this._update.bind(this)); |
89 | this.actions.user.resetStatus.listen(this._resetStatus.bind(this)); | 94 | this.actions.user.resetStatus.listen(this._resetStatus.bind(this)); |
90 | this.actions.user.importLegacyServices.listen(this._importLegacyServices.bind(this)); | 95 | this.actions.user.importLegacyServices.listen( |
96 | this._importLegacyServices.bind(this), | ||
97 | ); | ||
91 | this.actions.user.delete.listen(this._delete.bind(this)); | 98 | this.actions.user.delete.listen(this._delete.bind(this)); |
92 | 99 | ||
93 | // Reactions | 100 | // Reactions |
@@ -176,7 +183,14 @@ export default class UserStore extends Store { | |||
176 | } | 183 | } |
177 | 184 | ||
178 | @action async _signup({ | 185 | @action async _signup({ |
179 | firstname, lastname, email, password, accountType, company, plan, currency, | 186 | firstname, |
187 | lastname, | ||
188 | email, | ||
189 | password, | ||
190 | accountType, | ||
191 | company, | ||
192 | plan, | ||
193 | currency, | ||
180 | }) { | 194 | }) { |
181 | const authToken = await this.signupRequest.execute({ | 195 | const authToken = await this.signupRequest.execute({ |
182 | firstname, | 196 | firstname, |
@@ -205,7 +219,7 @@ export default class UserStore extends Store { | |||
205 | } | 219 | } |
206 | 220 | ||
207 | @action async _invite({ invites }) { | 221 | @action async _invite({ invites }) { |
208 | const data = invites.filter((invite) => invite.email !== ''); | 222 | const data = invites.filter(invite => invite.email !== ''); |
209 | 223 | ||
210 | const response = await this.inviteRequest.execute(data)._promise; | 224 | const response = await this.inviteRequest.execute(data)._promise; |
211 | 225 | ||
@@ -220,7 +234,8 @@ export default class UserStore extends Store { | |||
220 | @action async _update({ userData }) { | 234 | @action async _update({ userData }) { |
221 | if (!this.isLoggedIn) return; | 235 | if (!this.isLoggedIn) return; |
222 | 236 | ||
223 | const response = await this.updateUserInfoRequest.execute(userData)._promise; | 237 | const response = await this.updateUserInfoRequest.execute(userData) |
238 | ._promise; | ||
224 | 239 | ||
225 | this.getUserInfoRequest.patch(() => response.data); | 240 | this.getUserInfoRequest.patch(() => response.data); |
226 | this.actionStatus = response.status || []; | 241 | this.actionStatus = response.status || []; |
@@ -250,19 +265,27 @@ export default class UserStore extends Store { | |||
250 | this.isImportLegacyServicesExecuting = true; | 265 | this.isImportLegacyServicesExecuting = true; |
251 | 266 | ||
252 | // Reduces recipe duplicates | 267 | // Reduces recipe duplicates |
253 | const recipes = services.filter((obj, pos, arr) => arr.map((mapObj) => mapObj.recipe.id).indexOf(obj.recipe.id) === pos).map((s) => s.recipe.id); | 268 | const recipes = services |
269 | .filter( | ||
270 | (obj, pos, arr) => | ||
271 | arr.map(mapObj => mapObj.recipe.id).indexOf(obj.recipe.id) === pos, | ||
272 | ) | ||
273 | .map(s => s.recipe.id); | ||
254 | 274 | ||
255 | // Install recipes | 275 | // Install recipes |
256 | for (const recipe of recipes) { // eslint-disable-line no-unused-vars | 276 | for (const recipe of recipes) { |
257 | // eslint-disable-next-line | 277 | // eslint-disable-line no-unused-vars |
278 | // eslint-disable-next-line no-await-in-loop | ||
258 | await this.stores.recipes._install({ recipeId: recipe }); | 279 | await this.stores.recipes._install({ recipeId: recipe }); |
259 | } | 280 | } |
260 | 281 | ||
261 | for (const service of services) { // eslint-disable-line no-unused-vars | 282 | for (const service of services) { |
283 | // eslint-disable-line no-unused-vars | ||
262 | this.actions.service.createFromLegacyService({ | 284 | this.actions.service.createFromLegacyService({ |
263 | data: service, | 285 | data: service, |
264 | }); | 286 | }); |
265 | await this.stores.services.createServiceRequest._promise; // eslint-disable-line | 287 | // eslint-disable-next-line no-await-in-loop |
288 | await this.stores.services.createServiceRequest._promise; | ||
266 | } | 289 | } |
267 | 290 | ||
268 | this.isImportLegacyServicesExecuting = false; | 291 | this.isImportLegacyServicesExecuting = false; |
@@ -281,8 +304,7 @@ export default class UserStore extends Store { | |||
281 | 304 | ||
282 | const { router } = this.stores; | 305 | const { router } = this.stores; |
283 | const currentRoute = window.location.hash; | 306 | const currentRoute = window.location.hash; |
284 | if (!this.isLoggedIn | 307 | if (!this.isLoggedIn && currentRoute.includes('token=')) { |
285 | && currentRoute.includes('token=')) { | ||
286 | router.push(this.WELCOME_ROUTE); | 308 | router.push(this.WELCOME_ROUTE); |
287 | const token = currentRoute.split('=')[1]; | 309 | const token = currentRoute.split('=')[1]; |
288 | 310 | ||
@@ -293,20 +315,18 @@ export default class UserStore extends Store { | |||
293 | this._tokenLogin(token); | 315 | this._tokenLogin(token); |
294 | }, 1000); | 316 | }, 1000); |
295 | } | 317 | } |
296 | } else if (!this.isLoggedIn | 318 | } else if (!this.isLoggedIn && !currentRoute.includes(this.BASE_ROUTE)) { |
297 | && !currentRoute.includes(this.BASE_ROUTE)) { | ||
298 | router.push(this.WELCOME_ROUTE); | 319 | router.push(this.WELCOME_ROUTE); |
299 | } else if (this.isLoggedIn | 320 | } else if (this.isLoggedIn && currentRoute === this.LOGOUT_ROUTE) { |
300 | && currentRoute === this.LOGOUT_ROUTE) { | ||
301 | this.actions.user.logout(); | 321 | this.actions.user.logout(); |
302 | router.push(this.LOGIN_ROUTE); | 322 | router.push(this.LOGIN_ROUTE); |
303 | } else if (this.isLoggedIn | 323 | } else if ( |
304 | && currentRoute.includes(this.BASE_ROUTE) | 324 | this.isLoggedIn && |
305 | && (this.hasCompletedSignup | 325 | currentRoute.includes(this.BASE_ROUTE) && |
306 | || this.hasCompletedSignup === null)) { | 326 | (this.hasCompletedSignup || this.hasCompletedSignup === null) && |
307 | if (!isDevMode) { | 327 | !isDevMode |
308 | this.stores.router.push('/'); | 328 | ) { |
309 | } | 329 | this.stores.router.push('/'); |
310 | } | 330 | } |
311 | }; | 331 | }; |
312 | 332 | ||
@@ -316,7 +336,7 @@ export default class UserStore extends Store { | |||
316 | let data; | 336 | let data; |
317 | try { | 337 | try { |
318 | data = await this.getUserInfoRequest.execute()._promise; | 338 | data = await this.getUserInfoRequest.execute()._promise; |
319 | } catch (e) { | 339 | } catch { |
320 | return false; | 340 | return false; |
321 | } | 341 | } |
322 | 342 | ||
@@ -336,12 +356,12 @@ export default class UserStore extends Store { | |||
336 | try { | 356 | try { |
337 | const decoded = jwt.decode(authToken); | 357 | const decoded = jwt.decode(authToken); |
338 | 358 | ||
339 | return ({ | 359 | return { |
340 | id: decoded.userId, | 360 | id: decoded.userId, |
341 | tokenExpiry: moment.unix(decoded.exp).toISOString(), | 361 | tokenExpiry: moment.unix(decoded.exp).toISOString(), |
342 | authToken, | 362 | authToken, |
343 | }); | 363 | }; |
344 | } catch (err) { | 364 | } catch { |
345 | this._logout(); | 365 | this._logout(); |
346 | return false; | 366 | return false; |
347 | } | 367 | } |
@@ -372,7 +392,7 @@ export default class UserStore extends Store { | |||
372 | async _migrateUserLocale() { | 392 | async _migrateUserLocale() { |
373 | try { | 393 | try { |
374 | await this.getUserInfoRequest._promise; | 394 | await this.getUserInfoRequest._promise; |
375 | } catch (e) { | 395 | } catch { |
376 | return false; | 396 | return false; |
377 | } | 397 | } |
378 | 398 | ||
diff --git a/src/stores/index.ts b/src/stores/index.ts index 4cd4e92ea..1760ddfa2 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts | |||
@@ -34,10 +34,10 @@ export default (api, actions, router) => { | |||
34 | }); | 34 | }); |
35 | 35 | ||
36 | // Initialize all stores | 36 | // Initialize all stores |
37 | Object.keys(stores).forEach(name => { | 37 | for (const name of Object.keys(stores)) { |
38 | if (stores[name] && stores[name].initialize) { | 38 | if (stores[name] && stores[name].initialize) { |
39 | stores[name].initialize(); | 39 | stores[name].initialize(); |
40 | } | 40 | } |
41 | }); | 41 | } |
42 | return stores; | 42 | return stores; |
43 | }; | 43 | }; |
diff --git a/src/stores/lib/CachedRequest.js b/src/stores/lib/CachedRequest.js index 94f615144..a6dd47f7d 100644 --- a/src/stores/lib/CachedRequest.js +++ b/src/stores/lib/CachedRequest.js | |||
@@ -1,4 +1,3 @@ | |||
1 | // @flow | ||
2 | import { action } from 'mobx'; | 1 | import { action } from 'mobx'; |
3 | import { isEqual, remove } from 'lodash'; | 2 | import { isEqual, remove } from 'lodash'; |
4 | import Request from './Request'; | 3 | import Request from './Request'; |
@@ -30,48 +29,60 @@ export default class CachedRequest extends Request { | |||
30 | 29 | ||
31 | // This timeout is necessary to avoid warnings from mobx | 30 | // This timeout is necessary to avoid warnings from mobx |
32 | // regarding triggering actions as side-effect of getters | 31 | // regarding triggering actions as side-effect of getters |
33 | setTimeout(action(() => { | 32 | setTimeout( |
34 | this.isExecuting = true; | 33 | action(() => { |
35 | // Apply the previous result from this call immediately (cached) | 34 | this.isExecuting = true; |
36 | if (existingApiCall) { | 35 | // Apply the previous result from this call immediately (cached) |
37 | this.result = existingApiCall.result; | 36 | if (existingApiCall) { |
38 | } | 37 | this.result = existingApiCall.result; |
39 | }), 0); | 38 | } |
39 | }), | ||
40 | 0, | ||
41 | ); | ||
40 | 42 | ||
41 | // Issue api call & save it as promise that is handled to update the results of the operation | 43 | // Issue api call & save it as promise that is handled to update the results of the operation |
42 | this._promise = new Promise((resolve) => { | 44 | this._promise = new Promise(resolve => { |
43 | this._api[this._method](...callArgs) | 45 | this._api[this._method](...callArgs) |
44 | .then((result) => { | 46 | .then(result => { |
45 | setTimeout(action(() => { | 47 | setTimeout( |
46 | this.result = result; | 48 | action(() => { |
47 | if (this._currentApiCall) this._currentApiCall.result = result; | 49 | this.result = result; |
48 | this.isExecuting = false; | 50 | if (this._currentApiCall) this._currentApiCall.result = result; |
49 | this.isError = false; | 51 | this.isExecuting = false; |
50 | this.wasExecuted = true; | 52 | this.isError = false; |
51 | this._isInvalidated = false; | 53 | this.wasExecuted = true; |
52 | this._isWaitingForResponse = false; | 54 | this._isInvalidated = false; |
53 | this._triggerHooks(); | 55 | this._isWaitingForResponse = false; |
54 | resolve(result); | 56 | this._triggerHooks(); |
55 | }), 1); | 57 | resolve(result); |
58 | }), | ||
59 | 1, | ||
60 | ); | ||
56 | return result; | 61 | return result; |
57 | }) | 62 | }) |
58 | .catch(action((error) => { | 63 | .catch( |
59 | setTimeout(action(() => { | 64 | action(error => { |
60 | this.error = error; | 65 | setTimeout( |
61 | this.isExecuting = false; | 66 | action(() => { |
62 | this.isError = true; | 67 | this.error = error; |
63 | this.wasExecuted = true; | 68 | this.isExecuting = false; |
64 | this._isWaitingForResponse = false; | 69 | this.isError = true; |
65 | this._triggerHooks(); | 70 | this.wasExecuted = true; |
66 | // reject(error); | 71 | this._isWaitingForResponse = false; |
67 | }), 1); | 72 | this._triggerHooks(); |
68 | })); | 73 | // reject(error); |
74 | }), | ||
75 | 1, | ||
76 | ); | ||
77 | }), | ||
78 | ); | ||
69 | }); | 79 | }); |
70 | 80 | ||
71 | this._isWaitingForResponse = true; | 81 | this._isWaitingForResponse = true; |
72 | return this; | 82 | return this; |
73 | } | 83 | } |
74 | 84 | ||
85 | // eslint-disable-next-line unicorn/no-object-as-default-parameter | ||
75 | invalidate(options = { immediately: false }) { | 86 | invalidate(options = { immediately: false }) { |
76 | this._isInvalidated = true; | 87 | this._isInvalidated = true; |
77 | if (options.immediately && this._currentApiCall) { | 88 | if (options.immediately && this._currentApiCall) { |
@@ -81,18 +92,21 @@ export default class CachedRequest extends Request { | |||
81 | } | 92 | } |
82 | 93 | ||
83 | patch(modify) { | 94 | patch(modify) { |
84 | return new Promise((resolve) => { | 95 | return new Promise(resolve => { |
85 | setTimeout(action(() => { | 96 | setTimeout( |
86 | const override = modify(this.result); | 97 | action(() => { |
87 | if (override !== undefined) this.result = override; | 98 | const override = modify(this.result); |
88 | if (this._currentApiCall) this._currentApiCall.result = this.result; | 99 | if (override !== undefined) this.result = override; |
89 | resolve(this); | 100 | if (this._currentApiCall) this._currentApiCall.result = this.result; |
90 | }), 0); | 101 | resolve(this); |
102 | }), | ||
103 | 0, | ||
104 | ); | ||
91 | }); | 105 | }); |
92 | } | 106 | } |
93 | 107 | ||
94 | removeCacheForCallWith(...args) { | 108 | removeCacheForCallWith(...args) { |
95 | remove(this._apiCalls, (c) => isEqual(c.args, args)); | 109 | remove(this._apiCalls, c => isEqual(c.args, args)); |
96 | } | 110 | } |
97 | 111 | ||
98 | _addApiCall(args) { | 112 | _addApiCall(args) { |
@@ -102,6 +116,6 @@ export default class CachedRequest extends Request { | |||
102 | } | 116 | } |
103 | 117 | ||
104 | _findApiCall(args) { | 118 | _findApiCall(args) { |
105 | return this._apiCalls.find((c) => isEqual(c.args, args)); | 119 | return this._apiCalls.find(c => isEqual(c.args, args)); |
106 | } | 120 | } |
107 | } | 121 | } |
diff --git a/src/stores/lib/Request.js b/src/stores/lib/Request.js index 32ffe4367..39f32729a 100644 --- a/src/stores/lib/Request.js +++ b/src/stores/lib/Request.js | |||
@@ -107,7 +107,7 @@ export default class Request { | |||
107 | } | 107 | } |
108 | 108 | ||
109 | _triggerHooks() { | 109 | _triggerHooks() { |
110 | Request._hooks.forEach((hook) => hook(this)); | 110 | for (const hook of Request._hooks) hook(this); |
111 | } | 111 | } |
112 | 112 | ||
113 | reset = () => { | 113 | reset = () => { |
diff --git a/src/stores/lib/Store.js b/src/stores/lib/Store.js index b03a7e725..b39070ce8 100644 --- a/src/stores/lib/Store.js +++ b/src/stores/lib/Store.js | |||
@@ -28,18 +28,18 @@ export default class Store { | |||
28 | } | 28 | } |
29 | 29 | ||
30 | registerReactions(reactions) { | 30 | registerReactions(reactions) { |
31 | reactions.forEach((reaction) => this._reactions.push(new Reaction(reaction))); | 31 | for (const reaction of reactions) this._reactions.push(new Reaction(reaction)); |
32 | } | 32 | } |
33 | 33 | ||
34 | setup() {} | 34 | setup() {} |
35 | 35 | ||
36 | initialize() { | 36 | initialize() { |
37 | this.setup(); | 37 | this.setup(); |
38 | this._reactions.forEach((reaction) => reaction.start()); | 38 | for (const reaction of this._reactions) reaction.start(); |
39 | } | 39 | } |
40 | 40 | ||
41 | teardown() { | 41 | teardown() { |
42 | this._reactions.forEach((reaction) => reaction.stop()); | 42 | for (const reaction of this._reactions) reaction.stop(); |
43 | } | 43 | } |
44 | 44 | ||
45 | resetStatus() { | 45 | resetStatus() { |