diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/auth/AuthLayout.js | 6 | ||||
-rw-r--r-- | src/components/layout/AppLayout.js | 126 | ||||
-rw-r--r-- | src/containers/auth/AuthLayoutContainer.js | 10 | ||||
-rw-r--r-- | src/containers/layout/AppLayoutContainer.js | 1 | ||||
-rw-r--r-- | src/containers/settings/SettingsWindow.js | 35 | ||||
-rw-r--r-- | src/features/announcements/components/AnnouncementScreen.js | 2 | ||||
-rw-r--r-- | src/features/delayApp/index.js | 5 | ||||
-rw-r--r-- | src/features/delayApp/styles.js | 1 | ||||
-rw-r--r-- | src/features/workspaces/store.js | 21 | ||||
-rw-r--r-- | src/index.html | 1 | ||||
-rw-r--r-- | src/stores/RecipesStore.js | 27 | ||||
-rw-r--r-- | src/stores/ServicesStore.js | 18 | ||||
-rw-r--r-- | src/stores/UIStore.js | 30 | ||||
-rw-r--r-- | src/stores/lib/Reaction.js | 6 | ||||
-rw-r--r-- | src/styles/layout.scss | 2 | ||||
-rw-r--r-- | src/styles/reset.scss | 2 | ||||
-rw-r--r-- | src/webview/contextMenu.js | 5 | ||||
-rw-r--r-- | src/webview/spellchecker.js | 17 |
18 files changed, 179 insertions, 136 deletions
diff --git a/src/components/auth/AuthLayout.js b/src/components/auth/AuthLayout.js index 3d43d4e5c..75a8cfc61 100644 --- a/src/components/auth/AuthLayout.js +++ b/src/components/auth/AuthLayout.js | |||
@@ -22,7 +22,6 @@ export default @observer class AuthLayout extends Component { | |||
22 | retryHealthCheck: PropTypes.func.isRequired, | 22 | retryHealthCheck: PropTypes.func.isRequired, |
23 | isHealthCheckLoading: PropTypes.bool.isRequired, | 23 | isHealthCheckLoading: PropTypes.bool.isRequired, |
24 | isFullScreen: PropTypes.bool.isRequired, | 24 | isFullScreen: PropTypes.bool.isRequired, |
25 | darkMode: PropTypes.bool.isRequired, | ||
26 | nextAppReleaseVersion: PropTypes.string, | 25 | nextAppReleaseVersion: PropTypes.string, |
27 | installAppUpdate: PropTypes.func.isRequired, | 26 | installAppUpdate: PropTypes.func.isRequired, |
28 | appUpdateIsDownloaded: PropTypes.bool.isRequired, | 27 | appUpdateIsDownloaded: PropTypes.bool.isRequired, |
@@ -45,7 +44,6 @@ export default @observer class AuthLayout extends Component { | |||
45 | retryHealthCheck, | 44 | retryHealthCheck, |
46 | isHealthCheckLoading, | 45 | isHealthCheckLoading, |
47 | isFullScreen, | 46 | isFullScreen, |
48 | darkMode, | ||
49 | nextAppReleaseVersion, | 47 | nextAppReleaseVersion, |
50 | installAppUpdate, | 48 | installAppUpdate, |
51 | appUpdateIsDownloaded, | 49 | appUpdateIsDownloaded, |
@@ -53,7 +51,7 @@ export default @observer class AuthLayout extends Component { | |||
53 | const { intl } = this.context; | 51 | const { intl } = this.context; |
54 | 52 | ||
55 | return ( | 53 | return ( |
56 | <div className={darkMode ? 'theme__dark' : ''}> | 54 | <> |
57 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} | 55 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} |
58 | <div className="auth"> | 56 | <div className="auth"> |
59 | {!isOnline && ( | 57 | {!isOnline && ( |
@@ -93,7 +91,7 @@ export default @observer class AuthLayout extends Component { | |||
93 | <img src="./assets/images/adlk.svg" alt="" /> | 91 | <img src="./assets/images/adlk.svg" alt="" /> |
94 | </Link> | 92 | </Link> |
95 | </div> | 93 | </div> |
96 | </div> | 94 | </> |
97 | ); | 95 | ); |
98 | } | 96 | } |
99 | } | 97 | } |
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index 499bc097a..ebb9849ea 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js | |||
@@ -68,7 +68,6 @@ class AppLayout extends Component { | |||
68 | areRequiredRequestsSuccessful: PropTypes.bool.isRequired, | 68 | areRequiredRequestsSuccessful: PropTypes.bool.isRequired, |
69 | retryRequiredRequests: PropTypes.func.isRequired, | 69 | retryRequiredRequests: PropTypes.func.isRequired, |
70 | areRequiredRequestsLoading: PropTypes.bool.isRequired, | 70 | areRequiredRequestsLoading: PropTypes.bool.isRequired, |
71 | darkMode: PropTypes.bool.isRequired, | ||
72 | isDelayAppScreenVisible: PropTypes.bool.isRequired, | 71 | isDelayAppScreenVisible: PropTypes.bool.isRequired, |
73 | }; | 72 | }; |
74 | 73 | ||
@@ -101,7 +100,6 @@ class AppLayout extends Component { | |||
101 | areRequiredRequestsSuccessful, | 100 | areRequiredRequestsSuccessful, |
102 | retryRequiredRequests, | 101 | retryRequiredRequests, |
103 | areRequiredRequestsLoading, | 102 | areRequiredRequestsLoading, |
104 | darkMode, | ||
105 | isDelayAppScreenVisible, | 103 | isDelayAppScreenVisible, |
106 | } = this.props; | 104 | } = this.props; |
107 | 105 | ||
@@ -109,69 +107,67 @@ class AppLayout extends Component { | |||
109 | 107 | ||
110 | return ( | 108 | return ( |
111 | <ErrorBoundary> | 109 | <ErrorBoundary> |
112 | <div className={(darkMode ? 'theme__dark' : '')}> | 110 | <div className="app"> |
113 | <div className="app"> | 111 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} |
114 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} | 112 | <div className={`app__content ${classes.appContent}`}> |
115 | <div className={`app__content ${classes.appContent}`}> | 113 | {workspacesDrawer} |
116 | {workspacesDrawer} | 114 | {sidebar} |
117 | {sidebar} | 115 | <div className="app__service"> |
118 | <div className="app__service"> | 116 | <WorkspaceSwitchingIndicator /> |
119 | <WorkspaceSwitchingIndicator /> | 117 | {news.length > 0 && news.map(item => ( |
120 | {news.length > 0 && news.map(item => ( | 118 | <InfoBar |
121 | <InfoBar | 119 | key={item.id} |
122 | key={item.id} | 120 | position="top" |
123 | position="top" | 121 | type={item.type} |
124 | type={item.type} | 122 | sticky={item.sticky} |
125 | sticky={item.sticky} | 123 | onHide={() => removeNewsItem({ newsId: item.id })} |
126 | onHide={() => removeNewsItem({ newsId: item.id })} | 124 | > |
127 | > | 125 | <span dangerouslySetInnerHTML={createMarkup(item.message)} /> |
128 | <span dangerouslySetInnerHTML={createMarkup(item.message)} /> | 126 | </InfoBar> |
129 | </InfoBar> | 127 | ))} |
130 | ))} | 128 | {/* {!isOnline && ( |
131 | {/* {!isOnline && ( | 129 | <InfoBar |
132 | <InfoBar | 130 | type="danger" |
133 | type="danger" | 131 | sticky |
134 | sticky | 132 | > |
135 | > | 133 | <span className="mdi mdi-flash" /> |
136 | <span className="mdi mdi-flash" /> | 134 | {intl.formatMessage(globalMessages.notConnectedToTheInternet)} |
137 | {intl.formatMessage(globalMessages.notConnectedToTheInternet)} | 135 | </InfoBar> |
138 | </InfoBar> | 136 | )} */} |
139 | )} */} | 137 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( |
140 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( | 138 | <InfoBar |
141 | <InfoBar | 139 | type="danger" |
142 | type="danger" | 140 | ctaLabel="Try again" |
143 | ctaLabel="Try again" | 141 | ctaLoading={areRequiredRequestsLoading} |
144 | ctaLoading={areRequiredRequestsLoading} | 142 | sticky |
145 | sticky | 143 | onClick={retryRequiredRequests} |
146 | onClick={retryRequiredRequests} | 144 | > |
147 | > | 145 | <span className="mdi mdi-flash" /> |
148 | <span className="mdi mdi-flash" /> | 146 | {intl.formatMessage(messages.requiredRequestsFailed)} |
149 | {intl.formatMessage(messages.requiredRequestsFailed)} | 147 | </InfoBar> |
150 | </InfoBar> | 148 | )} |
151 | )} | 149 | {showServicesUpdatedInfoBar && ( |
152 | {showServicesUpdatedInfoBar && ( | 150 | <InfoBar |
153 | <InfoBar | 151 | type="primary" |
154 | type="primary" | 152 | ctaLabel={intl.formatMessage(messages.buttonReloadServices)} |
155 | ctaLabel={intl.formatMessage(messages.buttonReloadServices)} | 153 | onClick={reloadServicesAfterUpdate} |
156 | onClick={reloadServicesAfterUpdate} | 154 | sticky |
157 | sticky | 155 | > |
158 | > | 156 | <span className="mdi mdi-power-plug" /> |
159 | <span className="mdi mdi-power-plug" /> | 157 | {intl.formatMessage(messages.servicesUpdated)} |
160 | {intl.formatMessage(messages.servicesUpdated)} | 158 | </InfoBar> |
161 | </InfoBar> | 159 | )} |
162 | )} | 160 | {appUpdateIsDownloaded && ( |
163 | {appUpdateIsDownloaded && ( | 161 | <AppUpdateInfoBar |
164 | <AppUpdateInfoBar | 162 | nextAppReleaseVersion={nextAppReleaseVersion} |
165 | nextAppReleaseVersion={nextAppReleaseVersion} | 163 | onInstallUpdate={installAppUpdate} |
166 | onInstallUpdate={installAppUpdate} | 164 | /> |
167 | /> | 165 | )} |
168 | )} | 166 | {isDelayAppScreenVisible && (<DelayApp />)} |
169 | {isDelayAppScreenVisible && (<DelayApp />)} | 167 | <BasicAuth /> |
170 | <BasicAuth /> | 168 | <ShareFranz /> |
171 | <ShareFranz /> | 169 | {services} |
172 | {services} | 170 | {children} |
173 | {children} | ||
174 | </div> | ||
175 | </div> | 171 | </div> |
176 | </div> | 172 | </div> |
177 | </div> | 173 | </div> |
diff --git a/src/containers/auth/AuthLayoutContainer.js b/src/containers/auth/AuthLayoutContainer.js index 1f9c1ea61..427054d3d 100644 --- a/src/containers/auth/AuthLayoutContainer.js +++ b/src/containers/auth/AuthLayoutContainer.js | |||
@@ -2,7 +2,6 @@ import React, { Component } from 'react'; | |||
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import { inject, observer } from 'mobx-react'; | 3 | import { inject, observer } from 'mobx-react'; |
4 | import { ThemeProvider } from 'react-jss'; | 4 | import { ThemeProvider } from 'react-jss'; |
5 | import { theme } from '@meetfranz/theme'; | ||
6 | 5 | ||
7 | import AuthLayout from '../../components/auth/AuthLayout'; | 6 | import AuthLayout from '../../components/auth/AuthLayout'; |
8 | import AppStore from '../../stores/AppStore'; | 7 | import AppStore from '../../stores/AppStore'; |
@@ -24,24 +23,22 @@ export default @inject('stores', 'actions') @observer class AuthLayoutContainer | |||
24 | stores, actions, children, location, | 23 | stores, actions, children, location, |
25 | } = this.props; | 24 | } = this.props; |
26 | const { | 25 | const { |
27 | app, features, globalError, settings, | 26 | app, features, globalError, |
28 | } = stores; | 27 | } = stores; |
29 | 28 | ||
30 | const isLoadingBaseFeatures = features.defaultFeaturesRequest.isExecuting | 29 | const isLoadingBaseFeatures = features.defaultFeaturesRequest.isExecuting |
31 | && !features.defaultFeaturesRequest.wasExecuted; | 30 | && !features.defaultFeaturesRequest.wasExecuted; |
32 | 31 | ||
33 | const themeType = theme(settings.app.darkMode ? 'dark' : 'default'); | ||
34 | |||
35 | if (isLoadingBaseFeatures) { | 32 | if (isLoadingBaseFeatures) { |
36 | return ( | 33 | return ( |
37 | <ThemeProvider theme={theme(themeType)}> | 34 | <ThemeProvider theme={stores.ui.theme}> |
38 | <AppLoader /> | 35 | <AppLoader /> |
39 | </ThemeProvider> | 36 | </ThemeProvider> |
40 | ); | 37 | ); |
41 | } | 38 | } |
42 | 39 | ||
43 | return ( | 40 | return ( |
44 | <ThemeProvider theme={theme(themeType)}> | 41 | <ThemeProvider theme={stores.ui.theme}> |
45 | <AuthLayout | 42 | <AuthLayout |
46 | error={globalError.response} | 43 | error={globalError.response} |
47 | pathname={location.pathname} | 44 | pathname={location.pathname} |
@@ -50,7 +47,6 @@ export default @inject('stores', 'actions') @observer class AuthLayoutContainer | |||
50 | retryHealthCheck={actions.app.healthCheck} | 47 | retryHealthCheck={actions.app.healthCheck} |
51 | isHealthCheckLoading={app.healthCheckRequest.isExecuting} | 48 | isHealthCheckLoading={app.healthCheckRequest.isExecuting} |
52 | isFullScreen={app.isFullScreen} | 49 | isFullScreen={app.isFullScreen} |
53 | darkMode={app.isSystemDarkModeEnabled} | ||
54 | installAppUpdate={actions.app.installUpdate} | 50 | installAppUpdate={actions.app.installUpdate} |
55 | nextAppReleaseVersion={app.nextAppReleaseVersion} | 51 | nextAppReleaseVersion={app.nextAppReleaseVersion} |
56 | appUpdateIsDownloaded={app.updateStatus === app.updateStatusTypes.DOWNLOADED} | 52 | appUpdateIsDownloaded={app.updateStatus === app.updateStatusTypes.DOWNLOADED} |
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index d290a6094..cf3da71e8 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js | |||
@@ -148,7 +148,6 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
148 | areRequiredRequestsSuccessful={requests.areRequiredRequestsSuccessful} | 148 | areRequiredRequestsSuccessful={requests.areRequiredRequestsSuccessful} |
149 | retryRequiredRequests={retryRequiredRequests} | 149 | retryRequiredRequests={retryRequiredRequests} |
150 | areRequiredRequestsLoading={requests.areRequiredRequestsLoading} | 150 | areRequiredRequestsLoading={requests.areRequiredRequestsLoading} |
151 | darkMode={settings.all.app.darkMode} | ||
152 | isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible} | 151 | isDelayAppScreenVisible={delayAppState.isDelayAppScreenVisible} |
153 | > | 152 | > |
154 | {React.Children.count(children) > 0 ? children : null} | 153 | {React.Children.count(children) > 0 ? children : null} |
diff --git a/src/containers/settings/SettingsWindow.js b/src/containers/settings/SettingsWindow.js index 663b9e2e4..440d32a46 100644 --- a/src/containers/settings/SettingsWindow.js +++ b/src/containers/settings/SettingsWindow.js | |||
@@ -1,4 +1,5 @@ | |||
1 | import React, { Component } from 'react'; | 1 | import React, { Component } from 'react'; |
2 | import ReactDOM from 'react-dom'; | ||
2 | import PropTypes from 'prop-types'; | 3 | import PropTypes from 'prop-types'; |
3 | import { observer, inject } from 'mobx-react'; | 4 | import { observer, inject } from 'mobx-react'; |
4 | 5 | ||
@@ -10,10 +11,23 @@ import ErrorBoundary from '../../components/util/ErrorBoundary'; | |||
10 | import { workspaceStore } from '../../features/workspaces'; | 11 | import { workspaceStore } from '../../features/workspaces'; |
11 | 12 | ||
12 | export default @inject('stores', 'actions') @observer class SettingsContainer extends Component { | 13 | export default @inject('stores', 'actions') @observer class SettingsContainer extends Component { |
14 | portalRoot = document.querySelector('#portalContainer'); | ||
15 | |||
16 | el = document.createElement('div'); | ||
17 | |||
18 | componentDidMount() { | ||
19 | this.portalRoot.appendChild(this.el); | ||
20 | } | ||
21 | |||
22 | componentWillUnmount() { | ||
23 | this.portalRoot.removeChild(this.el); | ||
24 | } | ||
25 | |||
13 | render() { | 26 | render() { |
14 | const { children, stores } = this.props; | 27 | const { children, stores } = this.props; |
15 | const { closeSettings } = this.props.actions.ui; | 28 | const { closeSettings } = this.props.actions.ui; |
16 | 29 | ||
30 | |||
17 | const navigation = ( | 31 | const navigation = ( |
18 | <Navigation | 32 | <Navigation |
19 | serviceCount={stores.services.all.length} | 33 | serviceCount={stores.services.all.length} |
@@ -21,15 +35,18 @@ export default @inject('stores', 'actions') @observer class SettingsContainer ex | |||
21 | /> | 35 | /> |
22 | ); | 36 | ); |
23 | 37 | ||
24 | return ( | 38 | return ReactDOM.createPortal( |
25 | <ErrorBoundary> | 39 | ( |
26 | <Layout | 40 | <ErrorBoundary> |
27 | navigation={navigation} | 41 | <Layout |
28 | closeSettings={closeSettings} | 42 | navigation={navigation} |
29 | > | 43 | closeSettings={closeSettings} |
30 | {children} | 44 | > |
31 | </Layout> | 45 | {children} |
32 | </ErrorBoundary> | 46 | </Layout> |
47 | </ErrorBoundary> | ||
48 | ), | ||
49 | this.el, | ||
33 | ); | 50 | ); |
34 | } | 51 | } |
35 | } | 52 | } |
diff --git a/src/features/announcements/components/AnnouncementScreen.js b/src/features/announcements/components/AnnouncementScreen.js index e7c5fe395..03bd5ba41 100644 --- a/src/features/announcements/components/AnnouncementScreen.js +++ b/src/features/announcements/components/AnnouncementScreen.js | |||
@@ -28,7 +28,7 @@ const smallScreen = '1000px'; | |||
28 | const styles = theme => ({ | 28 | const styles = theme => ({ |
29 | container: { | 29 | container: { |
30 | background: theme.colorBackground, | 30 | background: theme.colorBackground, |
31 | position: 'absolute', | 31 | position: 'relative', |
32 | top: 0, | 32 | top: 0, |
33 | zIndex: 140, | 33 | zIndex: 140, |
34 | width: '100%', | 34 | width: '100%', |
diff --git a/src/features/delayApp/index.js b/src/features/delayApp/index.js index 67f0fc5e6..39fae3b20 100644 --- a/src/features/delayApp/index.js +++ b/src/features/delayApp/index.js | |||
@@ -33,7 +33,7 @@ export default function init(stores) { | |||
33 | }; | 33 | }; |
34 | 34 | ||
35 | reaction( | 35 | reaction( |
36 | () => stores.user.isLoggedIn && stores.features.features.needToWaitToProceed && !stores.user.data.isPremium, | 36 | () => stores.user.isLoggedIn && stores.services.allServicesRequest.wasExecuted && stores.features.features.needToWaitToProceed && !stores.user.data.isPremium, |
37 | (isEnabled) => { | 37 | (isEnabled) => { |
38 | if (isEnabled) { | 38 | if (isEnabled) { |
39 | debug('Enabling `delayApp` feature'); | 39 | debug('Enabling `delayApp` feature'); |
@@ -45,6 +45,7 @@ export default function init(stores) { | |||
45 | 45 | ||
46 | autorun(() => { | 46 | autorun(() => { |
47 | if (stores.services.all.length === 0) { | 47 | if (stores.services.all.length === 0) { |
48 | debug('seas', stores.services.all.length); | ||
48 | shownAfterLaunch = true; | 49 | shownAfterLaunch = true; |
49 | return; | 50 | return; |
50 | } | 51 | } |
@@ -64,7 +65,7 @@ export default function init(stores) { | |||
64 | debug('Resetting app delay'); | 65 | debug('Resetting app delay'); |
65 | 66 | ||
66 | setVisibility(false); | 67 | setVisibility(false); |
67 | }, DEFAULT_FEATURES_CONFIG.needToWaitToProceedConfig.wait + 1000); // timer needs to be able to hit 0 | 68 | }, config.delayDuration + 1000); // timer needs to be able to hit 0 |
68 | } | 69 | } |
69 | }); | 70 | }); |
70 | } else { | 71 | } else { |
diff --git a/src/features/delayApp/styles.js b/src/features/delayApp/styles.js index 5c214cfdf..69c3c7a27 100644 --- a/src/features/delayApp/styles.js +++ b/src/features/delayApp/styles.js | |||
@@ -1,7 +1,6 @@ | |||
1 | export default theme => ({ | 1 | export default theme => ({ |
2 | container: { | 2 | container: { |
3 | background: theme.colorBackground, | 3 | background: theme.colorBackground, |
4 | position: 'absolute', | ||
5 | top: 0, | 4 | top: 0, |
6 | width: '100%', | 5 | width: '100%', |
7 | display: 'flex', | 6 | display: 'flex', |
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index 07b16ff23..a82f6895c 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js | |||
@@ -79,7 +79,7 @@ export default class WorkspacesStore extends FeatureStore { | |||
79 | 79 | ||
80 | // ========== PUBLIC API ========= // | 80 | // ========== PUBLIC API ========= // |
81 | 81 | ||
82 | start(stores, actions) { | 82 | @action start(stores, actions) { |
83 | debug('WorkspacesStore::start'); | 83 | debug('WorkspacesStore::start'); |
84 | this.stores = stores; | 84 | this.stores = stores; |
85 | this.actions = actions; | 85 | this.actions = actions; |
@@ -104,7 +104,7 @@ export default class WorkspacesStore extends FeatureStore { | |||
104 | // REACTIONS | 104 | // REACTIONS |
105 | 105 | ||
106 | this._freeUserReactions = createReactions([ | 106 | this._freeUserReactions = createReactions([ |
107 | this._stopPremiumActionsAndReactions, | 107 | this._disablePremiumFeatures, |
108 | this._openDrawerWithSettingsReaction, | 108 | this._openDrawerWithSettingsReaction, |
109 | this._setFeatureEnabledReaction, | 109 | this._setFeatureEnabledReaction, |
110 | this._setIsPremiumFeatureReaction, | 110 | this._setIsPremiumFeatureReaction, |
@@ -123,10 +123,7 @@ export default class WorkspacesStore extends FeatureStore { | |||
123 | this.isFeatureActive = true; | 123 | this.isFeatureActive = true; |
124 | } | 124 | } |
125 | 125 | ||
126 | stop() { | 126 | @action reset() { |
127 | super.stop(); | ||
128 | debug('WorkspacesStore::stop'); | ||
129 | this.isFeatureActive = false; | ||
130 | this.activeWorkspace = null; | 127 | this.activeWorkspace = null; |
131 | this.nextWorkspace = null; | 128 | this.nextWorkspace = null; |
132 | this.workspaceBeingEdited = null; | 129 | this.workspaceBeingEdited = null; |
@@ -134,6 +131,13 @@ export default class WorkspacesStore extends FeatureStore { | |||
134 | this.isWorkspaceDrawerOpen = false; | 131 | this.isWorkspaceDrawerOpen = false; |
135 | } | 132 | } |
136 | 133 | ||
134 | @action stop() { | ||
135 | super.stop(); | ||
136 | debug('WorkspacesStore::stop'); | ||
137 | this.reset(); | ||
138 | this.isFeatureActive = false; | ||
139 | } | ||
140 | |||
137 | filterServicesByActiveWorkspace = (services) => { | 141 | filterServicesByActiveWorkspace = (services) => { |
138 | const { activeWorkspace, isFeatureActive } = this; | 142 | const { activeWorkspace, isFeatureActive } = this; |
139 | if (isFeatureActive && activeWorkspace) { | 143 | if (isFeatureActive && activeWorkspace) { |
@@ -281,6 +285,7 @@ export default class WorkspacesStore extends FeatureStore { | |||
281 | }; | 285 | }; |
282 | 286 | ||
283 | _activateLastUsedWorkspaceReaction = () => { | 287 | _activateLastUsedWorkspaceReaction = () => { |
288 | debug('_activateLastUsedWorkspaceReaction'); | ||
284 | if (!this.activeWorkspace && this.userHasWorkspaces) { | 289 | if (!this.activeWorkspace && this.userHasWorkspaces) { |
285 | const { lastActiveWorkspace } = this.settings; | 290 | const { lastActiveWorkspace } = this.settings; |
286 | if (lastActiveWorkspace) { | 291 | if (lastActiveWorkspace) { |
@@ -324,10 +329,12 @@ export default class WorkspacesStore extends FeatureStore { | |||
324 | }); | 329 | }); |
325 | }; | 330 | }; |
326 | 331 | ||
327 | _stopPremiumActionsAndReactions = () => { | 332 | _disablePremiumFeatures = () => { |
328 | if (!this.isUserAllowedToUseFeature) { | 333 | if (!this.isUserAllowedToUseFeature) { |
334 | debug('_disablePremiumFeatures'); | ||
329 | this._stopActions(this._premiumUserActions); | 335 | this._stopActions(this._premiumUserActions); |
330 | this._stopReactions(this._premiumUserReactions); | 336 | this._stopReactions(this._premiumUserReactions); |
337 | this.reset(); | ||
331 | } else { | 338 | } else { |
332 | this._startActions(this._premiumUserActions); | 339 | this._startActions(this._premiumUserActions); |
333 | this._startReactions(this._premiumUserReactions); | 340 | this._startReactions(this._premiumUserReactions); |
diff --git a/src/index.html b/src/index.html index bf15e2d4e..f29aa2686 100644 --- a/src/index.html +++ b/src/index.html | |||
@@ -10,6 +10,7 @@ | |||
10 | <div class="window-draggable"></div> | 10 | <div class="window-draggable"></div> |
11 | <div class="dev-warning">DEV MODE</div> | 11 | <div class="dev-warning">DEV MODE</div> |
12 | <div id="root"></div> | 12 | <div id="root"></div> |
13 | <div id="portalContainer"></div> | ||
13 | <script> | 14 | <script> |
14 | document.querySelector('body').classList.add(process.env.OS_PLATFORM ? process.env.OS_PLATFORM : process.platform); | 15 | document.querySelector('body').classList.add(process.env.OS_PLATFORM ? process.env.OS_PLATFORM : process.platform); |
15 | 16 | ||
diff --git a/src/stores/RecipesStore.js b/src/stores/RecipesStore.js index ab64bf79c..d51192078 100644 --- a/src/stores/RecipesStore.js +++ b/src/stores/RecipesStore.js | |||
@@ -20,6 +20,11 @@ export default class RecipesStore extends Store { | |||
20 | // Register action handlers | 20 | // Register action handlers |
21 | this.actions.recipe.install.listen(this._install.bind(this)); | 21 | this.actions.recipe.install.listen(this._install.bind(this)); |
22 | this.actions.recipe.update.listen(this._update.bind(this)); | 22 | this.actions.recipe.update.listen(this._update.bind(this)); |
23 | |||
24 | // Reactions | ||
25 | this.registerReactions([ | ||
26 | this._checkIfRecipeIsInstalled.bind(this), | ||
27 | ]); | ||
23 | } | 28 | } |
24 | 29 | ||
25 | setup() { | 30 | setup() { |
@@ -99,4 +104,26 @@ export default class RecipesStore extends Store { | |||
99 | syncUpdate(0); | 104 | syncUpdate(0); |
100 | } | 105 | } |
101 | } | 106 | } |
107 | |||
108 | async _checkIfRecipeIsInstalled() { | ||
109 | const { router } = this.stores; | ||
110 | |||
111 | const match = matchRoute('/settings/services/add/:id', router.location.pathname); | ||
112 | if (match) { | ||
113 | const recipeId = match.id; | ||
114 | |||
115 | if (!this.stores.recipes.isInstalled(recipeId)) { | ||
116 | router.push('/settings/recipes'); | ||
117 | debug(`Recipe ${recipeId} is not installed, trying to install it`); | ||
118 | |||
119 | const recipe = await this.installRecipeRequest.execute(recipeId)._promise; | ||
120 | if (recipe) { | ||
121 | await this.allRecipesRequest.invalidate({ immediately: true })._promise; | ||
122 | router.push(`/settings/services/add/${recipeId}`); | ||
123 | } else { | ||
124 | router.push('/settings/recipes'); | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | } | ||
102 | } | 129 | } |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index d63302fce..109ac5cd7 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -148,18 +148,7 @@ export default class ServicesStore extends Store { | |||
148 | } | 148 | } |
149 | 149 | ||
150 | async _showAddServiceInterface({ recipeId }) { | 150 | async _showAddServiceInterface({ recipeId }) { |
151 | const recipesStore = this.stores.recipes; | 151 | this.stores.router.push(`/settings/services/add/${recipeId}`); |
152 | |||
153 | if (recipesStore.isInstalled(recipeId)) { | ||
154 | debug(`Recipe ${recipeId} is installed`); | ||
155 | this._redirectToAddServiceRoute(recipeId); | ||
156 | } else { | ||
157 | debug(`Recipe ${recipeId} is not installed`); | ||
158 | // We access the RecipeStore action directly | ||
159 | // returns Promise instead of action | ||
160 | await this.stores.recipes._install({ recipeId }); | ||
161 | this._redirectToAddServiceRoute(recipeId); | ||
162 | } | ||
163 | } | 152 | } |
164 | 153 | ||
165 | // Actions | 154 | // Actions |
@@ -690,11 +679,6 @@ export default class ServicesStore extends Store { | |||
690 | } | 679 | } |
691 | 680 | ||
692 | // Helper | 681 | // Helper |
693 | _redirectToAddServiceRoute(recipeId) { | ||
694 | const route = `/settings/services/add/${recipeId}`; | ||
695 | this.stores.router.push(route); | ||
696 | } | ||
697 | |||
698 | _initializeServiceRecipeInWebview(serviceId) { | 682 | _initializeServiceRecipeInWebview(serviceId) { |
699 | const service = this.one(serviceId); | 683 | const service = this.one(serviceId); |
700 | 684 | ||
diff --git a/src/stores/UIStore.js b/src/stores/UIStore.js index a95a8e1e0..9680c5bcc 100644 --- a/src/stores/UIStore.js +++ b/src/stores/UIStore.js | |||
@@ -1,4 +1,9 @@ | |||
1 | import { action, observable, computed } from 'mobx'; | 1 | import { |
2 | action, | ||
3 | observable, | ||
4 | computed, | ||
5 | reaction, | ||
6 | } from 'mobx'; | ||
2 | import { theme } from '@meetfranz/theme'; | 7 | import { theme } from '@meetfranz/theme'; |
3 | 8 | ||
4 | import Store from './lib/Store'; | 9 | import Store from './lib/Store'; |
@@ -15,10 +20,18 @@ export default class UIStore extends Store { | |||
15 | this.actions.ui.toggleServiceUpdatedInfoBar.listen(this._toggleServiceUpdatedInfoBar.bind(this)); | 20 | this.actions.ui.toggleServiceUpdatedInfoBar.listen(this._toggleServiceUpdatedInfoBar.bind(this)); |
16 | } | 21 | } |
17 | 22 | ||
23 | setup() { | ||
24 | reaction( | ||
25 | () => this.isDarkThemeActive, | ||
26 | () => this._setupThemeInDOM(), | ||
27 | { fireImmediately: true }, | ||
28 | ); | ||
29 | } | ||
30 | |||
18 | @computed get showMessageBadgesEvenWhenMuted() { | 31 | @computed get showMessageBadgesEvenWhenMuted() { |
19 | const settings = this.stores.settings.all; | 32 | const settings = this.stores.settings.all; |
20 | 33 | ||
21 | return (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) || !settings.isAppMuted; | 34 | return (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) || !settings.app.isAppMuted; |
22 | } | 35 | } |
23 | 36 | ||
24 | @computed get isDarkThemeActive() { | 37 | @computed get isDarkThemeActive() { |
@@ -26,7 +39,7 @@ export default class UIStore extends Store { | |||
26 | } | 39 | } |
27 | 40 | ||
28 | @computed get theme() { | 41 | @computed get theme() { |
29 | if (this.isDarkThemeActive) return theme('dark'); | 42 | if (this.isDarkThemeActive || this.stores.settings.app.darkMode) return theme('dark'); |
30 | return theme('default'); | 43 | return theme('default'); |
31 | } | 44 | } |
32 | 45 | ||
@@ -47,4 +60,15 @@ export default class UIStore extends Store { | |||
47 | } | 60 | } |
48 | this.showServicesUpdatedInfoBar = visibility; | 61 | this.showServicesUpdatedInfoBar = visibility; |
49 | } | 62 | } |
63 | |||
64 | // Reactions | ||
65 | _setupThemeInDOM() { | ||
66 | const body = document.querySelector('body'); | ||
67 | |||
68 | if (!this.isDarkThemeActive) { | ||
69 | body.classList.remove('theme__dark'); | ||
70 | } else { | ||
71 | body.classList.add('theme__dark'); | ||
72 | } | ||
73 | } | ||
50 | } | 74 | } |
diff --git a/src/stores/lib/Reaction.js b/src/stores/lib/Reaction.js index f2642908f..f8009b7f6 100644 --- a/src/stores/lib/Reaction.js +++ b/src/stores/lib/Reaction.js | |||
@@ -13,15 +13,15 @@ export default class Reaction { | |||
13 | 13 | ||
14 | start() { | 14 | start() { |
15 | if (!this.isRunning) { | 15 | if (!this.isRunning) { |
16 | this.dispose = autorun(() => this.reaction()); | 16 | this.dispose = autorun(this.reaction); |
17 | this.isActive = true; | 17 | this.isRunning = true; |
18 | } | 18 | } |
19 | } | 19 | } |
20 | 20 | ||
21 | stop() { | 21 | stop() { |
22 | if (this.isRunning) { | 22 | if (this.isRunning) { |
23 | this.dispose(); | 23 | this.dispose(); |
24 | this.isActive = false; | 24 | this.isRunning = false; |
25 | } | 25 | } |
26 | } | 26 | } |
27 | } | 27 | } |
diff --git a/src/styles/layout.scss b/src/styles/layout.scss index e858b7904..9f226b61c 100644 --- a/src/styles/layout.scss +++ b/src/styles/layout.scss | |||
@@ -39,7 +39,7 @@ html { overflow: hidden; } | |||
39 | .app__content { display: flex; } | 39 | .app__content { display: flex; } |
40 | 40 | ||
41 | .app__service { | 41 | .app__service { |
42 | position: relative; | 42 | // position: relative; |
43 | display: flex; | 43 | display: flex; |
44 | flex: 1; | 44 | flex: 1; |
45 | flex-direction: column; | 45 | flex-direction: column; |
diff --git a/src/styles/reset.scss b/src/styles/reset.scss index 80328dcef..f46ede4a2 100644 --- a/src/styles/reset.scss +++ b/src/styles/reset.scss | |||
@@ -64,7 +64,7 @@ body { | |||
64 | font-size: 1.4rem; | 64 | font-size: 1.4rem; |
65 | line-height: 1; | 65 | line-height: 1; |
66 | 66 | ||
67 | .theme__dark { color: $dark-theme-gray-smoke; } | 67 | &.theme__dark { color: $dark-theme-gray-smoke; } |
68 | } | 68 | } |
69 | 69 | ||
70 | * { | 70 | * { |
diff --git a/src/webview/contextMenu.js b/src/webview/contextMenu.js index 967e8e667..a4a6ab899 100644 --- a/src/webview/contextMenu.js +++ b/src/webview/contextMenu.js | |||
@@ -280,13 +280,12 @@ const buildMenuTpl = (props, suggestions, isSpellcheckEnabled, defaultSpellcheck | |||
280 | }; | 280 | }; |
281 | 281 | ||
282 | export default function contextMenu(spellcheckProvider, isSpellcheckEnabled, getDefaultSpellcheckerLanguage, getSpellcheckerLanguage) { | 282 | export default function contextMenu(spellcheckProvider, isSpellcheckEnabled, getDefaultSpellcheckerLanguage, getSpellcheckerLanguage) { |
283 | webContents.on('context-menu', async (e, props) => { | 283 | webContents.on('context-menu', (e, props) => { |
284 | e.preventDefault(); | 284 | e.preventDefault(); |
285 | 285 | ||
286 | let suggestions = []; | 286 | let suggestions = []; |
287 | if (spellcheckProvider && props.misspelledWord) { | 287 | if (spellcheckProvider && props.misspelledWord) { |
288 | debug('Mispelled word', props.misspelledWord); | 288 | suggestions = spellcheckProvider.getSuggestion(props.misspelledWord); |
289 | suggestions = await spellcheckProvider.getSuggestion(props.misspelledWord); | ||
290 | 289 | ||
291 | debug('Suggestions', suggestions); | 290 | debug('Suggestions', suggestions); |
292 | } | 291 | } |
diff --git a/src/webview/spellchecker.js b/src/webview/spellchecker.js index 417d1ea1a..9158b3b94 100644 --- a/src/webview/spellchecker.js +++ b/src/webview/spellchecker.js | |||
@@ -1,8 +1,6 @@ | |||
1 | import { webFrame } from 'electron'; | 1 | import { webFrame } from 'electron'; |
2 | import { attachSpellCheckProvider, SpellCheckerProvider } from 'electron-hunspell'; | 2 | import { SpellCheckerProvider } from 'electron-hunspell'; |
3 | import { ENVIRONMENT } from 'hunspell-asm'; | ||
4 | import path from 'path'; | 3 | import path from 'path'; |
5 | import { readFileSync } from 'fs'; | ||
6 | 4 | ||
7 | import { DICTIONARY_PATH } from '../config'; | 5 | import { DICTIONARY_PATH } from '../config'; |
8 | import { SPELLCHECKER_LOCALES } from '../i18n/languages'; | 6 | import { SPELLCHECKER_LOCALES } from '../i18n/languages'; |
@@ -12,12 +10,11 @@ const debug = require('debug')('Franz:spellchecker'); | |||
12 | let provider; | 10 | let provider; |
13 | let currentDict; | 11 | let currentDict; |
14 | let _isEnabled = false; | 12 | let _isEnabled = false; |
15 | let attached; | ||
16 | 13 | ||
17 | async function loadDictionary(locale) { | 14 | async function loadDictionary(locale) { |
18 | try { | 15 | try { |
19 | const fileLocation = path.join(DICTIONARY_PATH, `hunspell-dict-${locale}/${locale}`); | 16 | const fileLocation = path.join(DICTIONARY_PATH, `hunspell-dict-${locale}/${locale}`); |
20 | await provider.loadDictionary(locale, readFileSync(`${fileLocation}.dic`), readFileSync(`${fileLocation}.aff`)); | 17 | await provider.loadDictionary(locale, `${fileLocation}.dic`, `${fileLocation}.aff`); |
21 | debug('Loaded dictionary', locale, 'from', fileLocation); | 18 | debug('Loaded dictionary', locale, 'from', fileLocation); |
22 | } catch (err) { | 19 | } catch (err) { |
23 | console.error('Could not load dictionary', err); | 20 | console.error('Could not load dictionary', err); |
@@ -44,7 +41,7 @@ export async function switchDict(locale) { | |||
44 | provider.unloadDictionary(locale); | 41 | provider.unloadDictionary(locale); |
45 | } | 42 | } |
46 | loadDictionary(locale); | 43 | loadDictionary(locale); |
47 | attached.switchLanguage(locale); | 44 | provider.switchDictionary(locale); |
48 | 45 | ||
49 | debug('Switched dictionary to', locale); | 46 | debug('Switched dictionary to', locale); |
50 | 47 | ||
@@ -61,14 +58,12 @@ export default async function initialize(languageCode = 'en-us') { | |||
61 | const locale = languageCode.toLowerCase(); | 58 | const locale = languageCode.toLowerCase(); |
62 | 59 | ||
63 | debug('Init spellchecker'); | 60 | debug('Init spellchecker'); |
64 | await provider.initialize({ environment: ENVIRONMENT.NODE }); | 61 | await provider.initialize(); |
65 | 62 | // await loadDictionaries(); | |
66 | debug('Attaching spellcheck provider'); | ||
67 | attached = await attachSpellCheckProvider(provider); | ||
68 | 63 | ||
69 | debug('Available spellchecker dictionaries', provider.availableDictionaries); | 64 | debug('Available spellchecker dictionaries', provider.availableDictionaries); |
70 | 65 | ||
71 | attached.switchLanguage(locale); | 66 | switchDict(locale); |
72 | 67 | ||
73 | return provider; | 68 | return provider; |
74 | } catch (err) { | 69 | } catch (err) { |