diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/I18n.tsx | 8 | ||||
-rw-r--r-- | src/actions/app.ts | 3 | ||||
-rw-r--r-- | src/actions/lib/actions.ts | 25 | ||||
-rw-r--r-- | src/actions/recipe.ts | 3 | ||||
-rw-r--r-- | src/actions/recipePreview.ts | 3 | ||||
-rw-r--r-- | src/actions/requests.ts | 4 | ||||
-rw-r--r-- | src/actions/service.ts | 3 | ||||
-rw-r--r-- | src/actions/settings.ts | 3 | ||||
-rw-r--r-- | src/actions/ui.ts | 3 | ||||
-rw-r--r-- | src/actions/user.ts | 3 | ||||
-rw-r--r-- | src/api/index.ts | 12 | ||||
-rw-r--r-- | src/app.js | 4 | ||||
-rw-r--r-- | src/config.ts | 8 | ||||
-rw-r--r-- | src/electron-util.ts | 2 | ||||
-rw-r--r-- | src/index.ts | 2 | ||||
-rw-r--r-- | src/models/User.ts | 4 | ||||
-rw-r--r-- | src/stores.types.ts | 44 | ||||
-rw-r--r-- | src/stores/AppStore.ts (renamed from src/stores/AppStore.js) | 40 | ||||
-rw-r--r-- | src/stores/index.ts | 13 | ||||
-rw-r--r-- | src/stores/lib/Reaction.ts | 14 | ||||
-rw-r--r-- | src/stores/lib/Store.js | 13 | ||||
-rw-r--r-- | src/stores/lib/TypedStore.ts | 46 |
22 files changed, 197 insertions, 63 deletions
diff --git a/src/I18n.tsx b/src/I18n.tsx index 0e63d1086..bf4b08cd1 100644 --- a/src/I18n.tsx +++ b/src/I18n.tsx | |||
@@ -10,7 +10,7 @@ const translations = generatedTranslations(); | |||
10 | 10 | ||
11 | type Props = { | 11 | type Props = { |
12 | stores: { | 12 | stores: { |
13 | app: typeof AppStore; | 13 | app: AppStore; |
14 | user: typeof UserStore; | 14 | user: typeof UserStore; |
15 | }; | 15 | }; |
16 | children: ReactNode; | 16 | children: ReactNode; |
@@ -21,14 +21,16 @@ class I18N extends Component<Props> { | |||
21 | window['ferdium'].menu.rebuild(); | 21 | window['ferdium'].menu.rebuild(); |
22 | } | 22 | } |
23 | 23 | ||
24 | render() { | 24 | render(): ReactNode { |
25 | const { stores, children } = this.props; | 25 | const { stores, children } = this.props; |
26 | const { locale } = stores.app; | 26 | const { locale } = stores.app; |
27 | return ( | 27 | return ( |
28 | <IntlProvider | 28 | <IntlProvider |
29 | {...{ locale, key: locale, messages: translations[locale] }} | 29 | {...{ locale, key: locale, messages: translations[locale] }} |
30 | ref={intlProvider => { | 30 | ref={intlProvider => { |
31 | window['ferdium'].intl = intlProvider ? intlProvider.state.intl : null; | 31 | window['ferdium'].intl = intlProvider |
32 | ? intlProvider.state.intl | ||
33 | : null; | ||
32 | }} | 34 | }} |
33 | > | 35 | > |
34 | {children} | 36 | {children} |
diff --git a/src/actions/app.ts b/src/actions/app.ts index e6f7f22ba..a798a8b0b 100644 --- a/src/actions/app.ts +++ b/src/actions/app.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import PropTypes from 'prop-types'; | 1 | import PropTypes from 'prop-types'; |
2 | import { ActionDefinitions } from './lib/actions'; | ||
2 | 3 | ||
3 | export default { | 4 | export default <ActionDefinitions>{ |
4 | setBadge: { | 5 | setBadge: { |
5 | unreadDirectMessageCount: PropTypes.number.isRequired, | 6 | unreadDirectMessageCount: PropTypes.number.isRequired, |
6 | unreadIndirectMessageCount: PropTypes.number, | 7 | unreadIndirectMessageCount: PropTypes.number, |
diff --git a/src/actions/lib/actions.ts b/src/actions/lib/actions.ts index 412a0d895..378cef574 100644 --- a/src/actions/lib/actions.ts +++ b/src/actions/lib/actions.ts | |||
@@ -1,4 +1,27 @@ | |||
1 | export const createActionsFromDefinitions = (actionDefinitions, validate) => { | 1 | import PropTypes from 'prop-types'; |
2 | |||
3 | export interface ActionDefinitions { | ||
4 | [key: string]: { | ||
5 | [key: string]: PropTypes.InferType<any>; | ||
6 | }; | ||
7 | } | ||
8 | |||
9 | export interface Actions { | ||
10 | [key: string]: { | ||
11 | [key: string]: { | ||
12 | (...args: any[]): void; | ||
13 | listeners: Array<Function>; | ||
14 | notify: (params: any) => void; | ||
15 | listen: (listener: (params: any) => void) => void; | ||
16 | off: (listener: (params: any) => void) => void; | ||
17 | }; | ||
18 | }; | ||
19 | } | ||
20 | |||
21 | export const createActionsFromDefinitions = ( | ||
22 | actionDefinitions: ActionDefinitions, | ||
23 | validate: any, | ||
24 | ) => { | ||
2 | const actions = {}; | 25 | const actions = {}; |
3 | // eslint-disable-next-line unicorn/no-array-for-each | 26 | // eslint-disable-next-line unicorn/no-array-for-each |
4 | Object.keys(actionDefinitions).forEach(actionName => { | 27 | Object.keys(actionDefinitions).forEach(actionName => { |
diff --git a/src/actions/recipe.ts b/src/actions/recipe.ts index 29b0a151f..0dd92737f 100644 --- a/src/actions/recipe.ts +++ b/src/actions/recipe.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import PropTypes from 'prop-types'; | 1 | import PropTypes from 'prop-types'; |
2 | import { ActionDefinitions } from './lib/actions'; | ||
2 | 3 | ||
3 | export default { | 4 | export default <ActionDefinitions>{ |
4 | install: { | 5 | install: { |
5 | recipeId: PropTypes.string.isRequired, | 6 | recipeId: PropTypes.string.isRequired, |
6 | update: PropTypes.bool, | 7 | update: PropTypes.bool, |
diff --git a/src/actions/recipePreview.ts b/src/actions/recipePreview.ts index 36de3d844..053b363e9 100644 --- a/src/actions/recipePreview.ts +++ b/src/actions/recipePreview.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import PropTypes from 'prop-types'; | 1 | import PropTypes from 'prop-types'; |
2 | import { ActionDefinitions } from './lib/actions'; | ||
2 | 3 | ||
3 | export default { | 4 | export default <ActionDefinitions>{ |
4 | search: { | 5 | search: { |
5 | needle: PropTypes.string.isRequired, | 6 | needle: PropTypes.string.isRequired, |
6 | }, | 7 | }, |
diff --git a/src/actions/requests.ts b/src/actions/requests.ts index 89296e7ec..0b4c905ee 100644 --- a/src/actions/requests.ts +++ b/src/actions/requests.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | export default { | 1 | import { ActionDefinitions } from './lib/actions'; |
2 | |||
3 | export default <ActionDefinitions>{ | ||
2 | retryRequiredRequests: {}, | 4 | retryRequiredRequests: {}, |
3 | }; | 5 | }; |
diff --git a/src/actions/service.ts b/src/actions/service.ts index aa02c860a..4b43fc2ca 100644 --- a/src/actions/service.ts +++ b/src/actions/service.ts | |||
@@ -1,7 +1,8 @@ | |||
1 | import PropTypes from 'prop-types'; | 1 | import PropTypes from 'prop-types'; |
2 | import ServiceModel from '../models/Service'; | 2 | import ServiceModel from '../models/Service'; |
3 | import { ActionDefinitions } from './lib/actions'; | ||
3 | 4 | ||
4 | export default { | 5 | export default <ActionDefinitions>{ |
5 | setActive: { | 6 | setActive: { |
6 | serviceId: PropTypes.string.isRequired, | 7 | serviceId: PropTypes.string.isRequired, |
7 | keepActiveRoute: PropTypes.bool, | 8 | keepActiveRoute: PropTypes.bool, |
diff --git a/src/actions/settings.ts b/src/actions/settings.ts index fd29b798b..4796f6a02 100644 --- a/src/actions/settings.ts +++ b/src/actions/settings.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import PropTypes from 'prop-types'; | 1 | import PropTypes from 'prop-types'; |
2 | import { ActionDefinitions } from './lib/actions'; | ||
2 | 3 | ||
3 | export default { | 4 | export default <ActionDefinitions>{ |
4 | update: { | 5 | update: { |
5 | type: PropTypes.string.isRequired, | 6 | type: PropTypes.string.isRequired, |
6 | data: PropTypes.object.isRequired, | 7 | data: PropTypes.object.isRequired, |
diff --git a/src/actions/ui.ts b/src/actions/ui.ts index b913b430b..7d2dbccfa 100644 --- a/src/actions/ui.ts +++ b/src/actions/ui.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import PropTypes from 'prop-types'; | 1 | import PropTypes from 'prop-types'; |
2 | import { ActionDefinitions } from './lib/actions'; | ||
2 | 3 | ||
3 | export default { | 4 | export default <ActionDefinitions>{ |
4 | openSettings: { | 5 | openSettings: { |
5 | path: PropTypes.string, | 6 | path: PropTypes.string, |
6 | }, | 7 | }, |
diff --git a/src/actions/user.ts b/src/actions/user.ts index 15a9216bd..c0ede619e 100644 --- a/src/actions/user.ts +++ b/src/actions/user.ts | |||
@@ -1,6 +1,7 @@ | |||
1 | import PropTypes from 'prop-types'; | 1 | import PropTypes from 'prop-types'; |
2 | import { ActionDefinitions } from './lib/actions'; | ||
2 | 3 | ||
3 | export default { | 4 | export default <ActionDefinitions>{ |
4 | login: { | 5 | login: { |
5 | email: PropTypes.string.isRequired, | 6 | email: PropTypes.string.isRequired, |
6 | password: PropTypes.string.isRequired, | 7 | password: PropTypes.string.isRequired, |
diff --git a/src/api/index.ts b/src/api/index.ts index 59fad194a..5ca6ba132 100644 --- a/src/api/index.ts +++ b/src/api/index.ts | |||
@@ -6,7 +6,17 @@ import UserApi from './UserApi'; | |||
6 | import LocalApi from './LocalApi'; | 6 | import LocalApi from './LocalApi'; |
7 | import FeaturesApi from './FeaturesApi'; | 7 | import FeaturesApi from './FeaturesApi'; |
8 | 8 | ||
9 | export default (server: any, local: any) => ({ | 9 | export interface ApiInterface { |
10 | app: AppApi; | ||
11 | services: ServicesApi; | ||
12 | recipePreviews: RecipePreviewsApi; | ||
13 | recipes: RecipesApi; | ||
14 | features: FeaturesApi; | ||
15 | user: UserApi; | ||
16 | local: LocalApi; | ||
17 | } | ||
18 | |||
19 | export default (server: any, local: any): ApiInterface => ({ | ||
10 | app: new AppApi(server), | 20 | app: new AppApi(server), |
11 | services: new ServicesApi(server, local), | 21 | services: new ServicesApi(server, local), |
12 | recipePreviews: new RecipePreviewsApi(server), | 22 | recipePreviews: new RecipePreviewsApi(server), |
diff --git a/src/app.js b/src/app.js index 54fba0c71..c92d044e6 100644 --- a/src/app.js +++ b/src/app.js | |||
@@ -53,8 +53,8 @@ window.addEventListener('load', () => { | |||
53 | // TODO: send this request to the recipe.js | 53 | // TODO: send this request to the recipe.js |
54 | window.addEventListener('mouseup', e => { | 54 | window.addEventListener('mouseup', e => { |
55 | if (e.button === 3 || e.button === 4) { | 55 | if (e.button === 3 || e.button === 4) { |
56 | e.preventDefault() | 56 | e.preventDefault(); |
57 | e.stopPropagation() | 57 | e.stopPropagation(); |
58 | } | 58 | } |
59 | }); | 59 | }); |
60 | 60 | ||
diff --git a/src/config.ts b/src/config.ts index 62b4f4e68..d29480dc6 100644 --- a/src/config.ts +++ b/src/config.ts | |||
@@ -86,7 +86,7 @@ export const SEARCH_ENGINE_NAMES = { | |||
86 | 86 | ||
87 | export const SEARCH_ENGINE_URLS = { | 87 | export const SEARCH_ENGINE_URLS = { |
88 | [SEARCH_ENGINE_STARTPAGE]: ({ searchTerm }) => | 88 | [SEARCH_ENGINE_STARTPAGE]: ({ searchTerm }) => |
89 | `https://www.startpage.com/sp/search?query=${searchTerm}`, | 89 | `https://www.startpage.com/sp/search?query=${searchTerm}`, |
90 | [SEARCH_ENGINE_GOOGLE]: ({ searchTerm }) => | 90 | [SEARCH_ENGINE_GOOGLE]: ({ searchTerm }) => |
91 | `https://www.google.com/search?q=${searchTerm}`, | 91 | `https://www.google.com/search?q=${searchTerm}`, |
92 | [SEARCH_ENGINE_DDG]: ({ searchTerm }) => | 92 | [SEARCH_ENGINE_DDG]: ({ searchTerm }) => |
@@ -105,7 +105,7 @@ const TODO_RTM_URL = 'https://www.rememberthemilk.com/'; | |||
105 | const TODO_ANYDO_URL = 'https://desktop.any.do/'; | 105 | const TODO_ANYDO_URL = 'https://desktop.any.do/'; |
106 | const TODO_GOOGLETASKS_URL = | 106 | const TODO_GOOGLETASKS_URL = |
107 | 'https://tasks.google.com/embed/?origin=https%3A%2F%2Fcalendar.google.com&fullWidth=1'; | 107 | 'https://tasks.google.com/embed/?origin=https%3A%2F%2Fcalendar.google.com&fullWidth=1'; |
108 | const TODO_GOOGLEKEEP_URL = 'https://keep.google.com/' | 108 | const TODO_GOOGLEKEEP_URL = 'https://keep.google.com/'; |
109 | 109 | ||
110 | export const TODO_SERVICE_RECIPE_IDS = { | 110 | export const TODO_SERVICE_RECIPE_IDS = { |
111 | [TODO_TODOIST_URL]: 'todoist', | 111 | [TODO_TODOIST_URL]: 'todoist', |
@@ -152,8 +152,8 @@ export const SIDEBAR_SERVICES_LOCATION_BOTTOMRIGHT = 2; | |||
152 | export const SIDEBAR_SERVICES_LOCATION = { | 152 | export const SIDEBAR_SERVICES_LOCATION = { |
153 | [SIDEBAR_SERVICES_LOCATION_TOPLEFT]: 'Top/Left', | 153 | [SIDEBAR_SERVICES_LOCATION_TOPLEFT]: 'Top/Left', |
154 | [SIDEBAR_SERVICES_LOCATION_CENTER]: 'Center', | 154 | [SIDEBAR_SERVICES_LOCATION_CENTER]: 'Center', |
155 | [SIDEBAR_SERVICES_LOCATION_BOTTOMRIGHT]: 'Bottom/Right' | 155 | [SIDEBAR_SERVICES_LOCATION_BOTTOMRIGHT]: 'Bottom/Right', |
156 | } | 156 | }; |
157 | 157 | ||
158 | export const ICON_SIZES = { | 158 | export const ICON_SIZES = { |
159 | 0: 'Very small icons', | 159 | 0: 'Very small icons', |
diff --git a/src/electron-util.ts b/src/electron-util.ts index eede55786..4576de9a6 100644 --- a/src/electron-util.ts +++ b/src/electron-util.ts | |||
@@ -15,7 +15,7 @@ export const initializeRemote = () => { | |||
15 | 15 | ||
16 | export const enableWebContents = (webContents: electron.WebContents) => { | 16 | export const enableWebContents = (webContents: electron.WebContents) => { |
17 | enable(webContents); | 17 | enable(webContents); |
18 | } | 18 | }; |
19 | 19 | ||
20 | export const remote = new Proxy( | 20 | export const remote = new Proxy( |
21 | {}, | 21 | {}, |
diff --git a/src/index.ts b/src/index.ts index df044ab7e..fa957bf10 100644 --- a/src/index.ts +++ b/src/index.ts | |||
@@ -69,7 +69,7 @@ function onDidLoad(fn: { | |||
69 | (window: BrowserWindow): void; | 69 | (window: BrowserWindow): void; |
70 | (window: BrowserWindow): void; | 70 | (window: BrowserWindow): void; |
71 | (arg0: BrowserWindow): void; | 71 | (arg0: BrowserWindow): void; |
72 | }) { | 72 | }): void { |
73 | if (onDidLoadFns) { | 73 | if (onDidLoadFns) { |
74 | onDidLoadFns.push(fn); | 74 | onDidLoadFns.push(fn); |
75 | } else if (mainWindow) { | 75 | } else if (mainWindow) { |
diff --git a/src/models/User.ts b/src/models/User.ts index 8c8f3e490..14481fbb6 100644 --- a/src/models/User.ts +++ b/src/models/User.ts | |||
@@ -8,7 +8,7 @@ interface IUser { | |||
8 | organization: string | null; | 8 | organization: string | null; |
9 | accountType: string | null; | 9 | accountType: string | null; |
10 | beta: boolean; | 10 | beta: boolean; |
11 | locale: boolean; | 11 | locale: string; |
12 | isSubscriptionOwner: boolean; | 12 | isSubscriptionOwner: boolean; |
13 | team: object; | 13 | team: object; |
14 | } | 14 | } |
@@ -37,7 +37,7 @@ export default class User { | |||
37 | 37 | ||
38 | @observable beta = false; | 38 | @observable beta = false; |
39 | 39 | ||
40 | @observable locale = false; | 40 | @observable locale: string | null = null; |
41 | 41 | ||
42 | @observable team = {}; | 42 | @observable team = {}; |
43 | 43 | ||
diff --git a/src/stores.types.ts b/src/stores.types.ts index d09916653..14ae32133 100644 --- a/src/stores.types.ts +++ b/src/stores.types.ts | |||
@@ -1,3 +1,9 @@ | |||
1 | import Workspace from './features/workspaces/models/Workspace'; | ||
2 | import Recipe from './models/Recipe'; | ||
3 | import Service from './models/Service'; | ||
4 | import User from './models/User'; | ||
5 | import { CachedRequest } from './stores/lib/CachedRequest'; | ||
6 | |||
1 | export interface FerdiumStores { | 7 | export interface FerdiumStores { |
2 | app: AppStore; | 8 | app: AppStore; |
3 | communityRecipes: CommunityRecipesStore; | 9 | communityRecipes: CommunityRecipesStore; |
@@ -15,7 +21,7 @@ export interface FerdiumStores { | |||
15 | workspaces: WorkspacesStore; | 21 | workspaces: WorkspacesStore; |
16 | } | 22 | } |
17 | 23 | ||
18 | interface Stores { | 24 | export interface Stores { |
19 | app: AppStore; | 25 | app: AppStore; |
20 | communityRecipes: CommunityRecipesStore; | 26 | communityRecipes: CommunityRecipesStore; |
21 | features: FeaturesStore; | 27 | features: FeaturesStore; |
@@ -62,9 +68,11 @@ interface AppStore { | |||
62 | api: Api; | 68 | api: Api; |
63 | authRequestFailed: () => void; | 69 | authRequestFailed: () => void; |
64 | autoLaunchOnStart: () => void; | 70 | autoLaunchOnStart: () => void; |
71 | automaticUpdates: boolean; | ||
65 | clearAppCacheRequest: () => void; | 72 | clearAppCacheRequest: () => void; |
66 | dictionaries: []; | 73 | dictionaries: []; |
67 | fetchDataInterval: 4; | 74 | fetchDataInterval: 4; |
75 | get(key: string): any; | ||
68 | getAppCacheSizeRequest: () => void; | 76 | getAppCacheSizeRequest: () => void; |
69 | healthCheckRequest: () => void; | 77 | healthCheckRequest: () => void; |
70 | isClearingAllCache: () => void; | 78 | isClearingAllCache: () => void; |
@@ -74,6 +82,8 @@ interface AppStore { | |||
74 | isSystemDarkModeEnabled: () => void; | 82 | isSystemDarkModeEnabled: () => void; |
75 | isSystemMuteOverridden: () => void; | 83 | isSystemMuteOverridden: () => void; |
76 | locale: () => void; | 84 | locale: () => void; |
85 | reloadAfterResume: boolean; | ||
86 | reloadAfterResumeTime: number; | ||
77 | stores: Stores; | 87 | stores: Stores; |
78 | timeOfflineStart: () => void; | 88 | timeOfflineStart: () => void; |
79 | timeSuspensionStart: () => void; | 89 | timeSuspensionStart: () => void; |
@@ -95,8 +105,8 @@ interface AppStore { | |||
95 | interface CommunityRecipesStore { | 105 | interface CommunityRecipesStore { |
96 | actions: Actions; | 106 | actions: Actions; |
97 | stores: Stores; | 107 | stores: Stores; |
98 | _actions: []; | 108 | _actions: any[]; |
99 | _reactions: []; | 109 | _reactions: any[]; |
100 | communityRecipes: () => void; | 110 | communityRecipes: () => void; |
101 | } | 111 | } |
102 | 112 | ||
@@ -105,7 +115,7 @@ interface FeaturesStore { | |||
105 | api: Api; | 115 | api: Api; |
106 | defaultFeaturesRequest: () => void; | 116 | defaultFeaturesRequest: () => void; |
107 | features: () => void; | 117 | features: () => void; |
108 | featuresRequest: () => void; | 118 | featuresRequest: CachedRequest; |
109 | stores: Stores; | 119 | stores: Stores; |
110 | _reactions: any[]; | 120 | _reactions: any[]; |
111 | _status: () => void; | 121 | _status: () => void; |
@@ -136,8 +146,8 @@ interface RecipePreviewsStore { | |||
136 | _reactions: []; | 146 | _reactions: []; |
137 | _status: () => void; | 147 | _status: () => void; |
138 | actionStatus: () => void; | 148 | actionStatus: () => void; |
139 | all: () => void; | 149 | all: Recipe[]; |
140 | dev: () => void; | 150 | dev: Recipe[]; |
141 | searchResults: () => void; | 151 | searchResults: () => void; |
142 | } | 152 | } |
143 | 153 | ||
@@ -152,7 +162,7 @@ interface RecipeStore { | |||
152 | _status: () => void; | 162 | _status: () => void; |
153 | actionStatus: () => void; | 163 | actionStatus: () => void; |
154 | active: () => void; | 164 | active: () => void; |
155 | all: () => void; | 165 | all: Recipe[]; |
156 | recipeIdForServices: () => void; | 166 | recipeIdForServices: () => void; |
157 | } | 167 | } |
158 | 168 | ||
@@ -179,7 +189,7 @@ interface RouterStore { | |||
179 | goForward: () => void; | 189 | goForward: () => void; |
180 | history: () => void; | 190 | history: () => void; |
181 | location: () => void; | 191 | location: () => void; |
182 | push: () => void; | 192 | push(path: string): void; |
183 | replace: () => void; | 193 | replace: () => void; |
184 | } | 194 | } |
185 | 195 | ||
@@ -200,7 +210,7 @@ export interface ServicesStore { | |||
200 | actionStatus: () => void; | 210 | actionStatus: () => void; |
201 | active: () => void; | 211 | active: () => void; |
202 | activeSettings: () => void; | 212 | activeSettings: () => void; |
203 | all: () => void; | 213 | all: Service[]; |
204 | allDisplayed: () => void; | 214 | allDisplayed: () => void; |
205 | allDisplayedUnordered: () => void; | 215 | allDisplayedUnordered: () => void; |
206 | enabled: () => void; | 216 | enabled: () => void; |
@@ -209,6 +219,11 @@ export interface ServicesStore { | |||
209 | isTodosServiceAdded: () => void; | 219 | isTodosServiceAdded: () => void; |
210 | } | 220 | } |
211 | 221 | ||
222 | // TODO: Create actual type based on the default config in config.ts | ||
223 | interface ISettings { | ||
224 | [key: string]: any; | ||
225 | } | ||
226 | |||
212 | interface SettingsStore { | 227 | interface SettingsStore { |
213 | actions: Actions; | 228 | actions: Actions; |
214 | api: Api; | 229 | api: Api; |
@@ -220,7 +235,7 @@ interface SettingsStore { | |||
220 | _reactions: []; | 235 | _reactions: []; |
221 | _status: () => void; | 236 | _status: () => void; |
222 | actionStatus: () => void; | 237 | actionStatus: () => void; |
223 | all: () => void; | 238 | all: ISettings; |
224 | app: AppStore; | 239 | app: AppStore; |
225 | migration: () => void; | 240 | migration: () => void; |
226 | proxy: () => void; | 241 | proxy: () => void; |
@@ -301,7 +316,7 @@ interface UserStore { | |||
301 | deleteAccountRequest: () => void; | 316 | deleteAccountRequest: () => void; |
302 | fetchUserInfoInterval: null; | 317 | fetchUserInfoInterval: null; |
303 | getLegacyServicesRequest: () => void; | 318 | getLegacyServicesRequest: () => void; |
304 | getUserInfoRequest: () => void; | 319 | getUserInfoRequest: CachedRequest; |
305 | hasCompletedSignup: () => void; | 320 | hasCompletedSignup: () => void; |
306 | id: () => void; | 321 | id: () => void; |
307 | inviteRequest: () => void; | 322 | inviteRequest: () => void; |
@@ -320,11 +335,11 @@ interface UserStore { | |||
320 | _requireAuthenticatedUser: () => void; | 335 | _requireAuthenticatedUser: () => void; |
321 | _status: () => void; | 336 | _status: () => void; |
322 | changeServerRoute: () => void; | 337 | changeServerRoute: () => void; |
323 | data: () => void; | 338 | data: User; |
324 | importRoute: () => void; | 339 | importRoute: () => void; |
325 | inviteRoute: () => void; | 340 | inviteRoute: () => void; |
326 | isLoggedIn: () => void; | 341 | isLoggedIn: boolean; |
327 | isTokenExpired: () => void; | 342 | isTokenExpired: () => boolean; |
328 | legacyServices: () => void; | 343 | legacyServices: () => void; |
329 | loginRoute: () => void; | 344 | loginRoute: () => void; |
330 | logoutRoute: () => void; | 345 | logoutRoute: () => void; |
@@ -348,6 +363,7 @@ export interface WorkspacesStore { | |||
348 | isWorkspaceDrawerOpen: () => void; | 363 | isWorkspaceDrawerOpen: () => void; |
349 | nextWorkspace: () => void; | 364 | nextWorkspace: () => void; |
350 | stores: Stores; | 365 | stores: Stores; |
366 | workspaces: Workspace[]; | ||
351 | workspaceBeingEdited: () => void; | 367 | workspaceBeingEdited: () => void; |
352 | _actions: any[]; | 368 | _actions: any[]; |
353 | _activateLastUsedWorkspaceReaction: () => void; | 369 | _activateLastUsedWorkspaceReaction: () => void; |
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.ts index a8e1ce247..5659460c6 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.ts | |||
@@ -14,12 +14,19 @@ import ms from 'ms'; | |||
14 | import { URL } from 'url'; | 14 | import { URL } from 'url'; |
15 | import { readJsonSync } from 'fs-extra'; | 15 | import { readJsonSync } from 'fs-extra'; |
16 | 16 | ||
17 | import Store from './lib/Store'; | 17 | import { Stores } from 'src/stores.types'; |
18 | import { ApiInterface } from 'src/api'; | ||
19 | import { Actions } from 'src/actions/lib/actions'; | ||
20 | import TypedStore from './lib/TypedStore'; | ||
18 | import Request from './lib/Request'; | 21 | import Request from './lib/Request'; |
19 | import { CHECK_INTERVAL, DEFAULT_APP_SETTINGS } from '../config'; | 22 | import { CHECK_INTERVAL, DEFAULT_APP_SETTINGS } from '../config'; |
20 | import { cleanseJSObject } from '../jsUtils'; | 23 | import { cleanseJSObject } from '../jsUtils'; |
21 | import { isMac, isWindows, electronVersion, osRelease } from '../environment'; | 24 | import { isMac, isWindows, electronVersion, osRelease } from '../environment'; |
22 | import { ferdiumVersion, userDataPath, ferdiumLocale } from '../environment-remote'; | 25 | import { |
26 | ferdiumVersion, | ||
27 | userDataPath, | ||
28 | ferdiumLocale, | ||
29 | } from '../environment-remote'; | ||
23 | import { generatedTranslations } from '../i18n/translations'; | 30 | import { generatedTranslations } from '../i18n/translations'; |
24 | import { getLocale } from '../helpers/i18n-helpers'; | 31 | import { getLocale } from '../helpers/i18n-helpers'; |
25 | 32 | ||
@@ -45,7 +52,7 @@ const CATALINA_NOTIFICATION_HACK_KEY = | |||
45 | 52 | ||
46 | const locales = generatedTranslations(); | 53 | const locales = generatedTranslations(); |
47 | 54 | ||
48 | export default class AppStore extends Store { | 55 | export default class AppStore extends TypedStore { |
49 | updateStatusTypes = { | 56 | updateStatusTypes = { |
50 | CHECKING: 'CHECKING', | 57 | CHECKING: 'CHECKING', |
51 | AVAILABLE: 'AVAILABLE', | 58 | AVAILABLE: 'AVAILABLE', |
@@ -89,10 +96,10 @@ export default class AppStore extends Store { | |||
89 | 96 | ||
90 | dictionaries = []; | 97 | dictionaries = []; |
91 | 98 | ||
92 | fetchDataInterval = null; | 99 | fetchDataInterval: null | NodeJS.Timer = null; |
93 | 100 | ||
94 | constructor(...args) { | 101 | constructor(stores: Stores, api: ApiInterface, actions: Actions) { |
95 | super(...args); | 102 | super(stores, api, actions); |
96 | 103 | ||
97 | // Register action handlers | 104 | // Register action handlers |
98 | this.actions.app.notify.listen(this._notify.bind(this)); | 105 | this.actions.app.notify.listen(this._notify.bind(this)); |
@@ -118,7 +125,7 @@ export default class AppStore extends Store { | |||
118 | ]); | 125 | ]); |
119 | } | 126 | } |
120 | 127 | ||
121 | async setup() { | 128 | async setup(): Promise<void> { |
122 | this._appStartsCounter(); | 129 | this._appStartsCounter(); |
123 | // Focus the active service | 130 | // Focus the active service |
124 | window.addEventListener('focus', this.actions.service.focusActiveService); | 131 | window.addEventListener('focus', this.actions.service.focusActiveService); |
@@ -162,7 +169,7 @@ export default class AppStore extends Store { | |||
162 | setInterval(() => this._checkForUpdates(), CHECK_INTERVAL); | 169 | setInterval(() => this._checkForUpdates(), CHECK_INTERVAL); |
163 | // Check for an update in 30s (need a delay to prevent Squirrel Installer lock file issues) | 170 | // Check for an update in 30s (need a delay to prevent Squirrel Installer lock file issues) |
164 | setTimeout(() => this._checkForUpdates(), ms('30s')); | 171 | setTimeout(() => this._checkForUpdates(), ms('30s')); |
165 | ipcRenderer.on('autoUpdate', (event, data) => { | 172 | ipcRenderer.on('autoUpdate', (_, data) => { |
166 | if (this.updateStatus !== this.updateStatusTypes.FAILED) { | 173 | if (this.updateStatus !== this.updateStatusTypes.FAILED) { |
167 | if (data.available) { | 174 | if (data.available) { |
168 | this.updateStatus = this.updateStatusTypes.AVAILABLE; | 175 | this.updateStatus = this.updateStatusTypes.AVAILABLE; |
@@ -185,7 +192,10 @@ export default class AppStore extends Store { | |||
185 | if (data.error) { | 192 | if (data.error) { |
186 | if (data.error.message && data.error.message.startsWith('404')) { | 193 | if (data.error.message && data.error.message.startsWith('404')) { |
187 | this.updateStatus = this.updateStatusTypes.NOT_AVAILABLE; | 194 | this.updateStatus = this.updateStatusTypes.NOT_AVAILABLE; |
188 | console.warn('Updater warning: there seems to be unpublished pre-release(s) available on GitHub', data.error); | 195 | console.warn( |
196 | 'Updater warning: there seems to be unpublished pre-release(s) available on GitHub', | ||
197 | data.error, | ||
198 | ); | ||
189 | } else { | 199 | } else { |
190 | console.error('Updater error:', data.error); | 200 | console.error('Updater error:', data.error); |
191 | this.updateStatus = this.updateStatusTypes.FAILED; | 201 | this.updateStatus = this.updateStatusTypes.FAILED; |
@@ -195,7 +205,7 @@ export default class AppStore extends Store { | |||
195 | }); | 205 | }); |
196 | 206 | ||
197 | // Handle deep linking (ferdium://) | 207 | // Handle deep linking (ferdium://) |
198 | ipcRenderer.on('navigateFromDeepLink', (event, data) => { | 208 | ipcRenderer.on('navigateFromDeepLink', (_, data) => { |
199 | debug('Navigate from deep link', data); | 209 | debug('Navigate from deep link', data); |
200 | let { url } = data; | 210 | let { url } = data; |
201 | if (!url) return; | 211 | if (!url) return; |
@@ -217,7 +227,7 @@ export default class AppStore extends Store { | |||
217 | 227 | ||
218 | this.isSystemDarkModeEnabled = nativeTheme.shouldUseDarkColors; | 228 | this.isSystemDarkModeEnabled = nativeTheme.shouldUseDarkColors; |
219 | 229 | ||
220 | ipcRenderer.on('isWindowFocused', (event, isFocused) => { | 230 | ipcRenderer.on('isWindowFocused', (_, isFocused) => { |
221 | debug('Setting is focused to', isFocused); | 231 | debug('Setting is focused to', isFocused); |
222 | this.isFocused = isFocused; | 232 | this.isFocused = isFocused; |
223 | }); | 233 | }); |
@@ -391,7 +401,11 @@ export default class AppStore extends Store { | |||
391 | } | 401 | } |
392 | 402 | ||
393 | @action _checkForUpdates() { | 403 | @action _checkForUpdates() { |
394 | if (this.isOnline && this.stores.settings.app.automaticUpdates && (isMac || isWindows || process.env.APPIMAGE)) { | 404 | if ( |
405 | this.isOnline && | ||
406 | this.stores.settings.app.automaticUpdates && | ||
407 | (isMac || isWindows || process.env.APPIMAGE) | ||
408 | ) { | ||
395 | debug('_checkForUpdates: sending event to autoUpdate:check'); | 409 | debug('_checkForUpdates: sending event to autoUpdate:check'); |
396 | this.updateStatus = this.updateStatusTypes.CHECKING; | 410 | this.updateStatus = this.updateStatusTypes.CHECKING; |
397 | ipcRenderer.send('autoUpdate', { | 411 | ipcRenderer.send('autoUpdate', { |
@@ -526,7 +540,7 @@ export default class AppStore extends Store { | |||
526 | } | 540 | } |
527 | 541 | ||
528 | _handleLogout() { | 542 | _handleLogout() { |
529 | if (!this.stores.user.isLoggedIn) { | 543 | if (!this.stores.user.isLoggedIn && this.fetchDataInterval !== null) { |
530 | clearInterval(this.fetchDataInterval); | 544 | clearInterval(this.fetchDataInterval); |
531 | } | 545 | } |
532 | } | 546 | } |
diff --git a/src/stores/index.ts b/src/stores/index.ts index 6ad898d85..a5b1a7452 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts | |||
@@ -1,3 +1,7 @@ | |||
1 | import { Stores } from 'src/stores.types'; | ||
2 | import { RouterStore } from 'mobx-react-router'; | ||
3 | import { ApiInterface } from 'src/api'; | ||
4 | import { Actions } from 'src/actions/lib/actions'; | ||
1 | import AppStore from './AppStore'; | 5 | import AppStore from './AppStore'; |
2 | import UserStore from './UserStore'; | 6 | import UserStore from './UserStore'; |
3 | import FeaturesStore from './FeaturesStore'; | 7 | import FeaturesStore from './FeaturesStore'; |
@@ -12,8 +16,12 @@ import { workspaceStore } from '../features/workspaces'; | |||
12 | import { communityRecipesStore } from '../features/communityRecipes'; | 16 | import { communityRecipesStore } from '../features/communityRecipes'; |
13 | import { todosStore } from '../features/todos'; | 17 | import { todosStore } from '../features/todos'; |
14 | 18 | ||
15 | export default (api, actions, router) => { | 19 | export default ( |
16 | const stores = {}; | 20 | api: ApiInterface, |
21 | actions: Actions, | ||
22 | router: RouterStore, | ||
23 | ): Stores => { | ||
24 | const stores: Stores | any = {}; | ||
17 | Object.assign(stores, { | 25 | Object.assign(stores, { |
18 | router, | 26 | router, |
19 | app: new AppStore(stores, api, actions), | 27 | app: new AppStore(stores, api, actions), |
@@ -37,5 +45,6 @@ export default (api, actions, router) => { | |||
37 | stores[name].initialize(); | 45 | stores[name].initialize(); |
38 | } | 46 | } |
39 | } | 47 | } |
48 | |||
40 | return stores; | 49 | return stores; |
41 | }; | 50 | }; |
diff --git a/src/stores/lib/Reaction.ts b/src/stores/lib/Reaction.ts index 0ca24a6fa..3966c8073 100644 --- a/src/stores/lib/Reaction.ts +++ b/src/stores/lib/Reaction.ts | |||
@@ -1,24 +1,24 @@ | |||
1 | import { autorun } from 'mobx'; | 1 | import { autorun, IReactionDisposer, IReactionPublic } from 'mobx'; |
2 | 2 | ||
3 | export default class Reaction { | 3 | export default class Reaction { |
4 | reaction; | 4 | public reaction: (r: IReactionPublic) => any; |
5 | 5 | ||
6 | isRunning = false; | 6 | private isRunning: boolean = false; |
7 | 7 | ||
8 | dispose; | 8 | public dispose?: IReactionDisposer; |
9 | 9 | ||
10 | constructor(reaction) { | 10 | constructor(reaction: any) { |
11 | this.reaction = reaction; | 11 | this.reaction = reaction; |
12 | } | 12 | } |
13 | 13 | ||
14 | start() { | 14 | start(): void { |
15 | if (!this.isRunning) { | 15 | if (!this.isRunning) { |
16 | this.dispose = autorun(this.reaction); | 16 | this.dispose = autorun(this.reaction); |
17 | this.isRunning = true; | 17 | this.isRunning = true; |
18 | } | 18 | } |
19 | } | 19 | } |
20 | 20 | ||
21 | stop() { | 21 | stop(): void { |
22 | if (this.isRunning) { | 22 | if (this.isRunning) { |
23 | this.dispose?.(); | 23 | this.dispose?.(); |
24 | this.isRunning = false; | 24 | this.isRunning = false; |
diff --git a/src/stores/lib/Store.js b/src/stores/lib/Store.js index a867c3a46..739a47729 100644 --- a/src/stores/lib/Store.js +++ b/src/stores/lib/Store.js | |||
@@ -2,12 +2,16 @@ import { computed, observable } from 'mobx'; | |||
2 | import Reaction from './Reaction'; | 2 | import Reaction from './Reaction'; |
3 | 3 | ||
4 | export default class Store { | 4 | export default class Store { |
5 | stores = {}; | 5 | /** @type Stores */ |
6 | stores; | ||
6 | 7 | ||
7 | api = {}; | 8 | /** @type ApiInterface */ |
9 | api; | ||
8 | 10 | ||
9 | actions = {}; | 11 | /** @type Actions */ |
12 | actions; | ||
10 | 13 | ||
14 | /** @type Reaction[] */ | ||
11 | _reactions = []; | 15 | _reactions = []; |
12 | 16 | ||
13 | // status implementation | 17 | // status implementation |
@@ -28,8 +32,9 @@ export default class Store { | |||
28 | } | 32 | } |
29 | 33 | ||
30 | registerReactions(reactions) { | 34 | registerReactions(reactions) { |
31 | for (const reaction of reactions) | 35 | for (const reaction of reactions) { |
32 | this._reactions.push(new Reaction(reaction)); | 36 | this._reactions.push(new Reaction(reaction)); |
37 | } | ||
33 | } | 38 | } |
34 | 39 | ||
35 | setup() {} | 40 | setup() {} |
diff --git a/src/stores/lib/TypedStore.ts b/src/stores/lib/TypedStore.ts new file mode 100644 index 000000000..5d8bf3bbd --- /dev/null +++ b/src/stores/lib/TypedStore.ts | |||
@@ -0,0 +1,46 @@ | |||
1 | import { computed, IReactionPublic, observable } from 'mobx'; | ||
2 | import { Actions } from 'src/actions/lib/actions'; | ||
3 | import { ApiInterface } from 'src/api'; | ||
4 | import { Stores } from 'src/stores.types'; | ||
5 | import Reaction from './Reaction'; | ||
6 | |||
7 | export default abstract class TypedStore { | ||
8 | _reactions: Reaction[] = []; | ||
9 | |||
10 | @observable _status: any = null; | ||
11 | |||
12 | @computed get actionStatus() { | ||
13 | return this._status || []; | ||
14 | } | ||
15 | |||
16 | set actionStatus(status) { | ||
17 | this._status = status; | ||
18 | } | ||
19 | |||
20 | constructor( | ||
21 | public stores: Stores, | ||
22 | public api: ApiInterface, | ||
23 | public actions: Actions, | ||
24 | ) {} | ||
25 | |||
26 | registerReactions(reactions: { (r: IReactionPublic): void }[]): void { | ||
27 | for (const reaction of reactions) { | ||
28 | this._reactions.push(new Reaction(reaction)); | ||
29 | } | ||
30 | } | ||
31 | |||
32 | public abstract setup(): void; | ||
33 | |||
34 | initialize(): void { | ||
35 | this.setup(); | ||
36 | for (const reaction of this._reactions) reaction.start(); | ||
37 | } | ||
38 | |||
39 | teardown(): void { | ||
40 | for (const reaction of this._reactions) reaction.stop(); | ||
41 | } | ||
42 | |||
43 | resetStatus(): void { | ||
44 | this._status = null; | ||
45 | } | ||
46 | } | ||