aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2018-12-08 17:08:58 +0100
committerLibravatar Stefan Malzner <stefan@adlk.io>2018-12-08 17:08:58 +0100
commita5e7171402eb27a4527a238d186c88ac03f8ffd7 (patch)
tree897708a2cfc88569c04f4896bacf2c9d390c7b39 /src
parentAdd service spellchecker language strings (diff)
downloadferdium-app-a5e7171402eb27a4527a238d186c88ac03f8ffd7.tar.gz
ferdium-app-a5e7171402eb27a4527a238d186c88ac03f8ffd7.tar.zst
ferdium-app-a5e7171402eb27a4527a238d186c88ac03f8ffd7.zip
feat(Service): Add error screen for services that failed to load
Diffstat (limited to 'src')
-rw-r--r--src/components/services/content/ErrorHandlers/WebviewErrorHandler.js79
-rw-r--r--src/components/services/content/ErrorHandlers/styles.js25
-rw-r--r--src/components/services/content/ServiceWebview.js18
-rw-r--r--src/components/services/content/Services.js3
-rw-r--r--src/containers/layout/AppLayoutContainer.js1
-rw-r--r--src/i18n/locales/en-US.json5
-rw-r--r--src/models/Service.js23
7 files changed, 154 insertions, 0 deletions
diff --git a/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js b/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js
new file mode 100644
index 000000000..05a64209b
--- /dev/null
+++ b/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js
@@ -0,0 +1,79 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import injectSheet from 'react-jss';
6
7import Button from '../../../ui/Button';
8
9import styles from './styles';
10
11const messages = defineMessages({
12 headline: {
13 id: 'service.errorHandler.headline',
14 defaultMessage: '!!!Oh no!',
15 },
16 text: {
17 id: 'service.errorHandler.text',
18 defaultMessage: '!!!{name} has failed to load.',
19 },
20 action: {
21 id: 'service.errorHandler.action',
22 defaultMessage: '!!!Reload {name}',
23 },
24 editAction: {
25 id: 'service.errorHandler.editAction',
26 defaultMessage: '!!!Edit {name}',
27 },
28 errorMessage: {
29 id: 'service.errorHandler.message',
30 defaultMessage: '!!!Error: {error}',
31 },
32});
33
34export default @injectSheet(styles) @observer class WebviewCrashHandler extends Component {
35 static propTypes = {
36 name: PropTypes.string.isRequired,
37 reload: PropTypes.func.isRequired,
38 edit: PropTypes.func.isRequired,
39 errorMessage: PropTypes.string.isRequired,
40 classes: PropTypes.object.isRequired,
41 };
42
43 static contextTypes = {
44 intl: intlShape,
45 };
46
47 render() {
48 const {
49 name,
50 reload,
51 edit,
52 errorMessage,
53 classes,
54 } = this.props;
55 const { intl } = this.context;
56
57 return (
58 <div className={classes.component}>
59 <h1>{intl.formatMessage(messages.headline)}</h1>
60 <p>{intl.formatMessage(messages.text, { name })}</p>
61 <p>{intl.formatMessage(messages.errorMessage, {
62 error: errorMessage,
63 })}</p>
64 <div className={classes.buttonContainer}>
65 <Button
66 label={intl.formatMessage(messages.editAction, { name })}
67 buttonType="inverted"
68 onClick={() => edit()}
69 />
70 <Button
71 label={intl.formatMessage(messages.action, { name })}
72 buttonType="inverted"
73 onClick={() => reload()}
74 />
75 </div>
76 </div>
77 );
78 }
79}
diff --git a/src/components/services/content/ErrorHandlers/styles.js b/src/components/services/content/ErrorHandlers/styles.js
new file mode 100644
index 000000000..f11386798
--- /dev/null
+++ b/src/components/services/content/ErrorHandlers/styles.js
@@ -0,0 +1,25 @@
1export default {
2 component: {
3 left: 0,
4 position: 'absolute',
5 top: 0,
6 width: '100%',
7 zIndex: 0,
8 alignItems: 'center',
9 // background: $theme-gray-lighter;
10 display: 'flex',
11 flexDirection: 'column',
12 justifyContent: 'center',
13 textAlign: 'center',
14 },
15 buttonContainer: {
16 display: 'flex',
17 flexDirection: 'row',
18 height: 'auto',
19 margin: [40, 0, 20],
20
21 '& button': {
22 margin: [0, 10, 0, 10],
23 },
24 },
25};
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js
index 6e56de92f..b3def3fa5 100644
--- a/src/components/services/content/ServiceWebview.js
+++ b/src/components/services/content/ServiceWebview.js
@@ -7,7 +7,9 @@ import classnames from 'classnames';
7 7
8import ServiceModel from '../../../models/Service'; 8import ServiceModel from '../../../models/Service';
9import StatusBarTargetUrl from '../../ui/StatusBarTargetUrl'; 9import StatusBarTargetUrl from '../../ui/StatusBarTargetUrl';
10import WebviewLoader from '../../ui/WebviewLoader';
10import WebviewCrashHandler from './WebviewCrashHandler'; 11import WebviewCrashHandler from './WebviewCrashHandler';
12import WebviewErrorHandler from './ErrorHandlers/WebviewErrorHandler';
11import ServiceDisabled from './ServiceDisabled'; 13import ServiceDisabled from './ServiceDisabled';
12 14
13export default @observer class ServiceWebview extends Component { 15export default @observer class ServiceWebview extends Component {
@@ -15,6 +17,7 @@ export default @observer class ServiceWebview extends Component {
15 service: PropTypes.instanceOf(ServiceModel).isRequired, 17 service: PropTypes.instanceOf(ServiceModel).isRequired,
16 setWebviewReference: PropTypes.func.isRequired, 18 setWebviewReference: PropTypes.func.isRequired,
17 reload: PropTypes.func.isRequired, 19 reload: PropTypes.func.isRequired,
20 edit: PropTypes.func.isRequired,
18 isAppMuted: PropTypes.bool.isRequired, 21 isAppMuted: PropTypes.bool.isRequired,
19 enable: PropTypes.func.isRequired, 22 enable: PropTypes.func.isRequired,
20 }; 23 };
@@ -58,6 +61,7 @@ export default @observer class ServiceWebview extends Component {
58 service, 61 service,
59 setWebviewReference, 62 setWebviewReference,
60 reload, 63 reload,
64 edit,
61 isAppMuted, 65 isAppMuted,
62 enable, 66 enable,
63 } = this.props; 67 } = this.props;
@@ -85,6 +89,20 @@ export default @observer class ServiceWebview extends Component {
85 reload={reload} 89 reload={reload}
86 /> 90 />
87 )} 91 )}
92 {service.isLoading && (
93 <WebviewLoader
94 loaded={!service.isLoading}
95 name={service.name}
96 />
97 )}
98 {service.isError && (
99 <WebviewErrorHandler
100 name={service.recipe.name}
101 errorMessage={service.errorMessage}
102 reload={reload}
103 edit={edit}
104 />
105 )}
88 {!service.isEnabled ? ( 106 {!service.isEnabled ? (
89 <ServiceDisabled 107 <ServiceDisabled
90 name={service.recipe.name} 108 name={service.recipe.name}
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js
index 4cbd51043..0d4d778cd 100644
--- a/src/components/services/content/Services.js
+++ b/src/components/services/content/Services.js
@@ -25,6 +25,7 @@ export default @observer class Services extends Component {
25 handleIPCMessage: PropTypes.func.isRequired, 25 handleIPCMessage: PropTypes.func.isRequired,
26 openWindow: PropTypes.func.isRequired, 26 openWindow: PropTypes.func.isRequired,
27 reload: PropTypes.func.isRequired, 27 reload: PropTypes.func.isRequired,
28 openSettings: PropTypes.func.isRequired,
28 isAppMuted: PropTypes.bool.isRequired, 29 isAppMuted: PropTypes.bool.isRequired,
29 update: PropTypes.func.isRequired, 30 update: PropTypes.func.isRequired,
30 }; 31 };
@@ -45,6 +46,7 @@ export default @observer class Services extends Component {
45 setWebviewReference, 46 setWebviewReference,
46 openWindow, 47 openWindow,
47 reload, 48 reload,
49 openSettings,
48 isAppMuted, 50 isAppMuted,
49 update, 51 update,
50 } = this.props; 52 } = this.props;
@@ -79,6 +81,7 @@ export default @observer class Services extends Component {
79 setWebviewReference={setWebviewReference} 81 setWebviewReference={setWebviewReference}
80 openWindow={openWindow} 82 openWindow={openWindow}
81 reload={() => reload({ serviceId: service.id })} 83 reload={() => reload({ serviceId: service.id })}
84 edit={() => openSettings({ path: `services/edit/${service.id}` })}
82 isAppMuted={isAppMuted} 85 isAppMuted={isAppMuted}
83 enable={() => update({ 86 enable={() => update({
84 serviceId: service.id, 87 serviceId: service.id,
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js
index e1423bdaa..455df10d7 100644
--- a/src/containers/layout/AppLayoutContainer.js
+++ b/src/containers/layout/AppLayoutContainer.js
@@ -105,6 +105,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e
105 setWebviewReference={setWebviewReference} 105 setWebviewReference={setWebviewReference}
106 openWindow={openWindow} 106 openWindow={openWindow}
107 reload={reload} 107 reload={reload}
108 openSettings={openSettings}
108 isAppMuted={settings.all.app.isAppMuted} 109 isAppMuted={settings.all.app.isAppMuted}
109 update={updateService} 110 update={updateService}
110 /> 111 />
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 7ccf94a87..17af2b128 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -212,6 +212,11 @@
212 "service.crashHandler.text": "{name} has caused an error.", 212 "service.crashHandler.text": "{name} has caused an error.",
213 "service.crashHandler.action": "Reload {name}", 213 "service.crashHandler.action": "Reload {name}",
214 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", 214 "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds",
215 "service.errorHandler.headline": "Oh no!",
216 "service.errorHandler.text": "{name} has failed to load.",
217 "service.errorHandler.message": "Error: {error}",
218 "service.errorHandler.action": "Reload {name}",
219 "service.errorHandler.editAction": "Edit {name}",
215 "service.disabledHandler.headline": "{name} is disabled", 220 "service.disabledHandler.headline": "{name} is disabled",
216 "service.disabledHandler.action": "Enable {name}", 221 "service.disabledHandler.action": "Enable {name}",
217 "menu.edit": "Edit", 222 "menu.edit": "Edit",
diff --git a/src/models/Service.js b/src/models/Service.js
index deeb544d1..7ba9aa396 100644
--- a/src/models/Service.js
+++ b/src/models/Service.js
@@ -2,6 +2,8 @@ import { computed, observable, autorun } from 'mobx';
2import path from 'path'; 2import path from 'path';
3import normalizeUrl from 'normalize-url'; 3import normalizeUrl from 'normalize-url';
4 4
5const debug = require('debug')('Franz:Service');
6
5export default class Service { 7export default class Service {
6 id = ''; 8 id = '';
7 recipe = ''; 9 recipe = '';
@@ -31,6 +33,11 @@ export default class Service {
31 @observable isDarkModeEnabled = false; 33 @observable isDarkModeEnabled = false;
32 @observable spellcheckerLanguage = null; 34 @observable spellcheckerLanguage = null;
33 35
36 // @observable isFirstNavigation = true;
37 @observable isLoading = true;
38 @observable isError = false;
39 @observable errorMessage = '';
40
34 constructor(data, recipe) { 41 constructor(data, recipe) {
35 if (!data) { 42 if (!data) {
36 console.error('Service config not valid'); 43 console.error('Service config not valid');
@@ -150,9 +157,25 @@ export default class Service {
150 157
151 this.webview.addEventListener('did-start-loading', () => { 158 this.webview.addEventListener('did-start-loading', () => {
152 this.hasCrashed = false; 159 this.hasCrashed = false;
160 this.isLoading = true;
161 this.isError = false;
162 });
163
164 this.webview.addEventListener('did-stop-loading', () => {
165 this.isLoading = false;
166 });
167
168 this.webview.addEventListener('did-fail-load', (event) => {
169 debug('Service failed to load', this.name, event);
170 if (event.isMainFrame) {
171 this.isError = true;
172 this.errorMessage = event.errorDescription;
173 this.isLoading = false;
174 }
153 }); 175 });
154 176
155 this.webview.addEventListener('crashed', () => { 177 this.webview.addEventListener('crashed', () => {
178 debug('Service crashed', this.name);
156 this.hasCrashed = true; 179 this.hasCrashed = true;
157 }); 180 });
158 } 181 }