diff options
author | Dominik Guzei <dominik.guzei@gmail.com> | 2019-03-19 11:46:30 +0100 |
---|---|---|
committer | Dominik Guzei <dominik.guzei@gmail.com> | 2019-03-19 11:46:30 +0100 |
commit | ab9ae1829e51e463d644ff369ebc3434f2f42c81 (patch) | |
tree | 639b4dc0c0d519fbd2bf99c869b00bce1ccfb5cf | |
parent | merge-in webview unmounting fix (diff) | |
parent | Merge pull request #1338 from meetfranz/chore/app-feature-helpers (diff) | |
download | ferdium-app-ab9ae1829e51e463d644ff369ebc3434f2f42c81.tar.gz ferdium-app-ab9ae1829e51e463d644ff369ebc3434f2f42c81.tar.zst ferdium-app-ab9ae1829e51e463d644ff369ebc3434f2f42c81.zip |
fix conflicts with latest develop
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | docs/example-feature/actions.js | 10 | ||||
-rw-r--r-- | docs/example-feature/api.js | 5 | ||||
-rw-r--r-- | docs/example-feature/index.js | 36 | ||||
-rw-r--r-- | docs/example-feature/state.js | 14 | ||||
-rw-r--r-- | docs/example-feature/store.js | 32 | ||||
-rw-r--r-- | package-lock.json | 60 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/api/server/ServerApi.js | 185 | ||||
-rw-r--r-- | src/api/utils/auth.js | 6 | ||||
-rw-r--r-- | src/index.js | 5 | ||||
-rw-r--r-- | src/lib/Tray.js | 8 | ||||
-rw-r--r-- | src/stores/AppStore.js | 19 | ||||
-rw-r--r-- | src/styles/auth.scss | 2 | ||||
-rw-r--r-- | src/webview/contextMenu.js | 21 |
15 files changed, 252 insertions, 155 deletions
@@ -16,7 +16,7 @@ Messaging app for WhatsApp, Slack, Telegram, HipChat, Hangouts and many many mor | |||
16 | 16 | ||
17 | `$ brew cask install franz` | 17 | `$ brew cask install franz` |
18 | 18 | ||
19 | (Don't know homebrew? [brew.sh](https://brew.sh/) | 19 | (Don't know homebrew? [brew.sh](https://brew.sh/)) |
20 | 20 | ||
21 | ## Development | 21 | ## Development |
22 | 22 | ||
diff --git a/docs/example-feature/actions.js b/docs/example-feature/actions.js new file mode 100644 index 000000000..c4d49b708 --- /dev/null +++ b/docs/example-feature/actions.js | |||
@@ -0,0 +1,10 @@ | |||
1 | import PropTypes from 'prop-types'; | ||
2 | import { createActionsFromDefinitions } from '../../src/actions/lib/actions'; | ||
3 | |||
4 | export const exampleFeatureActions = createActionsFromDefinitions({ | ||
5 | greet: { | ||
6 | name: PropTypes.string.isRequired, | ||
7 | }, | ||
8 | }, PropTypes.checkPropTypes); | ||
9 | |||
10 | export default exampleFeatureActions; | ||
diff --git a/docs/example-feature/api.js b/docs/example-feature/api.js new file mode 100644 index 000000000..65207e877 --- /dev/null +++ b/docs/example-feature/api.js | |||
@@ -0,0 +1,5 @@ | |||
1 | export default { | ||
2 | async getName() { | ||
3 | return Promise.resolve('Franz'); | ||
4 | }, | ||
5 | }; | ||
diff --git a/docs/example-feature/index.js b/docs/example-feature/index.js new file mode 100644 index 000000000..af859af26 --- /dev/null +++ b/docs/example-feature/index.js | |||
@@ -0,0 +1,36 @@ | |||
1 | import { reaction, runInAction } from 'mobx'; | ||
2 | import { ExampleFeatureStore } from './store'; | ||
3 | import state, { resetState } from './state'; | ||
4 | import api from './api'; | ||
5 | |||
6 | const debug = require('debug')('Franz:feature:EXAMPLE_FEATURE'); | ||
7 | |||
8 | let store = null; | ||
9 | |||
10 | export default function initAnnouncements(stores, actions) { | ||
11 | const { features } = stores; | ||
12 | |||
13 | // Toggle workspace feature | ||
14 | reaction( | ||
15 | () => ( | ||
16 | features.features.isExampleFeatureEnabled | ||
17 | ), | ||
18 | (isEnabled) => { | ||
19 | if (isEnabled) { | ||
20 | debug('Initializing `EXAMPLE_FEATURE` feature'); | ||
21 | store = new ExampleFeatureStore(stores, api, actions, state); | ||
22 | store.initialize(); | ||
23 | runInAction(() => { state.isFeatureActive = true; }); | ||
24 | } else if (store) { | ||
25 | debug('Disabling `EXAMPLE_FEATURE` feature'); | ||
26 | runInAction(() => { state.isFeatureActive = false; }); | ||
27 | store.teardown(); | ||
28 | store = null; | ||
29 | resetState(); // Reset state to default | ||
30 | } | ||
31 | }, | ||
32 | { | ||
33 | fireImmediately: true, | ||
34 | }, | ||
35 | ); | ||
36 | } | ||
diff --git a/docs/example-feature/state.js b/docs/example-feature/state.js new file mode 100644 index 000000000..676717da7 --- /dev/null +++ b/docs/example-feature/state.js | |||
@@ -0,0 +1,14 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | |||
3 | const defaultState = { | ||
4 | name: null, | ||
5 | isFeatureActive: false, | ||
6 | }; | ||
7 | |||
8 | export const exampleFeatureState = observable(defaultState); | ||
9 | |||
10 | export function resetState() { | ||
11 | Object.assign(exampleFeatureState, defaultState); | ||
12 | } | ||
13 | |||
14 | export default exampleFeatureState; | ||
diff --git a/docs/example-feature/store.js b/docs/example-feature/store.js new file mode 100644 index 000000000..d8acfdca3 --- /dev/null +++ b/docs/example-feature/store.js | |||
@@ -0,0 +1,32 @@ | |||
1 | import { action, observable, reaction } from 'mobx'; | ||
2 | import Store from '../../src/stores/lib/Store'; | ||
3 | import Request from '../../src/stores/lib/Request'; | ||
4 | |||
5 | const debug = require('debug')('Franz:feature:EXAMPLE_FEATURE:store'); | ||
6 | |||
7 | export class ExampleFeatureStore extends Store { | ||
8 | @observable getNameRequest = new Request(this.api, 'getName'); | ||
9 | |||
10 | constructor(stores, api, actions, state) { | ||
11 | super(stores, api, actions); | ||
12 | this.state = state; | ||
13 | } | ||
14 | |||
15 | setup() { | ||
16 | debug('fetching name from api'); | ||
17 | this.getNameRequest.execute(); | ||
18 | |||
19 | // Update the name on the state when the request resolved | ||
20 | reaction( | ||
21 | () => this.getNameRequest.result, | ||
22 | name => this._setName(name), | ||
23 | ); | ||
24 | } | ||
25 | |||
26 | @action _setName = (name) => { | ||
27 | debug('setting name', name); | ||
28 | this.state.name = name; | ||
29 | }; | ||
30 | } | ||
31 | |||
32 | export default ExampleFeatureStore; | ||
diff --git a/package-lock.json b/package-lock.json index 1f1ac3c00..c3b291acf 100644 --- a/package-lock.json +++ b/package-lock.json | |||
@@ -2340,7 +2340,8 @@ | |||
2340 | "abbrev": { | 2340 | "abbrev": { |
2341 | "version": "1.1.1", | 2341 | "version": "1.1.1", |
2342 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", | 2342 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", |
2343 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" | 2343 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", |
2344 | "dev": true | ||
2344 | }, | 2345 | }, |
2345 | "accepts": { | 2346 | "accepts": { |
2346 | "version": "1.0.7", | 2347 | "version": "1.0.7", |
@@ -2610,7 +2611,8 @@ | |||
2610 | "aproba": { | 2611 | "aproba": { |
2611 | "version": "1.2.0", | 2612 | "version": "1.2.0", |
2612 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", | 2613 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", |
2613 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" | 2614 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", |
2615 | "dev": true | ||
2614 | }, | 2616 | }, |
2615 | "archy": { | 2617 | "archy": { |
2616 | "version": "1.0.0", | 2618 | "version": "1.0.0", |
@@ -2622,6 +2624,7 @@ | |||
2622 | "version": "1.1.5", | 2624 | "version": "1.1.5", |
2623 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", | 2625 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", |
2624 | "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", | 2626 | "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", |
2627 | "dev": true, | ||
2625 | "requires": { | 2628 | "requires": { |
2626 | "delegates": "^1.0.0", | 2629 | "delegates": "^1.0.0", |
2627 | "readable-stream": "^2.0.6" | 2630 | "readable-stream": "^2.0.6" |
@@ -2631,6 +2634,7 @@ | |||
2631 | "version": "2.3.6", | 2634 | "version": "2.3.6", |
2632 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", | 2635 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", |
2633 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", | 2636 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", |
2637 | "dev": true, | ||
2634 | "requires": { | 2638 | "requires": { |
2635 | "core-util-is": "~1.0.0", | 2639 | "core-util-is": "~1.0.0", |
2636 | "inherits": "~2.0.3", | 2640 | "inherits": "~2.0.3", |
@@ -2645,6 +2649,7 @@ | |||
2645 | "version": "1.1.1", | 2649 | "version": "1.1.1", |
2646 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", | 2650 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", |
2647 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", | 2651 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", |
2652 | "dev": true, | ||
2648 | "requires": { | 2653 | "requires": { |
2649 | "safe-buffer": "~5.1.0" | 2654 | "safe-buffer": "~5.1.0" |
2650 | } | 2655 | } |
@@ -5410,7 +5415,8 @@ | |||
5410 | "delegates": { | 5415 | "delegates": { |
5411 | "version": "1.0.0", | 5416 | "version": "1.0.0", |
5412 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", | 5417 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", |
5413 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" | 5418 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", |
5419 | "dev": true | ||
5414 | }, | 5420 | }, |
5415 | "depd": { | 5421 | "depd": { |
5416 | "version": "0.4.4", | 5422 | "version": "0.4.4", |
@@ -5650,6 +5656,29 @@ | |||
5650 | "readable-stream": "~1.1.9" | 5656 | "readable-stream": "~1.1.9" |
5651 | }, | 5657 | }, |
5652 | "dependencies": { | 5658 | "dependencies": { |
5659 | "abbrev": { | ||
5660 | "version": "1.1.1", | ||
5661 | "resolved": false, | ||
5662 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" | ||
5663 | }, | ||
5664 | "ansi-regex": { | ||
5665 | "version": "2.1.1", | ||
5666 | "resolved": false, | ||
5667 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" | ||
5668 | }, | ||
5669 | "aproba": { | ||
5670 | "version": "1.2.0", | ||
5671 | "resolved": false, | ||
5672 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" | ||
5673 | }, | ||
5674 | "are-we-there-yet": { | ||
5675 | "version": "1.1.4", | ||
5676 | "resolved": false, | ||
5677 | "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", | ||
5678 | "requires": { | ||
5679 | "delegates": "^1.0.0" | ||
5680 | } | ||
5681 | }, | ||
5653 | "balanced-match": { | 5682 | "balanced-match": { |
5654 | "version": "1.0.0", | 5683 | "version": "1.0.0", |
5655 | "resolved": false, | 5684 | "resolved": false, |
@@ -5966,6 +5995,11 @@ | |||
5966 | "glob": "^7.0.5" | 5995 | "glob": "^7.0.5" |
5967 | } | 5996 | } |
5968 | }, | 5997 | }, |
5998 | "safe-buffer": { | ||
5999 | "version": "5.1.1", | ||
6000 | "resolved": false, | ||
6001 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" | ||
6002 | }, | ||
5969 | "safer-buffer": { | 6003 | "safer-buffer": { |
5970 | "version": "2.1.2", | 6004 | "version": "2.1.2", |
5971 | "resolved": false, | 6005 | "resolved": false, |
@@ -6010,7 +6044,10 @@ | |||
6010 | "strip-ansi": { | 6044 | "strip-ansi": { |
6011 | "version": "3.0.1", | 6045 | "version": "3.0.1", |
6012 | "resolved": false, | 6046 | "resolved": false, |
6013 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=" | 6047 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", |
6048 | "requires": { | ||
6049 | "ansi-regex": "^2.0.0" | ||
6050 | } | ||
6014 | }, | 6051 | }, |
6015 | "strip-json-comments": { | 6052 | "strip-json-comments": { |
6016 | "version": "2.0.1", | 6053 | "version": "2.0.1", |
@@ -6136,9 +6173,9 @@ | |||
6136 | "dev": true | 6173 | "dev": true |
6137 | }, | 6174 | }, |
6138 | "electron": { | 6175 | "electron": { |
6139 | "version": "4.0.7", | 6176 | "version": "4.0.8", |
6140 | "resolved": "https://registry.npmjs.org/electron/-/electron-4.0.7.tgz", | 6177 | "resolved": "https://registry.npmjs.org/electron/-/electron-4.0.8.tgz", |
6141 | "integrity": "sha512-KYQ9SJZFWNKqoq6XjKW1bLFHjmAGeSC3XNuhHK/Sd2MK5H5sO3iKjvZU/YhiBUtkB/cBSkOdQTVEaLcMwU8l3A==", | 6178 | "integrity": "sha512-FOBJIHkuv8wc15N+ZyqwDzPavYVu5CHMBEf14jHDWv7QW2vkEIpJjVK+PIT31kfZfvjsIP0j2wvA/FBsiqB7pw==", |
6142 | "dev": true, | 6179 | "dev": true, |
6143 | "requires": { | 6180 | "requires": { |
6144 | "@types/node": "^10.12.18", | 6181 | "@types/node": "^10.12.18", |
@@ -6147,9 +6184,9 @@ | |||
6147 | }, | 6184 | }, |
6148 | "dependencies": { | 6185 | "dependencies": { |
6149 | "@types/node": { | 6186 | "@types/node": { |
6150 | "version": "10.12.29", | 6187 | "version": "10.12.30", |
6151 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.29.tgz", | 6188 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.30.tgz", |
6152 | "integrity": "sha512-J/tnbnj8HcsBgCe2apZbdUpQ7hs4d7oZNTYA5bekWdP0sr2NGsOpI/HRdDroEi209tEvTcTtxhD0FfED3DhEcw==", | 6189 | "integrity": "sha512-nsqTN6zUcm9xtdJiM9OvOJ5EF0kOI8f1Zuug27O/rgtxCRJHGqncSWfCMZUP852dCKPsDsYXGvBhxfRjDBkF5Q==", |
6153 | "dev": true | 6190 | "dev": true |
6154 | } | 6191 | } |
6155 | } | 6192 | } |
@@ -14574,7 +14611,8 @@ | |||
14574 | "process-nextick-args": { | 14611 | "process-nextick-args": { |
14575 | "version": "2.0.0", | 14612 | "version": "2.0.0", |
14576 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", | 14613 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", |
14577 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" | 14614 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", |
14615 | "dev": true | ||
14578 | }, | 14616 | }, |
14579 | "progress": { | 14617 | "progress": { |
14580 | "version": "2.0.3", | 14618 | "version": "2.0.3", |
diff --git a/package.json b/package.json index 14e0df7ca..df7fa4191 100644 --- a/package.json +++ b/package.json | |||
@@ -113,7 +113,7 @@ | |||
113 | "cross-env": "^5.0.5", | 113 | "cross-env": "^5.0.5", |
114 | "cz-conventional-changelog": "2.1.0", | 114 | "cz-conventional-changelog": "2.1.0", |
115 | "dotenv": "^4.0.0", | 115 | "dotenv": "^4.0.0", |
116 | "electron": "4.0.7", | 116 | "electron": "4.0.8", |
117 | "electron-builder": "20.38.4", | 117 | "electron-builder": "20.38.4", |
118 | "electron-rebuild": "1.8.4", | 118 | "electron-rebuild": "1.8.4", |
119 | "eslint": "5.10.0", | 119 | "eslint": "5.10.0", |
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index 2871769a9..bafeef005 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js | |||
@@ -3,7 +3,6 @@ import path from 'path'; | |||
3 | import tar from 'tar'; | 3 | import tar from 'tar'; |
4 | import fs from 'fs-extra'; | 4 | import fs from 'fs-extra'; |
5 | import { remote } from 'electron'; | 5 | import { remote } from 'electron'; |
6 | import localStorage from 'mobx-localstorage'; | ||
7 | 6 | ||
8 | import ServiceModel from '../../models/Service'; | 7 | import ServiceModel from '../../models/Service'; |
9 | import RecipePreviewModel from '../../models/RecipePreview'; | 8 | import RecipePreviewModel from '../../models/RecipePreview'; |
@@ -16,6 +15,7 @@ import OrderModel from '../../models/Order'; | |||
16 | import { sleep } from '../../helpers/async-helpers'; | 15 | import { sleep } from '../../helpers/async-helpers'; |
17 | 16 | ||
18 | import { API } from '../../environment'; | 17 | import { API } from '../../environment'; |
18 | import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; | ||
19 | 19 | ||
20 | import { | 20 | import { |
21 | getRecipeDirectory, | 21 | getRecipeDirectory, |
@@ -39,6 +39,7 @@ const { default: fetch } = remote.require('electron-fetch'); | |||
39 | 39 | ||
40 | const SERVER_URL = API; | 40 | const SERVER_URL = API; |
41 | const API_VERSION = 'v1'; | 41 | const API_VERSION = 'v1'; |
42 | const API_URL = `${SERVER_URL}/${API_VERSION}`; | ||
42 | 43 | ||
43 | export default class ServerApi { | 44 | export default class ServerApi { |
44 | recipePreviews = []; | 45 | recipePreviews = []; |
@@ -47,12 +48,12 @@ export default class ServerApi { | |||
47 | 48 | ||
48 | // User | 49 | // User |
49 | async login(email, passwordHash) { | 50 | async login(email, passwordHash) { |
50 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/auth/login`, this._prepareAuthRequest({ | 51 | const request = await sendAuthRequest(`${API_URL}/auth/login`, { |
51 | method: 'POST', | 52 | method: 'POST', |
52 | headers: { | 53 | headers: { |
53 | Authorization: `Basic ${window.btoa(`${email}:${passwordHash}`)}`, | 54 | Authorization: `Basic ${window.btoa(`${email}:${passwordHash}`)}`, |
54 | }, | 55 | }, |
55 | }, false)); | 56 | }, false); |
56 | if (!request.ok) { | 57 | if (!request.ok) { |
57 | throw request; | 58 | throw request; |
58 | } | 59 | } |
@@ -63,10 +64,10 @@ export default class ServerApi { | |||
63 | } | 64 | } |
64 | 65 | ||
65 | async signup(data) { | 66 | async signup(data) { |
66 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/auth/signup`, this._prepareAuthRequest({ | 67 | const request = await sendAuthRequest(`${API_URL}/auth/signup`, { |
67 | method: 'POST', | 68 | method: 'POST', |
68 | body: JSON.stringify(data), | 69 | body: JSON.stringify(data), |
69 | }, false)); | 70 | }, false); |
70 | if (!request.ok) { | 71 | if (!request.ok) { |
71 | throw request; | 72 | throw request; |
72 | } | 73 | } |
@@ -77,10 +78,10 @@ export default class ServerApi { | |||
77 | } | 78 | } |
78 | 79 | ||
79 | async inviteUser(data) { | 80 | async inviteUser(data) { |
80 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/invite`, this._prepareAuthRequest({ | 81 | const request = await sendAuthRequest(`${API_URL}/invite`, { |
81 | method: 'POST', | 82 | method: 'POST', |
82 | body: JSON.stringify(data), | 83 | body: JSON.stringify(data), |
83 | })); | 84 | }); |
84 | if (!request.ok) { | 85 | if (!request.ok) { |
85 | throw request; | 86 | throw request; |
86 | } | 87 | } |
@@ -90,12 +91,12 @@ export default class ServerApi { | |||
90 | } | 91 | } |
91 | 92 | ||
92 | async retrievePassword(email) { | 93 | async retrievePassword(email) { |
93 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/auth/password`, this._prepareAuthRequest({ | 94 | const request = await sendAuthRequest(`${API_URL}/auth/password`, { |
94 | method: 'POST', | 95 | method: 'POST', |
95 | body: JSON.stringify({ | 96 | body: JSON.stringify({ |
96 | email, | 97 | email, |
97 | }), | 98 | }), |
98 | }, false)); | 99 | }, false); |
99 | if (!request.ok) { | 100 | if (!request.ok) { |
100 | throw request; | 101 | throw request; |
101 | } | 102 | } |
@@ -106,9 +107,7 @@ export default class ServerApi { | |||
106 | } | 107 | } |
107 | 108 | ||
108 | async userInfo() { | 109 | async userInfo() { |
109 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/me`, this._prepareAuthRequest({ | 110 | const request = await sendAuthRequest(`${API_URL}/me`); |
110 | method: 'GET', | ||
111 | })); | ||
112 | if (!request.ok) { | 111 | if (!request.ok) { |
113 | throw request; | 112 | throw request; |
114 | } | 113 | } |
@@ -121,10 +120,10 @@ export default class ServerApi { | |||
121 | } | 120 | } |
122 | 121 | ||
123 | async updateUserInfo(data) { | 122 | async updateUserInfo(data) { |
124 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/me`, this._prepareAuthRequest({ | 123 | const request = await sendAuthRequest(`${API_URL}/me`, { |
125 | method: 'PUT', | 124 | method: 'PUT', |
126 | body: JSON.stringify(data), | 125 | body: JSON.stringify(data), |
127 | })); | 126 | }); |
128 | if (!request.ok) { | 127 | if (!request.ok) { |
129 | throw request; | 128 | throw request; |
130 | } | 129 | } |
@@ -136,9 +135,9 @@ export default class ServerApi { | |||
136 | } | 135 | } |
137 | 136 | ||
138 | async deleteAccount() { | 137 | async deleteAccount() { |
139 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/me`, this._prepareAuthRequest({ | 138 | const request = await sendAuthRequest(`${API_URL}/me`, { |
140 | method: 'DELETE', | 139 | method: 'DELETE', |
141 | })); | 140 | }); |
142 | if (!request.ok) { | 141 | if (!request.ok) { |
143 | throw request; | 142 | throw request; |
144 | } | 143 | } |
@@ -150,9 +149,7 @@ export default class ServerApi { | |||
150 | 149 | ||
151 | // Services | 150 | // Services |
152 | async getServices() { | 151 | async getServices() { |
153 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/me/services`, this._prepareAuthRequest({ | 152 | const request = await sendAuthRequest(`${API_URL}/me/services`); |
154 | method: 'GET', | ||
155 | })); | ||
156 | if (!request.ok) { | 153 | if (!request.ok) { |
157 | throw request; | 154 | throw request; |
158 | } | 155 | } |
@@ -165,12 +162,12 @@ export default class ServerApi { | |||
165 | } | 162 | } |
166 | 163 | ||
167 | async createService(recipeId, data) { | 164 | async createService(recipeId, data) { |
168 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/service`, this._prepareAuthRequest({ | 165 | const request = await sendAuthRequest(`${API_URL}/service`, { |
169 | method: 'POST', | 166 | method: 'POST', |
170 | body: JSON.stringify(Object.assign({ | 167 | body: JSON.stringify(Object.assign({ |
171 | recipeId, | 168 | recipeId, |
172 | }, data)), | 169 | }, data)), |
173 | })); | 170 | }); |
174 | if (!request.ok) { | 171 | if (!request.ok) { |
175 | throw request; | 172 | throw request; |
176 | } | 173 | } |
@@ -195,10 +192,10 @@ export default class ServerApi { | |||
195 | await this.uploadServiceIcon(serviceId, data.iconFile); | 192 | await this.uploadServiceIcon(serviceId, data.iconFile); |
196 | } | 193 | } |
197 | 194 | ||
198 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/service/${serviceId}`, this._prepareAuthRequest({ | 195 | const request = await sendAuthRequest(`${API_URL}/service/${serviceId}`, { |
199 | method: 'PUT', | 196 | method: 'PUT', |
200 | body: JSON.stringify(data), | 197 | body: JSON.stringify(data), |
201 | })); | 198 | }); |
202 | 199 | ||
203 | if (!request.ok) { | 200 | if (!request.ok) { |
204 | throw request; | 201 | throw request; |
@@ -216,14 +213,14 @@ export default class ServerApi { | |||
216 | const formData = new FormData(); | 213 | const formData = new FormData(); |
217 | formData.append('icon', icon); | 214 | formData.append('icon', icon); |
218 | 215 | ||
219 | const requestData = this._prepareAuthRequest({ | 216 | const requestData = prepareAuthRequest({ |
220 | method: 'PUT', | 217 | method: 'PUT', |
221 | body: formData, | 218 | body: formData, |
222 | }); | 219 | }); |
223 | 220 | ||
224 | delete requestData.headers['Content-Type']; | 221 | delete requestData.headers['Content-Type']; |
225 | 222 | ||
226 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/service/${serviceId}`, requestData); | 223 | const request = await window.fetch(`${API_URL}/service/${serviceId}`, requestData); |
227 | 224 | ||
228 | if (!request.ok) { | 225 | if (!request.ok) { |
229 | throw request; | 226 | throw request; |
@@ -235,10 +232,10 @@ export default class ServerApi { | |||
235 | } | 232 | } |
236 | 233 | ||
237 | async reorderService(data) { | 234 | async reorderService(data) { |
238 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/service/reorder`, this._prepareAuthRequest({ | 235 | const request = await sendAuthRequest(`${API_URL}/service/reorder`, { |
239 | method: 'PUT', | 236 | method: 'PUT', |
240 | body: JSON.stringify(data), | 237 | body: JSON.stringify(data), |
241 | })); | 238 | }); |
242 | if (!request.ok) { | 239 | if (!request.ok) { |
243 | throw request; | 240 | throw request; |
244 | } | 241 | } |
@@ -248,9 +245,9 @@ export default class ServerApi { | |||
248 | } | 245 | } |
249 | 246 | ||
250 | async deleteService(id) { | 247 | async deleteService(id) { |
251 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/service/${id}`, this._prepareAuthRequest({ | 248 | const request = await sendAuthRequest(`${API_URL}/service/${id}`, { |
252 | method: 'DELETE', | 249 | method: 'DELETE', |
253 | })); | 250 | }); |
254 | if (!request.ok) { | 251 | if (!request.ok) { |
255 | throw request; | 252 | throw request; |
256 | } | 253 | } |
@@ -264,9 +261,7 @@ export default class ServerApi { | |||
264 | 261 | ||
265 | // Features | 262 | // Features |
266 | async getDefaultFeatures() { | 263 | async getDefaultFeatures() { |
267 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/features/default`, this._prepareAuthRequest({ | 264 | const request = await sendAuthRequest(`${API_URL}/features/default`); |
268 | method: 'GET', | ||
269 | })); | ||
270 | if (!request.ok) { | 265 | if (!request.ok) { |
271 | throw request; | 266 | throw request; |
272 | } | 267 | } |
@@ -278,9 +273,7 @@ export default class ServerApi { | |||
278 | } | 273 | } |
279 | 274 | ||
280 | async getFeatures() { | 275 | async getFeatures() { |
281 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/features`, this._prepareAuthRequest({ | 276 | const request = await sendAuthRequest(`${API_URL}/features`); |
282 | method: 'GET', | ||
283 | })); | ||
284 | if (!request.ok) { | 277 | if (!request.ok) { |
285 | throw request; | 278 | throw request; |
286 | } | 279 | } |
@@ -314,10 +307,10 @@ export default class ServerApi { | |||
314 | } | 307 | } |
315 | 308 | ||
316 | async getRecipeUpdates(recipeVersions) { | 309 | async getRecipeUpdates(recipeVersions) { |
317 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/recipes/update`, this._prepareAuthRequest({ | 310 | const request = await sendAuthRequest(`${API_URL}/recipes/update`, { |
318 | method: 'POST', | 311 | method: 'POST', |
319 | body: JSON.stringify(recipeVersions), | 312 | body: JSON.stringify(recipeVersions), |
320 | })); | 313 | }); |
321 | if (!request.ok) { | 314 | if (!request.ok) { |
322 | throw request; | 315 | throw request; |
323 | } | 316 | } |
@@ -328,29 +321,19 @@ export default class ServerApi { | |||
328 | 321 | ||
329 | // Recipes Previews | 322 | // Recipes Previews |
330 | async getRecipePreviews() { | 323 | async getRecipePreviews() { |
331 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/recipes`, this._prepareAuthRequest({ | 324 | const request = await sendAuthRequest(`${API_URL}/recipes`); |
332 | method: 'GET', | 325 | if (!request.ok) throw request; |
333 | })); | ||
334 | if (!request.ok) { | ||
335 | throw request; | ||
336 | } | ||
337 | const data = await request.json(); | 326 | const data = await request.json(); |
338 | |||
339 | const recipePreviews = this._mapRecipePreviewModel(data); | 327 | const recipePreviews = this._mapRecipePreviewModel(data); |
340 | debug('ServerApi::getRecipes resolves', recipePreviews); | 328 | debug('ServerApi::getRecipes resolves', recipePreviews); |
341 | |||
342 | return recipePreviews; | 329 | return recipePreviews; |
343 | } | 330 | } |
344 | 331 | ||
345 | async getFeaturedRecipePreviews() { | 332 | async getFeaturedRecipePreviews() { |
346 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/recipes/popular`, this._prepareAuthRequest({ | 333 | const request = await sendAuthRequest(`${API_URL}/recipes/popular`); |
347 | method: 'GET', | 334 | if (!request.ok) throw request; |
348 | })); | ||
349 | if (!request.ok) { | ||
350 | throw request; | ||
351 | } | ||
352 | const data = await request.json(); | ||
353 | 335 | ||
336 | const data = await request.json(); | ||
354 | // data = this._addLocalRecipesToPreviews(data); | 337 | // data = this._addLocalRecipesToPreviews(data); |
355 | 338 | ||
356 | const recipePreviews = this._mapRecipePreviewModel(data); | 339 | const recipePreviews = this._mapRecipePreviewModel(data); |
@@ -359,14 +342,11 @@ export default class ServerApi { | |||
359 | } | 342 | } |
360 | 343 | ||
361 | async searchRecipePreviews(needle) { | 344 | async searchRecipePreviews(needle) { |
362 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/recipes/search?needle=${needle}`, this._prepareAuthRequest({ | 345 | const url = `${API_URL}/recipes/search?needle=${needle}`; |
363 | method: 'GET', | 346 | const request = await sendAuthRequest(url); |
364 | })); | 347 | if (!request.ok) throw request; |
365 | if (!request.ok) { | ||
366 | throw request; | ||
367 | } | ||
368 | const data = await request.json(); | ||
369 | 348 | ||
349 | const data = await request.json(); | ||
370 | const recipePreviews = this._mapRecipePreviewModel(data); | 350 | const recipePreviews = this._mapRecipePreviewModel(data); |
371 | debug('ServerApi::searchRecipePreviews resolves', recipePreviews); | 351 | debug('ServerApi::searchRecipePreviews resolves', recipePreviews); |
372 | return recipePreviews; | 352 | return recipePreviews; |
@@ -375,10 +355,9 @@ export default class ServerApi { | |||
375 | async getRecipePackage(recipeId) { | 355 | async getRecipePackage(recipeId) { |
376 | try { | 356 | try { |
377 | const recipesDirectory = path.join(app.getPath('userData'), 'recipes'); | 357 | const recipesDirectory = path.join(app.getPath('userData'), 'recipes'); |
378 | |||
379 | const recipeTempDirectory = path.join(recipesDirectory, 'temp', recipeId); | 358 | const recipeTempDirectory = path.join(recipesDirectory, 'temp', recipeId); |
380 | const archivePath = path.join(recipeTempDirectory, 'recipe.tar.gz'); | 359 | const archivePath = path.join(recipeTempDirectory, 'recipe.tar.gz'); |
381 | const packageUrl = `${SERVER_URL}/${API_VERSION}/recipes/download/${recipeId}`; | 360 | const packageUrl = `${API_URL}/recipes/download/${recipeId}`; |
382 | 361 | ||
383 | fs.ensureDirSync(recipeTempDirectory); | 362 | fs.ensureDirSync(recipeTempDirectory); |
384 | const res = await fetch(packageUrl); | 363 | const res = await fetch(packageUrl); |
@@ -415,26 +394,21 @@ export default class ServerApi { | |||
415 | 394 | ||
416 | // Payment | 395 | // Payment |
417 | async getPlans() { | 396 | async getPlans() { |
418 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/payment/plans`, this._prepareAuthRequest({ | 397 | const request = await sendAuthRequest(`${API_URL}/payment/plans`); |
419 | method: 'GET', | 398 | if (!request.ok) throw request; |
420 | })); | ||
421 | if (!request.ok) { | ||
422 | throw request; | ||
423 | } | ||
424 | const data = await request.json(); | 399 | const data = await request.json(); |
425 | |||
426 | const plan = new PlanModel(data); | 400 | const plan = new PlanModel(data); |
427 | debug('ServerApi::getPlans resolves', plan); | 401 | debug('ServerApi::getPlans resolves', plan); |
428 | return plan; | 402 | return plan; |
429 | } | 403 | } |
430 | 404 | ||
431 | async getHostedPage(planId) { | 405 | async getHostedPage(planId) { |
432 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/payment/init`, this._prepareAuthRequest({ | 406 | const request = await sendAuthRequest(`${API_URL}/payment/init`, { |
433 | method: 'POST', | 407 | method: 'POST', |
434 | body: JSON.stringify({ | 408 | body: JSON.stringify({ |
435 | planId, | 409 | planId, |
436 | }), | 410 | }), |
437 | })); | 411 | }); |
438 | if (!request.ok) { | 412 | if (!request.ok) { |
439 | throw request; | 413 | throw request; |
440 | } | 414 | } |
@@ -445,25 +419,16 @@ export default class ServerApi { | |||
445 | } | 419 | } |
446 | 420 | ||
447 | async getPaymentDashboardUrl() { | 421 | async getPaymentDashboardUrl() { |
448 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/me/billing`, this._prepareAuthRequest({ | 422 | const request = await sendAuthRequest(`${API_URL}/me/billing`); |
449 | method: 'GET', | 423 | if (!request.ok) throw request; |
450 | })); | ||
451 | if (!request.ok) { | ||
452 | throw request; | ||
453 | } | ||
454 | const data = await request.json(); | 424 | const data = await request.json(); |
455 | |||
456 | debug('ServerApi::getPaymentDashboardUrl resolves', data); | 425 | debug('ServerApi::getPaymentDashboardUrl resolves', data); |
457 | return data; | 426 | return data; |
458 | } | 427 | } |
459 | 428 | ||
460 | async getSubscriptionOrders() { | 429 | async getSubscriptionOrders() { |
461 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/me/subscription`, this._prepareAuthRequest({ | 430 | const request = await sendAuthRequest(`${API_URL}/me/subscription`); |
462 | method: 'GET', | 431 | if (!request.ok) throw request; |
463 | })); | ||
464 | if (!request.ok) { | ||
465 | throw request; | ||
466 | } | ||
467 | const data = await request.json(); | 432 | const data = await request.json(); |
468 | const orders = this._mapOrderModels(data); | 433 | const orders = this._mapOrderModels(data); |
469 | debug('ServerApi::getSubscriptionOrders resolves', orders); | 434 | debug('ServerApi::getSubscriptionOrders resolves', orders); |
@@ -472,15 +437,9 @@ export default class ServerApi { | |||
472 | 437 | ||
473 | // News | 438 | // News |
474 | async getLatestNews() { | 439 | async getLatestNews() { |
475 | // eslint-disable-next-line | 440 | const url = `${API_URL}/news?platform=${os.platform()}&arch=${os.arch()}&version=${app.getVersion()}`; |
476 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/news?platform=${os.platform()}&arch=${os.arch()}&version=${app.getVersion()}`, | 441 | const request = await sendAuthRequest(url); |
477 | this._prepareAuthRequest({ | 442 | if (!request.ok) throw request; |
478 | method: 'GET', | ||
479 | })); | ||
480 | |||
481 | if (!request.ok) { | ||
482 | throw request; | ||
483 | } | ||
484 | const data = await request.json(); | 443 | const data = await request.json(); |
485 | const news = this._mapNewsModels(data); | 444 | const news = this._mapNewsModels(data); |
486 | debug('ServerApi::getLatestNews resolves', news); | 445 | debug('ServerApi::getLatestNews resolves', news); |
@@ -488,23 +447,16 @@ export default class ServerApi { | |||
488 | } | 447 | } |
489 | 448 | ||
490 | async hideNews(id) { | 449 | async hideNews(id) { |
491 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/news/${id}/read`, | 450 | const request = await sendAuthRequest(`${API_URL}/news/${id}/read`); |
492 | this._prepareAuthRequest({ | 451 | if (!request.ok) throw request; |
493 | method: 'GET', | ||
494 | })); | ||
495 | |||
496 | if (!request.ok) { | ||
497 | throw request; | ||
498 | } | ||
499 | |||
500 | debug('ServerApi::hideNews resolves', id); | 452 | debug('ServerApi::hideNews resolves', id); |
501 | } | 453 | } |
502 | 454 | ||
503 | // Health Check | 455 | // Health Check |
504 | async healthCheck() { | 456 | async healthCheck() { |
505 | const request = await window.fetch(`${SERVER_URL}/health`, this._prepareAuthRequest({ | 457 | const request = await sendAuthRequest(`${SERVER_URL}/health`, { |
506 | method: 'GET', | 458 | method: 'GET', |
507 | }, false)); | 459 | }, false); |
508 | if (!request.ok) { | 460 | if (!request.ok) { |
509 | throw request; | 461 | throw request; |
510 | } | 462 | } |
@@ -520,10 +472,7 @@ export default class ServerApi { | |||
520 | if (Object.prototype.hasOwnProperty.call(config, 'services')) { | 472 | if (Object.prototype.hasOwnProperty.call(config, 'services')) { |
521 | const services = await Promise.all(config.services.map(async (s) => { | 473 | const services = await Promise.all(config.services.map(async (s) => { |
522 | const service = s; | 474 | const service = s; |
523 | const request = await window.fetch(`${SERVER_URL}/${API_VERSION}/recipes/${s.service}`, | 475 | const request = await sendAuthRequest(`${API_URL}/recipes/${s.service}`); |
524 | this._prepareAuthRequest({ | ||
525 | method: 'GET', | ||
526 | })); | ||
527 | 476 | ||
528 | if (request.status === 200) { | 477 | if (request.status === 200) { |
529 | const data = await request.json(); | 478 | const data = await request.json(); |
@@ -546,9 +495,7 @@ export default class ServerApi { | |||
546 | // Helper | 495 | // Helper |
547 | async _mapServiceModels(services) { | 496 | async _mapServiceModels(services) { |
548 | const recipes = services.map(s => s.recipeId); | 497 | const recipes = services.map(s => s.recipeId); |
549 | |||
550 | await this._bulkRecipeCheck(recipes); | 498 | await this._bulkRecipeCheck(recipes); |
551 | |||
552 | /* eslint-disable no-return-await */ | 499 | /* eslint-disable no-return-await */ |
553 | return Promise.all(services.map(async service => await this._prepareServiceModel(service))); | 500 | return Promise.all(services.map(async service => await this._prepareServiceModel(service))); |
554 | /* eslint-enable no-return-await */ | 501 | /* eslint-enable no-return-await */ |
@@ -632,26 +579,6 @@ export default class ServerApi { | |||
632 | }).filter(orderItem => orderItem !== null); | 579 | }).filter(orderItem => orderItem !== null); |
633 | } | 580 | } |
634 | 581 | ||
635 | _prepareAuthRequest(options, auth = true) { | ||
636 | const request = Object.assign(options, { | ||
637 | mode: 'cors', | ||
638 | headers: Object.assign({ | ||
639 | 'Content-Type': 'application/json', | ||
640 | 'X-Franz-Source': 'desktop', | ||
641 | 'X-Franz-Version': app.getVersion(), | ||
642 | 'X-Franz-platform': process.platform, | ||
643 | 'X-Franz-Timezone-Offset': new Date().getTimezoneOffset(), | ||
644 | 'X-Franz-System-Locale': app.getLocale(), | ||
645 | }, options.headers), | ||
646 | }); | ||
647 | |||
648 | if (auth) { | ||
649 | request.headers.Authorization = `Bearer ${localStorage.getItem('authToken')}`; | ||
650 | } | ||
651 | |||
652 | return request; | ||
653 | } | ||
654 | |||
655 | _getDevRecipes() { | 582 | _getDevRecipes() { |
656 | const recipesDirectory = getDevRecipeDirectory(); | 583 | const recipesDirectory = getDevRecipeDirectory(); |
657 | try { | 584 | try { |
diff --git a/src/api/utils/auth.js b/src/api/utils/auth.js index d469853a5..6dbdeaa7f 100644 --- a/src/api/utils/auth.js +++ b/src/api/utils/auth.js | |||
@@ -3,7 +3,7 @@ import localStorage from 'mobx-localstorage'; | |||
3 | 3 | ||
4 | const { app } = remote; | 4 | const { app } = remote; |
5 | 5 | ||
6 | export const prepareAuthRequest = (options, auth = true) => { | 6 | export const prepareAuthRequest = (options = { method: 'GET' }, auth = true) => { |
7 | const request = Object.assign(options, { | 7 | const request = Object.assign(options, { |
8 | mode: 'cors', | 8 | mode: 'cors', |
9 | headers: Object.assign({ | 9 | headers: Object.assign({ |
@@ -23,6 +23,6 @@ export const prepareAuthRequest = (options, auth = true) => { | |||
23 | return request; | 23 | return request; |
24 | }; | 24 | }; |
25 | 25 | ||
26 | export const sendAuthRequest = (url, options) => ( | 26 | export const sendAuthRequest = (url, options, auth) => ( |
27 | window.fetch(url, prepareAuthRequest(options)) | 27 | window.fetch(url, prepareAuthRequest(options, auth)) |
28 | ); | 28 | ); |
diff --git a/src/index.js b/src/index.js index 0e222c3d6..05c793d98 100644 --- a/src/index.js +++ b/src/index.js | |||
@@ -72,7 +72,10 @@ if (!gotTheLock) { | |||
72 | app.on('second-instance', (event, argv) => { | 72 | app.on('second-instance', (event, argv) => { |
73 | // Someone tried to run a second instance, we should focus our window. | 73 | // Someone tried to run a second instance, we should focus our window. |
74 | if (mainWindow) { | 74 | if (mainWindow) { |
75 | if (mainWindow.isMinimized()) mainWindow.restore(); | 75 | mainWindow.show(); |
76 | if (mainWindow.isMinimized()) { | ||
77 | mainWindow.restore(); | ||
78 | } | ||
76 | mainWindow.focus(); | 79 | mainWindow.focus(); |
77 | 80 | ||
78 | if (isWindows) { | 81 | if (isWindows) { |
diff --git a/src/lib/Tray.js b/src/lib/Tray.js index 669b02709..192e24796 100644 --- a/src/lib/Tray.js +++ b/src/lib/Tray.js | |||
@@ -22,7 +22,11 @@ export default class TrayIcon { | |||
22 | { | 22 | { |
23 | label: 'Show Franz', | 23 | label: 'Show Franz', |
24 | click() { | 24 | click() { |
25 | if (app.mainWindow.isMinimized()) { | ||
26 | app.mainWindow.restore(); | ||
27 | } | ||
25 | app.mainWindow.show(); | 28 | app.mainWindow.show(); |
29 | app.mainWindow.focus(); | ||
26 | }, | 30 | }, |
27 | }, { | 31 | }, { |
28 | label: 'Quit Franz', | 32 | label: 'Quit Franz', |
@@ -36,7 +40,11 @@ export default class TrayIcon { | |||
36 | this.trayIcon.setContextMenu(trayMenu); | 40 | this.trayIcon.setContextMenu(trayMenu); |
37 | 41 | ||
38 | this.trayIcon.on('click', () => { | 42 | this.trayIcon.on('click', () => { |
43 | if (app.mainWindow.isMinimized()) { | ||
44 | app.mainWindow.restore(); | ||
45 | } | ||
39 | app.mainWindow.show(); | 46 | app.mainWindow.show(); |
47 | app.mainWindow.focus(); | ||
40 | }); | 48 | }); |
41 | 49 | ||
42 | if (process.platform === 'darwin') { | 50 | if (process.platform === 'darwin') { |
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index 7784ff1f9..351ad6422 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -12,7 +12,7 @@ import { URL } from 'url'; | |||
12 | import Store from './lib/Store'; | 12 | import Store from './lib/Store'; |
13 | import Request from './lib/Request'; | 13 | import Request from './lib/Request'; |
14 | import { CHECK_INTERVAL, DEFAULT_APP_SETTINGS } from '../config'; | 14 | import { CHECK_INTERVAL, DEFAULT_APP_SETTINGS } from '../config'; |
15 | import { isMac, isLinux, isWindows } from '../environment'; | 15 | import { isMac } from '../environment'; |
16 | import locales from '../i18n/translations'; | 16 | import locales from '../i18n/translations'; |
17 | import { gaEvent, gaPage } from '../lib/analytics'; | 17 | import { gaEvent, gaPage } from '../lib/analytics'; |
18 | import { onVisibilityChange } from '../helpers/visibility-helper'; | 18 | import { onVisibilityChange } from '../helpers/visibility-helper'; |
@@ -185,7 +185,15 @@ export default class AppStore extends Store { | |||
185 | }) { | 185 | }) { |
186 | if (this.stores.settings.all.app.isAppMuted) return; | 186 | if (this.stores.settings.all.app.isAppMuted) return; |
187 | 187 | ||
188 | // TODO: is there a simple way to use blobs for notifications without storing them on disk? | ||
189 | if (options.icon.startsWith('blob:')) { | ||
190 | delete options.icon; | ||
191 | } | ||
192 | |||
188 | const notification = new window.Notification(title, options); | 193 | const notification = new window.Notification(title, options); |
194 | |||
195 | debug('New notification', title, options); | ||
196 | |||
189 | notification.onclick = (e) => { | 197 | notification.onclick = (e) => { |
190 | if (serviceId) { | 198 | if (serviceId) { |
191 | this.actions.service.sendIPCMessage({ | 199 | this.actions.service.sendIPCMessage({ |
@@ -195,12 +203,13 @@ export default class AppStore extends Store { | |||
195 | }); | 203 | }); |
196 | 204 | ||
197 | this.actions.service.setActive({ serviceId }); | 205 | this.actions.service.setActive({ serviceId }); |
198 | 206 | mainWindow.show(); | |
199 | if (isWindows) { | 207 | if (app.mainWindow.isMinimized()) { |
200 | mainWindow.restore(); | 208 | mainWindow.restore(); |
201 | } else if (isLinux) { | ||
202 | mainWindow.show(); | ||
203 | } | 209 | } |
210 | mainWindow.focus(); | ||
211 | |||
212 | debug('Notification click handler'); | ||
204 | } | 213 | } |
205 | }; | 214 | }; |
206 | } | 215 | } |
diff --git a/src/styles/auth.scss b/src/styles/auth.scss index 817801982..0a075036a 100644 --- a/src/styles/auth.scss +++ b/src/styles/auth.scss | |||
@@ -107,7 +107,7 @@ | |||
107 | &__scroll-container { | 107 | &__scroll-container { |
108 | max-height: 100vh; | 108 | max-height: 100vh; |
109 | padding: 80px 0; | 109 | padding: 80px 0; |
110 | overflow: scroll; | 110 | overflow: auto; |
111 | width: 100%; | 111 | width: 100%; |
112 | } | 112 | } |
113 | 113 | ||
diff --git a/src/webview/contextMenu.js b/src/webview/contextMenu.js index afb1d8912..a4a6ab899 100644 --- a/src/webview/contextMenu.js +++ b/src/webview/contextMenu.js | |||
@@ -33,6 +33,8 @@ const buildMenuTpl = (props, suggestions, isSpellcheckEnabled, defaultSpellcheck | |||
33 | const canGoBack = webContents.canGoBack(); | 33 | const canGoBack = webContents.canGoBack(); |
34 | const canGoForward = webContents.canGoForward(); | 34 | const canGoForward = webContents.canGoForward(); |
35 | 35 | ||
36 | // @adlk: we can't use roles here due to a bug with electron where electron.remote.webContents.getFocusedWebContents() returns the first webview in DOM instead of the focused one | ||
37 | // Github issue creation is pending | ||
36 | let menuTpl = [ | 38 | let menuTpl = [ |
37 | { | 39 | { |
38 | type: 'separator', | 40 | type: 'separator', |
@@ -48,19 +50,32 @@ const buildMenuTpl = (props, suggestions, isSpellcheckEnabled, defaultSpellcheck | |||
48 | type: 'separator', | 50 | type: 'separator', |
49 | }, { | 51 | }, { |
50 | id: 'cut', | 52 | id: 'cut', |
51 | role: can('Cut') ? 'cut' : '', | 53 | label: 'Cut', |
54 | click() { | ||
55 | if (can('Cut')) { | ||
56 | webContents.cut(); | ||
57 | } | ||
58 | }, | ||
52 | enabled: can('Cut'), | 59 | enabled: can('Cut'), |
53 | visible: hasText && props.isEditable, | 60 | visible: hasText && props.isEditable, |
54 | }, { | 61 | }, { |
55 | id: 'copy', | 62 | id: 'copy', |
56 | label: 'Copy', | 63 | label: 'Copy', |
57 | role: can('Copy') ? 'copy' : '', | 64 | click() { |
65 | if (can('Copy')) { | ||
66 | webContents.copy(); | ||
67 | } | ||
68 | }, | ||
58 | enabled: can('Copy'), | 69 | enabled: can('Copy'), |
59 | visible: props.isEditable || hasText, | 70 | visible: props.isEditable || hasText, |
60 | }, { | 71 | }, { |
61 | id: 'paste', | 72 | id: 'paste', |
62 | label: 'Paste', | 73 | label: 'Paste', |
63 | role: editFlags.canPaste ? 'paste' : '', | 74 | click() { |
75 | if (editFlags.canPaste) { | ||
76 | webContents.paste(); | ||
77 | } | ||
78 | }, | ||
64 | enabled: editFlags.canPaste, | 79 | enabled: editFlags.canPaste, |
65 | visible: props.isEditable, | 80 | visible: props.isEditable, |
66 | }, { | 81 | }, { |