diff options
28 files changed, 149 insertions, 166 deletions
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index f91aeb23a..2111eb80b 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js | |||
@@ -1,6 +1,6 @@ | |||
1 | import path from 'path'; | 1 | import { join } from 'path'; |
2 | import tar from 'tar'; | 2 | import tar from 'tar'; |
3 | import fs from 'fs-extra'; | 3 | import { readdirSync, statSync, writeFileSync, copySync, ensureDirSync, pathExistsSync, readJsonSync, removeSync } from 'fs-extra'; |
4 | import { app, require as remoteRequire } from '@electron/remote'; | 4 | import { app, require as remoteRequire } from '@electron/remote'; |
5 | 5 | ||
6 | import ServiceModel from '../../models/Service'; | 6 | import ServiceModel from '../../models/Service'; |
@@ -13,7 +13,7 @@ import OrderModel from '../../models/Order'; | |||
13 | import { sleep } from '../../helpers/async-helpers'; | 13 | import { sleep } from '../../helpers/async-helpers'; |
14 | 14 | ||
15 | import { SERVER_NOT_LOADED } from '../../config'; | 15 | import { SERVER_NOT_LOADED } from '../../config'; |
16 | import { osArch, osPlatform, RECIPES_PATH } from '../../environment'; | 16 | import { osArch, osPlatform, asarRecipesPath, userDataRecipesPath, userDataPath } from '../../environment'; |
17 | import apiBase from '../apiBase'; | 17 | import apiBase from '../apiBase'; |
18 | import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; | 18 | import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; |
19 | 19 | ||
@@ -311,11 +311,10 @@ export default class ServerApi { | |||
311 | // Recipes | 311 | // Recipes |
312 | async getInstalledRecipes() { | 312 | async getInstalledRecipes() { |
313 | const recipesDirectory = getRecipeDirectory(); | 313 | const recipesDirectory = getRecipeDirectory(); |
314 | const paths = fs | 314 | const paths = readdirSync(recipesDirectory) |
315 | .readdirSync(recipesDirectory) | ||
316 | .filter( | 315 | .filter( |
317 | file => | 316 | file => |
318 | fs.statSync(path.join(recipesDirectory, file)).isDirectory() && | 317 | statSync(join(recipesDirectory, file)).isDirectory() && |
319 | file !== 'temp' && | 318 | file !== 'temp' && |
320 | file !== 'dev', | 319 | file !== 'dev', |
321 | ); | 320 | ); |
@@ -381,17 +380,17 @@ export default class ServerApi { | |||
381 | 380 | ||
382 | async getRecipePackage(recipeId) { | 381 | async getRecipePackage(recipeId) { |
383 | try { | 382 | try { |
384 | const recipesDirectory = path.join(app.getPath('userData'), 'recipes'); | 383 | const recipesDirectory = userDataRecipesPath(); |
385 | const recipeTempDirectory = path.join(recipesDirectory, 'temp', recipeId); | 384 | const recipeTempDirectory = join(recipesDirectory, 'temp', recipeId); |
386 | const tempArchivePath = path.join(recipeTempDirectory, 'recipe.tar.gz'); | 385 | const tempArchivePath = join(recipeTempDirectory, 'recipe.tar.gz'); |
387 | 386 | ||
388 | const internalRecipeFile = path.join(RECIPES_PATH, `${recipeId}.tar.gz`); | 387 | const internalRecipeFile = asarRecipesPath(`${recipeId}.tar.gz`); |
389 | 388 | ||
390 | fs.ensureDirSync(recipeTempDirectory); | 389 | ensureDirSync(recipeTempDirectory); |
391 | 390 | ||
392 | let archivePath; | 391 | let archivePath; |
393 | 392 | ||
394 | if (fs.existsSync(internalRecipeFile)) { | 393 | if (pathExistsSync(internalRecipeFile)) { |
395 | debug('[ServerApi::getRecipePackage] Using internal recipe file'); | 394 | debug('[ServerApi::getRecipePackage] Using internal recipe file'); |
396 | archivePath = internalRecipeFile; | 395 | archivePath = internalRecipeFile; |
397 | } else { | 396 | } else { |
@@ -403,7 +402,7 @@ export default class ServerApi { | |||
403 | const res = await fetch(packageUrl); | 402 | const res = await fetch(packageUrl); |
404 | debug('Recipe downloaded', recipeId); | 403 | debug('Recipe downloaded', recipeId); |
405 | const buffer = await res.buffer(); | 404 | const buffer = await res.buffer(); |
406 | fs.writeFileSync(archivePath, buffer); | 405 | writeFileSync(archivePath, buffer); |
407 | } | 406 | } |
408 | debug(archivePath); | 407 | debug(archivePath); |
409 | 408 | ||
@@ -420,13 +419,11 @@ export default class ServerApi { | |||
420 | 419 | ||
421 | await sleep(10); | 420 | await sleep(10); |
422 | 421 | ||
423 | const { id } = fs.readJsonSync( | 422 | const { id } = readJsonSync(join(recipeTempDirectory, 'package.json')); |
424 | path.join(recipeTempDirectory, 'package.json'), | 423 | const recipeDirectory = join(recipesDirectory, id); |
425 | ); | 424 | copySync(recipeTempDirectory, recipeDirectory); |
426 | const recipeDirectory = path.join(recipesDirectory, id); | 425 | removeSync(recipeTempDirectory); |
427 | fs.copySync(recipeTempDirectory, recipeDirectory); | 426 | removeSync(join(recipesDirectory, recipeId, 'recipe.tar.gz')); |
428 | fs.remove(recipeTempDirectory); | ||
429 | fs.remove(path.join(recipesDirectory, recipeId, 'recipe.tar.gz')); | ||
430 | 427 | ||
431 | return id; | 428 | return id; |
432 | } catch (err) { | 429 | } catch (err) { |
@@ -475,14 +472,10 @@ export default class ServerApi { | |||
475 | } | 472 | } |
476 | 473 | ||
477 | async getLegacyServices() { | 474 | async getLegacyServices() { |
478 | const file = path.join( | 475 | const file = userDataPath('settings', 'services.json'); |
479 | app.getPath('userData'), | ||
480 | 'settings', | ||
481 | 'services.json', | ||
482 | ); | ||
483 | 476 | ||
484 | try { | 477 | try { |
485 | const config = fs.readJsonSync(file); | 478 | const config = readJsonSync(file); |
486 | 479 | ||
487 | if (Object.prototype.hasOwnProperty.call(config, 'services')) { | 480 | if (Object.prototype.hasOwnProperty.call(config, 'services')) { |
488 | const services = await Promise.all( | 481 | const services = await Promise.all( |
@@ -614,11 +607,10 @@ export default class ServerApi { | |||
614 | _getDevRecipes() { | 607 | _getDevRecipes() { |
615 | const recipesDirectory = getDevRecipeDirectory(); | 608 | const recipesDirectory = getDevRecipeDirectory(); |
616 | try { | 609 | try { |
617 | const paths = fs | 610 | const paths = readdirSync(recipesDirectory) |
618 | .readdirSync(recipesDirectory) | ||
619 | .filter( | 611 | .filter( |
620 | file => | 612 | file => |
621 | fs.statSync(path.join(recipesDirectory, file)).isDirectory() && | 613 | statSync(join(recipesDirectory, file)).isDirectory() && |
622 | file !== 'temp', | 614 | file !== 'temp', |
623 | ); | 615 | ); |
624 | 616 | ||
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index 4edbde5e2..3b499a5db 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js | |||
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; | |||
3 | import { observer } from 'mobx-react'; | 3 | import { observer } from 'mobx-react'; |
4 | import { observable, reaction } from 'mobx'; | 4 | import { observable, reaction } from 'mobx'; |
5 | import ElectronWebView from 'react-electron-web-view'; | 5 | import ElectronWebView from 'react-electron-web-view'; |
6 | import path from 'path'; | 6 | import { join } from 'path'; |
7 | 7 | ||
8 | import ServiceModel from '../../../models/Service'; | 8 | import ServiceModel from '../../../models/Service'; |
9 | 9 | ||
@@ -59,7 +59,7 @@ class ServiceWebview extends Component { | |||
59 | isSpellcheckerEnabled, | 59 | isSpellcheckerEnabled, |
60 | } = this.props; | 60 | } = this.props; |
61 | 61 | ||
62 | const preloadScript = path.join(__dirname, '../../../', 'webview', 'recipe.js'); | 62 | const preloadScript = join(__dirname, '..', '..', '..', 'webview', 'recipe.js'); |
63 | 63 | ||
64 | return ( | 64 | return ( |
65 | <ElectronWebView | 65 | <ElectronWebView |
diff --git a/src/components/services/tabs/TabBarSortableList.js b/src/components/services/tabs/TabBarSortableList.js index f12d90602..117d799d7 100644 --- a/src/components/services/tabs/TabBarSortableList.js +++ b/src/components/services/tabs/TabBarSortableList.js | |||
@@ -64,15 +64,6 @@ class TabBarSortableList extends Component { | |||
64 | showMessageBadgesEvenWhenMuted={showMessageBadgesEvenWhenMuted} | 64 | showMessageBadgesEvenWhenMuted={showMessageBadgesEvenWhenMuted} |
65 | /> | 65 | /> |
66 | ))} | 66 | ))} |
67 | {/* <li> | ||
68 | <button | ||
69 | className="sidebar__add-service" | ||
70 | onClick={() => openSettings({ path: 'recipes' })} | ||
71 | data-tip={`${intl.formatMessage(messages.addNewService)} (${ctrlKey}+N)`} | ||
72 | > | ||
73 | <span className="mdi mdi-plus" /> | ||
74 | </button> | ||
75 | </li> */} | ||
76 | </ul> | 67 | </ul> |
77 | ); | 68 | ); |
78 | } | 69 | } |
diff --git a/src/containers/settings/RecipesScreen.js b/src/containers/settings/RecipesScreen.js index 93503fb0e..ff3c688fa 100644 --- a/src/containers/settings/RecipesScreen.js +++ b/src/containers/settings/RecipesScreen.js | |||
@@ -1,11 +1,9 @@ | |||
1 | import { shell } from 'electron'; | 1 | import { shell } from 'electron'; |
2 | import { app } from '@electron/remote'; | 2 | import { ensureDirSync, readJsonSync } from 'fs-extra'; |
3 | import fs from 'fs-extra'; | ||
4 | import React, { Component } from 'react'; | 3 | import React, { Component } from 'react'; |
5 | import PropTypes from 'prop-types'; | 4 | import PropTypes from 'prop-types'; |
6 | import { autorun } from 'mobx'; | 5 | import { autorun } from 'mobx'; |
7 | import { inject, observer } from 'mobx-react'; | 6 | import { inject, observer } from 'mobx-react'; |
8 | import path from 'path'; | ||
9 | 7 | ||
10 | import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; | 8 | import RecipePreviewsStore from '../../stores/RecipePreviewsStore'; |
11 | import RecipeStore from '../../stores/RecipesStore'; | 9 | import RecipeStore from '../../stores/RecipesStore'; |
@@ -15,7 +13,7 @@ import UserStore from '../../stores/UserStore'; | |||
15 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; | 13 | import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; |
16 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 14 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
17 | import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config'; | 15 | import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config'; |
18 | import { RECIPES_PATH } from '../../environment'; | 16 | import { asarRecipesPath, userDataRecipesPath } from '../../environment'; |
19 | import { communityRecipesStore } from '../../features/communityRecipes'; | 17 | import { communityRecipesStore } from '../../features/communityRecipes'; |
20 | import RecipePreview from '../../models/RecipePreview'; | 18 | import RecipePreview from '../../models/RecipePreview'; |
21 | import AppStore from '../../stores/AppStore'; | 19 | import AppStore from '../../stores/AppStore'; |
@@ -45,7 +43,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
45 | constructor(props) { | 43 | constructor(props) { |
46 | super(props); | 44 | super(props); |
47 | 45 | ||
48 | this.customRecipes = fs.readJsonSync(path.join(RECIPES_PATH, 'all.json')); | 46 | this.customRecipes = readJsonSync(asarRecipesPath('all.json')); |
49 | } | 47 | } |
50 | 48 | ||
51 | componentDidMount() { | 49 | componentDidMount() { |
@@ -140,7 +138,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
140 | || recipes.installRecipeRequest.isExecuting | 138 | || recipes.installRecipeRequest.isExecuting |
141 | || recipePreviews.searchRecipePreviewsRequest.isExecuting; | 139 | || recipePreviews.searchRecipePreviewsRequest.isExecuting; |
142 | 140 | ||
143 | const recipeDirectory = path.join(app.getPath('userData'), 'recipes', 'dev'); | 141 | const recipeDirectory = userDataRecipesPath('dev'); |
144 | 142 | ||
145 | return ( | 143 | return ( |
146 | <ErrorBoundary> | 144 | <ErrorBoundary> |
@@ -157,7 +155,7 @@ export default @inject('stores', 'actions') @observer class RecipesScreen extend | |||
157 | recipeFilter={filter} | 155 | recipeFilter={filter} |
158 | recipeDirectory={recipeDirectory} | 156 | recipeDirectory={recipeDirectory} |
159 | openRecipeDirectory={async () => { | 157 | openRecipeDirectory={async () => { |
160 | await fs.ensureDir(recipeDirectory); | 158 | ensureDirSync(recipeDirectory); |
161 | shell.openExternal(`file://${recipeDirectory}`); | 159 | shell.openExternal(`file://${recipeDirectory}`); |
162 | }} | 160 | }} |
163 | openDevDocs={() => { | 161 | openDevDocs={() => { |
diff --git a/src/electron/Settings.js b/src/electron/Settings.js index 2f3f8261a..4dd9f8245 100644 --- a/src/electron/Settings.js +++ b/src/electron/Settings.js | |||
@@ -1,8 +1,6 @@ | |||
1 | import { observable, toJS } from 'mobx'; | 1 | import { observable, toJS } from 'mobx'; |
2 | import { pathExistsSync, outputJsonSync, readJsonSync } from 'fs-extra'; | 2 | import { pathExistsSync, outputJsonSync, readJsonSync } from 'fs-extra'; |
3 | import path from 'path'; | 3 | import { userDataPath } from '../environment'; |
4 | |||
5 | import { SETTINGS_PATH } from '../environment'; | ||
6 | 4 | ||
7 | const debug = require('debug')('Ferdi:Settings'); | 5 | const debug = require('debug')('Ferdi:Settings'); |
8 | 6 | ||
@@ -58,6 +56,6 @@ export default class Settings { | |||
58 | } | 56 | } |
59 | 57 | ||
60 | get settingsFile() { | 58 | get settingsFile() { |
61 | return path.join(SETTINGS_PATH, `${this.type === 'app' ? 'settings' : this.type}.json`); | 59 | return userDataPath('config', `${this.type === 'app' ? 'settings' : this.type}.json`); |
62 | } | 60 | } |
63 | } | 61 | } |
diff --git a/src/electron/ipc-api/appIndicator.js b/src/electron/ipc-api/appIndicator.js index 0691e5170..c6c261d0f 100644 --- a/src/electron/ipc-api/appIndicator.js +++ b/src/electron/ipc-api/appIndicator.js | |||
@@ -1,5 +1,5 @@ | |||
1 | import { app, ipcMain } from 'electron'; | 1 | import { app, ipcMain } from 'electron'; |
2 | import path from 'path'; | 2 | import { join } from 'path'; |
3 | import { autorun } from 'mobx'; | 3 | import { autorun } from 'mobx'; |
4 | import { isMac, isWindows, isLinux } from '../../environment'; | 4 | import { isMac, isWindows, isLinux } from '../../environment'; |
5 | 5 | ||
@@ -9,7 +9,7 @@ const FILE_EXTENSION = isWindows ? 'ico' : 'png'; | |||
9 | let isTrayIconEnabled; | 9 | let isTrayIconEnabled; |
10 | 10 | ||
11 | function getAsset(type, asset) { | 11 | function getAsset(type, asset) { |
12 | return path.join( | 12 | return join( |
13 | __dirname, '..', '..', 'assets', 'images', type, process.platform, `${asset}.${FILE_EXTENSION}`, | 13 | __dirname, '..', '..', 'assets', 'images', type, process.platform, `${asset}.${FILE_EXTENSION}`, |
14 | ); | 14 | ); |
15 | } | 15 | } |
diff --git a/src/electron/ipc-api/download.js b/src/electron/ipc-api/download.js index 7f8718924..ba261ba1e 100644 --- a/src/electron/ipc-api/download.js +++ b/src/electron/ipc-api/download.js | |||
@@ -1,7 +1,7 @@ | |||
1 | import { ipcMain, dialog, BrowserWindow } from 'electron'; | 1 | import { ipcMain, dialog, BrowserWindow } from 'electron'; |
2 | import { download } from 'electron-dl'; | 2 | import { download } from 'electron-dl'; |
3 | import mime from 'mime-types'; | 3 | import mime from 'mime-types'; |
4 | import fs from 'fs-extra'; | 4 | import { writeFileSync } from 'fs-extra'; |
5 | 5 | ||
6 | const debug = require('debug')('Ferdi:ipcApi:download'); | 6 | const debug = require('debug')('Ferdi:ipcApi:download'); |
7 | 7 | ||
@@ -37,7 +37,7 @@ export default (params) => { | |||
37 | if (saveDialog.canceled) return; | 37 | if (saveDialog.canceled) return; |
38 | 38 | ||
39 | const binaryImage = decodeBase64Image(content); | 39 | const binaryImage = decodeBase64Image(content); |
40 | fs.writeFileSync(saveDialog.filePath, binaryImage, 'binary'); | 40 | writeFileSync(saveDialog.filePath, binaryImage, 'binary'); |
41 | 41 | ||
42 | debug('File blob saved to', saveDialog.filePath); | 42 | debug('File blob saved to', saveDialog.filePath); |
43 | } catch (err) { | 43 | } catch (err) { |
diff --git a/src/electron/ipc-api/localServer.js b/src/electron/ipc-api/localServer.js index 493253e17..1ed4b7167 100644 --- a/src/electron/ipc-api/localServer.js +++ b/src/electron/ipc-api/localServer.js | |||
@@ -1,6 +1,7 @@ | |||
1 | import { ipcMain, app } from 'electron'; | 1 | import { ipcMain } from 'electron'; |
2 | import net from 'net'; | 2 | import net from 'net'; |
3 | import { LOCAL_HOSTNAME } from '../../config'; | 3 | import { LOCAL_HOSTNAME } from '../../config'; |
4 | import { userDataPath } from '../../environment'; | ||
4 | import startServer from '../../internal-server/start'; | 5 | import startServer from '../../internal-server/start'; |
5 | 6 | ||
6 | const DEFAULT_PORT = 45569; | 7 | const DEFAULT_PORT = 45569; |
@@ -37,7 +38,7 @@ export default (params) => { | |||
37 | } | 38 | } |
38 | console.log('Starting local server on port', port); | 39 | console.log('Starting local server on port', port); |
39 | 40 | ||
40 | startServer(app.getPath('userData'), port); | 41 | startServer(userDataPath(), port); |
41 | 42 | ||
42 | params.mainWindow.webContents.send('localServerPort', { | 43 | params.mainWindow.webContents.send('localServerPort', { |
43 | port, | 44 | port, |
diff --git a/src/electron/macOSPermissions.js b/src/electron/macOSPermissions.js index c114f4843..887af2903 100644 --- a/src/electron/macOSPermissions.js +++ b/src/electron/macOSPermissions.js | |||
@@ -1,45 +1,43 @@ | |||
1 | import { app, systemPreferences, dialog } from 'electron'; | 1 | import { systemPreferences, dialog } from 'electron'; |
2 | import fs from 'fs'; | 2 | import { pathExistsSync, mkdirSync, writeFileSync } from 'fs-extra'; |
3 | import macosVersion from 'macos-version'; | 3 | import macosVersion from 'macos-version'; |
4 | import path from 'path'; | 4 | import { dirname } from 'path'; |
5 | import { askForScreenCaptureAccess } from 'node-mac-permissions'; | 5 | import { askForScreenCaptureAccess } from 'node-mac-permissions'; |
6 | import { userDataPath } from '../environment'; | ||
6 | 7 | ||
7 | const debug = require('debug')('Ferdi:macOSPermissions'); | 8 | const debug = require('debug')('Ferdi:macOSPermissions'); |
8 | 9 | ||
9 | const permissionExists = macosVersion.isGreaterThanOrEqualTo('10.15'); | 10 | const isExplicitScreenCapturePermissionReqd = macosVersion.isGreaterThanOrEqualTo('10.15'); |
10 | const filePath = path.join( | 11 | debug(`Should check explicitly for screen-capture permissions: ${isExplicitScreenCapturePermissionReqd}`); |
11 | app.getPath('userData'), | ||
12 | '.has-app-requested-screen-capture-permissions', | ||
13 | ); | ||
14 | 12 | ||
15 | function hasPromptedForPermission() { | 13 | const filePath = userDataPath('.has-app-requested-screen-capture-permissions'); |
16 | if (!permissionExists) { | ||
17 | return false; | ||
18 | } | ||
19 | 14 | ||
20 | if (filePath && fs.existsSync(filePath)) { | 15 | function hasPromptedForScreenCapturePermission() { |
21 | return true; | 16 | if (!isExplicitScreenCapturePermissionReqd) { |
17 | return false; | ||
22 | } | 18 | } |
23 | 19 | ||
24 | return false; | 20 | debug('Checking if status file exists'); |
21 | return filePath && pathExistsSync(filePath); | ||
25 | } | 22 | } |
26 | 23 | ||
27 | function hasScreenCapturePermission() { | 24 | function hasScreenCapturePermissionAlreadyBeenGranted() { |
28 | if (!permissionExists) { | 25 | if (!isExplicitScreenCapturePermissionReqd) { |
29 | return true; | 26 | return true; |
30 | } | 27 | } |
31 | 28 | ||
32 | const screenCaptureStatus = systemPreferences.getMediaAccessStatus('screen'); | 29 | const screenCaptureStatus = systemPreferences.getMediaAccessStatus('screen'); |
30 | debug(`screen-capture permissions status: ${screenCaptureStatus}`); | ||
33 | return screenCaptureStatus === 'granted'; | 31 | return screenCaptureStatus === 'granted'; |
34 | } | 32 | } |
35 | 33 | ||
36 | function createStatusFile() { | 34 | function createStatusFile() { |
37 | try { | 35 | try { |
38 | fs.writeFileSync(filePath, ''); | 36 | writeFileSync(filePath, ''); |
39 | } catch (error) { | 37 | } catch (error) { |
40 | if (error.code === 'ENOENT') { | 38 | if (error.code === 'ENOENT') { |
41 | fs.mkdirSync(path.dirname(filePath)); | 39 | mkdirSync(dirname(filePath)); |
42 | fs.writeFileSync(filePath, ''); | 40 | writeFileSync(filePath, ''); |
43 | } | 41 | } |
44 | 42 | ||
45 | throw error; | 43 | throw error; |
@@ -51,7 +49,13 @@ export const askFormacOSPermissions = async mainWindow => { | |||
51 | systemPreferences.askForMediaAccess('camera'); | 49 | systemPreferences.askForMediaAccess('camera'); |
52 | systemPreferences.askForMediaAccess('microphone'); | 50 | systemPreferences.askForMediaAccess('microphone'); |
53 | 51 | ||
54 | if (!hasPromptedForPermission() && !hasScreenCapturePermission()) { | 52 | if (hasScreenCapturePermissionAlreadyBeenGranted()) { |
53 | debug('Already obtained screen-capture permissions - writing status file'); | ||
54 | createStatusFile(); | ||
55 | return; | ||
56 | } | ||
57 | |||
58 | if (!hasPromptedForScreenCapturePermission()) { | ||
55 | debug('Checking screen capture permissions'); | 59 | debug('Checking screen capture permissions'); |
56 | 60 | ||
57 | const { response } = await dialog.showMessageBox(mainWindow, { | 61 | const { response } = await dialog.showMessageBox(mainWindow, { |
diff --git a/src/electron/webview-ime-focus.js b/src/electron/webview-ime-focus.js index b9421eb06..e187ee0b4 100644 --- a/src/electron/webview-ime-focus.js +++ b/src/electron/webview-ime-focus.js | |||
@@ -1,5 +1,5 @@ | |||
1 | const { webContents } = require('@electron/remote'); | 1 | import { webContents } from '@electron/remote'; |
2 | const { releaseDocumentFocus } = require('./webview-ime-focus-helpers'); | 2 | import { releaseDocumentFocus } from './webview-ime-focus-helpers'; |
3 | 3 | ||
4 | function giveWebviewDocumentFocus(element) { | 4 | function giveWebviewDocumentFocus(element) { |
5 | releaseDocumentFocus(); | 5 | releaseDocumentFocus(); |
diff --git a/src/environment.js b/src/environment.js index 7b560acb6..7267f93a6 100644 --- a/src/environment.js +++ b/src/environment.js | |||
@@ -1,10 +1,11 @@ | |||
1 | import os from 'os'; | 1 | import os from 'os'; |
2 | import path from 'path'; | 2 | import { join } from 'path'; |
3 | 3 | ||
4 | import { is, api as electronApi } from 'electron-util'; | 4 | import { is, api as electronApi } from 'electron-util'; |
5 | 5 | ||
6 | import { DEFAULT_ACCENT_COLOR } from '@meetfranz/theme'; | 6 | import { DEFAULT_ACCENT_COLOR } from '@meetfranz/theme'; |
7 | 7 | ||
8 | import osName from 'os-name'; | ||
8 | import { | 9 | import { |
9 | LIVE_FERDI_API, | 10 | LIVE_FERDI_API, |
10 | DEV_FRANZ_API, | 11 | DEV_FRANZ_API, |
@@ -25,8 +26,6 @@ import { | |||
25 | import { asarPath } from './helpers/asar-helpers'; | 26 | import { asarPath } from './helpers/asar-helpers'; |
26 | import * as buildInfo from './buildInfo.json'; // eslint-disable-line import/no-unresolved | 27 | import * as buildInfo from './buildInfo.json'; // eslint-disable-line import/no-unresolved |
27 | 28 | ||
28 | const osName = require('os-name'); | ||
29 | |||
30 | export const { app } = electronApi; | 29 | export const { app } = electronApi; |
31 | export const ferdiVersion = app.getVersion(); | 30 | export const ferdiVersion = app.getVersion(); |
32 | export const electronVersion = process.versions.electron; | 31 | export const electronVersion = process.versions.electron; |
@@ -36,24 +35,32 @@ export const nodeVersion = process.versions.node; | |||
36 | // Set app directory before loading user modules | 35 | // Set app directory before loading user modules |
37 | if (process.env.FERDI_APPDATA_DIR != null) { | 36 | if (process.env.FERDI_APPDATA_DIR != null) { |
38 | app.setPath('appData', process.env.FERDI_APPDATA_DIR); | 37 | app.setPath('appData', process.env.FERDI_APPDATA_DIR); |
39 | app.setPath('userData', path.join(app.getPath('appData'))); | 38 | app.setPath('userData', join(app.getPath('appData'))); |
40 | } else if (process.env.PORTABLE_EXECUTABLE_DIR != null) { | 39 | } else if (process.env.PORTABLE_EXECUTABLE_DIR != null) { |
41 | app.setPath('appData', process.env.PORTABLE_EXECUTABLE_DIR, `${app.name}AppData`); | 40 | app.setPath('appData', process.env.PORTABLE_EXECUTABLE_DIR, `${app.name}AppData`); |
42 | app.setPath('userData', path.join(app.getPath('appData'), `${app.name}AppData`)); | 41 | app.setPath('userData', join(app.getPath('appData'), `${app.name}AppData`)); |
43 | } else if (is.windows) { | 42 | } else if (is.windows) { |
44 | app.setPath('appData', process.env.APPDATA); | 43 | app.setPath('appData', process.env.APPDATA); |
45 | app.setPath('userData', path.join(app.getPath('appData'), app.name)); | 44 | app.setPath('userData', join(app.getPath('appData'), app.name)); |
46 | } | 45 | } |
47 | 46 | ||
48 | export const isDevMode = is.development; | 47 | export const isDevMode = is.development; |
49 | if (isDevMode) { | 48 | if (isDevMode) { |
50 | app.setPath('userData', path.join(app.getPath('appData'), `${app.name}Dev`)); | 49 | app.setPath('userData', join(app.getPath('appData'), `${app.name}Dev`)); |
51 | } | 50 | } |
52 | 51 | ||
53 | export const SETTINGS_PATH = path.join(app.getPath('userData'), 'config'); | 52 | export function userDataPath(...segments) { |
53 | return join(app.getPath('userData'), ...([segments].flat())); | ||
54 | } | ||
55 | |||
56 | export function userDataRecipesPath(...segments) { | ||
57 | return userDataPath('recipes', ...([segments].flat())); | ||
58 | } | ||
54 | 59 | ||
55 | // Replacing app.asar is not beautiful but unfortunately necessary | 60 | // Replacing app.asar is not beautiful but unfortunately necessary |
56 | export const RECIPES_PATH = asarPath(path.join(__dirname, 'recipes')); | 61 | export function asarRecipesPath(...segments) { |
62 | return join(asarPath(join(__dirname, 'recipes')), ...([segments].flat())); | ||
63 | } | ||
57 | 64 | ||
58 | export const useLiveAPI = process.env.USE_LIVE_API; | 65 | export const useLiveAPI = process.env.USE_LIVE_API; |
59 | const useLocalAPI = process.env.USE_LOCAL_API; | 66 | const useLocalAPI = process.env.USE_LOCAL_API; |
diff --git a/src/helpers/recipe-helpers.js b/src/helpers/recipe-helpers.js index 7daa0aaab..7e4bfa85a 100644 --- a/src/helpers/recipe-helpers.js +++ b/src/helpers/recipe-helpers.js | |||
@@ -1,12 +1,12 @@ | |||
1 | import path from 'path'; | 1 | import { parse } from 'path'; |
2 | import { app } from '@electron/remote'; | 2 | import { userDataRecipesPath } from '../environment'; |
3 | 3 | ||
4 | export function getRecipeDirectory(id = '') { | 4 | export function getRecipeDirectory(id = '') { |
5 | return path.join(app.getPath('userData'), 'recipes', id); | 5 | return userDataRecipesPath(id); |
6 | } | 6 | } |
7 | 7 | ||
8 | export function getDevRecipeDirectory(id = '') { | 8 | export function getDevRecipeDirectory(id = '') { |
9 | return path.join(app.getPath('userData'), 'recipes', 'dev', id); | 9 | return userDataRecipesPath('dev', id); |
10 | } | 10 | } |
11 | 11 | ||
12 | export function loadRecipeConfig(recipeId) { | 12 | export function loadRecipeConfig(recipeId) { |
@@ -19,8 +19,7 @@ export function loadRecipeConfig(recipeId) { | |||
19 | let config = require(configPath); | 19 | let config = require(configPath); |
20 | 20 | ||
21 | const moduleConfigPath = require.resolve(configPath); | 21 | const moduleConfigPath = require.resolve(configPath); |
22 | const paths = path.parse(moduleConfigPath); | 22 | config.path = parse(moduleConfigPath).dir; |
23 | config.path = paths.dir; | ||
24 | 23 | ||
25 | return config; | 24 | return config; |
26 | } catch (e) { | 25 | } catch (e) { |
diff --git a/src/helpers/service-helpers.js b/src/helpers/service-helpers.js index 28d483182..745f40dd9 100644 --- a/src/helpers/service-helpers.js +++ b/src/helpers/service-helpers.js | |||
@@ -1,18 +1,16 @@ | |||
1 | import path from 'path'; | 1 | import { readdirSync, removeSync } from 'fs-extra'; |
2 | import { app } from '@electron/remote'; | 2 | import { userDataPath } from '../environment'; |
3 | import fs from 'fs-extra'; | ||
4 | 3 | ||
5 | export function getServicePartitionsDirectory() { | 4 | export function getServicePartitionsDirectory(...segments) { |
6 | return path.join(app.getPath('userData'), 'Partitions'); | 5 | return userDataPath('Partitions', ...([segments].flat())); |
7 | } | 6 | } |
8 | 7 | ||
9 | export function removeServicePartitionDirectory(id = '', addServicePrefix = false) { | 8 | export function removeServicePartitionDirectory(id = '', addServicePrefix = false) { |
10 | const servicePartition = path.join(getServicePartitionsDirectory(), `${addServicePrefix ? 'service-' : ''}${id}`); | 9 | const servicePartition = getServicePartitionsDirectory(`${addServicePrefix ? 'service-' : ''}${id}`); |
11 | 10 | return removeSync(servicePartition); | |
12 | return fs.remove(servicePartition); | ||
13 | } | 11 | } |
14 | 12 | ||
15 | export async function getServiceIdsFromPartitions() { | 13 | export async function getServiceIdsFromPartitions() { |
16 | const files = await fs.readdir(getServicePartitionsDirectory()); | 14 | const files = readdirSync(getServicePartitionsDirectory()); |
17 | return files.filter((n) => n !== '__chrome_extension'); | 15 | return files.filter((n) => n !== '__chrome_extension'); |
18 | } | 16 | } |
diff --git a/src/helpers/userAgent-helpers.js b/src/helpers/userAgent-helpers.js index 9c9c8f132..ede5e6dc4 100644 --- a/src/helpers/userAgent-helpers.js +++ b/src/helpers/userAgent-helpers.js | |||
@@ -1,11 +1,10 @@ | |||
1 | import os from 'os'; | 1 | import os from 'os'; |
2 | import macosVersion from 'macos-version'; | 2 | import macosVersion from 'macos-version'; |
3 | import { chrome } from 'useragent-generator'; | ||
3 | import { | 4 | import { |
4 | chromeVersion, isMac, isWindows, is64Bit, osArch, osRelease, | 5 | chromeVersion, isMac, isWindows, is64Bit, osArch, osRelease, |
5 | } from '../environment'; | 6 | } from '../environment'; |
6 | 7 | ||
7 | const uaGenerator = require('useragent-generator'); | ||
8 | |||
9 | function macOS() { | 8 | function macOS() { |
10 | const version = macosVersion(); | 9 | const version = macosVersion(); |
11 | let cpuName = os.cpus()[0].model.split(' ')[0]; | 10 | let cpuName = os.cpus()[0].model.split(' ')[0]; |
@@ -38,5 +37,5 @@ export default function userAgent() { | |||
38 | platformString = linux(); | 37 | platformString = linux(); |
39 | } | 38 | } |
40 | 39 | ||
41 | return uaGenerator.chrome({ os: platformString, version: chromeVersion }); | 40 | return chrome({ os: platformString, version: chromeVersion }); |
42 | } | 41 | } |
diff --git a/src/index.js b/src/index.js index 78ab9bef2..3264fdc63 100644 --- a/src/index.js +++ b/src/index.js | |||
@@ -2,8 +2,8 @@ | |||
2 | 2 | ||
3 | import { app, BrowserWindow, shell, ipcMain, session } from 'electron'; | 3 | import { app, BrowserWindow, shell, ipcMain, session } from 'electron'; |
4 | 4 | ||
5 | import fs from 'fs-extra'; | 5 | import { emptyDirSync, ensureFileSync } from 'fs-extra'; |
6 | import path from 'path'; | 6 | import { join } from 'path'; |
7 | import windowStateKeeper from 'electron-window-state'; | 7 | import windowStateKeeper from 'electron-window-state'; |
8 | import { enforceMacOSAppLocation } from 'electron-util'; | 8 | import { enforceMacOSAppLocation } from 'electron-util'; |
9 | import ms from 'ms'; | 9 | import ms from 'ms'; |
@@ -19,6 +19,8 @@ import { | |||
19 | isWindows, | 19 | isWindows, |
20 | isLinux, | 20 | isLinux, |
21 | aboutAppDetails, | 21 | aboutAppDetails, |
22 | userDataRecipesPath, | ||
23 | userDataPath, | ||
22 | } from './environment'; | 24 | } from './environment'; |
23 | 25 | ||
24 | import { mainIpcHandler as basicAuthHandler } from './features/basicAuth'; | 26 | import { mainIpcHandler as basicAuthHandler } from './features/basicAuth'; |
@@ -63,8 +65,8 @@ function onDidLoad(fn) { | |||
63 | } | 65 | } |
64 | 66 | ||
65 | // Ensure that the recipe directory exists | 67 | // Ensure that the recipe directory exists |
66 | fs.emptyDirSync(path.join(app.getPath('userData'), 'recipes', 'temp')); | 68 | emptyDirSync(userDataRecipesPath('temp')); |
67 | fs.ensureFileSync(path.join(app.getPath('userData'), 'window-state.json')); | 69 | ensureFileSync(userDataPath('window-state.json')); |
68 | 70 | ||
69 | // Set App ID for Windows | 71 | // Set App ID for Windows |
70 | if (isWindows) { | 72 | if (isWindows) { |
@@ -193,7 +195,7 @@ const createWindow = () => { | |||
193 | nodeIntegration: true, | 195 | nodeIntegration: true, |
194 | contextIsolation: false, | 196 | contextIsolation: false, |
195 | webviewTag: true, | 197 | webviewTag: true, |
196 | preload: path.join(__dirname, 'sentry.js'), | 198 | preload: join(__dirname, 'sentry.js'), |
197 | enableRemoteModule: true, | 199 | enableRemoteModule: true, |
198 | }, | 200 | }, |
199 | }); | 201 | }); |
@@ -401,7 +403,7 @@ app.on('ready', () => { | |||
401 | program: process.execPath, | 403 | program: process.execPath, |
402 | arguments: `${isDevMode ? `${__dirname} ` : ''}--reset-window`, | 404 | arguments: `${isDevMode ? `${__dirname} ` : ''}--reset-window`, |
403 | iconPath: asarPath( | 405 | iconPath: asarPath( |
404 | path.join( | 406 | join( |
405 | isDevMode ? `${__dirname}../src/` : __dirname, | 407 | isDevMode ? `${__dirname}../src/` : __dirname, |
406 | 'assets/images/taskbar/win32/display.ico', | 408 | 'assets/images/taskbar/win32/display.ico', |
407 | ), | 409 | ), |
diff --git a/src/internal-server/start.js b/src/internal-server/start.js index cb8ef56c8..5ccc1330e 100644 --- a/src/internal-server/start.js +++ b/src/internal-server/start.js | |||
@@ -18,9 +18,9 @@ | |||
18 | const fold = require('@adonisjs/fold'); | 18 | const fold = require('@adonisjs/fold'); |
19 | const { Ignitor } = require('@adonisjs/ignitor'); | 19 | const { Ignitor } = require('@adonisjs/ignitor'); |
20 | const fs = require('fs-extra'); | 20 | const fs = require('fs-extra'); |
21 | const os = require('os'); | ||
22 | const path = require('path'); | 21 | const path = require('path'); |
23 | const { LOCAL_HOSTNAME } = require('../config'); | 22 | const { LOCAL_HOSTNAME } = require('../config'); |
23 | const { isWindows } = require('../environment'); | ||
24 | 24 | ||
25 | process.env.ENV_PATH = path.join(__dirname, 'env.ini'); | 25 | process.env.ENV_PATH = path.join(__dirname, 'env.ini'); |
26 | 26 | ||
@@ -35,7 +35,7 @@ module.exports = async (userPath, port) => { | |||
35 | await fs.writeFile(dbPath, dbTemplate); | 35 | await fs.writeFile(dbPath, dbTemplate); |
36 | 36 | ||
37 | // Change permissions to ensure to file is not read-only | 37 | // Change permissions to ensure to file is not read-only |
38 | if (os.platform() === 'win32') { | 38 | if (isWindows) { |
39 | // eslint-disable-next-line no-bitwise | 39 | // eslint-disable-next-line no-bitwise |
40 | fs.chmodSync(dbPath, fs.statSync(dbPath).mode | 146); | 40 | fs.chmodSync(dbPath, fs.statSync(dbPath).mode | 146); |
41 | } | 41 | } |
diff --git a/src/lib/Tray.js b/src/lib/Tray.js index f37b4eb7b..f5970f7e7 100644 --- a/src/lib/Tray.js +++ b/src/lib/Tray.js | |||
@@ -1,7 +1,7 @@ | |||
1 | import { | 1 | import { |
2 | app, Menu, nativeImage, nativeTheme, systemPreferences, Tray, ipcMain, | 2 | app, Menu, nativeImage, nativeTheme, systemPreferences, Tray, ipcMain, |
3 | } from 'electron'; | 3 | } from 'electron'; |
4 | import path from 'path'; | 4 | import { join } from 'path'; |
5 | import macosVersion from 'macos-version'; | 5 | import macosVersion from 'macos-version'; |
6 | import { isMac, isWindows, isLinux } from '../environment'; | 6 | import { isMac, isWindows, isLinux } from '../environment'; |
7 | 7 | ||
@@ -174,7 +174,7 @@ export default class TrayIcon { | |||
174 | platform = `${platform}-dark`; | 174 | platform = `${platform}-dark`; |
175 | } | 175 | } |
176 | 176 | ||
177 | return nativeImage.createFromPath(path.join( | 177 | return nativeImage.createFromPath(join( |
178 | __dirname, '..', 'assets', 'images', type, platform, `${asset}.${FILE_EXTENSION}`, | 178 | __dirname, '..', 'assets', 'images', type, platform, `${asset}.${FILE_EXTENSION}`, |
179 | )); | 179 | )); |
180 | } | 180 | } |
diff --git a/src/models/Recipe.js b/src/models/Recipe.js index 106b4a56a..92ff0d67d 100644 --- a/src/models/Recipe.js +++ b/src/models/Recipe.js | |||
@@ -1,7 +1,7 @@ | |||
1 | import emailParser from 'address-rfc2822'; | 1 | import emailParser from 'address-rfc2822'; |
2 | import semver from 'semver'; | 2 | import semver from 'semver'; |
3 | import fs from 'fs-extra'; | 3 | import { pathExistsSync } from 'fs-extra'; |
4 | import path from 'path'; | 4 | import { join } from 'path'; |
5 | 5 | ||
6 | export default class Recipe { | 6 | export default class Recipe { |
7 | id = ''; | 7 | id = ''; |
@@ -98,6 +98,6 @@ export default class Recipe { | |||
98 | } | 98 | } |
99 | 99 | ||
100 | get hasDarkMode() { | 100 | get hasDarkMode() { |
101 | return fs.pathExistsSync(path.join(this.path, 'darkmode.css')); | 101 | return pathExistsSync(join(this.path, 'darkmode.css')); |
102 | } | 102 | } |
103 | } | 103 | } |
diff --git a/src/models/Service.js b/src/models/Service.js index 79181186a..fe56e5a76 100644 --- a/src/models/Service.js +++ b/src/models/Service.js | |||
@@ -2,7 +2,7 @@ import { autorun, computed, observable } from 'mobx'; | |||
2 | import { ipcRenderer } from 'electron'; | 2 | import { ipcRenderer } from 'electron'; |
3 | import { webContents } from '@electron/remote'; | 3 | import { webContents } from '@electron/remote'; |
4 | import normalizeUrl from 'normalize-url'; | 4 | import normalizeUrl from 'normalize-url'; |
5 | import path from 'path'; | 5 | import { join } from 'path'; |
6 | 6 | ||
7 | import { todosStore } from '../features/todos'; | 7 | import { todosStore } from '../features/todos'; |
8 | import { isValidExternalURL } from '../helpers/url-helpers'; | 8 | import { isValidExternalURL } from '../helpers/url-helpers'; |
@@ -230,7 +230,7 @@ export default class Service { | |||
230 | return this.iconUrl; | 230 | return this.iconUrl; |
231 | } | 231 | } |
232 | 232 | ||
233 | return path.join(this.recipe.path, 'icon.svg'); | 233 | return join(this.recipe.path, 'icon.svg'); |
234 | } | 234 | } |
235 | 235 | ||
236 | @computed get hasCustomIcon() { | 236 | @computed get hasCustomIcon() { |
diff --git a/src/scripts/add-crowdin-contributors.js b/src/scripts/add-crowdin-contributors.js index efe981b6e..ed29a0daf 100644 --- a/src/scripts/add-crowdin-contributors.js +++ b/src/scripts/add-crowdin-contributors.js | |||
@@ -58,7 +58,7 @@ const fs = require('fs-extra'); | |||
58 | const path = require('path'); | 58 | const path = require('path'); |
59 | const allContributors = require('all-contributors-cli'); | 59 | const allContributors = require('all-contributors-cli'); |
60 | 60 | ||
61 | const infoPath = path.join(__dirname, '../../.all-contributorsrc'); | 61 | const infoPath = path.join(__dirname, '..', '..', '.all-contributorsrc'); |
62 | 62 | ||
63 | (async () => { | 63 | (async () => { |
64 | const info = await fs.readJSON(infoPath); | 64 | const info = await fs.readJSON(infoPath); |
diff --git a/src/scripts/build-theme-info.js b/src/scripts/build-theme-info.js index cff33e3c4..4058be942 100644 --- a/src/scripts/build-theme-info.js +++ b/src/scripts/build-theme-info.js | |||
@@ -15,8 +15,8 @@ const accentColors = [ | |||
15 | '#5e50ee', | 15 | '#5e50ee', |
16 | ]; | 16 | ]; |
17 | 17 | ||
18 | const cssFile = path.join(__dirname, '../../', 'build', 'styles', 'main.css'); | 18 | const cssFile = path.join(__dirname, '..', '..', 'build', 'styles', 'main.css'); |
19 | const outputFile = path.join(__dirname, '../', 'assets', 'themeInfo.json'); | 19 | const outputFile = path.join(__dirname, '..', 'assets', 'themeInfo.json'); |
20 | 20 | ||
21 | // Parse and extract the rules from a CSS stylesheet file | 21 | // Parse and extract the rules from a CSS stylesheet file |
22 | async function getRulesFromCssFile(file) { | 22 | async function getRulesFromCssFile(file) { |
diff --git a/src/scripts/link-readme.js b/src/scripts/link-readme.js index 694b89700..1e47cddf8 100644 --- a/src/scripts/link-readme.js +++ b/src/scripts/link-readme.js | |||
@@ -11,7 +11,7 @@ const path = require('path'); | |||
11 | 11 | ||
12 | console.log('Linking issues and PRs in README.md'); | 12 | console.log('Linking issues and PRs in README.md'); |
13 | 13 | ||
14 | const readmepath = path.join(__dirname, '../../', 'README.md'); | 14 | const readmepath = path.join(__dirname, '..', '..', 'README.md'); |
15 | 15 | ||
16 | // Read README.md | 16 | // Read README.md |
17 | let readme = fs.readFileSync(readmepath, 'utf-8'); | 17 | let readme = fs.readFileSync(readmepath, 'utf-8'); |
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index 6b5ca7c9a..1d706f1ef 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -12,7 +12,6 @@ import moment from 'moment'; | |||
12 | import AutoLaunch from 'auto-launch'; | 12 | import AutoLaunch from 'auto-launch'; |
13 | import ms from 'ms'; | 13 | import ms from 'ms'; |
14 | import { URL } from 'url'; | 14 | import { URL } from 'url'; |
15 | import path from 'path'; | ||
16 | import { readJsonSync } from 'fs-extra'; | 15 | import { readJsonSync } from 'fs-extra'; |
17 | 16 | ||
18 | import Store from './lib/Store'; | 17 | import Store from './lib/Store'; |
@@ -24,6 +23,7 @@ import { | |||
24 | ferdiVersion, | 23 | ferdiVersion, |
25 | electronVersion, | 24 | electronVersion, |
26 | osRelease, | 25 | osRelease, |
26 | userDataPath, | ||
27 | } from '../environment'; | 27 | } from '../environment'; |
28 | import locales from '../i18n/translations'; | 28 | import locales from '../i18n/translations'; |
29 | import { onVisibilityChange } from '../helpers/visibility-helper'; | 29 | import { onVisibilityChange } from '../helpers/visibility-helper'; |
@@ -307,9 +307,7 @@ export default class AppStore extends Store { | |||
307 | id: workspace.id, | 307 | id: workspace.id, |
308 | services: workspace.services, | 308 | services: workspace.services, |
309 | })), | 309 | })), |
310 | windowSettings: readJsonSync( | 310 | windowSettings: readJsonSync(userDataPath('window-state.json')), |
311 | path.join(app.getPath('userData'), 'window-state.json'), | ||
312 | ), | ||
313 | settings, | 311 | settings, |
314 | features: this.stores.features.features, | 312 | features: this.stores.features.features, |
315 | user: this.stores.user.data.id, | 313 | user: this.stores.user.data.id, |
diff --git a/src/stores/RecipesStore.js b/src/stores/RecipesStore.js index c7c4c1deb..d2acebb75 100644 --- a/src/stores/RecipesStore.js +++ b/src/stores/RecipesStore.js | |||
@@ -1,13 +1,12 @@ | |||
1 | import { action, computed, observable } from 'mobx'; | 1 | import { action, computed, observable } from 'mobx'; |
2 | import fs from 'fs-extra'; | 2 | import { readJSONSync } from 'fs-extra'; |
3 | import path from 'path'; | ||
4 | import semver from 'semver'; | 3 | import semver from 'semver'; |
5 | 4 | ||
6 | import Store from './lib/Store'; | 5 | import Store from './lib/Store'; |
7 | import CachedRequest from './lib/CachedRequest'; | 6 | import CachedRequest from './lib/CachedRequest'; |
8 | import Request from './lib/Request'; | 7 | import Request from './lib/Request'; |
9 | import { matchRoute } from '../helpers/routing-helpers'; | 8 | import { matchRoute } from '../helpers/routing-helpers'; |
10 | import { RECIPES_PATH } from '../environment'; | 9 | import { asarRecipesPath } from '../environment'; |
11 | 10 | ||
12 | const debug = require('debug')('Ferdi:RecipeStore'); | 11 | const debug = require('debug')('Ferdi:RecipeStore'); |
13 | 12 | ||
@@ -90,8 +89,8 @@ export default class RecipesStore extends Store { | |||
90 | const remoteUpdates = await this.getRecipeUpdatesRequest.execute(recipes)._promise; | 89 | const remoteUpdates = await this.getRecipeUpdatesRequest.execute(recipes)._promise; |
91 | 90 | ||
92 | // Check for local updates | 91 | // Check for local updates |
93 | const allJsonFile = path.join(RECIPES_PATH, 'all.json'); | 92 | const allJsonFile = asarRecipesPath('all.json'); |
94 | const allJson = await fs.readJSON(allJsonFile); | 93 | const allJson = readJSONSync(allJsonFile); |
95 | const localUpdates = []; | 94 | const localUpdates = []; |
96 | 95 | ||
97 | Object.keys(recipes).forEach((recipe) => { | 96 | Object.keys(recipes).forEach((recipe) => { |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 829797930..499495d08 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -3,8 +3,8 @@ import { action, reaction, computed, observable } from 'mobx'; | |||
3 | import { debounce, remove } from 'lodash'; | 3 | import { debounce, remove } from 'lodash'; |
4 | import ms from 'ms'; | 4 | import ms from 'ms'; |
5 | import { app } from '@electron/remote'; | 5 | import { app } from '@electron/remote'; |
6 | import fs from 'fs-extra'; | 6 | import { ensureFileSync, pathExistsSync, writeFileSync } from 'fs-extra'; |
7 | import path from 'path'; | 7 | import { join } from 'path'; |
8 | 8 | ||
9 | import Store from './lib/Store'; | 9 | import Store from './lib/Store'; |
10 | import Request from './lib/Request'; | 10 | import Request from './lib/Request'; |
@@ -524,9 +524,9 @@ export default class ServicesStore extends Store { | |||
524 | const devDirectory = getDevRecipeDirectory(recipe); | 524 | const devDirectory = getDevRecipeDirectory(recipe); |
525 | let directory; | 525 | let directory; |
526 | 526 | ||
527 | if (await fs.pathExists(normalDirectory)) { | 527 | if (pathExistsSync(normalDirectory)) { |
528 | directory = normalDirectory; | 528 | directory = normalDirectory; |
529 | } else if (await fs.pathExists(devDirectory)) { | 529 | } else if (pathExistsSync(devDirectory)) { |
530 | directory = devDirectory; | 530 | directory = devDirectory; |
531 | } else { | 531 | } else { |
532 | // Recipe cannot be found on drive | 532 | // Recipe cannot be found on drive |
@@ -534,20 +534,19 @@ export default class ServicesStore extends Store { | |||
534 | } | 534 | } |
535 | 535 | ||
536 | // Create and open file | 536 | // Create and open file |
537 | const filePath = path.join(directory, file); | 537 | const filePath = join(directory, file); |
538 | if (file === 'user.js') { | 538 | if (file === 'user.js') { |
539 | if (!fs.existsSync(filePath)) { | 539 | if (!pathExistsSync(filePath)) { |
540 | await fs.writeFile( | 540 | writeFileSync( |
541 | filePath, | 541 | filePath, |
542 | `module.exports = (config, Ferdi) => { | 542 | `module.exports = (config, Ferdi) => { |
543 | // Write your scripts here | 543 | // Write your scripts here |
544 | console.log("Hello, World!", config); | 544 | console.log("Hello, World!", config); |
545 | } | 545 | }; |
546 | `, | 546 | `); |
547 | ); | ||
548 | } | 547 | } |
549 | } else { | 548 | } else { |
550 | await fs.ensureFile(filePath); | 549 | ensureFileSync(filePath); |
551 | } | 550 | } |
552 | shell.showItemInFolder(filePath); | 551 | shell.showItemInFolder(filePath); |
553 | } | 552 | } |
diff --git a/src/webview/darkmode.js b/src/webview/darkmode.js index ab629435c..7435d6404 100644 --- a/src/webview/darkmode.js +++ b/src/webview/darkmode.js | |||
@@ -1,7 +1,7 @@ | |||
1 | /* eslint no-bitwise: ["error", { "int32Hint": true }] */ | 1 | /* eslint no-bitwise: ["error", { "int32Hint": true }] */ |
2 | 2 | ||
3 | import path from 'path'; | 3 | import { join } from 'path'; |
4 | import fs from 'fs-extra'; | 4 | import { pathExistsSync, readFileSync } from 'fs-extra'; |
5 | 5 | ||
6 | const debug = require('debug')('Ferdi:DarkMode'); | 6 | const debug = require('debug')('Ferdi:DarkMode'); |
7 | 7 | ||
@@ -10,9 +10,9 @@ const chars = [...'abcdefghijklmnopqrstuvwxyz']; | |||
10 | const ID = [...Array(20)].map(() => chars[Math.random() * chars.length | 0]).join``; | 10 | const ID = [...Array(20)].map(() => chars[Math.random() * chars.length | 0]).join``; |
11 | 11 | ||
12 | export function injectDarkModeStyle(recipePath) { | 12 | export function injectDarkModeStyle(recipePath) { |
13 | const darkModeStyle = path.join(recipePath, 'darkmode.css'); | 13 | const darkModeStyle = join(recipePath, 'darkmode.css'); |
14 | if (fs.pathExistsSync(darkModeStyle)) { | 14 | if (pathExistsSync(darkModeStyle)) { |
15 | const data = fs.readFileSync(darkModeStyle); | 15 | const data = readFileSync(darkModeStyle); |
16 | const styles = document.createElement('style'); | 16 | const styles = document.createElement('style'); |
17 | styles.id = ID; | 17 | styles.id = ID; |
18 | styles.innerHTML = data.toString(); | 18 | styles.innerHTML = data.toString(); |
diff --git a/src/webview/lib/RecipeWebview.js b/src/webview/lib/RecipeWebview.js index 305e79882..96caa125e 100644 --- a/src/webview/lib/RecipeWebview.js +++ b/src/webview/lib/RecipeWebview.js | |||
@@ -1,5 +1,5 @@ | |||
1 | import { ipcRenderer } from 'electron'; | 1 | import { ipcRenderer } from 'electron'; |
2 | import { exists, pathExistsSync, readFile } from 'fs-extra'; | 2 | import { exists, pathExistsSync, readFileSync } from 'fs-extra'; |
3 | 3 | ||
4 | const debug = require('debug')('Ferdi:Plugin:RecipeWebview'); | 4 | const debug = require('debug')('Ferdi:Plugin:RecipeWebview'); |
5 | 5 | ||
@@ -55,9 +55,8 @@ class RecipeWebview { | |||
55 | injectCSS(...files) { | 55 | injectCSS(...files) { |
56 | files.forEach(async (file) => { | 56 | files.forEach(async (file) => { |
57 | if (pathExistsSync(file)) { | 57 | if (pathExistsSync(file)) { |
58 | const data = await readFile(file, 'utf8'); | ||
59 | const styles = document.createElement('style'); | 58 | const styles = document.createElement('style'); |
60 | styles.innerHTML = data; | 59 | styles.innerHTML = readFileSync(file, 'utf8'); |
61 | 60 | ||
62 | document.querySelector('head').appendChild(styles); | 61 | document.querySelector('head').appendChild(styles); |
63 | 62 | ||
@@ -69,8 +68,7 @@ class RecipeWebview { | |||
69 | injectJSUnsafe(...files) { | 68 | injectJSUnsafe(...files) { |
70 | Promise.all(files.map(async (file) => { | 69 | Promise.all(files.map(async (file) => { |
71 | if (await exists(file)) { | 70 | if (await exists(file)) { |
72 | const data = await readFile(file, 'utf8'); | 71 | return readFileSync(file, 'utf8'); |
73 | return data; | ||
74 | } | 72 | } |
75 | debug('Script not found', file); | 73 | debug('Script not found', file); |
76 | return null; | 74 | return null; |
diff --git a/src/webview/recipe.js b/src/webview/recipe.js index 598c3eb9a..a45c34002 100644 --- a/src/webview/recipe.js +++ b/src/webview/recipe.js | |||
@@ -1,8 +1,8 @@ | |||
1 | /* eslint-disable import/first */ | 1 | /* eslint-disable import/first */ |
2 | import { contextBridge, ipcRenderer } from 'electron'; | 2 | import { contextBridge, ipcRenderer } from 'electron'; |
3 | import path from 'path'; | 3 | import { join } from 'path'; |
4 | import { autorun, computed, observable } from 'mobx'; | 4 | import { autorun, computed, observable } from 'mobx'; |
5 | import fs from 'fs-extra'; | 5 | import { pathExistsSync, readFileSync } from 'fs-extra'; |
6 | import { debounce } from 'lodash'; | 6 | import { debounce } from 'lodash'; |
7 | 7 | ||
8 | // For some services darkreader tries to use the chrome extension message API | 8 | // For some services darkreader tries to use the chrome extension message API |
@@ -189,7 +189,7 @@ class RecipeController { | |||
189 | 189 | ||
190 | loadRecipeModule(event, config, recipe) { | 190 | loadRecipeModule(event, config, recipe) { |
191 | debug('loadRecipeModule'); | 191 | debug('loadRecipeModule'); |
192 | const modulePath = path.join(recipe.path, 'webview.js'); | 192 | const modulePath = join(recipe.path, 'webview.js'); |
193 | debug('module path', modulePath); | 193 | debug('module path', modulePath); |
194 | // Delete module from cache | 194 | // Delete module from cache |
195 | delete require.cache[require.resolve(modulePath)]; | 195 | delete require.cache[require.resolve(modulePath)]; |
@@ -214,15 +214,15 @@ class RecipeController { | |||
214 | const styles = document.createElement('style'); | 214 | const styles = document.createElement('style'); |
215 | styles.innerHTML = screenShareCss; | 215 | styles.innerHTML = screenShareCss; |
216 | 216 | ||
217 | const userCss = path.join(recipe.path, 'user.css'); | 217 | const userCss = join(recipe.path, 'user.css'); |
218 | if (fs.existsSync(userCss)) { | 218 | if (pathExistsSync(userCss)) { |
219 | const data = await fs.readFile(userCss); | 219 | const data = readFileSync(userCss); |
220 | styles.innerHTML += data.toString(); | 220 | styles.innerHTML += data.toString(); |
221 | } | 221 | } |
222 | document.querySelector('head').appendChild(styles); | 222 | document.querySelector('head').appendChild(styles); |
223 | 223 | ||
224 | const userJs = path.join(recipe.path, 'user.js'); | 224 | const userJs = join(recipe.path, 'user.js'); |
225 | if (fs.existsSync(userJs)) { | 225 | if (pathExistsSync(userJs)) { |
226 | const loadUserJs = () => { | 226 | const loadUserJs = () => { |
227 | // eslint-disable-next-line | 227 | // eslint-disable-next-line |
228 | const userJsModule = require(userJs); | 228 | const userJsModule = require(userJs); |
@@ -308,11 +308,11 @@ class RecipeController { | |||
308 | debug('Enable dark mode'); | 308 | debug('Enable dark mode'); |
309 | 309 | ||
310 | // Check if recipe has a darkmode.css | 310 | // Check if recipe has a darkmode.css |
311 | const darkModeStyle = path.join( | 311 | const darkModeStyle = join( |
312 | this.settings.service.recipe.path, | 312 | this.settings.service.recipe.path, |
313 | 'darkmode.css', | 313 | 'darkmode.css', |
314 | ); | 314 | ); |
315 | const darkModeExists = fs.pathExistsSync(darkModeStyle); | 315 | const darkModeExists = pathExistsSync(darkModeStyle); |
316 | 316 | ||
317 | debug('darkmode.css exists? ', darkModeExists ? 'Yes' : 'No'); | 317 | debug('darkmode.css exists? ', darkModeExists ? 'Yes' : 'No'); |
318 | 318 | ||