diff options
Diffstat (limited to 'src/components/services')
6 files changed, 177 insertions, 28 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..415a8d1b5 --- /dev/null +++ b/src/components/services/content/ErrorHandlers/WebviewErrorHandler.js | |||
@@ -0,0 +1,84 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | ||
4 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | import injectSheet from 'react-jss'; | ||
6 | |||
7 | import Button from '../../../ui/Button'; | ||
8 | |||
9 | import styles from './styles'; | ||
10 | |||
11 | const 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:', | ||
31 | }, | ||
32 | }); | ||
33 | |||
34 | export 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> | ||
62 | <strong> | ||
63 | {intl.formatMessage(messages.errorMessage)} | ||
64 | : | ||
65 | </strong> | ||
66 | {' '} | ||
67 | {errorMessage} | ||
68 | </p> | ||
69 | <div className={classes.buttonContainer}> | ||
70 | <Button | ||
71 | label={intl.formatMessage(messages.editAction, { name })} | ||
72 | buttonType="inverted" | ||
73 | onClick={() => edit()} | ||
74 | /> | ||
75 | <Button | ||
76 | label={intl.formatMessage(messages.action, { name })} | ||
77 | buttonType="inverted" | ||
78 | onClick={() => reload()} | ||
79 | /> | ||
80 | </div> | ||
81 | </div> | ||
82 | ); | ||
83 | } | ||
84 | } | ||
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 @@ | |||
1 | export 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/ServiceDisabled.js b/src/components/services/content/ServiceDisabled.js index 58fb38d8c..d0f12256e 100644 --- a/src/components/services/content/ServiceDisabled.js +++ b/src/components/services/content/ServiceDisabled.js | |||
@@ -27,6 +27,7 @@ export default @observer class ServiceDisabled extends Component { | |||
27 | }; | 27 | }; |
28 | 28 | ||
29 | countdownInterval = null; | 29 | countdownInterval = null; |
30 | |||
30 | countdownIntervalTimeout = 1000; | 31 | countdownIntervalTimeout = 1000; |
31 | 32 | ||
32 | render() { | 33 | render() { |
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index 7163209ee..b1a2c0207 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js | |||
@@ -1,4 +1,4 @@ | |||
1 | import React, { Component } from 'react'; | 1 | import React, { Component, Fragment } from 'react'; |
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import { autorun } from 'mobx'; | 3 | import { autorun } from 'mobx'; |
4 | import { observer } from 'mobx-react'; | 4 | import { observer } from 'mobx-react'; |
@@ -7,7 +7,9 @@ import classnames from 'classnames'; | |||
7 | 7 | ||
8 | import ServiceModel from '../../../models/Service'; | 8 | import ServiceModel from '../../../models/Service'; |
9 | import StatusBarTargetUrl from '../../ui/StatusBarTargetUrl'; | 9 | import StatusBarTargetUrl from '../../ui/StatusBarTargetUrl'; |
10 | import WebviewLoader from '../../ui/WebviewLoader'; | ||
10 | import WebviewCrashHandler from './WebviewCrashHandler'; | 11 | import WebviewCrashHandler from './WebviewCrashHandler'; |
12 | import WebviewErrorHandler from './ErrorHandlers/WebviewErrorHandler'; | ||
11 | import ServiceDisabled from './ServiceDisabled'; | 13 | import ServiceDisabled from './ServiceDisabled'; |
12 | 14 | ||
13 | export default @observer class ServiceWebview extends Component { | 15 | export default @observer class ServiceWebview extends Component { |
@@ -15,8 +17,10 @@ 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, |
23 | isActive: PropTypes.bool, | ||
20 | }; | 24 | }; |
21 | 25 | ||
22 | static defaultProps = { | 26 | static defaultProps = { |
@@ -29,8 +33,12 @@ export default @observer class ServiceWebview extends Component { | |||
29 | statusBarVisible: false, | 33 | statusBarVisible: false, |
30 | }; | 34 | }; |
31 | 35 | ||
36 | autorunDisposer = null; | ||
37 | |||
38 | webview = null; | ||
39 | |||
32 | componentDidMount() { | 40 | componentDidMount() { |
33 | autorun(() => { | 41 | this.autorunDisposer = autorun(() => { |
34 | if (this.props.service.isActive) { | 42 | if (this.props.service.isActive) { |
35 | this.setState({ forceRepaint: true }); | 43 | this.setState({ forceRepaint: true }); |
36 | setTimeout(() => { | 44 | setTimeout(() => { |
@@ -40,6 +48,10 @@ export default @observer class ServiceWebview extends Component { | |||
40 | }); | 48 | }); |
41 | } | 49 | } |
42 | 50 | ||
51 | componentWillUnmount() { | ||
52 | this.autorunDisposer(); | ||
53 | } | ||
54 | |||
43 | updateTargetUrl = (event) => { | 55 | updateTargetUrl = (event) => { |
44 | let visible = true; | 56 | let visible = true; |
45 | if (event.url === '' || event.url === '#') { | 57 | if (event.url === '' || event.url === '#') { |
@@ -51,13 +63,12 @@ export default @observer class ServiceWebview extends Component { | |||
51 | }); | 63 | }); |
52 | } | 64 | } |
53 | 65 | ||
54 | webview = null; | ||
55 | |||
56 | render() { | 66 | render() { |
57 | const { | 67 | const { |
58 | service, | 68 | service, |
59 | setWebviewReference, | 69 | setWebviewReference, |
60 | reload, | 70 | reload, |
71 | edit, | ||
61 | isAppMuted, | 72 | isAppMuted, |
62 | enable, | 73 | enable, |
63 | } = this.props; | 74 | } = this.props; |
@@ -78,25 +89,47 @@ export default @observer class ServiceWebview extends Component { | |||
78 | 89 | ||
79 | return ( | 90 | return ( |
80 | <div className={webviewClasses}> | 91 | <div className={webviewClasses}> |
81 | {service.hasCrashed && ( | 92 | {service.isActive && service.isEnabled && ( |
82 | <WebviewCrashHandler | 93 | <Fragment> |
83 | name={service.recipe.name} | 94 | {service.hasCrashed && ( |
84 | webview={service.webview} | 95 | <WebviewCrashHandler |
85 | reload={reload} | 96 | name={service.recipe.name} |
86 | /> | 97 | webview={service.webview} |
98 | reload={reload} | ||
99 | /> | ||
100 | )} | ||
101 | {service.isEnabled && service.isLoading && service.isFirstLoad && ( | ||
102 | <WebviewLoader | ||
103 | loaded={false} | ||
104 | name={service.name} | ||
105 | /> | ||
106 | )} | ||
107 | {service.isError && ( | ||
108 | <WebviewErrorHandler | ||
109 | name={service.recipe.name} | ||
110 | errorMessage={service.errorMessage} | ||
111 | reload={reload} | ||
112 | edit={edit} | ||
113 | /> | ||
114 | )} | ||
115 | </Fragment> | ||
87 | )} | 116 | )} |
88 | {!service.isEnabled ? ( | 117 | {!service.isEnabled ? ( |
89 | <ServiceDisabled | 118 | <Fragment> |
90 | name={service.recipe.name} | 119 | {service.isActive && ( |
91 | webview={service.webview} | 120 | <ServiceDisabled |
92 | enable={enable} | 121 | name={service.recipe.name} |
93 | /> | 122 | webview={service.webview} |
123 | enable={enable} | ||
124 | /> | ||
125 | )} | ||
126 | </Fragment> | ||
94 | ) : ( | 127 | ) : ( |
95 | <Webview | 128 | <Webview |
96 | ref={(element) => { this.webview = element; }} | 129 | ref={(element) => { this.webview = element; }} |
97 | autosize | 130 | autosize |
98 | src={service.url} | 131 | src={service.url} |
99 | preload="./webview/plugin.js" | 132 | preload="./webview/recipe.js" |
100 | partition={`persist:service-${service.id}`} | 133 | partition={`persist:service-${service.id}`} |
101 | onDidAttach={() => setWebviewReference({ | 134 | onDidAttach={() => setWebviewReference({ |
102 | serviceId: service.id, | 135 | serviceId: service.id, |
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js index 4cbd51043..1aeb17e03 100644 --- a/src/components/services/content/Services.js +++ b/src/components/services/content/Services.js | |||
@@ -20,18 +20,18 @@ const messages = defineMessages({ | |||
20 | 20 | ||
21 | export default @observer class Services extends Component { | 21 | export default @observer class Services extends Component { |
22 | static propTypes = { | 22 | static propTypes = { |
23 | services: MobxPropTypes.arrayOrObservableArray.isRequired, | 23 | services: MobxPropTypes.arrayOrObservableArray, |
24 | setWebviewReference: PropTypes.func.isRequired, | 24 | setWebviewReference: PropTypes.func.isRequired, |
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 | }; |
31 | 32 | ||
32 | static defaultProps = { | 33 | static defaultProps = { |
33 | services: [], | 34 | services: [], |
34 | activeService: '', | ||
35 | }; | 35 | }; |
36 | 36 | ||
37 | static contextTypes = { | 37 | static contextTypes = { |
@@ -45,6 +45,7 @@ export default @observer class Services extends Component { | |||
45 | setWebviewReference, | 45 | setWebviewReference, |
46 | openWindow, | 46 | openWindow, |
47 | reload, | 47 | reload, |
48 | openSettings, | ||
48 | isAppMuted, | 49 | isAppMuted, |
49 | update, | 50 | update, |
50 | } = this.props; | 51 | } = this.props; |
@@ -79,6 +80,7 @@ export default @observer class Services extends Component { | |||
79 | setWebviewReference={setWebviewReference} | 80 | setWebviewReference={setWebviewReference} |
80 | openWindow={openWindow} | 81 | openWindow={openWindow} |
81 | reload={() => reload({ serviceId: service.id })} | 82 | reload={() => reload({ serviceId: service.id })} |
83 | edit={() => openSettings({ path: `services/edit/${service.id}` })} | ||
82 | isAppMuted={isAppMuted} | 84 | isAppMuted={isAppMuted} |
83 | enable={() => update({ | 85 | enable={() => update({ |
84 | serviceId: service.id, | 86 | serviceId: service.id, |
diff --git a/src/components/services/content/WebviewCrashHandler.js b/src/components/services/content/WebviewCrashHandler.js index 3be1fccf4..42bc3c877 100644 --- a/src/components/services/content/WebviewCrashHandler.js +++ b/src/components/services/content/WebviewCrashHandler.js | |||
@@ -38,13 +38,18 @@ export default @observer class WebviewCrashHandler extends Component { | |||
38 | countdown: 10000, | 38 | countdown: 10000, |
39 | } | 39 | } |
40 | 40 | ||
41 | countdownInterval = null; | ||
42 | |||
43 | countdownIntervalTimeout = 1000; | ||
44 | |||
45 | |||
41 | componentDidMount() { | 46 | componentDidMount() { |
42 | const { reload } = this.props; | 47 | const { reload } = this.props; |
43 | 48 | ||
44 | this.countdownInterval = setInterval(() => { | 49 | this.countdownInterval = setInterval(() => { |
45 | this.setState({ | 50 | this.setState(prevState => ({ |
46 | countdown: this.state.countdown - this.countdownIntervalTimeout, | 51 | countdown: prevState.countdown - this.countdownIntervalTimeout, |
47 | }); | 52 | })); |
48 | 53 | ||
49 | if (this.state.countdown <= 0) { | 54 | if (this.state.countdown <= 0) { |
50 | reload(); | 55 | reload(); |
@@ -53,9 +58,6 @@ export default @observer class WebviewCrashHandler extends Component { | |||
53 | }, this.countdownIntervalTimeout); | 58 | }, this.countdownIntervalTimeout); |
54 | } | 59 | } |
55 | 60 | ||
56 | countdownInterval = null; | ||
57 | countdownIntervalTimeout = 1000; | ||
58 | |||
59 | render() { | 61 | render() { |
60 | const { name, reload } = this.props; | 62 | const { name, reload } = this.props; |
61 | const { intl } = this.context; | 63 | const { intl } = this.context; |
@@ -70,10 +72,12 @@ export default @observer class WebviewCrashHandler extends Component { | |||
70 | buttonType="inverted" | 72 | buttonType="inverted" |
71 | onClick={() => reload()} | 73 | onClick={() => reload()} |
72 | /> | 74 | /> |
73 | <p className="footnote">{intl.formatMessage(messages.autoReload, { | 75 | <p className="footnote"> |
74 | name, | 76 | {intl.formatMessage(messages.autoReload, { |
75 | seconds: this.state.countdown / 1000, | 77 | name, |
76 | })}</p> | 78 | seconds: this.state.countdown / 1000, |
79 | })} | ||
80 | </p> | ||
77 | </div> | 81 | </div> |
78 | ); | 82 | ); |
79 | } | 83 | } |