aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.all-contributorsrc56
-rw-r--r--.gitmodules4
-rw-r--r--.travis.yml29
-rw-r--r--README.md33
-rw-r--r--appveyor.yml4
-rw-r--r--branding/screenshots/hero.pngbin352745 -> 321357 bytes
-rw-r--r--build-helpers/images/win-app-ico.icobin4286 -> 162459 bytes
-rw-r--r--next_release.md44
-rw-r--r--package-lock.json2
-rw-r--r--package.json2
-rw-r--r--src/api/apiBase.js21
-rw-r--r--src/api/server/ServerApi.js23
-rw-r--r--src/components/services/content/ServiceView.js30
-rw-r--r--src/components/services/content/ServiceWebview.js5
-rw-r--r--src/components/ui/FeatureList.js2
-rw-r--r--src/config.js1
-rw-r--r--src/lib/Menu.js3
-rw-r--r--src/stores/AppStore.js18
-rw-r--r--src/stores/FeaturesStore.js5
-rw-r--r--src/stores/GlobalErrorStore.js52
-rw-r--r--src/stores/ServicesStore.js3
-rw-r--r--src/stores/UserStore.js13
-rw-r--r--src/stores/lib/CachedRequest.js4
-rw-r--r--src/styles/tabs.scss2
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 @@
1matrix: 1matrix:
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
15language: node_js 15language: node_js
16# Handle git submodules yourself
17git:
18 submodules: false
19# Use sed to replace the SSH URL with the public URL, then initialize submodules
20before_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
16install: 23install:
17 - echo do nothing 24 - echo do nothing
18before_script: 25before_script:
diff --git a/README.md b/README.md
index 90a01b091..44ab84831 100644
--- a/README.md
+++ b/README.md
@@ -196,34 +196,37 @@ When pushing a new tag, the CI builds will create a draft GitHub release and upl
196Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 196Thanks 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:
4version: 5.0.1.{build} 4version: 5.0.1.{build}
5 5
6install: 6install:
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
2Infos about the next release:
3
4## Beta
5v5.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
15v5.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';
7import { 7import {
8 LOCAL_SERVER, 8 LOCAL_SERVER,
9 SERVER_NOT_LOADED,
9} from '../config'; 10} from '../config';
10 11
11const apiBase = () => { 12const 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
38export default apiBase; 35export 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
15import { sleep } from '../../helpers/async-helpers'; 15import { sleep } from '../../helpers/async-helpers';
16 16
17import { API } from '../../environment'; 17import { RECIPES_PATH, SERVER_NOT_LOADED } from '../../config';
18import { RECIPES_PATH } from '../../config';
19import apiBase from '../apiBase'; 18import apiBase from '../apiBase';
20import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; 19import { prepareAuthRequest, sendAuthRequest } from '../utils/auth';
21 20
@@ -39,8 +38,6 @@ module.paths.unshift(
39const { app } = remote; 38const { app } = remote;
40const { default: fetch } = remote.require('electron-fetch'); 39const { default: fetch } = remote.require('electron-fetch');
41 40
42const SERVER_URL = API;
43
44export default class ServerApi { 41export 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';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { observable, reaction } from 'mobx'; 4import { observable, reaction } from 'mobx';
5import ElectronWebView from 'react-electron-web-view'; 5import ElectronWebView from 'react-electron-web-view';
6import path from 'path';
6 7
7import ServiceModel from '../../../models/Service'; 8import 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
114export const LOCAL_SERVER = 'You are using Ferdi without a server'; 114export const LOCAL_SERVER = 'You are using Ferdi without a server';
115export const SERVER_NOT_LOADED = 'Ferdi::SERVER_NOT_LOADED';
115 116
116export const SETTINGS_PATH = path.join(app.getPath('userData'), 'config'); 117export 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';
5export default class GlobalErrorStore extends Store { 5export 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