diff options
-rw-r--r-- | .all-contributorsrc | 56 | ||||
-rw-r--r-- | .gitmodules | 4 | ||||
-rw-r--r-- | .travis.yml | 29 | ||||
-rw-r--r-- | README.md | 33 | ||||
-rw-r--r-- | appveyor.yml | 4 | ||||
-rw-r--r-- | branding/screenshots/hero.png | bin | 352745 -> 321357 bytes | |||
-rw-r--r-- | build-helpers/images/win-app-ico.ico | bin | 4286 -> 162459 bytes | |||
-rw-r--r-- | next_release.md | 44 | ||||
-rw-r--r-- | package-lock.json | 2 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | src/api/apiBase.js | 21 | ||||
-rw-r--r-- | src/api/server/ServerApi.js | 23 | ||||
-rw-r--r-- | src/components/services/content/ServiceView.js | 30 | ||||
-rw-r--r-- | src/components/services/content/ServiceWebview.js | 5 | ||||
-rw-r--r-- | src/components/ui/FeatureList.js | 2 | ||||
-rw-r--r-- | src/config.js | 1 | ||||
-rw-r--r-- | src/lib/Menu.js | 3 | ||||
-rw-r--r-- | src/stores/AppStore.js | 18 | ||||
-rw-r--r-- | src/stores/FeaturesStore.js | 5 | ||||
-rw-r--r-- | src/stores/GlobalErrorStore.js | 52 | ||||
-rw-r--r-- | src/stores/ServicesStore.js | 3 | ||||
-rw-r--r-- | src/stores/UserStore.js | 13 | ||||
-rw-r--r-- | src/stores/lib/CachedRequest.js | 4 | ||||
-rw-r--r-- | src/styles/tabs.scss | 2 |
24 files changed, 267 insertions, 89 deletions
diff --git a/.all-contributorsrc b/.all-contributorsrc index cd9704edf..89c1d6f2a 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc | |||
@@ -1,6 +1,6 @@ | |||
1 | { | 1 | { |
2 | "projectName": "ferdi", | 2 | "projectName": "ferdi", |
3 | "projectOwner": "kytwb", | 3 | "projectOwner": "getferdi", |
4 | "repoType": "github", | 4 | "repoType": "github", |
5 | "repoHost": "https://github.com", | 5 | "repoHost": "https://github.com", |
6 | "files": [ | 6 | "files": [ |
@@ -63,7 +63,8 @@ | |||
63 | "projectManagement", | 63 | "projectManagement", |
64 | "review", | 64 | "review", |
65 | "infra", | 65 | "infra", |
66 | "fundingFinding" | 66 | "fundingFinding", |
67 | "blog" | ||
67 | ] | 68 | ] |
68 | }, | 69 | }, |
69 | { | 70 | { |
@@ -158,7 +159,10 @@ | |||
158 | "contributions": [ | 159 | "contributions": [ |
159 | "bug", | 160 | "bug", |
160 | "code", | 161 | "code", |
161 | "translation" | 162 | "translation", |
163 | "content", | ||
164 | "doc", | ||
165 | "platform" | ||
162 | ] | 166 | ] |
163 | }, | 167 | }, |
164 | { | 168 | { |
@@ -172,6 +176,52 @@ | |||
172 | "infra", | 176 | "infra", |
173 | "platform" | 177 | "platform" |
174 | ] | 178 | ] |
179 | }, | ||
180 | { | ||
181 | "login": "Gaboris", | ||
182 | "name": "Gaboris", | ||
183 | "avatar_url": "https://avatars2.githubusercontent.com/u/9462372?v=4", | ||
184 | "profile": "https://github.com/Gaboris", | ||
185 | "contributions": [ | ||
186 | "question", | ||
187 | "bug" | ||
188 | ] | ||
189 | }, | ||
190 | { | ||
191 | "login": "incace", | ||
192 | "name": "Ce", | ||
193 | "avatar_url": "https://avatars1.githubusercontent.com/u/61343?v=4", | ||
194 | "profile": "http://www.cu3ed.com/", | ||
195 | "contributions": [ | ||
196 | "bug" | ||
197 | ] | ||
198 | }, | ||
199 | { | ||
200 | "login": "pztrn", | ||
201 | "name": "Stanislav N.", | ||
202 | "avatar_url": "https://avatars1.githubusercontent.com/u/869402?v=4", | ||
203 | "profile": "http://pztrn.name/", | ||
204 | "contributions": [ | ||
205 | "bug" | ||
206 | ] | ||
207 | }, | ||
208 | { | ||
209 | "login": "patrickcurl", | ||
210 | "name": "Patrick Curl", | ||
211 | "avatar_url": "https://avatars1.githubusercontent.com/u/1470061?v=4", | ||
212 | "profile": "http://www.patrickcurl.com", | ||
213 | "contributions": [ | ||
214 | "ideas" | ||
215 | ] | ||
216 | }, | ||
217 | { | ||
218 | "login": "Stanzilla", | ||
219 | "name": "Benjamin Staneck", | ||
220 | "avatar_url": "https://avatars3.githubusercontent.com/u/75278?v=4", | ||
221 | "profile": "https://github.com/Stanzilla", | ||
222 | "contributions": [ | ||
223 | "design" | ||
224 | ] | ||
175 | } | 225 | } |
176 | ], | 226 | ], |
177 | "contributorsPerLine": 6 | 227 | "contributorsPerLine": 6 |
diff --git a/.gitmodules b/.gitmodules index 00bc1d26d..d121d6c01 100644 --- a/.gitmodules +++ b/.gitmodules | |||
@@ -1,8 +1,8 @@ | |||
1 | [submodule "recipes"] | 1 | [submodule "recipes"] |
2 | path = recipes | 2 | path = recipes |
3 | url = https://github.com/getferdi/recipes.git | 3 | url = git@github.com:getferdi/recipes.git |
4 | ignore = all | 4 | ignore = all |
5 | [submodule "src/server"] | 5 | [submodule "src/server"] |
6 | path = src/server | 6 | path = src/server |
7 | url = https://github.com/getferdi/internal-server.git | 7 | url = git@github.com:getferdi/internal-server.git |
8 | ignore = all | 8 | ignore = all |
diff --git a/.travis.yml b/.travis.yml index ff015b92c..ba8bc86ac 100644 --- a/.travis.yml +++ b/.travis.yml | |||
@@ -1,18 +1,25 @@ | |||
1 | matrix: | 1 | matrix: |
2 | include: | 2 | include: |
3 | - os: linux | 3 | - os: linux |
4 | dist: xenial | 4 | dist: xenial |
5 | addons: | 5 | addons: |
6 | apt: | 6 | apt: |
7 | packages: | 7 | packages: |
8 | - libx11-dev | 8 | - libx11-dev |
9 | - libxext-dev | 9 | - libxext-dev |
10 | - libxss-dev | 10 | - libxss-dev |
11 | - libxkbfile-dev | 11 | - libxkbfile-dev |
12 | - os: osx | 12 | - os: osx |
13 | osx_image: xcode11 | 13 | osx_image: xcode11 |
14 | 14 | ||
15 | language: node_js | 15 | language: node_js |
16 | # Handle git submodules yourself | ||
17 | git: | ||
18 | submodules: false | ||
19 | # Use sed to replace the SSH URL with the public URL, then initialize submodules | ||
20 | before_install: | ||
21 | - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules; else sed -i '' 's/git@github.com:/https:\/\/github.com\//' .gitmodules; fi | ||
22 | - git submodule update --init --recursive | ||
16 | install: | 23 | install: |
17 | - echo do nothing | 24 | - echo do nothing |
18 | before_script: | 25 | before_script: |
@@ -196,34 +196,37 @@ When pushing a new tag, the CI builds will create a draft GitHub release and upl | |||
196 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): | 196 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): |
197 | 197 | ||
198 | <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> | 198 | <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> |
199 | <!-- prettier-ignore-start --> | 199 | <!-- prettier-ignore --> |
200 | <!-- markdownlint-disable --> | ||
201 | <table> | 200 | <table> |
202 | <tr> | 201 | <tr> |
203 | <td align="center"><a href="https://vantezzen.io"><img src="https://avatars2.githubusercontent.com/u/10333196?v=4" width="40px;" alt="Bennett"/><br /><sub><b>Bennett</b></sub></a><br /><a href="https://github.com/kytwb/ferdi/commits?author=vantezzen" title="Code">💻</a> <a href="#design-vantezzen" title="Design">🎨</a> <a href="https://github.com/kytwb/ferdi/commits?author=vantezzen" title="Documentation">📖</a> <a href="#ideas-vantezzen" title="Ideas, Planning, & Feedback">🤔</a> <a href="#translation-vantezzen" title="Translation">🌍</a> <a href="#example-vantezzen" title="Examples">💡</a> <a href="https://github.com/kytwb/ferdi/issues?q=author%3Avantezzen" title="Bug reports">🐛</a> <a href="#content-vantezzen" title="Content">🖋</a> <a href="#infra-vantezzen" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#userTesting-vantezzen" title="User Testing">📓</a> <a href="#question-vantezzen" title="Answering Questions">💬</a> <a href="#projectManagement-vantezzen" title="Project Management">📆</a> <a href="#review-vantezzen" title="Reviewed Pull Requests">👀</a></td> | 202 | <td align="center"><a href="https://vantezzen.io"><img src="https://avatars2.githubusercontent.com/u/10333196?v=4" width="40px;" alt="Bennett"/><br /><sub><b>Bennett</b></sub></a><br /><a href="https://github.com/getferdi/ferdi/commits?author=vantezzen" title="Code">💻</a> <a href="#design-vantezzen" title="Design">🎨</a> <a href="https://github.com/getferdi/ferdi/commits?author=vantezzen" title="Documentation">📖</a> <a href="#ideas-vantezzen" title="Ideas, Planning, & Feedback">🤔</a> <a href="#translation-vantezzen" title="Translation">🌍</a> <a href="#example-vantezzen" title="Examples">💡</a> <a href="https://github.com/getferdi/ferdi/issues?q=author%3Avantezzen" title="Bug reports">🐛</a> <a href="#content-vantezzen" title="Content">🖋</a> <a href="#infra-vantezzen" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#userTesting-vantezzen" title="User Testing">📓</a> <a href="#question-vantezzen" title="Answering Questions">💬</a> <a href="#projectManagement-vantezzen" title="Project Management">📆</a> <a href="#review-vantezzen" title="Reviewed Pull Requests">👀</a></td> |
204 | <td align="center"><a href="http://www.adlk.io"><img src="https://avatars1.githubusercontent.com/u/3265004?v=4" width="40px;" alt="Stefan Malzner"/><br /><sub><b>Stefan Malzner</b></sub></a><br /><a href="https://github.com/kytwb/ferdi/commits?author=adlk" title="Code">💻</a> <a href="#content-adlk" title="Content">🖋</a> <a href="#design-adlk" title="Design">🎨</a> <a href="https://github.com/kytwb/ferdi/commits?author=adlk" title="Documentation">📖</a> <a href="#ideas-adlk" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-adlk" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#projectManagement-adlk" title="Project Management">📆</a> <a href="https://github.com/kytwb/ferdi/commits?author=adlk" title="Tests">⚠️</a> <a href="#translation-adlk" title="Translation">🌍</a></td> | 203 | <td align="center"><a href="http://www.adlk.io"><img src="https://avatars1.githubusercontent.com/u/3265004?v=4" width="40px;" alt="Stefan Malzner"/><br /><sub><b>Stefan Malzner</b></sub></a><br /><a href="https://github.com/getferdi/ferdi/commits?author=adlk" title="Code">💻</a> <a href="#content-adlk" title="Content">🖋</a> <a href="#design-adlk" title="Design">🎨</a> <a href="https://github.com/getferdi/ferdi/commits?author=adlk" title="Documentation">📖</a> <a href="#ideas-adlk" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-adlk" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#projectManagement-adlk" title="Project Management">📆</a> <a href="https://github.com/getferdi/ferdi/commits?author=adlk" title="Tests">⚠️</a> <a href="#translation-adlk" title="Translation">🌍</a></td> |
205 | <td align="center"><a href="https://twitter.com/kytwb"><img src="https://avatars0.githubusercontent.com/u/412895?v=4" width="40px;" alt="Amine Mouafik"/><br /><sub><b>Amine Mouafik</b></sub></a><br /><a href="#question-kytwb" title="Answering Questions">💬</a> <a href="https://github.com/kytwb/ferdi/commits?author=kytwb" title="Code">💻</a> <a href="https://github.com/kytwb/ferdi/commits?author=kytwb" title="Documentation">📖</a> <a href="#ideas-kytwb" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-kytwb" title="Maintenance">🚧</a> <a href="#platform-kytwb" title="Packaging/porting to new platform">📦</a> <a href="#projectManagement-kytwb" title="Project Management">📆</a> <a href="#review-kytwb" title="Reviewed Pull Requests">👀</a> <a href="#infra-kytwb" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#fundingFinding-kytwb" title="Funding Finding">🔍</a></td> | 204 | <td align="center"><a href="https://twitter.com/kytwb"><img src="https://avatars0.githubusercontent.com/u/412895?v=4" width="40px;" alt="Amine Mouafik"/><br /><sub><b>Amine Mouafik</b></sub></a><br /><a href="#question-kytwb" title="Answering Questions">💬</a> <a href="https://github.com/getferdi/ferdi/commits?author=kytwb" title="Code">💻</a> <a href="https://github.com/getferdi/ferdi/commits?author=kytwb" title="Documentation">📖</a> <a href="#ideas-kytwb" title="Ideas, Planning, & Feedback">🤔</a> <a href="#maintenance-kytwb" title="Maintenance">🚧</a> <a href="#platform-kytwb" title="Packaging/porting to new platform">📦</a> <a href="#projectManagement-kytwb" title="Project Management">📆</a> <a href="#review-kytwb" title="Reviewed Pull Requests">👀</a> <a href="#infra-kytwb" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#fundingFinding-kytwb" title="Funding Finding">🔍</a> <a href="#blog-kytwb" title="Blogposts">📝</a></td> |
206 | <td align="center"><a href="http://seriesgt.com"><img src="https://avatars3.githubusercontent.com/u/5977640?v=4" width="40px;" alt="ZeroCool"/><br /><sub><b>ZeroCool</b></sub></a><br /><a href="https://github.com/kytwb/ferdi/commits?author=ZeroCool940711" title="Code">💻</a> <a href="#ideas-ZeroCool940711" title="Ideas, Planning, & Feedback">🤔</a></td> | 205 | <td align="center"><a href="http://seriesgt.com"><img src="https://avatars3.githubusercontent.com/u/5977640?v=4" width="40px;" alt="ZeroCool"/><br /><sub><b>ZeroCool</b></sub></a><br /><a href="https://github.com/getferdi/ferdi/commits?author=ZeroCool940711" title="Code">💻</a> <a href="#ideas-ZeroCool940711" title="Ideas, Planning, & Feedback">🤔</a></td> |
207 | <td align="center"><a href="https://github.com/rseitbekov"><img src="https://avatars2.githubusercontent.com/u/35684439?v=4" width="40px;" alt="rseitbekov"/><br /><sub><b>rseitbekov</b></sub></a><br /><a href="https://github.com/kytwb/ferdi/commits?author=rseitbekov" title="Code">💻</a></td> | 206 | <td align="center"><a href="https://github.com/rseitbekov"><img src="https://avatars2.githubusercontent.com/u/35684439?v=4" width="40px;" alt="rseitbekov"/><br /><sub><b>rseitbekov</b></sub></a><br /><a href="https://github.com/getferdi/ferdi/commits?author=rseitbekov" title="Code">💻</a></td> |
208 | <td align="center"><a href="https://djangogigs.com/developers/peter-bittner/"><img src="https://avatars2.githubusercontent.com/u/665072?v=4" width="40px;" alt="Peter Bittner"/><br /><sub><b>Peter Bittner</b></sub></a><br /><a href="#ideas-bittner" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/kytwb/ferdi/issues?q=author%3Abittner" title="Bug reports">🐛</a></td> | 207 | <td align="center"><a href="https://djangogigs.com/developers/peter-bittner/"><img src="https://avatars2.githubusercontent.com/u/665072?v=4" width="40px;" alt="Peter Bittner"/><br /><sub><b>Peter Bittner</b></sub></a><br /><a href="#ideas-bittner" title="Ideas, Planning, & Feedback">🤔</a> <a href="https://github.com/getferdi/ferdi/issues?q=author%3Abittner" title="Bug reports">🐛</a></td> |
209 | </tr> | 208 | </tr> |
210 | <tr> | 209 | <tr> |
211 | <td align="center"><a href="https://github.com/justus-saul"><img src="https://avatars1.githubusercontent.com/u/5861826?v=4" width="40px;" alt="Justus Saul"/><br /><sub><b>Justus Saul</b></sub></a><br /><a href="https://github.com/kytwb/ferdi/issues?q=author%3Ajustus-saul" title="Bug reports">🐛</a> <a href="#ideas-justus-saul" title="Ideas, Planning, & Feedback">🤔</a></td> | 210 | <td align="center"><a href="https://github.com/justus-saul"><img src="https://avatars1.githubusercontent.com/u/5861826?v=4" width="40px;" alt="Justus Saul"/><br /><sub><b>Justus Saul</b></sub></a><br /><a href="https://github.com/getferdi/ferdi/issues?q=author%3Ajustus-saul" title="Bug reports">🐛</a> <a href="#ideas-justus-saul" title="Ideas, Planning, & Feedback">🤔</a></td> |
212 | <td align="center"><a href="https://github.com/igreil"><img src="https://avatars0.githubusercontent.com/u/17239151?v=4" width="40px;" alt="igreil"/><br /><sub><b>igreil</b></sub></a><br /><a href="#ideas-igreil" title="Ideas, Planning, & Feedback">🤔</a></td> | 211 | <td align="center"><a href="https://github.com/igreil"><img src="https://avatars0.githubusercontent.com/u/17239151?v=4" width="40px;" alt="igreil"/><br /><sub><b>igreil</b></sub></a><br /><a href="#ideas-igreil" title="Ideas, Planning, & Feedback">🤔</a></td> |
213 | <td align="center"><a href="http://marcolopes.eu"><img src="https://avatars1.githubusercontent.com/u/431889?v=4" width="40px;" alt="Marco Lopes"/><br /><sub><b>Marco Lopes</b></sub></a><br /><a href="#ideas-marcolopes" title="Ideas, Planning, & Feedback">🤔</a></td> | 212 | <td align="center"><a href="http://marcolopes.eu"><img src="https://avatars1.githubusercontent.com/u/431889?v=4" width="40px;" alt="Marco Lopes"/><br /><sub><b>Marco Lopes</b></sub></a><br /><a href="#ideas-marcolopes" title="Ideas, Planning, & Feedback">🤔</a></td> |
214 | <td align="center"><a href="https://github.com/dayzlun"><img src="https://avatars3.githubusercontent.com/u/17259690?v=4" width="40px;" alt="dayzlun"/><br /><sub><b>dayzlun</b></sub></a><br /><a href="https://github.com/kytwb/ferdi/issues?q=author%3Adayzlun" title="Bug reports">🐛</a></td> | 213 | <td align="center"><a href="https://github.com/dayzlun"><img src="https://avatars3.githubusercontent.com/u/17259690?v=4" width="40px;" alt="dayzlun"/><br /><sub><b>dayzlun</b></sub></a><br /><a href="https://github.com/getferdi/ferdi/issues?q=author%3Adayzlun" title="Bug reports">🐛</a></td> |
215 | <td align="center"><a href="https://twitter.com/tobigue_"><img src="https://avatars2.githubusercontent.com/u/1560152?v=4" width="40px;" alt="Tobias Günther"/><br /><sub><b>Tobias Günther</b></sub></a><br /><a href="#ideas-tobigue" title="Ideas, Planning, & Feedback">🤔</a></td> | 214 | <td align="center"><a href="https://twitter.com/tobigue_"><img src="https://avatars2.githubusercontent.com/u/1560152?v=4" width="40px;" alt="Tobias Günther"/><br /><sub><b>Tobias Günther</b></sub></a><br /><a href="#ideas-tobigue" title="Ideas, Planning, & Feedback">🤔</a></td> |
216 | <td align="center"><a href="https://github.com/AGCaesar"><img src="https://avatars3.githubusercontent.com/u/7844066?v=4" width="40px;" alt="AGCaesar"/><br /><sub><b>AGCaesar</b></sub></a><br /><a href="#platform-AGCaesar" title="Packaging/porting to new platform">📦</a></td> | 215 | <td align="center"><a href="https://github.com/AGCaesar"><img src="https://avatars3.githubusercontent.com/u/7844066?v=4" width="40px;" alt="AGCaesar"/><br /><sub><b>AGCaesar</b></sub></a><br /><a href="#platform-AGCaesar" title="Packaging/porting to new platform">📦</a></td> |
217 | </tr> | 216 | </tr> |
218 | <tr> | 217 | <tr> |
219 | <td align="center"><a href="https://github.com/Makazzz"><img src="https://avatars2.githubusercontent.com/u/49844464?v=4" width="40px;" alt="Makazzz"/><br /><sub><b>Makazzz</b></sub></a><br /><a href="https://github.com/kytwb/ferdi/issues?q=author%3AMakazzz" title="Bug reports">🐛</a> <a href="https://github.com/kytwb/ferdi/commits?author=Makazzz" title="Code">💻</a> <a href="#translation-Makazzz" title="Translation">🌍</a></td> | 218 | <td align="center"><a href="https://github.com/Makazzz"><img src="https://avatars2.githubusercontent.com/u/49844464?v=4" width="40px;" alt="Makazzz"/><br /><sub><b>Makazzz</b></sub></a><br /><a href="https://github.com/getferdi/ferdi/issues?q=author%3AMakazzz" title="Bug reports">🐛</a> <a href="https://github.com/getferdi/ferdi/commits?author=Makazzz" title="Code">💻</a> <a href="#translation-Makazzz" title="Translation">🌍</a> <a href="#content-Makazzz" title="Content">🖋</a> <a href="https://github.com/getferdi/ferdi/commits?author=Makazzz" title="Documentation">📖</a> <a href="#platform-Makazzz" title="Packaging/porting to new platform">📦</a></td> |
220 | <td align="center"><a href="https://github.com/xthursdayx"><img src="https://avatars0.githubusercontent.com/u/18044308?v=4" width="40px;" alt="xthursdayx"/><br /><sub><b>xthursdayx</b></sub></a><br /><a href="https://github.com/kytwb/ferdi/commits?author=xthursdayx" title="Code">💻</a> <a href="https://github.com/kytwb/ferdi/commits?author=xthursdayx" title="Documentation">📖</a> <a href="#infra-xthursdayx" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#platform-xthursdayx" title="Packaging/porting to new platform">📦</a></td> | 219 | <td align="center"><a href="https://github.com/xthursdayx"><img src="https://avatars0.githubusercontent.com/u/18044308?v=4" width="40px;" alt="xthursdayx"/><br /><sub><b>xthursdayx</b></sub></a><br /><a href="https://github.com/getferdi/ferdi/commits?author=xthursdayx" title="Code">💻</a> <a href="https://github.com/getferdi/ferdi/commits?author=xthursdayx" title="Documentation">📖</a> <a href="#infra-xthursdayx" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#platform-xthursdayx" title="Packaging/porting to new platform">📦</a></td> |
220 | <td align="center"><a href="https://github.com/Gaboris"><img src="https://avatars2.githubusercontent.com/u/9462372?v=4" width="40px;" alt="Gaboris"/><br /><sub><b>Gaboris</b></sub></a><br /><a href="#question-Gaboris" title="Answering Questions">💬</a> <a href="https://github.com/getferdi/ferdi/issues?q=author%3AGaboris" title="Bug reports">🐛</a></td> | ||
221 | <td align="center"><a href="http://www.cu3ed.com/"><img src="https://avatars1.githubusercontent.com/u/61343?v=4" width="40px;" alt="Ce"/><br /><sub><b>Ce</b></sub></a><br /><a href="https://github.com/getferdi/ferdi/issues?q=author%3Aincace" title="Bug reports">🐛</a></td> | ||
222 | <td align="center"><a href="http://pztrn.name/"><img src="https://avatars1.githubusercontent.com/u/869402?v=4" width="40px;" alt="Stanislav N."/><br /><sub><b>Stanislav N.</b></sub></a><br /><a href="https://github.com/getferdi/ferdi/issues?q=author%3Apztrn" title="Bug reports">🐛</a></td> | ||
223 | <td align="center"><a href="http://www.patrickcurl.com"><img src="https://avatars1.githubusercontent.com/u/1470061?v=4" width="40px;" alt="Patrick Curl"/><br /><sub><b>Patrick Curl</b></sub></a><br /><a href="#ideas-patrickcurl" title="Ideas, Planning, & Feedback">🤔</a></td> | ||
224 | </tr> | ||
225 | <tr> | ||
226 | <td align="center"><a href="https://github.com/Stanzilla"><img src="https://avatars3.githubusercontent.com/u/75278?v=4" width="40px;" alt="Benjamin Staneck"/><br /><sub><b>Benjamin Staneck</b></sub></a><br /><a href="#design-Stanzilla" title="Design">🎨</a></td> | ||
221 | </tr> | 227 | </tr> |
222 | </table> | 228 | </table> |
223 | 229 | ||
224 | <!-- markdownlint-enable --> | ||
225 | <!-- prettier-ignore-end --> | ||
226 | |||
227 | <!-- ALL-CONTRIBUTORS-LIST:END --> | 230 | <!-- ALL-CONTRIBUTORS-LIST:END --> |
228 | 231 | ||
229 | <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> | 232 | <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --> |
diff --git a/appveyor.yml b/appveyor.yml index 1034565ed..5d2e0c6bd 100644 --- a/appveyor.yml +++ b/appveyor.yml | |||
@@ -4,6 +4,10 @@ environment: | |||
4 | version: 5.0.1.{build} | 4 | version: 5.0.1.{build} |
5 | 5 | ||
6 | install: | 6 | install: |
7 | - ps: $fileContent = "-----BEGIN RSA PRIVATE KEY-----`n" | ||
8 | - ps: $fileContent += $env:priv_key.Replace(' ', "`n") | ||
9 | - ps: $fileContent += "`n-----END RSA PRIVATE KEY-----`n" | ||
10 | - ps: Set-Content $env:userprofile\.ssh\id_rsa $fileContent | ||
7 | - git submodule update --init --recursive | 11 | - git submodule update --init --recursive |
8 | - ps: Install-Product node 10 | 12 | - ps: Install-Product node 10 |
9 | - npx lerna bootstrap | 13 | - npx lerna bootstrap |
diff --git a/branding/screenshots/hero.png b/branding/screenshots/hero.png index f21e2abb6..09f509ca7 100644 --- a/branding/screenshots/hero.png +++ b/branding/screenshots/hero.png | |||
Binary files differ | |||
diff --git a/build-helpers/images/win-app-ico.ico b/build-helpers/images/win-app-ico.ico index 658826324..3731f6425 100644 --- a/build-helpers/images/win-app-ico.ico +++ b/build-helpers/images/win-app-ico.ico | |||
Binary files differ | |||
diff --git a/next_release.md b/next_release.md new file mode 100644 index 000000000..0e4bc411b --- /dev/null +++ b/next_release.md | |||
@@ -0,0 +1,44 @@ | |||
1 | # Next release | ||
2 | Infos about the next release: | ||
3 | |||
4 | ## Beta | ||
5 | v5.4.0-beta.5: | ||
6 | - Updated translations | ||
7 | - Remove "&" sign from window menu bar (#65) | ||
8 | - Extend debug information | ||
9 | - Use SSH for submodules | ||
10 | - Move hibernation indicator to bottom left (#129 (comment)) | ||
11 | - Add fix for 1.1.1.1 hack (#146) | ||
12 | - Fix darkmode not loading correctly (#158) | ||
13 | |||
14 | ## Minor | ||
15 | v5.4.0 | ||
16 | |||
17 | ### Features | ||
18 | - **Merge Franz 5.4.0** | ||
19 | - **Use Ferdi without an Account**: Simply choose "Use Ferdi without an Account" on the login screen | ||
20 | - **Accent color**: Change Ferdi's accent color | ||
21 | - **Darkmode**: Easily open and edit any service's `darkmode.css` through the new "Open darkmode.css" button | ||
22 | - **Hibernation**: Activate service hibernation to save battery | ||
23 | - **Smaller file size**: Ferdi is now 17% smaller | ||
24 | - **Annoucements**: Always get notified about the latest features of Ferdi | ||
25 | - **Navigation bar**: Add option to always show a service navigation bar | ||
26 | |||
27 | ### Minor changes | ||
28 | - Sorting applications in QuickSwitch by last used | ||
29 | - Add info about teams only being available on Franz servers | ||
30 | - Add toggle to disable dark mode on per-service basis | ||
31 | - Add toggle to disable universal Dark Mode | ||
32 | - Improve switching between accounts | ||
33 | - Extend debug information | ||
34 | - Add fix for 1.1.1.1 hack (#146) | ||
35 | |||
36 | ### Bug fixes | ||
37 | - Fix universal darkmode for WhatsApp and Threema QR Codes | ||
38 | - Fix darkmode not activating on reload | ||
39 | - Fix disabling/enabling service not correctly reloading webview (#116) | ||
40 | - Remove "&" sign from window menu bar (#65) | ||
41 | |||
42 | ### Changes in building Ferdi | ||
43 | - Update Building Node Version | ||
44 | - Use SSH for submodules \ No newline at end of file | ||
diff --git a/package-lock.json b/package-lock.json index 2cbbe8939..a5b797e14 100644 --- a/package-lock.json +++ b/package-lock.json | |||
@@ -1,6 +1,6 @@ | |||
1 | { | 1 | { |
2 | "name": "ferdi", | 2 | "name": "ferdi", |
3 | "version": "5.4.0-beta.2", | 3 | "version": "5.4.0-beta.5", |
4 | "lockfileVersion": 1, | 4 | "lockfileVersion": 1, |
5 | "requires": true, | 5 | "requires": true, |
6 | "dependencies": { | 6 | "dependencies": { |
diff --git a/package.json b/package.json index b26986270..6bafa0f2b 100644 --- a/package.json +++ b/package.json | |||
@@ -2,7 +2,7 @@ | |||
2 | "name": "ferdi", | 2 | "name": "ferdi", |
3 | "productName": "Ferdi", | 3 | "productName": "Ferdi", |
4 | "appId": "com.kytwb.ferdi", | 4 | "appId": "com.kytwb.ferdi", |
5 | "version": "5.4.0-beta.3", | 5 | "version": "5.4.0-beta.5", |
6 | "description": "Messaging app for WhatsApp, Slack, Telegram, HipChat, Hangouts and many many more.", | 6 | "description": "Messaging app for WhatsApp, Slack, Telegram, HipChat, Hangouts and many many more.", |
7 | "copyright": "kytwb", | 7 | "copyright": "kytwb", |
8 | "main": "index.js", | 8 | "main": "index.js", |
diff --git a/src/api/apiBase.js b/src/api/apiBase.js index 561b025f0..85dd0f3df 100644 --- a/src/api/apiBase.js +++ b/src/api/apiBase.js | |||
@@ -6,25 +6,19 @@ import { | |||
6 | } from '../environment'; | 6 | } from '../environment'; |
7 | import { | 7 | import { |
8 | LOCAL_SERVER, | 8 | LOCAL_SERVER, |
9 | SERVER_NOT_LOADED, | ||
9 | } from '../config'; | 10 | } from '../config'; |
10 | 11 | ||
11 | const apiBase = () => { | 12 | const apiBase = (withVersion = true) => { |
12 | let url; | 13 | let url; |
13 | 14 | ||
14 | if (!window.ferdi | 15 | if (!window.ferdi |
15 | || !window.ferdi.stores.settings | 16 | || !window.ferdi.stores.settings |
16 | || !window.ferdi.stores.settings.all | 17 | || !window.ferdi.stores.settings.all |
17 | || !window.ferdi.stores.settings.all.app.server) { | 18 | || !window.ferdi.stores.settings.all.app.server) { |
18 | // Stores have not yet been loaded - send invalid URL to force a retry when stores are loaded | 19 | // Stores have not yet been loaded - return SERVER_NOT_LOADED to force a retry when stores are loaded |
19 | // "Why 1.1.1.1 as the default, invalid URL?" | 20 | return SERVER_NOT_LOADED; |
20 | // 1.1.1.1 is the server for Cloudflare's DNS service and will be the same across most networks. | 21 | } if (window.ferdi.stores.settings.all.app.server === LOCAL_SERVER) { |
21 | // Using a random IP could result in unwanted connections, using localhost could unwantedly | ||
22 | // connect to local develoment servers. | ||
23 | // 1.1.1.1 also sends a status 400 response for invalid routes. Other servers may return status 401 | ||
24 | // on some routes. This would result in Ferdi deleting its current authToken as it thinks it | ||
25 | // has gone invalid. | ||
26 | url = 'https://1.1.1.1'; | ||
27 | } else if (window.ferdi.stores.settings.all.app.server === LOCAL_SERVER) { | ||
28 | // Use URL for local server | 22 | // Use URL for local server |
29 | url = `http://127.0.0.1:${window.ferdi.stores.requests.localServerPort}`; | 23 | url = `http://127.0.0.1:${window.ferdi.stores.requests.localServerPort}`; |
30 | } else { | 24 | } else { |
@@ -32,7 +26,10 @@ const apiBase = () => { | |||
32 | url = window.ferdi.stores.settings.all.app.server; | 26 | url = window.ferdi.stores.settings.all.app.server; |
33 | } | 27 | } |
34 | 28 | ||
35 | return `${url}/${API_VERSION}`; | 29 | if (withVersion) { |
30 | return `${url}/${API_VERSION}`; | ||
31 | } | ||
32 | return url; | ||
36 | }; | 33 | }; |
37 | 34 | ||
38 | export default apiBase; | 35 | export default apiBase; |
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index a5d636b4e..164bc237b 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js | |||
@@ -14,8 +14,7 @@ import OrderModel from '../../models/Order'; | |||
14 | 14 | ||
15 | import { sleep } from '../../helpers/async-helpers'; | 15 | import { sleep } from '../../helpers/async-helpers'; |
16 | 16 | ||
17 | import { API } from '../../environment'; | 17 | import { RECIPES_PATH, SERVER_NOT_LOADED } from '../../config'; |
18 | import { RECIPES_PATH } from '../../config'; | ||
19 | import apiBase from '../apiBase'; | 18 | import apiBase from '../apiBase'; |
20 | import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; | 19 | import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; |
21 | 20 | ||
@@ -39,8 +38,6 @@ module.paths.unshift( | |||
39 | const { app } = remote; | 38 | const { app } = remote; |
40 | const { default: fetch } = remote.require('electron-fetch'); | 39 | const { default: fetch } = remote.require('electron-fetch'); |
41 | 40 | ||
42 | const SERVER_URL = API; | ||
43 | |||
44 | export default class ServerApi { | 41 | export default class ServerApi { |
45 | recipePreviews = []; | 42 | recipePreviews = []; |
46 | 43 | ||
@@ -121,6 +118,10 @@ export default class ServerApi { | |||
121 | } | 118 | } |
122 | 119 | ||
123 | async userInfo() { | 120 | async userInfo() { |
121 | if (apiBase() === SERVER_NOT_LOADED) { | ||
122 | throw new Error('Server not loaded'); | ||
123 | } | ||
124 | |||
124 | const request = await sendAuthRequest(`${apiBase()}/me`); | 125 | const request = await sendAuthRequest(`${apiBase()}/me`); |
125 | if (!request.ok) { | 126 | if (!request.ok) { |
126 | throw request; | 127 | throw request; |
@@ -163,6 +164,10 @@ export default class ServerApi { | |||
163 | 164 | ||
164 | // Services | 165 | // Services |
165 | async getServices() { | 166 | async getServices() { |
167 | if (apiBase() === SERVER_NOT_LOADED) { | ||
168 | throw new Error('Server not loaded'); | ||
169 | } | ||
170 | |||
166 | const request = await sendAuthRequest(`${apiBase()}/me/services`); | 171 | const request = await sendAuthRequest(`${apiBase()}/me/services`); |
167 | if (!request.ok) { | 172 | if (!request.ok) { |
168 | throw request; | 173 | throw request; |
@@ -287,6 +292,10 @@ export default class ServerApi { | |||
287 | } | 292 | } |
288 | 293 | ||
289 | async getFeatures() { | 294 | async getFeatures() { |
295 | if (apiBase() === SERVER_NOT_LOADED) { | ||
296 | throw new Error('Server not loaded'); | ||
297 | } | ||
298 | |||
290 | const request = await sendAuthRequest(`${apiBase()}/features`); | 299 | const request = await sendAuthRequest(`${apiBase()}/features`); |
291 | if (!request.ok) { | 300 | if (!request.ok) { |
292 | throw request; | 301 | throw request; |
@@ -466,7 +475,11 @@ export default class ServerApi { | |||
466 | 475 | ||
467 | // Health Check | 476 | // Health Check |
468 | async healthCheck() { | 477 | async healthCheck() { |
469 | const request = await sendAuthRequest(`${SERVER_URL}/health`, { | 478 | if (apiBase() === SERVER_NOT_LOADED) { |
479 | throw new Error('Server not loaded'); | ||
480 | } | ||
481 | |||
482 | const request = await sendAuthRequest(`${apiBase(false)}/health`, { | ||
470 | method: 'GET', | 483 | method: 'GET', |
471 | }, false); | 484 | }, false); |
472 | if (!request.ok) { | 485 | if (!request.ok) { |
diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js index 49ee24361..1fff5ef7a 100644 --- a/src/components/services/content/ServiceView.js +++ b/src/components/services/content/ServiceView.js | |||
@@ -42,10 +42,10 @@ export default @inject('stores', 'actions') @observer class ServiceView extends | |||
42 | forceRepaint: false, | 42 | forceRepaint: false, |
43 | targetUrl: '', | 43 | targetUrl: '', |
44 | statusBarVisible: false, | 44 | statusBarVisible: false, |
45 | hibernate: false, | ||
46 | hibernationTimer: null, | ||
47 | }; | 45 | }; |
48 | 46 | ||
47 | hibernationTimer = null; | ||
48 | |||
49 | autorunDisposer = null; | 49 | autorunDisposer = null; |
50 | 50 | ||
51 | forceRepaintTimeout = null; | 51 | forceRepaintTimeout = null; |
@@ -73,15 +73,12 @@ export default @inject('stores', 'actions') @observer class ServiceView extends | |||
73 | // Service is inactive - start hibernation countdown | 73 | // Service is inactive - start hibernation countdown |
74 | this.startHibernationTimer(); | 74 | this.startHibernationTimer(); |
75 | } else { | 75 | } else { |
76 | if (this.state.hibernationTimer) { | 76 | if (this.hibernationTimer) { |
77 | // Service is active but we have an active hibernation timer: Clear timeout | 77 | // Service is active but we have an active hibernation timer: Clear timeout |
78 | clearTimeout(this.state.hibernationTimer); | 78 | clearTimeout(this.hibernationTimer); |
79 | } | 79 | } |
80 | 80 | ||
81 | // Service is active, wake up service from hibernation | 81 | // Service is active, wake up service from hibernation |
82 | this.setState({ | ||
83 | hibernate: false, | ||
84 | }); | ||
85 | this.props.actions.service.setHibernation({ | 82 | this.props.actions.service.setHibernation({ |
86 | serviceId: this.props.service.id, | 83 | serviceId: this.props.service.id, |
87 | hibernating: false, | 84 | hibernating: false, |
@@ -90,16 +87,6 @@ export default @inject('stores', 'actions') @observer class ServiceView extends | |||
90 | }, | 87 | }, |
91 | ); | 88 | ); |
92 | 89 | ||
93 | // Store hibernation status to state, otherwise the webview won't get unloaded correctly | ||
94 | reaction( | ||
95 | () => this.props.service.isHibernating, | ||
96 | () => { | ||
97 | this.setState({ | ||
98 | hibernate: this.props.service.isHibernating, | ||
99 | }); | ||
100 | }, | ||
101 | ); | ||
102 | |||
103 | // Start hibernation counter if we are in background | 90 | // Start hibernation counter if we are in background |
104 | if (!this.props.service.isActive && this.props.stores.settings.all.app.hibernate) { | 91 | if (!this.props.service.isActive && this.props.stores.settings.all.app.hibernate) { |
105 | this.startHibernationTimer(); | 92 | this.startHibernationTimer(); |
@@ -126,18 +113,13 @@ export default @inject('stores', 'actions') @observer class ServiceView extends | |||
126 | const timerDuration = (Number(this.props.stores.settings.all.app.hibernationStrategy) || 300) * 1000; | 113 | const timerDuration = (Number(this.props.stores.settings.all.app.hibernationStrategy) || 300) * 1000; |
127 | 114 | ||
128 | const hibernationTimer = setTimeout(() => { | 115 | const hibernationTimer = setTimeout(() => { |
129 | this.setState({ | ||
130 | hibernate: true, | ||
131 | }); | ||
132 | this.props.actions.service.setHibernation({ | 116 | this.props.actions.service.setHibernation({ |
133 | serviceId: this.props.service.id, | 117 | serviceId: this.props.service.id, |
134 | hibernating: true, | 118 | hibernating: true, |
135 | }); | 119 | }); |
136 | }, timerDuration); | 120 | }, timerDuration); |
137 | 121 | ||
138 | this.setState({ | 122 | this.hibernationTimer = hibernationTimer; |
139 | hibernationTimer, | ||
140 | }); | ||
141 | } | 123 | } |
142 | 124 | ||
143 | render() { | 125 | render() { |
@@ -208,7 +190,7 @@ export default @inject('stores', 'actions') @observer class ServiceView extends | |||
208 | </Fragment> | 190 | </Fragment> |
209 | ) : ( | 191 | ) : ( |
210 | <> | 192 | <> |
211 | {!this.state.hibernate ? ( | 193 | {!service.isHibernating ? ( |
212 | <> | 194 | <> |
213 | {(service.recipe.id === CUSTOM_WEBSITE_ID || showServiceNavigationBar) && ( | 195 | {(service.recipe.id === CUSTOM_WEBSITE_ID || showServiceNavigationBar) && ( |
214 | <WebControlsScreen service={service} /> | 196 | <WebControlsScreen service={service} /> |
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index e6ebb6afb..652647470 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js | |||
@@ -3,6 +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 | 7 | ||
7 | import ServiceModel from '../../../models/Service'; | 8 | import ServiceModel from '../../../models/Service'; |
8 | 9 | ||
@@ -51,6 +52,8 @@ class ServiceWebview extends Component { | |||
51 | setWebviewReference, | 52 | setWebviewReference, |
52 | } = this.props; | 53 | } = this.props; |
53 | 54 | ||
55 | const preloadScript = path.join(__dirname, '../../../', 'webview', 'recipe.js'); | ||
56 | |||
54 | return ( | 57 | return ( |
55 | <ElectronWebView | 58 | <ElectronWebView |
56 | ref={(webview) => { | 59 | ref={(webview) => { |
@@ -61,7 +64,7 @@ class ServiceWebview extends Component { | |||
61 | }} | 64 | }} |
62 | autosize | 65 | autosize |
63 | src={service.url} | 66 | src={service.url} |
64 | preload="./webview/recipe.js" | 67 | preload={preloadScript} |
65 | partition={`persist:service-${service.id}`} | 68 | partition={`persist:service-${service.id}`} |
66 | onDidAttach={() => { | 69 | onDidAttach={() => { |
67 | setWebviewReference({ | 70 | setWebviewReference({ |
diff --git a/src/components/ui/FeatureList.js b/src/components/ui/FeatureList.js index 7ba8b54d7..f1039709c 100644 --- a/src/components/ui/FeatureList.js +++ b/src/components/ui/FeatureList.js | |||
@@ -72,7 +72,7 @@ export class FeatureList extends Component { | |||
72 | static propTypes = { | 72 | static propTypes = { |
73 | className: PropTypes.string, | 73 | className: PropTypes.string, |
74 | featureClassName: PropTypes.string, | 74 | featureClassName: PropTypes.string, |
75 | plan: PropTypes.oneOf(PLANS), | 75 | plan: PropTypes.oneOf(Object.values(PLANS)), |
76 | }; | 76 | }; |
77 | 77 | ||
78 | static defaultProps = { | 78 | static defaultProps = { |
diff --git a/src/config.js b/src/config.js index 761d26eea..1db881d35 100644 --- a/src/config.js +++ b/src/config.js | |||
@@ -112,6 +112,7 @@ export const FILE_SYSTEM_SETTINGS_TYPES = [ | |||
112 | ]; | 112 | ]; |
113 | 113 | ||
114 | export const LOCAL_SERVER = 'You are using Ferdi without a server'; | 114 | export const LOCAL_SERVER = 'You are using Ferdi without a server'; |
115 | export const SERVER_NOT_LOADED = 'Ferdi::SERVER_NOT_LOADED'; | ||
115 | 116 | ||
116 | export const SETTINGS_PATH = path.join(app.getPath('userData'), 'config'); | 117 | export const SETTINGS_PATH = path.join(app.getPath('userData'), 'config'); |
117 | 118 | ||
diff --git a/src/lib/Menu.js b/src/lib/Menu.js index f3fbb0c73..826fe843f 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js | |||
@@ -678,7 +678,8 @@ const _titleBarTemplateFactory = intl => [ | |||
678 | ], | 678 | ], |
679 | }, | 679 | }, |
680 | { | 680 | { |
681 | label: '&?', | 681 | label: '?', |
682 | accelerator: 'Alt+?', | ||
682 | submenu: [ | 683 | submenu: [ |
683 | { | 684 | { |
684 | label: intl.formatMessage(menuItems.learnMore), | 685 | label: intl.formatMessage(menuItems.learnMore), |
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index 59b100b55..0756a05eb 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -181,7 +181,9 @@ export default class AppStore extends Store { | |||
181 | 181 | ||
182 | this.locale = this._getDefaultLocale(); | 182 | this.locale = this._getDefaultLocale(); |
183 | 183 | ||
184 | this._healthCheck(); | 184 | setTimeout(() => { |
185 | this._healthCheck(); | ||
186 | }, 1000); | ||
185 | 187 | ||
186 | this.isSystemDarkModeEnabled = systemPreferences.isDarkMode(); | 188 | this.isSystemDarkModeEnabled = systemPreferences.isDarkMode(); |
187 | 189 | ||
@@ -227,6 +229,9 @@ export default class AppStore extends Store { | |||
227 | } | 229 | } |
228 | 230 | ||
229 | @computed get debugInfo() { | 231 | @computed get debugInfo() { |
232 | const settings = JSON.parse(JSON.stringify(this.stores.settings.app)); | ||
233 | settings.lockedPassword = '******'; | ||
234 | |||
230 | return { | 235 | return { |
231 | host: { | 236 | host: { |
232 | platform: process.platform, | 237 | platform: process.platform, |
@@ -238,19 +243,20 @@ export default class AppStore extends Store { | |||
238 | electron: process.versions.electron, | 243 | electron: process.versions.electron, |
239 | installedRecipes: this.stores.recipes.all.map(recipe => ({ id: recipe.id, version: recipe.version })), | 244 | installedRecipes: this.stores.recipes.all.map(recipe => ({ id: recipe.id, version: recipe.version })), |
240 | devRecipes: this.stores.recipePreviews.dev.map(recipe => ({ id: recipe.id, version: recipe.version })), | 245 | devRecipes: this.stores.recipePreviews.dev.map(recipe => ({ id: recipe.id, version: recipe.version })), |
241 | services: this.stores.services.all.map(service => ({ | 246 | services: this.stores.services.all.map(service => ({ |
242 | id: service.id, | 247 | id: service.id, |
243 | recipe: service.recipe.id, | 248 | recipe: service.recipe.id, |
244 | isAttached: service.isAttached, | 249 | isAttached: service.isAttached, |
245 | isActive: service.isActive, | 250 | isActive: service.isActive, |
246 | isEnabled: service.isEnabled, | 251 | isEnabled: service.isEnabled, |
247 | isHibernating: service.isHibernating, | 252 | isHibernating: service.isHibernating, |
248 | hasCrashed: service.hasCrashed, | 253 | hasCrashed: service.hasCrashed, |
249 | isDarkModeEnabled: service.isDarkModeEnabled, | 254 | isDarkModeEnabled: service.isDarkModeEnabled, |
250 | })), | 255 | })), |
256 | messages: this.stores.globalError.messages, | ||
251 | workspaces: this.stores.workspaces.workspaces.map(workspace => ({ id: workspace.id, services: workspace.services })), | 257 | workspaces: this.stores.workspaces.workspaces.map(workspace => ({ id: workspace.id, services: workspace.services })), |
252 | windowSettings: readJsonSync(path.join(app.getPath('userData'), 'window-state.json')), | 258 | windowSettings: readJsonSync(path.join(app.getPath('userData'), 'window-state.json')), |
253 | settings: this.stores.settings.app, | 259 | settings, |
254 | features: this.stores.features.features, | 260 | features: this.stores.features.features, |
255 | user: this.stores.user.data.id, | 261 | user: this.stores.user.data.id, |
256 | }, | 262 | }, |
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index ab5d762c7..780cde3a7 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -57,7 +57,10 @@ export default class FeaturesStore extends Store { | |||
57 | _updateFeatures = () => { | 57 | _updateFeatures = () => { |
58 | const features = Object.assign({}, DEFAULT_FEATURES_CONFIG); | 58 | const features = Object.assign({}, DEFAULT_FEATURES_CONFIG); |
59 | if (this.stores.user.isLoggedIn) { | 59 | if (this.stores.user.isLoggedIn) { |
60 | const requestResult = this.featuresRequest.execute().result; | 60 | let requestResult = {}; |
61 | try { | ||
62 | requestResult = this.featuresRequest.execute().result; | ||
63 | } catch (e) {} // eslint-disable-line no-empty | ||
61 | Object.assign(features, requestResult); | 64 | Object.assign(features, requestResult); |
62 | } | 65 | } |
63 | runInAction('FeaturesStore::_updateFeatures', () => { | 66 | runInAction('FeaturesStore::_updateFeatures', () => { |
diff --git a/src/stores/GlobalErrorStore.js b/src/stores/GlobalErrorStore.js index 8bdafb68c..aacaa247f 100644 --- a/src/stores/GlobalErrorStore.js +++ b/src/stores/GlobalErrorStore.js | |||
@@ -5,14 +5,54 @@ import Request from './lib/Request'; | |||
5 | export default class GlobalErrorStore extends Store { | 5 | export default class GlobalErrorStore extends Store { |
6 | @observable error = null; | 6 | @observable error = null; |
7 | 7 | ||
8 | @observable messages = []; | ||
9 | |||
8 | @observable response = {}; | 10 | @observable response = {}; |
9 | 11 | ||
10 | constructor(...args) { | 12 | constructor(...args) { |
11 | super(...args); | 13 | super(...args); |
12 | 14 | ||
15 | window.onerror = (...errorArgs) => { | ||
16 | this._handleConsoleError.call(this, ['error', ...errorArgs]); | ||
17 | }; | ||
18 | |||
19 | const origConsoleError = console.error; | ||
20 | window.console.error = (...errorArgs) => { | ||
21 | this._handleConsoleError.call(this, ['error', ...errorArgs]); | ||
22 | origConsoleError.apply(this, errorArgs); | ||
23 | }; | ||
24 | |||
25 | const origConsoleLog = console.log; | ||
26 | window.console.log = (...logArgs) => { | ||
27 | this._handleConsoleError.call(this, ['log', ...logArgs]); | ||
28 | origConsoleLog.apply(this, logArgs); | ||
29 | }; | ||
30 | |||
31 | const origConsoleInfo = console.info; | ||
32 | window.console.info = (...infoArgs) => { | ||
33 | this._handleConsoleError.call(this, ['info', ...infoArgs]); | ||
34 | origConsoleInfo.apply(this, infoArgs); | ||
35 | }; | ||
36 | |||
13 | Request.registerHook(this._handleRequests); | 37 | Request.registerHook(this._handleRequests); |
14 | } | 38 | } |
15 | 39 | ||
40 | _handleConsoleError(type, error, url, line) { | ||
41 | if (typeof type === 'object' && type.length && type.length >= 1) { | ||
42 | this.messages.push({ | ||
43 | type: type[0], | ||
44 | info: type, | ||
45 | }); | ||
46 | } else { | ||
47 | this.messages.push({ | ||
48 | type, | ||
49 | error, | ||
50 | url, | ||
51 | line, | ||
52 | }); | ||
53 | } | ||
54 | } | ||
55 | |||
16 | _handleRequests = action(async (request) => { | 56 | _handleRequests = action(async (request) => { |
17 | if (request.isError) { | 57 | if (request.isError) { |
18 | this.error = request.error; | 58 | this.error = request.error; |
@@ -28,6 +68,18 @@ export default class GlobalErrorStore extends Store { | |||
28 | // this.actions.user.logout({ serverLogout: true }); | 68 | // this.actions.user.logout({ serverLogout: true }); |
29 | } | 69 | } |
30 | } | 70 | } |
71 | |||
72 | this.messages.push({ | ||
73 | type: 'error', | ||
74 | request: { | ||
75 | result: request.result, | ||
76 | wasExecuted: request.wasExecuted, | ||
77 | method: request._method, | ||
78 | }, | ||
79 | error: this.error, | ||
80 | response: this.response, | ||
81 | server: window.ferdi.stores.settings.app.server, | ||
82 | }); | ||
31 | } else { | 83 | } else { |
32 | window.ferdi.stores.app.authRequestFailed = false; | 84 | window.ferdi.stores.app.authRequestFailed = false; |
33 | } | 85 | } |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 934a8a6e0..f65faa5a5 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -585,7 +585,8 @@ export default class ServicesStore extends Store { | |||
585 | 585 | ||
586 | service.resetMessageCount(); | 586 | service.resetMessageCount(); |
587 | 587 | ||
588 | service.webview.loadURL(service.url); | 588 | // service.webview.loadURL(service.url); |
589 | service.webview.reload(); | ||
589 | } | 590 | } |
590 | 591 | ||
591 | @action _reloadActive() { | 592 | @action _reloadActive() { |
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index d6a2e5fde..ec0b0cf8d 100644 --- a/src/stores/UserStore.js +++ b/src/stores/UserStore.js | |||
@@ -348,7 +348,12 @@ export default class UserStore extends Store { | |||
348 | // Reactions | 348 | // Reactions |
349 | async _getUserData() { | 349 | async _getUserData() { |
350 | if (this.isLoggedIn) { | 350 | if (this.isLoggedIn) { |
351 | const data = await this.getUserInfoRequest.execute()._promise; | 351 | let data; |
352 | try { | ||
353 | data = await this.getUserInfoRequest.execute()._promise; | ||
354 | } catch (e) { | ||
355 | return false; | ||
356 | } | ||
352 | 357 | ||
353 | // We need to set the beta flag for the SettingsStore | 358 | // We need to set the beta flag for the SettingsStore |
354 | this.actions.settings.update({ | 359 | this.actions.settings.update({ |
@@ -408,7 +413,11 @@ export default class UserStore extends Store { | |||
408 | } | 413 | } |
409 | 414 | ||
410 | async _migrateUserLocale() { | 415 | async _migrateUserLocale() { |
411 | await this.getUserInfoRequest._promise; | 416 | try { |
417 | await this.getUserInfoRequest._promise; | ||
418 | } catch (e) { | ||
419 | return false; | ||
420 | } | ||
412 | 421 | ||
413 | if (!this.data.locale) { | 422 | if (!this.data.locale) { |
414 | debug('Migrate "locale" to user data'); | 423 | debug('Migrate "locale" to user data'); |
diff --git a/src/stores/lib/CachedRequest.js b/src/stores/lib/CachedRequest.js index ac8b2bd81..31c7ce241 100644 --- a/src/stores/lib/CachedRequest.js +++ b/src/stores/lib/CachedRequest.js | |||
@@ -39,7 +39,7 @@ export default class CachedRequest extends Request { | |||
39 | }), 0); | 39 | }), 0); |
40 | 40 | ||
41 | // Issue api call & save it as promise that is handled to update the results of the operation | 41 | // Issue api call & save it as promise that is handled to update the results of the operation |
42 | this._promise = new Promise((resolve, reject) => { | 42 | this._promise = new Promise((resolve) => { |
43 | this._api[this._method](...callArgs) | 43 | this._api[this._method](...callArgs) |
44 | .then((result) => { | 44 | .then((result) => { |
45 | setTimeout(action(() => { | 45 | setTimeout(action(() => { |
@@ -63,7 +63,7 @@ export default class CachedRequest extends Request { | |||
63 | this.wasExecuted = true; | 63 | this.wasExecuted = true; |
64 | this._isWaitingForResponse = false; | 64 | this._isWaitingForResponse = false; |
65 | this._triggerHooks(); | 65 | this._triggerHooks(); |
66 | reject(error); | 66 | // reject(error); |
67 | }), 1); | 67 | }), 1); |
68 | })); | 68 | })); |
69 | }); | 69 | }); |
diff --git a/src/styles/tabs.scss b/src/styles/tabs.scss index e500830ed..5bd0555d2 100644 --- a/src/styles/tabs.scss +++ b/src/styles/tabs.scss | |||
@@ -72,6 +72,8 @@ | |||
72 | font-size: 0px; | 72 | font-size: 0px; |
73 | min-height: 10px; | 73 | min-height: 10px; |
74 | min-width: 10px; | 74 | min-width: 10px; |
75 | right: auto; | ||
76 | left: 8px; | ||
75 | } | 77 | } |
76 | } | 78 | } |
77 | 79 | ||