aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Markus Hatvan <markus_hatvan@aon.at>2021-07-02 19:49:55 -0600
committerLibravatar GitHub <noreply@github.com>2021-07-03 07:19:55 +0530
commit33123c354b79f7951423dd75097b11e7eb075f99 (patch)
tree29f6e857f02d0e0fc67d89a657a54a865ed5538a /src
parentMinor refactoring to move all runtime configs from 'config.js' into 'environm... (diff)
downloadferdium-app-33123c354b79f7951423dd75097b11e7eb075f99.tar.gz
ferdium-app-33123c354b79f7951423dd75097b11e7eb075f99.tar.zst
ferdium-app-33123c354b79f7951423dd75097b11e7eb075f99.zip
Upgrade various dependencies to latest part 2 (#1557)
* Upgrade various dependencies to latest, remove unnecessary electron-hunspell - upgrade eslint and friends to latest - remove deprecated 'node-sass' in favor of 'sass' - disable new rules from 'eslint-config-airbnb' that are conflicting with current code style - add workspace config for 'vscode' that silences 'experimentalDecorator' warning and forces 'prettier' to single quote * Run yarn lint to autofix with new ruleset and worked down lint issues to zero
Diffstat (limited to 'src')
-rw-r--r--src/actions/index.js4
-rw-r--r--src/api/server/ServerApi.js4
-rw-r--r--src/api/utils/auth.js5
-rw-r--r--src/components/auth/Import.js87
-rw-r--r--src/components/auth/Invite.js105
-rw-r--r--src/components/auth/Pricing.js1
-rw-r--r--src/components/auth/Welcome.js1
-rw-r--r--src/components/services/content/ServiceView.js8
-rw-r--r--src/components/services/content/Services.js1
-rw-r--r--src/components/services/content/WebviewCrashHandler.js1
-rw-r--r--src/components/settings/SettingsLayout.js37
-rw-r--r--src/components/settings/services/EditServiceForm.js15
-rw-r--r--src/components/settings/settings/EditSettingsForm.js9
-rw-r--r--src/components/settings/team/TeamDashboard.js1
-rw-r--r--src/components/ui/ImageUpload.js4
-rw-r--r--src/components/ui/InfoBar.js25
-rw-r--r--src/components/ui/Infobox.js33
-rw-r--r--src/components/ui/Input.js54
-rw-r--r--src/components/ui/Tabs/TabItem.js2
-rw-r--r--src/components/ui/Tabs/Tabs.js8
-rw-r--r--src/containers/settings/AccountScreen.js3
-rw-r--r--src/containers/settings/SettingsWindow.js1
-rw-r--r--src/containers/subscription/SubscriptionPopupScreen.js2
-rw-r--r--src/features/announcements/components/AnnouncementScreen.js1
-rw-r--r--src/features/announcements/index.js1
-rw-r--r--src/features/delayApp/index.js1
-rw-r--r--src/features/planSelection/components/PlanItem.js1
-rw-r--r--src/features/publishDebugInfo/Component.js1
-rw-r--r--src/features/serviceLimit/components/LimitReachedInfobox.js1
-rw-r--r--src/features/todos/components/TodosWebview.js51
-rw-r--r--src/features/trialStatusBar/containers/TrialStatusBarScreen.js20
-rw-r--r--src/features/workspaces/components/EditWorkspaceForm.js23
-rw-r--r--src/features/workspaces/components/WorkspacesDashboard.js8
-rw-r--r--src/features/workspaces/containers/EditWorkspaceScreen.js4
-rw-r--r--src/features/workspaces/store.js47
-rw-r--r--src/i18n/apply-branding.js1
-rw-r--r--src/i18n/locales/defaultMessages.json166
-rw-r--r--src/i18n/locales/en-US.json4
-rw-r--r--src/i18n/messages/src/components/auth/Pricing.json52
-rw-r--r--src/i18n/messages/src/components/settings/SettingsLayout.json15
-rw-r--r--src/i18n/messages/src/components/ui/InfoBar.json15
-rw-r--r--src/i18n/messages/src/components/ui/Infobox.json15
-rw-r--r--src/i18n/messages/src/components/ui/Input.json15
-rw-r--r--src/i18n/messages/src/features/publishDebugInfo/Component.json28
-rw-r--r--src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json14
-rw-r--r--src/lib/Menu.js1
-rw-r--r--src/models/User.js1
-rw-r--r--src/stores/AppStore.js2
-rw-r--r--src/stores/FeaturesStore.js4
-rw-r--r--src/stores/ServicesStore.js1
-rw-r--r--src/theme/default/legacy.js1
-rw-r--r--src/webview/contextMenuBuilder.js2
-rw-r--r--src/webview/lib/RecipeWebview.js1
-rw-r--r--src/webview/screenshare.js39
54 files changed, 575 insertions, 372 deletions
diff --git a/src/actions/index.js b/src/actions/index.js
index 9d3684edc..6f32732b9 100644
--- a/src/actions/index.js
+++ b/src/actions/index.js
@@ -17,7 +17,7 @@ import todos from '../features/todos/actions';
17import planSelection from '../features/planSelection/actions'; 17import planSelection from '../features/planSelection/actions';
18import trialStatusBar from '../features/trialStatusBar/actions'; 18import trialStatusBar from '../features/trialStatusBar/actions';
19 19
20const actions = Object.assign({}, { 20const actions = {
21 service, 21 service,
22 recipe, 22 recipe,
23 recipePreview, 23 recipePreview,
@@ -28,7 +28,7 @@ const actions = Object.assign({}, {
28 news, 28 news,
29 settings, 29 settings,
30 requests, 30 requests,
31}); 31};
32 32
33export default Object.assign( 33export default Object.assign(
34 defineActions(actions, PropTypes.checkPropTypes), 34 defineActions(actions, PropTypes.checkPropTypes),
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js
index 75d18f234..8fdaed363 100644
--- a/src/api/server/ServerApi.js
+++ b/src/api/server/ServerApi.js
@@ -183,9 +183,7 @@ export default class ServerApi {
183 async createService(recipeId, data) { 183 async createService(recipeId, data) {
184 const request = await sendAuthRequest(`${apiBase()}/service`, { 184 const request = await sendAuthRequest(`${apiBase()}/service`, {
185 method: 'POST', 185 method: 'POST',
186 body: JSON.stringify(Object.assign({ 186 body: JSON.stringify({ recipeId, ...data }),
187 recipeId,
188 }, data)),
189 }); 187 });
190 if (!request.ok) { 188 if (!request.ok) {
191 throw request; 189 throw request;
diff --git a/src/api/utils/auth.js b/src/api/utils/auth.js
index 5952cfe11..9f718f171 100644
--- a/src/api/utils/auth.js
+++ b/src/api/utils/auth.js
@@ -4,14 +4,15 @@ import localStorage from 'mobx-localstorage';
4export const prepareAuthRequest = (options = { method: 'GET' }, auth = true) => { 4export const prepareAuthRequest = (options = { method: 'GET' }, auth = true) => {
5 const request = Object.assign(options, { 5 const request = Object.assign(options, {
6 mode: 'cors', 6 mode: 'cors',
7 headers: Object.assign({ 7 headers: {
8 'Content-Type': 'application/json', 8 'Content-Type': 'application/json',
9 'X-Franz-Source': 'desktop', 9 'X-Franz-Source': 'desktop',
10 'X-Franz-Version': app.getVersion(), 10 'X-Franz-Version': app.getVersion(),
11 'X-Franz-platform': process.platform, 11 'X-Franz-platform': process.platform,
12 'X-Franz-Timezone-Offset': new Date().getTimezoneOffset(), 12 'X-Franz-Timezone-Offset': new Date().getTimezoneOffset(),
13 'X-Franz-System-Locale': app.getLocale(), 13 'X-Franz-System-Locale': app.getLocale(),
14 }, options.headers), 14 ...options.headers,
15 },
15 }); 16 });
16 17
17 if (auth) { 18 if (auth) {
diff --git a/src/components/auth/Import.js b/src/components/auth/Import.js
index 3e34c3162..3073cad73 100644
--- a/src/components/auth/Import.js
+++ b/src/components/auth/Import.js
@@ -28,7 +28,9 @@ const messages = defineMessages({
28 }, 28 },
29}); 29});
30 30
31export default @observer class Import extends Component { 31export default
32@observer
33class Import extends Component {
32 static propTypes = { 34 static propTypes = {
33 services: MobxPropTypes.arrayOrObservableArray.isRequired, 35 services: MobxPropTypes.arrayOrObservableArray.isRequired,
34 onSubmit: PropTypes.func.isRequired, 36 onSubmit: PropTypes.func.isRequired,
@@ -40,17 +42,21 @@ export default @observer class Import extends Component {
40 intl: intlShape, 42 intl: intlShape,
41 }; 43 };
42 44
43 componentWillMount() { 45 componentDidMount() {
44 const config = { 46 const config = {
45 fields: { 47 fields: {
46 import: [...this.props.services.filter(s => s.recipe).map(s => ({ 48 import: [
47 fields: { 49 ...this.props.services
48 add: { 50 .filter((s) => s.recipe)
49 default: true, 51 .map((s) => ({
50 options: s, 52 fields: {
51 }, 53 add: {
52 }, 54 default: true,
53 }))], 55 options: s,
56 },
57 },
58 })),
59 ],
54 }, 60 },
55 }; 61 };
56 62
@@ -62,9 +68,12 @@ export default @observer class Import extends Component {
62 e.preventDefault(); 68 e.preventDefault();
63 this.form.submit({ 69 this.form.submit({
64 onSuccess: (form) => { 70 onSuccess: (form) => {
65 const servicesImport = form.values().import 71 const servicesImport = form
66 .map((value, i) => !value.add || services.filter(s => s.recipe)[i]) 72 .values()
67 .filter(s => typeof s !== 'boolean'); 73 .import.map(
74 (value, i) => !value.add || services.filter((s) => s.recipe)[i],
75 )
76 .filter((s) => typeof s !== 'boolean');
68 77
69 this.props.onSubmit({ services: servicesImport }); 78 this.props.onSubmit({ services: servicesImport });
70 }, 79 },
@@ -76,37 +85,31 @@ export default @observer class Import extends Component {
76 const { intl } = this.context; 85 const { intl } = this.context;
77 const { services, isSubmitting, inviteRoute } = this.props; 86 const { services, isSubmitting, inviteRoute } = this.props;
78 87
79 const availableServices = services.filter(s => s.recipe); 88 const availableServices = services.filter((s) => s.recipe);
80 const unavailableServices = services.filter(s => !s.recipe); 89 const unavailableServices = services.filter((s) => !s.recipe);
81 90
82 return ( 91 return (
83 <div className="auth__scroll-container"> 92 <div className="auth__scroll-container">
84 <div className="auth__container auth__container--signup"> 93 <div className="auth__container auth__container--signup">
85 <form className="franz-form auth__form" onSubmit={e => this.submit(e)}> 94 <form
86 <img 95 className="franz-form auth__form"
87 src="./assets/images/logo.svg" 96 onSubmit={(e) => this.submit(e)}
88 className="auth__logo" 97 >
89 alt="" 98 <img src="./assets/images/logo.svg" className="auth__logo" alt="" />
90 /> 99 <h1>{intl.formatMessage(messages.headline)}</h1>
91 <h1>
92 {intl.formatMessage(messages.headline)}
93 </h1>
94 <table className="service-table available-services"> 100 <table className="service-table available-services">
95 <tbody> 101 <tbody>
96 {this.form.$('import').map((service, i) => ( 102 {this.form.$('import').map((service, i) => (
97 <tr 103 <tr key={service.id} className="service-table__row">
98 key={service.id}
99 className="service-table__row"
100 >
101 <td className="service-table__toggle"> 104 <td className="service-table__toggle">
102 <Toggle 105 <Toggle field={service.$('add')} showLabel={false} />
103 field={service.$('add')}
104 showLabel={false}
105 />
106 </td> 106 </td>
107 <td className="service-table__column-icon"> 107 <td className="service-table__column-icon">
108 <img 108 <img
109 src={availableServices[i].custom_icon || availableServices[i].recipe.icons.svg} 109 src={
110 availableServices[i].custom_icon
111 || availableServices[i].recipe.icons.svg
112 }
110 className={classnames({ 113 className={classnames({
111 'service-table__icon': true, 114 'service-table__icon': true,
112 'has-custom-icon': availableServices[i].custom_icon, 115 'has-custom-icon': availableServices[i].custom_icon,
@@ -125,14 +128,18 @@ export default @observer class Import extends Component {
125 </table> 128 </table>
126 {unavailableServices.length > 0 && ( 129 {unavailableServices.length > 0 && (
127 <div className="unavailable-services"> 130 <div className="unavailable-services">
128 <strong>{intl.formatMessage(messages.notSupportedHeadline)}</strong> 131 <strong>
132 {intl.formatMessage(messages.notSupportedHeadline)}
133 </strong>
129 <p> 134 <p>
130 {services.filter(s => !s.recipe).map((service, i) => ( 135 {services
131 <span key={service.id}> 136 .filter((s) => !s.recipe)
132 {service.name !== '' ? service.name : service.service} 137 .map((service, i) => (
133 {unavailableServices.length > i + 1 ? ', ' : ''} 138 <span key={service.id}>
134 </span> 139 {service.name !== '' ? service.name : service.service}
135 ))} 140 {unavailableServices.length > i + 1 ? ', ' : ''}
141 </span>
142 ))}
136 </p> 143 </p>
137 </div> 144 </div>
138 )} 145 )}
diff --git a/src/components/auth/Invite.js b/src/components/auth/Invite.js
index fd957ee73..4b4d63a6b 100644
--- a/src/components/auth/Invite.js
+++ b/src/components/auth/Invite.js
@@ -43,7 +43,9 @@ const messages = defineMessages({
43 }, 43 },
44}); 44});
45 45
46export default @observer class Invite extends Component { 46export default
47@observer
48class Invite extends Component {
47 static propTypes = { 49 static propTypes = {
48 onSubmit: PropTypes.func.isRequired, 50 onSubmit: PropTypes.func.isRequired,
49 embed: PropTypes.bool, 51 embed: PropTypes.bool,
@@ -63,36 +65,41 @@ export default @observer class Invite extends Component {
63 65
64 state = { showSuccessInfo: false }; 66 state = { showSuccessInfo: false };
65 67
66 componentWillMount() { 68 componentDidMount() {
67 const handlers = { 69 this.form = new Form(
68 onChange: () => { 70 {
69 this.setState({ showSuccessInfo: false }); 71 fields: {
70 }, 72 invite: [
71 }; 73 ...Array(3).fill({
72 74 fields: {
73 this.form = new Form({ 75 name: {
74 fields: { 76 label: this.context.intl.formatMessage(messages.nameLabel),
75 invite: [...Array(3).fill({ 77 placeholder: this.context.intl.formatMessage(
76 fields: { 78 messages.nameLabel,
77 name: { 79 ),
78 label: this.context.intl.formatMessage(messages.nameLabel), 80 onChange: () => {
79 placeholder: this.context.intl.formatMessage(messages.nameLabel), 81 this.setState({ showSuccessInfo: false });
80 handlers, 82 },
81 // related: ['invite.0.email'], // path accepted but does not work 83 // related: ['invite.0.email'], // path accepted but does not work
82 }, 84 },
83 email: { 85 email: {
84 label: this.context.intl.formatMessage(messages.emailLabel), 86 label: this.context.intl.formatMessage(messages.emailLabel),
85 placeholder: this.context.intl.formatMessage(messages.emailLabel), 87 placeholder: this.context.intl.formatMessage(
86 handlers, 88 messages.emailLabel,
87 validators: [email], 89 ),
88 }, 90 onChange: () => {
89 }, 91 this.setState({ showSuccessInfo: false });
90 })], 92 },
93 validators: [email],
94 },
95 },
96 }),
97 ],
98 },
91 }, 99 },
92 }, this.context.intl); 100 this.context.intl,
93 } 101 );
94 102
95 componentDidMount() {
96 document.querySelector('input:first-child').focus(); 103 document.querySelector('input:first-child').focus();
97 } 104 }
98 105
@@ -117,9 +124,10 @@ export default @observer class Invite extends Component {
117 const { intl } = this.context; 124 const { intl } = this.context;
118 const { embed, isInviteSuccessful, isLoadingInvite } = this.props; 125 const { embed, isInviteSuccessful, isLoadingInvite } = this.props;
119 126
120 const atLeastOneEmailAddress = form.$('invite') 127 const atLeastOneEmailAddress = form
121 .map(invite => invite.$('email').value) 128 .$('invite')
122 .some(emailValue => emailValue.trim() !== ''); 129 .map((invite) => invite.$('email').value)
130 .some((emailValue) => emailValue.trim() !== '');
123 131
124 const sendButtonClassName = classnames({ 132 const sendButtonClassName = classnames({
125 auth__button: true, 133 auth__button: true,
@@ -127,7 +135,7 @@ export default @observer class Invite extends Component {
127 }); 135 });
128 136
129 const renderForm = ( 137 const renderForm = (
130 <Fragment> 138 <>
131 {this.state.showSuccessInfo && isInviteSuccessful && ( 139 {this.state.showSuccessInfo && isInviteSuccessful && (
132 <Appear> 140 <Appear>
133 <Infobox 141 <Infobox
@@ -140,18 +148,17 @@ export default @observer class Invite extends Component {
140 </Appear> 148 </Appear>
141 )} 149 )}
142 150
143 <form className="franz-form auth__form" onSubmit={e => this.submit(e)}> 151 <form
152 className="franz-form auth__form"
153 onSubmit={(e) => this.submit(e)}
154 >
144 {!embed && ( 155 {!embed && (
145 <img 156 <img src="./assets/images/logo.svg" className="auth__logo" alt="" />
146 src="./assets/images/logo.svg"
147 className="auth__logo"
148 alt=""
149 />
150 )} 157 )}
151 <h1 className={embed && 'invite__embed'}> 158 <h1 className={embed && 'invite__embed'}>
152 {intl.formatMessage(messages.headline)} 159 {intl.formatMessage(messages.headline)}
153 </h1> 160 </h1>
154 {form.$('invite').map(invite => ( 161 {form.$('invite').map((invite) => (
155 <div className="grid" key={invite.key}> 162 <div className="grid" key={invite.key}>
156 <div className="grid__row"> 163 <div className="grid__row">
157 <Input field={invite.$('name')} showLabel={false} /> 164 <Input field={invite.$('name')} showLabel={false} />
@@ -175,17 +182,27 @@ export default @observer class Invite extends Component {
175 </Link> 182 </Link>
176 )} 183 )}
177 </form> 184 </form>
178 </Fragment> 185 </>
179 ); 186 );
180 187
181 return ( 188 return (
182 <div className={!embed ? 'auth__container auth__container--signup' : 'settings__main'}> 189 <div
190 className={
191 !embed ? 'auth__container auth__container--signup' : 'settings__main'
192 }
193 >
183 {embed && ( 194 {embed && (
184 <div className="settings__header"> 195 <div className="settings__header">
185 <h1>{this.context.intl.formatMessage(messages.settingsHeadline)}</h1> 196 <h1>
197 {this.context.intl.formatMessage(messages.settingsHeadline)}
198 </h1>
186 </div> 199 </div>
187 )} 200 )}
188 {!embed ? <div>{renderForm}</div> : <div className="settings__body invite__form">{renderForm}</div>} 201 {!embed ? (
202 <div>{renderForm}</div>
203 ) : (
204 <div className="settings__body invite__form">{renderForm}</div>
205 )}
189 </div> 206 </div>
190 ); 207 );
191 } 208 }
diff --git a/src/components/auth/Pricing.js b/src/components/auth/Pricing.js
index fecc6ba56..2fcabe54d 100644
--- a/src/components/auth/Pricing.js
+++ b/src/components/auth/Pricing.js
@@ -10,7 +10,6 @@ import { Button } from '@meetfranz/forms';
10import { FeatureItem } from '../ui/FeatureItem'; 10import { FeatureItem } from '../ui/FeatureItem';
11import { FeatureList } from '../ui/FeatureList'; 11import { FeatureList } from '../ui/FeatureList';
12 12
13
14const messages = defineMessages({ 13const messages = defineMessages({
15 headline: { 14 headline: {
16 id: 'pricing.trial.headline.pro', 15 id: 'pricing.trial.headline.pro',
diff --git a/src/components/auth/Welcome.js b/src/components/auth/Welcome.js
index 6e742e0c1..5f2fac64b 100644
--- a/src/components/auth/Welcome.js
+++ b/src/components/auth/Welcome.js
@@ -72,7 +72,6 @@ export default @inject('actions') @observer class Login extends Component {
72 <br /> 72 <br />
73 <br /> 73 <br />
74 74
75
76 <Link to={changeServerRoute}> 75 <Link to={changeServerRoute}>
77 <span style={{ 76 <span style={{
78 textAlign: 'center', 77 textAlign: 'center',
diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js
index 444d5fea4..3c0fed32b 100644
--- a/src/components/services/content/ServiceView.js
+++ b/src/components/services/content/ServiceView.js
@@ -109,7 +109,7 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
109 return ( 109 return (
110 <div className={webviewClasses}> 110 <div className={webviewClasses}>
111 {service.isActive && service.isEnabled && ( 111 {service.isActive && service.isEnabled && (
112 <Fragment> 112 <>
113 {service.hasCrashed && ( 113 {service.hasCrashed && (
114 <WebviewCrashHandler 114 <WebviewCrashHandler
115 name={service.recipe.name} 115 name={service.recipe.name}
@@ -131,10 +131,10 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
131 edit={edit} 131 edit={edit}
132 /> 132 />
133 )} 133 )}
134 </Fragment> 134 </>
135 )} 135 )}
136 {!service.isEnabled ? ( 136 {!service.isEnabled ? (
137 <Fragment> 137 <>
138 {service.isActive && ( 138 {service.isActive && (
139 <ServiceDisabled 139 <ServiceDisabled
140 name={service.recipe.name} 140 name={service.recipe.name}
@@ -142,7 +142,7 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
142 enable={enable} 142 enable={enable}
143 /> 143 />
144 )} 144 )}
145 </Fragment> 145 </>
146 ) : ( 146 ) : (
147 <> 147 <>
148 {(!service.isHibernating || service.isHibernationEnabled) ? ( 148 {(!service.isHibernating || service.isHibernationEnabled) ? (
diff --git a/src/components/services/content/Services.js b/src/components/services/content/Services.js
index 7cf02c237..caa3cf9aa 100644
--- a/src/components/services/content/Services.js
+++ b/src/components/services/content/Services.js
@@ -34,7 +34,6 @@ const messages = defineMessages({
34 }, 34 },
35}); 35});
36 36
37
38const styles = { 37const styles = {
39 confettiContainer: { 38 confettiContainer: {
40 position: 'absolute', 39 position: 'absolute',
diff --git a/src/components/services/content/WebviewCrashHandler.js b/src/components/services/content/WebviewCrashHandler.js
index 7a69dba87..b62940c06 100644
--- a/src/components/services/content/WebviewCrashHandler.js
+++ b/src/components/services/content/WebviewCrashHandler.js
@@ -43,7 +43,6 @@ export default @observer class WebviewCrashHandler extends Component {
43 43
44 countdownIntervalTimeout = ms('1s'); 44 countdownIntervalTimeout = ms('1s');
45 45
46
47 componentDidMount() { 46 componentDidMount() {
48 const { reload } = this.props; 47 const { reload } = this.props;
49 48
diff --git a/src/components/settings/SettingsLayout.js b/src/components/settings/SettingsLayout.js
index 72ba7b2e3..5b3b754fa 100644
--- a/src/components/settings/SettingsLayout.js
+++ b/src/components/settings/SettingsLayout.js
@@ -1,38 +1,55 @@
1import React, { Component } from 'react'; 1import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
4 5
5import ErrorBoundary from '../util/ErrorBoundary'; 6import ErrorBoundary from '../util/ErrorBoundary';
6import { oneOrManyChildElements } from '../../prop-types'; 7import { oneOrManyChildElements } from '../../prop-types';
7import Appear from '../ui/effects/Appear'; 8import Appear from '../ui/effects/Appear';
8 9
9export default @observer class SettingsLayout extends Component { 10const messages = defineMessages({
11 closeSettings: {
12 id: 'settings.app.closeSettings',
13 defaultMessage: '!!!Close settings',
14 },
15});
16
17export default
18@observer
19class SettingsLayout extends Component {
10 static propTypes = { 20 static propTypes = {
11 navigation: PropTypes.element.isRequired, 21 navigation: PropTypes.element.isRequired,
12 children: oneOrManyChildElements.isRequired, 22 children: oneOrManyChildElements.isRequired,
13 closeSettings: PropTypes.func.isRequired, 23 closeSettings: PropTypes.func.isRequired,
14 }; 24 };
15 25
16 componentWillMount() { 26 static contextTypes = {
27 intl: intlShape,
28 };
29
30 componentDidMount() {
17 document.addEventListener('keydown', this.handleKeyDown.bind(this), false); 31 document.addEventListener('keydown', this.handleKeyDown.bind(this), false);
18 } 32 }
19 33
20 componentWillUnmount() { 34 componentWillUnmount() {
21 document.removeEventListener('keydown', this.handleKeyDown.bind(this), false); 35 document.removeEventListener(
36 'keydown',
37 this.handleKeyDown.bind(this),
38 false,
39 );
22 } 40 }
23 41
24 handleKeyDown(e) { 42 handleKeyDown(e) {
25 if (e.keyCode === 27) { // escape key 43 if (e.keyCode === 27) {
44 // escape key
26 this.props.closeSettings(); 45 this.props.closeSettings();
27 } 46 }
28 } 47 }
29 48
30 render() { 49 render() {
31 const { 50 const { navigation, children, closeSettings } = this.props;
32 navigation, 51
33 children, 52 const { intl } = this.context;
34 closeSettings,
35 } = this.props;
36 53
37 return ( 54 return (
38 <Appear transitionName="fadeIn-fast"> 55 <Appear transitionName="fadeIn-fast">
@@ -42,6 +59,7 @@ export default @observer class SettingsLayout extends Component {
42 type="button" 59 type="button"
43 className="settings-wrapper__action" 60 className="settings-wrapper__action"
44 onClick={closeSettings} 61 onClick={closeSettings}
62 aria-label={intl.formatMessage(messages.closeSettings)}
45 /> 63 />
46 <div className="settings franz-form"> 64 <div className="settings franz-form">
47 {navigation} 65 {navigation}
@@ -50,6 +68,7 @@ export default @observer class SettingsLayout extends Component {
50 type="button" 68 type="button"
51 className="settings__close mdi mdi-close" 69 className="settings__close mdi mdi-close"
52 onClick={closeSettings} 70 onClick={closeSettings}
71 aria-label={intl.formatMessage(messages.closeSettings)}
53 /> 72 />
54 </div> 73 </div>
55 </ErrorBoundary> 74 </ErrorBoundary>
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js
index 1bbc1f1d4..a8501670b 100644
--- a/src/components/settings/services/EditServiceForm.js
+++ b/src/components/settings/services/EditServiceForm.js
@@ -311,14 +311,14 @@ export default @observer class EditServiceForm extends Component {
311 {recipe.hasCustomUrl && ( 311 {recipe.hasCustomUrl && (
312 <TabItem title={intl.formatMessage(messages.tabOnPremise)}> 312 <TabItem title={intl.formatMessage(messages.tabOnPremise)}>
313 {user.isPremium || recipe.author.find(a => a.email === user.email) ? ( 313 {user.isPremium || recipe.author.find(a => a.email === user.email) ? (
314 <Fragment> 314 <>
315 <Input field={form.$('customUrl')} /> 315 <Input field={form.$('customUrl')} />
316 {form.error === 'url-validation-error' && ( 316 {form.error === 'url-validation-error' && (
317 <p className="franz-form__error"> 317 <p className="franz-form__error">
318 {intl.formatMessage(messages.customUrlValidationError, { name: recipe.name })} 318 {intl.formatMessage(messages.customUrlValidationError, { name: recipe.name })}
319 </p> 319 </p>
320 )} 320 )}
321 </Fragment> 321 </>
322 ) : ( 322 ) : (
323 <div className="center premium-info"> 323 <div className="center premium-info">
324 <p>{intl.formatMessage(messages.customUrlPremiumInfo)}</p> 324 <p>{intl.formatMessage(messages.customUrlPremiumInfo)}</p>
@@ -360,12 +360,12 @@ export default @observer class EditServiceForm extends Component {
360 <h3>{intl.formatMessage(messages.headlineBadges)}</h3> 360 <h3>{intl.formatMessage(messages.headlineBadges)}</h3>
361 <Toggle field={form.$('isBadgeEnabled')} /> 361 <Toggle field={form.$('isBadgeEnabled')} />
362 {recipe.hasIndirectMessages && form.$('isBadgeEnabled').value && ( 362 {recipe.hasIndirectMessages && form.$('isBadgeEnabled').value && (
363 <Fragment> 363 <>
364 <Toggle field={form.$('isIndirectMessageBadgeEnabled')} /> 364 <Toggle field={form.$('isIndirectMessageBadgeEnabled')} />
365 <p className="settings__help"> 365 <p className="settings__help">
366 {intl.formatMessage(messages.indirectMessageInfo)} 366 {intl.formatMessage(messages.indirectMessageInfo)}
367 </p> 367 </p>
368 </Fragment> 368 </>
369 )} 369 )}
370 </div> 370 </div>
371 371
@@ -389,8 +389,7 @@ export default @observer class EditServiceForm extends Component {
389 <Slider field={form.$('darkReaderContrast')} /> 389 <Slider field={form.$('darkReaderContrast')} />
390 <Slider field={form.$('darkReaderSepia')} /> 390 <Slider field={form.$('darkReaderSepia')} />
391 </> 391 </>
392 ) 392 )}
393 }
394 </div> 393 </div>
395 </div> 394 </div>
396 <div className="service-icon"> 395 <div className="service-icon">
@@ -425,7 +424,7 @@ export default @observer class EditServiceForm extends Component {
425 </h3> 424 </h3>
426 <Toggle field={form.$('proxy.isEnabled')} /> 425 <Toggle field={form.$('proxy.isEnabled')} />
427 {form.$('proxy.isEnabled').value && ( 426 {form.$('proxy.isEnabled').value && (
428 <Fragment> 427 <>
429 <div className="grid"> 428 <div className="grid">
430 <div className="grid__row"> 429 <div className="grid__row">
431 <Input field={form.$('proxy.host')} className="proxyHost" /> 430 <Input field={form.$('proxy.host')} className="proxyHost" />
@@ -449,7 +448,7 @@ export default @observer class EditServiceForm extends Component {
449 <span className="mdi mdi-information" /> 448 <span className="mdi mdi-information" />
450 {intl.formatMessage(messages.proxyInfo)} 449 {intl.formatMessage(messages.proxyInfo)}
451 </p> 450 </p>
452 </Fragment> 451 </>
453 )} 452 )}
454 </div> 453 </div>
455 </PremiumFeatureContainer> 454 </PremiumFeatureContainer>
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js
index 4ba7dc720..98a119bfa 100644
--- a/src/components/settings/settings/EditSettingsForm.js
+++ b/src/components/settings/settings/EditSettingsForm.js
@@ -567,7 +567,7 @@ export default @observer class EditSettingsForm extends Component {
567 condition={!isSpellcheckerIncludedInCurrentPlan} 567 condition={!isSpellcheckerIncludedInCurrentPlan}
568 gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }} 568 gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }}
569 > 569 >
570 <Fragment> 570 <>
571 <Toggle 571 <Toggle
572 field={form.$('enableSpellchecking')} 572 field={form.$('enableSpellchecking')}
573 /> 573 />
@@ -577,7 +577,7 @@ export default @observer class EditSettingsForm extends Component {
577 {isMac && form.$('enableSpellchecking').value && ( 577 {isMac && form.$('enableSpellchecking').value && (
578 <p>{intl.formatMessage(messages.spellCheckerLanguageInfo)}</p> 578 <p>{intl.formatMessage(messages.spellCheckerLanguageInfo)}</p>
579 )} 579 )}
580 </Fragment> 580 </>
581 </PremiumFeatureContainer> 581 </PremiumFeatureContainer>
582 <a 582 <a
583 href={FRANZ_TRANSLATION} 583 href={FRANZ_TRANSLATION}
@@ -679,18 +679,15 @@ export default @observer class EditSettingsForm extends Component {
679 <br /> 679 <br />
680 {intl.formatMessage(messages.updateStatusUpToDate)} 680 {intl.formatMessage(messages.updateStatusUpToDate)}
681 </> 681 </>
682 ) 682 )}
683 }
684 <p className="settings__message"> 683 <p className="settings__message">
685 <span className="mdi mdi-github-face" /> 684 <span className="mdi mdi-github-face" />
686 <span> 685 <span>
687 686
688
689 Ferdi is based on 687 Ferdi is based on
690 {' '} 688 {' '}
691 <a href={`${GITHUB_FRANZ_URL}/franz`} target="_blank">Franz</a> 689 <a href={`${GITHUB_FRANZ_URL}/franz`} target="_blank">Franz</a>
692 690
693
694 , a project published 691 , a project published
695 under the 692 under the
696 {' '} 693 {' '}
diff --git a/src/components/settings/team/TeamDashboard.js b/src/components/settings/team/TeamDashboard.js
index f26f4cc0c..602d6e490 100644
--- a/src/components/settings/team/TeamDashboard.js
+++ b/src/components/settings/team/TeamDashboard.js
@@ -98,7 +98,6 @@ const styles = {
98 }, 98 },
99}; 99};
100 100
101
102export default @injectSheet(styles) @observer class TeamDashboard extends Component { 101export default @injectSheet(styles) @observer class TeamDashboard extends Component {
103 static propTypes = { 102 static propTypes = {
104 isLoading: PropTypes.bool.isRequired, 103 isLoading: PropTypes.bool.isRequired,
diff --git a/src/components/ui/ImageUpload.js b/src/components/ui/ImageUpload.js
index e831eb47b..6a8c7645f 100644
--- a/src/components/ui/ImageUpload.js
+++ b/src/components/ui/ImageUpload.js
@@ -55,7 +55,7 @@ export default @observer class ImageUpload extends Component {
55 </label> 55 </label>
56 <div className="image-upload"> 56 <div className="image-upload">
57 {(field.value && field.value !== 'delete') || this.state.path ? ( 57 {(field.value && field.value !== 'delete') || this.state.path ? (
58 <Fragment> 58 <>
59 <div 59 <div
60 className="image-upload__preview" 60 className="image-upload__preview"
61 style={{ 61 style={{
@@ -80,7 +80,7 @@ export default @observer class ImageUpload extends Component {
80 </button> 80 </button>
81 <div className="image-upload__action-background" /> 81 <div className="image-upload__action-background" />
82 </div> 82 </div>
83 </Fragment> 83 </>
84 ) : ( 84 ) : (
85 <Dropzone 85 <Dropzone
86 ref={(node) => { 86 ref={(node) => {
diff --git a/src/components/ui/InfoBar.js b/src/components/ui/InfoBar.js
index 612399e9f..bd2af2296 100644
--- a/src/components/ui/InfoBar.js
+++ b/src/components/ui/InfoBar.js
@@ -3,11 +3,21 @@ import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import classnames from 'classnames'; 4import classnames from 'classnames';
5import Loader from 'react-loader'; 5import Loader from 'react-loader';
6import { defineMessages, intlShape } from 'react-intl';
6 7
7// import { oneOrManyChildElements } from '../../prop-types'; 8// import { oneOrManyChildElements } from '../../prop-types';
8import Appear from './effects/Appear'; 9import Appear from './effects/Appear';
9 10
10export default @observer class InfoBar extends Component { 11const messages = defineMessages({
12 hide: {
13 id: 'infobar.hide',
14 defaultMessage: '!!!Hide',
15 },
16});
17
18export default
19@observer
20class InfoBar extends Component {
11 static propTypes = { 21 static propTypes = {
12 // eslint-disable-next-line 22 // eslint-disable-next-line
13 children: PropTypes.any.isRequired, 23 children: PropTypes.any.isRequired,
@@ -32,6 +42,10 @@ export default @observer class InfoBar extends Component {
32 onHide: () => null, 42 onHide: () => null,
33 }; 43 };
34 44
45 static contextTypes = {
46 intl: intlShape,
47 };
48
35 render() { 49 render() {
36 const { 50 const {
37 children, 51 children,
@@ -45,6 +59,8 @@ export default @observer class InfoBar extends Component {
45 onHide, 59 onHide,
46 } = this.props; 60 } = this.props;
47 61
62 const { intl } = this.context;
63
48 let transitionName = 'slideUp'; 64 let transitionName = 'slideUp';
49 if (position === 'top') { 65 if (position === 'top') {
50 transitionName = 'slideDown'; 66 transitionName = 'slideDown';
@@ -63,11 +79,7 @@ export default @observer class InfoBar extends Component {
63 <div className="info-bar__content"> 79 <div className="info-bar__content">
64 {children} 80 {children}
65 {ctaLabel && ( 81 {ctaLabel && (
66 <button 82 <button type="button" className="info-bar__cta" onClick={onClick}>
67 type="button"
68 className="info-bar__cta"
69 onClick={onClick}
70 >
71 <Loader 83 <Loader
72 loaded={!ctaLoading} 84 loaded={!ctaLoading}
73 lines={10} 85 lines={10}
@@ -84,6 +96,7 @@ export default @observer class InfoBar extends Component {
84 type="button" 96 type="button"
85 className="info-bar__close mdi mdi-close" 97 className="info-bar__close mdi mdi-close"
86 onClick={onHide} 98 onClick={onHide}
99 aria-label={intl.formatMessage(messages.hide)}
87 /> 100 />
88 )} 101 )}
89 </Appear> 102 </Appear>
diff --git a/src/components/ui/Infobox.js b/src/components/ui/Infobox.js
index 0917ee9f0..73b48b957 100644
--- a/src/components/ui/Infobox.js
+++ b/src/components/ui/Infobox.js
@@ -3,8 +3,18 @@ import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import classnames from 'classnames'; 4import classnames from 'classnames';
5import Loader from 'react-loader'; 5import Loader from 'react-loader';
6import { defineMessages, intlShape } from 'react-intl';
6 7
7export default @observer class Infobox extends Component { 8const messages = defineMessages({
9 dismiss: {
10 id: 'infobox.dismiss',
11 defaultMessage: '!!!Dismiss',
12 },
13});
14
15export default
16@observer
17class Infobox extends Component {
8 static propTypes = { 18 static propTypes = {
9 children: PropTypes.any.isRequired, // eslint-disable-line 19 children: PropTypes.any.isRequired, // eslint-disable-line
10 icon: PropTypes.string, 20 icon: PropTypes.string,
@@ -28,6 +38,10 @@ export default @observer class Infobox extends Component {
28 onSeen: () => null, 38 onSeen: () => null,
29 }; 39 };
30 40
41 static contextTypes = {
42 intl: intlShape,
43 };
44
31 state = { 45 state = {
32 dismissed: false, 46 dismissed: false,
33 }; 47 };
@@ -49,6 +63,8 @@ export default @observer class Infobox extends Component {
49 onDismiss, 63 onDismiss,
50 } = this.props; 64 } = this.props;
51 65
66 const { intl } = this.context;
67
52 if (this.state.dismissed) { 68 if (this.state.dismissed) {
53 return null; 69 return null;
54 } 70 }
@@ -61,18 +77,10 @@ export default @observer class Infobox extends Component {
61 'infobox--default': !type, 77 'infobox--default': !type,
62 })} 78 })}
63 > 79 >
64 {icon && ( 80 {icon && <i className={`mdi mdi-${icon}`} />}
65 <i className={`mdi mdi-${icon}`} /> 81 <div className="infobox__content">{children}</div>
66 )}
67 <div className="infobox__content">
68 {children}
69 </div>
70 {ctaLabel && ( 82 {ctaLabel && (
71 <button 83 <button className="infobox__cta" onClick={ctaOnClick} type="button">
72 className="infobox__cta"
73 onClick={ctaOnClick}
74 type="button"
75 >
76 <Loader 84 <Loader
77 loaded={!ctaLoading} 85 loaded={!ctaLoading}
78 lines={10} 86 lines={10}
@@ -91,6 +99,7 @@ export default @observer class Infobox extends Component {
91 if (onDismiss) onDismiss(); 99 if (onDismiss) onDismiss();
92 }} 100 }}
93 className="infobox__delete mdi mdi-close" 101 className="infobox__delete mdi mdi-close"
102 aria-label={intl.formatMessage(messages.dismiss)}
94 /> 103 />
95 )} 104 )}
96 </div> 105 </div>
diff --git a/src/components/ui/Input.js b/src/components/ui/Input.js
index 4e3eb4ab8..7417fef1c 100644
--- a/src/components/ui/Input.js
+++ b/src/components/ui/Input.js
@@ -3,10 +3,20 @@ import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { Field } from 'mobx-react-form'; 4import { Field } from 'mobx-react-form';
5import classnames from 'classnames'; 5import classnames from 'classnames';
6import { defineMessages, intlShape } from 'react-intl';
6 7
7import { scorePassword as scorePasswordFunc } from '../../helpers/password-helpers'; 8import { scorePassword as scorePasswordFunc } from '../../helpers/password-helpers';
8 9
9export default @observer class Input extends Component { 10const messages = defineMessages({
11 passwordToggle: {
12 id: 'settings.app.form.passwordToggle',
13 defaultMessage: '!!!Password toggle',
14 },
15});
16
17export default
18@observer
19class Input extends Component {
10 static propTypes = { 20 static propTypes = {
11 field: PropTypes.instanceOf(Field).isRequired, 21 field: PropTypes.instanceOf(Field).isRequired,
12 className: PropTypes.string, 22 className: PropTypes.string,
@@ -28,10 +38,14 @@ export default @observer class Input extends Component {
28 suffix: '', 38 suffix: '',
29 }; 39 };
30 40
41 static contextTypes = {
42 intl: intlShape,
43 };
44
31 state = { 45 state = {
32 showPassword: false, 46 showPassword: false,
33 passwordScore: 0, 47 passwordScore: 0,
34 } 48 };
35 49
36 inputElement = null; 50 inputElement = null;
37 51
@@ -68,6 +82,8 @@ export default @observer class Input extends Component {
68 82
69 const { passwordScore } = this.state; 83 const { passwordScore } = this.state;
70 84
85 const { intl } = this.context;
86
71 let { type } = field; 87 let { type } = field;
72 if (type === 'password' && this.state.showPassword) { 88 if (type === 'password' && this.state.showPassword) {
73 type = 'text'; 89 type = 'text';
@@ -82,9 +98,7 @@ export default @observer class Input extends Component {
82 })} 98 })}
83 > 99 >
84 <div className="franz-form__input-wrapper"> 100 <div className="franz-form__input-wrapper">
85 {prefix && ( 101 {prefix && <span className="franz-form__input-prefix">{prefix}</span>}
86 <span className="franz-form__input-prefix">{prefix}</span>
87 )}
88 <input 102 <input
89 id={field.id} 103 id={field.id}
90 type={type} 104 type={type}
@@ -92,15 +106,15 @@ export default @observer class Input extends Component {
92 name={field.name} 106 name={field.name}
93 value={field.value} 107 value={field.value}
94 placeholder={field.placeholder} 108 placeholder={field.placeholder}
95 onChange={e => this.onChange(e)} 109 onChange={(e) => this.onChange(e)}
96 onBlur={field.onBlur} 110 onBlur={field.onBlur}
97 onFocus={field.onFocus} 111 onFocus={field.onFocus}
98 ref={(element) => { this.inputElement = element; }} 112 ref={(element) => {
113 this.inputElement = element;
114 }}
99 disabled={field.disabled} 115 disabled={field.disabled}
100 /> 116 />
101 {suffix && ( 117 {suffix && <span className="franz-form__input-suffix">{suffix}</span>}
102 <span className="franz-form__input-suffix">{suffix}</span>
103 )}
104 {showPasswordToggle && ( 118 {showPasswordToggle && (
105 <button 119 <button
106 type="button" 120 type="button"
@@ -110,8 +124,11 @@ export default @observer class Input extends Component {
110 'mdi-eye': !this.state.showPassword, 124 'mdi-eye': !this.state.showPassword,
111 'mdi-eye-off': this.state.showPassword, 125 'mdi-eye-off': this.state.showPassword,
112 })} 126 })}
113 onClick={() => this.setState(prevState => ({ showPassword: !prevState.showPassword }))} 127 onClick={() => this.setState((prevState) => ({
114 tabIndex="-1" 128 showPassword: !prevState.showPassword,
129 }))}
130 tabIndex={-1}
131 aria-label={intl.formatMessage(messages.passwordToggle)}
115 /> 132 />
116 )} 133 )}
117 {scorePassword && ( 134 {scorePassword && (
@@ -128,20 +145,11 @@ export default @observer class Input extends Component {
128 )} 145 )}
129 </div> 146 </div>
130 {field.label && showLabel && ( 147 {field.label && showLabel && (
131 <label 148 <label className="franz-form__label" htmlFor={field.name}>
132 className="franz-form__label"
133 htmlFor={field.name}
134 >
135 {field.label} 149 {field.label}
136 </label> 150 </label>
137 )} 151 )}
138 {field.error && ( 152 {field.error && <div className="franz-form__error">{field.error}</div>}
139 <div
140 className="franz-form__error"
141 >
142 {field.error}
143 </div>
144 )}
145 </div> 153 </div>
146 ); 154 );
147 } 155 }
diff --git a/src/components/ui/Tabs/TabItem.js b/src/components/ui/Tabs/TabItem.js
index 16881a7f7..546b05a4e 100644
--- a/src/components/ui/Tabs/TabItem.js
+++ b/src/components/ui/Tabs/TabItem.js
@@ -11,7 +11,7 @@ export default class TabItem extends Component {
11 const { children } = this.props; 11 const { children } = this.props;
12 12
13 return ( 13 return (
14 <Fragment>{children}</Fragment> 14 <>{children}</>
15 ); 15 );
16 } 16 }
17} 17}
diff --git a/src/components/ui/Tabs/Tabs.js b/src/components/ui/Tabs/Tabs.js
index 196cddc66..7ece29fbe 100644
--- a/src/components/ui/Tabs/Tabs.js
+++ b/src/components/ui/Tabs/Tabs.js
@@ -5,7 +5,9 @@ import classnames from 'classnames';
5 5
6import { oneOrManyChildElements } from '../../../prop-types'; 6import { oneOrManyChildElements } from '../../../prop-types';
7 7
8export default @observer class Tab extends Component { 8export default
9@observer
10class Tab extends Component {
9 static propTypes = { 11 static propTypes = {
10 children: oneOrManyChildElements.isRequired, 12 children: oneOrManyChildElements.isRequired,
11 active: PropTypes.number, 13 active: PropTypes.number,
@@ -15,7 +17,7 @@ export default @observer class Tab extends Component {
15 active: 0, 17 active: 0,
16 }; 18 };
17 19
18 componentWillMount() { 20 componentDidMount() {
19 this.setState({ active: this.props.active }); 21 this.setState({ active: this.props.active });
20 } 22 }
21 23
@@ -25,7 +27,7 @@ export default @observer class Tab extends Component {
25 27
26 render() { 28 render() {
27 const { children: childElements } = this.props; 29 const { children: childElements } = this.props;
28 const children = childElements.filter(c => !!c); 30 const children = childElements.filter((c) => !!c);
29 31
30 if (children.length === 1) { 32 if (children.length === 1) {
31 return <div>{children}</div>; 33 return <div>{children}</div>;
diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js
index 2c9cac084..db3b2a4a7 100644
--- a/src/containers/settings/AccountScreen.js
+++ b/src/containers/settings/AccountScreen.js
@@ -85,8 +85,7 @@ class AccountScreen extends Component {
85 openEditAccount={() => this.handleWebsiteLink('/user/profile')} 85 openEditAccount={() => this.handleWebsiteLink('/user/profile')}
86 upgradeToPro={() => upgradeAccount({ 86 upgradeToPro={() => upgradeAccount({
87 planId: features.features.pricingConfig.plans.pro.yearly.id, 87 planId: features.features.pricingConfig.plans.pro.yearly.id,
88 }) 88 })}
89 }
90 openBilling={() => this.handleWebsiteLink('/user/billing')} 89 openBilling={() => this.handleWebsiteLink('/user/billing')}
91 openInvoices={() => this.handleWebsiteLink('/user/invoices')} 90 openInvoices={() => this.handleWebsiteLink('/user/invoices')}
92 /> 91 />
diff --git a/src/containers/settings/SettingsWindow.js b/src/containers/settings/SettingsWindow.js
index 89c2aaa27..9bb64b6fe 100644
--- a/src/containers/settings/SettingsWindow.js
+++ b/src/containers/settings/SettingsWindow.js
@@ -28,7 +28,6 @@ export default @inject('stores', 'actions') @observer class SettingsContainer ex
28 const { children, stores } = this.props; 28 const { children, stores } = this.props;
29 const { closeSettings } = this.props.actions.ui; 29 const { closeSettings } = this.props.actions.ui;
30 30
31
32 const navigation = ( 31 const navigation = (
33 <Navigation 32 <Navigation
34 serviceCount={stores.services.all.length} 33 serviceCount={stores.services.all.length}
diff --git a/src/containers/subscription/SubscriptionPopupScreen.js b/src/containers/subscription/SubscriptionPopupScreen.js
index 0de5a87c4..43966b6a4 100644
--- a/src/containers/subscription/SubscriptionPopupScreen.js
+++ b/src/containers/subscription/SubscriptionPopupScreen.js
@@ -5,7 +5,6 @@ import { inject, observer } from 'mobx-react';
5import SubscriptionPopup from '../../components/subscription/SubscriptionPopup'; 5import SubscriptionPopup from '../../components/subscription/SubscriptionPopup';
6import { isDevMode } from '../../environment'; 6import { isDevMode } from '../../environment';
7 7
8
9export default @inject('stores', 'actions') @observer class SubscriptionPopupScreen extends Component { 8export default @inject('stores', 'actions') @observer class SubscriptionPopupScreen extends Component {
10 state = { 9 state = {
11 complete: false, 10 complete: false,
@@ -33,7 +32,6 @@ export default @inject('stores', 'actions') @observer class SubscriptionPopupScr
33 } 32 }
34} 33}
35 34
36
37SubscriptionPopupScreen.wrappedComponent.propTypes = { 35SubscriptionPopupScreen.wrappedComponent.propTypes = {
38 router: PropTypes.shape({ 36 router: PropTypes.shape({
39 params: PropTypes.shape({ 37 params: PropTypes.shape({
diff --git a/src/features/announcements/components/AnnouncementScreen.js b/src/features/announcements/components/AnnouncementScreen.js
index 659cb4961..21964b108 100644
--- a/src/features/announcements/components/AnnouncementScreen.js
+++ b/src/features/announcements/components/AnnouncementScreen.js
@@ -185,7 +185,6 @@ const styles = theme => ({
185 }, 185 },
186}); 186});
187 187
188
189@inject('stores', 'actions') @injectSheet(styles) @observer 188@inject('stores', 'actions') @injectSheet(styles) @observer
190class AnnouncementScreen extends Component { 189class AnnouncementScreen extends Component {
191 static propTypes = { 190 static propTypes = {
diff --git a/src/features/announcements/index.js b/src/features/announcements/index.js
index 369ded1b2..28f0b10ed 100644
--- a/src/features/announcements/index.js
+++ b/src/features/announcements/index.js
@@ -7,7 +7,6 @@ export const GA_CATEGORY_ANNOUNCEMENTS = 'Announcements';
7 7
8export const announcementsStore = new AnnouncementsStore(); 8export const announcementsStore = new AnnouncementsStore();
9 9
10
11export default function initAnnouncements(stores, actions) { 10export default function initAnnouncements(stores, actions) {
12 const { features } = stores; 11 const { features } = stores;
13 12
diff --git a/src/features/delayApp/index.js b/src/features/delayApp/index.js
index 5ef01a47e..f0c2bdc82 100644
--- a/src/features/delayApp/index.js
+++ b/src/features/delayApp/index.js
@@ -59,7 +59,6 @@ export default function init(stores) {
59 59
60 setVisibility(true); 60 setVisibility(true);
61 61
62
63 setTimeout(() => { 62 setTimeout(() => {
64 debug('Resetting app delay'); 63 debug('Resetting app delay');
65 64
diff --git a/src/features/planSelection/components/PlanItem.js b/src/features/planSelection/components/PlanItem.js
index 3855fedf1..e90532dec 100644
--- a/src/features/planSelection/components/PlanItem.js
+++ b/src/features/planSelection/components/PlanItem.js
@@ -111,7 +111,6 @@ const styles = theme => ({
111 }, 111 },
112}); 112});
113 113
114
115export default @observer @injectSheet(styles) class PlanItem extends Component { 114export default @observer @injectSheet(styles) class PlanItem extends Component {
116 static propTypes = { 115 static propTypes = {
117 name: PropTypes.string.isRequired, 116 name: PropTypes.string.isRequired,
diff --git a/src/features/publishDebugInfo/Component.js b/src/features/publishDebugInfo/Component.js
index 4308b8f09..e7949a0be 100644
--- a/src/features/publishDebugInfo/Component.js
+++ b/src/features/publishDebugInfo/Component.js
@@ -13,7 +13,6 @@ import { DEBUG_API } from '../../config';
13import AppStore from '../../stores/AppStore'; 13import AppStore from '../../stores/AppStore';
14import ServicesStore from '../../stores/ServicesStore'; 14import ServicesStore from '../../stores/ServicesStore';
15 15
16
17const messages = defineMessages({ 16const messages = defineMessages({
18 title: { 17 title: {
19 id: 'feature.publishDebugInfo.title', 18 id: 'feature.publishDebugInfo.title',
diff --git a/src/features/serviceLimit/components/LimitReachedInfobox.js b/src/features/serviceLimit/components/LimitReachedInfobox.js
index 83aec4c40..424c92990 100644
--- a/src/features/serviceLimit/components/LimitReachedInfobox.js
+++ b/src/features/serviceLimit/components/LimitReachedInfobox.js
@@ -34,7 +34,6 @@ const styles = theme => ({
34 }, 34 },
35}); 35});
36 36
37
38@inject('stores', 'actions') @injectSheet(styles) @observer 37@inject('stores', 'actions') @injectSheet(styles) @observer
39class LimitReachedInfobox extends Component { 38class LimitReachedInfobox extends Component {
40 static propTypes = { 39 static propTypes = {
diff --git a/src/features/todos/components/TodosWebview.js b/src/features/todos/components/TodosWebview.js
index dccb818a6..ca8460f94 100644
--- a/src/features/todos/components/TodosWebview.js
+++ b/src/features/todos/components/TodosWebview.js
@@ -7,7 +7,7 @@ import classnames from 'classnames';
7 7
8import { TODOS_PARTITION_ID } from '../../../config'; 8import { TODOS_PARTITION_ID } from '../../../config';
9 9
10const styles = theme => ({ 10const styles = (theme) => ({
11 root: { 11 root: {
12 background: theme.colorBackground, 12 background: theme.colorBackground,
13 position: 'relative', 13 position: 'relative',
@@ -34,7 +34,6 @@ const styles = theme => ({
34 width: 5, 34 width: 5,
35 zIndex: 400, 35 zIndex: 400,
36 background: theme.todos.dragIndicator.background, 36 background: theme.todos.dragIndicator.background,
37
38 }, 37 },
39 premiumContainer: { 38 premiumContainer: {
40 display: 'flex', 39 display: 'flex',
@@ -68,7 +67,8 @@ const styles = theme => ({
68 }, 67 },
69}); 68});
70 69
71@injectSheet(styles) @observer 70@injectSheet(styles)
71@observer
72class TodosWebview extends Component { 72class TodosWebview extends Component {
73 static propTypes = { 73 static propTypes = {
74 classes: PropTypes.object.isRequired, 74 classes: PropTypes.object.isRequired,
@@ -89,15 +89,11 @@ class TodosWebview extends Component {
89 width: 300, 89 width: 300,
90 }; 90 };
91 91
92 componentWillMount() { 92 componentDidMount() {
93 const { width } = this.props;
94
95 this.setState({ 93 this.setState({
96 width, 94 width: this.props.width,
97 }); 95 });
98 }
99 96
100 componentDidMount() {
101 this.node.addEventListener('mousemove', this.resizePanel.bind(this)); 97 this.node.addEventListener('mousemove', this.resizePanel.bind(this));
102 this.node.addEventListener('mouseup', this.stopResize.bind(this)); 98 this.node.addEventListener('mouseup', this.stopResize.bind(this));
103 this.node.addEventListener('mouseleave', this.stopResize.bind(this)); 99 this.node.addEventListener('mouseleave', this.stopResize.bind(this));
@@ -114,10 +110,7 @@ class TodosWebview extends Component {
114 resizePanel(e) { 110 resizePanel(e) {
115 const { minWidth } = this.props; 111 const { minWidth } = this.props;
116 112
117 const { 113 const { isDragging, initialPos } = this.state;
118 isDragging,
119 initialPos,
120 } = this.state;
121 114
122 if (isDragging && Math.abs(e.clientX - window.innerWidth) > minWidth) { 115 if (isDragging && Math.abs(e.clientX - window.innerWidth) > minWidth) {
123 const delta = e.clientX - initialPos; 116 const delta = e.clientX - initialPos;
@@ -129,16 +122,9 @@ class TodosWebview extends Component {
129 } 122 }
130 123
131 stopResize() { 124 stopResize() {
132 const { 125 const { resize, minWidth } = this.props;
133 resize,
134 minWidth,
135 } = this.props;
136 126
137 const { 127 const { isDragging, delta, width } = this.state;
138 isDragging,
139 delta,
140 width,
141 } = this.state;
142 128
143 if (isDragging) { 129 if (isDragging) {
144 let newWidth = width + (delta < 0 ? Math.abs(delta) : -Math.abs(delta)); 130 let newWidth = width + (delta < 0 ? Math.abs(delta) : -Math.abs(delta));
@@ -176,11 +162,7 @@ class TodosWebview extends Component {
176 isTodoUrlValid, 162 isTodoUrlValid,
177 } = this.props; 163 } = this.props;
178 164
179 const { 165 const { width, delta, isDragging } = this.state;
180 width,
181 delta,
182 isDragging,
183 } = this.state;
184 166
185 let displayedWidth = isVisible ? width : 0; 167 let displayedWidth = isVisible ? width : 0;
186 if (isTodosServiceActive) { 168 if (isTodosServiceActive) {
@@ -197,13 +179,18 @@ class TodosWebview extends Component {
197 })} 179 })}
198 style={{ width: displayedWidth }} 180 style={{ width: displayedWidth }}
199 onMouseUp={() => this.stopResize()} 181 onMouseUp={() => this.stopResize()}
200 ref={(node) => { this.node = node; }} 182 ref={(node) => {
183 this.node = node;
184 }}
201 id="todos-panel" 185 id="todos-panel"
202 > 186 >
203 <div 187 <div
204 className={classes.resizeHandler} 188 className={classes.resizeHandler}
205 style={Object.assign({ left: delta }, isDragging ? { width: 600, marginLeft: -200 } : {})} // This hack is required as resizing with webviews beneath behaves quite bad 189 style={{
206 onMouseDown={e => this.startResize(e)} 190 left: delta,
191 ...(isDragging ? { width: 600, marginLeft: -200 } : {}),
192 }} // This hack is required as resizing with webviews beneath behaves quite bad
193 onMouseDown={(e) => this.startResize(e)}
207 /> 194 />
208 {isDragging && ( 195 {isDragging && (
209 <div 196 <div
@@ -221,7 +208,9 @@ class TodosWebview extends Component {
221 }} 208 }}
222 partition={TODOS_PARTITION_ID} 209 partition={TODOS_PARTITION_ID}
223 preload="./features/todos/preload.js" 210 preload="./features/todos/preload.js"
224 ref={(webview) => { this.webview = webview ? webview.view : null; }} 211 ref={(webview) => {
212 this.webview = webview ? webview.view : null;
213 }}
225 useragent={userAgent} 214 useragent={userAgent}
226 src={todoUrl} 215 src={todoUrl}
227 /> 216 />
diff --git a/src/features/trialStatusBar/containers/TrialStatusBarScreen.js b/src/features/trialStatusBar/containers/TrialStatusBarScreen.js
index 715251854..e0f5ab5f2 100644
--- a/src/features/trialStatusBar/containers/TrialStatusBarScreen.js
+++ b/src/features/trialStatusBar/containers/TrialStatusBarScreen.js
@@ -12,7 +12,8 @@ import { trialStatusBarStore } from '..';
12import { i18nPlanName } from '../../../helpers/plan-helpers'; 12import { i18nPlanName } from '../../../helpers/plan-helpers';
13import PaymentStore from '../../../stores/PaymentStore'; 13import PaymentStore from '../../../stores/PaymentStore';
14 14
15@inject('stores', 'actions') @observer 15@inject('stores', 'actions')
16@observer
16class TrialStatusBarScreen extends Component { 17class TrialStatusBarScreen extends Component {
17 static contextTypes = { 18 static contextTypes = {
18 intl: intlShape, 19 intl: intlShape,
@@ -41,7 +42,9 @@ class TrialStatusBarScreen extends Component {
41 42
42 calculateRestTime() { 43 calculateRestTime() {
43 const { trialEndTime } = trialStatusBarStore; 44 const { trialEndTime } = trialStatusBarStore;
44 const percent = Math.abs(100 - Math.abs(trialEndTime.asMilliseconds()) * 100 / ms('14d')).toFixed(2); 45 const percent = (
46 Math.abs(100 - Math.abs(trialEndTime.asMilliseconds()) * 100) / ms('14d')
47 ).toFixed(2);
45 const restTime = trialEndTime.humanize(); 48 const restTime = trialEndTime.humanize();
46 const hasEnded = trialEndTime.asMilliseconds() > 0; 49 const hasEnded = trialEndTime.asMilliseconds() > 0;
47 50
@@ -58,18 +61,19 @@ class TrialStatusBarScreen extends Component {
58 }); 61 });
59 } 62 }
60 63
61
62 render() { 64 render() {
63 const { intl } = this.context; 65 const { intl } = this.context;
64 66
65 const { 67 const {
66 showOverlay, 68 showOverlay, percent, restTime, hasEnded,
67 percent,
68 restTime,
69 hasEnded,
70 } = this.state; 69 } = this.state;
71 70
72 if (!trialStatusBarStore || !trialStatusBarStore.isFeatureActive || !showOverlay || !trialStatusBarStore.showTrialStatusBarOverlay) { 71 if (
72 !trialStatusBarStore
73 || !trialStatusBarStore.isFeatureActive
74 || !showOverlay
75 || !trialStatusBarStore.showTrialStatusBarOverlay
76 ) {
73 return null; 77 return null;
74 } 78 }
75 79
diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js
index f23bc6cbf..0ff836cba 100644
--- a/src/features/workspaces/components/EditWorkspaceForm.js
+++ b/src/features/workspaces/components/EditWorkspaceForm.js
@@ -40,7 +40,8 @@ const messages = defineMessages({
40 }, 40 },
41 keepLoadedInfo: { 41 keepLoadedInfo: {
42 id: 'settings.workspace.form.keepLoadedInfo', 42 id: 'settings.workspace.form.keepLoadedInfo',
43 defaultMessage: '!!!*This option will be overwritten by the global "Keep all workspaces loaded" option.', 43 defaultMessage:
44 '!!!*This option will be overwritten by the global "Keep all workspaces loaded" option.',
44 }, 45 },
45 servicesInWorkspaceHeadline: { 46 servicesInWorkspaceHeadline: {
46 id: 'settings.workspace.form.servicesInWorkspaceHeadline', 47 id: 'settings.workspace.form.servicesInWorkspaceHeadline',
@@ -68,7 +69,8 @@ const styles = () => ({
68 }, 69 },
69}); 70});
70 71
71@injectSheet(styles) @observer 72@injectSheet(styles)
73@observer
72class EditWorkspaceForm extends Component { 74class EditWorkspaceForm extends Component {
73 static contextTypes = { 75 static contextTypes = {
74 intl: intlShape, 76 intl: intlShape,
@@ -86,6 +88,7 @@ class EditWorkspaceForm extends Component {
86 88
87 form = this.prepareWorkspaceForm(this.props.workspace); 89 form = this.prepareWorkspaceForm(this.props.workspace);
88 90
91 // eslint-disable-next-line react/no-deprecated
89 componentWillReceiveProps(nextProps) { 92 componentWillReceiveProps(nextProps) {
90 const { workspace } = this.props; 93 const { workspace } = this.props;
91 if (workspace.id !== nextProps.workspace.id) { 94 if (workspace.id !== nextProps.workspace.id) {
@@ -164,16 +167,14 @@ class EditWorkspaceForm extends Component {
164 </Link> 167 </Link>
165 </span> 168 </span>
166 <span className="separator" /> 169 <span className="separator" />
167 <span className="settings__header-item"> 170 <span className="settings__header-item">{workspace.name}</span>
168 {workspace.name}
169 </span>
170 </div> 171 </div>
171 <div className="settings__body"> 172 <div className="settings__body">
172 <div className={classes.nameInput}> 173 <div className={classes.nameInput}>
173 <Input {...form.$('name').bind()} /> 174 <Input {...form.$('name').bind()} />
174 <Toggle field={form.$('keepLoaded')} /> 175 <Toggle field={form.$('keepLoaded')} />
175 <p className={`${classes.keepLoadedInfo} franz-form__label`}> 176 <p className={`${classes.keepLoadedInfo} franz-form__label`}>
176 { intl.formatMessage(messages.keepLoadedInfo) } 177 {intl.formatMessage(messages.keepLoadedInfo)}
177 </p> 178 </p>
178 </div> 179 </div>
179 <h2>{intl.formatMessage(messages.servicesInWorkspaceHeadline)}</h2> 180 <h2>{intl.formatMessage(messages.servicesInWorkspaceHeadline)}</h2>
@@ -187,11 +188,13 @@ class EditWorkspaceForm extends Component {
187 </span> 188 </span>
188 {intl.formatMessage(messages.noServicesAdded)} 189 {intl.formatMessage(messages.noServicesAdded)}
189 </p> 190 </p>
190 <Link to="/settings/recipes" className="button">{intl.formatMessage(messages.discoverServices)}</Link> 191 <Link to="/settings/recipes" className="button">
192 {intl.formatMessage(messages.discoverServices)}
193 </Link>
191 </div> 194 </div>
192 ) : ( 195 ) : (
193 <Fragment> 196 <>
194 {services.map(s => ( 197 {services.map((s) => (
195 <WorkspaceServiceListItem 198 <WorkspaceServiceListItem
196 key={s.id} 199 key={s.id}
197 service={s} 200 service={s}
@@ -199,7 +202,7 @@ class EditWorkspaceForm extends Component {
199 onToggle={() => this.toggleService(s)} 202 onToggle={() => this.toggleService(s)}
200 /> 203 />
201 ))} 204 ))}
202 </Fragment> 205 </>
203 )} 206 )}
204 </div> 207 </div>
205 </div> 208 </div>
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js
index a90bb37e9..cfaacd56e 100644
--- a/src/features/workspaces/components/WorkspacesDashboard.js
+++ b/src/features/workspaces/components/WorkspacesDashboard.js
@@ -184,7 +184,7 @@ class WorkspacesDashboard extends Component {
184 {getUserWorkspacesRequest.isExecuting ? ( 184 {getUserWorkspacesRequest.isExecuting ? (
185 <Loader /> 185 <Loader />
186 ) : ( 186 ) : (
187 <Fragment> 187 <>
188 {/* ===== Workspace could not be loaded error ===== */} 188 {/* ===== Workspace could not be loaded error ===== */}
189 {getUserWorkspacesRequest.error ? ( 189 {getUserWorkspacesRequest.error ? (
190 <Infobox 190 <Infobox
@@ -197,7 +197,7 @@ class WorkspacesDashboard extends Component {
197 {intl.formatMessage(messages.workspacesRequestFailed)} 197 {intl.formatMessage(messages.workspacesRequestFailed)}
198 </Infobox> 198 </Infobox>
199 ) : ( 199 ) : (
200 <Fragment> 200 <>
201 {workspaces.length === 0 ? ( 201 {workspaces.length === 0 ? (
202 <div className="align-middle settings__empty-state"> 202 <div className="align-middle settings__empty-state">
203 {/* ===== Workspaces empty state ===== */} 203 {/* ===== Workspaces empty state ===== */}
@@ -222,9 +222,9 @@ class WorkspacesDashboard extends Component {
222 </tbody> 222 </tbody>
223 </table> 223 </table>
224 )} 224 )}
225 </Fragment> 225 </>
226 )} 226 )}
227 </Fragment> 227 </>
228 )} 228 )}
229 </> 229 </>
230 )} 230 )}
diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.js b/src/features/workspaces/containers/EditWorkspaceScreen.js
index 5eca71259..ba7606031 100644
--- a/src/features/workspaces/containers/EditWorkspaceScreen.js
+++ b/src/features/workspaces/containers/EditWorkspaceScreen.js
@@ -32,9 +32,7 @@ class EditWorkspaceScreen extends Component {
32 const { workspaceBeingEdited } = workspaceStore; 32 const { workspaceBeingEdited } = workspaceStore;
33 const { actions } = this.props; 33 const { actions } = this.props;
34 const workspace = new Workspace( 34 const workspace = new Workspace(
35 Object.assign({ 35 ({ saving: true, ...workspaceBeingEdited, ...values }),
36 saving: true,
37 }, workspaceBeingEdited, values),
38 ); 36 );
39 actions.workspaces.update({ workspace }); 37 actions.workspaces.update({ workspace });
40 }; 38 };
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js
index bddcb6eb4..632f3c299 100644
--- a/src/features/workspaces/store.js
+++ b/src/features/workspaces/store.js
@@ -1,8 +1,4 @@
1import { 1import { computed, observable, action } from 'mobx';
2 computed,
3 observable,
4 action,
5} from 'mobx';
6import localStorage from 'mobx-localstorage'; 2import localStorage from 'mobx-localstorage';
7import { matchRoute } from '../../helpers/routing-helpers'; 3import { matchRoute } from '../../helpers/routing-helpers';
8import { workspaceActions } from './actions'; 4import { workspaceActions } from './actions';
@@ -105,7 +101,10 @@ export default class WorkspacesStore extends FeatureStore {
105 [workspaceActions.update, this._update], 101 [workspaceActions.update, this._update],
106 [workspaceActions.activate, this._setActiveWorkspace], 102 [workspaceActions.activate, this._setActiveWorkspace],
107 [workspaceActions.deactivate, this._deactivateActiveWorkspace], 103 [workspaceActions.deactivate, this._deactivateActiveWorkspace],
108 [workspaceActions.toggleKeepAllWorkspacesLoadedSetting, this._toggleKeepAllWorkspacesLoadedSetting], 104 [
105 workspaceActions.toggleKeepAllWorkspacesLoadedSetting,
106 this._toggleKeepAllWorkspacesLoadedSetting,
107 ],
109 ]); 108 ]);
110 this._allActions = this._freeUserActions.concat(this._premiumUserActions); 109 this._allActions = this._freeUserActions.concat(this._premiumUserActions);
111 this._registerActions(this._allActions); 110 this._registerActions(this._allActions);
@@ -124,7 +123,9 @@ export default class WorkspacesStore extends FeatureStore {
124 this._activateLastUsedWorkspaceReaction, 123 this._activateLastUsedWorkspaceReaction,
125 this._setWorkspaceBeingEditedReaction, 124 this._setWorkspaceBeingEditedReaction,
126 ]); 125 ]);
127 this._allReactions = this._freeUserReactions.concat(this._premiumUserReactions); 126 this._allReactions = this._freeUserReactions.concat(
127 this._premiumUserReactions,
128 );
128 129
129 this._registerReactions(this._allReactions); 130 this._registerReactions(this._allReactions);
130 131
@@ -157,12 +158,12 @@ export default class WorkspacesStore extends FeatureStore {
157 158
158 getWorkspaceServices(workspace) { 159 getWorkspaceServices(workspace) {
159 const { services } = this.stores; 160 const { services } = this.stores;
160 return workspace.services.map(id => services.one(id)).filter(s => !!s); 161 return workspace.services.map((id) => services.one(id)).filter((s) => !!s);
161 } 162 }
162 163
163 // ========== PRIVATE METHODS ========= // 164 // ========== PRIVATE METHODS ========= //
164 165
165 _getWorkspaceById = id => this.workspaces.find(w => w.id === id); 166 _getWorkspaceById = (id) => this.workspaces.find((w) => w.id === id);
166 167
167 _updateSettings = (changes) => { 168 _updateSettings = (changes) => {
168 localStorage.setItem('workspaces', { 169 localStorage.setItem('workspaces', {
@@ -178,6 +179,7 @@ export default class WorkspacesStore extends FeatureStore {
178 }; 179 };
179 180
180 @action _create = async ({ name }) => { 181 @action _create = async ({ name }) => {
182 // eslint-disable-next-line no-useless-catch
181 try { 183 try {
182 const workspace = await createWorkspaceRequest.execute(name); 184 const workspace = await createWorkspaceRequest.execute(name);
183 await getUserWorkspacesRequest.result.push(workspace); 185 await getUserWorkspacesRequest.result.push(workspace);
@@ -188,6 +190,7 @@ export default class WorkspacesStore extends FeatureStore {
188 }; 190 };
189 191
190 @action _delete = async ({ workspace }) => { 192 @action _delete = async ({ workspace }) => {
193 // eslint-disable-next-line no-useless-catch
191 try { 194 try {
192 await deleteWorkspaceRequest.execute(workspace); 195 await deleteWorkspaceRequest.execute(workspace);
193 await getUserWorkspacesRequest.result.remove(workspace); 196 await getUserWorkspacesRequest.result.remove(workspace);
@@ -198,6 +201,7 @@ export default class WorkspacesStore extends FeatureStore {
198 }; 201 };
199 202
200 @action _update = async ({ workspace }) => { 203 @action _update = async ({ workspace }) => {
204 // eslint-disable-next-line no-useless-catch
201 try { 205 try {
202 await updateWorkspaceRequest.execute(workspace); 206 await updateWorkspaceRequest.execute(workspace);
203 // Path local result optimistically 207 // Path local result optimistically
@@ -235,7 +239,9 @@ export default class WorkspacesStore extends FeatureStore {
235 this.activeWorkspace = null; 239 this.activeWorkspace = null;
236 }, 100); 240 }, 100);
237 // Indicate that we are done switching to the default workspace 241 // Indicate that we are done switching to the default workspace
238 setTimeout(() => { this.isSwitchingWorkspace = false; }, 1000); 242 setTimeout(() => {
243 this.isSwitchingWorkspace = false;
244 }, 1000);
239 }; 245 };
240 246
241 @action _toggleWorkspaceDrawer = () => { 247 @action _toggleWorkspaceDrawer = () => {
@@ -255,7 +261,9 @@ export default class WorkspacesStore extends FeatureStore {
255 }; 261 };
256 262
257 _toggleKeepAllWorkspacesLoadedSetting = async () => { 263 _toggleKeepAllWorkspacesLoadedSetting = async () => {
258 this._updateSettings({ keepAllWorkspacesLoaded: !this.settings.keepAllWorkspacesLoaded }); 264 this._updateSettings({
265 keepAllWorkspacesLoaded: !this.settings.keepAllWorkspacesLoaded,
266 });
259 }; 267 };
260 268
261 // Reactions 269 // Reactions
@@ -309,7 +317,9 @@ export default class WorkspacesStore extends FeatureStore {
309 317
310 _openDrawerWithSettingsReaction = () => { 318 _openDrawerWithSettingsReaction = () => {
311 const { router } = this.stores; 319 const { router } = this.stores;
312 const isWorkspaceSettingsRoute = router.location.pathname.includes(WORKSPACES_ROUTES.ROOT); 320 const isWorkspaceSettingsRoute = router.location.pathname.includes(
321 WORKSPACES_ROUTES.ROOT,
322 );
313 const isSwitchingToSettingsRoute = !this.isSettingsRouteActive && isWorkspaceSettingsRoute; 323 const isSwitchingToSettingsRoute = !this.isSettingsRouteActive && isWorkspaceSettingsRoute;
314 const isLeavingSettingsRoute = !isWorkspaceSettingsRoute && this.isSettingsRouteActive; 324 const isLeavingSettingsRoute = !isWorkspaceSettingsRoute && this.isSettingsRouteActive;
315 325
@@ -321,7 +331,10 @@ export default class WorkspacesStore extends FeatureStore {
321 } 331 }
322 } else if (isLeavingSettingsRoute) { 332 } else if (isLeavingSettingsRoute) {
323 this.isSettingsRouteActive = false; 333 this.isSettingsRouteActive = false;
324 if (!this._wasDrawerOpenBeforeSettingsRoute && this.isWorkspaceDrawerOpen) { 334 if (
335 !this._wasDrawerOpenBeforeSettingsRoute
336 && this.isWorkspaceDrawerOpen
337 ) {
325 workspaceActions.toggleWorkspaceDrawer(); 338 workspaceActions.toggleWorkspaceDrawer();
326 } 339 }
327 } 340 }
@@ -334,7 +347,11 @@ export default class WorkspacesStore extends FeatureStore {
334 // Loop through all workspaces and remove invalid service ids (locally) 347 // Loop through all workspaces and remove invalid service ids (locally)
335 this.workspaces.forEach((workspace) => { 348 this.workspaces.forEach((workspace) => {
336 workspace.services.forEach((serviceId) => { 349 workspace.services.forEach((serviceId) => {
337 if (servicesHaveBeenLoaded && !services.one(serviceId) && serviceId !== KEEP_WS_LOADED_USID) { 350 if (
351 servicesHaveBeenLoaded
352 && !services.one(serviceId)
353 && serviceId !== KEEP_WS_LOADED_USID
354 ) {
338 workspace.services.remove(serviceId); 355 workspace.services.remove(serviceId);
339 } 356 }
340 }); 357 });
@@ -351,5 +368,5 @@ export default class WorkspacesStore extends FeatureStore {
351 this._startActions(this._premiumUserActions); 368 this._startActions(this._premiumUserActions);
352 this._startReactions(this._premiumUserReactions); 369 this._startReactions(this._premiumUserReactions);
353 } 370 }
354 } 371 };
355} 372}
diff --git a/src/i18n/apply-branding.js b/src/i18n/apply-branding.js
index 68ffb822a..40a07ded0 100644
--- a/src/i18n/apply-branding.js
+++ b/src/i18n/apply-branding.js
@@ -36,7 +36,6 @@ const replace = {
36 '!!!': '', 36 '!!!': '',
37}; 37};
38 38
39
40const locales = path.join(__dirname, 'locales'); 39const locales = path.join(__dirname, 'locales');
41const files = fs.readdirSync(locales); 40const files = fs.readdirSync(locales);
42 41
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json
index 8401184de..4ee96822e 100644
--- a/src/i18n/locales/defaultMessages.json
+++ b/src/i18n/locales/defaultMessages.json
@@ -664,169 +664,169 @@
664 "defaultMessage": "!!!Hi {name}, welcome to Franz", 664 "defaultMessage": "!!!Hi {name}, welcome to Franz",
665 "end": { 665 "end": {
666 "column": 3, 666 "column": 3,
667 "line": 18 667 "line": 17
668 }, 668 },
669 "file": "src/components/auth/Pricing.js", 669 "file": "src/components/auth/Pricing.js",
670 "id": "pricing.trial.headline.pro", 670 "id": "pricing.trial.headline.pro",
671 "start": { 671 "start": {
672 "column": 12, 672 "column": 12,
673 "line": 15 673 "line": 14
674 } 674 }
675 }, 675 },
676 { 676 {
677 "defaultMessage": "!!!We have a special treat for you.", 677 "defaultMessage": "!!!We have a special treat for you.",
678 "end": { 678 "end": {
679 "column": 3, 679 "column": 3,
680 "line": 22 680 "line": 21
681 }, 681 },
682 "file": "src/components/auth/Pricing.js", 682 "file": "src/components/auth/Pricing.js",
683 "id": "pricing.trial.intro.specialTreat", 683 "id": "pricing.trial.intro.specialTreat",
684 "start": { 684 "start": {
685 "column": 16, 685 "column": 16,
686 "line": 19 686 "line": 18
687 } 687 }
688 }, 688 },
689 { 689 {
690 "defaultMessage": "!!!Enjoy the full Franz Professional experience completely free for 14 days.", 690 "defaultMessage": "!!!Enjoy the full Franz Professional experience completely free for 14 days.",
691 "end": { 691 "end": {
692 "column": 3, 692 "column": 3,
693 "line": 26 693 "line": 25
694 }, 694 },
695 "file": "src/components/auth/Pricing.js", 695 "file": "src/components/auth/Pricing.js",
696 "id": "pricing.trial.intro.tryPro", 696 "id": "pricing.trial.intro.tryPro",
697 "start": { 697 "start": {
698 "column": 10, 698 "column": 10,
699 "line": 23 699 "line": 22
700 } 700 }
701 }, 701 },
702 { 702 {
703 "defaultMessage": "!!!Happy messaging,", 703 "defaultMessage": "!!!Happy messaging,",
704 "end": { 704 "end": {
705 "column": 3, 705 "column": 3,
706 "line": 30 706 "line": 29
707 }, 707 },
708 "file": "src/components/auth/Pricing.js", 708 "file": "src/components/auth/Pricing.js",
709 "id": "pricing.trial.intro.happyMessaging", 709 "id": "pricing.trial.intro.happyMessaging",
710 "start": { 710 "start": {
711 "column": 18, 711 "column": 18,
712 "line": 27 712 "line": 26
713 } 713 }
714 }, 714 },
715 { 715 {
716 "defaultMessage": "!!!No strings attached", 716 "defaultMessage": "!!!No strings attached",
717 "end": { 717 "end": {
718 "column": 3, 718 "column": 3,
719 "line": 34 719 "line": 33
720 }, 720 },
721 "file": "src/components/auth/Pricing.js", 721 "file": "src/components/auth/Pricing.js",
722 "id": "pricing.trial.terms.headline", 722 "id": "pricing.trial.terms.headline",
723 "start": { 723 "start": {
724 "column": 29, 724 "column": 29,
725 "line": 31 725 "line": 30
726 } 726 }
727 }, 727 },
728 { 728 {
729 "defaultMessage": "!!!No credit card required", 729 "defaultMessage": "!!!No credit card required",
730 "end": { 730 "end": {
731 "column": 3, 731 "column": 3,
732 "line": 38 732 "line": 37
733 }, 733 },
734 "file": "src/components/auth/Pricing.js", 734 "file": "src/components/auth/Pricing.js",
735 "id": "pricing.trial.terms.noCreditCard", 735 "id": "pricing.trial.terms.noCreditCard",
736 "start": { 736 "start": {
737 "column": 16, 737 "column": 16,
738 "line": 35 738 "line": 34
739 } 739 }
740 }, 740 },
741 { 741 {
742 "defaultMessage": "!!!Your free trial ends automatically after 14 days", 742 "defaultMessage": "!!!Your free trial ends automatically after 14 days",
743 "end": { 743 "end": {
744 "column": 3, 744 "column": 3,
745 "line": 42 745 "line": 41
746 }, 746 },
747 "file": "src/components/auth/Pricing.js", 747 "file": "src/components/auth/Pricing.js",
748 "id": "pricing.trial.terms.automaticTrialEnd", 748 "id": "pricing.trial.terms.automaticTrialEnd",
749 "start": { 749 "start": {
750 "column": 21, 750 "column": 21,
751 "line": 39 751 "line": 38
752 } 752 }
753 }, 753 },
754 { 754 {
755 "defaultMessage": "!!!Free trial (normally {currency}{price} per month)", 755 "defaultMessage": "!!!Free trial (normally {currency}{price} per month)",
756 "end": { 756 "end": {
757 "column": 3, 757 "column": 3,
758 "line": 46 758 "line": 45
759 }, 759 },
760 "file": "src/components/auth/Pricing.js", 760 "file": "src/components/auth/Pricing.js",
761 "id": "pricing.trial.terms.trialWorth", 761 "id": "pricing.trial.terms.trialWorth",
762 "start": { 762 "start": {
763 "column": 14, 763 "column": 14,
764 "line": 43 764 "line": 42
765 } 765 }
766 }, 766 },
767 { 767 {
768 "defaultMessage": "!!!Sorry, we could not activate your trial!", 768 "defaultMessage": "!!!Sorry, we could not activate your trial!",
769 "end": { 769 "end": {
770 "column": 3, 770 "column": 3,
771 "line": 50 771 "line": 49
772 }, 772 },
773 "file": "src/components/auth/Pricing.js", 773 "file": "src/components/auth/Pricing.js",
774 "id": "pricing.trial.error", 774 "id": "pricing.trial.error",
775 "start": { 775 "start": {
776 "column": 19, 776 "column": 19,
777 "line": 47 777 "line": 46
778 } 778 }
779 }, 779 },
780 { 780 {
781 "defaultMessage": "!!!Start my 14-day Franz Professional Trial", 781 "defaultMessage": "!!!Start my 14-day Franz Professional Trial",
782 "end": { 782 "end": {
783 "column": 3, 783 "column": 3,
784 "line": 54 784 "line": 53
785 }, 785 },
786 "file": "src/components/auth/Pricing.js", 786 "file": "src/components/auth/Pricing.js",
787 "id": "pricing.trial.cta.accept", 787 "id": "pricing.trial.cta.accept",
788 "start": { 788 "start": {
789 "column": 13, 789 "column": 13,
790 "line": 51 790 "line": 50
791 } 791 }
792 }, 792 },
793 { 793 {
794 "defaultMessage": "!!!Start using Franz", 794 "defaultMessage": "!!!Start using Franz",
795 "end": { 795 "end": {
796 "column": 3, 796 "column": 3,
797 "line": 58 797 "line": 57
798 }, 798 },
799 "file": "src/components/auth/Pricing.js", 799 "file": "src/components/auth/Pricing.js",
800 "id": "pricing.trial.cta.start", 800 "id": "pricing.trial.cta.start",
801 "start": { 801 "start": {
802 "column": 12, 802 "column": 12,
803 "line": 55 803 "line": 54
804 } 804 }
805 }, 805 },
806 { 806 {
807 "defaultMessage": "!!!Continue to Ferdi", 807 "defaultMessage": "!!!Continue to Ferdi",
808 "end": { 808 "end": {
809 "column": 3, 809 "column": 3,
810 "line": 62 810 "line": 61
811 }, 811 },
812 "file": "src/components/auth/Pricing.js", 812 "file": "src/components/auth/Pricing.js",
813 "id": "pricing.trial.cta.skip", 813 "id": "pricing.trial.cta.skip",
814 "start": { 814 "start": {
815 "column": 11, 815 "column": 11,
816 "line": 59 816 "line": 58
817 } 817 }
818 }, 818 },
819 { 819 {
820 "defaultMessage": "!!!Franz Professional includes:", 820 "defaultMessage": "!!!Franz Professional includes:",
821 "end": { 821 "end": {
822 "column": 3, 822 "column": 3,
823 "line": 66 823 "line": 65
824 }, 824 },
825 "file": "src/components/auth/Pricing.js", 825 "file": "src/components/auth/Pricing.js",
826 "id": "pricing.trial.features.headline", 826 "id": "pricing.trial.features.headline",
827 "start": { 827 "start": {
828 "column": 20, 828 "column": 20,
829 "line": 63 829 "line": 62
830 } 830 }
831 } 831 }
832 ], 832 ],
@@ -3659,6 +3659,24 @@
3659 { 3659 {
3660 "descriptors": [ 3660 "descriptors": [
3661 { 3661 {
3662 "defaultMessage": "!!!Close settings",
3663 "end": {
3664 "column": 3,
3665 "line": 14
3666 },
3667 "file": "src/components/settings/SettingsLayout.js",
3668 "id": "settings.app.closeSettings",
3669 "start": {
3670 "column": 17,
3671 "line": 11
3672 }
3673 }
3674 ],
3675 "path": "src/components/settings/SettingsLayout.json"
3676 },
3677 {
3678 "descriptors": [
3679 {
3662 "defaultMessage": "!!!About Ferdi", 3680 "defaultMessage": "!!!About Ferdi",
3663 "end": { 3681 "end": {
3664 "column": 3, 3682 "column": 3,
@@ -4562,6 +4580,60 @@
4562 { 4580 {
4563 "descriptors": [ 4581 "descriptors": [
4564 { 4582 {
4583 "defaultMessage": "!!!Hide",
4584 "end": {
4585 "column": 3,
4586 "line": 15
4587 },
4588 "file": "src/components/ui/InfoBar.js",
4589 "id": "infobar.hide",
4590 "start": {
4591 "column": 8,
4592 "line": 12
4593 }
4594 }
4595 ],
4596 "path": "src/components/ui/InfoBar.json"
4597 },
4598 {
4599 "descriptors": [
4600 {
4601 "defaultMessage": "!!!Dismiss",
4602 "end": {
4603 "column": 3,
4604 "line": 12
4605 },
4606 "file": "src/components/ui/Infobox.js",
4607 "id": "infobox.dismiss",
4608 "start": {
4609 "column": 11,
4610 "line": 9
4611 }
4612 }
4613 ],
4614 "path": "src/components/ui/Infobox.json"
4615 },
4616 {
4617 "descriptors": [
4618 {
4619 "defaultMessage": "!!!Password toggle",
4620 "end": {
4621 "column": 3,
4622 "line": 14
4623 },
4624 "file": "src/components/ui/Input.js",
4625 "id": "settings.app.form.passwordToggle",
4626 "start": {
4627 "column": 18,
4628 "line": 11
4629 }
4630 }
4631 ],
4632 "path": "src/components/ui/Input.json"
4633 },
4634 {
4635 "descriptors": [
4636 {
4565 "defaultMessage": "!!!Upgrade account", 4637 "defaultMessage": "!!!Upgrade account",
4566 "end": { 4638 "end": {
4567 "column": 3, 4639 "column": 3,
@@ -6070,91 +6142,91 @@
6070 "defaultMessage": "!!!Publish debug information", 6142 "defaultMessage": "!!!Publish debug information",
6071 "end": { 6143 "end": {
6072 "column": 3, 6144 "column": 3,
6073 "line": 21 6145 "line": 20
6074 }, 6146 },
6075 "file": "src/features/publishDebugInfo/Component.js", 6147 "file": "src/features/publishDebugInfo/Component.js",
6076 "id": "feature.publishDebugInfo.title", 6148 "id": "feature.publishDebugInfo.title",
6077 "start": { 6149 "start": {
6078 "column": 9, 6150 "column": 9,
6079 "line": 18 6151 "line": 17
6080 } 6152 }
6081 }, 6153 },
6082 { 6154 {
6083 "defaultMessage": "!!!Publishing your debug information helps us find issues and errors in Ferdi. By publishing your debug information you accept Ferdi Debugger's privacy policy and terms of service", 6155 "defaultMessage": "!!!Publishing your debug information helps us find issues and errors in Ferdi. By publishing your debug information you accept Ferdi Debugger's privacy policy and terms of service",
6084 "end": { 6156 "end": {
6085 "column": 3, 6157 "column": 3,
6086 "line": 25 6158 "line": 24
6087 }, 6159 },
6088 "file": "src/features/publishDebugInfo/Component.js", 6160 "file": "src/features/publishDebugInfo/Component.js",
6089 "id": "feature.publishDebugInfo.info", 6161 "id": "feature.publishDebugInfo.info",
6090 "start": { 6162 "start": {
6091 "column": 8, 6163 "column": 8,
6092 "line": 22 6164 "line": 21
6093 } 6165 }
6094 }, 6166 },
6095 { 6167 {
6096 "defaultMessage": "!!!There was an error while trying to publish the debug information. Please try again later or view the console for more information.", 6168 "defaultMessage": "!!!There was an error while trying to publish the debug information. Please try again later or view the console for more information.",
6097 "end": { 6169 "end": {
6098 "column": 3, 6170 "column": 3,
6099 "line": 29 6171 "line": 28
6100 }, 6172 },
6101 "file": "src/features/publishDebugInfo/Component.js", 6173 "file": "src/features/publishDebugInfo/Component.js",
6102 "id": "feature.publishDebugInfo.error", 6174 "id": "feature.publishDebugInfo.error",
6103 "start": { 6175 "start": {
6104 "column": 9, 6176 "column": 9,
6105 "line": 26 6177 "line": 25
6106 } 6178 }
6107 }, 6179 },
6108 { 6180 {
6109 "defaultMessage": "!!!Privacy policy", 6181 "defaultMessage": "!!!Privacy policy",
6110 "end": { 6182 "end": {
6111 "column": 3, 6183 "column": 3,
6112 "line": 33 6184 "line": 32
6113 }, 6185 },
6114 "file": "src/features/publishDebugInfo/Component.js", 6186 "file": "src/features/publishDebugInfo/Component.js",
6115 "id": "feature.publishDebugInfo.privacy", 6187 "id": "feature.publishDebugInfo.privacy",
6116 "start": { 6188 "start": {
6117 "column": 11, 6189 "column": 11,
6118 "line": 30 6190 "line": 29
6119 } 6191 }
6120 }, 6192 },
6121 { 6193 {
6122 "defaultMessage": "!!!Terms of service", 6194 "defaultMessage": "!!!Terms of service",
6123 "end": { 6195 "end": {
6124 "column": 3, 6196 "column": 3,
6125 "line": 37 6197 "line": 36
6126 }, 6198 },
6127 "file": "src/features/publishDebugInfo/Component.js", 6199 "file": "src/features/publishDebugInfo/Component.js",
6128 "id": "feature.publishDebugInfo.terms", 6200 "id": "feature.publishDebugInfo.terms",
6129 "start": { 6201 "start": {
6130 "column": 9, 6202 "column": 9,
6131 "line": 34 6203 "line": 33
6132 } 6204 }
6133 }, 6205 },
6134 { 6206 {
6135 "defaultMessage": "!!!Accept and publish", 6207 "defaultMessage": "!!!Accept and publish",
6136 "end": { 6208 "end": {
6137 "column": 3, 6209 "column": 3,
6138 "line": 41 6210 "line": 40
6139 }, 6211 },
6140 "file": "src/features/publishDebugInfo/Component.js", 6212 "file": "src/features/publishDebugInfo/Component.js",
6141 "id": "feature.publishDebugInfo.publish", 6213 "id": "feature.publishDebugInfo.publish",
6142 "start": { 6214 "start": {
6143 "column": 11, 6215 "column": 11,
6144 "line": 38 6216 "line": 37
6145 } 6217 }
6146 }, 6218 },
6147 { 6219 {
6148 "defaultMessage": "!!!Your debug log was published and is now availible at", 6220 "defaultMessage": "!!!Your debug log was published and is now availible at",
6149 "end": { 6221 "end": {
6150 "column": 3, 6222 "column": 3,
6151 "line": 45 6223 "line": 44
6152 }, 6224 },
6153 "file": "src/features/publishDebugInfo/Component.js", 6225 "file": "src/features/publishDebugInfo/Component.js",
6154 "id": "feature.publishDebugInfo.published", 6226 "id": "feature.publishDebugInfo.published",
6155 "start": { 6227 "start": {
6156 "column": 13, 6228 "column": 13,
6157 "line": 42 6229 "line": 41
6158 } 6230 }
6159 } 6231 }
6160 ], 6232 ],
@@ -6736,7 +6808,7 @@
6736 "defaultMessage": "!!!*This option will be overwritten by the global \"Keep all workspaces loaded\" option.", 6808 "defaultMessage": "!!!*This option will be overwritten by the global \"Keep all workspaces loaded\" option.",
6737 "end": { 6809 "end": {
6738 "column": 3, 6810 "column": 3,
6739 "line": 44 6811 "line": 45
6740 }, 6812 },
6741 "file": "src/features/workspaces/components/EditWorkspaceForm.js", 6813 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
6742 "id": "settings.workspace.form.keepLoadedInfo", 6814 "id": "settings.workspace.form.keepLoadedInfo",
@@ -6749,39 +6821,39 @@
6749 "defaultMessage": "!!!Services in this Workspace", 6821 "defaultMessage": "!!!Services in this Workspace",
6750 "end": { 6822 "end": {
6751 "column": 3, 6823 "column": 3,
6752 "line": 48 6824 "line": 49
6753 }, 6825 },
6754 "file": "src/features/workspaces/components/EditWorkspaceForm.js", 6826 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
6755 "id": "settings.workspace.form.servicesInWorkspaceHeadline", 6827 "id": "settings.workspace.form.servicesInWorkspaceHeadline",
6756 "start": { 6828 "start": {
6757 "column": 31, 6829 "column": 31,
6758 "line": 45 6830 "line": 46
6759 } 6831 }
6760 }, 6832 },
6761 { 6833 {
6762 "defaultMessage": "!!!Start by adding a service.", 6834 "defaultMessage": "!!!Start by adding a service.",
6763 "end": { 6835 "end": {
6764 "column": 3, 6836 "column": 3,
6765 "line": 52 6837 "line": 53
6766 }, 6838 },
6767 "file": "src/features/workspaces/components/EditWorkspaceForm.js", 6839 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
6768 "id": "settings.services.noServicesAdded", 6840 "id": "settings.services.noServicesAdded",
6769 "start": { 6841 "start": {
6770 "column": 19, 6842 "column": 19,
6771 "line": 49 6843 "line": 50
6772 } 6844 }
6773 }, 6845 },
6774 { 6846 {
6775 "defaultMessage": "!!!Discover services", 6847 "defaultMessage": "!!!Discover services",
6776 "end": { 6848 "end": {
6777 "column": 3, 6849 "column": 3,
6778 "line": 56 6850 "line": 57
6779 }, 6851 },
6780 "file": "src/features/workspaces/components/EditWorkspaceForm.js", 6852 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
6781 "id": "settings.services.discoverServices", 6853 "id": "settings.services.discoverServices",
6782 "start": { 6854 "start": {
6783 "column": 20, 6855 "column": 20,
6784 "line": 53 6856 "line": 54
6785 } 6857 }
6786 } 6858 }
6787 ], 6859 ],
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index fc25795a4..05a8e7486 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -84,10 +84,12 @@
84 "infobar.buttonChangelog": "What is new?", 84 "infobar.buttonChangelog": "What is new?",
85 "infobar.buttonInstallUpdate": "Restart & install update", 85 "infobar.buttonInstallUpdate": "Restart & install update",
86 "infobar.buttonReloadServices": "Reload services", 86 "infobar.buttonReloadServices": "Reload services",
87 "infobar.hide": "Hide",
87 "infobar.requiredRequestsFailed": "Could not load services and user information", 88 "infobar.requiredRequestsFailed": "Could not load services and user information",
88 "infobar.servicesUpdated": "Your services have been updated.", 89 "infobar.servicesUpdated": "Your services have been updated.",
89 "infobar.trialActivated": "Your trial was successfully activated. Happy messaging!", 90 "infobar.trialActivated": "Your trial was successfully activated. Happy messaging!",
90 "infobar.updateAvailable": "A new update for Ferdi is available.", 91 "infobar.updateAvailable": "A new update for Ferdi is available.",
92 "infobox.dismiss": "Dismiss",
91 "invite.email.label": "Email address", 93 "invite.email.label": "Email address",
92 "invite.headline.friends": "Invite 3 of your friends or colleagues", 94 "invite.headline.friends": "Invite 3 of your friends or colleagues",
93 "invite.name.label": "Name", 95 "invite.name.label": "Name",
@@ -286,6 +288,7 @@
286 "settings.app.buttonSearchForUpdate": "Check for updates", 288 "settings.app.buttonSearchForUpdate": "Check for updates",
287 "settings.app.cacheInfo": "Ferdi cache is currently using {size} of disk space.", 289 "settings.app.cacheInfo": "Ferdi cache is currently using {size} of disk space.",
288 "settings.app.cacheNotCleared": "Couldn't clear all cache", 290 "settings.app.cacheNotCleared": "Couldn't clear all cache",
291 "settings.app.closeSettings": "Close settings",
289 "settings.app.currentVersion": "Current version:", 292 "settings.app.currentVersion": "Current version:",
290 "settings.app.form.accentColor": "Accent color", 293 "settings.app.form.accentColor": "Accent color",
291 "settings.app.form.adaptableDarkMode": "Synchronize dark mode with my OS's dark mode setting", 294 "settings.app.form.adaptableDarkMode": "Synchronize dark mode with my OS's dark mode setting",
@@ -315,6 +318,7 @@
315 "settings.app.form.minimizeToSystemTray": "Minimize Ferdi to system tray", 318 "settings.app.form.minimizeToSystemTray": "Minimize Ferdi to system tray",
316 "settings.app.form.navigationBarBehaviour": "Navigation bar behaviour", 319 "settings.app.form.navigationBarBehaviour": "Navigation bar behaviour",
317 "settings.app.form.notifyTaskBarOnMessage": "Notify TaskBar/Dock on new message", 320 "settings.app.form.notifyTaskBarOnMessage": "Notify TaskBar/Dock on new message",
321 "settings.app.form.passwordToggle": "Password toggle",
318 "settings.app.form.predefinedTodoServer": "Todo Server", 322 "settings.app.form.predefinedTodoServer": "Todo Server",
319 "settings.app.form.privateNotifications": "Don't show message content in notifications", 323 "settings.app.form.privateNotifications": "Don't show message content in notifications",
320 "settings.app.form.reloadAfterResume": "Reload Ferdi after system resume", 324 "settings.app.form.reloadAfterResume": "Reload Ferdi after system resume",
diff --git a/src/i18n/messages/src/components/auth/Pricing.json b/src/i18n/messages/src/components/auth/Pricing.json
index c4c94bb32..b5b7d72a8 100644
--- a/src/i18n/messages/src/components/auth/Pricing.json
+++ b/src/i18n/messages/src/components/auth/Pricing.json
@@ -4,11 +4,11 @@
4 "defaultMessage": "!!!Hi {name}, welcome to Franz", 4 "defaultMessage": "!!!Hi {name}, welcome to Franz",
5 "file": "src/components/auth/Pricing.js", 5 "file": "src/components/auth/Pricing.js",
6 "start": { 6 "start": {
7 "line": 15, 7 "line": 14,
8 "column": 12 8 "column": 12
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 18, 11 "line": 17,
12 "column": 3 12 "column": 3
13 } 13 }
14 }, 14 },
@@ -17,11 +17,11 @@
17 "defaultMessage": "!!!We have a special treat for you.", 17 "defaultMessage": "!!!We have a special treat for you.",
18 "file": "src/components/auth/Pricing.js", 18 "file": "src/components/auth/Pricing.js",
19 "start": { 19 "start": {
20 "line": 19, 20 "line": 18,
21 "column": 16 21 "column": 16
22 }, 22 },
23 "end": { 23 "end": {
24 "line": 22, 24 "line": 21,
25 "column": 3 25 "column": 3
26 } 26 }
27 }, 27 },
@@ -30,11 +30,11 @@
30 "defaultMessage": "!!!Enjoy the full Franz Professional experience completely free for 14 days.", 30 "defaultMessage": "!!!Enjoy the full Franz Professional experience completely free for 14 days.",
31 "file": "src/components/auth/Pricing.js", 31 "file": "src/components/auth/Pricing.js",
32 "start": { 32 "start": {
33 "line": 23, 33 "line": 22,
34 "column": 10 34 "column": 10
35 }, 35 },
36 "end": { 36 "end": {
37 "line": 26, 37 "line": 25,
38 "column": 3 38 "column": 3
39 } 39 }
40 }, 40 },
@@ -43,11 +43,11 @@
43 "defaultMessage": "!!!Happy messaging,", 43 "defaultMessage": "!!!Happy messaging,",
44 "file": "src/components/auth/Pricing.js", 44 "file": "src/components/auth/Pricing.js",
45 "start": { 45 "start": {
46 "line": 27, 46 "line": 26,
47 "column": 18 47 "column": 18
48 }, 48 },
49 "end": { 49 "end": {
50 "line": 30, 50 "line": 29,
51 "column": 3 51 "column": 3
52 } 52 }
53 }, 53 },
@@ -56,11 +56,11 @@
56 "defaultMessage": "!!!No strings attached", 56 "defaultMessage": "!!!No strings attached",
57 "file": "src/components/auth/Pricing.js", 57 "file": "src/components/auth/Pricing.js",
58 "start": { 58 "start": {
59 "line": 31, 59 "line": 30,
60 "column": 29 60 "column": 29
61 }, 61 },
62 "end": { 62 "end": {
63 "line": 34, 63 "line": 33,
64 "column": 3 64 "column": 3
65 } 65 }
66 }, 66 },
@@ -69,11 +69,11 @@
69 "defaultMessage": "!!!No credit card required", 69 "defaultMessage": "!!!No credit card required",
70 "file": "src/components/auth/Pricing.js", 70 "file": "src/components/auth/Pricing.js",
71 "start": { 71 "start": {
72 "line": 35, 72 "line": 34,
73 "column": 16 73 "column": 16
74 }, 74 },
75 "end": { 75 "end": {
76 "line": 38, 76 "line": 37,
77 "column": 3 77 "column": 3
78 } 78 }
79 }, 79 },
@@ -82,11 +82,11 @@
82 "defaultMessage": "!!!Your free trial ends automatically after 14 days", 82 "defaultMessage": "!!!Your free trial ends automatically after 14 days",
83 "file": "src/components/auth/Pricing.js", 83 "file": "src/components/auth/Pricing.js",
84 "start": { 84 "start": {
85 "line": 39, 85 "line": 38,
86 "column": 21 86 "column": 21
87 }, 87 },
88 "end": { 88 "end": {
89 "line": 42, 89 "line": 41,
90 "column": 3 90 "column": 3
91 } 91 }
92 }, 92 },
@@ -95,11 +95,11 @@
95 "defaultMessage": "!!!Free trial (normally {currency}{price} per month)", 95 "defaultMessage": "!!!Free trial (normally {currency}{price} per month)",
96 "file": "src/components/auth/Pricing.js", 96 "file": "src/components/auth/Pricing.js",
97 "start": { 97 "start": {
98 "line": 43, 98 "line": 42,
99 "column": 14 99 "column": 14
100 }, 100 },
101 "end": { 101 "end": {
102 "line": 46, 102 "line": 45,
103 "column": 3 103 "column": 3
104 } 104 }
105 }, 105 },
@@ -108,11 +108,11 @@
108 "defaultMessage": "!!!Sorry, we could not activate your trial!", 108 "defaultMessage": "!!!Sorry, we could not activate your trial!",
109 "file": "src/components/auth/Pricing.js", 109 "file": "src/components/auth/Pricing.js",
110 "start": { 110 "start": {
111 "line": 47, 111 "line": 46,
112 "column": 19 112 "column": 19
113 }, 113 },
114 "end": { 114 "end": {
115 "line": 50, 115 "line": 49,
116 "column": 3 116 "column": 3
117 } 117 }
118 }, 118 },
@@ -121,11 +121,11 @@
121 "defaultMessage": "!!!Start my 14-day Franz Professional Trial", 121 "defaultMessage": "!!!Start my 14-day Franz Professional Trial",
122 "file": "src/components/auth/Pricing.js", 122 "file": "src/components/auth/Pricing.js",
123 "start": { 123 "start": {
124 "line": 51, 124 "line": 50,
125 "column": 13 125 "column": 13
126 }, 126 },
127 "end": { 127 "end": {
128 "line": 54, 128 "line": 53,
129 "column": 3 129 "column": 3
130 } 130 }
131 }, 131 },
@@ -134,11 +134,11 @@
134 "defaultMessage": "!!!Start using Franz", 134 "defaultMessage": "!!!Start using Franz",
135 "file": "src/components/auth/Pricing.js", 135 "file": "src/components/auth/Pricing.js",
136 "start": { 136 "start": {
137 "line": 55, 137 "line": 54,
138 "column": 12 138 "column": 12
139 }, 139 },
140 "end": { 140 "end": {
141 "line": 58, 141 "line": 57,
142 "column": 3 142 "column": 3
143 } 143 }
144 }, 144 },
@@ -147,11 +147,11 @@
147 "defaultMessage": "!!!Continue to Ferdi", 147 "defaultMessage": "!!!Continue to Ferdi",
148 "file": "src/components/auth/Pricing.js", 148 "file": "src/components/auth/Pricing.js",
149 "start": { 149 "start": {
150 "line": 59, 150 "line": 58,
151 "column": 11 151 "column": 11
152 }, 152 },
153 "end": { 153 "end": {
154 "line": 62, 154 "line": 61,
155 "column": 3 155 "column": 3
156 } 156 }
157 }, 157 },
@@ -160,11 +160,11 @@
160 "defaultMessage": "!!!Franz Professional includes:", 160 "defaultMessage": "!!!Franz Professional includes:",
161 "file": "src/components/auth/Pricing.js", 161 "file": "src/components/auth/Pricing.js",
162 "start": { 162 "start": {
163 "line": 63, 163 "line": 62,
164 "column": 20 164 "column": 20
165 }, 165 },
166 "end": { 166 "end": {
167 "line": 66, 167 "line": 65,
168 "column": 3 168 "column": 3
169 } 169 }
170 } 170 }
diff --git a/src/i18n/messages/src/components/settings/SettingsLayout.json b/src/i18n/messages/src/components/settings/SettingsLayout.json
new file mode 100644
index 000000000..99337a315
--- /dev/null
+++ b/src/i18n/messages/src/components/settings/SettingsLayout.json
@@ -0,0 +1,15 @@
1[
2 {
3 "id": "settings.app.closeSettings",
4 "defaultMessage": "!!!Close settings",
5 "file": "src/components/settings/SettingsLayout.js",
6 "start": {
7 "line": 11,
8 "column": 17
9 },
10 "end": {
11 "line": 14,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/ui/InfoBar.json b/src/i18n/messages/src/components/ui/InfoBar.json
new file mode 100644
index 000000000..a6a629c71
--- /dev/null
+++ b/src/i18n/messages/src/components/ui/InfoBar.json
@@ -0,0 +1,15 @@
1[
2 {
3 "id": "infobar.hide",
4 "defaultMessage": "!!!Hide",
5 "file": "src/components/ui/InfoBar.js",
6 "start": {
7 "line": 12,
8 "column": 8
9 },
10 "end": {
11 "line": 15,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/ui/Infobox.json b/src/i18n/messages/src/components/ui/Infobox.json
new file mode 100644
index 000000000..296c2ad3e
--- /dev/null
+++ b/src/i18n/messages/src/components/ui/Infobox.json
@@ -0,0 +1,15 @@
1[
2 {
3 "id": "infobox.dismiss",
4 "defaultMessage": "!!!Dismiss",
5 "file": "src/components/ui/Infobox.js",
6 "start": {
7 "line": 9,
8 "column": 11
9 },
10 "end": {
11 "line": 12,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/components/ui/Input.json b/src/i18n/messages/src/components/ui/Input.json
new file mode 100644
index 000000000..6240badfb
--- /dev/null
+++ b/src/i18n/messages/src/components/ui/Input.json
@@ -0,0 +1,15 @@
1[
2 {
3 "id": "settings.app.form.passwordToggle",
4 "defaultMessage": "!!!Password toggle",
5 "file": "src/components/ui/Input.js",
6 "start": {
7 "line": 11,
8 "column": 18
9 },
10 "end": {
11 "line": 14,
12 "column": 3
13 }
14 }
15] \ No newline at end of file
diff --git a/src/i18n/messages/src/features/publishDebugInfo/Component.json b/src/i18n/messages/src/features/publishDebugInfo/Component.json
index 85fbe7ca6..25048ace6 100644
--- a/src/i18n/messages/src/features/publishDebugInfo/Component.json
+++ b/src/i18n/messages/src/features/publishDebugInfo/Component.json
@@ -4,11 +4,11 @@
4 "defaultMessage": "!!!Publish debug information", 4 "defaultMessage": "!!!Publish debug information",
5 "file": "src/features/publishDebugInfo/Component.js", 5 "file": "src/features/publishDebugInfo/Component.js",
6 "start": { 6 "start": {
7 "line": 18, 7 "line": 17,
8 "column": 9 8 "column": 9
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 21, 11 "line": 20,
12 "column": 3 12 "column": 3
13 } 13 }
14 }, 14 },
@@ -17,11 +17,11 @@
17 "defaultMessage": "!!!Publishing your debug information helps us find issues and errors in Ferdi. By publishing your debug information you accept Ferdi Debugger's privacy policy and terms of service", 17 "defaultMessage": "!!!Publishing your debug information helps us find issues and errors in Ferdi. By publishing your debug information you accept Ferdi Debugger's privacy policy and terms of service",
18 "file": "src/features/publishDebugInfo/Component.js", 18 "file": "src/features/publishDebugInfo/Component.js",
19 "start": { 19 "start": {
20 "line": 22, 20 "line": 21,
21 "column": 8 21 "column": 8
22 }, 22 },
23 "end": { 23 "end": {
24 "line": 25, 24 "line": 24,
25 "column": 3 25 "column": 3
26 } 26 }
27 }, 27 },
@@ -30,11 +30,11 @@
30 "defaultMessage": "!!!There was an error while trying to publish the debug information. Please try again later or view the console for more information.", 30 "defaultMessage": "!!!There was an error while trying to publish the debug information. Please try again later or view the console for more information.",
31 "file": "src/features/publishDebugInfo/Component.js", 31 "file": "src/features/publishDebugInfo/Component.js",
32 "start": { 32 "start": {
33 "line": 26, 33 "line": 25,
34 "column": 9 34 "column": 9
35 }, 35 },
36 "end": { 36 "end": {
37 "line": 29, 37 "line": 28,
38 "column": 3 38 "column": 3
39 } 39 }
40 }, 40 },
@@ -43,11 +43,11 @@
43 "defaultMessage": "!!!Privacy policy", 43 "defaultMessage": "!!!Privacy policy",
44 "file": "src/features/publishDebugInfo/Component.js", 44 "file": "src/features/publishDebugInfo/Component.js",
45 "start": { 45 "start": {
46 "line": 30, 46 "line": 29,
47 "column": 11 47 "column": 11
48 }, 48 },
49 "end": { 49 "end": {
50 "line": 33, 50 "line": 32,
51 "column": 3 51 "column": 3
52 } 52 }
53 }, 53 },
@@ -56,11 +56,11 @@
56 "defaultMessage": "!!!Terms of service", 56 "defaultMessage": "!!!Terms of service",
57 "file": "src/features/publishDebugInfo/Component.js", 57 "file": "src/features/publishDebugInfo/Component.js",
58 "start": { 58 "start": {
59 "line": 34, 59 "line": 33,
60 "column": 9 60 "column": 9
61 }, 61 },
62 "end": { 62 "end": {
63 "line": 37, 63 "line": 36,
64 "column": 3 64 "column": 3
65 } 65 }
66 }, 66 },
@@ -69,11 +69,11 @@
69 "defaultMessage": "!!!Accept and publish", 69 "defaultMessage": "!!!Accept and publish",
70 "file": "src/features/publishDebugInfo/Component.js", 70 "file": "src/features/publishDebugInfo/Component.js",
71 "start": { 71 "start": {
72 "line": 38, 72 "line": 37,
73 "column": 11 73 "column": 11
74 }, 74 },
75 "end": { 75 "end": {
76 "line": 41, 76 "line": 40,
77 "column": 3 77 "column": 3
78 } 78 }
79 }, 79 },
@@ -82,11 +82,11 @@
82 "defaultMessage": "!!!Your debug log was published and is now availible at", 82 "defaultMessage": "!!!Your debug log was published and is now availible at",
83 "file": "src/features/publishDebugInfo/Component.js", 83 "file": "src/features/publishDebugInfo/Component.js",
84 "start": { 84 "start": {
85 "line": 42, 85 "line": 41,
86 "column": 13 86 "column": 13
87 }, 87 },
88 "end": { 88 "end": {
89 "line": 45, 89 "line": 44,
90 "column": 3 90 "column": 3
91 } 91 }
92 } 92 }
diff --git a/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json b/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json
index 053751c84..804e30070 100644
--- a/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json
+++ b/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json
@@ -73,7 +73,7 @@
73 "column": 18 73 "column": 18
74 }, 74 },
75 "end": { 75 "end": {
76 "line": 44, 76 "line": 45,
77 "column": 3 77 "column": 3
78 } 78 }
79 }, 79 },
@@ -82,11 +82,11 @@
82 "defaultMessage": "!!!Services in this Workspace", 82 "defaultMessage": "!!!Services in this Workspace",
83 "file": "src/features/workspaces/components/EditWorkspaceForm.js", 83 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
84 "start": { 84 "start": {
85 "line": 45, 85 "line": 46,
86 "column": 31 86 "column": 31
87 }, 87 },
88 "end": { 88 "end": {
89 "line": 48, 89 "line": 49,
90 "column": 3 90 "column": 3
91 } 91 }
92 }, 92 },
@@ -95,11 +95,11 @@
95 "defaultMessage": "!!!Start by adding a service.", 95 "defaultMessage": "!!!Start by adding a service.",
96 "file": "src/features/workspaces/components/EditWorkspaceForm.js", 96 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
97 "start": { 97 "start": {
98 "line": 49, 98 "line": 50,
99 "column": 19 99 "column": 19
100 }, 100 },
101 "end": { 101 "end": {
102 "line": 52, 102 "line": 53,
103 "column": 3 103 "column": 3
104 } 104 }
105 }, 105 },
@@ -108,11 +108,11 @@
108 "defaultMessage": "!!!Discover services", 108 "defaultMessage": "!!!Discover services",
109 "file": "src/features/workspaces/components/EditWorkspaceForm.js", 109 "file": "src/features/workspaces/components/EditWorkspaceForm.js",
110 "start": { 110 "start": {
111 "line": 53, 111 "line": 54,
112 "column": 20 112 "column": 20
113 }, 113 },
114 "end": { 114 "end": {
115 "line": 56, 115 "line": 57,
116 "column": 3 116 "column": 3
117 } 117 }
118 } 118 }
diff --git a/src/lib/Menu.js b/src/lib/Menu.js
index 6e3f120ba..8118b4e26 100644
--- a/src/lib/Menu.js
+++ b/src/lib/Menu.js
@@ -1269,7 +1269,6 @@ export default class FranzMenu {
1269 return menu; 1269 return menu;
1270 } 1270 }
1271 1271
1272
1273 debugMenu() { 1272 debugMenu() {
1274 const { intl } = window.ferdi; 1273 const { intl } = window.ferdi;
1275 1274
diff --git a/src/models/User.js b/src/models/User.js
index 5a614efbe..74a39926b 100644
--- a/src/models/User.js
+++ b/src/models/User.js
@@ -38,7 +38,6 @@ export default class User {
38 38
39 @observable team = {}; 39 @observable team = {};
40 40
41
42 constructor(data) { 41 constructor(data) {
43 if (!data.id) { 42 if (!data.id) {
44 throw Error('User requires Id'); 43 throw Error('User requires Id');
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js
index dd4ab3629..3116677c2 100644
--- a/src/stores/AppStore.js
+++ b/src/stores/AppStore.js
@@ -127,7 +127,6 @@ export default class AppStore extends Store {
127 this.isFullScreen = false; 127 this.isFullScreen = false;
128 }); 128 });
129 129
130
131 this.isOnline = navigator.onLine; 130 this.isOnline = navigator.onLine;
132 131
133 // Check if Ferdi should launch on start 132 // Check if Ferdi should launch on start
@@ -474,7 +473,6 @@ export default class AppStore extends Store {
474 locale = this.stores.user.data.locale; 473 locale = this.stores.user.data.locale;
475 } 474 }
476 475
477
478 if (locale && Object.prototype.hasOwnProperty.call(locales, locale) && locale !== this.locale) { 476 if (locale && Object.prototype.hasOwnProperty.call(locales, locale) && locale !== this.locale) {
479 this.locale = locale; 477 this.locale = locale;
480 } else if (!locale) { 478 } else if (!locale) {
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js
index 631d0318e..2fee9bdda 100644
--- a/src/stores/FeaturesStore.js
+++ b/src/stores/FeaturesStore.js
@@ -33,7 +33,7 @@ export default class FeaturesStore extends Store {
33 33
34 @observable featuresRequest = new CachedRequest(this.api.features, 'features'); 34 @observable featuresRequest = new CachedRequest(this.api.features, 'features');
35 35
36 @observable features = Object.assign({}, DEFAULT_FEATURES_CONFIG); 36 @observable features = ({ ...DEFAULT_FEATURES_CONFIG });
37 37
38 async setup() { 38 async setup() {
39 this.registerReactions([ 39 this.registerReactions([
@@ -57,7 +57,7 @@ export default class FeaturesStore extends Store {
57 } 57 }
58 58
59 _updateFeatures = () => { 59 _updateFeatures = () => {
60 const features = Object.assign({}, DEFAULT_FEATURES_CONFIG); 60 const features = { ...DEFAULT_FEATURES_CONFIG };
61 if (this.stores.user.isLoggedIn) { 61 if (this.stores.user.isLoggedIn) {
62 let requestResult = {}; 62 let requestResult = {};
63 try { 63 try {
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js
index 3dba217b2..9b69cb7c6 100644
--- a/src/stores/ServicesStore.js
+++ b/src/stores/ServicesStore.js
@@ -306,6 +306,7 @@ export default class ServicesStore extends Store {
306 } 306 }
307 307
308 // set default values for serviceData 308 // set default values for serviceData
309 // eslint-disable-next-line prefer-object-spread
309 Object.assign({ 310 Object.assign({
310 isEnabled: true, 311 isEnabled: true,
311 isHibernationEnabled: false, 312 isHibernationEnabled: false,
diff --git a/src/theme/default/legacy.js b/src/theme/default/legacy.js
index e894a06ed..3f4bec5d5 100644
--- a/src/theme/default/legacy.js
+++ b/src/theme/default/legacy.js
@@ -22,7 +22,6 @@ export const themeTransitionTime = '.5s';
22 22
23export const themeInsetShadow = 'inset 0 2px 5px rgba(0, 0, 0, .03)'; 23export const themeInsetShadow = 'inset 0 2px 5px rgba(0, 0, 0, .03)';
24 24
25
26export const darkThemeBlack = '#1A1A1A'; 25export const darkThemeBlack = '#1A1A1A';
27 26
28export const darkThemeGrayDarkest = '#1E1E1E'; 27export const darkThemeGrayDarkest = '#1E1E1E';
diff --git a/src/webview/contextMenuBuilder.js b/src/webview/contextMenuBuilder.js
index c26f192fe..500a1a653 100644
--- a/src/webview/contextMenuBuilder.js
+++ b/src/webview/contextMenuBuilder.js
@@ -64,7 +64,7 @@ module.exports = class ContextMenuBuilder {
64 this.debugMode = debugMode; 64 this.debugMode = debugMode;
65 this.processMenu = processMenu; 65 this.processMenu = processMenu;
66 this.menu = null; 66 this.menu = null;
67 this.stringTable = Object.assign({}, contextMenuStringTable); 67 this.stringTable = { ...contextMenuStringTable };
68 this.getWebContents = () => webContents; 68 this.getWebContents = () => webContents;
69 } 69 }
70 70
diff --git a/src/webview/lib/RecipeWebview.js b/src/webview/lib/RecipeWebview.js
index 84ac45ecc..b5793a5f1 100644
--- a/src/webview/lib/RecipeWebview.js
+++ b/src/webview/lib/RecipeWebview.js
@@ -59,7 +59,6 @@ class RecipeWebview {
59 indirect: Math.max(indirectInt, 0), 59 indirect: Math.max(indirectInt, 0),
60 }; 60 };
61 61
62
63 ipcRenderer.sendToHost('message-counts', count); 62 ipcRenderer.sendToHost('message-counts', count);
64 Object.assign(this.countCache, count); 63 Object.assign(this.countCache, count);
65 64
diff --git a/src/webview/screenshare.js b/src/webview/screenshare.js
index 2715f2e3e..84d2e1e95 100644
--- a/src/webview/screenshare.js
+++ b/src/webview/screenshare.js
@@ -73,25 +73,29 @@ export const screenShareCss = `
73`; 73`;
74 74
75// Patch getDisplayMedia for screen sharing 75// Patch getDisplayMedia for screen sharing
76window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve, reject) => { 76window.navigator.mediaDevices.getDisplayMedia = () => async (resolve, reject) => {
77 try { 77 try {
78 const sources = await desktopCapturer.getSources({ types: ['screen', 'window'] }); 78 const sources = await desktopCapturer.getSources({
79 types: ['screen', 'window'],
80 });
79 81
80 const selectionElem = document.createElement('div'); 82 const selectionElem = document.createElement('div');
81 selectionElem.classList = 'desktop-capturer-selection'; 83 selectionElem.classList = 'desktop-capturer-selection';
82 selectionElem.innerHTML = ` 84 selectionElem.innerHTML = `
83 <div class="desktop-capturer-selection__scroller"> 85 <div class="desktop-capturer-selection__scroller">
84 <ul class="desktop-capturer-selection__list"> 86 <ul class="desktop-capturer-selection__list">
85 ${sources.map(({ 87 ${sources
86 id, name, thumbnail, 88 .map(
87 }) => ` 89 ({ id, name, thumbnail }) => `
88 <li class="desktop-capturer-selection__item"> 90 <li class="desktop-capturer-selection__item">
89 <button class="desktop-capturer-selection__btn" data-id="${id}" title="${name}"> 91 <button class="desktop-capturer-selection__btn" data-id="${id}" title="${name}">
90 <img class="desktop-capturer-selection__thumbnail" src="${thumbnail.toDataURL()}" /> 92 <img class="desktop-capturer-selection__thumbnail" src="${thumbnail.toDataURL()}" />
91 <span class="desktop-capturer-selection__name">${name}</span> 93 <span class="desktop-capturer-selection__name">${name}</span>
92 </button> 94 </button>
93 </li> 95 </li>
94 `).join('')} 96 `,
97 )
98 .join('')}
95 <li class="desktop-capturer-selection__item"> 99 <li class="desktop-capturer-selection__item">
96 <button class="desktop-capturer-selection__btn" data-id="${CANCEL_ID}" title="Cancel"> 100 <button class="desktop-capturer-selection__btn" data-id="${CANCEL_ID}" title="Cancel">
97 <span class="desktop-capturer-selection__name desktop-capturer-selection__name--cancel">Cancel</span> 101 <span class="desktop-capturer-selection__name desktop-capturer-selection__name--cancel">Cancel</span>
@@ -102,7 +106,8 @@ window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve
102 `; 106 `;
103 document.body.appendChild(selectionElem); 107 document.body.appendChild(selectionElem);
104 108
105 document.querySelectorAll('.desktop-capturer-selection__btn') 109 document
110 .querySelectorAll('.desktop-capturer-selection__btn')
106 .forEach((button) => { 111 .forEach((button) => {
107 button.addEventListener('click', async () => { 112 button.addEventListener('click', async () => {
108 try { 113 try {
@@ -110,20 +115,22 @@ window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve
110 if (id === CANCEL_ID) { 115 if (id === CANCEL_ID) {
111 reject(new Error('Cancelled by user')); 116 reject(new Error('Cancelled by user'));
112 } else { 117 } else {
113 const mediaSource = sources.find(source => source.id === id); 118 const mediaSource = sources.find((source) => source.id === id);
114 if (!mediaSource) { 119 if (!mediaSource) {
115 throw new Error(`Source with id ${id} does not exist`); 120 throw new Error(`Source with id ${id} does not exist`);
116 } 121 }
117 122
118 const stream = await window.navigator.mediaDevices.getUserMedia({ 123 const stream = await window.navigator.mediaDevices.getUserMedia(
119 audio: false, 124 {
120 video: { 125 audio: false,
121 mandatory: { 126 video: {
122 chromeMediaSource: 'desktop', 127 mandatory: {
123 chromeMediaSourceId: mediaSource.id, 128 chromeMediaSource: 'desktop',
129 chromeMediaSourceId: mediaSource.id,
130 },
124 }, 131 },
125 }, 132 },
126 }); 133 );
127 resolve(stream); 134 resolve(stream);
128 } 135 }
129 } catch (err) { 136 } catch (err) {
@@ -136,4 +143,4 @@ window.navigator.mediaDevices.getDisplayMedia = () => new Promise(async (resolve
136 } catch (err) { 143 } catch (err) {
137 reject(err); 144 reject(err);
138 } 145 }
139}); 146};