aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/services
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2017-11-23 16:17:34 +0100
committerLibravatar GitHub <noreply@github.com>2017-11-23 16:17:34 +0100
commitabca425e4a7b63be93132067bc335e8b6b39c2b2 (patch)
treee386f3e5d4c1c1caff19e3555e7ed1ce93e625f6 /src/components/services
parentreplace typeform (diff)
parentAdd windows notification fix to changelog (diff)
downloadferdium-app-abca425e4a7b63be93132067bc335e8b6b39c2b2.tar.gz
ferdium-app-abca425e4a7b63be93132067bc335e8b6b39c2b2.tar.zst
ferdium-app-abca425e4a7b63be93132067bc335e8b6b39c2b2.zip
Merge pull request #330 from meetfranz/developv5.0.0-beta.14
Beta 14
Diffstat (limited to 'src/components/services')
-rw-r--r--src/components/services/content/ServiceDisabled.js48
-rw-r--r--src/components/services/content/ServiceWebview.js59
-rw-r--r--src/components/services/content/Services.js15
-rw-r--r--src/components/services/content/WebviewCrashHandler.js81
-rw-r--r--src/components/services/tabs/TabBarSortableList.js25
-rw-r--r--src/components/services/tabs/TabItem.js26
-rw-r--r--src/components/services/tabs/Tabbar.js21
7 files changed, 233 insertions, 42 deletions
diff --git a/src/components/services/content/ServiceDisabled.js b/src/components/services/content/ServiceDisabled.js
new file mode 100644
index 000000000..b5af3743d
--- /dev/null
+++ b/src/components/services/content/ServiceDisabled.js
@@ -0,0 +1,48 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5
6import Button from '../../ui/Button';
7
8const messages = defineMessages({
9 headline: {
10 id: 'service.disabledHandler.headline',
11 defaultMessage: '!!!{name} is disabled',
12 },
13 action: {
14 id: 'service.disabledHandler.action',
15 defaultMessage: '!!!Enable {name}',
16 },
17});
18
19@observer
20export default class ServiceDisabled extends Component {
21 static propTypes = {
22 name: PropTypes.string.isRequired,
23 enable: PropTypes.func.isRequired,
24 };
25
26 static contextTypes = {
27 intl: intlShape,
28 };
29
30 countdownInterval = null;
31 countdownIntervalTimeout = 1000;
32
33 render() {
34 const { name, enable } = this.props;
35 const { intl } = this.context;
36
37 return (
38 <div className="services__info-layer">
39 <h1>{intl.formatMessage(messages.headline, { name })}</h1>
40 <Button
41 label={intl.formatMessage(messages.action, { name })}
42 buttonType="inverted"
43 onClick={() => enable()}
44 />
45 </div>
46 );
47 }
48}
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js
index 3ee3155be..faa356d3d 100644
--- a/src/components/services/content/ServiceWebview.js
+++ b/src/components/services/content/ServiceWebview.js
@@ -7,12 +7,17 @@ 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 WebviewCrashHandler from './WebviewCrashHandler';
11import ServiceDisabled from './ServiceDisabled';
10 12
11@observer 13@observer
12export default class ServiceWebview extends Component { 14export default class ServiceWebview extends Component {
13 static propTypes = { 15 static propTypes = {
14 service: PropTypes.instanceOf(ServiceModel).isRequired, 16 service: PropTypes.instanceOf(ServiceModel).isRequired,
15 setWebviewReference: PropTypes.func.isRequired, 17 setWebviewReference: PropTypes.func.isRequired,
18 reload: PropTypes.func.isRequired,
19 isAppMuted: PropTypes.bool.isRequired,
20 enable: PropTypes.func.isRequired,
16 }; 21 };
17 22
18 static defaultProps = { 23 static defaultProps = {
@@ -53,6 +58,9 @@ export default class ServiceWebview extends Component {
53 const { 58 const {
54 service, 59 service,
55 setWebviewReference, 60 setWebviewReference,
61 reload,
62 isAppMuted,
63 enable,
56 } = this.props; 64 } = this.props;
57 65
58 const webviewClasses = classnames({ 66 const webviewClasses = classnames({
@@ -70,26 +78,37 @@ export default class ServiceWebview extends Component {
70 78
71 return ( 79 return (
72 <div className={webviewClasses}> 80 <div className={webviewClasses}>
73 <Webview 81 {service.hasCrashed && (
74 ref={(element) => { this.webview = element; }} 82 <WebviewCrashHandler
75 83 name={service.recipe.name}
76 autosize 84 webview={service.webview}
77 src={service.url} 85 reload={reload}
78 preload="./webview/plugin.js" 86 />
79 partition={`persist:service-${service.id}`} 87 )}
80 88 {!service.isEnabled ? (
81 onDidAttach={() => setWebviewReference({ 89 <ServiceDisabled
82 serviceId: service.id, 90 name={service.recipe.name}
83 webview: this.webview.view, 91 webview={service.webview}
84 })} 92 enable={enable}
85 93 />
86 onUpdateTargetUrl={this.updateTargetUrl} 94 ) : (
87 95 <Webview
88 useragent={service.userAgent} 96 ref={(element) => { this.webview = element; }}
89 97 autosize
90 disablewebsecurity 98 src={service.url}
91 allowpopups 99 preload="./webview/plugin.js"
92 /> 100 partition={`persist:service-${service.id}`}
101 onDidAttach={() => setWebviewReference({
102 serviceId: service.id,
103 webview: this.webview.view,
104 })}
105 onUpdateTargetUrl={this.updateTargetUrl}
106 useragent={service.userAgent}
107 muted={isAppMuted || service.isMuted}
108 disablewebsecurity
109 allowpopups
110 />
111 )}
93 {statusBar} 112 {statusBar}
94 </div> 113 </div>
95 ); 114 );
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js
index 03c68b06f..b1322afc2 100644
--- a/src/components/services/content/Services.js
+++ b/src/components/services/content/Services.js
@@ -25,6 +25,9 @@ export default class Services extends Component {
25 setWebviewReference: PropTypes.func.isRequired, 25 setWebviewReference: PropTypes.func.isRequired,
26 handleIPCMessage: PropTypes.func.isRequired, 26 handleIPCMessage: PropTypes.func.isRequired,
27 openWindow: PropTypes.func.isRequired, 27 openWindow: PropTypes.func.isRequired,
28 reload: PropTypes.func.isRequired,
29 isAppMuted: PropTypes.bool.isRequired,
30 update: PropTypes.func.isRequired,
28 }; 31 };
29 32
30 static defaultProps = { 33 static defaultProps = {
@@ -42,6 +45,9 @@ export default class Services extends Component {
42 handleIPCMessage, 45 handleIPCMessage,
43 setWebviewReference, 46 setWebviewReference,
44 openWindow, 47 openWindow,
48 reload,
49 isAppMuted,
50 update,
45 } = this.props; 51 } = this.props;
46 const { intl } = this.context; 52 const { intl } = this.context;
47 53
@@ -73,6 +79,15 @@ export default class Services extends Component {
73 handleIPCMessage={handleIPCMessage} 79 handleIPCMessage={handleIPCMessage}
74 setWebviewReference={setWebviewReference} 80 setWebviewReference={setWebviewReference}
75 openWindow={openWindow} 81 openWindow={openWindow}
82 reload={() => reload({ serviceId: service.id })}
83 isAppMuted={isAppMuted}
84 enable={() => update({
85 serviceId: service.id,
86 serviceData: {
87 isEnabled: true,
88 },
89 redirect: false,
90 })}
76 /> 91 />
77 ))} 92 ))}
78 </div> 93 </div>
diff --git a/src/components/services/content/WebviewCrashHandler.js b/src/components/services/content/WebviewCrashHandler.js
new file mode 100644
index 000000000..d3e6951f3
--- /dev/null
+++ b/src/components/services/content/WebviewCrashHandler.js
@@ -0,0 +1,81 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5
6import Button from '../../ui/Button';
7
8const messages = defineMessages({
9 headline: {
10 id: 'service.crashHandler.headline',
11 defaultMessage: '!!!Oh no!',
12 },
13 text: {
14 id: 'service.crashHandler.text',
15 defaultMessage: '!!!{name} has caused an error.',
16 },
17 action: {
18 id: 'service.crashHandler.action',
19 defaultMessage: '!!!Reload {name}',
20 },
21 autoReload: {
22 id: 'service.crashHandler.autoReload',
23 defaultMessage: '!!!Trying to automatically restore {name} in {seconds} seconds',
24 },
25});
26
27@observer
28export default class WebviewCrashHandler extends Component {
29 static propTypes = {
30 name: PropTypes.string.isRequired,
31 reload: PropTypes.func.isRequired,
32 };
33
34 static contextTypes = {
35 intl: intlShape,
36 };
37
38 state = {
39 countdown: 10000,
40 }
41
42 componentDidMount() {
43 const { reload } = this.props;
44
45 this.countdownInterval = setInterval(() => {
46 this.setState({
47 countdown: this.state.countdown - this.countdownIntervalTimeout,
48 });
49
50 if (this.state.countdown <= 0) {
51 reload();
52 clearInterval(this.countdownInterval);
53 }
54 }, this.countdownIntervalTimeout);
55 }
56
57 countdownInterval = null;
58 countdownIntervalTimeout = 1000;
59
60 render() {
61 const { name, reload } = this.props;
62 const { intl } = this.context;
63
64 return (
65 <div className="services__info-layer">
66 <h1>{intl.formatMessage(messages.headline)}</h1>
67 <p>{intl.formatMessage(messages.text, { name })}</p>
68 <Button
69 // label={`Reload ${name}`}
70 label={intl.formatMessage(messages.action, { name })}
71 buttonType="inverted"
72 onClick={() => reload()}
73 />
74 <p className="footnote">{intl.formatMessage(messages.autoReload, {
75 name,
76 seconds: this.state.countdown / 1000,
77 })}</p>
78 </div>
79 );
80 }
81}
diff --git a/src/components/services/tabs/TabBarSortableList.js b/src/components/services/tabs/TabBarSortableList.js
index e5ae36419..2daf55676 100644
--- a/src/components/services/tabs/TabBarSortableList.js
+++ b/src/components/services/tabs/TabBarSortableList.js
@@ -2,17 +2,8 @@ import React, { Component } from 'react';
2import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 2import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
3import PropTypes from 'prop-types'; 3import PropTypes from 'prop-types';
4import { SortableContainer } from 'react-sortable-hoc'; 4import { SortableContainer } from 'react-sortable-hoc';
5import { defineMessages, intlShape } from 'react-intl';
6 5
7import TabItem from './TabItem'; 6import TabItem from './TabItem';
8import { ctrlKey } from '../../../environment';
9
10const messages = defineMessages({
11 addNewService: {
12 id: 'sidebar.addNewService',
13 defaultMessage: '!!!Add new service',
14 },
15});
16 7
17@observer 8@observer
18class TabBarSortableList extends Component { 9class TabBarSortableList extends Component {
@@ -22,27 +13,25 @@ class TabBarSortableList extends Component {
22 openSettings: PropTypes.func.isRequired, 13 openSettings: PropTypes.func.isRequired,
23 reload: PropTypes.func.isRequired, 14 reload: PropTypes.func.isRequired,
24 toggleNotifications: PropTypes.func.isRequired, 15 toggleNotifications: PropTypes.func.isRequired,
16 toggleAudio: PropTypes.func.isRequired,
25 deleteService: PropTypes.func.isRequired, 17 deleteService: PropTypes.func.isRequired,
26 disableService: PropTypes.func.isRequired, 18 disableService: PropTypes.func.isRequired,
19 enableService: PropTypes.func.isRequired,
27 } 20 }
28 21
29 static contextTypes = {
30 intl: intlShape,
31 };
32
33 render() { 22 render() {
34 const { 23 const {
35 services, 24 services,
36 setActive, 25 setActive,
37 reload, 26 reload,
38 toggleNotifications, 27 toggleNotifications,
28 toggleAudio,
39 deleteService, 29 deleteService,
40 disableService, 30 disableService,
31 enableService,
41 openSettings, 32 openSettings,
42 } = this.props; 33 } = this.props;
43 34
44 const { intl } = this.context;
45
46 return ( 35 return (
47 <ul 36 <ul
48 className="tabs" 37 className="tabs"
@@ -56,12 +45,14 @@ class TabBarSortableList extends Component {
56 shortcutIndex={index + 1} 45 shortcutIndex={index + 1}
57 reload={() => reload({ serviceId: service.id })} 46 reload={() => reload({ serviceId: service.id })}
58 toggleNotifications={() => toggleNotifications({ serviceId: service.id })} 47 toggleNotifications={() => toggleNotifications({ serviceId: service.id })}
48 toggleAudio={() => toggleAudio({ serviceId: service.id })}
59 deleteService={() => deleteService({ serviceId: service.id })} 49 deleteService={() => deleteService({ serviceId: service.id })}
60 disableService={() => disableService({ serviceId: service.id })} 50 disableService={() => disableService({ serviceId: service.id })}
51 enableService={() => enableService({ serviceId: service.id })}
61 openSettings={openSettings} 52 openSettings={openSettings}
62 /> 53 />
63 ))} 54 ))}
64 <li> 55 {/* <li>
65 <button 56 <button
66 className="sidebar__add-service" 57 className="sidebar__add-service"
67 onClick={() => openSettings({ path: 'recipes' })} 58 onClick={() => openSettings({ path: 'recipes' })}
@@ -69,7 +60,7 @@ class TabBarSortableList extends Component {
69 > 60 >
70 <span className="mdi mdi-plus" /> 61 <span className="mdi mdi-plus" />
71 </button> 62 </button>
72 </li> 63 </li> */}
73 </ul> 64 </ul>
74 ); 65 );
75 } 66 }
diff --git a/src/components/services/tabs/TabItem.js b/src/components/services/tabs/TabItem.js
index 9e03d2e21..a7136c43f 100644
--- a/src/components/services/tabs/TabItem.js
+++ b/src/components/services/tabs/TabItem.js
@@ -28,10 +28,22 @@ const messages = defineMessages({
28 id: 'tabs.item.enableNotification', 28 id: 'tabs.item.enableNotification',
29 defaultMessage: '!!!Enable notifications', 29 defaultMessage: '!!!Enable notifications',
30 }, 30 },
31 disableAudio: {
32 id: 'tabs.item.disableAudio',
33 defaultMessage: '!!!Disable audio',
34 },
35 enableAudio: {
36 id: 'tabs.item.enableAudio',
37 defaultMessage: '!!!Enable audio',
38 },
31 disableService: { 39 disableService: {
32 id: 'tabs.item.disableService', 40 id: 'tabs.item.disableService',
33 defaultMessage: '!!!Disable Service', 41 defaultMessage: '!!!Disable Service',
34 }, 42 },
43 enableService: {
44 id: 'tabs.item.enableService',
45 defaultMessage: '!!!Enable Service',
46 },
35 deleteService: { 47 deleteService: {
36 id: 'tabs.item.deleteService', 48 id: 'tabs.item.deleteService',
37 defaultMessage: '!!!Delete Service', 49 defaultMessage: '!!!Delete Service',
@@ -46,9 +58,11 @@ class TabItem extends Component {
46 shortcutIndex: PropTypes.number.isRequired, 58 shortcutIndex: PropTypes.number.isRequired,
47 reload: PropTypes.func.isRequired, 59 reload: PropTypes.func.isRequired,
48 toggleNotifications: PropTypes.func.isRequired, 60 toggleNotifications: PropTypes.func.isRequired,
61 toggleAudio: PropTypes.func.isRequired,
49 openSettings: PropTypes.func.isRequired, 62 openSettings: PropTypes.func.isRequired,
50 deleteService: PropTypes.func.isRequired, 63 deleteService: PropTypes.func.isRequired,
51 disableService: PropTypes.func.isRequired, 64 disableService: PropTypes.func.isRequired,
65 enableService: PropTypes.func.isRequired,
52 }; 66 };
53 67
54 static contextTypes = { 68 static contextTypes = {
@@ -62,8 +76,10 @@ class TabItem extends Component {
62 shortcutIndex, 76 shortcutIndex,
63 reload, 77 reload,
64 toggleNotifications, 78 toggleNotifications,
79 toggleAudio,
65 deleteService, 80 deleteService,
66 disableService, 81 disableService,
82 enableService,
67 openSettings, 83 openSettings,
68 } = this.props; 84 } = this.props;
69 const { intl } = this.context; 85 const { intl } = this.context;
@@ -90,8 +106,13 @@ class TabItem extends Component {
90 : intl.formatMessage(messages.enableNotifications), 106 : intl.formatMessage(messages.enableNotifications),
91 click: () => toggleNotifications(), 107 click: () => toggleNotifications(),
92 }, { 108 }, {
93 label: intl.formatMessage(messages.disableService), 109 label: service.isMuted
94 click: () => disableService(), 110 ? intl.formatMessage(messages.enableAudio)
111 : intl.formatMessage(messages.disableAudio),
112 click: () => toggleAudio(),
113 }, {
114 label: intl.formatMessage(service.isEnabled ? messages.disableService : messages.enableService),
115 click: () => (service.isEnabled ? disableService() : enableService()),
95 }, { 116 }, {
96 type: 'separator', 117 type: 'separator',
97 }, { 118 }, {
@@ -106,6 +127,7 @@ class TabItem extends Component {
106 'tab-item': true, 127 'tab-item': true,
107 'is-active': service.isActive, 128 'is-active': service.isActive,
108 'has-custom-icon': service.hasCustomIcon, 129 'has-custom-icon': service.hasCustomIcon,
130 'is-disabled': !service.isEnabled,
109 })} 131 })}
110 onClick={clickHandler} 132 onClick={clickHandler}
111 onContextMenu={() => menu.popup(remote.getCurrentWindow())} 133 onContextMenu={() => menu.popup(remote.getCurrentWindow())}
diff --git a/src/components/services/tabs/Tabbar.js b/src/components/services/tabs/Tabbar.js
index fdb2c0a59..9da1090b7 100644
--- a/src/components/services/tabs/Tabbar.js
+++ b/src/components/services/tabs/Tabbar.js
@@ -15,6 +15,7 @@ export default class TabBar extends Component {
15 reorder: PropTypes.func.isRequired, 15 reorder: PropTypes.func.isRequired,
16 reload: PropTypes.func.isRequired, 16 reload: PropTypes.func.isRequired,
17 toggleNotifications: PropTypes.func.isRequired, 17 toggleNotifications: PropTypes.func.isRequired,
18 toggleAudio: PropTypes.func.isRequired,
18 deleteService: PropTypes.func.isRequired, 19 deleteService: PropTypes.func.isRequired,
19 updateService: PropTypes.func.isRequired, 20 updateService: PropTypes.func.isRequired,
20 } 21 }
@@ -29,20 +30,30 @@ export default class TabBar extends Component {
29 reorder({ oldIndex, newIndex }); 30 reorder({ oldIndex, newIndex });
30 }; 31 };
31 32
32 disableService = ({ serviceId }) => { 33 shouldPreventSorting = event => event.target.tagName !== 'LI';
34
35 toggleService = ({ serviceId, isEnabled }) => {
33 const { updateService } = this.props; 36 const { updateService } = this.props;
34 37
35 if (serviceId) { 38 if (serviceId) {
36 updateService({ 39 updateService({
37 serviceId, 40 serviceId,
38 serviceData: { 41 serviceData: {
39 isEnabled: false, 42 isEnabled,
40 }, 43 },
41 redirect: false, 44 redirect: false,
42 }); 45 });
43 } 46 }
44 } 47 }
45 48
49 disableService({ serviceId }) {
50 this.toggleService({ serviceId, isEnabled: false });
51 }
52
53 enableService({ serviceId }) {
54 this.toggleService({ serviceId, isEnabled: true });
55 }
56
46 render() { 57 render() {
47 const { 58 const {
48 services, 59 services,
@@ -51,6 +62,7 @@ export default class TabBar extends Component {
51 disableToolTip, 62 disableToolTip,
52 reload, 63 reload,
53 toggleNotifications, 64 toggleNotifications,
65 toggleAudio,
54 deleteService, 66 deleteService,
55 } = this.props; 67 } = this.props;
56 68
@@ -61,10 +73,13 @@ export default class TabBar extends Component {
61 setActive={setActive} 73 setActive={setActive}
62 onSortEnd={this.onSortEnd} 74 onSortEnd={this.onSortEnd}
63 onSortStart={disableToolTip} 75 onSortStart={disableToolTip}
76 shouldCancelStart={this.shouldPreventSorting}
64 reload={reload} 77 reload={reload}
65 toggleNotifications={toggleNotifications} 78 toggleNotifications={toggleNotifications}
79 toggleAudio={toggleAudio}
66 deleteService={deleteService} 80 deleteService={deleteService}
67 disableService={this.disableService} 81 disableService={args => this.disableService(args)}
82 enableService={args => this.enableService(args)}
68 openSettings={openSettings} 83 openSettings={openSettings}
69 distance={20} 84 distance={20}
70 axis="y" 85 axis="y"