aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/actions/service.js3
-rw-r--r--src/components/layout/Sidebar.js11
-rw-r--r--src/components/services/content/ServiceView.js6
-rw-r--r--src/components/settings/services/EditServiceForm.js65
-rw-r--r--src/components/settings/settings/EditSettingsForm.js2
-rw-r--r--src/config.js7
-rw-r--r--src/containers/settings/EditServiceScreen.js26
-rw-r--r--src/containers/settings/EditSettingsScreen.js24
-rw-r--r--src/i18n/locales/defaultMessages.json125
-rw-r--r--src/i18n/locales/en-US.json5
-rw-r--r--src/i18n/messages/src/components/settings/services/EditServiceForm.json119
-rw-r--r--src/i18n/messages/src/containers/settings/EditSettingsScreen.json6
-rw-r--r--src/lib/Menu.js177
-rw-r--r--src/stores/ServicesStore.js12
-rw-r--r--src/stores/SettingsStore.js88
-rw-r--r--src/styles/settings.scss10
-rw-r--r--src/webview/recipe.js33
17 files changed, 440 insertions, 279 deletions
diff --git a/src/actions/service.js b/src/actions/service.js
index d32bb80d3..f0c42e8aa 100644
--- a/src/actions/service.js
+++ b/src/actions/service.js
@@ -28,8 +28,9 @@ export default {
28 serviceId: PropTypes.string.isRequired, 28 serviceId: PropTypes.string.isRequired,
29 redirect: PropTypes.string, 29 redirect: PropTypes.string,
30 }, 30 },
31 openDarkmodeCss: { 31 openRecipeFile: {
32 recipe: PropTypes.string.isRequired, 32 recipe: PropTypes.string.isRequired,
33 file: PropTypes.string.isRequired,
33 }, 34 },
34 clearCache: { 35 clearCache: {
35 serviceId: PropTypes.string.isRequired, 36 serviceId: PropTypes.string.isRequired,
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js
index 48a83c5a1..bd10ccb4a 100644
--- a/src/components/layout/Sidebar.js
+++ b/src/components/layout/Sidebar.js
@@ -118,21 +118,12 @@ export default @inject('stores', 'actions') @observer class Sidebar extends Comp
118 type="button" 118 type="button"
119 className="sidebar__button" 119 className="sidebar__button"
120 onClick={() => { 120 onClick={() => {
121 // Disable lock first - otherwise the application might not update correctly
122 actions.settings.update({ 121 actions.settings.update({
123 type: 'app', 122 type: 'app',
124 data: { 123 data: {
125 locked: false, 124 locked: true,
126 }, 125 },
127 }); 126 });
128 setTimeout(() => {
129 actions.settings.update({
130 type: 'app',
131 data: {
132 locked: true,
133 },
134 });
135 }, 0);
136 }} 127 }}
137 data-tip={`${intl.formatMessage(messages.lockFerdi)} (${ctrlKey}+Shift+L)`} 128 data-tip={`${intl.formatMessage(messages.lockFerdi)} (${ctrlKey}+Shift+L)`}
138 > 129 >
diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js
index 860863d26..f6832038a 100644
--- a/src/components/services/content/ServiceView.js
+++ b/src/components/services/content/ServiceView.js
@@ -135,9 +135,11 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
135 } = this.props; 135 } = this.props;
136 136
137 const { 137 const {
138 showServiceNavigationBar, 138 navigationBarBehaviour,
139 } = stores.settings.app; 139 } = stores.settings.app;
140 140
141 const showNavBar = navigationBarBehaviour === 'always' || (navigationBarBehaviour === 'custom' && service.recipe.id === CUSTOM_WEBSITE_ID);
142
141 const webviewClasses = classnames({ 143 const webviewClasses = classnames({
142 services__webview: true, 144 services__webview: true,
143 'services__webview-wrapper': true, 145 'services__webview-wrapper': true,
@@ -193,7 +195,7 @@ export default @inject('stores', 'actions') @observer class ServiceView extends
193 <> 195 <>
194 {!service.isHibernating ? ( 196 {!service.isHibernating ? (
195 <> 197 <>
196 {(service.recipe.id === CUSTOM_WEBSITE_ID || showServiceNavigationBar) && ( 198 {showNavBar && (
197 <WebControlsScreen service={service} /> 199 <WebControlsScreen service={service} />
198 )} 200 )}
199 <ServiceWebview 201 <ServiceWebview
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js
index 89c82c7f8..98051d78f 100644
--- a/src/components/settings/services/EditServiceForm.js
+++ b/src/components/settings/services/EditServiceForm.js
@@ -33,6 +33,18 @@ const messages = defineMessages({
33 id: 'settings.service.form.openDarkmodeCss', 33 id: 'settings.service.form.openDarkmodeCss',
34 defaultMessage: '!!!Open darkmode.css', 34 defaultMessage: '!!!Open darkmode.css',
35 }, 35 },
36 openUserCss: {
37 id: 'settings.service.form.openUserCss',
38 defaultMessage: '!!!Open user.css',
39 },
40 openUserJs: {
41 id: 'settings.service.form.openUserJs',
42 defaultMessage: '!!!Open user.js',
43 },
44 recipeFileInfo: {
45 id: 'settings.service.form.recipeFileInfo',
46 defaultMessage: '!!!Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.',
47 },
36 availableServices: { 48 availableServices: {
37 id: 'settings.service.form.availableServices', 49 id: 'settings.service.form.availableServices',
38 defaultMessage: '!!!Available services', 50 defaultMessage: '!!!Available services',
@@ -131,8 +143,7 @@ export default @observer class EditServiceForm extends Component {
131 form: PropTypes.instanceOf(Form).isRequired, 143 form: PropTypes.instanceOf(Form).isRequired,
132 onSubmit: PropTypes.func.isRequired, 144 onSubmit: PropTypes.func.isRequired,
133 onDelete: PropTypes.func.isRequired, 145 onDelete: PropTypes.func.isRequired,
134 openDarkmodeCss: PropTypes.func.isRequired, 146 openRecipeFile: PropTypes.func.isRequired,
135 isOpeningDarkModeCss: PropTypes.bool.isRequired,
136 isSaving: PropTypes.bool.isRequired, 147 isSaving: PropTypes.bool.isRequired,
137 isDeleting: PropTypes.bool.isRequired, 148 isDeleting: PropTypes.bool.isRequired,
138 isProxyFeatureEnabled: PropTypes.bool.isRequired, 149 isProxyFeatureEnabled: PropTypes.bool.isRequired,
@@ -199,8 +210,7 @@ export default @observer class EditServiceForm extends Component {
199 isSaving, 210 isSaving,
200 isDeleting, 211 isDeleting,
201 onDelete, 212 onDelete,
202 openDarkmodeCss, 213 openRecipeFile,
203 isOpeningDarkModeCss,
204 isProxyFeatureEnabled, 214 isProxyFeatureEnabled,
205 isServiceProxyIncludedInCurrentPlan, 215 isServiceProxyIncludedInCurrentPlan,
206 isSpellcheckerIncludedInCurrentPlan, 216 isSpellcheckerIncludedInCurrentPlan,
@@ -226,23 +236,6 @@ export default @observer class EditServiceForm extends Component {
226 /> 236 />
227 ); 237 );
228 238
229 const openDarkmodeCssButton = isOpeningDarkModeCss ? (
230 <Button
231 label={intl.formatMessage(messages.openDarkmodeCss)}
232 loaded={false}
233 buttonType="secondary"
234 className="settings__open-dark-mode-button"
235 disabled
236 />
237 ) : (
238 <Button
239 buttonType="secondary"
240 label={intl.formatMessage(messages.openDarkmodeCss)}
241 className="settings__open-dark-mode-button"
242 onClick={openDarkmodeCss}
243 />
244 );
245
246 let activeTabIndex = 0; 239 let activeTabIndex = 0;
247 if (recipe.hasHostedOption && service.team) { 240 if (recipe.hasHostedOption && service.team) {
248 activeTabIndex = 1; 241 activeTabIndex = 1;
@@ -430,11 +423,39 @@ export default @observer class EditServiceForm extends Component {
430 </PremiumFeatureContainer> 423 </PremiumFeatureContainer>
431 )} 424 )}
432 </form> 425 </form>
426
427 {action === 'edit' && (
428 <>
429 <div className="settings__open-recipe-file-container">
430 <Button
431 buttonType="secondary"
432 label={intl.formatMessage(messages.openDarkmodeCss)}
433 className="settings__open-recipe-file-button"
434 onClick={() => openRecipeFile('darkmode.css')}
435 />
436 <Button
437 buttonType="secondary"
438 label={intl.formatMessage(messages.openUserCss)}
439 className="settings__open-recipe-file-button"
440 onClick={() => openRecipeFile('user.css')}
441 />
442 <Button
443 buttonType="secondary"
444 label={intl.formatMessage(messages.openUserJs)}
445 className="settings__open-recipe-file-button"
446 onClick={() => openRecipeFile('user.js')}
447 />
448 </div>
449 <p style={{ marginTop: 10 }}>
450 <span className="mdi mdi-information" />
451 {intl.formatMessage(messages.recipeFileInfo)}
452 </p>
453 </>
454 )}
433 </div> 455 </div>
434 <div className="settings__controls"> 456 <div className="settings__controls">
435 {/* Delete Button */} 457 {/* Delete Button */}
436 {action === 'edit' && deleteButton} 458 {action === 'edit' && deleteButton}
437 {action === 'edit' && openDarkmodeCssButton}
438 459
439 {/* Save Button */} 460 {/* Save Button */}
440 {isSaving || isValidatingCustomUrl ? ( 461 {isSaving || isValidatingCustomUrl ? (
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js
index 432a546d9..f41c7db8e 100644
--- a/src/components/settings/settings/EditSettingsForm.js
+++ b/src/components/settings/settings/EditSettingsForm.js
@@ -256,7 +256,7 @@ export default @observer class EditSettingsForm extends Component {
256 <Toggle field={form.$('minimizeToSystemTray')} /> 256 <Toggle field={form.$('minimizeToSystemTray')} />
257 )} 257 )}
258 <Toggle field={form.$('privateNotifications')} /> 258 <Toggle field={form.$('privateNotifications')} />
259 <Toggle field={form.$('showServiceNavigationBar')} /> 259 <Select field={form.$('navigationBarBehaviour')} />
260 260
261 <Hr /> 261 <Hr />
262 262
diff --git a/src/config.js b/src/config.js
index 9b77aa9a5..283c20f84 100644
--- a/src/config.js
+++ b/src/config.js
@@ -45,6 +45,12 @@ export const HIBERNATION_STRATEGIES = {
45 3600: 'Extemely Slow Hibernation (1hour)', 45 3600: 'Extemely Slow Hibernation (1hour)',
46}; 46};
47 47
48export const NAVIGATION_BAR_BEHAVIOURS = {
49 custom: 'Show navigation bar on custom websites only',
50 always: 'Show navigation bar on all services',
51 never: 'Never show navigation bar',
52};
53
48export const SIDEBAR_WIDTH = { 54export const SIDEBAR_WIDTH = {
49 35: 'Extemely slim sidebar', 55 35: 'Extemely slim sidebar',
50 45: 'Very slim sidebar', 56 45: 'Very slim sidebar',
@@ -107,6 +113,7 @@ export const DEFAULT_APP_SETTINGS = {
107 serviceRibbonWidth: 68, 113 serviceRibbonWidth: 68,
108 iconSize: iconSizeBias, 114 iconSize: iconSizeBias,
109 sentry: false, 115 sentry: false,
116 navigationBarBehaviour: 'custom',
110}; 117};
111 118
112export const DEFAULT_FEATURES_CONFIG = { 119export const DEFAULT_FEATURES_CONFIG = {
diff --git a/src/containers/settings/EditServiceScreen.js b/src/containers/settings/EditServiceScreen.js
index 99c40b086..a7d33a3ea 100644
--- a/src/containers/settings/EditServiceScreen.js
+++ b/src/containers/settings/EditServiceScreen.js
@@ -92,10 +92,6 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
92 intl: intlShape, 92 intl: intlShape,
93 }; 93 };
94 94
95 state = {
96 isOpeningDarkModeCss: false,
97 }
98
99 onSubmit(data) { 95 onSubmit(data) {
100 const { action } = this.props.router.params; 96 const { action } = this.props.router.params;
101 const { recipes, services } = this.props.stores; 97 const { recipes, services } = this.props.stores;
@@ -282,25 +278,16 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
282 } 278 }
283 } 279 }
284 280
285 openDarkmodeCss() { 281 openRecipeFile(file) {
286 const { openDarkmodeCss } = this.props.actions.service; 282 const { openRecipeFile } = this.props.actions.service;
287 const { action } = this.props.router.params; 283 const { action } = this.props.router.params;
288 284
289 if (action === 'edit') { 285 if (action === 'edit') {
290 this.setState({
291 isOpeningDarkModeCss: true,
292 });
293
294 const { activeSettings: service } = this.props.stores.services; 286 const { activeSettings: service } = this.props.stores.services;
295 openDarkmodeCss({ 287 openRecipeFile({
296 recipe: service.recipe.id, 288 recipe: service.recipe.id,
289 file,
297 }); 290 });
298
299 setTimeout(() => {
300 this.setState({
301 isOpeningDarkModeCss: false,
302 });
303 }, 2500);
304 } 291 }
305 } 292 }
306 293
@@ -355,8 +342,7 @@ export default @inject('stores', 'actions') @observer class EditServiceScreen ex
355 isDeleting={services.deleteServiceRequest.isExecuting} 342 isDeleting={services.deleteServiceRequest.isExecuting}
356 onSubmit={d => this.onSubmit(d)} 343 onSubmit={d => this.onSubmit(d)}
357 onDelete={() => this.deleteService()} 344 onDelete={() => this.deleteService()}
358 openDarkmodeCss={() => this.openDarkmodeCss()} 345 openRecipeFile={file => this.openRecipeFile(file)}
359 isOpeningDarkModeCss={this.state.isOpeningDarkModeCss}
360 isProxyFeatureEnabled={proxyFeature.isEnabled} 346 isProxyFeatureEnabled={proxyFeature.isEnabled}
361 isServiceProxyIncludedInCurrentPlan={proxyFeature.isIncludedInCurrentPlan} 347 isServiceProxyIncludedInCurrentPlan={proxyFeature.isIncludedInCurrentPlan}
362 isSpellcheckerIncludedInCurrentPlan={spellcheckerFeature.isIncludedInCurrentPlan} 348 isSpellcheckerIncludedInCurrentPlan={spellcheckerFeature.isIncludedInCurrentPlan}
@@ -384,7 +370,7 @@ EditServiceScreen.wrappedComponent.propTypes = {
384 createService: PropTypes.func.isRequired, 370 createService: PropTypes.func.isRequired,
385 updateService: PropTypes.func.isRequired, 371 updateService: PropTypes.func.isRequired,
386 deleteService: PropTypes.func.isRequired, 372 deleteService: PropTypes.func.isRequired,
387 openDarkmodeCss: PropTypes.func.isRequired, 373 openRecipeFile: PropTypes.func.isRequired,
388 }).isRequired, 374 }).isRequired,
389 // settings: PropTypes.shape({ 375 // settings: PropTypes.shape({
390 // update: PropTypes.func.isRequred, 376 // update: PropTypes.func.isRequred,
diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js
index ee5e3615c..6dd21f961 100644
--- a/src/containers/settings/EditSettingsScreen.js
+++ b/src/containers/settings/EditSettingsScreen.js
@@ -11,7 +11,7 @@ import TodosStore from '../../features/todos/store';
11import Form from '../../lib/Form'; 11import Form from '../../lib/Form';
12import { APP_LOCALES, SPELLCHECKER_LOCALES } from '../../i18n/languages'; 12import { APP_LOCALES, SPELLCHECKER_LOCALES } from '../../i18n/languages';
13import { 13import {
14 DEFAULT_APP_SETTINGS, HIBERNATION_STRATEGIES, SIDEBAR_WIDTH, ICON_SIZES, 14 DEFAULT_APP_SETTINGS, HIBERNATION_STRATEGIES, SIDEBAR_WIDTH, ICON_SIZES, NAVIGATION_BAR_BEHAVIOURS,
15} from '../../config'; 15} from '../../config';
16import { config as spellcheckerConfig } from '../../features/spellchecker'; 16import { config as spellcheckerConfig } from '../../features/spellchecker';
17 17
@@ -56,9 +56,9 @@ const messages = defineMessages({
56 id: 'settings.app.form.privateNotifications', 56 id: 'settings.app.form.privateNotifications',
57 defaultMessage: '!!!Don\'t show message content in notifications', 57 defaultMessage: '!!!Don\'t show message content in notifications',
58 }, 58 },
59 showServiceNavigationBar: { 59 navigationBarBehaviour: {
60 id: 'settings.app.form.showServiceNavigationBar', 60 id: 'settings.app.form.navigationBarBehaviour',
61 defaultMessage: '!!!Always show service navigation bar', 61 defaultMessage: '!!!Navigation bar behaviour',
62 }, 62 },
63 sentry: { 63 sentry: {
64 id: 'settings.app.form.sentry', 64 id: 'settings.app.form.sentry',
@@ -194,7 +194,7 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
194 startMinimized: settingsData.startMinimized, 194 startMinimized: settingsData.startMinimized,
195 minimizeToSystemTray: settingsData.minimizeToSystemTray, 195 minimizeToSystemTray: settingsData.minimizeToSystemTray,
196 privateNotifications: settingsData.privateNotifications, 196 privateNotifications: settingsData.privateNotifications,
197 showServiceNavigationBar: settingsData.showServiceNavigationBar, 197 navigationBarBehaviour: settingsData.navigationBarBehaviour,
198 sentry: settingsData.sentry, 198 sentry: settingsData.sentry,
199 hibernate: settingsData.hibernate, 199 hibernate: settingsData.hibernate,
200 hibernationStrategy: settingsData.hibernationStrategy, 200 hibernationStrategy: settingsData.hibernationStrategy,
@@ -260,6 +260,11 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
260 locales: APP_LOCALES, 260 locales: APP_LOCALES,
261 }); 261 });
262 262
263 const navigationBarBehaviours = getSelectOptions({
264 locales: NAVIGATION_BAR_BEHAVIOURS,
265 sort: false,
266 });
267
263 const hibernationStrategies = getSelectOptions({ 268 const hibernationStrategies = getSelectOptions({
264 locales: HIBERNATION_STRATEGIES, 269 locales: HIBERNATION_STRATEGIES,
265 sort: false, 270 sort: false,
@@ -317,10 +322,11 @@ export default @inject('stores', 'actions') @observer class EditSettingsScreen e
317 value: settings.all.app.privateNotifications, 322 value: settings.all.app.privateNotifications,
318 default: DEFAULT_APP_SETTINGS.privateNotifications, 323 default: DEFAULT_APP_SETTINGS.privateNotifications,
319 }, 324 },
320 showServiceNavigationBar: { 325 navigationBarBehaviour: {
321 label: intl.formatMessage(messages.showServiceNavigationBar), 326 label: intl.formatMessage(messages.navigationBarBehaviour),
322 value: settings.all.app.showServiceNavigationBar, 327 value: settings.all.app.navigationBarBehaviour,
323 default: DEFAULT_APP_SETTINGS.showServiceNavigationBar, 328 default: DEFAULT_APP_SETTINGS.navigationBarBehaviour,
329 options: navigationBarBehaviours,
324 }, 330 },
325 sentry: { 331 sentry: {
326 label: intl.formatMessage(messages.sentry), 332 label: intl.formatMessage(messages.sentry),
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json
index 44411cdad..211214d93 100644
--- a/src/i18n/locales/defaultMessages.json
+++ b/src/i18n/locales/defaultMessages.json
@@ -2143,263 +2143,302 @@
2143 } 2143 }
2144 }, 2144 },
2145 { 2145 {
2146 "defaultMessage": "!!!Available services", 2146 "defaultMessage": "!!!Open user.css",
2147 "end": { 2147 "end": {
2148 "column": 3, 2148 "column": 3,
2149 "line": 39 2149 "line": 39
2150 }, 2150 },
2151 "file": "src/components/settings/services/EditServiceForm.js", 2151 "file": "src/components/settings/services/EditServiceForm.js",
2152 "id": "settings.service.form.openUserCss",
2153 "start": {
2154 "column": 15,
2155 "line": 36
2156 }
2157 },
2158 {
2159 "defaultMessage": "!!!Open user.js",
2160 "end": {
2161 "column": 3,
2162 "line": 43
2163 },
2164 "file": "src/components/settings/services/EditServiceForm.js",
2165 "id": "settings.service.form.openUserJs",
2166 "start": {
2167 "column": 14,
2168 "line": 40
2169 }
2170 },
2171 {
2172 "defaultMessage": "!!!Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
2173 "end": {
2174 "column": 3,
2175 "line": 47
2176 },
2177 "file": "src/components/settings/services/EditServiceForm.js",
2178 "id": "settings.service.form.recipeFileInfo",
2179 "start": {
2180 "column": 18,
2181 "line": 44
2182 }
2183 },
2184 {
2185 "defaultMessage": "!!!Available services",
2186 "end": {
2187 "column": 3,
2188 "line": 51
2189 },
2190 "file": "src/components/settings/services/EditServiceForm.js",
2152 "id": "settings.service.form.availableServices", 2191 "id": "settings.service.form.availableServices",
2153 "start": { 2192 "start": {
2154 "column": 21, 2193 "column": 21,
2155 "line": 36 2194 "line": 48
2156 } 2195 }
2157 }, 2196 },
2158 { 2197 {
2159 "defaultMessage": "!!!Your services", 2198 "defaultMessage": "!!!Your services",
2160 "end": { 2199 "end": {
2161 "column": 3, 2200 "column": 3,
2162 "line": 43 2201 "line": 55
2163 }, 2202 },
2164 "file": "src/components/settings/services/EditServiceForm.js", 2203 "file": "src/components/settings/services/EditServiceForm.js",
2165 "id": "settings.service.form.yourServices", 2204 "id": "settings.service.form.yourServices",
2166 "start": { 2205 "start": {
2167 "column": 16, 2206 "column": 16,
2168 "line": 40 2207 "line": 52
2169 } 2208 }
2170 }, 2209 },
2171 { 2210 {
2172 "defaultMessage": "!!!Add {name}", 2211 "defaultMessage": "!!!Add {name}",
2173 "end": { 2212 "end": {
2174 "column": 3, 2213 "column": 3,
2175 "line": 47 2214 "line": 59
2176 }, 2215 },
2177 "file": "src/components/settings/services/EditServiceForm.js", 2216 "file": "src/components/settings/services/EditServiceForm.js",
2178 "id": "settings.service.form.addServiceHeadline", 2217 "id": "settings.service.form.addServiceHeadline",
2179 "start": { 2218 "start": {
2180 "column": 22, 2219 "column": 22,
2181 "line": 44 2220 "line": 56
2182 } 2221 }
2183 }, 2222 },
2184 { 2223 {
2185 "defaultMessage": "!!!Edit {name}", 2224 "defaultMessage": "!!!Edit {name}",
2186 "end": { 2225 "end": {
2187 "column": 3, 2226 "column": 3,
2188 "line": 51 2227 "line": 63
2189 }, 2228 },
2190 "file": "src/components/settings/services/EditServiceForm.js", 2229 "file": "src/components/settings/services/EditServiceForm.js",
2191 "id": "settings.service.form.editServiceHeadline", 2230 "id": "settings.service.form.editServiceHeadline",
2192 "start": { 2231 "start": {
2193 "column": 23, 2232 "column": 23,
2194 "line": 48 2233 "line": 60
2195 } 2234 }
2196 }, 2235 },
2197 { 2236 {
2198 "defaultMessage": "!!!Hosted", 2237 "defaultMessage": "!!!Hosted",
2199 "end": { 2238 "end": {
2200 "column": 3, 2239 "column": 3,
2201 "line": 55 2240 "line": 67
2202 }, 2241 },
2203 "file": "src/components/settings/services/EditServiceForm.js", 2242 "file": "src/components/settings/services/EditServiceForm.js",
2204 "id": "settings.service.form.tabHosted", 2243 "id": "settings.service.form.tabHosted",
2205 "start": { 2244 "start": {
2206 "column": 13, 2245 "column": 13,
2207 "line": 52 2246 "line": 64
2208 } 2247 }
2209 }, 2248 },
2210 { 2249 {
2211 "defaultMessage": "!!!Self hosted ⭐️", 2250 "defaultMessage": "!!!Self hosted ⭐️",
2212 "end": { 2251 "end": {
2213 "column": 3, 2252 "column": 3,
2214 "line": 59 2253 "line": 71
2215 }, 2254 },
2216 "file": "src/components/settings/services/EditServiceForm.js", 2255 "file": "src/components/settings/services/EditServiceForm.js",
2217 "id": "settings.service.form.tabOnPremise", 2256 "id": "settings.service.form.tabOnPremise",
2218 "start": { 2257 "start": {
2219 "column": 16, 2258 "column": 16,
2220 "line": 56 2259 "line": 68
2221 } 2260 }
2222 }, 2261 },
2223 { 2262 {
2224 "defaultMessage": "!!!Use the hosted {name} service.", 2263 "defaultMessage": "!!!Use the hosted {name} service.",
2225 "end": { 2264 "end": {
2226 "column": 3, 2265 "column": 3,
2227 "line": 63 2266 "line": 75
2228 }, 2267 },
2229 "file": "src/components/settings/services/EditServiceForm.js", 2268 "file": "src/components/settings/services/EditServiceForm.js",
2230 "id": "settings.service.form.useHostedService", 2269 "id": "settings.service.form.useHostedService",
2231 "start": { 2270 "start": {
2232 "column": 20, 2271 "column": 20,
2233 "line": 60 2272 "line": 72
2234 } 2273 }
2235 }, 2274 },
2236 { 2275 {
2237 "defaultMessage": "!!!Could not validate custom {name} server.", 2276 "defaultMessage": "!!!Could not validate custom {name} server.",
2238 "end": { 2277 "end": {
2239 "column": 3, 2278 "column": 3,
2240 "line": 67 2279 "line": 79
2241 }, 2280 },
2242 "file": "src/components/settings/services/EditServiceForm.js", 2281 "file": "src/components/settings/services/EditServiceForm.js",
2243 "id": "settings.service.form.customUrlValidationError", 2282 "id": "settings.service.form.customUrlValidationError",
2244 "start": { 2283 "start": {
2245 "column": 28, 2284 "column": 28,
2246 "line": 64 2285 "line": 76
2247 } 2286 }
2248 }, 2287 },
2249 { 2288 {
2250 "defaultMessage": "!!!To add self hosted services, you need a Ferdi Premium Supporter Account.", 2289 "defaultMessage": "!!!To add self hosted services, you need a Ferdi Premium Supporter Account.",
2251 "end": { 2290 "end": {
2252 "column": 3, 2291 "column": 3,
2253 "line": 71 2292 "line": 83
2254 }, 2293 },
2255 "file": "src/components/settings/services/EditServiceForm.js", 2294 "file": "src/components/settings/services/EditServiceForm.js",
2256 "id": "settings.service.form.customUrlPremiumInfo", 2295 "id": "settings.service.form.customUrlPremiumInfo",
2257 "start": { 2296 "start": {
2258 "column": 24, 2297 "column": 24,
2259 "line": 68 2298 "line": 80
2260 } 2299 }
2261 }, 2300 },
2262 { 2301 {
2263 "defaultMessage": "!!!Upgrade your account", 2302 "defaultMessage": "!!!Upgrade your account",
2264 "end": { 2303 "end": {
2265 "column": 3, 2304 "column": 3,
2266 "line": 75 2305 "line": 87
2267 }, 2306 },
2268 "file": "src/components/settings/services/EditServiceForm.js", 2307 "file": "src/components/settings/services/EditServiceForm.js",
2269 "id": "settings.service.form.customUrlUpgradeAccount", 2308 "id": "settings.service.form.customUrlUpgradeAccount",
2270 "start": { 2309 "start": {
2271 "column": 27, 2310 "column": 27,
2272 "line": 72 2311 "line": 84
2273 } 2312 }
2274 }, 2313 },
2275 { 2314 {
2276 "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", 2315 "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...",
2277 "end": { 2316 "end": {
2278 "column": 3, 2317 "column": 3,
2279 "line": 79 2318 "line": 91
2280 }, 2319 },
2281 "file": "src/components/settings/services/EditServiceForm.js", 2320 "file": "src/components/settings/services/EditServiceForm.js",
2282 "id": "settings.service.form.indirectMessageInfo", 2321 "id": "settings.service.form.indirectMessageInfo",
2283 "start": { 2322 "start": {
2284 "column": 23, 2323 "column": 23,
2285 "line": 76 2324 "line": 88
2286 } 2325 }
2287 }, 2326 },
2288 { 2327 {
2289 "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted", 2328 "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted",
2290 "end": { 2329 "end": {
2291 "column": 3, 2330 "column": 3,
2292 "line": 83 2331 "line": 95
2293 }, 2332 },
2294 "file": "src/components/settings/services/EditServiceForm.js", 2333 "file": "src/components/settings/services/EditServiceForm.js",
2295 "id": "settings.service.form.isMutedInfo", 2334 "id": "settings.service.form.isMutedInfo",
2296 "start": { 2335 "start": {
2297 "column": 15, 2336 "column": 15,
2298 "line": 80 2337 "line": 92
2299 } 2338 }
2300 }, 2339 },
2301 { 2340 {
2302 "defaultMessage": "!!!Notifications", 2341 "defaultMessage": "!!!Notifications",
2303 "end": { 2342 "end": {
2304 "column": 3, 2343 "column": 3,
2305 "line": 87 2344 "line": 99
2306 }, 2345 },
2307 "file": "src/components/settings/services/EditServiceForm.js", 2346 "file": "src/components/settings/services/EditServiceForm.js",
2308 "id": "settings.service.form.headlineNotifications", 2347 "id": "settings.service.form.headlineNotifications",
2309 "start": { 2348 "start": {
2310 "column": 25, 2349 "column": 25,
2311 "line": 84 2350 "line": 96
2312 } 2351 }
2313 }, 2352 },
2314 { 2353 {
2315 "defaultMessage": "!!!Unread message badges", 2354 "defaultMessage": "!!!Unread message badges",
2316 "end": { 2355 "end": {
2317 "column": 3, 2356 "column": 3,
2318 "line": 91 2357 "line": 103
2319 }, 2358 },
2320 "file": "src/components/settings/services/EditServiceForm.js", 2359 "file": "src/components/settings/services/EditServiceForm.js",
2321 "id": "settings.service.form.headlineBadges", 2360 "id": "settings.service.form.headlineBadges",
2322 "start": { 2361 "start": {
2323 "column": 18, 2362 "column": 18,
2324 "line": 88 2363 "line": 100
2325 } 2364 }
2326 }, 2365 },
2327 { 2366 {
2328 "defaultMessage": "!!!General", 2367 "defaultMessage": "!!!General",
2329 "end": { 2368 "end": {
2330 "column": 3, 2369 "column": 3,
2331 "line": 95 2370 "line": 107
2332 }, 2371 },
2333 "file": "src/components/settings/services/EditServiceForm.js", 2372 "file": "src/components/settings/services/EditServiceForm.js",
2334 "id": "settings.service.form.headlineGeneral", 2373 "id": "settings.service.form.headlineGeneral",
2335 "start": { 2374 "start": {
2336 "column": 19, 2375 "column": 19,
2337 "line": 92 2376 "line": 104
2338 } 2377 }
2339 }, 2378 },
2340 { 2379 {
2341 "defaultMessage": "!!!Delete", 2380 "defaultMessage": "!!!Delete",
2342 "end": { 2381 "end": {
2343 "column": 3, 2382 "column": 3,
2344 "line": 99 2383 "line": 111
2345 }, 2384 },
2346 "file": "src/components/settings/services/EditServiceForm.js", 2385 "file": "src/components/settings/services/EditServiceForm.js",
2347 "id": "settings.service.form.iconDelete", 2386 "id": "settings.service.form.iconDelete",
2348 "start": { 2387 "start": {
2349 "column": 14, 2388 "column": 14,
2350 "line": 96 2389 "line": 108
2351 } 2390 }
2352 }, 2391 },
2353 { 2392 {
2354 "defaultMessage": "!!!Drop your image, or click here", 2393 "defaultMessage": "!!!Drop your image, or click here",
2355 "end": { 2394 "end": {
2356 "column": 3, 2395 "column": 3,
2357 "line": 103 2396 "line": 115
2358 }, 2397 },
2359 "file": "src/components/settings/services/EditServiceForm.js", 2398 "file": "src/components/settings/services/EditServiceForm.js",
2360 "id": "settings.service.form.iconUpload", 2399 "id": "settings.service.form.iconUpload",
2361 "start": { 2400 "start": {
2362 "column": 14, 2401 "column": 14,
2363 "line": 100 2402 "line": 112
2364 } 2403 }
2365 }, 2404 },
2366 { 2405 {
2367 "defaultMessage": "!!!HTTP/HTTPS Proxy Settings", 2406 "defaultMessage": "!!!HTTP/HTTPS Proxy Settings",
2368 "end": { 2407 "end": {
2369 "column": 3, 2408 "column": 3,
2370 "line": 107 2409 "line": 119
2371 }, 2410 },
2372 "file": "src/components/settings/services/EditServiceForm.js", 2411 "file": "src/components/settings/services/EditServiceForm.js",
2373 "id": "settings.service.form.proxy.headline", 2412 "id": "settings.service.form.proxy.headline",
2374 "start": { 2413 "start": {
2375 "column": 17, 2414 "column": 17,
2376 "line": 104 2415 "line": 116
2377 } 2416 }
2378 }, 2417 },
2379 { 2418 {
2380 "defaultMessage": "!!!Please restart Ferdi after changing proxy Settings.", 2419 "defaultMessage": "!!!Please restart Ferdi after changing proxy Settings.",
2381 "end": { 2420 "end": {
2382 "column": 3, 2421 "column": 3,
2383 "line": 111 2422 "line": 123
2384 }, 2423 },
2385 "file": "src/components/settings/services/EditServiceForm.js", 2424 "file": "src/components/settings/services/EditServiceForm.js",
2386 "id": "settings.service.form.proxy.restartInfo", 2425 "id": "settings.service.form.proxy.restartInfo",
2387 "start": { 2426 "start": {
2388 "column": 20, 2427 "column": 20,
2389 "line": 108 2428 "line": 120
2390 } 2429 }
2391 }, 2430 },
2392 { 2431 {
2393 "defaultMessage": "!!!Proxy settings will not be synchronized with the Ferdi servers.", 2432 "defaultMessage": "!!!Proxy settings will not be synchronized with the Ferdi servers.",
2394 "end": { 2433 "end": {
2395 "column": 3, 2434 "column": 3,
2396 "line": 115 2435 "line": 127
2397 }, 2436 },
2398 "file": "src/components/settings/services/EditServiceForm.js", 2437 "file": "src/components/settings/services/EditServiceForm.js",
2399 "id": "settings.service.form.proxy.info", 2438 "id": "settings.service.form.proxy.info",
2400 "start": { 2439 "start": {
2401 "column": 13, 2440 "column": 13,
2402 "line": 112 2441 "line": 124
2403 } 2442 }
2404 } 2443 }
2405 ], 2444 ],
@@ -4175,15 +4214,15 @@
4175 } 4214 }
4176 }, 4215 },
4177 { 4216 {
4178 "defaultMessage": "!!!Always show service navigation bar", 4217 "defaultMessage": "!!!Navigation bar behaviour",
4179 "end": { 4218 "end": {
4180 "column": 3, 4219 "column": 3,
4181 "line": 62 4220 "line": 62
4182 }, 4221 },
4183 "file": "src/containers/settings/EditSettingsScreen.js", 4222 "file": "src/containers/settings/EditSettingsScreen.js",
4184 "id": "settings.app.form.showServiceNavigationBar", 4223 "id": "settings.app.form.navigationBarBehaviour",
4185 "start": { 4224 "start": {
4186 "column": 28, 4225 "column": 26,
4187 "line": 59 4226 "line": 59
4188 } 4227 }
4189 }, 4228 },
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 97be15fed..36494724b 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -284,6 +284,7 @@
284 "settings.app.form.language": "Language", 284 "settings.app.form.language": "Language",
285 "settings.app.form.lockPassword": "Password", 285 "settings.app.form.lockPassword": "Password",
286 "settings.app.form.minimizeToSystemTray": "Minimize Ferdi to system tray", 286 "settings.app.form.minimizeToSystemTray": "Minimize Ferdi to system tray",
287 "settings.app.form.navigationBarBehaviour": "Navigation bar behaviour",
287 "settings.app.form.noUpdates": "Disable updates", 288 "settings.app.form.noUpdates": "Disable updates",
288 "settings.app.form.privateNotifications": "Don't show message content in notifications", 289 "settings.app.form.privateNotifications": "Don't show message content in notifications",
289 "settings.app.form.runInBackground": "Keep Ferdi in background when closing the window", 290 "settings.app.form.runInBackground": "Keep Ferdi in background when closing the window",
@@ -295,7 +296,6 @@
295 "settings.app.form.serviceRibbonWidth": "Sidebar width", 296 "settings.app.form.serviceRibbonWidth": "Sidebar width",
296 "settings.app.form.showDisabledServices": "Display disabled services tabs", 297 "settings.app.form.showDisabledServices": "Display disabled services tabs",
297 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled", 298 "settings.app.form.showMessagesBadgesWhenMuted": "Show unread message badge when notifications are disabled",
298 "settings.app.form.showServiceNavigationBar": "Always show service navigation bar",
299 "settings.app.form.startMinimized": "Start minimized in tray", 299 "settings.app.form.startMinimized": "Start minimized in tray",
300 "settings.app.form.todoServer": "Todo Server", 300 "settings.app.form.todoServer": "Todo Server",
301 "settings.app.form.universalDarkMode": "Enable universal Dark Mode", 301 "settings.app.form.universalDarkMode": "Enable universal Dark Mode",
@@ -374,6 +374,8 @@
374 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted", 374 "settings.service.form.isMutedInfo": "When disabled, all notification sounds and audio playback are muted",
375 "settings.service.form.name": "Name", 375 "settings.service.form.name": "Name",
376 "settings.service.form.openDarkmodeCss": "Open darkmode.css", 376 "settings.service.form.openDarkmodeCss": "Open darkmode.css",
377 "settings.service.form.openUserCss": "Open user.css",
378 "settings.service.form.openUserJs": "Open user.js",
377 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings", 379 "settings.service.form.proxy.headline": "HTTP/HTTPS Proxy Settings",
378 "settings.service.form.proxy.host": "Proxy Host/IP", 380 "settings.service.form.proxy.host": "Proxy Host/IP",
379 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.", 381 "settings.service.form.proxy.info": "Proxy settings will not synced with the Ferdi servers.",
@@ -382,6 +384,7 @@
382 "settings.service.form.proxy.port": "Port", 384 "settings.service.form.proxy.port": "Port",
383 "settings.service.form.proxy.restartInfo": "Please restart Ferdi after changing proxy Settings.", 385 "settings.service.form.proxy.restartInfo": "Please restart Ferdi after changing proxy Settings.",
384 "settings.service.form.proxy.user": "User (optional)", 386 "settings.service.form.proxy.user": "User (optional)",
387 "settings.service.form.recipeFileInfo": "Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
385 "settings.service.form.saveButton": "Save service", 388 "settings.service.form.saveButton": "Save service",
386 "settings.service.form.tabHosted": "Hosted", 389 "settings.service.form.tabHosted": "Hosted",
387 "settings.service.form.tabOnPremise": "Self hosted ⭐️", 390 "settings.service.form.tabOnPremise": "Self hosted ⭐️",
diff --git a/src/i18n/messages/src/components/settings/services/EditServiceForm.json b/src/i18n/messages/src/components/settings/services/EditServiceForm.json
index f4692ed29..df64c8a5f 100644
--- a/src/i18n/messages/src/components/settings/services/EditServiceForm.json
+++ b/src/i18n/messages/src/components/settings/services/EditServiceForm.json
@@ -39,15 +39,54 @@
39 } 39 }
40 }, 40 },
41 { 41 {
42 "id": "settings.service.form.openUserCss",
43 "defaultMessage": "!!!Open user.css",
44 "file": "src/components/settings/services/EditServiceForm.js",
45 "start": {
46 "line": 36,
47 "column": 15
48 },
49 "end": {
50 "line": 39,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.service.form.openUserJs",
56 "defaultMessage": "!!!Open user.js",
57 "file": "src/components/settings/services/EditServiceForm.js",
58 "start": {
59 "line": 40,
60 "column": 14
61 },
62 "end": {
63 "line": 43,
64 "column": 3
65 }
66 },
67 {
68 "id": "settings.service.form.recipeFileInfo",
69 "defaultMessage": "!!!Your user files will be inserted into the webpage so you can customize services in any way you like. User files are only stored locally and are not transferred to other computers using the same account.",
70 "file": "src/components/settings/services/EditServiceForm.js",
71 "start": {
72 "line": 44,
73 "column": 18
74 },
75 "end": {
76 "line": 47,
77 "column": 3
78 }
79 },
80 {
42 "id": "settings.service.form.availableServices", 81 "id": "settings.service.form.availableServices",
43 "defaultMessage": "!!!Available services", 82 "defaultMessage": "!!!Available services",
44 "file": "src/components/settings/services/EditServiceForm.js", 83 "file": "src/components/settings/services/EditServiceForm.js",
45 "start": { 84 "start": {
46 "line": 36, 85 "line": 48,
47 "column": 21 86 "column": 21
48 }, 87 },
49 "end": { 88 "end": {
50 "line": 39, 89 "line": 51,
51 "column": 3 90 "column": 3
52 } 91 }
53 }, 92 },
@@ -56,11 +95,11 @@
56 "defaultMessage": "!!!Your services", 95 "defaultMessage": "!!!Your services",
57 "file": "src/components/settings/services/EditServiceForm.js", 96 "file": "src/components/settings/services/EditServiceForm.js",
58 "start": { 97 "start": {
59 "line": 40, 98 "line": 52,
60 "column": 16 99 "column": 16
61 }, 100 },
62 "end": { 101 "end": {
63 "line": 43, 102 "line": 55,
64 "column": 3 103 "column": 3
65 } 104 }
66 }, 105 },
@@ -69,11 +108,11 @@
69 "defaultMessage": "!!!Add {name}", 108 "defaultMessage": "!!!Add {name}",
70 "file": "src/components/settings/services/EditServiceForm.js", 109 "file": "src/components/settings/services/EditServiceForm.js",
71 "start": { 110 "start": {
72 "line": 44, 111 "line": 56,
73 "column": 22 112 "column": 22
74 }, 113 },
75 "end": { 114 "end": {
76 "line": 47, 115 "line": 59,
77 "column": 3 116 "column": 3
78 } 117 }
79 }, 118 },
@@ -82,11 +121,11 @@
82 "defaultMessage": "!!!Edit {name}", 121 "defaultMessage": "!!!Edit {name}",
83 "file": "src/components/settings/services/EditServiceForm.js", 122 "file": "src/components/settings/services/EditServiceForm.js",
84 "start": { 123 "start": {
85 "line": 48, 124 "line": 60,
86 "column": 23 125 "column": 23
87 }, 126 },
88 "end": { 127 "end": {
89 "line": 51, 128 "line": 63,
90 "column": 3 129 "column": 3
91 } 130 }
92 }, 131 },
@@ -95,11 +134,11 @@
95 "defaultMessage": "!!!Hosted", 134 "defaultMessage": "!!!Hosted",
96 "file": "src/components/settings/services/EditServiceForm.js", 135 "file": "src/components/settings/services/EditServiceForm.js",
97 "start": { 136 "start": {
98 "line": 52, 137 "line": 64,
99 "column": 13 138 "column": 13
100 }, 139 },
101 "end": { 140 "end": {
102 "line": 55, 141 "line": 67,
103 "column": 3 142 "column": 3
104 } 143 }
105 }, 144 },
@@ -108,11 +147,11 @@
108 "defaultMessage": "!!!Self hosted ⭐️", 147 "defaultMessage": "!!!Self hosted ⭐️",
109 "file": "src/components/settings/services/EditServiceForm.js", 148 "file": "src/components/settings/services/EditServiceForm.js",
110 "start": { 149 "start": {
111 "line": 56, 150 "line": 68,
112 "column": 16 151 "column": 16
113 }, 152 },
114 "end": { 153 "end": {
115 "line": 59, 154 "line": 71,
116 "column": 3 155 "column": 3
117 } 156 }
118 }, 157 },
@@ -121,11 +160,11 @@
121 "defaultMessage": "!!!Use the hosted {name} service.", 160 "defaultMessage": "!!!Use the hosted {name} service.",
122 "file": "src/components/settings/services/EditServiceForm.js", 161 "file": "src/components/settings/services/EditServiceForm.js",
123 "start": { 162 "start": {
124 "line": 60, 163 "line": 72,
125 "column": 20 164 "column": 20
126 }, 165 },
127 "end": { 166 "end": {
128 "line": 63, 167 "line": 75,
129 "column": 3 168 "column": 3
130 } 169 }
131 }, 170 },
@@ -134,11 +173,11 @@
134 "defaultMessage": "!!!Could not validate custom {name} server.", 173 "defaultMessage": "!!!Could not validate custom {name} server.",
135 "file": "src/components/settings/services/EditServiceForm.js", 174 "file": "src/components/settings/services/EditServiceForm.js",
136 "start": { 175 "start": {
137 "line": 64, 176 "line": 76,
138 "column": 28 177 "column": 28
139 }, 178 },
140 "end": { 179 "end": {
141 "line": 67, 180 "line": 79,
142 "column": 3 181 "column": 3
143 } 182 }
144 }, 183 },
@@ -147,11 +186,11 @@
147 "defaultMessage": "!!!To add self hosted services, you need a Ferdi Premium Supporter Account.", 186 "defaultMessage": "!!!To add self hosted services, you need a Ferdi Premium Supporter Account.",
148 "file": "src/components/settings/services/EditServiceForm.js", 187 "file": "src/components/settings/services/EditServiceForm.js",
149 "start": { 188 "start": {
150 "line": 68, 189 "line": 80,
151 "column": 24 190 "column": 24
152 }, 191 },
153 "end": { 192 "end": {
154 "line": 71, 193 "line": 83,
155 "column": 3 194 "column": 3
156 } 195 }
157 }, 196 },
@@ -160,11 +199,11 @@
160 "defaultMessage": "!!!Upgrade your account", 199 "defaultMessage": "!!!Upgrade your account",
161 "file": "src/components/settings/services/EditServiceForm.js", 200 "file": "src/components/settings/services/EditServiceForm.js",
162 "start": { 201 "start": {
163 "line": 72, 202 "line": 84,
164 "column": 27 203 "column": 27
165 }, 204 },
166 "end": { 205 "end": {
167 "line": 75, 206 "line": 87,
168 "column": 3 207 "column": 3
169 } 208 }
170 }, 209 },
@@ -173,11 +212,11 @@
173 "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", 212 "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...",
174 "file": "src/components/settings/services/EditServiceForm.js", 213 "file": "src/components/settings/services/EditServiceForm.js",
175 "start": { 214 "start": {
176 "line": 76, 215 "line": 88,
177 "column": 23 216 "column": 23
178 }, 217 },
179 "end": { 218 "end": {
180 "line": 79, 219 "line": 91,
181 "column": 3 220 "column": 3
182 } 221 }
183 }, 222 },
@@ -186,11 +225,11 @@
186 "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted", 225 "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted",
187 "file": "src/components/settings/services/EditServiceForm.js", 226 "file": "src/components/settings/services/EditServiceForm.js",
188 "start": { 227 "start": {
189 "line": 80, 228 "line": 92,
190 "column": 15 229 "column": 15
191 }, 230 },
192 "end": { 231 "end": {
193 "line": 83, 232 "line": 95,
194 "column": 3 233 "column": 3
195 } 234 }
196 }, 235 },
@@ -199,11 +238,11 @@
199 "defaultMessage": "!!!Notifications", 238 "defaultMessage": "!!!Notifications",
200 "file": "src/components/settings/services/EditServiceForm.js", 239 "file": "src/components/settings/services/EditServiceForm.js",
201 "start": { 240 "start": {
202 "line": 84, 241 "line": 96,
203 "column": 25 242 "column": 25
204 }, 243 },
205 "end": { 244 "end": {
206 "line": 87, 245 "line": 99,
207 "column": 3 246 "column": 3
208 } 247 }
209 }, 248 },
@@ -212,11 +251,11 @@
212 "defaultMessage": "!!!Unread message badges", 251 "defaultMessage": "!!!Unread message badges",
213 "file": "src/components/settings/services/EditServiceForm.js", 252 "file": "src/components/settings/services/EditServiceForm.js",
214 "start": { 253 "start": {
215 "line": 88, 254 "line": 100,
216 "column": 18 255 "column": 18
217 }, 256 },
218 "end": { 257 "end": {
219 "line": 91, 258 "line": 103,
220 "column": 3 259 "column": 3
221 } 260 }
222 }, 261 },
@@ -225,11 +264,11 @@
225 "defaultMessage": "!!!General", 264 "defaultMessage": "!!!General",
226 "file": "src/components/settings/services/EditServiceForm.js", 265 "file": "src/components/settings/services/EditServiceForm.js",
227 "start": { 266 "start": {
228 "line": 92, 267 "line": 104,
229 "column": 19 268 "column": 19
230 }, 269 },
231 "end": { 270 "end": {
232 "line": 95, 271 "line": 107,
233 "column": 3 272 "column": 3
234 } 273 }
235 }, 274 },
@@ -238,11 +277,11 @@
238 "defaultMessage": "!!!Delete", 277 "defaultMessage": "!!!Delete",
239 "file": "src/components/settings/services/EditServiceForm.js", 278 "file": "src/components/settings/services/EditServiceForm.js",
240 "start": { 279 "start": {
241 "line": 96, 280 "line": 108,
242 "column": 14 281 "column": 14
243 }, 282 },
244 "end": { 283 "end": {
245 "line": 99, 284 "line": 111,
246 "column": 3 285 "column": 3
247 } 286 }
248 }, 287 },
@@ -251,11 +290,11 @@
251 "defaultMessage": "!!!Drop your image, or click here", 290 "defaultMessage": "!!!Drop your image, or click here",
252 "file": "src/components/settings/services/EditServiceForm.js", 291 "file": "src/components/settings/services/EditServiceForm.js",
253 "start": { 292 "start": {
254 "line": 100, 293 "line": 112,
255 "column": 14 294 "column": 14
256 }, 295 },
257 "end": { 296 "end": {
258 "line": 103, 297 "line": 115,
259 "column": 3 298 "column": 3
260 } 299 }
261 }, 300 },
@@ -264,11 +303,11 @@
264 "defaultMessage": "!!!HTTP/HTTPS Proxy Settings", 303 "defaultMessage": "!!!HTTP/HTTPS Proxy Settings",
265 "file": "src/components/settings/services/EditServiceForm.js", 304 "file": "src/components/settings/services/EditServiceForm.js",
266 "start": { 305 "start": {
267 "line": 104, 306 "line": 116,
268 "column": 17 307 "column": 17
269 }, 308 },
270 "end": { 309 "end": {
271 "line": 107, 310 "line": 119,
272 "column": 3 311 "column": 3
273 } 312 }
274 }, 313 },
@@ -277,11 +316,11 @@
277 "defaultMessage": "!!!Please restart Ferdi after changing proxy Settings.", 316 "defaultMessage": "!!!Please restart Ferdi after changing proxy Settings.",
278 "file": "src/components/settings/services/EditServiceForm.js", 317 "file": "src/components/settings/services/EditServiceForm.js",
279 "start": { 318 "start": {
280 "line": 108, 319 "line": 120,
281 "column": 20 320 "column": 20
282 }, 321 },
283 "end": { 322 "end": {
284 "line": 111, 323 "line": 123,
285 "column": 3 324 "column": 3
286 } 325 }
287 }, 326 },
@@ -290,11 +329,11 @@
290 "defaultMessage": "!!!Proxy settings will not be synchronized with the Ferdi servers.", 329 "defaultMessage": "!!!Proxy settings will not be synchronized with the Ferdi servers.",
291 "file": "src/components/settings/services/EditServiceForm.js", 330 "file": "src/components/settings/services/EditServiceForm.js",
292 "start": { 331 "start": {
293 "line": 112, 332 "line": 124,
294 "column": 13 333 "column": 13
295 }, 334 },
296 "end": { 335 "end": {
297 "line": 115, 336 "line": 127,
298 "column": 3 337 "column": 3
299 } 338 }
300 } 339 }
diff --git a/src/i18n/messages/src/containers/settings/EditSettingsScreen.json b/src/i18n/messages/src/containers/settings/EditSettingsScreen.json
index 98abb0f2b..fdf49bbb6 100644
--- a/src/i18n/messages/src/containers/settings/EditSettingsScreen.json
+++ b/src/i18n/messages/src/containers/settings/EditSettingsScreen.json
@@ -91,12 +91,12 @@
91 } 91 }
92 }, 92 },
93 { 93 {
94 "id": "settings.app.form.showServiceNavigationBar", 94 "id": "settings.app.form.navigationBarBehaviour",
95 "defaultMessage": "!!!Always show service navigation bar", 95 "defaultMessage": "!!!Navigation bar behaviour",
96 "file": "src/containers/settings/EditSettingsScreen.js", 96 "file": "src/containers/settings/EditSettingsScreen.js",
97 "start": { 97 "start": {
98 "line": 59, 98 "line": 59,
99 "column": 28 99 "column": 26
100 }, 100 },
101 "end": { 101 "end": {
102 "line": 62, 102 "line": 62,
diff --git a/src/lib/Menu.js b/src/lib/Menu.js
index f2669a106..91e7c981a 100644
--- a/src/lib/Menu.js
+++ b/src/lib/Menu.js
@@ -1,15 +1,15 @@
1import { remote, shell, clipboard } from 'electron'; 1import { clipboard, remote, shell } from 'electron';
2import { observable, autorun } from 'mobx'; 2import { autorun, observable } from 'mobx';
3import { defineMessages } from 'react-intl'; 3import { defineMessages } from 'react-intl';
4 4import { cmdKey, ctrlKey, isMac } from '../environment';
5import { isMac, ctrlKey, cmdKey } from '../environment';
6import { workspaceStore } from '../features/workspaces/index';
7import { workspaceActions } from '../features/workspaces/actions';
8import { announcementActions } from '../features/announcements/actions';
9import { announcementsStore } from '../features/announcements'; 5import { announcementsStore } from '../features/announcements';
6import { announcementActions } from '../features/announcements/actions';
10import { todosStore } from '../features/todos'; 7import { todosStore } from '../features/todos';
11import { todoActions } from '../features/todos/actions'; 8import { todoActions } from '../features/todos/actions';
12import { CUSTOM_WEBSITE_ID } from '../features/webControls/constants'; 9import { CUSTOM_WEBSITE_ID } from '../features/webControls/constants';
10import { workspaceActions } from '../features/workspaces/actions';
11import { workspaceStore } from '../features/workspaces/index';
12
13 13
14const { app, Menu, dialog } = remote; 14const { app, Menu, dialog } = remote;
15 15
@@ -300,7 +300,7 @@ function termsBase() {
300 return window.ferdi.stores.settings.all.app.server !== 'https://api.franzinfra.com' ? window.ferdi.stores.settings.all.app.server : 'https://meetfranz.com'; 300 return window.ferdi.stores.settings.all.app.server !== 'https://api.franzinfra.com' ? window.ferdi.stores.settings.all.app.server : 'https://meetfranz.com';
301} 301}
302 302
303const _templateFactory = intl => [ 303const _templateFactory = (intl, locked) => [
304 { 304 {
305 label: intl.formatMessage(menuItems.edit), 305 label: intl.formatMessage(menuItems.edit),
306 submenu: [ 306 submenu: [
@@ -351,6 +351,7 @@ const _templateFactory = intl => [
351 }, 351 },
352 { 352 {
353 label: intl.formatMessage(menuItems.view), 353 label: intl.formatMessage(menuItems.view),
354 visible: !locked,
354 submenu: [ 355 submenu: [
355 { 356 {
356 type: 'separator', 357 type: 'separator',
@@ -426,17 +427,18 @@ const _templateFactory = intl => [
426 }, 427 },
427 { 428 {
428 label: intl.formatMessage(menuItems.services), 429 label: intl.formatMessage(menuItems.services),
430 visible: !locked,
429 submenu: [], 431 submenu: [],
430 }, 432 },
431 { 433 {
432 label: intl.formatMessage(menuItems.workspaces), 434 label: intl.formatMessage(menuItems.workspaces),
433 submenu: [], 435 submenu: [],
434 visible: workspaceStore.isFeatureEnabled, 436 visible: !locked && workspaceStore.isFeatureEnabled,
435 }, 437 },
436 { 438 {
437 label: intl.formatMessage(menuItems.todos), 439 label: intl.formatMessage(menuItems.todos),
438 submenu: [], 440 submenu: [],
439 visible: todosStore.isFeatureEnabled, 441 visible: !locked && todosStore.isFeatureEnabled,
440 }, 442 },
441 { 443 {
442 label: intl.formatMessage(menuItems.window), 444 label: intl.formatMessage(menuItems.window),
@@ -465,7 +467,7 @@ const _templateFactory = intl => [
465 click: () => { 467 click: () => {
466 announcementActions.show(); 468 announcementActions.show();
467 }, 469 },
468 visible: window.ferdi.stores.user.isLoggedIn && announcementsStore.areNewsAvailable, 470 visible: !locked && window.ferdi.stores.user.isLoggedIn && announcementsStore.areNewsAvailable,
469 }, 471 },
470 { 472 {
471 type: 'separator', 473 type: 'separator',
@@ -489,7 +491,7 @@ const _templateFactory = intl => [
489 }, 491 },
490]; 492];
491 493
492const _titleBarTemplateFactory = intl => [ 494const _titleBarTemplateFactory = (intl, locked) => [
493 { 495 {
494 label: intl.formatMessage(menuItems.edit), 496 label: intl.formatMessage(menuItems.edit),
495 accelerator: 'Alt+E', 497 accelerator: 'Alt+E',
@@ -557,6 +559,7 @@ const _titleBarTemplateFactory = intl => [
557 { 559 {
558 label: intl.formatMessage(menuItems.view), 560 label: intl.formatMessage(menuItems.view),
559 accelerator: 'Alt+V', 561 accelerator: 'Alt+V',
562 visible: !locked,
560 submenu: [ 563 submenu: [
561 { 564 {
562 type: 'separator', 565 type: 'separator',
@@ -649,18 +652,19 @@ const _titleBarTemplateFactory = intl => [
649 { 652 {
650 label: intl.formatMessage(menuItems.services), 653 label: intl.formatMessage(menuItems.services),
651 accelerator: 'Alt+S', 654 accelerator: 'Alt+S',
655 visible: !locked,
652 submenu: [], 656 submenu: [],
653 }, 657 },
654 { 658 {
655 label: intl.formatMessage(menuItems.workspaces), 659 label: intl.formatMessage(menuItems.workspaces),
656 accelerator: 'Alt+W', 660 accelerator: 'Alt+W',
657 submenu: [], 661 submenu: [],
658 visible: workspaceStore.isFeatureEnabled, 662 visible: !locked && workspaceStore.isFeatureEnabled,
659 }, 663 },
660 { 664 {
661 label: intl.formatMessage(menuItems.todos), 665 label: intl.formatMessage(menuItems.todos),
662 submenu: [], 666 submenu: [],
663 visible: todosStore.isFeatureEnabled, 667 visible: !locked && todosStore.isFeatureEnabled,
664 }, 668 },
665 { 669 {
666 label: intl.formatMessage(menuItems.window), 670 label: intl.formatMessage(menuItems.window),
@@ -746,83 +750,90 @@ export default class FranzMenu {
746 } 750 }
747 751
748 const { intl } = window.ferdi; 752 const { intl } = window.ferdi;
749 const tpl = isMac ? _templateFactory(intl) : _titleBarTemplateFactory(intl); 753 const tpl = isMac
754 ? _templateFactory(intl, this.stores.settings.app.locked)
755 : _titleBarTemplateFactory(intl, this.stores.settings.app.locked);
750 const { actions } = this; 756 const { actions } = this;
751 757
752 tpl[1].submenu.push({ 758 if (this.stores.settings.app.locked) {
753 type: 'separator',
754 }, {
755 label: intl.formatMessage(menuItems.toggleDevTools),
756 accelerator: `${cmdKey}+Alt+I`,
757 click: (menuItem, browserWindow) => {
758 browserWindow.webContents.toggleDevTools();
759 },
760 }, {
761 label: intl.formatMessage(menuItems.toggleServiceDevTools),
762 accelerator: `${cmdKey}+Shift+Alt+I`,
763 click: () => {
764 this.actions.service.openDevToolsForActiveService();
765 },
766 enabled: this.stores.user.isLoggedIn && this.stores.services.enabled.length > 0,
767 });
768
769 if (this.stores.features.features.isTodosEnabled) {
770 tpl[1].submenu.push({ 759 tpl[1].submenu.push({
771 label: intl.formatMessage(menuItems.toggleTodosDevTools), 760 type: 'separator',
772 accelerator: `${cmdKey}+Shift+Alt+O`, 761 }, {
762 label: intl.formatMessage(menuItems.toggleDevTools),
763 accelerator: `${cmdKey}+Alt+I`,
764 click: (menuItem, browserWindow) => {
765 browserWindow.webContents.toggleDevTools();
766 },
767 }, {
768 label: intl.formatMessage(menuItems.toggleServiceDevTools),
769 accelerator: `${cmdKey}+Shift+Alt+I`,
773 click: () => { 770 click: () => {
774 const webview = document.querySelector('webview[partition="persist:todos"]'); 771 this.actions.service.openDevToolsForActiveService();
775 if (webview) webview.openDevTools();
776 }, 772 },
773 enabled: this.stores.user.isLoggedIn && this.stores.services.enabled.length > 0,
777 }); 774 });
778 }
779 775
780 tpl[1].submenu.unshift({ 776 if (this.stores.features.features.isTodosEnabled) {
781 label: intl.formatMessage(menuItems.reloadService), 777 tpl[1].submenu.push({
782 id: 'reloadService', // TODO: needed? 778 label: intl.formatMessage(menuItems.toggleTodosDevTools),
783 accelerator: `${cmdKey}+R`, 779 accelerator: `${cmdKey}+Shift+Alt+O`,
784 click: () => { 780 click: () => {
785 if (this.stores.user.isLoggedIn 781 const webview = document.querySelector('webview[partition="persist:todos"]');
786 && this.stores.services.enabled.length > 0) { 782 if (webview) webview.openDevTools();
787 if (this.stores.services.active.recipe.id === CUSTOM_WEBSITE_ID) { 783 },
788 this.stores.services.active.webview.reload(); 784 });
785 }
786
787 tpl[1].submenu.unshift({
788 label: intl.formatMessage(menuItems.reloadService),
789 id: 'reloadService', // TODO: needed?
790 accelerator: `${cmdKey}+R`,
791 click: () => {
792 if (this.stores.user.isLoggedIn
793 && this.stores.services.enabled.length > 0) {
794 if (this.stores.services.active.recipe.id === CUSTOM_WEBSITE_ID) {
795 this.stores.services.active.webview.reload();
796 } else {
797 this.actions.service.reloadActive();
798 }
789 } else { 799 } else {
790 this.actions.service.reloadActive(); 800 window.location.reload();
791 } 801 }
792 } else { 802 },
803 }, {
804 label: intl.formatMessage(menuItems.reloadFranz),
805 accelerator: `${cmdKey}+Shift+R`,
806 click: () => {
793 window.location.reload(); 807 window.location.reload();
794 } 808 },
795 }, 809 }, {
796 }, { 810 type: 'separator',
797 label: intl.formatMessage(menuItems.reloadFranz), 811 }, {
798 accelerator: `${cmdKey}+Shift+R`, 812 label: intl.formatMessage(menuItems.lockFerdi),
799 click: () => { 813 accelerator: 'CmdOrCtrl+Shift+L',
800 window.location.reload(); 814 enabled: this.stores.user.isLoggedIn && this.stores.settings.app.lockingFeatureEnabled,
801 }, 815 click() {
802 }, {
803 type: 'separator',
804 }, {
805 label: intl.formatMessage(menuItems.lockFerdi),
806 accelerator: 'CmdOrCtrl+Shift+L',
807 enabled: this.stores.user.isLoggedIn && this.stores.settings.app.lockingFeatureEnabled,
808 click() {
809 // Disable lock first - otherwise the application might not update correctly
810 actions.settings.update({
811 type: 'app',
812 data: {
813 locked: false,
814 },
815 });
816 setTimeout(() => {
817 actions.settings.update({ 816 actions.settings.update({
818 type: 'app', 817 type: 'app',
819 data: { 818 data: {
820 locked: true, 819 locked: true,
821 }, 820 },
822 }); 821 });
823 }, 0); 822 }
824 }, 823 });
825 }); 824
825 if (serviceTpl.length > 0) {
826 tpl[3].submenu = serviceTpl;
827 }
828
829 if (workspaceStore.isFeatureEnabled) {
830 tpl[4].submenu = this.workspacesMenu();
831 }
832
833 if (todosStore.isFeatureEnabled) {
834 tpl[5].submenu = this.todosMenu();
835 }
836 }
826 837
827 tpl.unshift({ 838 tpl.unshift({
828 label: isMac ? app.name : intl.formatMessage(menuItems.file), 839 label: isMac ? app.name : intl.formatMessage(menuItems.file),
@@ -842,15 +853,18 @@ export default class FranzMenu {
842 this.actions.ui.openSettings({ path: 'app' }); 853 this.actions.ui.openSettings({ path: 'app' });
843 }, 854 },
844 enabled: this.stores.user.isLoggedIn, 855 enabled: this.stores.user.isLoggedIn,
856 visible: !this.stores.settings.app.locked,
845 }, 857 },
846 { 858 {
847 label: intl.formatMessage(menuItems.checkForUpdates), 859 label: intl.formatMessage(menuItems.checkForUpdates),
860 visible: !this.stores.settings.app.locked,
848 click: () => { 861 click: () => {
849 this.actions.app.checkForUpdates(); 862 this.actions.app.checkForUpdates();
850 }, 863 },
851 }, 864 },
852 { 865 {
853 type: 'separator', 866 type: 'separator',
867 visible: !this.stores.settings.app.locked,
854 }, 868 },
855 { 869 {
856 label: intl.formatMessage(menuItems.services), 870 label: intl.formatMessage(menuItems.services),
@@ -930,6 +944,7 @@ export default class FranzMenu {
930 this.actions.ui.openSettings({ path: 'app' }); 944 this.actions.ui.openSettings({ path: 'app' });
931 }, 945 },
932 enabled: this.stores.user.isLoggedIn, 946 enabled: this.stores.user.isLoggedIn,
947 visible: !this.stores.settings.locked,
933 }, 948 },
934 { 949 {
935 type: 'separator', 950 type: 'separator',
@@ -961,14 +976,14 @@ export default class FranzMenu {
961 tpl[5].submenu = this.todosMenu(); 976 tpl[5].submenu = this.todosMenu();
962 } 977 }
963 978
964 tpl[tpl.length - 1].submenu.push({ 979 if (!this.stores.settings.app.locked) {
965 type: 'separator', 980 tpl[tpl.length - 1].submenu.push({
966 }, ...this.debugMenu()); 981 type: 'separator',
967 982 }, ...this.debugMenu());
983 }
968 this.currentTemplate = tpl; 984 this.currentTemplate = tpl;
969 const menu = Menu.buildFromTemplate(tpl); 985 const menu = Menu.buildFromTemplate(tpl);
970 const lockedMenu = Menu.buildFromTemplate([]); 986 Menu.setApplicationMenu(menu);
971 Menu.setApplicationMenu(this.stores.user.isLoggedIn && this.stores.settings.app.locked ? lockedMenu : menu);
972 } 987 }
973 988
974 serviceTpl() { 989 serviceTpl() {
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js
index e38b82f03..ae6ba11c5 100644
--- a/src/stores/ServicesStore.js
+++ b/src/stores/ServicesStore.js
@@ -58,7 +58,7 @@ export default class ServicesStore extends Store {
58 this.actions.service.createFromLegacyService.listen(this._createFromLegacyService.bind(this)); 58 this.actions.service.createFromLegacyService.listen(this._createFromLegacyService.bind(this));
59 this.actions.service.updateService.listen(this._updateService.bind(this)); 59 this.actions.service.updateService.listen(this._updateService.bind(this));
60 this.actions.service.deleteService.listen(this._deleteService.bind(this)); 60 this.actions.service.deleteService.listen(this._deleteService.bind(this));
61 this.actions.service.openDarkmodeCss.listen(this._openDarkmodeCss.bind(this)); 61 this.actions.service.openRecipeFile.listen(this._openRecipeFile.bind(this));
62 this.actions.service.clearCache.listen(this._clearCache.bind(this)); 62 this.actions.service.clearCache.listen(this._clearCache.bind(this));
63 this.actions.service.setWebviewReference.listen(this._setWebviewReference.bind(this)); 63 this.actions.service.setWebviewReference.listen(this._setWebviewReference.bind(this));
64 this.actions.service.detachService.listen(this._detachService.bind(this)); 64 this.actions.service.detachService.listen(this._detachService.bind(this));
@@ -334,7 +334,7 @@ export default class ServicesStore extends Store {
334 this.actionStatus = request.result.status; 334 this.actionStatus = request.result.status;
335 } 335 }
336 336
337 @action async _openDarkmodeCss({ recipe }) { 337 @action async _openRecipeFile({ recipe, file }) {
338 // Get directory for recipe 338 // Get directory for recipe
339 const normalDirectory = getRecipeDirectory(recipe); 339 const normalDirectory = getRecipeDirectory(recipe);
340 const devDirectory = getDevRecipeDirectory(recipe); 340 const devDirectory = getDevRecipeDirectory(recipe);
@@ -349,10 +349,10 @@ export default class ServicesStore extends Store {
349 return; 349 return;
350 } 350 }
351 351
352 // Create and open darkmode.css 352 // Create and open file
353 const file = path.join(directory, 'darkmode.css'); 353 const filePath = path.join(directory, file);
354 await fs.ensureFile(file); 354 await fs.ensureFile(filePath);
355 shell.showItemInFolder(file); 355 shell.showItemInFolder(filePath);
356 } 356 }
357 357
358 @action async _clearCache({ serviceId }) { 358 @action async _clearCache({ serviceId }) {
diff --git a/src/stores/SettingsStore.js b/src/stores/SettingsStore.js
index da63bc972..26e83b725 100644
--- a/src/stores/SettingsStore.js
+++ b/src/stores/SettingsStore.js
@@ -1,21 +1,18 @@
1import { ipcRenderer, remote } from 'electron'; 1import { ipcRenderer, remote } from 'electron';
2import { 2import { action, computed, observable, reaction } from 'mobx';
3 action, computed, observable, reaction,
4} from 'mobx';
5import localStorage from 'mobx-localstorage'; 3import localStorage from 'mobx-localstorage';
6
7import Store from './lib/Store';
8import Request from './lib/Request';
9import { getLocale } from '../helpers/i18n-helpers';
10import { API } from '../environment';
11
12import { DEFAULT_APP_SETTINGS, FILE_SYSTEM_SETTINGS_TYPES, LOCAL_SERVER } from '../config'; 4import { DEFAULT_APP_SETTINGS, FILE_SYSTEM_SETTINGS_TYPES, LOCAL_SERVER } from '../config';
5import { API } from '../environment';
6import { getLocale } from '../helpers/i18n-helpers';
13import { SPELLCHECKER_LOCALES } from '../i18n/languages'; 7import { SPELLCHECKER_LOCALES } from '../i18n/languages';
8import Request from './lib/Request';
9import Store from './lib/Store';
14 10
15const debug = require('debug')('Ferdi:SettingsStore'); 11const debug = require('debug')('Ferdi:SettingsStore');
16 12
17export default class SettingsStore extends Store { 13export default class SettingsStore extends Store {
18 @observable updateAppSettingsRequest = new Request(this.api.local, 'updateAppSettings'); 14 @observable updateAppSettingsRequest = new Request(this.api.local, 'updateAppSettings');
15 startup = true;
19 16
20 fileSystemSettingsTypes = FILE_SYSTEM_SETTINGS_TYPES; 17 fileSystemSettingsTypes = FILE_SYSTEM_SETTINGS_TYPES;
21 18
@@ -30,16 +27,6 @@ export default class SettingsStore extends Store {
30 // Register action handlers 27 // Register action handlers
31 this.actions.settings.update.listen(this._update.bind(this)); 28 this.actions.settings.update.listen(this._update.bind(this));
32 this.actions.settings.remove.listen(this._remove.bind(this)); 29 this.actions.settings.remove.listen(this._remove.bind(this));
33
34 ipcRenderer.on('appSettings', (event, resp) => {
35 debug('Get appSettings resolves', resp.type, resp.data);
36
37 Object.assign(this._fileSystemSettingsCache[resp.type], resp.data);
38 });
39
40 this.fileSystemSettingsTypes.forEach((type) => {
41 ipcRenderer.send('getAppSettings', type);
42 });
43 } 30 }
44 31
45 async setup() { 32 async setup() {
@@ -101,27 +88,30 @@ export default class SettingsStore extends Store {
101 } 88 }
102 }); 89 });
103 90
104 // Make sure to lock app on launch if locking feature is enabled 91 ipcRenderer.on('appSettings', (event, resp) => {
105 setTimeout(() => { 92 // Lock on startup if enabled in settings
106 const isLoggedIn = Boolean(localStorage.getItem('authToken')); 93 if (this.startup && resp.type === 'app' && resp.data.lockingFeatureEnabled) {
107 if (isLoggedIn && this.all.app.lockingFeatureEnabled) { 94 this.startup = false;
108 // Disable lock first - otherwise the lock might not get activated corrently 95 process.nextTick(() => {
109 this.actions.settings.update({ 96 // If the app was previously closed unlocked
110 type: 'app', 97 // we can update the `locked` setting and rely on the reaction to lock at startup
111 data: { 98 if (!this.all.app.locked) {
112 locked: false, 99 this.all.app.locked = true;
113 }, 100 } else {
114 }); 101 // Otherwise the app previously closed in a locked state
115 setTimeout(() => { 102 // We can't rely on updating the locked setting for the reaction to be triggered
116 this.actions.settings.update({ 103 // So we lock manually
117 type: 'app', 104 window.ferdi.stores.router.push('/auth/locked');
118 data: { 105 }
119 locked: true, 106 })
120 },
121 });
122 }, 0);
123 } 107 }
124 }, 1000); 108 debug('Get appSettings resolves', resp.type, resp.data);
109 Object.assign(this._fileSystemSettingsCache[resp.type], resp.data);
110 });
111
112 this.fileSystemSettingsTypes.forEach((type) => {
113 ipcRenderer.send('getAppSettings', type);
114 });
125 } 115 }
126 116
127 @computed get app() { 117 @computed get app() {
@@ -250,5 +240,25 @@ export default class SettingsStore extends Store {
250 }, 240 },
251 }); 241 });
252 } 242 }
243
244 if (!this.all.migration['5.4.4-beta.2-settings']) {
245 const {
246 showServiceNavigationBar,
247 } = this.all.app;
248
249 this.actions.settings.update({
250 type: 'app',
251 data: {
252 navigationBarBehaviour: showServiceNavigationBar ? 'custom' : 'never',
253 },
254 });
255
256 this.actions.settings.update({
257 type: 'migration',
258 data: {
259 '5.4.4-beta.2-settings': true,
260 },
261 });
262 }
253 } 263 }
254} 264}
diff --git a/src/styles/settings.scss b/src/styles/settings.scss
index 305450fd2..14cc91f87 100644
--- a/src/styles/settings.scss
+++ b/src/styles/settings.scss
@@ -306,7 +306,15 @@
306 } 306 }
307 307
308 .settings__delete-button { right: 0; } 308 .settings__delete-button { right: 0; }
309 .settings__open-dark-mode-button { right: 0; cursor:pointer; } 309 .settings__open-recipe-file-button {
310 cursor:pointer;
311 margin-right: 10px;
312 }
313 .settings__open-recipe-file-container {
314 margin-top: 20px;
315 display: flex;
316 height: auto !important;
317 }
310 318
311 .settings__empty-state { 319 .settings__empty-state {
312 align-items: center; 320 align-items: center;
diff --git a/src/webview/recipe.js b/src/webview/recipe.js
index e95cae18b..1a22542d8 100644
--- a/src/webview/recipe.js
+++ b/src/webview/recipe.js
@@ -99,6 +99,39 @@ class RecipeController {
99 } catch (err) { 99 } catch (err) {
100 console.error('Recipe initialization failed', err); 100 console.error('Recipe initialization failed', err);
101 } 101 }
102
103 this.loadUserFiles(recipe, config);
104 }
105
106 async loadUserFiles(recipe, config) {
107 const userCss = path.join(recipe.path, 'user.css');
108 if (await fs.exists(userCss)) {
109 const data = await fs.readFile(userCss);
110 const styles = document.createElement('style');
111 styles.innerHTML = data.toString();
112
113 document.querySelector('head').appendChild(styles);
114 }
115
116 const userJs = path.join(recipe.path, 'user.js');
117 if (await fs.exists(userJs)) {
118 const loadUserJs = () => {
119 // eslint-disable-next-line
120 const userJsModule = require(userJs);
121
122 if (typeof userJsModule === 'function') {
123 userJsModule(config);
124 }
125 };
126
127 if (document.readyState !== 'loading') {
128 loadUserJs();
129 } else {
130 document.addEventListener('DOMContentLoaded', () => {
131 loadUserJs();
132 });
133 }
134 }
102 } 135 }
103 136
104 update() { 137 update() {