diff options
-rw-r--r-- | src/models/Recipe.ts | 5 | ||||
-rw-r--r-- | src/stores.types.ts | 15 | ||||
-rw-r--r-- | src/stores/RecipePreviewsStore.ts (renamed from src/stores/RecipePreviewsStore.js) | 36 | ||||
-rw-r--r-- | src/stores/RecipesStore.ts (renamed from src/stores/RecipesStore.js) | 35 | ||||
-rw-r--r-- | src/stores/RequestStore.ts (renamed from src/stores/RequestStore.js) | 33 |
5 files changed, 83 insertions, 41 deletions
diff --git a/src/models/Recipe.ts b/src/models/Recipe.ts index 4463abe95..be889d22c 100644 --- a/src/models/Recipe.ts +++ b/src/models/Recipe.ts | |||
@@ -23,6 +23,7 @@ interface IRecipe { | |||
23 | disablewebsecurity?: boolean; | 23 | disablewebsecurity?: boolean; |
24 | autoHibernate?: boolean; | 24 | autoHibernate?: boolean; |
25 | partition?: string; | 25 | partition?: string; |
26 | local?: boolean; | ||
26 | message?: string; | 27 | message?: string; |
27 | allowFavoritesDelineationInUnreadCount?: boolean; | 28 | allowFavoritesDelineationInUnreadCount?: boolean; |
28 | }; | 29 | }; |
@@ -71,6 +72,9 @@ export default class Recipe { | |||
71 | 72 | ||
72 | partition: string = ''; | 73 | partition: string = ''; |
73 | 74 | ||
75 | // TODO: Is this being used? | ||
76 | local: boolean = false; | ||
77 | |||
74 | // TODO: Need to reconcile which of these are optional/mandatory | 78 | // TODO: Need to reconcile which of these are optional/mandatory |
75 | constructor(data: IRecipe) { | 79 | constructor(data: IRecipe) { |
76 | if (!data) { | 80 | if (!data) { |
@@ -134,6 +138,7 @@ export default class Recipe { | |||
134 | data.config.autoHibernate, | 138 | data.config.autoHibernate, |
135 | this.autoHibernate, | 139 | this.autoHibernate, |
136 | ); | 140 | ); |
141 | this.local = ifUndefinedBoolean(data.config.local, this.local); | ||
137 | this.message = ifUndefinedString(data.config.message, this.message); | 142 | this.message = ifUndefinedString(data.config.message, this.message); |
138 | this.allowFavoritesDelineationInUnreadCount = ifUndefinedBoolean( | 143 | this.allowFavoritesDelineationInUnreadCount = ifUndefinedBoolean( |
139 | data.config.allowFavoritesDelineationInUnreadCount, | 144 | data.config.allowFavoritesDelineationInUnreadCount, |
diff --git a/src/stores.types.ts b/src/stores.types.ts index 14ae32133..b0912c463 100644 --- a/src/stores.types.ts +++ b/src/stores.types.ts | |||
@@ -161,6 +161,7 @@ interface RecipeStore { | |||
161 | _reactions: any[]; | 161 | _reactions: any[]; |
162 | _status: () => void; | 162 | _status: () => void; |
163 | actionStatus: () => void; | 163 | actionStatus: () => void; |
164 | isInstalled: (id: string) => boolean; | ||
164 | active: () => void; | 165 | active: () => void; |
165 | all: Recipe[]; | 166 | all: Recipe[]; |
166 | recipeIdForServices: () => void; | 167 | recipeIdForServices: () => void; |
@@ -188,7 +189,16 @@ interface RouterStore { | |||
188 | goBack: () => void; | 189 | goBack: () => void; |
189 | goForward: () => void; | 190 | goForward: () => void; |
190 | history: () => void; | 191 | history: () => void; |
191 | location: () => void; | 192 | location: { |
193 | pathname: string; | ||
194 | search: string; | ||
195 | action: string; | ||
196 | key: string; | ||
197 | state: any; | ||
198 | query: any; | ||
199 | hash?: string; | ||
200 | basename?: string; | ||
201 | }; | ||
192 | push(path: string): void; | 202 | push(path: string): void; |
193 | replace: () => void; | 203 | replace: () => void; |
194 | } | 204 | } |
@@ -199,6 +209,7 @@ export interface ServicesStore { | |||
199 | clearCacheRequest: () => void; | 209 | clearCacheRequest: () => void; |
200 | createServiceRequest: () => void; | 210 | createServiceRequest: () => void; |
201 | deleteServiceRequest: () => void; | 211 | deleteServiceRequest: () => void; |
212 | allServicesRequest: CachedRequest; | ||
202 | filterNeedle: () => void; | 213 | filterNeedle: () => void; |
203 | lastUsedServices: () => void; | 214 | lastUsedServices: () => void; |
204 | reorderServicesRequest: () => void; | 215 | reorderServicesRequest: () => void; |
@@ -285,11 +296,11 @@ interface UIStore { | |||
285 | actions: Actions; | 296 | actions: Actions; |
286 | api: Api; | 297 | api: Api; |
287 | isOsDarkThemeActive: () => void; | 298 | isOsDarkThemeActive: () => void; |
288 | showServicesUpdatedInfoBar: () => void; | ||
289 | stores: Stores; | 299 | stores: Stores; |
290 | _reactions: []; | 300 | _reactions: []; |
291 | _status: () => void; | 301 | _status: () => void; |
292 | actionStatus: () => void; | 302 | actionStatus: () => void; |
303 | showServicesUpdatedInfoBar: boolean; | ||
293 | isDarkThemeActive: () => void; | 304 | isDarkThemeActive: () => void; |
294 | isSplitModeActive: () => void; | 305 | isSplitModeActive: () => void; |
295 | splitColumnsNo: () => void; | 306 | splitColumnsNo: () => void; |
diff --git a/src/stores/RecipePreviewsStore.js b/src/stores/RecipePreviewsStore.ts index ef0bca430..500f69b40 100644 --- a/src/stores/RecipePreviewsStore.js +++ b/src/stores/RecipePreviewsStore.ts | |||
@@ -1,44 +1,58 @@ | |||
1 | import { action, computed, observable } from 'mobx'; | 1 | import { action, computed, observable } from 'mobx'; |
2 | import { Actions } from 'src/actions/lib/actions'; | ||
3 | import { ApiInterface } from 'src/api'; | ||
4 | import Recipe from 'src/models/Recipe'; | ||
5 | import { Stores } from 'src/stores.types'; | ||
2 | 6 | ||
3 | import Store from './lib/Store'; | ||
4 | import CachedRequest from './lib/CachedRequest'; | 7 | import CachedRequest from './lib/CachedRequest'; |
5 | import Request from './lib/Request'; | 8 | import Request from './lib/Request'; |
9 | import TypedStore from './lib/TypedStore'; | ||
6 | 10 | ||
7 | export default class RecipePreviewsStore extends Store { | 11 | export default class RecipePreviewsStore extends TypedStore { |
8 | @observable allRecipePreviewsRequest = new CachedRequest( | 12 | @observable allRecipePreviewsRequest = new CachedRequest( |
9 | this.api.recipePreviews, | 13 | this.api.recipePreviews, |
10 | 'all', | 14 | 'all', |
11 | ); | 15 | ); |
12 | 16 | ||
13 | @observable featuredRecipePreviewsRequest = new CachedRequest(this.api.recipePreviews, 'featured'); | 17 | @observable featuredRecipePreviewsRequest = new CachedRequest( |
18 | this.api.recipePreviews, | ||
19 | 'featured', | ||
20 | ); | ||
14 | 21 | ||
15 | @observable searchRecipePreviewsRequest = new Request(this.api.recipePreviews, 'search'); | 22 | @observable searchRecipePreviewsRequest = new Request( |
23 | this.api.recipePreviews, | ||
24 | 'search', | ||
25 | ); | ||
16 | 26 | ||
17 | constructor(...args) { | 27 | constructor(stores: Stores, api: ApiInterface, actions: Actions) { |
18 | super(...args); | 28 | super(stores, api, actions); |
19 | 29 | ||
20 | // Register action handlers | 30 | // Register action handlers |
21 | this.actions.recipePreview.search.listen(this._search.bind(this)); | 31 | this.actions.recipePreview.search.listen(this._search.bind(this)); |
22 | } | 32 | } |
23 | 33 | ||
24 | @computed get all() { | 34 | async setup(): Promise<void> { |
35 | // Not implemented | ||
36 | } | ||
37 | |||
38 | @computed get all(): Recipe[] { | ||
25 | return this.allRecipePreviewsRequest.execute().result || []; | 39 | return this.allRecipePreviewsRequest.execute().result || []; |
26 | } | 40 | } |
27 | 41 | ||
28 | @computed get featured() { | 42 | @computed get featured(): Recipe[] { |
29 | return this.featuredRecipePreviewsRequest.execute().result || []; | 43 | return this.featuredRecipePreviewsRequest.execute().result || []; |
30 | } | 44 | } |
31 | 45 | ||
32 | @computed get searchResults() { | 46 | @computed get searchResults(): Recipe[] { |
33 | return this.searchRecipePreviewsRequest.result || []; | 47 | return this.searchRecipePreviewsRequest.result || []; |
34 | } | 48 | } |
35 | 49 | ||
36 | @computed get dev() { | 50 | @computed get dev(): Recipe[] { |
37 | return this.stores.recipes.all.filter(r => r.local); | 51 | return this.stores.recipes.all.filter(r => r.local); |
38 | } | 52 | } |
39 | 53 | ||
40 | // Actions | 54 | // Actions |
41 | @action _search({ needle }) { | 55 | @action _search({ needle }): void { |
42 | if (needle !== '') { | 56 | if (needle !== '') { |
43 | this.searchRecipePreviewsRequest.execute(needle); | 57 | this.searchRecipePreviewsRequest.execute(needle); |
44 | } | 58 | } |
diff --git a/src/stores/RecipesStore.js b/src/stores/RecipesStore.ts index 3d3a506cc..af2aa7fb0 100644 --- a/src/stores/RecipesStore.js +++ b/src/stores/RecipesStore.ts | |||
@@ -2,23 +2,27 @@ import { action, computed, observable } from 'mobx'; | |||
2 | import { readJSONSync } from 'fs-extra'; | 2 | import { readJSONSync } from 'fs-extra'; |
3 | import semver from 'semver'; | 3 | import semver from 'semver'; |
4 | 4 | ||
5 | import Store from './lib/Store'; | 5 | import { Stores } from 'src/stores.types'; |
6 | import { ApiInterface } from 'src/api'; | ||
7 | import { Actions } from 'src/actions/lib/actions'; | ||
8 | import Recipe from 'src/models/Recipe'; | ||
6 | import CachedRequest from './lib/CachedRequest'; | 9 | import CachedRequest from './lib/CachedRequest'; |
7 | import Request from './lib/Request'; | 10 | import Request from './lib/Request'; |
8 | import { matchRoute } from '../helpers/routing-helpers'; | 11 | import { matchRoute } from '../helpers/routing-helpers'; |
9 | import { asarRecipesPath } from '../helpers/asar-helpers'; | 12 | import { asarRecipesPath } from '../helpers/asar-helpers'; |
13 | import TypedStore from './lib/TypedStore'; | ||
10 | 14 | ||
11 | const debug = require('../preload-safe-debug')('Ferdium:RecipeStore'); | 15 | const debug = require('../preload-safe-debug')('Ferdium:RecipeStore'); |
12 | 16 | ||
13 | export default class RecipesStore extends Store { | 17 | export default class RecipesStore extends TypedStore { |
14 | @observable allRecipesRequest = new CachedRequest(this.api.recipes, 'all'); | 18 | @observable allRecipesRequest = new CachedRequest(this.api.recipes, 'all'); |
15 | 19 | ||
16 | @observable installRecipeRequest = new Request(this.api.recipes, 'install'); | 20 | @observable installRecipeRequest = new Request(this.api.recipes, 'install'); |
17 | 21 | ||
18 | @observable getRecipeUpdatesRequest = new Request(this.api.recipes, 'update'); | 22 | @observable getRecipeUpdatesRequest = new Request(this.api.recipes, 'update'); |
19 | 23 | ||
20 | constructor(...args) { | 24 | constructor(stores: Stores, api: ApiInterface, actions: Actions) { |
21 | super(...args); | 25 | super(stores, api, actions); |
22 | 26 | ||
23 | // Register action handlers | 27 | // Register action handlers |
24 | this.actions.recipe.install.listen(this._install.bind(this)); | 28 | this.actions.recipe.install.listen(this._install.bind(this)); |
@@ -28,11 +32,12 @@ export default class RecipesStore extends Store { | |||
28 | this.registerReactions([this._checkIfRecipeIsInstalled.bind(this)]); | 32 | this.registerReactions([this._checkIfRecipeIsInstalled.bind(this)]); |
29 | } | 33 | } |
30 | 34 | ||
31 | setup() { | 35 | async setup(): Promise<void> { |
32 | return this.all; | 36 | // Initially load all recipes |
37 | this.all; | ||
33 | } | 38 | } |
34 | 39 | ||
35 | @computed get all() { | 40 | @computed get all(): Recipe[] { |
36 | return this.allRecipesRequest.execute().result || []; | 41 | return this.allRecipesRequest.execute().result || []; |
37 | } | 42 | } |
38 | 43 | ||
@@ -53,20 +58,20 @@ export default class RecipesStore extends Store { | |||
53 | return null; | 58 | return null; |
54 | } | 59 | } |
55 | 60 | ||
56 | @computed get recipeIdForServices() { | 61 | @computed get recipeIdForServices(): string[] { |
57 | return this.stores.services.all.map(s => s.recipe.id); | 62 | return this.stores.services.all.map(s => s.recipe.id); |
58 | } | 63 | } |
59 | 64 | ||
60 | one(id) { | 65 | one(id: string): Recipe | undefined { |
61 | return this.all.find(recipe => recipe.id === id); | 66 | return this.all.find(recipe => recipe.id === id); |
62 | } | 67 | } |
63 | 68 | ||
64 | isInstalled(id) { | 69 | isInstalled(id: string): boolean { |
65 | return !!this.one(id); | 70 | return !!this.one(id); |
66 | } | 71 | } |
67 | 72 | ||
68 | // Actions | 73 | // Actions |
69 | async _install({ recipeId }) { | 74 | async _install({ recipeId }): Promise<Recipe> { |
70 | const recipe = await this.installRecipeRequest.execute(recipeId)._promise; | 75 | const recipe = await this.installRecipeRequest.execute(recipeId)._promise; |
71 | await this.allRecipesRequest.invalidate({ immediately: true })._promise; | 76 | await this.allRecipesRequest.invalidate({ immediately: true })._promise; |
72 | 77 | ||
@@ -82,7 +87,9 @@ export default class RecipesStore extends Store { | |||
82 | 87 | ||
83 | for (const r of recipeIds) { | 88 | for (const r of recipeIds) { |
84 | const recipe = this.one(r); | 89 | const recipe = this.one(r); |
85 | recipes[r] = recipe.version; | 90 | if (recipe) { |
91 | recipes[r] = recipe.version; | ||
92 | } | ||
86 | } | 93 | } |
87 | 94 | ||
88 | if (Object.keys(recipes).length === 0) return; | 95 | if (Object.keys(recipes).length === 0) return; |
@@ -93,7 +100,7 @@ export default class RecipesStore extends Store { | |||
93 | // Check for local updates | 100 | // Check for local updates |
94 | const allJsonFile = asarRecipesPath('all.json'); | 101 | const allJsonFile = asarRecipesPath('all.json'); |
95 | const allJson = readJSONSync(allJsonFile); | 102 | const allJson = readJSONSync(allJsonFile); |
96 | const localUpdates = []; | 103 | const localUpdates: string[] = []; |
97 | 104 | ||
98 | for (const recipe of Object.keys(recipes)) { | 105 | for (const recipe of Object.keys(recipes)) { |
99 | const version = recipes[recipe]; | 106 | const version = recipes[recipe]; |
@@ -134,7 +141,7 @@ export default class RecipesStore extends Store { | |||
134 | } | 141 | } |
135 | } | 142 | } |
136 | 143 | ||
137 | async _checkIfRecipeIsInstalled() { | 144 | async _checkIfRecipeIsInstalled(): Promise<void> { |
138 | const { router } = this.stores; | 145 | const { router } = this.stores; |
139 | 146 | ||
140 | const match = | 147 | const match = |
diff --git a/src/stores/RequestStore.js b/src/stores/RequestStore.ts index 71a5360ac..03ad2c7db 100644 --- a/src/stores/RequestStore.js +++ b/src/stores/RequestStore.ts | |||
@@ -1,27 +1,32 @@ | |||
1 | import { ipcRenderer } from 'electron'; | 1 | import { ipcRenderer } from 'electron'; |
2 | import { action, computed, observable } from 'mobx'; | 2 | import { action, computed, observable } from 'mobx'; |
3 | import ms from 'ms'; | 3 | import ms from 'ms'; |
4 | |||
5 | import { Actions } from 'src/actions/lib/actions'; | ||
6 | import { ApiInterface } from 'src/api'; | ||
7 | import { Stores } from 'src/stores.types'; | ||
8 | import CachedRequest from './lib/CachedRequest'; | ||
4 | import { LOCAL_PORT } from '../config'; | 9 | import { LOCAL_PORT } from '../config'; |
5 | 10 | ||
6 | import Store from './lib/Store'; | 11 | import TypedStore from './lib/TypedStore'; |
7 | 12 | ||
8 | const debug = require('../preload-safe-debug')('Ferdium:RequestsStore'); | 13 | const debug = require('../preload-safe-debug')('Ferdium:RequestsStore'); |
9 | 14 | ||
10 | export default class RequestStore extends Store { | 15 | export default class RequestStore extends TypedStore { |
11 | @observable userInfoRequest; | 16 | @observable userInfoRequest: CachedRequest; |
12 | 17 | ||
13 | @observable servicesRequest; | 18 | @observable servicesRequest: CachedRequest; |
14 | 19 | ||
15 | @observable showRequiredRequestsError = false; | 20 | @observable showRequiredRequestsError = false; |
16 | 21 | ||
17 | @observable localServerPort = LOCAL_PORT; | 22 | @observable localServerPort = LOCAL_PORT; |
18 | 23 | ||
19 | retries = 0; | 24 | retries: number = 0; |
20 | 25 | ||
21 | retryDelay = ms('2s'); | 26 | retryDelay: number = ms('2s'); |
22 | 27 | ||
23 | constructor(...args) { | 28 | constructor(stores: Stores, api: ApiInterface, actions: Actions) { |
24 | super(...args); | 29 | super(stores, api, actions); |
25 | 30 | ||
26 | this.actions.requests.retryRequiredRequests.listen( | 31 | this.actions.requests.retryRequiredRequests.listen( |
27 | this._retryRequiredRequests.bind(this), | 32 | this._retryRequiredRequests.bind(this), |
@@ -30,32 +35,32 @@ export default class RequestStore extends Store { | |||
30 | this.registerReactions([this._autoRetry.bind(this)]); | 35 | this.registerReactions([this._autoRetry.bind(this)]); |
31 | } | 36 | } |
32 | 37 | ||
33 | setup() { | 38 | async setup(): Promise<void> { |
34 | this.userInfoRequest = this.stores.user.getUserInfoRequest; | 39 | this.userInfoRequest = this.stores.user.getUserInfoRequest; |
35 | this.servicesRequest = this.stores.services.allServicesRequest; | 40 | this.servicesRequest = this.stores.services.allServicesRequest; |
36 | 41 | ||
37 | ipcRenderer.on('localServerPort', (event, data) => { | 42 | ipcRenderer.on('localServerPort', (_, data) => { |
38 | if (data.port) { | 43 | if (data.port) { |
39 | this.localServerPort = data.port; | 44 | this.localServerPort = data.port; |
40 | } | 45 | } |
41 | }); | 46 | }); |
42 | } | 47 | } |
43 | 48 | ||
44 | @computed get areRequiredRequestsSuccessful() { | 49 | @computed get areRequiredRequestsSuccessful(): boolean { |
45 | return !this.userInfoRequest.isError && !this.servicesRequest.isError; | 50 | return !this.userInfoRequest.isError && !this.servicesRequest.isError; |
46 | } | 51 | } |
47 | 52 | ||
48 | @computed get areRequiredRequestsLoading() { | 53 | @computed get areRequiredRequestsLoading(): boolean { |
49 | return this.userInfoRequest.isExecuting || this.servicesRequest.isExecuting; | 54 | return this.userInfoRequest.isExecuting || this.servicesRequest.isExecuting; |
50 | } | 55 | } |
51 | 56 | ||
52 | @action _retryRequiredRequests() { | 57 | @action _retryRequiredRequests(): void { |
53 | this.userInfoRequest.reload(); | 58 | this.userInfoRequest.reload(); |
54 | this.servicesRequest.reload(); | 59 | this.servicesRequest.reload(); |
55 | } | 60 | } |
56 | 61 | ||
57 | // Reactions | 62 | // Reactions |
58 | _autoRetry() { | 63 | _autoRetry(): void { |
59 | const delay = (this.retries <= 10 ? this.retries : 10) * this.retryDelay; | 64 | const delay = (this.retries <= 10 ? this.retries : 10) * this.retryDelay; |
60 | if (!this.areRequiredRequestsSuccessful && this.stores.user.isLoggedIn) { | 65 | if (!this.areRequiredRequestsSuccessful && this.stores.user.isLoggedIn) { |
61 | setTimeout(() => { | 66 | setTimeout(() => { |