diff options
author | Amine El Mouafik <412895+kytwb@users.noreply.github.com> | 2021-02-08 10:34:45 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-08 10:34:45 +0100 |
commit | 035002ceedf78d5ec73eabc0df7f06139939b967 (patch) | |
tree | 1c0d1e9531bae05fb65d70b9ea25baf404b74fe1 /src/components/services | |
parent | docs: add k0staa as a contributor (#1193) (diff) | |
download | ferdium-app-035002ceedf78d5ec73eabc0df7f06139939b967.tar.gz ferdium-app-035002ceedf78d5ec73eabc0df7f06139939b967.tar.zst ferdium-app-035002ceedf78d5ec73eabc0df7f06139939b967.zip |
Synchronize with Franz 5.6.0 (#1033)
Co-authored-by: FranzBot <i18n@meetfranz.com>
Co-authored-by: vantezzen <hello@vantezzen.io>
Co-authored-by: Makazzz <makazzzpro@live.ca>
Co-authored-by: Stefan Malzner <stefan@adlk.io>
Co-authored-by: Amine Mouafik <amine@mouafik.fr>
Diffstat (limited to 'src/components/services')
-rw-r--r-- | src/components/services/content/ServiceView.js | 73 | ||||
-rw-r--r-- | src/components/services/content/ServiceWebview.js | 5 | ||||
-rw-r--r-- | src/components/services/content/Services.js | 6 | ||||
-rw-r--r-- | src/components/services/tabs/TabItem.js | 87 |
4 files changed, 103 insertions, 68 deletions
diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js index d91016c71..444d5fea4 100644 --- a/src/components/services/content/ServiceView.js +++ b/src/components/services/content/ServiceView.js | |||
@@ -1,6 +1,6 @@ | |||
1 | import React, { Component, Fragment } from 'react'; | 1 | import React, { Component, Fragment } from 'react'; |
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import { autorun, reaction } from 'mobx'; | 3 | import { autorun } from 'mobx'; |
4 | import { observer, inject } from 'mobx-react'; | 4 | import { observer, inject } from 'mobx-react'; |
5 | import classnames from 'classnames'; | 5 | import classnames from 'classnames'; |
6 | 6 | ||
@@ -27,11 +27,7 @@ export default @inject('stores', 'actions') @observer class ServiceView extends | |||
27 | stores: PropTypes.shape({ | 27 | stores: PropTypes.shape({ |
28 | settings: PropTypes.instanceOf(SettingsStore).isRequired, | 28 | settings: PropTypes.instanceOf(SettingsStore).isRequired, |
29 | }).isRequired, | 29 | }).isRequired, |
30 | actions: PropTypes.shape({ | 30 | isSpellcheckerEnabled: PropTypes.bool.isRequired, |
31 | service: PropTypes.shape({ | ||
32 | setHibernation: PropTypes.func.isRequired, | ||
33 | }).isRequired, | ||
34 | }).isRequired, | ||
35 | }; | 31 | }; |
36 | 32 | ||
37 | static defaultProps = { | 33 | static defaultProps = { |
@@ -50,12 +46,6 @@ export default @inject('stores', 'actions') @observer class ServiceView extends | |||
50 | 46 | ||
51 | forceRepaintTimeout = null; | 47 | forceRepaintTimeout = null; |
52 | 48 | ||
53 | constructor(props) { | ||
54 | super(props); | ||
55 | |||
56 | this.startHibernationTimer = this.startHibernationTimer.bind(this); | ||
57 | } | ||
58 | |||
59 | componentDidMount() { | 49 | componentDidMount() { |
60 | this.autorunDisposer = autorun(() => { | 50 | this.autorunDisposer = autorun(() => { |
61 | if (this.props.service.isActive) { | 51 | if (this.props.service.isActive) { |
@@ -65,32 +55,6 @@ export default @inject('stores', 'actions') @observer class ServiceView extends | |||
65 | }, 100); | 55 | }, 100); |
66 | } | 56 | } |
67 | }); | 57 | }); |
68 | |||
69 | reaction( | ||
70 | () => this.props.service.isActive, | ||
71 | () => { | ||
72 | if (!this.props.service.isActive && this.props.stores.settings.all.app.hibernate) { | ||
73 | // Service is inactive - start hibernation countdown | ||
74 | this.startHibernationTimer(); | ||
75 | } else { | ||
76 | if (this.hibernationTimer) { | ||
77 | // Service is active but we have an active hibernation timer: Clear timeout | ||
78 | clearTimeout(this.hibernationTimer); | ||
79 | } | ||
80 | |||
81 | // Service is active, wake up service from hibernation | ||
82 | this.props.actions.service.setHibernation({ | ||
83 | serviceId: this.props.service.id, | ||
84 | hibernating: false, | ||
85 | }); | ||
86 | } | ||
87 | }, | ||
88 | ); | ||
89 | |||
90 | // Start hibernation counter if we are in background | ||
91 | if (!this.props.service.isActive && this.props.stores.settings.all.app.hibernate) { | ||
92 | this.startHibernationTimer(); | ||
93 | } | ||
94 | } | 58 | } |
95 | 59 | ||
96 | componentWillUnmount() { | 60 | componentWillUnmount() { |
@@ -110,19 +74,6 @@ export default @inject('stores', 'actions') @observer class ServiceView extends | |||
110 | }); | 74 | }); |
111 | }; | 75 | }; |
112 | 76 | ||
113 | startHibernationTimer() { | ||
114 | const timerDuration = (Number(this.props.stores.settings.all.app.hibernationStrategy) || 300) * 1000; | ||
115 | |||
116 | const hibernationTimer = setTimeout(() => { | ||
117 | this.props.actions.service.setHibernation({ | ||
118 | serviceId: this.props.service.id, | ||
119 | hibernating: true, | ||
120 | }); | ||
121 | }, timerDuration); | ||
122 | |||
123 | this.hibernationTimer = hibernationTimer; | ||
124 | } | ||
125 | |||
126 | render() { | 77 | render() { |
127 | const { | 78 | const { |
128 | detachService, | 79 | detachService, |
@@ -132,6 +83,7 @@ export default @inject('stores', 'actions') @observer class ServiceView extends | |||
132 | edit, | 83 | edit, |
133 | enable, | 84 | enable, |
134 | stores, | 85 | stores, |
86 | isSpellcheckerEnabled, | ||
135 | } = this.props; | 87 | } = this.props; |
136 | 88 | ||
137 | const { | 89 | const { |
@@ -193,22 +145,19 @@ export default @inject('stores', 'actions') @observer class ServiceView extends | |||
193 | </Fragment> | 145 | </Fragment> |
194 | ) : ( | 146 | ) : ( |
195 | <> | 147 | <> |
196 | {(!service.isHibernating || service.disableHibernation) ? ( | 148 | {(!service.isHibernating || service.isHibernationEnabled) ? ( |
197 | <> | 149 | <> |
198 | {showNavBar && ( | 150 | {showNavBar && ( |
199 | <WebControlsScreen service={service} /> | 151 | <WebControlsScreen service={service} /> |
200 | )} | 152 | )} |
201 | <ServiceWebview | 153 | {!service.isHibernating && ( |
202 | service={service} | 154 | <ServiceWebview |
203 | setWebviewReference={setWebviewReference} | 155 | service={service} |
204 | detachService={detachService} | 156 | setWebviewReference={setWebviewReference} |
205 | /> | 157 | detachService={detachService} |
206 | {/* {service.lostRecipeConnection && ( | 158 | isSpellcheckerEnabled={isSpellcheckerEnabled} |
207 | <ConnectionLostBanner | ||
208 | name={service.name} | ||
209 | reload={reload} | ||
210 | /> | 159 | /> |
211 | )} */} | 160 | )} |
212 | </> | 161 | </> |
213 | ) : ( | 162 | ) : ( |
214 | <div> | 163 | <div> |
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js index 2e3354279..4edbde5e2 100644 --- a/src/components/services/content/ServiceWebview.js +++ b/src/components/services/content/ServiceWebview.js | |||
@@ -15,6 +15,7 @@ class ServiceWebview extends Component { | |||
15 | service: PropTypes.instanceOf(ServiceModel).isRequired, | 15 | service: PropTypes.instanceOf(ServiceModel).isRequired, |
16 | setWebviewReference: PropTypes.func.isRequired, | 16 | setWebviewReference: PropTypes.func.isRequired, |
17 | detachService: PropTypes.func.isRequired, | 17 | detachService: PropTypes.func.isRequired, |
18 | isSpellcheckerEnabled: PropTypes.bool.isRequired, | ||
18 | }; | 19 | }; |
19 | 20 | ||
20 | @observable webview = null; | 21 | @observable webview = null; |
@@ -55,6 +56,7 @@ class ServiceWebview extends Component { | |||
55 | const { | 56 | const { |
56 | service, | 57 | service, |
57 | setWebviewReference, | 58 | setWebviewReference, |
59 | isSpellcheckerEnabled, | ||
58 | } = this.props; | 60 | } = this.props; |
59 | 61 | ||
60 | const preloadScript = path.join(__dirname, '../../../', 'webview', 'recipe.js'); | 62 | const preloadScript = path.join(__dirname, '../../../', 'webview', 'recipe.js'); |
@@ -70,7 +72,7 @@ class ServiceWebview extends Component { | |||
70 | autosize | 72 | autosize |
71 | src={service.url} | 73 | src={service.url} |
72 | preload={preloadScript} | 74 | preload={preloadScript} |
73 | partition={`persist:service-${service.id}`} | 75 | partition={service.partition} |
74 | onDidAttach={() => { | 76 | onDidAttach={() => { |
75 | setWebviewReference({ | 77 | setWebviewReference({ |
76 | serviceId: service.id, | 78 | serviceId: service.id, |
@@ -81,6 +83,7 @@ class ServiceWebview extends Component { | |||
81 | useragent={service.userAgent} | 83 | useragent={service.userAgent} |
82 | disablewebsecurity={service.recipe.disablewebsecurity ? true : undefined} | 84 | disablewebsecurity={service.recipe.disablewebsecurity ? true : undefined} |
83 | allowpopups | 85 | allowpopups |
86 | webpreferences={`spellcheck=${isSpellcheckerEnabled ? 1 : 0}`} | ||
84 | /> | 87 | /> |
85 | ); | 88 | ); |
86 | } | 89 | } |
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js index da2ee0b9e..f679eeed0 100644 --- a/src/components/services/content/Services.js +++ b/src/components/services/content/Services.js | |||
@@ -10,6 +10,7 @@ import injectSheet from 'react-jss'; | |||
10 | import ServiceView from './ServiceView'; | 10 | import ServiceView from './ServiceView'; |
11 | import Appear from '../../ui/effects/Appear'; | 11 | import Appear from '../../ui/effects/Appear'; |
12 | import serverlessLogin from '../../../helpers/serverless-helpers'; | 12 | import serverlessLogin from '../../../helpers/serverless-helpers'; |
13 | import { TODOS_RECIPE_ID } from '../../../features/todos'; | ||
13 | 14 | ||
14 | const messages = defineMessages({ | 15 | const messages = defineMessages({ |
15 | welcome: { | 16 | welcome: { |
@@ -58,6 +59,7 @@ export default @injectSheet(styles) @inject('actions') @observer class Services | |||
58 | hasActivatedTrial: PropTypes.bool.isRequired, | 59 | hasActivatedTrial: PropTypes.bool.isRequired, |
59 | classes: PropTypes.object.isRequired, | 60 | classes: PropTypes.object.isRequired, |
60 | actions: PropTypes.object.isRequired, | 61 | actions: PropTypes.object.isRequired, |
62 | isSpellcheckerEnabled: PropTypes.bool.isRequired, | ||
61 | }; | 63 | }; |
62 | 64 | ||
63 | static defaultProps = { | 65 | static defaultProps = { |
@@ -111,6 +113,7 @@ export default @injectSheet(styles) @inject('actions') @observer class Services | |||
111 | userHasCompletedSignup, | 113 | userHasCompletedSignup, |
112 | hasActivatedTrial, | 114 | hasActivatedTrial, |
113 | classes, | 115 | classes, |
116 | isSpellcheckerEnabled, | ||
114 | } = this.props; | 117 | } = this.props; |
115 | 118 | ||
116 | const { | 119 | const { |
@@ -168,7 +171,7 @@ export default @injectSheet(styles) @inject('actions') @observer class Services | |||
168 | </div> | 171 | </div> |
169 | </Appear> | 172 | </Appear> |
170 | )} | 173 | )} |
171 | {services.map(service => ( | 174 | {services.filter(service => service.recipe.id !== TODOS_RECIPE_ID).map(service => ( |
172 | <ServiceView | 175 | <ServiceView |
173 | key={service.id} | 176 | key={service.id} |
174 | service={service} | 177 | service={service} |
@@ -186,6 +189,7 @@ export default @injectSheet(styles) @inject('actions') @observer class Services | |||
186 | redirect: false, | 189 | redirect: false, |
187 | })} | 190 | })} |
188 | upgrade={() => openSettings({ path: 'user' })} | 191 | upgrade={() => openSettings({ path: 'user' })} |
192 | isSpellcheckerEnabled={isSpellcheckerEnabled} | ||
189 | /> | 193 | /> |
190 | ))} | 194 | ))} |
191 | </div> | 195 | </div> |
diff --git a/src/components/services/tabs/TabItem.js b/src/components/services/tabs/TabItem.js index efa5fa60c..479f151a6 100644 --- a/src/components/services/tabs/TabItem.js +++ b/src/components/services/tabs/TabItem.js | |||
@@ -5,9 +5,14 @@ import PropTypes from 'prop-types'; | |||
5 | import { observer } from 'mobx-react'; | 5 | import { observer } from 'mobx-react'; |
6 | import classnames from 'classnames'; | 6 | import classnames from 'classnames'; |
7 | import { SortableElement } from 'react-sortable-hoc'; | 7 | import { SortableElement } from 'react-sortable-hoc'; |
8 | import injectSheet from 'react-jss'; | ||
9 | import ms from 'ms'; | ||
8 | 10 | ||
11 | import { observable, autorun } from 'mobx'; | ||
9 | import ServiceModel from '../../../models/Service'; | 12 | import ServiceModel from '../../../models/Service'; |
10 | import { ctrlKey } from '../../../environment'; | 13 | import { ctrlKey, cmdKey } from '../../../environment'; |
14 | |||
15 | const IS_SERVICE_DEBUGGING_ENABLED = (localStorage.getItem('debug') || '').includes('Franz:Service'); | ||
11 | 16 | ||
12 | const { Menu } = remote; | 17 | const { Menu } = remote; |
13 | 18 | ||
@@ -50,9 +55,38 @@ const messages = defineMessages({ | |||
50 | }, | 55 | }, |
51 | }); | 56 | }); |
52 | 57 | ||
53 | @observer | 58 | const styles = { |
54 | class TabItem extends Component { | 59 | pollIndicator: { |
60 | position: 'absolute', | ||
61 | bottom: 2, | ||
62 | width: 10, | ||
63 | height: 10, | ||
64 | borderRadius: 5, | ||
65 | background: 'gray', | ||
66 | transition: 'background 0.5s', | ||
67 | }, | ||
68 | pollIndicatorPoll: { | ||
69 | left: 2, | ||
70 | }, | ||
71 | pollIndicatorAnswer: { | ||
72 | left: 14, | ||
73 | }, | ||
74 | polled: { | ||
75 | background: 'yellow !important', | ||
76 | transition: 'background 0.1s', | ||
77 | }, | ||
78 | pollAnswered: { | ||
79 | background: 'green !important', | ||
80 | transition: 'background 0.1s', | ||
81 | }, | ||
82 | stale: { | ||
83 | background: 'red !important', | ||
84 | }, | ||
85 | }; | ||
86 | |||
87 | @injectSheet(styles) @observer class TabItem extends Component { | ||
55 | static propTypes = { | 88 | static propTypes = { |
89 | classes: PropTypes.object.isRequired, | ||
56 | service: PropTypes.instanceOf(ServiceModel).isRequired, | 90 | service: PropTypes.instanceOf(ServiceModel).isRequired, |
57 | clickHandler: PropTypes.func.isRequired, | 91 | clickHandler: PropTypes.func.isRequired, |
58 | shortcutIndex: PropTypes.number.isRequired, | 92 | shortcutIndex: PropTypes.number.isRequired, |
@@ -71,8 +105,33 @@ class TabItem extends Component { | |||
71 | intl: intlShape, | 105 | intl: intlShape, |
72 | }; | 106 | }; |
73 | 107 | ||
108 | @observable isPolled = false; | ||
109 | |||
110 | @observable isPollAnswered = false; | ||
111 | |||
112 | componentDidMount() { | ||
113 | const { service } = this.props; | ||
114 | |||
115 | if (IS_SERVICE_DEBUGGING_ENABLED) { | ||
116 | autorun(() => { | ||
117 | if (Date.now() - service.lastPoll < ms('0.2s')) { | ||
118 | this.isPolled = true; | ||
119 | |||
120 | setTimeout(() => { this.isPolled = false; }, ms('1s')); | ||
121 | } | ||
122 | |||
123 | if (Date.now() - service.lastPollAnswer < ms('0.2s')) { | ||
124 | this.isPollAnswered = true; | ||
125 | |||
126 | setTimeout(() => { this.isPollAnswered = false; }, ms('1s')); | ||
127 | } | ||
128 | }); | ||
129 | } | ||
130 | } | ||
131 | |||
74 | render() { | 132 | render() { |
75 | const { | 133 | const { |
134 | classes, | ||
76 | service, | 135 | service, |
77 | clickHandler, | 136 | clickHandler, |
78 | shortcutIndex, | 137 | shortcutIndex, |
@@ -97,6 +156,7 @@ class TabItem extends Component { | |||
97 | }, { | 156 | }, { |
98 | label: intl.formatMessage(messages.reload), | 157 | label: intl.formatMessage(messages.reload), |
99 | click: reload, | 158 | click: reload, |
159 | accelerator: `${cmdKey}+R`, | ||
100 | }, { | 160 | }, { |
101 | label: intl.formatMessage(messages.edit), | 161 | label: intl.formatMessage(messages.edit), |
102 | click: () => openSettings({ | 162 | click: () => openSettings({ |
@@ -141,7 +201,7 @@ class TabItem extends Component { | |||
141 | • | 201 | • |
142 | </span> | 202 | </span> |
143 | )} | 203 | )} |
144 | {service.isHibernating && !service.disableHibernation && ( | 204 | {service.isHibernating && !service.isHibernationEnabled && ( |
145 | <span className="tab-item__message-count hibernating"> | 205 | <span className="tab-item__message-count hibernating"> |
146 | • | 206 | • |
147 | </span> | 207 | </span> |
@@ -153,6 +213,7 @@ class TabItem extends Component { | |||
153 | return ( | 213 | return ( |
154 | <li | 214 | <li |
155 | className={classnames({ | 215 | className={classnames({ |
216 | [classes.stale]: IS_SERVICE_DEBUGGING_ENABLED && service.lostRecipeConnection, | ||
156 | 'tab-item': true, | 217 | 'tab-item': true, |
157 | 'is-active': service.isActive, | 218 | 'is-active': service.isActive, |
158 | 'has-custom-icon': service.hasCustomIcon, | 219 | 'has-custom-icon': service.hasCustomIcon, |
@@ -168,6 +229,24 @@ class TabItem extends Component { | |||
168 | alt="" | 229 | alt="" |
169 | /> | 230 | /> |
170 | {notificationBadge} | 231 | {notificationBadge} |
232 | {IS_SERVICE_DEBUGGING_ENABLED && ( | ||
233 | <> | ||
234 | <div | ||
235 | className={classnames({ | ||
236 | [classes.pollIndicator]: true, | ||
237 | [classes.pollIndicatorPoll]: true, | ||
238 | [classes.polled]: this.isPolled, | ||
239 | })} | ||
240 | /> | ||
241 | <div | ||
242 | className={classnames({ | ||
243 | [classes.pollIndicator]: true, | ||
244 | [classes.pollIndicatorAnswer]: true, | ||
245 | [classes.pollAnswered]: this.isPollAnswered, | ||
246 | })} | ||
247 | /> | ||
248 | </> | ||
249 | )} | ||
171 | </li> | 250 | </li> |
172 | ); | 251 | ); |
173 | } | 252 | } |