diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/actions/app.ts (renamed from src/actions/app.js) | 0 | ||||
-rw-r--r-- | src/actions/index.ts (renamed from src/actions/index.js) | 0 | ||||
-rw-r--r-- | src/actions/lib/actions.ts (renamed from src/actions/lib/actions.js) | 16 | ||||
-rw-r--r-- | src/actions/news.ts (renamed from src/actions/news.js) | 0 | ||||
-rw-r--r-- | src/actions/recipe.ts (renamed from src/actions/recipe.js) | 0 | ||||
-rw-r--r-- | src/actions/recipePreview.ts (renamed from src/actions/recipePreview.js) | 0 | ||||
-rw-r--r-- | src/actions/requests.ts (renamed from src/actions/requests.js) | 0 | ||||
-rw-r--r-- | src/actions/service.ts (renamed from src/actions/service.js) | 0 | ||||
-rw-r--r-- | src/actions/settings.ts (renamed from src/actions/settings.js) | 0 | ||||
-rw-r--r-- | src/actions/ui.ts (renamed from src/actions/ui.js) | 0 | ||||
-rw-r--r-- | src/actions/user.ts (renamed from src/actions/user.js) | 0 | ||||
-rw-r--r-- | src/api/apiBase.ts (renamed from src/api/apiBase.js) | 28 | ||||
-rw-r--r-- | src/components/ui/FeatureItem.js | 38 | ||||
-rw-r--r-- | src/components/ui/FeatureList.js | 99 | ||||
-rw-r--r-- | src/components/ui/Input.js | 10 | ||||
-rw-r--r-- | src/features/appearance/index.js | 50 | ||||
-rw-r--r-- | src/helpers/serverless-helpers.ts (renamed from src/helpers/serverless-helpers.js) | 0 | ||||
-rw-r--r-- | src/helpers/service-helpers.ts (renamed from src/helpers/service-helpers.js) | 13 | ||||
-rw-r--r-- | src/helpers/validation-helpers.ts (renamed from src/helpers/validation-helpers.js) | 20 | ||||
-rw-r--r-- | src/i18n/locales/en-US.json | 11 | ||||
-rw-r--r-- | src/index.js | 61 | ||||
-rw-r--r-- | src/stores/UIStore.ts (renamed from src/stores/UIStore.js) | 45 |
22 files changed, 143 insertions, 248 deletions
diff --git a/src/actions/app.js b/src/actions/app.ts index e6f7f22ba..e6f7f22ba 100644 --- a/src/actions/app.js +++ b/src/actions/app.ts | |||
diff --git a/src/actions/index.js b/src/actions/index.ts index aecdac675..aecdac675 100644 --- a/src/actions/index.js +++ b/src/actions/index.ts | |||
diff --git a/src/actions/lib/actions.js b/src/actions/lib/actions.ts index 7be40f1cf..ed42eabc0 100644 --- a/src/actions/lib/actions.js +++ b/src/actions/lib/actions.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | export const createActionsFromDefinitions = (actionDefinitions, validate) => { | 1 | export const createActionsFromDefinitions = (actionDefinitions, validate) => { |
2 | const actions = {}; | 2 | const actions = {}; |
3 | Object.keys(actionDefinitions).forEach((actionName) => { | 3 | Object.keys(actionDefinitions).forEach(actionName => { |
4 | const action = (params = {}) => { | 4 | const action = (params = {}) => { |
5 | const schema = actionDefinitions[actionName]; | 5 | const schema = actionDefinitions[actionName]; |
6 | validate(schema, params, actionName); | 6 | validate(schema, params, actionName); |
@@ -8,20 +8,24 @@ export const createActionsFromDefinitions = (actionDefinitions, validate) => { | |||
8 | }; | 8 | }; |
9 | actions[actionName] = action; | 9 | actions[actionName] = action; |
10 | action.listeners = []; | 10 | action.listeners = []; |
11 | action.listen = (listener) => action.listeners.push(listener); | 11 | action.listen = listener => action.listeners.push(listener); |
12 | action.off = (listener) => { | 12 | action.off = listener => { |
13 | const { listeners } = action; | 13 | const { listeners } = action; |
14 | listeners.splice(listeners.indexOf(listener), 1); | 14 | listeners.splice(listeners.indexOf(listener), 1); |
15 | }; | 15 | }; |
16 | action.notify = (params) => action.listeners.forEach((listener) => listener(params)); | 16 | action.notify = params => |
17 | action.listeners.forEach(listener => listener(params)); | ||
17 | }); | 18 | }); |
18 | return actions; | 19 | return actions; |
19 | }; | 20 | }; |
20 | 21 | ||
21 | export default (definitions, validate) => { | 22 | export default (definitions, validate) => { |
22 | const newActions = {}; | 23 | const newActions = {}; |
23 | Object.keys(definitions).forEach((scopeName) => { | 24 | Object.keys(definitions).forEach(scopeName => { |
24 | newActions[scopeName] = createActionsFromDefinitions(definitions[scopeName], validate); | 25 | newActions[scopeName] = createActionsFromDefinitions( |
26 | definitions[scopeName], | ||
27 | validate, | ||
28 | ); | ||
25 | }); | 29 | }); |
26 | return newActions; | 30 | return newActions; |
27 | }; | 31 | }; |
diff --git a/src/actions/news.js b/src/actions/news.ts index db106e84f..db106e84f 100644 --- a/src/actions/news.js +++ b/src/actions/news.ts | |||
diff --git a/src/actions/recipe.js b/src/actions/recipe.ts index 29b0a151f..29b0a151f 100644 --- a/src/actions/recipe.js +++ b/src/actions/recipe.ts | |||
diff --git a/src/actions/recipePreview.js b/src/actions/recipePreview.ts index 36de3d844..36de3d844 100644 --- a/src/actions/recipePreview.js +++ b/src/actions/recipePreview.ts | |||
diff --git a/src/actions/requests.js b/src/actions/requests.ts index 89296e7ec..89296e7ec 100644 --- a/src/actions/requests.js +++ b/src/actions/requests.ts | |||
diff --git a/src/actions/service.js b/src/actions/service.ts index e56513f8f..e56513f8f 100644 --- a/src/actions/service.js +++ b/src/actions/service.ts | |||
diff --git a/src/actions/settings.js b/src/actions/settings.ts index fd29b798b..fd29b798b 100644 --- a/src/actions/settings.js +++ b/src/actions/settings.ts | |||
diff --git a/src/actions/ui.js b/src/actions/ui.ts index b913b430b..b913b430b 100644 --- a/src/actions/ui.js +++ b/src/actions/ui.ts | |||
diff --git a/src/actions/user.js b/src/actions/user.ts index 20d27ee53..20d27ee53 100644 --- a/src/actions/user.js +++ b/src/actions/user.ts | |||
diff --git a/src/api/apiBase.js b/src/api/apiBase.ts index 2fad7eb21..dc10fad91 100644 --- a/src/api/apiBase.js +++ b/src/api/apiBase.ts | |||
@@ -1,9 +1,7 @@ | |||
1 | /** | 1 | /** |
2 | * Get API base URL from store | 2 | * Get API base URL from store |
3 | */ | 3 | */ |
4 | import { | 4 | import { API_VERSION } from '../environment'; |
5 | API_VERSION, | ||
6 | } from '../environment'; | ||
7 | import { | 5 | import { |
8 | DEV_API_FRANZ_WEBSITE, | 6 | DEV_API_FRANZ_WEBSITE, |
9 | LIVE_FRANZ_API, | 7 | LIVE_FRANZ_API, |
@@ -14,21 +12,25 @@ import { | |||
14 | 12 | ||
15 | // Note: This cannot be used from the internal-server since we are not running within the context of a browser window | 13 | // Note: This cannot be used from the internal-server since we are not running within the context of a browser window |
16 | const apiBase = (withVersion = true) => { | 14 | const apiBase = (withVersion = true) => { |
17 | let url; | 15 | let url: string; |
18 | 16 | ||
19 | if (!window.ferdi | 17 | if ( |
20 | || !window.ferdi.stores.settings | 18 | !(window as any).ferdi || |
21 | || !window.ferdi.stores.settings.all | 19 | !(window as any).ferdi.stores.settings || |
22 | || !window.ferdi.stores.settings.all.app.server) { | 20 | !(window as any).ferdi.stores.settings.all || |
21 | !(window as any).ferdi.stores.settings.all.app.server | ||
22 | ) { | ||
23 | // Stores have not yet been loaded - return SERVER_NOT_LOADED to force a retry when stores are loaded | 23 | // Stores have not yet been loaded - return SERVER_NOT_LOADED to force a retry when stores are loaded |
24 | return SERVER_NOT_LOADED; | 24 | return SERVER_NOT_LOADED; |
25 | } | 25 | } |
26 | if (window.ferdi.stores.settings.all.app.server === LOCAL_SERVER) { | 26 | if ((window as any).ferdi.stores.settings.all.app.server === LOCAL_SERVER) { |
27 | // Use URL for local server | 27 | // Use URL for local server |
28 | url = `http://${LOCAL_HOSTNAME}:${window.ferdi.stores.requests.localServerPort}`; | 28 | url = `http://${LOCAL_HOSTNAME}:${ |
29 | (window as any).ferdi.stores.requests.localServerPort | ||
30 | }`; | ||
29 | } else { | 31 | } else { |
30 | // Load URL from store | 32 | // Load URL from store |
31 | url = window.ferdi.stores.settings.all.app.server; | 33 | url = (window as any).ferdi.stores.settings.all.app.server; |
32 | } | 34 | } |
33 | 35 | ||
34 | return withVersion ? `${url}/${API_VERSION}` : url; | 36 | return withVersion ? `${url}/${API_VERSION}` : url; |
@@ -38,5 +40,7 @@ export default apiBase; | |||
38 | 40 | ||
39 | export function termsBase() { | 41 | export function termsBase() { |
40 | // TODO: This needs to handle local vs ferdi vs franz servers | 42 | // TODO: This needs to handle local vs ferdi vs franz servers |
41 | return window.ferdi.stores.settings.all.app.server !== LIVE_FRANZ_API ? window.ferdi.stores.settings.all.app.server : DEV_API_FRANZ_WEBSITE; | 43 | return (window as any).ferdi.stores.settings.all.app.server !== LIVE_FRANZ_API |
44 | ? (window as any).ferdi.stores.settings.all.app.server | ||
45 | : DEV_API_FRANZ_WEBSITE; | ||
42 | } | 46 | } |
diff --git a/src/components/ui/FeatureItem.js b/src/components/ui/FeatureItem.js deleted file mode 100644 index 646cf56ca..000000000 --- a/src/components/ui/FeatureItem.js +++ /dev/null | |||
@@ -1,38 +0,0 @@ | |||
1 | import React from 'react'; | ||
2 | import injectSheet from 'react-jss'; | ||
3 | import { Icon } from '@meetfranz/ui'; | ||
4 | import classnames from 'classnames'; | ||
5 | import { mdiCheckCircle } from '@mdi/js'; | ||
6 | |||
7 | const styles = (theme) => ({ | ||
8 | featureItem: { | ||
9 | borderBottom: [1, 'solid', theme.defaultContentBorder], | ||
10 | padding: [8, 0], | ||
11 | display: 'flex', | ||
12 | alignItems: 'center', | ||
13 | textAlign: 'left', | ||
14 | }, | ||
15 | featureIcon: { | ||
16 | fill: theme.brandSuccess, | ||
17 | marginRight: 10, | ||
18 | }, | ||
19 | }); | ||
20 | |||
21 | export const FeatureItem = injectSheet(styles)(({ | ||
22 | classes, className, name, icon, | ||
23 | }) => ( | ||
24 | <li className={classnames({ | ||
25 | [classes.featureItem]: true, | ||
26 | [className]: className, | ||
27 | })} | ||
28 | > | ||
29 | {icon ? ( | ||
30 | <span className={classes.featureIcon}>{icon}</span> | ||
31 | ) : ( | ||
32 | <Icon icon={mdiCheckCircle} className={classes.featureIcon} size={1.5} /> | ||
33 | )} | ||
34 | {name} | ||
35 | </li> | ||
36 | )); | ||
37 | |||
38 | export default FeatureItem; | ||
diff --git a/src/components/ui/FeatureList.js b/src/components/ui/FeatureList.js deleted file mode 100644 index 14e7ec3c4..000000000 --- a/src/components/ui/FeatureList.js +++ /dev/null | |||
@@ -1,99 +0,0 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { defineMessages, injectIntl } from 'react-intl'; | ||
4 | |||
5 | import { FeatureItem } from './FeatureItem'; | ||
6 | |||
7 | const messages = defineMessages({ | ||
8 | availableRecipes: { | ||
9 | id: 'pricing.features.recipes', | ||
10 | defaultMessage: 'Choose from more than 70 Services', // TODO: Make this dynamic | ||
11 | }, | ||
12 | accountSync: { | ||
13 | id: 'pricing.features.accountSync', | ||
14 | defaultMessage: 'Account Synchronisation', | ||
15 | }, | ||
16 | desktopNotifications: { | ||
17 | id: 'pricing.features.desktopNotifications', | ||
18 | defaultMessage: 'Desktop Notifications', | ||
19 | }, | ||
20 | unlimitedServices: { | ||
21 | id: 'pricing.features.unlimitedServices', | ||
22 | defaultMessage: 'Add unlimited services', | ||
23 | }, | ||
24 | spellchecker: { | ||
25 | id: 'pricing.features.spellchecker', | ||
26 | defaultMessage: 'Spellchecker support', | ||
27 | }, | ||
28 | workspaces: { | ||
29 | id: 'pricing.features.workspaces', | ||
30 | defaultMessage: 'Workspaces', | ||
31 | }, | ||
32 | customWebsites: { | ||
33 | id: 'pricing.features.customWebsites', | ||
34 | defaultMessage: 'Add Custom Websites', | ||
35 | }, | ||
36 | onPremise: { | ||
37 | id: 'pricing.features.onPremise', | ||
38 | defaultMessage: 'On-premise & other Hosted Services', | ||
39 | }, | ||
40 | thirdPartyServices: { | ||
41 | id: 'pricing.features.thirdPartyServices', | ||
42 | defaultMessage: 'Install 3rd party services', | ||
43 | }, | ||
44 | serviceProxies: { | ||
45 | id: 'pricing.features.serviceProxies', | ||
46 | defaultMessage: 'Service Proxies', | ||
47 | }, | ||
48 | teamManagement: { | ||
49 | id: 'pricing.features.teamManagement', | ||
50 | defaultMessage: 'Team Management', | ||
51 | }, | ||
52 | }); | ||
53 | |||
54 | export class FeatureList extends Component { | ||
55 | static propTypes = { | ||
56 | className: PropTypes.string, | ||
57 | featureClassName: PropTypes.string, | ||
58 | }; | ||
59 | |||
60 | static defaultProps = { | ||
61 | className: '', | ||
62 | featureClassName: '', | ||
63 | }; | ||
64 | |||
65 | render() { | ||
66 | const { className, featureClassName } = this.props; | ||
67 | const { intl } = this.props; | ||
68 | |||
69 | const features = [ | ||
70 | messages.availableRecipes, | ||
71 | messages.accountSync, | ||
72 | messages.desktopNotifications, | ||
73 | |||
74 | messages.spellchecker, | ||
75 | |||
76 | messages.workspaces, | ||
77 | messages.customWebsites, | ||
78 | messages.thirdPartyServices, | ||
79 | |||
80 | messages.unlimitedServices, | ||
81 | messages.onPremise, | ||
82 | messages.serviceProxies, | ||
83 | messages.teamManagement, | ||
84 | ]; | ||
85 | |||
86 | return ( | ||
87 | <ul className={className}> | ||
88 | {features.map(feature => ( | ||
89 | <FeatureItem | ||
90 | name={intl.formatMessage(feature)} | ||
91 | className={featureClassName} | ||
92 | /> | ||
93 | ))} | ||
94 | </ul> | ||
95 | ); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | export default injectIntl(FeatureList); | ||
diff --git a/src/components/ui/Input.js b/src/components/ui/Input.js index 335367f03..43fab10ee 100644 --- a/src/components/ui/Input.js +++ b/src/components/ui/Input.js | |||
@@ -42,7 +42,7 @@ class Input extends Component { | |||
42 | passwordScore: 0, | 42 | passwordScore: 0, |
43 | }; | 43 | }; |
44 | 44 | ||
45 | inputElement = null; | 45 | inputElement; |
46 | 46 | ||
47 | componentDidMount() { | 47 | componentDidMount() { |
48 | if (this.props.focus) { | 48 | if (this.props.focus) { |
@@ -133,10 +133,10 @@ class Input extends Component { | |||
133 | {/* <progress value={this.state.passwordScore} max="100" /> */} | 133 | {/* <progress value={this.state.passwordScore} max="100" /> */} |
134 | <meter | 134 | <meter |
135 | value={passwordScore < 5 ? 5 : passwordScore} | 135 | value={passwordScore < 5 ? 5 : passwordScore} |
136 | low="30" | 136 | low={30} |
137 | high="75" | 137 | high={75} |
138 | optimum="100" | 138 | optimum={100} |
139 | max="100" | 139 | max={100} |
140 | /> | 140 | /> |
141 | </div> | 141 | </div> |
142 | )} | 142 | )} |
diff --git a/src/features/appearance/index.js b/src/features/appearance/index.js index 3aab2fcad..d1db68ac6 100644 --- a/src/features/appearance/index.js +++ b/src/features/appearance/index.js | |||
@@ -10,13 +10,15 @@ function createStyleElement() { | |||
10 | const styles = document.createElement('style'); | 10 | const styles = document.createElement('style'); |
11 | styles.id = STYLE_ELEMENT_ID; | 11 | styles.id = STYLE_ELEMENT_ID; |
12 | 12 | ||
13 | document.querySelector('head').appendChild(styles); | 13 | document.querySelector('head')?.appendChild(styles); |
14 | } | 14 | } |
15 | 15 | ||
16 | function setAppearance(style) { | 16 | function setAppearance(style) { |
17 | const styleElement = document.getElementById(STYLE_ELEMENT_ID); | 17 | const styleElement = document.getElementById(STYLE_ELEMENT_ID); |
18 | 18 | ||
19 | styleElement.innerHTML = style; | 19 | if (styleElement) { |
20 | styleElement.innerHTML = style; | ||
21 | } | ||
20 | } | 22 | } |
21 | 23 | ||
22 | // See https://github.com/Qix-/color/issues/53#issuecomment-656590710 | 24 | // See https://github.com/Qix-/color/issues/53#issuecomment-656590710 |
@@ -28,7 +30,7 @@ function darkenAbsolute(originalColor, absoluteChange) { | |||
28 | function generateAccentStyle(accentColorStr) { | 30 | function generateAccentStyle(accentColorStr) { |
29 | let style = ''; | 31 | let style = ''; |
30 | 32 | ||
31 | Object.keys(themeInfo).forEach((property) => { | 33 | Object.keys(themeInfo).forEach(property => { |
32 | style += ` | 34 | style += ` |
33 | ${themeInfo[property]} { | 35 | ${themeInfo[property]} { |
34 | ${property}: ${accentColorStr}; | 36 | ${property}: ${accentColorStr}; |
@@ -80,19 +82,21 @@ function generateServiceRibbonWidthStyle(widthStr, iconSizeStr, vertical) { | |||
80 | const width = Number(widthStr); | 82 | const width = Number(widthStr); |
81 | const iconSize = Number(iconSizeStr) - iconSizeBias; | 83 | const iconSize = Number(iconSizeStr) - iconSizeBias; |
82 | 84 | ||
83 | return vertical ? ` | 85 | return vertical |
86 | ? ` | ||
84 | .tab-item { | 87 | .tab-item { |
85 | width: ${width - 2}px !important; | 88 | width: ${width - 2}px !important; |
86 | height: ${width - 5 + iconSize}px !important; | 89 | height: ${width - 5 + iconSize}px !important; |
87 | min-height: unset; | 90 | min-height: unset; |
88 | } | 91 | } |
89 | .tab-item .tab-item__icon { | 92 | .tab-item .tab-item__icon { |
90 | width: ${(width / 2) + iconSize}px !important; | 93 | width: ${width / 2 + iconSize}px !important; |
91 | } | 94 | } |
92 | .sidebar__button { | 95 | .sidebar__button { |
93 | font-size: ${width / 3}px !important; | 96 | font-size: ${width / 3}px !important; |
94 | } | 97 | } |
95 | ` : ` | 98 | ` |
99 | : ` | ||
96 | .sidebar { | 100 | .sidebar { |
97 | width: ${width}px !important; | 101 | width: ${width}px !important; |
98 | } | 102 | } |
@@ -101,7 +105,7 @@ function generateServiceRibbonWidthStyle(widthStr, iconSizeStr, vertical) { | |||
101 | height: ${width - 5 + iconSize}px !important; | 105 | height: ${width - 5 + iconSize}px !important; |
102 | } | 106 | } |
103 | .tab-item .tab-item__icon { | 107 | .tab-item .tab-item__icon { |
104 | width: ${(width / 2) + iconSize}px !important; | 108 | width: ${width / 2 + iconSize}px !important; |
105 | } | 109 | } |
106 | .sidebar__button { | 110 | .sidebar__button { |
107 | font-size: ${width / 3}px !important; | 111 | font-size: ${width / 3}px !important; |
@@ -145,9 +149,13 @@ function generateVerticalStyle(widthStr, alwaysShowWorkspaces) { | |||
145 | return ` | 149 | return ` |
146 | .sidebar { | 150 | .sidebar { |
147 | height: ${sidebarWidth + verticalStyleOffset + 1}px !important; | 151 | height: ${sidebarWidth + verticalStyleOffset + 1}px !important; |
148 | ${alwaysShowWorkspaces ? ` | 152 | ${ |
153 | alwaysShowWorkspaces | ||
154 | ? ` | ||
149 | width: calc(100% - 300px) !important; | 155 | width: calc(100% - 300px) !important; |
150 | ` : ''} | 156 | ` |
157 | : '' | ||
158 | } | ||
151 | } | 159 | } |
152 | 160 | ||
153 | .sidebar .sidebar__button { | 161 | .sidebar .sidebar__button { |
@@ -192,12 +200,20 @@ function generateStyle(settings) { | |||
192 | alwaysShowWorkspaces, | 200 | alwaysShowWorkspaces, |
193 | } = settings; | 201 | } = settings; |
194 | 202 | ||
195 | if (accentColor.toLowerCase() !== DEFAULT_APP_SETTINGS.accentColor.toLowerCase()) { | 203 | if ( |
204 | accentColor.toLowerCase() !== DEFAULT_APP_SETTINGS.accentColor.toLowerCase() | ||
205 | ) { | ||
196 | style += generateAccentStyle(accentColor); | 206 | style += generateAccentStyle(accentColor); |
197 | } | 207 | } |
198 | if (serviceRibbonWidth !== DEFAULT_APP_SETTINGS.serviceRibbonWidth | 208 | if ( |
199 | || iconSize !== DEFAULT_APP_SETTINGS.iconSize) { | 209 | serviceRibbonWidth !== DEFAULT_APP_SETTINGS.serviceRibbonWidth || |
200 | style += generateServiceRibbonWidthStyle(serviceRibbonWidth, iconSize, useVerticalStyle); | 210 | iconSize !== DEFAULT_APP_SETTINGS.iconSize |
211 | ) { | ||
212 | style += generateServiceRibbonWidthStyle( | ||
213 | serviceRibbonWidth, | ||
214 | iconSize, | ||
215 | useVerticalStyle, | ||
216 | ); | ||
201 | } | 217 | } |
202 | if (showDragArea) { | 218 | if (showDragArea) { |
203 | style += generateShowDragAreaStyle(accentColor); | 219 | style += generateShowDragAreaStyle(accentColor); |
@@ -206,7 +222,9 @@ function generateStyle(settings) { | |||
206 | style += generateVerticalStyle(serviceRibbonWidth, alwaysShowWorkspaces); | 222 | style += generateVerticalStyle(serviceRibbonWidth, alwaysShowWorkspaces); |
207 | } else if (document.getElementById('vertical-style')) { | 223 | } else if (document.getElementById('vertical-style')) { |
208 | const link = document.getElementById('vertical-style'); | 224 | const link = document.getElementById('vertical-style'); |
209 | document.head.removeChild(link); | 225 | if (link) { |
226 | document.head.removeChild(link); | ||
227 | } | ||
210 | } | 228 | } |
211 | if (alwaysShowWorkspaces) { | 229 | if (alwaysShowWorkspaces) { |
212 | style += generateOpenWorkspaceStyle(); | 230 | style += generateOpenWorkspaceStyle(); |
@@ -225,14 +243,14 @@ export default function initAppearance(stores) { | |||
225 | 243 | ||
226 | // Update style when settings change | 244 | // Update style when settings change |
227 | reaction( | 245 | reaction( |
228 | () => ([ | 246 | () => [ |
229 | settings.all.app.accentColor, | 247 | settings.all.app.accentColor, |
230 | settings.all.app.serviceRibbonWidth, | 248 | settings.all.app.serviceRibbonWidth, |
231 | settings.all.app.iconSize, | 249 | settings.all.app.iconSize, |
232 | settings.all.app.showDragArea, | 250 | settings.all.app.showDragArea, |
233 | settings.all.app.useVerticalStyle, | 251 | settings.all.app.useVerticalStyle, |
234 | settings.all.app.alwaysShowWorkspaces, | 252 | settings.all.app.alwaysShowWorkspaces, |
235 | ]), | 253 | ], |
236 | () => { | 254 | () => { |
237 | updateStyle(settings.all.app); | 255 | updateStyle(settings.all.app); |
238 | }, | 256 | }, |
diff --git a/src/helpers/serverless-helpers.js b/src/helpers/serverless-helpers.ts index 01549e038..01549e038 100644 --- a/src/helpers/serverless-helpers.js +++ b/src/helpers/serverless-helpers.ts | |||
diff --git a/src/helpers/service-helpers.js b/src/helpers/service-helpers.ts index 745f40dd9..13c921f88 100644 --- a/src/helpers/service-helpers.js +++ b/src/helpers/service-helpers.ts | |||
@@ -2,15 +2,20 @@ import { readdirSync, removeSync } from 'fs-extra'; | |||
2 | import { userDataPath } from '../environment'; | 2 | import { userDataPath } from '../environment'; |
3 | 3 | ||
4 | export function getServicePartitionsDirectory(...segments) { | 4 | export function getServicePartitionsDirectory(...segments) { |
5 | return userDataPath('Partitions', ...([segments].flat())); | 5 | return userDataPath('Partitions', ...[segments].flat()); |
6 | } | 6 | } |
7 | 7 | ||
8 | export function removeServicePartitionDirectory(id = '', addServicePrefix = false) { | 8 | export function removeServicePartitionDirectory( |
9 | const servicePartition = getServicePartitionsDirectory(`${addServicePrefix ? 'service-' : ''}${id}`); | 9 | id = '', |
10 | addServicePrefix = false, | ||
11 | ) { | ||
12 | const servicePartition = getServicePartitionsDirectory( | ||
13 | `${addServicePrefix ? 'service-' : ''}${id}`, | ||
14 | ); | ||
10 | return removeSync(servicePartition); | 15 | return removeSync(servicePartition); |
11 | } | 16 | } |
12 | 17 | ||
13 | export async function getServiceIdsFromPartitions() { | 18 | export async function getServiceIdsFromPartitions() { |
14 | const files = readdirSync(getServicePartitionsDirectory()); | 19 | const files = readdirSync(getServicePartitionsDirectory()); |
15 | return files.filter((n) => n !== '__chrome_extension'); | 20 | return files.filter(n => n !== '__chrome_extension'); |
16 | } | 21 | } |
diff --git a/src/helpers/validation-helpers.js b/src/helpers/validation-helpers.ts index 569b13bb0..80d368b2e 100644 --- a/src/helpers/validation-helpers.js +++ b/src/helpers/validation-helpers.ts | |||
@@ -28,7 +28,9 @@ export function required({ field }) { | |||
28 | const isValid = field.value.trim() !== ''; | 28 | const isValid = field.value.trim() !== ''; |
29 | return [ | 29 | return [ |
30 | isValid, | 30 | isValid, |
31 | window.ferdi.intl.formatMessage(messages.required, { field: field.label }), | 31 | (window as any).ferdi.intl.formatMessage(messages.required, { |
32 | field: field.label, | ||
33 | }), | ||
32 | ]; | 34 | ]; |
33 | } | 35 | } |
34 | 36 | ||
@@ -37,7 +39,9 @@ export function email({ field }) { | |||
37 | const isValid = isEmail(value); | 39 | const isValid = isEmail(value); |
38 | return [ | 40 | return [ |
39 | isValid, | 41 | isValid, |
40 | window.ferdi.intl.formatMessage(messages.email, { field: field.label }), | 42 | (window as any).ferdi.intl.formatMessage(messages.email, { |
43 | field: field.label, | ||
44 | }), | ||
41 | ]; | 45 | ]; |
42 | } | 46 | } |
43 | 47 | ||
@@ -58,11 +62,13 @@ export function url({ field }) { | |||
58 | 62 | ||
59 | return [ | 63 | return [ |
60 | isValid, | 64 | isValid, |
61 | window.ferdi.intl.formatMessage(messages.url, { field: field.label }), | 65 | (window as any).ferdi.intl.formatMessage(messages.url, { |
66 | field: field.label, | ||
67 | }), | ||
62 | ]; | 68 | ]; |
63 | } | 69 | } |
64 | 70 | ||
65 | export function minLength(length) { | 71 | export function minLength(length: number) { |
66 | return ({ field }) => { | 72 | return ({ field }) => { |
67 | let isValid = true; | 73 | let isValid = true; |
68 | if (field.touched) { | 74 | if (field.touched) { |
@@ -70,7 +76,7 @@ export function minLength(length) { | |||
70 | } | 76 | } |
71 | return [ | 77 | return [ |
72 | isValid, | 78 | isValid, |
73 | window.ferdi.intl.formatMessage(messages.minLength, { | 79 | (window as any).ferdi.intl.formatMessage(messages.minLength, { |
74 | field: field.label, | 80 | field: field.label, |
75 | length, | 81 | length, |
76 | }), | 82 | }), |
@@ -78,12 +84,12 @@ export function minLength(length) { | |||
78 | }; | 84 | }; |
79 | } | 85 | } |
80 | 86 | ||
81 | export function oneRequired(targets) { | 87 | export function oneRequired(targets: string[]) { |
82 | return ({ field, form }) => { | 88 | return ({ field, form }) => { |
83 | const invalidFields = targets.filter(target => form.$(target).value === ''); | 89 | const invalidFields = targets.filter(target => form.$(target).value === ''); |
84 | return [ | 90 | return [ |
85 | targets.length !== invalidFields.length, | 91 | targets.length !== invalidFields.length, |
86 | window.ferdi.intl.formatMessage(messages.required, { | 92 | (window as any).ferdi.intl.formatMessage(messages.required, { |
87 | field: field.label, | 93 | field: field.label, |
88 | }), | 94 | }), |
89 | ]; | 95 | ]; |
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 19adaaf6a..c66056467 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -152,17 +152,6 @@ | |||
152 | "password.link.signup": "Create a free account", | 152 | "password.link.signup": "Create a free account", |
153 | "password.noUser": "No user affiliated with that email address", | 153 | "password.noUser": "No user affiliated with that email address", |
154 | "password.successInfo": "Your new password was sent to your email address", | 154 | "password.successInfo": "Your new password was sent to your email address", |
155 | "pricing.features.accountSync": "Account Synchronisation", | ||
156 | "pricing.features.customWebsites": "Add Custom Websites", | ||
157 | "pricing.features.desktopNotifications": "Desktop Notifications", | ||
158 | "pricing.features.onPremise": "On-premise & other Hosted Services", | ||
159 | "pricing.features.recipes": "Choose from more than 70 Services", | ||
160 | "pricing.features.serviceProxies": "Service Proxies", | ||
161 | "pricing.features.spellchecker": "Spellchecker support", | ||
162 | "pricing.features.teamManagement": "Team Management", | ||
163 | "pricing.features.thirdPartyServices": "Install 3rd party services", | ||
164 | "pricing.features.unlimitedServices": "Add unlimited services", | ||
165 | "pricing.features.workspaces": "Workspaces", | ||
166 | "service.crashHandler.action": "Reload {name}", | 155 | "service.crashHandler.action": "Reload {name}", |
167 | "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", | 156 | "service.crashHandler.autoReload": "Trying to automatically restore {name} in {seconds} seconds", |
168 | "service.crashHandler.headline": "Oh no!", | 157 | "service.crashHandler.headline": "Oh no!", |
diff --git a/src/index.js b/src/index.js index 7f1f77b4e..08d9a3a45 100644 --- a/src/index.js +++ b/src/index.js | |||
@@ -78,14 +78,18 @@ if (isWindows) { | |||
78 | const settings = new Settings('app', DEFAULT_APP_SETTINGS); | 78 | const settings = new Settings('app', DEFAULT_APP_SETTINGS); |
79 | const proxySettings = new Settings('proxy'); | 79 | const proxySettings = new Settings('proxy'); |
80 | 80 | ||
81 | const retrieveSettingValue = (key, defaultValue = true) => ifUndefinedBoolean(settings.get(key), defaultValue); | 81 | const retrieveSettingValue = (key, defaultValue = true) => |
82 | ifUndefinedBoolean(settings.get(key), defaultValue); | ||
82 | 83 | ||
83 | if (retrieveSettingValue('sentry')) { | 84 | if (retrieveSettingValue('sentry')) { |
84 | // eslint-disable-next-line global-require | 85 | // eslint-disable-next-line global-require |
85 | require('./sentry'); | 86 | require('./sentry'); |
86 | } | 87 | } |
87 | 88 | ||
88 | const liftSingleInstanceLock = retrieveSettingValue('liftSingleInstanceLock', false); | 89 | const liftSingleInstanceLock = retrieveSettingValue( |
90 | 'liftSingleInstanceLock', | ||
91 | false, | ||
92 | ); | ||
89 | 93 | ||
90 | // Force single window | 94 | // Force single window |
91 | const gotTheLock = liftSingleInstanceLock | 95 | const gotTheLock = liftSingleInstanceLock |
@@ -190,11 +194,11 @@ const createWindow = () => { | |||
190 | minWidth: 600, | 194 | minWidth: 600, |
191 | minHeight: 500, | 195 | minHeight: 500, |
192 | show: false, | 196 | show: false, |
193 | titleBarStyle: isMac ? 'hidden' : '', | 197 | titleBarStyle: isMac ? 'hidden' : 'default', |
194 | frame: isLinux, | 198 | frame: isLinux, |
195 | spellcheck: retrieveSettingValue('enableSpellchecking'), | ||
196 | backgroundColor, | 199 | backgroundColor, |
197 | webPreferences: { | 200 | webPreferences: { |
201 | spellcheck: retrieveSettingValue('enableSpellchecking'), | ||
198 | nodeIntegration: true, | 202 | nodeIntegration: true, |
199 | contextIsolation: false, | 203 | contextIsolation: false, |
200 | webviewTag: true, | 204 | webviewTag: true, |
@@ -268,10 +272,7 @@ const createWindow = () => { | |||
268 | // Dereference the window object, usually you would store windows | 272 | // Dereference the window object, usually you would store windows |
269 | // in an array if your app supports multi windows, this is the time | 273 | // in an array if your app supports multi windows, this is the time |
270 | // when you should delete the corresponding element. | 274 | // when you should delete the corresponding element. |
271 | if ( | 275 | if (!willQuitApp && retrieveSettingValue('runInBackground')) { |
272 | !willQuitApp && | ||
273 | retrieveSettingValue('runInBackground') | ||
274 | ) { | ||
275 | e.preventDefault(); | 276 | e.preventDefault(); |
276 | if (isWindows) { | 277 | if (isWindows) { |
277 | debug('Window: minimize'); | 278 | debug('Window: minimize'); |
@@ -471,7 +472,9 @@ ipcMain.on('open-browser-window', (e, { url, serviceId }) => { | |||
471 | ipcMain.on( | 472 | ipcMain.on( |
472 | 'modifyRequestHeaders', | 473 | 'modifyRequestHeaders', |
473 | (e, { modifiedRequestHeaders, serviceId }) => { | 474 | (e, { modifiedRequestHeaders, serviceId }) => { |
474 | debug(`Received modifyRequestHeaders ${modifiedRequestHeaders} for serviceId ${serviceId}`); | 475 | debug( |
476 | `Received modifyRequestHeaders ${modifiedRequestHeaders} for serviceId ${serviceId}`, | ||
477 | ); | ||
475 | modifiedRequestHeaders.forEach(headerFilterSet => { | 478 | modifiedRequestHeaders.forEach(headerFilterSet => { |
476 | const { headers, requestFilters } = headerFilterSet; | 479 | const { headers, requestFilters } = headerFilterSet; |
477 | session | 480 | session |
@@ -489,23 +492,22 @@ ipcMain.on( | |||
489 | }, | 492 | }, |
490 | ); | 493 | ); |
491 | 494 | ||
492 | ipcMain.on( | 495 | ipcMain.on('knownCertificateHosts', (e, { knownHosts, serviceId }) => { |
493 | 'knownCertificateHosts', | 496 | debug( |
494 | (e, { knownHosts, serviceId }) => { | 497 | `Received knownCertificateHosts ${knownHosts} for serviceId ${serviceId}`, |
495 | debug(`Received knownCertificateHosts ${knownHosts} for serviceId ${serviceId}`); | 498 | ); |
496 | session | 499 | session |
497 | .fromPartition(`persist:service-${serviceId}`) | 500 | .fromPartition(`persist:service-${serviceId}`) |
498 | .setCertificateVerifyProc((request, callback) => { | 501 | .setCertificateVerifyProc((request, callback) => { |
499 | // To know more about these callbacks: https://www.electronjs.org/docs/api/session#sessetcertificateverifyprocproc | 502 | // To know more about these callbacks: https://www.electronjs.org/docs/api/session#sessetcertificateverifyprocproc |
500 | const { hostname } = request; | 503 | const { hostname } = request; |
501 | if (knownHosts.find(item => item.includes(hostname)).length > 0) { | 504 | if (knownHosts.find(item => item.includes(hostname)).length > 0) { |
502 | callback(0); | 505 | callback(0); |
503 | } else { | 506 | } else { |
504 | callback(-2); | 507 | callback(-2); |
505 | } | 508 | } |
506 | }); | 509 | }); |
507 | }, | 510 | }); |
508 | ); | ||
509 | 511 | ||
510 | ipcMain.on('feature-basic-auth-cancel', () => { | 512 | ipcMain.on('feature-basic-auth-cancel', () => { |
511 | debug('Cancel basic auth'); | 513 | debug('Cancel basic auth'); |
@@ -560,7 +562,7 @@ app.on('window-all-closed', () => { | |||
560 | } | 562 | } |
561 | }); | 563 | }); |
562 | 564 | ||
563 | app.on('before-quit', (event) => { | 565 | app.on('before-quit', event => { |
564 | const yesButtonIndex = 0; | 566 | const yesButtonIndex = 0; |
565 | let selection = yesButtonIndex; | 567 | let selection = yesButtonIndex; |
566 | if (retrieveSettingValue('confirmOnQuit')) { | 568 | if (retrieveSettingValue('confirmOnQuit')) { |
@@ -568,10 +570,7 @@ app.on('before-quit', (event) => { | |||
568 | type: 'question', | 570 | type: 'question', |
569 | message: 'Quit', | 571 | message: 'Quit', |
570 | detail: 'Do you really want to quit Ferdi?', | 572 | detail: 'Do you really want to quit Ferdi?', |
571 | buttons: [ | 573 | buttons: ['Yes', 'No'], |
572 | 'Yes', | ||
573 | 'No', | ||
574 | ], | ||
575 | }); | 574 | }); |
576 | } | 575 | } |
577 | if (selection === yesButtonIndex) { | 576 | if (selection === yesButtonIndex) { |
diff --git a/src/stores/UIStore.js b/src/stores/UIStore.ts index be675d5ed..ec48eeb40 100644 --- a/src/stores/UIStore.js +++ b/src/stores/UIStore.ts | |||
@@ -1,13 +1,15 @@ | |||
1 | import { | 1 | import { action, observable, computed, reaction } from 'mobx'; |
2 | action, observable, computed, reaction, | 2 | import { theme, ThemeType } from '@meetfranz/theme'; |
3 | } from 'mobx'; | ||
4 | import { theme } from '@meetfranz/theme'; | ||
5 | import { nativeTheme, systemPreferences } from '@electron/remote'; | 3 | import { nativeTheme, systemPreferences } from '@electron/remote'; |
6 | 4 | ||
7 | import Store from './lib/Store'; | 5 | import Store from './lib/Store'; |
8 | import { isMac, isWindows } from '../environment'; | 6 | import { isMac, isWindows } from '../environment'; |
9 | 7 | ||
10 | export default class UIStore extends Store { | 8 | export default class UIStore extends Store { |
9 | actions: any; | ||
10 | |||
11 | stores: any; | ||
12 | |||
11 | @observable showServicesUpdatedInfoBar = false; | 13 | @observable showServicesUpdatedInfoBar = false; |
12 | 14 | ||
13 | @observable isOsDarkThemeActive = nativeTheme.shouldUseDarkColors; | 15 | @observable isOsDarkThemeActive = nativeTheme.shouldUseDarkColors; |
@@ -43,9 +45,7 @@ export default class UIStore extends Store { | |||
43 | 45 | ||
44 | setup() { | 46 | setup() { |
45 | reaction( | 47 | reaction( |
46 | () => ( | 48 | () => this.isDarkThemeActive, |
47 | this.isDarkThemeActive | ||
48 | ), | ||
49 | () => { | 49 | () => { |
50 | this._setupThemeInDOM(); | 50 | this._setupThemeInDOM(); |
51 | }, | 51 | }, |
@@ -57,24 +57,31 @@ export default class UIStore extends Store { | |||
57 | const settings = this.stores.settings.all; | 57 | const settings = this.stores.settings.all; |
58 | 58 | ||
59 | return ( | 59 | return ( |
60 | (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) | 60 | (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) || |
61 | || !settings.app.isAppMuted | 61 | !settings.app.isAppMuted |
62 | ); | 62 | ); |
63 | } | 63 | } |
64 | 64 | ||
65 | @computed get isDarkThemeActive() { | 65 | @computed get isDarkThemeActive() { |
66 | const isWithAdaptableInDarkMode = this.stores.settings.all.app.adaptableDarkMode | 66 | const isWithAdaptableInDarkMode = |
67 | && this.isOsDarkThemeActive; | 67 | this.stores.settings.all.app.adaptableDarkMode && |
68 | const isWithoutAdaptableInDarkMode = this.stores.settings.all.app.darkMode | 68 | this.isOsDarkThemeActive; |
69 | && !this.stores.settings.all.app.adaptableDarkMode; | 69 | const isWithoutAdaptableInDarkMode = |
70 | this.stores.settings.all.app.darkMode && | ||
71 | !this.stores.settings.all.app.adaptableDarkMode; | ||
70 | const isInDarkMode = this.stores.settings.all.app.darkMode; | 72 | const isInDarkMode = this.stores.settings.all.app.darkMode; |
71 | return !!(isWithAdaptableInDarkMode | 73 | return !!( |
72 | || isWithoutAdaptableInDarkMode | 74 | isWithAdaptableInDarkMode || |
73 | || isInDarkMode); | 75 | isWithoutAdaptableInDarkMode || |
76 | isInDarkMode | ||
77 | ); | ||
74 | } | 78 | } |
75 | 79 | ||
76 | @computed get theme() { | 80 | @computed get theme() { |
77 | const themeId = (this.isDarkThemeActive || this.stores.settings.app.darkMode) ? 'dark' : 'default'; | 81 | const themeId = |
82 | this.isDarkThemeActive || this.stores.settings.app.darkMode | ||
83 | ? ThemeType.dark | ||
84 | : ThemeType.default; | ||
78 | const { accentColor } = this.stores.settings.app; | 85 | const { accentColor } = this.stores.settings.app; |
79 | return theme(themeId, accentColor); | 86 | return theme(themeId, accentColor); |
80 | } | 87 | } |
@@ -102,9 +109,9 @@ export default class UIStore extends Store { | |||
102 | const body = document.querySelector('body'); | 109 | const body = document.querySelector('body'); |
103 | 110 | ||
104 | if (!this.isDarkThemeActive) { | 111 | if (!this.isDarkThemeActive) { |
105 | body.classList.remove('theme__dark'); | 112 | body?.classList.remove('theme__dark'); |
106 | } else { | 113 | } else { |
107 | body.classList.add('theme__dark'); | 114 | body?.classList.add('theme__dark'); |
108 | } | 115 | } |
109 | } | 116 | } |
110 | } | 117 | } |