diff options
author | 2019-04-12 13:32:19 +0200 | |
---|---|---|
committer | 2019-04-12 13:32:19 +0200 | |
commit | f941074dd7520efb63e9507294df8c420715b9df (patch) | |
tree | 614d03296254f02fe93a67a5c3b2feef1446e3aa /src | |
parent | Don't invalidate user request on componentWillMount (diff) | |
parent | feat(App): Update electron to 4.1.4 (diff) | |
download | ferdium-app-f941074dd7520efb63e9507294df8c420715b9df.tar.gz ferdium-app-f941074dd7520efb63e9507294df8c420715b9df.tar.zst ferdium-app-f941074dd7520efb63e9507294df8c420715b9df.zip |
Merge branch 'develop' into chore/streamline-dashboard
Diffstat (limited to 'src')
65 files changed, 3333 insertions, 317 deletions
diff --git a/src/actions/index.js b/src/actions/index.js index 59acabb0b..00f843cd6 100644 --- a/src/actions/index.js +++ b/src/actions/index.js | |||
@@ -11,6 +11,7 @@ import payment from './payment'; | |||
11 | import news from './news'; | 11 | import news from './news'; |
12 | import settings from './settings'; | 12 | import settings from './settings'; |
13 | import requests from './requests'; | 13 | import requests from './requests'; |
14 | import workspaces from '../features/workspaces/actions'; | ||
14 | 15 | ||
15 | const actions = Object.assign({}, { | 16 | const actions = Object.assign({}, { |
16 | service, | 17 | service, |
@@ -25,4 +26,7 @@ const actions = Object.assign({}, { | |||
25 | requests, | 26 | requests, |
26 | }); | 27 | }); |
27 | 28 | ||
28 | export default defineActions(actions, PropTypes.checkPropTypes); | 29 | export default Object.assign( |
30 | defineActions(actions, PropTypes.checkPropTypes), | ||
31 | { workspaces }, | ||
32 | ); | ||
diff --git a/src/actions/lib/actions.js b/src/actions/lib/actions.js index 6571e9441..2bc7d2711 100644 --- a/src/actions/lib/actions.js +++ b/src/actions/lib/actions.js | |||
@@ -9,6 +9,10 @@ export const createActionsFromDefinitions = (actionDefinitions, validate) => { | |||
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) => { | ||
13 | const { listeners } = action; | ||
14 | listeners.splice(listeners.indexOf(listener), 1); | ||
15 | }; | ||
12 | action.notify = params => action.listeners.forEach(listener => listener(params)); | 16 | action.notify = params => action.listeners.forEach(listener => listener(params)); |
13 | }); | 17 | }); |
14 | return actions; | 18 | return actions; |
diff --git a/src/app.js b/src/app.js index 96454779e..f6092bf60 100644 --- a/src/app.js +++ b/src/app.js | |||
@@ -40,6 +40,9 @@ import PricingScreen from './containers/auth/PricingScreen'; | |||
40 | import InviteScreen from './containers/auth/InviteScreen'; | 40 | import InviteScreen from './containers/auth/InviteScreen'; |
41 | import AuthLayoutContainer from './containers/auth/AuthLayoutContainer'; | 41 | import AuthLayoutContainer from './containers/auth/AuthLayoutContainer'; |
42 | import SubscriptionPopupScreen from './containers/subscription/SubscriptionPopupScreen'; | 42 | import SubscriptionPopupScreen from './containers/subscription/SubscriptionPopupScreen'; |
43 | import WorkspacesScreen from './features/workspaces/containers/WorkspacesScreen'; | ||
44 | import EditWorkspaceScreen from './features/workspaces/containers/EditWorkspaceScreen'; | ||
45 | import { WORKSPACES_ROUTES } from './features/workspaces'; | ||
43 | 46 | ||
44 | // Add Polyfills | 47 | // Add Polyfills |
45 | smoothScroll.polyfill(); | 48 | smoothScroll.polyfill(); |
@@ -76,6 +79,8 @@ window.addEventListener('load', () => { | |||
76 | <Route path="/settings/recipes/:filter" component={RecipesScreen} /> | 79 | <Route path="/settings/recipes/:filter" component={RecipesScreen} /> |
77 | <Route path="/settings/services" component={ServicesScreen} /> | 80 | <Route path="/settings/services" component={ServicesScreen} /> |
78 | <Route path="/settings/services/:action/:id" component={EditServiceScreen} /> | 81 | <Route path="/settings/services/:action/:id" component={EditServiceScreen} /> |
82 | <Route path={WORKSPACES_ROUTES.ROOT} component={WorkspacesScreen} /> | ||
83 | <Route path={WORKSPACES_ROUTES.EDIT} component={EditWorkspaceScreen} /> | ||
79 | <Route path="/settings/user" component={AccountScreen} /> | 84 | <Route path="/settings/user" component={AccountScreen} /> |
80 | <Route path="/settings/user/edit" component={EditUserScreen} /> | 85 | <Route path="/settings/user/edit" component={EditUserScreen} /> |
81 | <Route path="/settings/team" component={TeamScreen} /> | 86 | <Route path="/settings/team" component={TeamScreen} /> |
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index 593149e72..b7f7722dd 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js | |||
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; | |||
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | 3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; |
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | import { TitleBar } from 'electron-react-titlebar'; | 5 | import { TitleBar } from 'electron-react-titlebar'; |
6 | import injectSheet from 'react-jss'; | ||
6 | 7 | ||
7 | import InfoBar from '../ui/InfoBar'; | 8 | import InfoBar from '../ui/InfoBar'; |
8 | import { Component as DelayApp } from '../../features/delayApp'; | 9 | import { Component as DelayApp } from '../../features/delayApp'; |
@@ -13,6 +14,8 @@ import ErrorBoundary from '../util/ErrorBoundary'; | |||
13 | // import globalMessages from '../../i18n/globalMessages'; | 14 | // import globalMessages from '../../i18n/globalMessages'; |
14 | 15 | ||
15 | import { isWindows } from '../../environment'; | 16 | import { isWindows } from '../../environment'; |
17 | import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator'; | ||
18 | import { workspaceStore } from '../../features/workspaces'; | ||
16 | 19 | ||
17 | function createMarkup(HTMLString) { | 20 | function createMarkup(HTMLString) { |
18 | return { __html: HTMLString }; | 21 | return { __html: HTMLString }; |
@@ -45,10 +48,23 @@ const messages = defineMessages({ | |||
45 | }, | 48 | }, |
46 | }); | 49 | }); |
47 | 50 | ||
48 | export default @observer class AppLayout extends Component { | 51 | const styles = theme => ({ |
52 | appContent: { | ||
53 | width: `calc(100% + ${theme.workspaces.drawer.width}px)`, | ||
54 | transition: 'transform 0.5s ease', | ||
55 | transform() { | ||
56 | return workspaceStore.isWorkspaceDrawerOpen ? 'translateX(0)' : `translateX(-${theme.workspaces.drawer.width}px)`; | ||
57 | }, | ||
58 | }, | ||
59 | }); | ||
60 | |||
61 | @injectSheet(styles) @observer | ||
62 | class AppLayout extends Component { | ||
49 | static propTypes = { | 63 | static propTypes = { |
64 | classes: PropTypes.object.isRequired, | ||
50 | isFullScreen: PropTypes.bool.isRequired, | 65 | isFullScreen: PropTypes.bool.isRequired, |
51 | sidebar: PropTypes.element.isRequired, | 66 | sidebar: PropTypes.element.isRequired, |
67 | workspacesDrawer: PropTypes.element.isRequired, | ||
52 | services: PropTypes.element.isRequired, | 68 | services: PropTypes.element.isRequired, |
53 | children: PropTypes.element, | 69 | children: PropTypes.element, |
54 | news: MobxPropTypes.arrayOrObservableArray.isRequired, | 70 | news: MobxPropTypes.arrayOrObservableArray.isRequired, |
@@ -76,7 +92,9 @@ export default @observer class AppLayout extends Component { | |||
76 | 92 | ||
77 | render() { | 93 | render() { |
78 | const { | 94 | const { |
95 | classes, | ||
79 | isFullScreen, | 96 | isFullScreen, |
97 | workspacesDrawer, | ||
80 | sidebar, | 98 | sidebar, |
81 | services, | 99 | services, |
82 | children, | 100 | children, |
@@ -102,9 +120,11 @@ export default @observer class AppLayout extends Component { | |||
102 | <div className={(darkMode ? 'theme__dark' : '')}> | 120 | <div className={(darkMode ? 'theme__dark' : '')}> |
103 | <div className="app"> | 121 | <div className="app"> |
104 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} | 122 | {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} |
105 | <div className="app__content"> | 123 | <div className={`app__content ${classes.appContent}`}> |
124 | {workspacesDrawer} | ||
106 | {sidebar} | 125 | {sidebar} |
107 | <div className="app__service"> | 126 | <div className="app__service"> |
127 | <WorkspaceSwitchingIndicator /> | ||
108 | {news.length > 0 && news.map(item => ( | 128 | {news.length > 0 && news.map(item => ( |
109 | <InfoBar | 129 | <InfoBar |
110 | key={item.id} | 130 | key={item.id} |
@@ -176,3 +196,5 @@ export default @observer class AppLayout extends Component { | |||
176 | ); | 196 | ); |
177 | } | 197 | } |
178 | } | 198 | } |
199 | |||
200 | export default AppLayout; | ||
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js index 609a3b604..36c1f2e39 100644 --- a/src/components/layout/Sidebar.js +++ b/src/components/layout/Sidebar.js | |||
@@ -6,6 +6,8 @@ import { observer } from 'mobx-react'; | |||
6 | 6 | ||
7 | import Tabbar from '../services/tabs/Tabbar'; | 7 | import Tabbar from '../services/tabs/Tabbar'; |
8 | import { ctrlKey } from '../../environment'; | 8 | import { ctrlKey } from '../../environment'; |
9 | import { GA_CATEGORY_WORKSPACES, workspaceStore } from '../../features/workspaces'; | ||
10 | import { gaEvent } from '../../lib/analytics'; | ||
9 | 11 | ||
10 | const messages = defineMessages({ | 12 | const messages = defineMessages({ |
11 | settings: { | 13 | settings: { |
@@ -24,6 +26,14 @@ const messages = defineMessages({ | |||
24 | id: 'sidebar.unmuteApp', | 26 | id: 'sidebar.unmuteApp', |
25 | defaultMessage: '!!!Enable notifications & audio', | 27 | defaultMessage: '!!!Enable notifications & audio', |
26 | }, | 28 | }, |
29 | openWorkspaceDrawer: { | ||
30 | id: 'sidebar.openWorkspaceDrawer', | ||
31 | defaultMessage: '!!!Open workspace drawer', | ||
32 | }, | ||
33 | closeWorkspaceDrawer: { | ||
34 | id: 'sidebar.closeWorkspaceDrawer', | ||
35 | defaultMessage: '!!!Close workspace drawer', | ||
36 | }, | ||
27 | }); | 37 | }); |
28 | 38 | ||
29 | export default @observer class Sidebar extends Component { | 39 | export default @observer class Sidebar extends Component { |
@@ -31,7 +41,9 @@ export default @observer class Sidebar extends Component { | |||
31 | openSettings: PropTypes.func.isRequired, | 41 | openSettings: PropTypes.func.isRequired, |
32 | toggleMuteApp: PropTypes.func.isRequired, | 42 | toggleMuteApp: PropTypes.func.isRequired, |
33 | isAppMuted: PropTypes.bool.isRequired, | 43 | isAppMuted: PropTypes.bool.isRequired, |
34 | } | 44 | isWorkspaceDrawerOpen: PropTypes.bool.isRequired, |
45 | toggleWorkspaceDrawer: PropTypes.func.isRequired, | ||
46 | }; | ||
35 | 47 | ||
36 | static contextTypes = { | 48 | static contextTypes = { |
37 | intl: intlShape, | 49 | intl: intlShape, |
@@ -53,9 +65,23 @@ export default @observer class Sidebar extends Component { | |||
53 | this.setState({ tooltipEnabled: false }); | 65 | this.setState({ tooltipEnabled: false }); |
54 | } | 66 | } |
55 | 67 | ||
68 | updateToolTip() { | ||
69 | this.disableToolTip(); | ||
70 | setTimeout(this.enableToolTip.bind(this)); | ||
71 | } | ||
72 | |||
56 | render() { | 73 | render() { |
57 | const { openSettings, toggleMuteApp, isAppMuted } = this.props; | 74 | const { |
75 | openSettings, | ||
76 | toggleMuteApp, | ||
77 | isAppMuted, | ||
78 | isWorkspaceDrawerOpen, | ||
79 | toggleWorkspaceDrawer, | ||
80 | } = this.props; | ||
58 | const { intl } = this.context; | 81 | const { intl } = this.context; |
82 | const workspaceToggleMessage = ( | ||
83 | isWorkspaceDrawerOpen ? messages.closeWorkspaceDrawer : messages.openWorkspaceDrawer | ||
84 | ); | ||
59 | 85 | ||
60 | return ( | 86 | return ( |
61 | <div className="sidebar"> | 87 | <div className="sidebar"> |
@@ -64,9 +90,26 @@ export default @observer class Sidebar extends Component { | |||
64 | enableToolTip={() => this.enableToolTip()} | 90 | enableToolTip={() => this.enableToolTip()} |
65 | disableToolTip={() => this.disableToolTip()} | 91 | disableToolTip={() => this.disableToolTip()} |
66 | /> | 92 | /> |
93 | {workspaceStore.isFeatureEnabled ? ( | ||
94 | <button | ||
95 | type="button" | ||
96 | onClick={() => { | ||
97 | toggleWorkspaceDrawer(); | ||
98 | this.updateToolTip(); | ||
99 | gaEvent(GA_CATEGORY_WORKSPACES, 'toggleDrawer', 'sidebar'); | ||
100 | }} | ||
101 | className={`sidebar__button sidebar__button--workspaces ${isWorkspaceDrawerOpen ? 'is-active' : ''}`} | ||
102 | data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${ctrlKey}+D)`} | ||
103 | > | ||
104 | <i className="mdi mdi-view-grid" /> | ||
105 | </button> | ||
106 | ) : null} | ||
67 | <button | 107 | <button |
68 | type="button" | 108 | type="button" |
69 | onClick={toggleMuteApp} | 109 | onClick={() => { |
110 | toggleMuteApp(); | ||
111 | this.updateToolTip(); | ||
112 | }} | ||
70 | className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`} | 113 | className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`} |
71 | data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${ctrlKey}+Shift+M)`} | 114 | data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${ctrlKey}+Shift+M)`} |
72 | > | 115 | > |
diff --git a/src/components/services/content/ServiceView.js b/src/components/services/content/ServiceView.js index 5afc54f9d..13148b9b3 100644 --- a/src/components/services/content/ServiceView.js +++ b/src/components/services/content/ServiceView.js | |||
@@ -35,11 +35,13 @@ export default @observer class ServiceView extends Component { | |||
35 | 35 | ||
36 | autorunDisposer = null; | 36 | autorunDisposer = null; |
37 | 37 | ||
38 | forceRepaintTimeout = null; | ||
39 | |||
38 | componentDidMount() { | 40 | componentDidMount() { |
39 | this.autorunDisposer = autorun(() => { | 41 | this.autorunDisposer = autorun(() => { |
40 | if (this.props.service.isActive) { | 42 | if (this.props.service.isActive) { |
41 | this.setState({ forceRepaint: true }); | 43 | this.setState({ forceRepaint: true }); |
42 | setTimeout(() => { | 44 | this.forceRepaintTimeout = setTimeout(() => { |
43 | this.setState({ forceRepaint: false }); | 45 | this.setState({ forceRepaint: false }); |
44 | }, 100); | 46 | }, 100); |
45 | } | 47 | } |
@@ -48,6 +50,7 @@ export default @observer class ServiceView extends Component { | |||
48 | 50 | ||
49 | componentWillUnmount() { | 51 | componentWillUnmount() { |
50 | this.autorunDisposer(); | 52 | this.autorunDisposer(); |
53 | clearTimeout(this.forceRepaintTimeout); | ||
51 | } | 54 | } |
52 | 55 | ||
53 | updateTargetUrl = (event) => { | 56 | updateTargetUrl = (event) => { |
diff --git a/src/components/services/tabs/Tabbar.js b/src/components/services/tabs/Tabbar.js index dd5c2140f..5e8260ad0 100644 --- a/src/components/services/tabs/Tabbar.js +++ b/src/components/services/tabs/Tabbar.js | |||
@@ -19,7 +19,7 @@ export default @observer class TabBar extends Component { | |||
19 | updateService: PropTypes.func.isRequired, | 19 | updateService: PropTypes.func.isRequired, |
20 | showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired, | 20 | showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired, |
21 | showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired, | 21 | showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired, |
22 | } | 22 | }; |
23 | 23 | ||
24 | onSortEnd = ({ oldIndex, newIndex }) => { | 24 | onSortEnd = ({ oldIndex, newIndex }) => { |
25 | const { | 25 | const { |
@@ -45,7 +45,7 @@ export default @observer class TabBar extends Component { | |||
45 | redirect: false, | 45 | redirect: false, |
46 | }); | 46 | }); |
47 | } | 47 | } |
48 | } | 48 | }; |
49 | 49 | ||
50 | disableService({ serviceId }) { | 50 | disableService({ serviceId }) { |
51 | this.toggleService({ serviceId, isEnabled: false }); | 51 | this.toggleService({ serviceId, isEnabled: false }); |
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index 0be1a22ba..cab6f23d7 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js | |||
@@ -2,8 +2,11 @@ import React, { Component } from 'react'; | |||
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import { defineMessages, intlShape } from 'react-intl'; | 3 | import { defineMessages, intlShape } from 'react-intl'; |
4 | import { inject, observer } from 'mobx-react'; | 4 | import { inject, observer } from 'mobx-react'; |
5 | import { ProBadge } from '@meetfranz/ui'; | ||
5 | 6 | ||
6 | import Link from '../../ui/Link'; | 7 | import Link from '../../ui/Link'; |
8 | import { workspaceStore } from '../../../features/workspaces'; | ||
9 | import UIStore from '../../../stores/UIStore'; | ||
7 | 10 | ||
8 | const messages = defineMessages({ | 11 | const messages = defineMessages({ |
9 | availableServices: { | 12 | availableServices: { |
@@ -14,6 +17,10 @@ const messages = defineMessages({ | |||
14 | id: 'settings.navigation.yourServices', | 17 | id: 'settings.navigation.yourServices', |
15 | defaultMessage: '!!!Your services', | 18 | defaultMessage: '!!!Your services', |
16 | }, | 19 | }, |
20 | yourWorkspaces: { | ||
21 | id: 'settings.navigation.yourWorkspaces', | ||
22 | defaultMessage: '!!!Your workspaces', | ||
23 | }, | ||
17 | account: { | 24 | account: { |
18 | id: 'settings.navigation.account', | 25 | id: 'settings.navigation.account', |
19 | defaultMessage: '!!!Account', | 26 | defaultMessage: '!!!Account', |
@@ -38,7 +45,11 @@ const messages = defineMessages({ | |||
38 | 45 | ||
39 | export default @inject('stores') @observer class SettingsNavigation extends Component { | 46 | export default @inject('stores') @observer class SettingsNavigation extends Component { |
40 | static propTypes = { | 47 | static propTypes = { |
48 | stores: PropTypes.shape({ | ||
49 | ui: PropTypes.instanceOf(UIStore).isRequired, | ||
50 | }).isRequired, | ||
41 | serviceCount: PropTypes.number.isRequired, | 51 | serviceCount: PropTypes.number.isRequired, |
52 | workspaceCount: PropTypes.number.isRequired, | ||
42 | }; | 53 | }; |
43 | 54 | ||
44 | static contextTypes = { | 55 | static contextTypes = { |
@@ -46,7 +57,8 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
46 | }; | 57 | }; |
47 | 58 | ||
48 | render() { | 59 | render() { |
49 | const { serviceCount } = this.props; | 60 | const { serviceCount, workspaceCount, stores } = this.props; |
61 | const { isDarkThemeActive } = stores.ui; | ||
50 | const { intl } = this.context; | 62 | const { intl } = this.context; |
51 | 63 | ||
52 | return ( | 64 | return ( |
@@ -67,6 +79,21 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp | |||
67 | {' '} | 79 | {' '} |
68 | <span className="badge">{serviceCount}</span> | 80 | <span className="badge">{serviceCount}</span> |
69 | </Link> | 81 | </Link> |
82 | {workspaceStore.isFeatureEnabled ? ( | ||
83 | <Link | ||
84 | to="/settings/workspaces" | ||
85 | className="settings-navigation__link" | ||
86 | activeClassName="is-active" | ||
87 | > | ||
88 | {intl.formatMessage(messages.yourWorkspaces)} | ||
89 | {' '} | ||
90 | {workspaceStore.isPremiumUpgradeRequired ? ( | ||
91 | <ProBadge inverted={!isDarkThemeActive && workspaceStore.isSettingsRouteActive} /> | ||
92 | ) : ( | ||
93 | <span className="badge">{workspaceCount}</span> | ||
94 | )} | ||
95 | </Link> | ||
96 | ) : null} | ||
70 | <Link | 97 | <Link |
71 | to="/settings/user" | 98 | to="/settings/user" |
72 | className="settings-navigation__link" | 99 | className="settings-navigation__link" |
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js index 21616b5de..4ba2eb844 100644 --- a/src/components/settings/services/EditServiceForm.js +++ b/src/components/settings/services/EditServiceForm.js | |||
@@ -341,14 +341,20 @@ export default @observer class EditServiceForm extends Component { | |||
341 | </div> | 341 | </div> |
342 | </div> | 342 | </div> |
343 | 343 | ||
344 | <PremiumFeatureContainer condition={isSpellcheckerPremiumFeature}> | 344 | <PremiumFeatureContainer |
345 | condition={isSpellcheckerPremiumFeature} | ||
346 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }} | ||
347 | > | ||
345 | <div className="settings__settings-group"> | 348 | <div className="settings__settings-group"> |
346 | <Select field={form.$('spellcheckerLanguage')} /> | 349 | <Select field={form.$('spellcheckerLanguage')} /> |
347 | </div> | 350 | </div> |
348 | </PremiumFeatureContainer> | 351 | </PremiumFeatureContainer> |
349 | 352 | ||
350 | {isProxyFeatureEnabled && ( | 353 | {isProxyFeatureEnabled && ( |
351 | <PremiumFeatureContainer condition={isProxyPremiumFeature}> | 354 | <PremiumFeatureContainer |
355 | condition={isProxyPremiumFeature} | ||
356 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'proxy' }} | ||
357 | > | ||
352 | <div className="settings__settings-group"> | 358 | <div className="settings__settings-group"> |
353 | <h3> | 359 | <h3> |
354 | {intl.formatMessage(messages.headlineProxy)} | 360 | {intl.formatMessage(messages.headlineProxy)} |
diff --git a/src/components/settings/services/ServicesDashboard.js b/src/components/settings/services/ServicesDashboard.js index a12df7372..53bae12df 100644 --- a/src/components/settings/services/ServicesDashboard.js +++ b/src/components/settings/services/ServicesDashboard.js | |||
@@ -65,7 +65,7 @@ export default @observer class ServicesDashboard extends Component { | |||
65 | 65 | ||
66 | static defaultProps = { | 66 | static defaultProps = { |
67 | searchNeedle: '', | 67 | searchNeedle: '', |
68 | } | 68 | }; |
69 | 69 | ||
70 | static contextTypes = { | 70 | static contextTypes = { |
71 | intl: intlShape, | 71 | intl: intlShape, |
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index a92e559f3..8429d0ecb 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js | |||
@@ -170,6 +170,7 @@ export default @observer class EditSettingsForm extends Component { | |||
170 | <Select field={form.$('locale')} showLabel={false} /> | 170 | <Select field={form.$('locale')} showLabel={false} /> |
171 | <PremiumFeatureContainer | 171 | <PremiumFeatureContainer |
172 | condition={isSpellcheckerPremiumFeature} | 172 | condition={isSpellcheckerPremiumFeature} |
173 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }} | ||
173 | > | 174 | > |
174 | <Fragment> | 175 | <Fragment> |
175 | <Toggle | 176 | <Toggle |
diff --git a/src/components/ui/AppLoader/index.js b/src/components/ui/AppLoader/index.js index 61053f6d1..b0c7fed7b 100644 --- a/src/components/ui/AppLoader/index.js +++ b/src/components/ui/AppLoader/index.js | |||
@@ -23,11 +23,11 @@ export default @injectSheet(styles) @withTheme class AppLoader extends Component | |||
23 | static propTypes = { | 23 | static propTypes = { |
24 | classes: PropTypes.object.isRequired, | 24 | classes: PropTypes.object.isRequired, |
25 | theme: PropTypes.object.isRequired, | 25 | theme: PropTypes.object.isRequired, |
26 | } | 26 | }; |
27 | 27 | ||
28 | state = { | 28 | state = { |
29 | step: 0, | 29 | step: 0, |
30 | } | 30 | }; |
31 | 31 | ||
32 | interval = null; | 32 | interval = null; |
33 | 33 | ||
diff --git a/src/components/ui/FullscreenLoader/index.js b/src/components/ui/FullscreenLoader/index.js index 6ecf4d395..06dab1eb6 100644 --- a/src/components/ui/FullscreenLoader/index.js +++ b/src/components/ui/FullscreenLoader/index.js | |||
@@ -16,13 +16,13 @@ export default @observer @withTheme @injectSheet(styles) class FullscreenLoader | |||
16 | theme: PropTypes.object.isRequired, | 16 | theme: PropTypes.object.isRequired, |
17 | spinnerColor: PropTypes.string, | 17 | spinnerColor: PropTypes.string, |
18 | children: PropTypes.node, | 18 | children: PropTypes.node, |
19 | } | 19 | }; |
20 | 20 | ||
21 | static defaultProps = { | 21 | static defaultProps = { |
22 | className: null, | 22 | className: null, |
23 | spinnerColor: null, | 23 | spinnerColor: null, |
24 | children: null, | 24 | children: null, |
25 | } | 25 | }; |
26 | 26 | ||
27 | render() { | 27 | render() { |
28 | const { | 28 | const { |
diff --git a/src/components/ui/Infobox.js b/src/components/ui/Infobox.js index a33c6474a..0917ee9f0 100644 --- a/src/components/ui/Infobox.js +++ b/src/components/ui/Infobox.js | |||
@@ -13,6 +13,8 @@ export default @observer class Infobox extends Component { | |||
13 | ctaLabel: PropTypes.string, | 13 | ctaLabel: PropTypes.string, |
14 | ctaLoading: PropTypes.bool, | 14 | ctaLoading: PropTypes.bool, |
15 | dismissable: PropTypes.bool, | 15 | dismissable: PropTypes.bool, |
16 | onDismiss: PropTypes.func, | ||
17 | onSeen: PropTypes.func, | ||
16 | }; | 18 | }; |
17 | 19 | ||
18 | static defaultProps = { | 20 | static defaultProps = { |
@@ -22,12 +24,19 @@ export default @observer class Infobox extends Component { | |||
22 | ctaOnClick: () => null, | 24 | ctaOnClick: () => null, |
23 | ctaLabel: '', | 25 | ctaLabel: '', |
24 | ctaLoading: false, | 26 | ctaLoading: false, |
27 | onDismiss: () => null, | ||
28 | onSeen: () => null, | ||
25 | }; | 29 | }; |
26 | 30 | ||
27 | state = { | 31 | state = { |
28 | dismissed: false, | 32 | dismissed: false, |
29 | }; | 33 | }; |
30 | 34 | ||
35 | componentDidMount() { | ||
36 | const { onSeen } = this.props; | ||
37 | if (onSeen) onSeen(); | ||
38 | } | ||
39 | |||
31 | render() { | 40 | render() { |
32 | const { | 41 | const { |
33 | children, | 42 | children, |
@@ -37,6 +46,7 @@ export default @observer class Infobox extends Component { | |||
37 | ctaLoading, | 46 | ctaLoading, |
38 | ctaOnClick, | 47 | ctaOnClick, |
39 | dismissable, | 48 | dismissable, |
49 | onDismiss, | ||
40 | } = this.props; | 50 | } = this.props; |
41 | 51 | ||
42 | if (this.state.dismissed) { | 52 | if (this.state.dismissed) { |
@@ -76,9 +86,10 @@ export default @observer class Infobox extends Component { | |||
76 | {dismissable && ( | 86 | {dismissable && ( |
77 | <button | 87 | <button |
78 | type="button" | 88 | type="button" |
79 | onClick={() => this.setState({ | 89 | onClick={() => { |
80 | dismissed: true, | 90 | this.setState({ dismissed: true }); |
81 | })} | 91 | if (onDismiss) onDismiss(); |
92 | }} | ||
82 | className="infobox__delete mdi mdi-close" | 93 | className="infobox__delete mdi mdi-close" |
83 | /> | 94 | /> |
84 | )} | 95 | )} |
diff --git a/src/components/ui/PremiumFeatureContainer/index.js b/src/components/ui/PremiumFeatureContainer/index.js index 67cd6af0b..3c1e0fac3 100644 --- a/src/components/ui/PremiumFeatureContainer/index.js +++ b/src/components/ui/PremiumFeatureContainer/index.js | |||
@@ -9,6 +9,7 @@ import { oneOrManyChildElements } from '../../../prop-types'; | |||
9 | import UserStore from '../../../stores/UserStore'; | 9 | import UserStore from '../../../stores/UserStore'; |
10 | 10 | ||
11 | import styles from './styles'; | 11 | import styles from './styles'; |
12 | import { gaEvent } from '../../../lib/analytics'; | ||
12 | 13 | ||
13 | const messages = defineMessages({ | 14 | const messages = defineMessages({ |
14 | action: { | 15 | action: { |
@@ -17,14 +18,21 @@ const messages = defineMessages({ | |||
17 | }, | 18 | }, |
18 | }); | 19 | }); |
19 | 20 | ||
20 | export default @inject('stores', 'actions') @injectSheet(styles) @observer class PremiumFeatureContainer extends Component { | 21 | @inject('stores', 'actions') @injectSheet(styles) @observer |
22 | class PremiumFeatureContainer extends Component { | ||
21 | static propTypes = { | 23 | static propTypes = { |
22 | classes: PropTypes.object.isRequired, | 24 | classes: PropTypes.object.isRequired, |
23 | condition: PropTypes.bool, | 25 | condition: PropTypes.bool, |
26 | gaEventInfo: PropTypes.shape({ | ||
27 | category: PropTypes.string.isRequired, | ||
28 | event: PropTypes.string.isRequired, | ||
29 | label: PropTypes.string, | ||
30 | }), | ||
24 | }; | 31 | }; |
25 | 32 | ||
26 | static defaultProps = { | 33 | static defaultProps = { |
27 | condition: true, | 34 | condition: true, |
35 | gaEventInfo: null, | ||
28 | }; | 36 | }; |
29 | 37 | ||
30 | static contextTypes = { | 38 | static contextTypes = { |
@@ -38,6 +46,7 @@ export default @inject('stores', 'actions') @injectSheet(styles) @observer class | |||
38 | actions, | 46 | actions, |
39 | condition, | 47 | condition, |
40 | stores, | 48 | stores, |
49 | gaEventInfo, | ||
41 | } = this.props; | 50 | } = this.props; |
42 | 51 | ||
43 | const { intl } = this.context; | 52 | const { intl } = this.context; |
@@ -49,7 +58,13 @@ export default @inject('stores', 'actions') @injectSheet(styles) @observer class | |||
49 | <button | 58 | <button |
50 | className={classes.actionButton} | 59 | className={classes.actionButton} |
51 | type="button" | 60 | type="button" |
52 | onClick={() => actions.ui.openSettings({ path: 'user' })} | 61 | onClick={() => { |
62 | actions.ui.openSettings({ path: 'user' }); | ||
63 | if (gaEventInfo) { | ||
64 | const { category, event, label } = gaEventInfo; | ||
65 | gaEvent(category, event, label); | ||
66 | } | ||
67 | }} | ||
53 | > | 68 | > |
54 | {intl.formatMessage(messages.action)} | 69 | {intl.formatMessage(messages.action)} |
55 | </button> | 70 | </button> |
@@ -73,3 +88,5 @@ PremiumFeatureContainer.wrappedComponent.propTypes = { | |||
73 | }).isRequired, | 88 | }).isRequired, |
74 | }).isRequired, | 89 | }).isRequired, |
75 | }; | 90 | }; |
91 | |||
92 | export default PremiumFeatureContainer; | ||
diff --git a/src/components/ui/PremiumFeatureContainer/styles.js b/src/components/ui/PremiumFeatureContainer/styles.js index 11cbfbb90..41881e044 100644 --- a/src/components/ui/PremiumFeatureContainer/styles.js +++ b/src/components/ui/PremiumFeatureContainer/styles.js | |||
@@ -20,14 +20,14 @@ export default theme => ({ | |||
20 | color: theme.colorSubscriptionContainerActionButtonColor, | 20 | color: theme.colorSubscriptionContainerActionButtonColor, |
21 | 'margin-left': 'auto', | 21 | 'margin-left': 'auto', |
22 | 'border-radius': theme.borderRadiusSmall, | 22 | 'border-radius': theme.borderRadiusSmall, |
23 | padding: [2, 4], | 23 | padding: [4, 8], |
24 | 'font-size': 12, | 24 | 'font-size': 12, |
25 | pointerEvents: 'initial', | 25 | pointerEvents: 'initial', |
26 | }, | 26 | }, |
27 | content: { | 27 | content: { |
28 | opacity: 0.5, | 28 | opacity: 0.5, |
29 | 'margin-top': 20, | 29 | 'margin-top': 20, |
30 | '& :last-child': { | 30 | '& > :last-child': { |
31 | 'margin-bottom': 0, | 31 | 'margin-bottom': 0, |
32 | }, | 32 | }, |
33 | }, | 33 | }, |
diff --git a/src/components/ui/ServiceIcon.js b/src/components/ui/ServiceIcon.js new file mode 100644 index 000000000..0b9155a4e --- /dev/null +++ b/src/components/ui/ServiceIcon.js | |||
@@ -0,0 +1,67 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | ||
4 | import injectSheet from 'react-jss'; | ||
5 | import classnames from 'classnames'; | ||
6 | |||
7 | import ServiceModel from '../../models/Service'; | ||
8 | |||
9 | const styles = theme => ({ | ||
10 | root: { | ||
11 | height: 'auto', | ||
12 | }, | ||
13 | icon: { | ||
14 | width: theme.serviceIcon.width, | ||
15 | }, | ||
16 | isCustomIcon: { | ||
17 | width: theme.serviceIcon.isCustom.width, | ||
18 | border: theme.serviceIcon.isCustom.border, | ||
19 | borderRadius: theme.serviceIcon.isCustom.borderRadius, | ||
20 | }, | ||
21 | isDisabled: { | ||
22 | filter: 'grayscale(100%)', | ||
23 | opacity: '.5', | ||
24 | }, | ||
25 | }); | ||
26 | |||
27 | @injectSheet(styles) @observer | ||
28 | class ServiceIcon extends Component { | ||
29 | static propTypes = { | ||
30 | classes: PropTypes.object.isRequired, | ||
31 | service: PropTypes.instanceOf(ServiceModel).isRequired, | ||
32 | className: PropTypes.string, | ||
33 | }; | ||
34 | |||
35 | static defaultProps = { | ||
36 | className: '', | ||
37 | }; | ||
38 | |||
39 | render() { | ||
40 | const { | ||
41 | classes, | ||
42 | className, | ||
43 | service, | ||
44 | } = this.props; | ||
45 | |||
46 | return ( | ||
47 | <div | ||
48 | className={classnames([ | ||
49 | classes.root, | ||
50 | className, | ||
51 | ])} | ||
52 | > | ||
53 | <img | ||
54 | src={service.icon} | ||
55 | className={classnames([ | ||
56 | classes.icon, | ||
57 | service.isEnabled ? null : classes.isDisabled, | ||
58 | service.hasCustomIcon ? classes.isCustomIcon : null, | ||
59 | ])} | ||
60 | alt="" | ||
61 | /> | ||
62 | </div> | ||
63 | ); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | export default ServiceIcon; | ||
diff --git a/src/components/ui/WebviewLoader/index.js b/src/components/ui/WebviewLoader/index.js index 3a3dbbe49..58b6b6f1b 100644 --- a/src/components/ui/WebviewLoader/index.js +++ b/src/components/ui/WebviewLoader/index.js | |||
@@ -2,23 +2,35 @@ import React, { Component } from 'react'; | |||
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import { observer } from 'mobx-react'; | 3 | import { observer } from 'mobx-react'; |
4 | import injectSheet from 'react-jss'; | 4 | import injectSheet from 'react-jss'; |
5 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | 6 | ||
6 | import FullscreenLoader from '../FullscreenLoader'; | 7 | import FullscreenLoader from '../FullscreenLoader'; |
7 | |||
8 | import styles from './styles'; | 8 | import styles from './styles'; |
9 | 9 | ||
10 | const messages = defineMessages({ | ||
11 | loading: { | ||
12 | id: 'service.webviewLoader.loading', | ||
13 | defaultMessage: '!!!Loading', | ||
14 | }, | ||
15 | }); | ||
16 | |||
10 | export default @observer @injectSheet(styles) class WebviewLoader extends Component { | 17 | export default @observer @injectSheet(styles) class WebviewLoader extends Component { |
11 | static propTypes = { | 18 | static propTypes = { |
12 | name: PropTypes.string.isRequired, | 19 | name: PropTypes.string.isRequired, |
13 | classes: PropTypes.object.isRequired, | 20 | classes: PropTypes.object.isRequired, |
14 | } | 21 | }; |
22 | |||
23 | static contextTypes = { | ||
24 | intl: intlShape, | ||
25 | }; | ||
15 | 26 | ||
16 | render() { | 27 | render() { |
17 | const { classes, name } = this.props; | 28 | const { classes, name } = this.props; |
29 | const { intl } = this.context; | ||
18 | return ( | 30 | return ( |
19 | <FullscreenLoader | 31 | <FullscreenLoader |
20 | className={classes.component} | 32 | className={classes.component} |
21 | title={`Loading ${name}`} | 33 | title={`${intl.formatMessage(messages.loading)} ${name}`} |
22 | /> | 34 | /> |
23 | ); | 35 | ); |
24 | } | 36 | } |
diff --git a/src/config.js b/src/config.js index 05ee07ee5..0a47aa7d7 100644 --- a/src/config.js +++ b/src/config.js | |||
@@ -50,6 +50,8 @@ export const DEFAULT_FEATURES_CONFIG = { | |||
50 | }, | 50 | }, |
51 | isServiceProxyEnabled: false, | 51 | isServiceProxyEnabled: false, |
52 | isServiceProxyPremiumFeature: true, | 52 | isServiceProxyPremiumFeature: true, |
53 | isWorkspacePremiumFeature: true, | ||
54 | isWorkspaceEnabled: false, | ||
53 | }; | 55 | }; |
54 | 56 | ||
55 | export const DEFAULT_WINDOW_OPTIONS = { | 57 | export const DEFAULT_WINDOW_OPTIONS = { |
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js index 5a05ce431..2d855c78f 100644 --- a/src/containers/layout/AppLayoutContainer.js +++ b/src/containers/layout/AppLayoutContainer.js | |||
@@ -20,6 +20,9 @@ import Services from '../../components/services/content/Services'; | |||
20 | import AppLoader from '../../components/ui/AppLoader'; | 20 | import AppLoader from '../../components/ui/AppLoader'; |
21 | 21 | ||
22 | import { state as delayAppState } from '../../features/delayApp'; | 22 | import { state as delayAppState } from '../../features/delayApp'; |
23 | import { workspaceActions } from '../../features/workspaces/actions'; | ||
24 | import WorkspaceDrawer from '../../features/workspaces/components/WorkspaceDrawer'; | ||
25 | import { workspaceStore } from '../../features/workspaces'; | ||
23 | 26 | ||
24 | export default @inject('stores', 'actions') @observer class AppLayoutContainer extends Component { | 27 | export default @inject('stores', 'actions') @observer class AppLayoutContainer extends Component { |
25 | static defaultProps = { | 28 | static defaultProps = { |
@@ -82,6 +85,15 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
82 | ); | 85 | ); |
83 | } | 86 | } |
84 | 87 | ||
88 | const workspacesDrawer = ( | ||
89 | <WorkspaceDrawer | ||
90 | getServicesForWorkspace={workspace => ( | ||
91 | workspace ? workspaceStore.getWorkspaceServices(workspace).map(s => s.name) : services.all.map(s => s.name) | ||
92 | )} | ||
93 | onUpgradeAccountClick={() => openSettings({ path: 'user' })} | ||
94 | /> | ||
95 | ); | ||
96 | |||
85 | const sidebar = ( | 97 | const sidebar = ( |
86 | <Sidebar | 98 | <Sidebar |
87 | services={services.allDisplayed} | 99 | services={services.allDisplayed} |
@@ -96,6 +108,8 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
96 | deleteService={deleteService} | 108 | deleteService={deleteService} |
97 | updateService={updateService} | 109 | updateService={updateService} |
98 | toggleMuteApp={toggleMuteApp} | 110 | toggleMuteApp={toggleMuteApp} |
111 | toggleWorkspaceDrawer={workspaceActions.toggleWorkspaceDrawer} | ||
112 | isWorkspaceDrawerOpen={workspaceStore.isWorkspaceDrawerOpen} | ||
99 | showMessageBadgeWhenMutedSetting={settings.all.app.showMessageBadgeWhenMuted} | 113 | showMessageBadgeWhenMutedSetting={settings.all.app.showMessageBadgeWhenMuted} |
100 | showMessageBadgesEvenWhenMuted={ui.showMessageBadgesEvenWhenMuted} | 114 | showMessageBadgesEvenWhenMuted={ui.showMessageBadgesEvenWhenMuted} |
101 | /> | 115 | /> |
@@ -122,6 +136,7 @@ export default @inject('stores', 'actions') @observer class AppLayoutContainer e | |||
122 | showServicesUpdatedInfoBar={ui.showServicesUpdatedInfoBar} | 136 | showServicesUpdatedInfoBar={ui.showServicesUpdatedInfoBar} |
123 | appUpdateIsDownloaded={app.updateStatus === app.updateStatusTypes.DOWNLOADED} | 137 | appUpdateIsDownloaded={app.updateStatus === app.updateStatusTypes.DOWNLOADED} |
124 | sidebar={sidebar} | 138 | sidebar={sidebar} |
139 | workspacesDrawer={workspacesDrawer} | ||
125 | services={servicesContainer} | 140 | services={servicesContainer} |
126 | news={news.latest} | 141 | news={news.latest} |
127 | removeNewsItem={hide} | 142 | removeNewsItem={hide} |
diff --git a/src/containers/settings/SettingsWindow.js b/src/containers/settings/SettingsWindow.js index 6d9e0ee77..663b9e2e4 100644 --- a/src/containers/settings/SettingsWindow.js +++ b/src/containers/settings/SettingsWindow.js | |||
@@ -7,6 +7,7 @@ import ServicesStore from '../../stores/ServicesStore'; | |||
7 | import Layout from '../../components/settings/SettingsLayout'; | 7 | import Layout from '../../components/settings/SettingsLayout'; |
8 | import Navigation from '../../components/settings/navigation/SettingsNavigation'; | 8 | import Navigation from '../../components/settings/navigation/SettingsNavigation'; |
9 | import ErrorBoundary from '../../components/util/ErrorBoundary'; | 9 | import ErrorBoundary from '../../components/util/ErrorBoundary'; |
10 | import { workspaceStore } from '../../features/workspaces'; | ||
10 | 11 | ||
11 | export default @inject('stores', 'actions') @observer class SettingsContainer extends Component { | 12 | export default @inject('stores', 'actions') @observer class SettingsContainer extends Component { |
12 | render() { | 13 | render() { |
@@ -16,6 +17,7 @@ export default @inject('stores', 'actions') @observer class SettingsContainer ex | |||
16 | const navigation = ( | 17 | const navigation = ( |
17 | <Navigation | 18 | <Navigation |
18 | serviceCount={stores.services.all.length} | 19 | serviceCount={stores.services.all.length} |
20 | workspaceCount={workspaceStore.workspaces.length} | ||
19 | /> | 21 | /> |
20 | ); | 22 | ); |
21 | 23 | ||
diff --git a/src/environment.js b/src/environment.js index e47b373b0..ae7a67e4d 100644 --- a/src/environment.js +++ b/src/environment.js | |||
@@ -46,5 +46,6 @@ if (!isDevMode || (isDevMode && useLiveAPI)) { | |||
46 | } | 46 | } |
47 | 47 | ||
48 | export const API = api; | 48 | export const API = api; |
49 | export const API_VERSION = 'v1'; | ||
49 | export const WS_API = wsApi; | 50 | export const WS_API = wsApi; |
50 | export const WEBSITE = web; | 51 | export const WEBSITE = web; |
diff --git a/src/features/delayApp/Component.js b/src/features/delayApp/Component.js index ff84510e8..ff0f1f2f8 100644 --- a/src/features/delayApp/Component.js +++ b/src/features/delayApp/Component.js | |||
@@ -38,7 +38,7 @@ export default @inject('actions') @injectSheet(styles) @observer class DelayApp | |||
38 | 38 | ||
39 | state = { | 39 | state = { |
40 | countdown: config.delayDuration, | 40 | countdown: config.delayDuration, |
41 | } | 41 | }; |
42 | 42 | ||
43 | countdownInterval = null; | 43 | countdownInterval = null; |
44 | 44 | ||
diff --git a/src/features/delayApp/index.js b/src/features/delayApp/index.js index abc8274cf..67f0fc5e6 100644 --- a/src/features/delayApp/index.js +++ b/src/features/delayApp/index.js | |||
@@ -55,7 +55,7 @@ export default function init(stores) { | |||
55 | 55 | ||
56 | setVisibility(true); | 56 | setVisibility(true); |
57 | gaPage('/delayApp'); | 57 | gaPage('/delayApp'); |
58 | gaEvent('delayApp', 'show', 'Delay App Feature'); | 58 | gaEvent('DelayApp', 'show', 'Delay App Feature'); |
59 | 59 | ||
60 | timeLastDelay = moment(); | 60 | timeLastDelay = moment(); |
61 | shownAfterLaunch = true; | 61 | shownAfterLaunch = true; |
diff --git a/src/features/utils/FeatureStore.js b/src/features/utils/FeatureStore.js new file mode 100644 index 000000000..66b66a104 --- /dev/null +++ b/src/features/utils/FeatureStore.js | |||
@@ -0,0 +1,21 @@ | |||
1 | import Reaction from '../../stores/lib/Reaction'; | ||
2 | |||
3 | export class FeatureStore { | ||
4 | _actions = null; | ||
5 | |||
6 | _reactions = null; | ||
7 | |||
8 | _listenToActions(actions) { | ||
9 | if (this._actions) this._actions.forEach(a => a[0].off(a[1])); | ||
10 | this._actions = []; | ||
11 | actions.forEach(a => this._actions.push(a)); | ||
12 | this._actions.forEach(a => a[0].listen(a[1])); | ||
13 | } | ||
14 | |||
15 | _startReactions(reactions) { | ||
16 | if (this._reactions) this._reactions.forEach(r => r.stop()); | ||
17 | this._reactions = []; | ||
18 | reactions.forEach(r => this._reactions.push(new Reaction(r))); | ||
19 | this._reactions.forEach(r => r.start()); | ||
20 | } | ||
21 | } | ||
diff --git a/src/features/workspaces/actions.js b/src/features/workspaces/actions.js new file mode 100644 index 000000000..a85f8f57f --- /dev/null +++ b/src/features/workspaces/actions.js | |||
@@ -0,0 +1,26 @@ | |||
1 | import PropTypes from 'prop-types'; | ||
2 | import Workspace from './models/Workspace'; | ||
3 | import { createActionsFromDefinitions } from '../../actions/lib/actions'; | ||
4 | |||
5 | export const workspaceActions = createActionsFromDefinitions({ | ||
6 | edit: { | ||
7 | workspace: PropTypes.instanceOf(Workspace).isRequired, | ||
8 | }, | ||
9 | create: { | ||
10 | name: PropTypes.string.isRequired, | ||
11 | }, | ||
12 | delete: { | ||
13 | workspace: PropTypes.instanceOf(Workspace).isRequired, | ||
14 | }, | ||
15 | update: { | ||
16 | workspace: PropTypes.instanceOf(Workspace).isRequired, | ||
17 | }, | ||
18 | activate: { | ||
19 | workspace: PropTypes.instanceOf(Workspace).isRequired, | ||
20 | }, | ||
21 | deactivate: {}, | ||
22 | toggleWorkspaceDrawer: {}, | ||
23 | openWorkspaceSettings: {}, | ||
24 | }, PropTypes.checkPropTypes); | ||
25 | |||
26 | export default workspaceActions; | ||
diff --git a/src/features/workspaces/api.js b/src/features/workspaces/api.js new file mode 100644 index 000000000..0ec20c9ea --- /dev/null +++ b/src/features/workspaces/api.js | |||
@@ -0,0 +1,66 @@ | |||
1 | import { pick } from 'lodash'; | ||
2 | import { sendAuthRequest } from '../../api/utils/auth'; | ||
3 | import { API, API_VERSION } from '../../environment'; | ||
4 | import Request from '../../stores/lib/Request'; | ||
5 | import Workspace from './models/Workspace'; | ||
6 | |||
7 | const debug = require('debug')('Franz:feature:workspaces:api'); | ||
8 | |||
9 | export const workspaceApi = { | ||
10 | getUserWorkspaces: async () => { | ||
11 | const url = `${API}/${API_VERSION}/workspace`; | ||
12 | debug('getUserWorkspaces GET', url); | ||
13 | const result = await sendAuthRequest(url, { method: 'GET' }); | ||
14 | debug('getUserWorkspaces RESULT', result); | ||
15 | if (!result.ok) throw result; | ||
16 | const workspaces = await result.json(); | ||
17 | return workspaces.map(data => new Workspace(data)); | ||
18 | }, | ||
19 | |||
20 | createWorkspace: async (name) => { | ||
21 | const url = `${API}/${API_VERSION}/workspace`; | ||
22 | const options = { | ||
23 | method: 'POST', | ||
24 | body: JSON.stringify({ name }), | ||
25 | }; | ||
26 | debug('createWorkspace POST', url, options); | ||
27 | const result = await sendAuthRequest(url, options); | ||
28 | debug('createWorkspace RESULT', result); | ||
29 | if (!result.ok) throw result; | ||
30 | return new Workspace(await result.json()); | ||
31 | }, | ||
32 | |||
33 | deleteWorkspace: async (workspace) => { | ||
34 | const url = `${API}/${API_VERSION}/workspace/${workspace.id}`; | ||
35 | debug('deleteWorkspace DELETE', url); | ||
36 | const result = await sendAuthRequest(url, { method: 'DELETE' }); | ||
37 | debug('deleteWorkspace RESULT', result); | ||
38 | if (!result.ok) throw result; | ||
39 | return true; | ||
40 | }, | ||
41 | |||
42 | updateWorkspace: async (workspace) => { | ||
43 | const url = `${API}/${API_VERSION}/workspace/${workspace.id}`; | ||
44 | const options = { | ||
45 | method: 'PUT', | ||
46 | body: JSON.stringify(pick(workspace, ['name', 'services'])), | ||
47 | }; | ||
48 | debug('updateWorkspace UPDATE', url, options); | ||
49 | const result = await sendAuthRequest(url, options); | ||
50 | debug('updateWorkspace RESULT', result); | ||
51 | if (!result.ok) throw result; | ||
52 | return new Workspace(await result.json()); | ||
53 | }, | ||
54 | }; | ||
55 | |||
56 | export const getUserWorkspacesRequest = new Request(workspaceApi, 'getUserWorkspaces'); | ||
57 | export const createWorkspaceRequest = new Request(workspaceApi, 'createWorkspace'); | ||
58 | export const deleteWorkspaceRequest = new Request(workspaceApi, 'deleteWorkspace'); | ||
59 | export const updateWorkspaceRequest = new Request(workspaceApi, 'updateWorkspace'); | ||
60 | |||
61 | export const resetApiRequests = () => { | ||
62 | getUserWorkspacesRequest.reset(); | ||
63 | createWorkspaceRequest.reset(); | ||
64 | deleteWorkspaceRequest.reset(); | ||
65 | updateWorkspaceRequest.reset(); | ||
66 | }; | ||
diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js new file mode 100644 index 000000000..2c00ea63c --- /dev/null +++ b/src/features/workspaces/components/CreateWorkspaceForm.js | |||
@@ -0,0 +1,100 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | ||
4 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | import { Input, Button } from '@meetfranz/forms'; | ||
6 | import injectSheet from 'react-jss'; | ||
7 | import Form from '../../../lib/Form'; | ||
8 | import { required } from '../../../helpers/validation-helpers'; | ||
9 | import { gaEvent } from '../../../lib/analytics'; | ||
10 | import { GA_CATEGORY_WORKSPACES } from '../index'; | ||
11 | |||
12 | const messages = defineMessages({ | ||
13 | submitButton: { | ||
14 | id: 'settings.workspace.add.form.submitButton', | ||
15 | defaultMessage: '!!!Create workspace', | ||
16 | }, | ||
17 | name: { | ||
18 | id: 'settings.workspace.add.form.name', | ||
19 | defaultMessage: '!!!Name', | ||
20 | }, | ||
21 | }); | ||
22 | |||
23 | const styles = () => ({ | ||
24 | form: { | ||
25 | display: 'flex', | ||
26 | }, | ||
27 | input: { | ||
28 | flexGrow: 1, | ||
29 | marginRight: '10px', | ||
30 | }, | ||
31 | submitButton: { | ||
32 | height: 'inherit', | ||
33 | }, | ||
34 | }); | ||
35 | |||
36 | @injectSheet(styles) @observer | ||
37 | class CreateWorkspaceForm extends Component { | ||
38 | static contextTypes = { | ||
39 | intl: intlShape, | ||
40 | }; | ||
41 | |||
42 | static propTypes = { | ||
43 | classes: PropTypes.object.isRequired, | ||
44 | isSubmitting: PropTypes.bool.isRequired, | ||
45 | onSubmit: PropTypes.func.isRequired, | ||
46 | }; | ||
47 | |||
48 | form = (() => { | ||
49 | const { intl } = this.context; | ||
50 | return new Form({ | ||
51 | fields: { | ||
52 | name: { | ||
53 | label: intl.formatMessage(messages.name), | ||
54 | placeholder: intl.formatMessage(messages.name), | ||
55 | value: '', | ||
56 | validators: [required], | ||
57 | }, | ||
58 | }, | ||
59 | }); | ||
60 | })(); | ||
61 | |||
62 | submitForm() { | ||
63 | const { form } = this; | ||
64 | form.submit({ | ||
65 | onSuccess: async (f) => { | ||
66 | const { onSubmit } = this.props; | ||
67 | const values = f.values(); | ||
68 | onSubmit(values); | ||
69 | gaEvent(GA_CATEGORY_WORKSPACES, 'create', values.name); | ||
70 | }, | ||
71 | }); | ||
72 | } | ||
73 | |||
74 | render() { | ||
75 | const { intl } = this.context; | ||
76 | const { classes, isSubmitting } = this.props; | ||
77 | const { form } = this; | ||
78 | return ( | ||
79 | <div className={classes.form}> | ||
80 | <Input | ||
81 | className={classes.input} | ||
82 | {...form.$('name').bind()} | ||
83 | showLabel={false} | ||
84 | onEnterKey={this.submitForm.bind(this, form)} | ||
85 | focus | ||
86 | /> | ||
87 | <Button | ||
88 | className={classes.submitButton} | ||
89 | type="submit" | ||
90 | label={intl.formatMessage(messages.submitButton)} | ||
91 | onClick={this.submitForm.bind(this, form)} | ||
92 | busy={isSubmitting} | ||
93 | buttonType={isSubmitting ? 'secondary' : 'primary'} | ||
94 | /> | ||
95 | </div> | ||
96 | ); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | export default CreateWorkspaceForm; | ||
diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js new file mode 100644 index 000000000..bba4485ff --- /dev/null +++ b/src/features/workspaces/components/EditWorkspaceForm.js | |||
@@ -0,0 +1,189 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | ||
4 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | import { Link } from 'react-router'; | ||
6 | import { Input, Button } from '@meetfranz/forms'; | ||
7 | import injectSheet from 'react-jss'; | ||
8 | |||
9 | import Workspace from '../models/Workspace'; | ||
10 | import Service from '../../../models/Service'; | ||
11 | import Form from '../../../lib/Form'; | ||
12 | import { required } from '../../../helpers/validation-helpers'; | ||
13 | import WorkspaceServiceListItem from './WorkspaceServiceListItem'; | ||
14 | import Request from '../../../stores/lib/Request'; | ||
15 | import { gaEvent } from '../../../lib/analytics'; | ||
16 | import { GA_CATEGORY_WORKSPACES } from '../index'; | ||
17 | |||
18 | const messages = defineMessages({ | ||
19 | buttonDelete: { | ||
20 | id: 'settings.workspace.form.buttonDelete', | ||
21 | defaultMessage: '!!!Delete workspace', | ||
22 | }, | ||
23 | buttonSave: { | ||
24 | id: 'settings.workspace.form.buttonSave', | ||
25 | defaultMessage: '!!!Save workspace', | ||
26 | }, | ||
27 | name: { | ||
28 | id: 'settings.workspace.form.name', | ||
29 | defaultMessage: '!!!Name', | ||
30 | }, | ||
31 | yourWorkspaces: { | ||
32 | id: 'settings.workspace.form.yourWorkspaces', | ||
33 | defaultMessage: '!!!Your workspaces', | ||
34 | }, | ||
35 | servicesInWorkspaceHeadline: { | ||
36 | id: 'settings.workspace.form.servicesInWorkspaceHeadline', | ||
37 | defaultMessage: '!!!Services in this Workspace', | ||
38 | }, | ||
39 | }); | ||
40 | |||
41 | const styles = () => ({ | ||
42 | nameInput: { | ||
43 | height: 'auto', | ||
44 | }, | ||
45 | serviceList: { | ||
46 | height: 'auto', | ||
47 | }, | ||
48 | }); | ||
49 | |||
50 | @injectSheet(styles) @observer | ||
51 | class EditWorkspaceForm extends Component { | ||
52 | static contextTypes = { | ||
53 | intl: intlShape, | ||
54 | }; | ||
55 | |||
56 | static propTypes = { | ||
57 | classes: PropTypes.object.isRequired, | ||
58 | onDelete: PropTypes.func.isRequired, | ||
59 | onSave: PropTypes.func.isRequired, | ||
60 | services: PropTypes.arrayOf(PropTypes.instanceOf(Service)).isRequired, | ||
61 | workspace: PropTypes.instanceOf(Workspace).isRequired, | ||
62 | updateWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, | ||
63 | deleteWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, | ||
64 | }; | ||
65 | |||
66 | form = this.prepareWorkspaceForm(this.props.workspace); | ||
67 | |||
68 | componentWillReceiveProps(nextProps) { | ||
69 | const { workspace } = this.props; | ||
70 | if (workspace.id !== nextProps.workspace.id) { | ||
71 | this.form = this.prepareWorkspaceForm(nextProps.workspace); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | prepareWorkspaceForm(workspace) { | ||
76 | const { intl } = this.context; | ||
77 | return new Form({ | ||
78 | fields: { | ||
79 | name: { | ||
80 | label: intl.formatMessage(messages.name), | ||
81 | placeholder: intl.formatMessage(messages.name), | ||
82 | value: workspace.name, | ||
83 | validators: [required], | ||
84 | }, | ||
85 | services: { | ||
86 | value: workspace.services.slice(), | ||
87 | }, | ||
88 | }, | ||
89 | }); | ||
90 | } | ||
91 | |||
92 | save(form) { | ||
93 | form.submit({ | ||
94 | onSuccess: async (f) => { | ||
95 | const { onSave } = this.props; | ||
96 | const values = f.values(); | ||
97 | onSave(values); | ||
98 | gaEvent(GA_CATEGORY_WORKSPACES, 'save'); | ||
99 | }, | ||
100 | onError: async () => {}, | ||
101 | }); | ||
102 | } | ||
103 | |||
104 | delete() { | ||
105 | const { onDelete } = this.props; | ||
106 | onDelete(); | ||
107 | gaEvent(GA_CATEGORY_WORKSPACES, 'delete'); | ||
108 | } | ||
109 | |||
110 | toggleService(service) { | ||
111 | const servicesField = this.form.$('services'); | ||
112 | const serviceIds = servicesField.value; | ||
113 | if (serviceIds.includes(service.id)) { | ||
114 | serviceIds.splice(serviceIds.indexOf(service.id), 1); | ||
115 | } else { | ||
116 | serviceIds.push(service.id); | ||
117 | } | ||
118 | servicesField.set(serviceIds); | ||
119 | } | ||
120 | |||
121 | render() { | ||
122 | const { intl } = this.context; | ||
123 | const { | ||
124 | classes, | ||
125 | workspace, | ||
126 | services, | ||
127 | deleteWorkspaceRequest, | ||
128 | updateWorkspaceRequest, | ||
129 | } = this.props; | ||
130 | const { form } = this; | ||
131 | const workspaceServices = form.$('services').value; | ||
132 | const isDeleting = deleteWorkspaceRequest.isExecuting; | ||
133 | const isSaving = updateWorkspaceRequest.isExecuting; | ||
134 | return ( | ||
135 | <div className="settings__main"> | ||
136 | <div className="settings__header"> | ||
137 | <span className="settings__header-item"> | ||
138 | <Link to="/settings/workspaces"> | ||
139 | {intl.formatMessage(messages.yourWorkspaces)} | ||
140 | </Link> | ||
141 | </span> | ||
142 | <span className="separator" /> | ||
143 | <span className="settings__header-item"> | ||
144 | {workspace.name} | ||
145 | </span> | ||
146 | </div> | ||
147 | <div className="settings__body"> | ||
148 | <div className={classes.nameInput}> | ||
149 | <Input {...form.$('name').bind()} /> | ||
150 | </div> | ||
151 | <h2>{intl.formatMessage(messages.servicesInWorkspaceHeadline)}</h2> | ||
152 | <div className={classes.serviceList}> | ||
153 | {services.map(s => ( | ||
154 | <WorkspaceServiceListItem | ||
155 | key={s.id} | ||
156 | service={s} | ||
157 | isInWorkspace={workspaceServices.includes(s.id)} | ||
158 | onToggle={() => this.toggleService(s)} | ||
159 | /> | ||
160 | ))} | ||
161 | </div> | ||
162 | </div> | ||
163 | <div className="settings__controls"> | ||
164 | {/* ===== Delete Button ===== */} | ||
165 | <Button | ||
166 | label={intl.formatMessage(messages.buttonDelete)} | ||
167 | loaded={false} | ||
168 | busy={isDeleting} | ||
169 | buttonType={isDeleting ? 'secondary' : 'danger'} | ||
170 | className="settings__delete-button" | ||
171 | disabled={isDeleting} | ||
172 | onClick={this.delete.bind(this)} | ||
173 | /> | ||
174 | {/* ===== Save Button ===== */} | ||
175 | <Button | ||
176 | type="submit" | ||
177 | label={intl.formatMessage(messages.buttonSave)} | ||
178 | busy={isSaving} | ||
179 | buttonType={isSaving ? 'secondary' : 'primary'} | ||
180 | onClick={this.save.bind(this, form)} | ||
181 | disabled={isSaving} | ||
182 | /> | ||
183 | </div> | ||
184 | </div> | ||
185 | ); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | export default EditWorkspaceForm; | ||
diff --git a/src/features/workspaces/components/WorkspaceDrawer.js b/src/features/workspaces/components/WorkspaceDrawer.js new file mode 100644 index 000000000..684e50dd0 --- /dev/null +++ b/src/features/workspaces/components/WorkspaceDrawer.js | |||
@@ -0,0 +1,246 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | ||
4 | import injectSheet from 'react-jss'; | ||
5 | import { defineMessages, FormattedHTMLMessage, intlShape } from 'react-intl'; | ||
6 | import { H1, Icon, ProBadge } from '@meetfranz/ui'; | ||
7 | import { Button } from '@meetfranz/forms/lib'; | ||
8 | import ReactTooltip from 'react-tooltip'; | ||
9 | |||
10 | import WorkspaceDrawerItem from './WorkspaceDrawerItem'; | ||
11 | import { workspaceActions } from '../actions'; | ||
12 | import { GA_CATEGORY_WORKSPACES, workspaceStore } from '../index'; | ||
13 | import { gaEvent } from '../../../lib/analytics'; | ||
14 | |||
15 | const messages = defineMessages({ | ||
16 | headline: { | ||
17 | id: 'workspaceDrawer.headline', | ||
18 | defaultMessage: '!!!Workspaces', | ||
19 | }, | ||
20 | allServices: { | ||
21 | id: 'workspaceDrawer.allServices', | ||
22 | defaultMessage: '!!!All services', | ||
23 | }, | ||
24 | workspacesSettingsTooltip: { | ||
25 | id: 'workspaceDrawer.workspacesSettingsTooltip', | ||
26 | defaultMessage: '!!!Workspaces settings', | ||
27 | }, | ||
28 | workspaceFeatureInfo: { | ||
29 | id: 'workspaceDrawer.workspaceFeatureInfo', | ||
30 | defaultMessage: '!!!Info about workspace feature', | ||
31 | }, | ||
32 | premiumCtaButtonLabel: { | ||
33 | id: 'workspaceDrawer.premiumCtaButtonLabel', | ||
34 | defaultMessage: '!!!Create your first workspace', | ||
35 | }, | ||
36 | reactivatePremiumAccount: { | ||
37 | id: 'workspaceDrawer.reactivatePremiumAccountLabel', | ||
38 | defaultMessage: '!!!Reactivate premium account', | ||
39 | }, | ||
40 | addNewWorkspaceLabel: { | ||
41 | id: 'workspaceDrawer.addNewWorkspaceLabel', | ||
42 | defaultMessage: '!!!add new workspace', | ||
43 | }, | ||
44 | premiumFeatureBadge: { | ||
45 | id: 'workspaceDrawer.proFeatureBadge', | ||
46 | defaultMessage: '!!!Premium feature', | ||
47 | }, | ||
48 | }); | ||
49 | |||
50 | const styles = theme => ({ | ||
51 | drawer: { | ||
52 | background: theme.workspaces.drawer.background, | ||
53 | width: `${theme.workspaces.drawer.width}px`, | ||
54 | }, | ||
55 | headline: { | ||
56 | fontSize: '24px', | ||
57 | marginTop: '38px', | ||
58 | marginBottom: '25px', | ||
59 | marginLeft: theme.workspaces.drawer.padding, | ||
60 | }, | ||
61 | headlineProBadge: { | ||
62 | marginRight: 15, | ||
63 | }, | ||
64 | workspacesSettingsButton: { | ||
65 | float: 'right', | ||
66 | marginRight: theme.workspaces.drawer.padding, | ||
67 | marginTop: '2px', | ||
68 | }, | ||
69 | workspacesSettingsButtonIcon: { | ||
70 | fill: theme.workspaces.drawer.buttons.color, | ||
71 | '&:hover': { | ||
72 | fill: theme.workspaces.drawer.buttons.hoverColor, | ||
73 | }, | ||
74 | }, | ||
75 | workspaces: { | ||
76 | height: 'auto', | ||
77 | }, | ||
78 | premiumAnnouncement: { | ||
79 | padding: '20px', | ||
80 | paddingTop: '0', | ||
81 | height: 'auto', | ||
82 | }, | ||
83 | premiumCtaButton: { | ||
84 | marginTop: '20px', | ||
85 | width: '100%', | ||
86 | color: 'white !important', | ||
87 | }, | ||
88 | addNewWorkspaceLabel: { | ||
89 | height: 'auto', | ||
90 | color: theme.workspaces.drawer.buttons.color, | ||
91 | marginTop: 40, | ||
92 | textAlign: 'center', | ||
93 | '& > svg': { | ||
94 | fill: theme.workspaces.drawer.buttons.color, | ||
95 | }, | ||
96 | '& > span': { | ||
97 | fontSize: '13px', | ||
98 | marginLeft: 10, | ||
99 | position: 'relative', | ||
100 | top: -3, | ||
101 | }, | ||
102 | '&:hover': { | ||
103 | color: theme.workspaces.drawer.buttons.hoverColor, | ||
104 | '& > svg': { | ||
105 | fill: theme.workspaces.drawer.buttons.hoverColor, | ||
106 | }, | ||
107 | }, | ||
108 | }, | ||
109 | }); | ||
110 | |||
111 | @injectSheet(styles) @observer | ||
112 | class WorkspaceDrawer extends Component { | ||
113 | static propTypes = { | ||
114 | classes: PropTypes.object.isRequired, | ||
115 | getServicesForWorkspace: PropTypes.func.isRequired, | ||
116 | onUpgradeAccountClick: PropTypes.func.isRequired, | ||
117 | }; | ||
118 | |||
119 | static contextTypes = { | ||
120 | intl: intlShape, | ||
121 | }; | ||
122 | |||
123 | componentDidMount() { | ||
124 | ReactTooltip.rebuild(); | ||
125 | } | ||
126 | |||
127 | render() { | ||
128 | const { | ||
129 | classes, | ||
130 | getServicesForWorkspace, | ||
131 | onUpgradeAccountClick, | ||
132 | } = this.props; | ||
133 | const { intl } = this.context; | ||
134 | const { | ||
135 | activeWorkspace, | ||
136 | isSwitchingWorkspace, | ||
137 | nextWorkspace, | ||
138 | workspaces, | ||
139 | } = workspaceStore; | ||
140 | const actualWorkspace = isSwitchingWorkspace ? nextWorkspace : activeWorkspace; | ||
141 | return ( | ||
142 | <div className={classes.drawer}> | ||
143 | <H1 className={classes.headline}> | ||
144 | {workspaceStore.isPremiumUpgradeRequired && ( | ||
145 | <span | ||
146 | className={classes.headlineProBadge} | ||
147 | data-tip={`${intl.formatMessage(messages.premiumFeatureBadge)}`} | ||
148 | > | ||
149 | <ProBadge /> | ||
150 | </span> | ||
151 | )} | ||
152 | {intl.formatMessage(messages.headline)} | ||
153 | <span | ||
154 | className={classes.workspacesSettingsButton} | ||
155 | onClick={() => { | ||
156 | workspaceActions.openWorkspaceSettings(); | ||
157 | gaEvent(GA_CATEGORY_WORKSPACES, 'settings', 'drawerHeadline'); | ||
158 | }} | ||
159 | data-tip={`${intl.formatMessage(messages.workspacesSettingsTooltip)}`} | ||
160 | > | ||
161 | <Icon | ||
162 | icon="mdiSettings" | ||
163 | size={1.5} | ||
164 | className={classes.workspacesSettingsButtonIcon} | ||
165 | /> | ||
166 | </span> | ||
167 | </H1> | ||
168 | {workspaceStore.isPremiumUpgradeRequired ? ( | ||
169 | <div className={classes.premiumAnnouncement}> | ||
170 | <FormattedHTMLMessage {...messages.workspaceFeatureInfo} /> | ||
171 | {workspaceStore.userHasWorkspaces ? ( | ||
172 | <Button | ||
173 | className={classes.premiumCtaButton} | ||
174 | buttonType="primary" | ||
175 | label={intl.formatMessage(messages.reactivatePremiumAccount)} | ||
176 | icon="mdiStar" | ||
177 | onClick={() => { | ||
178 | onUpgradeAccountClick(); | ||
179 | gaEvent('User', 'upgrade', 'workspaceDrawer'); | ||
180 | }} | ||
181 | /> | ||
182 | ) : ( | ||
183 | <Button | ||
184 | className={classes.premiumCtaButton} | ||
185 | buttonType="primary" | ||
186 | label={intl.formatMessage(messages.premiumCtaButtonLabel)} | ||
187 | icon="mdiPlusBox" | ||
188 | onClick={() => { | ||
189 | workspaceActions.openWorkspaceSettings(); | ||
190 | gaEvent(GA_CATEGORY_WORKSPACES, 'add', 'drawerPremiumCta'); | ||
191 | }} | ||
192 | /> | ||
193 | )} | ||
194 | </div> | ||
195 | ) : ( | ||
196 | <div className={classes.workspaces}> | ||
197 | <WorkspaceDrawerItem | ||
198 | name={intl.formatMessage(messages.allServices)} | ||
199 | onClick={() => { | ||
200 | workspaceActions.deactivate(); | ||
201 | workspaceActions.toggleWorkspaceDrawer(); | ||
202 | gaEvent(GA_CATEGORY_WORKSPACES, 'switch', 'drawer'); | ||
203 | }} | ||
204 | services={getServicesForWorkspace(null)} | ||
205 | isActive={actualWorkspace == null} | ||
206 | /> | ||
207 | {workspaces.map(workspace => ( | ||
208 | <WorkspaceDrawerItem | ||
209 | key={workspace.id} | ||
210 | name={workspace.name} | ||
211 | isActive={actualWorkspace === workspace} | ||
212 | onClick={() => { | ||
213 | if (actualWorkspace === workspace) return; | ||
214 | workspaceActions.activate({ workspace }); | ||
215 | workspaceActions.toggleWorkspaceDrawer(); | ||
216 | gaEvent(GA_CATEGORY_WORKSPACES, 'switch', 'drawer'); | ||
217 | }} | ||
218 | onContextMenuEditClick={() => workspaceActions.edit({ workspace })} | ||
219 | services={getServicesForWorkspace(workspace)} | ||
220 | /> | ||
221 | ))} | ||
222 | <div | ||
223 | className={classes.addNewWorkspaceLabel} | ||
224 | onClick={() => { | ||
225 | workspaceActions.openWorkspaceSettings(); | ||
226 | gaEvent(GA_CATEGORY_WORKSPACES, 'add', 'drawerAddLabel'); | ||
227 | }} | ||
228 | > | ||
229 | <Icon | ||
230 | icon="mdiPlusBox" | ||
231 | size={1} | ||
232 | className={classes.workspacesSettingsButtonIcon} | ||
233 | /> | ||
234 | <span> | ||
235 | {intl.formatMessage(messages.addNewWorkspaceLabel)} | ||
236 | </span> | ||
237 | </div> | ||
238 | </div> | ||
239 | )} | ||
240 | <ReactTooltip place="right" type="dark" effect="solid" /> | ||
241 | </div> | ||
242 | ); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | export default WorkspaceDrawer; | ||
diff --git a/src/features/workspaces/components/WorkspaceDrawerItem.js b/src/features/workspaces/components/WorkspaceDrawerItem.js new file mode 100644 index 000000000..59a2144d3 --- /dev/null +++ b/src/features/workspaces/components/WorkspaceDrawerItem.js | |||
@@ -0,0 +1,137 @@ | |||
1 | import { remote } from 'electron'; | ||
2 | import React, { Component } from 'react'; | ||
3 | import PropTypes from 'prop-types'; | ||
4 | import { observer } from 'mobx-react'; | ||
5 | import injectSheet from 'react-jss'; | ||
6 | import classnames from 'classnames'; | ||
7 | import { defineMessages, intlShape } from 'react-intl'; | ||
8 | |||
9 | const { Menu } = remote; | ||
10 | |||
11 | const messages = defineMessages({ | ||
12 | noServicesAddedYet: { | ||
13 | id: 'workspaceDrawer.item.noServicesAddedYet', | ||
14 | defaultMessage: '!!!No services added yet', | ||
15 | }, | ||
16 | contextMenuEdit: { | ||
17 | id: 'workspaceDrawer.item.contextMenuEdit', | ||
18 | defaultMessage: '!!!edit', | ||
19 | }, | ||
20 | }); | ||
21 | |||
22 | const styles = theme => ({ | ||
23 | item: { | ||
24 | height: '67px', | ||
25 | padding: `15px ${theme.workspaces.drawer.padding}px`, | ||
26 | borderBottom: `1px solid ${theme.workspaces.drawer.listItem.border}`, | ||
27 | transition: 'background-color 300ms ease-out', | ||
28 | '&:first-child': { | ||
29 | borderTop: `1px solid ${theme.workspaces.drawer.listItem.border}`, | ||
30 | }, | ||
31 | '&:hover': { | ||
32 | backgroundColor: theme.workspaces.drawer.listItem.hoverBackground, | ||
33 | }, | ||
34 | }, | ||
35 | isActiveItem: { | ||
36 | backgroundColor: theme.workspaces.drawer.listItem.activeBackground, | ||
37 | '&:hover': { | ||
38 | backgroundColor: theme.workspaces.drawer.listItem.activeBackground, | ||
39 | }, | ||
40 | }, | ||
41 | name: { | ||
42 | marginTop: '4px', | ||
43 | color: theme.workspaces.drawer.listItem.name.color, | ||
44 | }, | ||
45 | activeName: { | ||
46 | color: theme.workspaces.drawer.listItem.name.activeColor, | ||
47 | }, | ||
48 | services: { | ||
49 | display: 'block', | ||
50 | fontSize: '11px', | ||
51 | marginTop: '5px', | ||
52 | color: theme.workspaces.drawer.listItem.services.color, | ||
53 | whiteSpace: 'nowrap', | ||
54 | textOverflow: 'ellipsis', | ||
55 | overflow: 'hidden', | ||
56 | lineHeight: '15px', | ||
57 | }, | ||
58 | activeServices: { | ||
59 | color: theme.workspaces.drawer.listItem.services.active, | ||
60 | }, | ||
61 | }); | ||
62 | |||
63 | @injectSheet(styles) @observer | ||
64 | class WorkspaceDrawerItem extends Component { | ||
65 | static propTypes = { | ||
66 | classes: PropTypes.object.isRequired, | ||
67 | isActive: PropTypes.bool.isRequired, | ||
68 | name: PropTypes.string.isRequired, | ||
69 | onClick: PropTypes.func.isRequired, | ||
70 | services: PropTypes.arrayOf(PropTypes.string).isRequired, | ||
71 | onContextMenuEditClick: PropTypes.func, | ||
72 | }; | ||
73 | |||
74 | static defaultProps = { | ||
75 | onContextMenuEditClick: null, | ||
76 | }; | ||
77 | |||
78 | static contextTypes = { | ||
79 | intl: intlShape, | ||
80 | }; | ||
81 | |||
82 | render() { | ||
83 | const { | ||
84 | classes, | ||
85 | isActive, | ||
86 | name, | ||
87 | onClick, | ||
88 | onContextMenuEditClick, | ||
89 | services, | ||
90 | } = this.props; | ||
91 | const { intl } = this.context; | ||
92 | |||
93 | const contextMenuTemplate = [{ | ||
94 | label: name, | ||
95 | enabled: false, | ||
96 | }, { | ||
97 | type: 'separator', | ||
98 | }, { | ||
99 | label: intl.formatMessage(messages.contextMenuEdit), | ||
100 | click: onContextMenuEditClick, | ||
101 | }]; | ||
102 | |||
103 | const contextMenu = Menu.buildFromTemplate(contextMenuTemplate); | ||
104 | |||
105 | return ( | ||
106 | <div | ||
107 | className={classnames([ | ||
108 | classes.item, | ||
109 | isActive ? classes.isActiveItem : null, | ||
110 | ])} | ||
111 | onClick={onClick} | ||
112 | onContextMenu={() => ( | ||
113 | onContextMenuEditClick && contextMenu.popup(remote.getCurrentWindow()) | ||
114 | )} | ||
115 | > | ||
116 | <span | ||
117 | className={classnames([ | ||
118 | classes.name, | ||
119 | isActive ? classes.activeName : null, | ||
120 | ])} | ||
121 | > | ||
122 | {name} | ||
123 | </span> | ||
124 | <span | ||
125 | className={classnames([ | ||
126 | classes.services, | ||
127 | isActive ? classes.activeServices : null, | ||
128 | ])} | ||
129 | > | ||
130 | {services.length ? services.join(', ') : intl.formatMessage(messages.noServicesAddedYet)} | ||
131 | </span> | ||
132 | </div> | ||
133 | ); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | export default WorkspaceDrawerItem; | ||
diff --git a/src/features/workspaces/components/WorkspaceItem.js b/src/features/workspaces/components/WorkspaceItem.js new file mode 100644 index 000000000..cc4b1a3ba --- /dev/null +++ b/src/features/workspaces/components/WorkspaceItem.js | |||
@@ -0,0 +1,45 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { intlShape } from 'react-intl'; | ||
4 | import { observer } from 'mobx-react'; | ||
5 | import injectSheet from 'react-jss'; | ||
6 | |||
7 | import Workspace from '../models/Workspace'; | ||
8 | |||
9 | const styles = theme => ({ | ||
10 | row: { | ||
11 | height: theme.workspaces.settings.listItems.height, | ||
12 | borderBottom: `1px solid ${theme.workspaces.settings.listItems.borderColor}`, | ||
13 | '&:hover': { | ||
14 | background: theme.workspaces.settings.listItems.hoverBgColor, | ||
15 | }, | ||
16 | }, | ||
17 | columnName: {}, | ||
18 | }); | ||
19 | |||
20 | @injectSheet(styles) @observer | ||
21 | class WorkspaceItem extends Component { | ||
22 | static propTypes = { | ||
23 | classes: PropTypes.object.isRequired, | ||
24 | workspace: PropTypes.instanceOf(Workspace).isRequired, | ||
25 | onItemClick: PropTypes.func.isRequired, | ||
26 | }; | ||
27 | |||
28 | static contextTypes = { | ||
29 | intl: intlShape, | ||
30 | }; | ||
31 | |||
32 | render() { | ||
33 | const { classes, workspace, onItemClick } = this.props; | ||
34 | |||
35 | return ( | ||
36 | <tr className={classes.row}> | ||
37 | <td onClick={() => onItemClick(workspace)}> | ||
38 | {workspace.name} | ||
39 | </td> | ||
40 | </tr> | ||
41 | ); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | export default WorkspaceItem; | ||
diff --git a/src/features/workspaces/components/WorkspaceServiceListItem.js b/src/features/workspaces/components/WorkspaceServiceListItem.js new file mode 100644 index 000000000..e05b21440 --- /dev/null +++ b/src/features/workspaces/components/WorkspaceServiceListItem.js | |||
@@ -0,0 +1,75 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | ||
4 | import injectSheet from 'react-jss'; | ||
5 | import classnames from 'classnames'; | ||
6 | import { Toggle } from '@meetfranz/forms'; | ||
7 | |||
8 | import Service from '../../../models/Service'; | ||
9 | import ServiceIcon from '../../../components/ui/ServiceIcon'; | ||
10 | |||
11 | const styles = theme => ({ | ||
12 | listItem: { | ||
13 | height: theme.workspaces.settings.listItems.height, | ||
14 | borderBottom: `1px solid ${theme.workspaces.settings.listItems.borderColor}`, | ||
15 | display: 'flex', | ||
16 | alignItems: 'center', | ||
17 | }, | ||
18 | serviceIcon: { | ||
19 | padding: theme.workspaces.settings.listItems.padding, | ||
20 | }, | ||
21 | toggle: { | ||
22 | height: 'auto', | ||
23 | margin: 0, | ||
24 | }, | ||
25 | label: { | ||
26 | padding: theme.workspaces.settings.listItems.padding, | ||
27 | flexGrow: 1, | ||
28 | }, | ||
29 | disabledLabel: { | ||
30 | color: theme.workspaces.settings.listItems.disabled.color, | ||
31 | }, | ||
32 | }); | ||
33 | |||
34 | @injectSheet(styles) @observer | ||
35 | class WorkspaceServiceListItem extends Component { | ||
36 | static propTypes = { | ||
37 | classes: PropTypes.object.isRequired, | ||
38 | isInWorkspace: PropTypes.bool.isRequired, | ||
39 | onToggle: PropTypes.func.isRequired, | ||
40 | service: PropTypes.instanceOf(Service).isRequired, | ||
41 | }; | ||
42 | |||
43 | render() { | ||
44 | const { | ||
45 | classes, | ||
46 | isInWorkspace, | ||
47 | onToggle, | ||
48 | service, | ||
49 | } = this.props; | ||
50 | |||
51 | return ( | ||
52 | <div className={classes.listItem}> | ||
53 | <ServiceIcon | ||
54 | className={classes.serviceIcon} | ||
55 | service={service} | ||
56 | /> | ||
57 | <span | ||
58 | className={classnames([ | ||
59 | classes.label, | ||
60 | service.isEnabled ? null : classes.disabledLabel, | ||
61 | ])} | ||
62 | > | ||
63 | {service.name} | ||
64 | </span> | ||
65 | <Toggle | ||
66 | className={classes.toggle} | ||
67 | checked={isInWorkspace} | ||
68 | onChange={onToggle} | ||
69 | /> | ||
70 | </div> | ||
71 | ); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | export default WorkspaceServiceListItem; | ||
diff --git a/src/features/workspaces/components/WorkspaceSwitchingIndicator.js b/src/features/workspaces/components/WorkspaceSwitchingIndicator.js new file mode 100644 index 000000000..c4a800a7b --- /dev/null +++ b/src/features/workspaces/components/WorkspaceSwitchingIndicator.js | |||
@@ -0,0 +1,91 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer } from 'mobx-react'; | ||
4 | import injectSheet from 'react-jss'; | ||
5 | import classnames from 'classnames'; | ||
6 | import { Loader } from '@meetfranz/ui'; | ||
7 | import { defineMessages, intlShape } from 'react-intl'; | ||
8 | |||
9 | import { workspaceStore } from '../index'; | ||
10 | |||
11 | const messages = defineMessages({ | ||
12 | switchingTo: { | ||
13 | id: 'workspaces.switchingIndicator.switchingTo', | ||
14 | defaultMessage: '!!!Switching to', | ||
15 | }, | ||
16 | }); | ||
17 | |||
18 | const styles = theme => ({ | ||
19 | wrapper: { | ||
20 | display: 'flex', | ||
21 | alignItems: 'flex-start', | ||
22 | position: 'absolute', | ||
23 | transition: 'width 0.5s ease', | ||
24 | width: '100%', | ||
25 | marginTop: '20px', | ||
26 | }, | ||
27 | wrapperWhenDrawerIsOpen: { | ||
28 | width: `calc(100% - ${theme.workspaces.drawer.width}px)`, | ||
29 | }, | ||
30 | component: { | ||
31 | background: 'rgba(20, 20, 20, 0.4)', | ||
32 | padding: '10px 20px', | ||
33 | display: 'flex', | ||
34 | width: 'auto', | ||
35 | height: 'auto', | ||
36 | margin: [0, 'auto'], | ||
37 | borderRadius: 6, | ||
38 | alignItems: 'center', | ||
39 | zIndex: 200, | ||
40 | }, | ||
41 | spinner: { | ||
42 | width: 40, | ||
43 | height: 40, | ||
44 | marginRight: 10, | ||
45 | }, | ||
46 | message: { | ||
47 | fontSize: 16, | ||
48 | whiteSpace: 'nowrap', | ||
49 | color: theme.colorAppLoaderSpinner, | ||
50 | }, | ||
51 | }); | ||
52 | |||
53 | @injectSheet(styles) @observer | ||
54 | class WorkspaceSwitchingIndicator extends Component { | ||
55 | static propTypes = { | ||
56 | classes: PropTypes.object.isRequired, | ||
57 | theme: PropTypes.object.isRequired, | ||
58 | }; | ||
59 | |||
60 | static contextTypes = { | ||
61 | intl: intlShape, | ||
62 | }; | ||
63 | |||
64 | render() { | ||
65 | const { classes, theme } = this.props; | ||
66 | const { intl } = this.context; | ||
67 | const { isSwitchingWorkspace, isWorkspaceDrawerOpen, nextWorkspace } = workspaceStore; | ||
68 | if (!isSwitchingWorkspace) return null; | ||
69 | const nextWorkspaceName = nextWorkspace ? nextWorkspace.name : 'All services'; | ||
70 | return ( | ||
71 | <div | ||
72 | className={classnames([ | ||
73 | classes.wrapper, | ||
74 | isWorkspaceDrawerOpen ? classes.wrapperWhenDrawerIsOpen : null, | ||
75 | ])} | ||
76 | > | ||
77 | <div className={classes.component}> | ||
78 | <Loader | ||
79 | className={classes.spinner} | ||
80 | color={theme.workspaces.switchingIndicator.spinnerColor} | ||
81 | /> | ||
82 | <p className={classes.message}> | ||
83 | {`${intl.formatMessage(messages.switchingTo)} ${nextWorkspaceName}`} | ||
84 | </p> | ||
85 | </div> | ||
86 | </div> | ||
87 | ); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | export default WorkspaceSwitchingIndicator; | ||
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js new file mode 100644 index 000000000..dd4381a15 --- /dev/null +++ b/src/features/workspaces/components/WorkspacesDashboard.js | |||
@@ -0,0 +1,195 @@ | |||
1 | import React, { Component, Fragment } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | ||
4 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | import injectSheet from 'react-jss'; | ||
6 | import { Infobox } from '@meetfranz/ui'; | ||
7 | |||
8 | import Loader from '../../../components/ui/Loader'; | ||
9 | import WorkspaceItem from './WorkspaceItem'; | ||
10 | import CreateWorkspaceForm from './CreateWorkspaceForm'; | ||
11 | import Request from '../../../stores/lib/Request'; | ||
12 | import Appear from '../../../components/ui/effects/Appear'; | ||
13 | import { workspaceStore } from '../index'; | ||
14 | import PremiumFeatureContainer from '../../../components/ui/PremiumFeatureContainer'; | ||
15 | |||
16 | const messages = defineMessages({ | ||
17 | headline: { | ||
18 | id: 'settings.workspaces.headline', | ||
19 | defaultMessage: '!!!Your workspaces', | ||
20 | }, | ||
21 | noServicesAdded: { | ||
22 | id: 'settings.workspaces.noWorkspacesAdded', | ||
23 | defaultMessage: '!!!You haven\'t added any workspaces yet.', | ||
24 | }, | ||
25 | workspacesRequestFailed: { | ||
26 | id: 'settings.workspaces.workspacesRequestFailed', | ||
27 | defaultMessage: '!!!Could not load your workspaces', | ||
28 | }, | ||
29 | tryReloadWorkspaces: { | ||
30 | id: 'settings.workspaces.tryReloadWorkspaces', | ||
31 | defaultMessage: '!!!Try again', | ||
32 | }, | ||
33 | updatedInfo: { | ||
34 | id: 'settings.workspaces.updatedInfo', | ||
35 | defaultMessage: '!!!Your changes have been saved', | ||
36 | }, | ||
37 | deletedInfo: { | ||
38 | id: 'settings.workspaces.deletedInfo', | ||
39 | defaultMessage: '!!!Workspace has been deleted', | ||
40 | }, | ||
41 | workspaceFeatureInfo: { | ||
42 | id: 'settings.workspaces.workspaceFeatureInfo', | ||
43 | defaultMessage: '!!!Info about workspace feature', | ||
44 | }, | ||
45 | workspaceFeatureHeadline: { | ||
46 | id: 'settings.workspaces.workspaceFeatureHeadline', | ||
47 | defaultMessage: '!!!Less is More: Introducing Franz Workspaces', | ||
48 | }, | ||
49 | }); | ||
50 | |||
51 | const styles = theme => ({ | ||
52 | table: { | ||
53 | width: '100%', | ||
54 | '& td': { | ||
55 | padding: '10px', | ||
56 | }, | ||
57 | }, | ||
58 | createForm: { | ||
59 | height: 'auto', | ||
60 | }, | ||
61 | appear: { | ||
62 | height: 'auto', | ||
63 | }, | ||
64 | premiumAnnouncement: { | ||
65 | padding: '20px', | ||
66 | backgroundColor: '#3498db', | ||
67 | marginLeft: '-20px', | ||
68 | marginBottom: '20px', | ||
69 | height: 'auto', | ||
70 | color: 'white', | ||
71 | borderRadius: theme.borderRadius, | ||
72 | }, | ||
73 | }); | ||
74 | |||
75 | @injectSheet(styles) @observer | ||
76 | class WorkspacesDashboard extends Component { | ||
77 | static propTypes = { | ||
78 | classes: PropTypes.object.isRequired, | ||
79 | getUserWorkspacesRequest: PropTypes.instanceOf(Request).isRequired, | ||
80 | createWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, | ||
81 | deleteWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, | ||
82 | updateWorkspaceRequest: PropTypes.instanceOf(Request).isRequired, | ||
83 | onCreateWorkspaceSubmit: PropTypes.func.isRequired, | ||
84 | onWorkspaceClick: PropTypes.func.isRequired, | ||
85 | workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, | ||
86 | }; | ||
87 | |||
88 | static contextTypes = { | ||
89 | intl: intlShape, | ||
90 | }; | ||
91 | |||
92 | render() { | ||
93 | const { | ||
94 | classes, | ||
95 | getUserWorkspacesRequest, | ||
96 | createWorkspaceRequest, | ||
97 | deleteWorkspaceRequest, | ||
98 | updateWorkspaceRequest, | ||
99 | onCreateWorkspaceSubmit, | ||
100 | onWorkspaceClick, | ||
101 | workspaces, | ||
102 | } = this.props; | ||
103 | const { intl } = this.context; | ||
104 | return ( | ||
105 | <div className="settings__main"> | ||
106 | <div className="settings__header"> | ||
107 | <h1>{intl.formatMessage(messages.headline)}</h1> | ||
108 | </div> | ||
109 | <div className="settings__body"> | ||
110 | |||
111 | {/* ===== Workspace updated info ===== */} | ||
112 | {updateWorkspaceRequest.wasExecuted && updateWorkspaceRequest.result && ( | ||
113 | <Appear className={classes.appear}> | ||
114 | <Infobox | ||
115 | type="success" | ||
116 | icon="mdiCheckboxMarkedCircleOutline" | ||
117 | dismissable | ||
118 | onUnmount={updateWorkspaceRequest.reset} | ||
119 | > | ||
120 | {intl.formatMessage(messages.updatedInfo)} | ||
121 | </Infobox> | ||
122 | </Appear> | ||
123 | )} | ||
124 | |||
125 | {/* ===== Workspace deleted info ===== */} | ||
126 | {deleteWorkspaceRequest.wasExecuted && deleteWorkspaceRequest.result && ( | ||
127 | <Appear className={classes.appear}> | ||
128 | <Infobox | ||
129 | type="success" | ||
130 | icon="mdiCheckboxMarkedCircleOutline" | ||
131 | dismissable | ||
132 | onUnmount={deleteWorkspaceRequest.reset} | ||
133 | > | ||
134 | {intl.formatMessage(messages.deletedInfo)} | ||
135 | </Infobox> | ||
136 | </Appear> | ||
137 | )} | ||
138 | |||
139 | {workspaceStore.isPremiumUpgradeRequired && ( | ||
140 | <div className={classes.premiumAnnouncement}> | ||
141 | <h2>{intl.formatMessage(messages.workspaceFeatureHeadline)}</h2> | ||
142 | <p>{intl.formatMessage(messages.workspaceFeatureInfo)}</p> | ||
143 | </div> | ||
144 | )} | ||
145 | |||
146 | <PremiumFeatureContainer | ||
147 | condition={workspaceStore.isPremiumFeature} | ||
148 | gaEventInfo={{ category: 'User', event: 'upgrade', label: 'workspaces' }} | ||
149 | > | ||
150 | {/* ===== Create workspace form ===== */} | ||
151 | <div className={classes.createForm}> | ||
152 | <CreateWorkspaceForm | ||
153 | isSubmitting={createWorkspaceRequest.isExecuting} | ||
154 | onSubmit={onCreateWorkspaceSubmit} | ||
155 | /> | ||
156 | </div> | ||
157 | {getUserWorkspacesRequest.isExecuting ? ( | ||
158 | <Loader /> | ||
159 | ) : ( | ||
160 | <Fragment> | ||
161 | {/* ===== Workspace could not be loaded error ===== */} | ||
162 | {getUserWorkspacesRequest.error ? ( | ||
163 | <Infobox | ||
164 | icon="alert" | ||
165 | type="danger" | ||
166 | ctaLabel={intl.formatMessage(messages.tryReloadWorkspaces)} | ||
167 | ctaLoading={getUserWorkspacesRequest.isExecuting} | ||
168 | ctaOnClick={getUserWorkspacesRequest.retry} | ||
169 | > | ||
170 | {intl.formatMessage(messages.workspacesRequestFailed)} | ||
171 | </Infobox> | ||
172 | ) : ( | ||
173 | <table className={classes.table}> | ||
174 | {/* ===== Workspaces list ===== */} | ||
175 | <tbody> | ||
176 | {workspaces.map(workspace => ( | ||
177 | <WorkspaceItem | ||
178 | key={workspace.id} | ||
179 | workspace={workspace} | ||
180 | onItemClick={w => onWorkspaceClick(w)} | ||
181 | /> | ||
182 | ))} | ||
183 | </tbody> | ||
184 | </table> | ||
185 | )} | ||
186 | </Fragment> | ||
187 | )} | ||
188 | </PremiumFeatureContainer> | ||
189 | </div> | ||
190 | </div> | ||
191 | ); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | export default WorkspacesDashboard; | ||
diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.js b/src/features/workspaces/containers/EditWorkspaceScreen.js new file mode 100644 index 000000000..248b40131 --- /dev/null +++ b/src/features/workspaces/containers/EditWorkspaceScreen.js | |||
@@ -0,0 +1,60 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import { inject, observer } from 'mobx-react'; | ||
3 | import PropTypes from 'prop-types'; | ||
4 | |||
5 | import ErrorBoundary from '../../../components/util/ErrorBoundary'; | ||
6 | import EditWorkspaceForm from '../components/EditWorkspaceForm'; | ||
7 | import ServicesStore from '../../../stores/ServicesStore'; | ||
8 | import Workspace from '../models/Workspace'; | ||
9 | import { workspaceStore } from '../index'; | ||
10 | import { deleteWorkspaceRequest, updateWorkspaceRequest } from '../api'; | ||
11 | |||
12 | @inject('stores', 'actions') @observer | ||
13 | class EditWorkspaceScreen extends Component { | ||
14 | static propTypes = { | ||
15 | actions: PropTypes.shape({ | ||
16 | workspace: PropTypes.shape({ | ||
17 | delete: PropTypes.func.isRequired, | ||
18 | }), | ||
19 | }).isRequired, | ||
20 | stores: PropTypes.shape({ | ||
21 | services: PropTypes.instanceOf(ServicesStore).isRequired, | ||
22 | }).isRequired, | ||
23 | }; | ||
24 | |||
25 | onDelete = () => { | ||
26 | const { workspaceBeingEdited } = workspaceStore; | ||
27 | const { actions } = this.props; | ||
28 | if (!workspaceBeingEdited) return null; | ||
29 | actions.workspaces.delete({ workspace: workspaceBeingEdited }); | ||
30 | }; | ||
31 | |||
32 | onSave = (values) => { | ||
33 | const { workspaceBeingEdited } = workspaceStore; | ||
34 | const { actions } = this.props; | ||
35 | const workspace = new Workspace( | ||
36 | Object.assign({}, workspaceBeingEdited, values), | ||
37 | ); | ||
38 | actions.workspaces.update({ workspace }); | ||
39 | }; | ||
40 | |||
41 | render() { | ||
42 | const { workspaceBeingEdited } = workspaceStore; | ||
43 | const { stores } = this.props; | ||
44 | if (!workspaceBeingEdited) return null; | ||
45 | return ( | ||
46 | <ErrorBoundary> | ||
47 | <EditWorkspaceForm | ||
48 | workspace={workspaceBeingEdited} | ||
49 | services={stores.services.all} | ||
50 | onDelete={this.onDelete} | ||
51 | onSave={this.onSave} | ||
52 | updateWorkspaceRequest={updateWorkspaceRequest} | ||
53 | deleteWorkspaceRequest={deleteWorkspaceRequest} | ||
54 | /> | ||
55 | </ErrorBoundary> | ||
56 | ); | ||
57 | } | ||
58 | } | ||
59 | |||
60 | export default EditWorkspaceScreen; | ||
diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js new file mode 100644 index 000000000..2ab565fa1 --- /dev/null +++ b/src/features/workspaces/containers/WorkspacesScreen.js | |||
@@ -0,0 +1,42 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import { inject, observer } from 'mobx-react'; | ||
3 | import PropTypes from 'prop-types'; | ||
4 | import WorkspacesDashboard from '../components/WorkspacesDashboard'; | ||
5 | import ErrorBoundary from '../../../components/util/ErrorBoundary'; | ||
6 | import { workspaceStore } from '../index'; | ||
7 | import { | ||
8 | createWorkspaceRequest, | ||
9 | deleteWorkspaceRequest, | ||
10 | getUserWorkspacesRequest, | ||
11 | updateWorkspaceRequest, | ||
12 | } from '../api'; | ||
13 | |||
14 | @inject('actions') @observer | ||
15 | class WorkspacesScreen extends Component { | ||
16 | static propTypes = { | ||
17 | actions: PropTypes.shape({ | ||
18 | workspace: PropTypes.shape({ | ||
19 | edit: PropTypes.func.isRequired, | ||
20 | }), | ||
21 | }).isRequired, | ||
22 | }; | ||
23 | |||
24 | render() { | ||
25 | const { actions } = this.props; | ||
26 | return ( | ||
27 | <ErrorBoundary> | ||
28 | <WorkspacesDashboard | ||
29 | workspaces={workspaceStore.workspaces} | ||
30 | getUserWorkspacesRequest={getUserWorkspacesRequest} | ||
31 | createWorkspaceRequest={createWorkspaceRequest} | ||
32 | deleteWorkspaceRequest={deleteWorkspaceRequest} | ||
33 | updateWorkspaceRequest={updateWorkspaceRequest} | ||
34 | onCreateWorkspaceSubmit={data => actions.workspaces.create(data)} | ||
35 | onWorkspaceClick={w => actions.workspaces.edit({ workspace: w })} | ||
36 | /> | ||
37 | </ErrorBoundary> | ||
38 | ); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | export default WorkspacesScreen; | ||
diff --git a/src/features/workspaces/index.js b/src/features/workspaces/index.js new file mode 100644 index 000000000..ad9023b8b --- /dev/null +++ b/src/features/workspaces/index.js | |||
@@ -0,0 +1,37 @@ | |||
1 | import { reaction } from 'mobx'; | ||
2 | import WorkspacesStore from './store'; | ||
3 | import { resetApiRequests } from './api'; | ||
4 | |||
5 | const debug = require('debug')('Franz:feature:workspaces'); | ||
6 | |||
7 | export const GA_CATEGORY_WORKSPACES = 'Workspaces'; | ||
8 | |||
9 | export const workspaceStore = new WorkspacesStore(); | ||
10 | |||
11 | export default function initWorkspaces(stores, actions) { | ||
12 | stores.workspaces = workspaceStore; | ||
13 | const { features } = stores; | ||
14 | |||
15 | // Toggle workspace feature | ||
16 | reaction( | ||
17 | () => features.features.isWorkspaceEnabled, | ||
18 | (isEnabled) => { | ||
19 | if (isEnabled && !workspaceStore.isFeatureActive) { | ||
20 | debug('Initializing `workspaces` feature'); | ||
21 | workspaceStore.start(stores, actions); | ||
22 | } else if (workspaceStore.isFeatureActive) { | ||
23 | debug('Disabling `workspaces` feature'); | ||
24 | workspaceStore.stop(); | ||
25 | resetApiRequests(); | ||
26 | } | ||
27 | }, | ||
28 | { | ||
29 | fireImmediately: true, | ||
30 | }, | ||
31 | ); | ||
32 | } | ||
33 | |||
34 | export const WORKSPACES_ROUTES = { | ||
35 | ROOT: '/settings/workspaces', | ||
36 | EDIT: '/settings/workspaces/:action/:id', | ||
37 | }; | ||
diff --git a/src/features/workspaces/models/Workspace.js b/src/features/workspaces/models/Workspace.js new file mode 100644 index 000000000..6c73d7095 --- /dev/null +++ b/src/features/workspaces/models/Workspace.js | |||
@@ -0,0 +1,25 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | |||
3 | export default class Workspace { | ||
4 | id = null; | ||
5 | |||
6 | @observable name = null; | ||
7 | |||
8 | @observable order = null; | ||
9 | |||
10 | @observable services = []; | ||
11 | |||
12 | @observable userId = null; | ||
13 | |||
14 | constructor(data) { | ||
15 | if (!data.id) { | ||
16 | throw Error('Workspace requires Id'); | ||
17 | } | ||
18 | |||
19 | this.id = data.id; | ||
20 | this.name = data.name; | ||
21 | this.order = data.order; | ||
22 | this.services.replace(data.services); | ||
23 | this.userId = data.userId; | ||
24 | } | ||
25 | } | ||
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js new file mode 100644 index 000000000..ea601700e --- /dev/null +++ b/src/features/workspaces/store.js | |||
@@ -0,0 +1,276 @@ | |||
1 | import { | ||
2 | computed, | ||
3 | observable, | ||
4 | action, | ||
5 | } from 'mobx'; | ||
6 | import localStorage from 'mobx-localstorage'; | ||
7 | import { matchRoute } from '../../helpers/routing-helpers'; | ||
8 | import { workspaceActions } from './actions'; | ||
9 | import { FeatureStore } from '../utils/FeatureStore'; | ||
10 | import { | ||
11 | createWorkspaceRequest, | ||
12 | deleteWorkspaceRequest, | ||
13 | getUserWorkspacesRequest, | ||
14 | updateWorkspaceRequest, | ||
15 | } from './api'; | ||
16 | import { WORKSPACES_ROUTES } from './index'; | ||
17 | |||
18 | const debug = require('debug')('Franz:feature:workspaces:store'); | ||
19 | |||
20 | export default class WorkspacesStore extends FeatureStore { | ||
21 | @observable isFeatureEnabled = false; | ||
22 | |||
23 | @observable isFeatureActive = false; | ||
24 | |||
25 | @observable isPremiumFeature = true; | ||
26 | |||
27 | @observable isPremiumUpgradeRequired = true; | ||
28 | |||
29 | @observable activeWorkspace = null; | ||
30 | |||
31 | @observable nextWorkspace = null; | ||
32 | |||
33 | @observable workspaceBeingEdited = null; | ||
34 | |||
35 | @observable isSwitchingWorkspace = false; | ||
36 | |||
37 | @observable isWorkspaceDrawerOpen = false; | ||
38 | |||
39 | @observable isSettingsRouteActive = null; | ||
40 | |||
41 | @computed get workspaces() { | ||
42 | if (!this.isFeatureActive) return []; | ||
43 | return getUserWorkspacesRequest.result || []; | ||
44 | } | ||
45 | |||
46 | @computed get settings() { | ||
47 | return localStorage.getItem('workspaces') || {}; | ||
48 | } | ||
49 | |||
50 | @computed get userHasWorkspaces() { | ||
51 | return getUserWorkspacesRequest.wasExecuted && this.workspaces.length > 0; | ||
52 | } | ||
53 | |||
54 | start(stores, actions) { | ||
55 | debug('WorkspacesStore::start'); | ||
56 | this.stores = stores; | ||
57 | this.actions = actions; | ||
58 | |||
59 | this._listenToActions([ | ||
60 | [workspaceActions.edit, this._edit], | ||
61 | [workspaceActions.create, this._create], | ||
62 | [workspaceActions.delete, this._delete], | ||
63 | [workspaceActions.update, this._update], | ||
64 | [workspaceActions.activate, this._setActiveWorkspace], | ||
65 | [workspaceActions.deactivate, this._deactivateActiveWorkspace], | ||
66 | [workspaceActions.toggleWorkspaceDrawer, this._toggleWorkspaceDrawer], | ||
67 | [workspaceActions.openWorkspaceSettings, this._openWorkspaceSettings], | ||
68 | ]); | ||
69 | |||
70 | this._startReactions([ | ||
71 | this._setWorkspaceBeingEditedReaction, | ||
72 | this._setActiveServiceOnWorkspaceSwitchReaction, | ||
73 | this._setFeatureEnabledReaction, | ||
74 | this._setIsPremiumFeatureReaction, | ||
75 | this._activateLastUsedWorkspaceReaction, | ||
76 | this._openDrawerWithSettingsReaction, | ||
77 | this._cleanupInvalidServiceReferences, | ||
78 | ]); | ||
79 | |||
80 | getUserWorkspacesRequest.execute(); | ||
81 | this.isFeatureActive = true; | ||
82 | } | ||
83 | |||
84 | stop() { | ||
85 | debug('WorkspacesStore::stop'); | ||
86 | this.isFeatureActive = false; | ||
87 | this.activeWorkspace = null; | ||
88 | this.nextWorkspace = null; | ||
89 | this.workspaceBeingEdited = null; | ||
90 | this.isSwitchingWorkspace = false; | ||
91 | this.isWorkspaceDrawerOpen = false; | ||
92 | } | ||
93 | |||
94 | filterServicesByActiveWorkspace = (services) => { | ||
95 | const { activeWorkspace, isFeatureActive } = this; | ||
96 | if (isFeatureActive && activeWorkspace) { | ||
97 | return this.getWorkspaceServices(activeWorkspace); | ||
98 | } | ||
99 | return services; | ||
100 | }; | ||
101 | |||
102 | getWorkspaceServices(workspace) { | ||
103 | const { services } = this.stores; | ||
104 | return workspace.services.map(id => services.one(id)).filter(s => !!s); | ||
105 | } | ||
106 | |||
107 | // ========== PRIVATE ========= // | ||
108 | |||
109 | _wasDrawerOpenBeforeSettingsRoute = null; | ||
110 | |||
111 | _getWorkspaceById = id => this.workspaces.find(w => w.id === id); | ||
112 | |||
113 | _updateSettings = (changes) => { | ||
114 | localStorage.setItem('workspaces', { | ||
115 | ...this.settings, | ||
116 | ...changes, | ||
117 | }); | ||
118 | }; | ||
119 | |||
120 | // Actions | ||
121 | |||
122 | @action _edit = ({ workspace }) => { | ||
123 | this.stores.router.push(`/settings/workspaces/edit/${workspace.id}`); | ||
124 | }; | ||
125 | |||
126 | @action _create = async ({ name }) => { | ||
127 | try { | ||
128 | const workspace = await createWorkspaceRequest.execute(name); | ||
129 | await getUserWorkspacesRequest.result.push(workspace); | ||
130 | this._edit({ workspace }); | ||
131 | } catch (error) { | ||
132 | throw error; | ||
133 | } | ||
134 | }; | ||
135 | |||
136 | @action _delete = async ({ workspace }) => { | ||
137 | try { | ||
138 | await deleteWorkspaceRequest.execute(workspace); | ||
139 | await getUserWorkspacesRequest.result.remove(workspace); | ||
140 | this.stores.router.push('/settings/workspaces'); | ||
141 | } catch (error) { | ||
142 | throw error; | ||
143 | } | ||
144 | }; | ||
145 | |||
146 | @action _update = async ({ workspace }) => { | ||
147 | try { | ||
148 | await updateWorkspaceRequest.execute(workspace); | ||
149 | // Path local result optimistically | ||
150 | const localWorkspace = this._getWorkspaceById(workspace.id); | ||
151 | Object.assign(localWorkspace, workspace); | ||
152 | this.stores.router.push('/settings/workspaces'); | ||
153 | } catch (error) { | ||
154 | throw error; | ||
155 | } | ||
156 | }; | ||
157 | |||
158 | @action _setActiveWorkspace = ({ workspace }) => { | ||
159 | // Indicate that we are switching to another workspace | ||
160 | this.isSwitchingWorkspace = true; | ||
161 | this.nextWorkspace = workspace; | ||
162 | // Delay switching to next workspace so that the services loading does not drag down UI | ||
163 | setTimeout(() => { | ||
164 | this.activeWorkspace = workspace; | ||
165 | this._updateSettings({ lastActiveWorkspace: workspace.id }); | ||
166 | }, 100); | ||
167 | // Indicate that we are done switching to the next workspace | ||
168 | setTimeout(() => { | ||
169 | this.isSwitchingWorkspace = false; | ||
170 | this.nextWorkspace = null; | ||
171 | }, 1000); | ||
172 | }; | ||
173 | |||
174 | @action _deactivateActiveWorkspace = () => { | ||
175 | // Indicate that we are switching to default workspace | ||
176 | this.isSwitchingWorkspace = true; | ||
177 | this.nextWorkspace = null; | ||
178 | this._updateSettings({ lastActiveWorkspace: null }); | ||
179 | // Delay switching to next workspace so that the services loading does not drag down UI | ||
180 | setTimeout(() => { | ||
181 | this.activeWorkspace = null; | ||
182 | }, 100); | ||
183 | // Indicate that we are done switching to the default workspace | ||
184 | setTimeout(() => { this.isSwitchingWorkspace = false; }, 1000); | ||
185 | }; | ||
186 | |||
187 | @action _toggleWorkspaceDrawer = () => { | ||
188 | this.isWorkspaceDrawerOpen = !this.isWorkspaceDrawerOpen; | ||
189 | }; | ||
190 | |||
191 | @action _openWorkspaceSettings = () => { | ||
192 | this.actions.ui.openSettings({ path: 'workspaces' }); | ||
193 | }; | ||
194 | |||
195 | // Reactions | ||
196 | |||
197 | _setFeatureEnabledReaction = () => { | ||
198 | const { isWorkspaceEnabled } = this.stores.features.features; | ||
199 | this.isFeatureEnabled = isWorkspaceEnabled; | ||
200 | }; | ||
201 | |||
202 | _setIsPremiumFeatureReaction = () => { | ||
203 | const { features, user } = this.stores; | ||
204 | const { isPremium } = user.data; | ||
205 | const { isWorkspacePremiumFeature } = features.features; | ||
206 | this.isPremiumFeature = isWorkspacePremiumFeature; | ||
207 | this.isPremiumUpgradeRequired = isWorkspacePremiumFeature && !isPremium; | ||
208 | }; | ||
209 | |||
210 | _setWorkspaceBeingEditedReaction = () => { | ||
211 | const { pathname } = this.stores.router.location; | ||
212 | const match = matchRoute('/settings/workspaces/edit/:id', pathname); | ||
213 | if (match) { | ||
214 | this.workspaceBeingEdited = this._getWorkspaceById(match.id); | ||
215 | } | ||
216 | }; | ||
217 | |||
218 | _setActiveServiceOnWorkspaceSwitchReaction = () => { | ||
219 | if (!this.isFeatureActive) return; | ||
220 | if (this.activeWorkspace) { | ||
221 | const services = this.stores.services.allDisplayed; | ||
222 | const activeService = services.find(s => s.isActive); | ||
223 | const workspaceServices = this.getWorkspaceServices(this.activeWorkspace); | ||
224 | if (workspaceServices.length <= 0) return; | ||
225 | const isActiveServiceInWorkspace = workspaceServices.includes(activeService); | ||
226 | if (!isActiveServiceInWorkspace) { | ||
227 | this.actions.service.setActive({ serviceId: workspaceServices[0].id }); | ||
228 | } | ||
229 | } | ||
230 | }; | ||
231 | |||
232 | _activateLastUsedWorkspaceReaction = () => { | ||
233 | if (!this.activeWorkspace && this.userHasWorkspaces) { | ||
234 | const { lastActiveWorkspace } = this.settings; | ||
235 | if (lastActiveWorkspace) { | ||
236 | const workspace = this._getWorkspaceById(lastActiveWorkspace); | ||
237 | if (workspace) this._setActiveWorkspace({ workspace }); | ||
238 | } | ||
239 | } | ||
240 | }; | ||
241 | |||
242 | _openDrawerWithSettingsReaction = () => { | ||
243 | const { router } = this.stores; | ||
244 | const isWorkspaceSettingsRoute = router.location.pathname.includes(WORKSPACES_ROUTES.ROOT); | ||
245 | const isSwitchingToSettingsRoute = !this.isSettingsRouteActive && isWorkspaceSettingsRoute; | ||
246 | const isLeavingSettingsRoute = !isWorkspaceSettingsRoute && this.isSettingsRouteActive; | ||
247 | |||
248 | if (isSwitchingToSettingsRoute) { | ||
249 | this.isSettingsRouteActive = true; | ||
250 | this._wasDrawerOpenBeforeSettingsRoute = this.isWorkspaceDrawerOpen; | ||
251 | if (!this._wasDrawerOpenBeforeSettingsRoute) { | ||
252 | workspaceActions.toggleWorkspaceDrawer(); | ||
253 | } | ||
254 | } else if (isLeavingSettingsRoute) { | ||
255 | this.isSettingsRouteActive = false; | ||
256 | if (!this._wasDrawerOpenBeforeSettingsRoute && this.isWorkspaceDrawerOpen) { | ||
257 | workspaceActions.toggleWorkspaceDrawer(); | ||
258 | } | ||
259 | } | ||
260 | }; | ||
261 | |||
262 | _cleanupInvalidServiceReferences = () => { | ||
263 | const { services } = this.stores; | ||
264 | let invalidServiceReferencesExist = false; | ||
265 | this.workspaces.forEach((workspace) => { | ||
266 | workspace.services.forEach((serviceId) => { | ||
267 | if (!services.one(serviceId)) { | ||
268 | invalidServiceReferencesExist = true; | ||
269 | } | ||
270 | }); | ||
271 | }); | ||
272 | if (invalidServiceReferencesExist) { | ||
273 | getUserWorkspacesRequest.execute(); | ||
274 | } | ||
275 | }; | ||
276 | } | ||
diff --git a/src/i18n/locales/de.json b/src/i18n/locales/de.json index 2560a5add..06a03db65 100644 --- a/src/i18n/locales/de.json +++ b/src/i18n/locales/de.json | |||
@@ -87,6 +87,9 @@ | |||
87 | "menu.window" : "Fenster", | 87 | "menu.window" : "Fenster", |
88 | "menu.window.close" : "Schließen", | 88 | "menu.window.close" : "Schließen", |
89 | "menu.window.minimize" : "Minimieren", | 89 | "menu.window.minimize" : "Minimieren", |
90 | "menu.workspaces": "Workspaces", | ||
91 | "menu.workspaces.defaultWorkspace": "All services", | ||
92 | "menu.workspaces.addNewWorkspace": "Add New Workspace", | ||
90 | "password.email.label" : "E-Mail Adresse", | 93 | "password.email.label" : "E-Mail Adresse", |
91 | "password.headline" : "Passwort zurücksetzen", | 94 | "password.headline" : "Passwort zurücksetzen", |
92 | "password.link.login" : "An Deinem Konto anmelden", | 95 | "password.link.login" : "An Deinem Konto anmelden", |
@@ -169,6 +172,7 @@ | |||
169 | "settings.navigation.logout" : "Abmelden", | 172 | "settings.navigation.logout" : "Abmelden", |
170 | "settings.navigation.settings" : "Einstellungen", | 173 | "settings.navigation.settings" : "Einstellungen", |
171 | "settings.navigation.yourServices" : "Deine Dienste", | 174 | "settings.navigation.yourServices" : "Deine Dienste", |
175 | "settings.navigation.yourWorkspaces": "Deine Workspaces", | ||
172 | "settings.recipes.all" : "Alle Dienste", | 176 | "settings.recipes.all" : "Alle Dienste", |
173 | "settings.recipes.dev" : "Entwicklung", | 177 | "settings.recipes.dev" : "Entwicklung", |
174 | "settings.recipes.headline" : "Verfügbare Dienste", | 178 | "settings.recipes.headline" : "Verfügbare Dienste", |
@@ -226,6 +230,14 @@ | |||
226 | "settings.services.tooltip.isMuted" : "Alle Töne sind deaktiviert", | 230 | "settings.services.tooltip.isMuted" : "Alle Töne sind deaktiviert", |
227 | "settings.services.tooltip.notificationsDisabled" : "Benachrichtigungen deaktiviert", | 231 | "settings.services.tooltip.notificationsDisabled" : "Benachrichtigungen deaktiviert", |
228 | "settings.services.updatedInfo" : "Deine Änderungen wurden gespeichert", | 232 | "settings.services.updatedInfo" : "Deine Änderungen wurden gespeichert", |
233 | "settings.workspaces.headline": "Deine Workspaces", | ||
234 | "settings.workspace.add.form.submitButton": "Workspace erstellen", | ||
235 | "settings.workspace.add.form.name": "Name", | ||
236 | "settings.workspace.form.yourWorkspaces": "Deine Workspaces", | ||
237 | "settings.workspace.form.name": "Name", | ||
238 | "settings.workspace.form.buttonDelete": "Workspace löschen", | ||
239 | "settings.workspace.form.buttonSave": "Workspace speichern", | ||
240 | "settings.workspace.form.servicesInWorkspaceHeadline": "Services in diesem Workspace", | ||
229 | "settings.user.form.accountType.company" : "Firma", | 241 | "settings.user.form.accountType.company" : "Firma", |
230 | "settings.user.form.accountType.individual" : "Einzelperson", | 242 | "settings.user.form.accountType.individual" : "Einzelperson", |
231 | "settings.user.form.accountType.label" : "Konto-Typ", | 243 | "settings.user.form.accountType.label" : "Konto-Typ", |
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 650bfc65f..8fe5e8852 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json | |||
@@ -625,78 +625,78 @@ | |||
625 | "defaultMessage": "!!!Your services have been updated.", | 625 | "defaultMessage": "!!!Your services have been updated.", |
626 | "end": { | 626 | "end": { |
627 | "column": 3, | 627 | "column": 3, |
628 | "line": 25 | 628 | "line": 28 |
629 | }, | 629 | }, |
630 | "file": "src/components/layout/AppLayout.js", | 630 | "file": "src/components/layout/AppLayout.js", |
631 | "id": "infobar.servicesUpdated", | 631 | "id": "infobar.servicesUpdated", |
632 | "start": { | 632 | "start": { |
633 | "column": 19, | 633 | "column": 19, |
634 | "line": 22 | 634 | "line": 25 |
635 | } | 635 | } |
636 | }, | 636 | }, |
637 | { | 637 | { |
638 | "defaultMessage": "!!!A new update for Franz is available.", | 638 | "defaultMessage": "!!!A new update for Franz is available.", |
639 | "end": { | 639 | "end": { |
640 | "column": 3, | 640 | "column": 3, |
641 | "line": 29 | 641 | "line": 32 |
642 | }, | 642 | }, |
643 | "file": "src/components/layout/AppLayout.js", | 643 | "file": "src/components/layout/AppLayout.js", |
644 | "id": "infobar.updateAvailable", | 644 | "id": "infobar.updateAvailable", |
645 | "start": { | 645 | "start": { |
646 | "column": 19, | 646 | "column": 19, |
647 | "line": 26 | 647 | "line": 29 |
648 | } | 648 | } |
649 | }, | 649 | }, |
650 | { | 650 | { |
651 | "defaultMessage": "!!!Reload services", | 651 | "defaultMessage": "!!!Reload services", |
652 | "end": { | 652 | "end": { |
653 | "column": 3, | 653 | "column": 3, |
654 | "line": 33 | 654 | "line": 36 |
655 | }, | 655 | }, |
656 | "file": "src/components/layout/AppLayout.js", | 656 | "file": "src/components/layout/AppLayout.js", |
657 | "id": "infobar.buttonReloadServices", | 657 | "id": "infobar.buttonReloadServices", |
658 | "start": { | 658 | "start": { |
659 | "column": 24, | 659 | "column": 24, |
660 | "line": 30 | 660 | "line": 33 |
661 | } | 661 | } |
662 | }, | 662 | }, |
663 | { | 663 | { |
664 | "defaultMessage": "!!!Changelog", | 664 | "defaultMessage": "!!!Changelog", |
665 | "end": { | 665 | "end": { |
666 | "column": 3, | 666 | "column": 3, |
667 | "line": 37 | 667 | "line": 40 |
668 | }, | 668 | }, |
669 | "file": "src/components/layout/AppLayout.js", | 669 | "file": "src/components/layout/AppLayout.js", |
670 | "id": "infobar.buttonChangelog", | 670 | "id": "infobar.buttonChangelog", |
671 | "start": { | 671 | "start": { |
672 | "column": 13, | 672 | "column": 13, |
673 | "line": 34 | 673 | "line": 37 |
674 | } | 674 | } |
675 | }, | 675 | }, |
676 | { | 676 | { |
677 | "defaultMessage": "!!!Restart & install update", | 677 | "defaultMessage": "!!!Restart & install update", |
678 | "end": { | 678 | "end": { |
679 | "column": 3, | 679 | "column": 3, |
680 | "line": 41 | 680 | "line": 44 |
681 | }, | 681 | }, |
682 | "file": "src/components/layout/AppLayout.js", | 682 | "file": "src/components/layout/AppLayout.js", |
683 | "id": "infobar.buttonInstallUpdate", | 683 | "id": "infobar.buttonInstallUpdate", |
684 | "start": { | 684 | "start": { |
685 | "column": 23, | 685 | "column": 23, |
686 | "line": 38 | 686 | "line": 41 |
687 | } | 687 | } |
688 | }, | 688 | }, |
689 | { | 689 | { |
690 | "defaultMessage": "!!!Could not load services and user information", | 690 | "defaultMessage": "!!!Could not load services and user information", |
691 | "end": { | 691 | "end": { |
692 | "column": 3, | 692 | "column": 3, |
693 | "line": 45 | 693 | "line": 48 |
694 | }, | 694 | }, |
695 | "file": "src/components/layout/AppLayout.js", | 695 | "file": "src/components/layout/AppLayout.js", |
696 | "id": "infobar.requiredRequestsFailed", | 696 | "id": "infobar.requiredRequestsFailed", |
697 | "start": { | 697 | "start": { |
698 | "column": 26, | 698 | "column": 26, |
699 | "line": 42 | 699 | "line": 45 |
700 | } | 700 | } |
701 | } | 701 | } |
702 | ], | 702 | ], |
@@ -708,52 +708,78 @@ | |||
708 | "defaultMessage": "!!!Settings", | 708 | "defaultMessage": "!!!Settings", |
709 | "end": { | 709 | "end": { |
710 | "column": 3, | 710 | "column": 3, |
711 | "line": 14 | 711 | "line": 16 |
712 | }, | 712 | }, |
713 | "file": "src/components/layout/Sidebar.js", | 713 | "file": "src/components/layout/Sidebar.js", |
714 | "id": "sidebar.settings", | 714 | "id": "sidebar.settings", |
715 | "start": { | 715 | "start": { |
716 | "column": 12, | 716 | "column": 12, |
717 | "line": 11 | 717 | "line": 13 |
718 | } | 718 | } |
719 | }, | 719 | }, |
720 | { | 720 | { |
721 | "defaultMessage": "!!!Add new service", | 721 | "defaultMessage": "!!!Add new service", |
722 | "end": { | 722 | "end": { |
723 | "column": 3, | 723 | "column": 3, |
724 | "line": 18 | 724 | "line": 20 |
725 | }, | 725 | }, |
726 | "file": "src/components/layout/Sidebar.js", | 726 | "file": "src/components/layout/Sidebar.js", |
727 | "id": "sidebar.addNewService", | 727 | "id": "sidebar.addNewService", |
728 | "start": { | 728 | "start": { |
729 | "column": 17, | 729 | "column": 17, |
730 | "line": 15 | 730 | "line": 17 |
731 | } | 731 | } |
732 | }, | 732 | }, |
733 | { | 733 | { |
734 | "defaultMessage": "!!!Disable notifications & audio", | 734 | "defaultMessage": "!!!Disable notifications & audio", |
735 | "end": { | 735 | "end": { |
736 | "column": 3, | 736 | "column": 3, |
737 | "line": 22 | 737 | "line": 24 |
738 | }, | 738 | }, |
739 | "file": "src/components/layout/Sidebar.js", | 739 | "file": "src/components/layout/Sidebar.js", |
740 | "id": "sidebar.muteApp", | 740 | "id": "sidebar.muteApp", |
741 | "start": { | 741 | "start": { |
742 | "column": 8, | 742 | "column": 8, |
743 | "line": 19 | 743 | "line": 21 |
744 | } | 744 | } |
745 | }, | 745 | }, |
746 | { | 746 | { |
747 | "defaultMessage": "!!!Enable notifications & audio", | 747 | "defaultMessage": "!!!Enable notifications & audio", |
748 | "end": { | 748 | "end": { |
749 | "column": 3, | 749 | "column": 3, |
750 | "line": 26 | 750 | "line": 28 |
751 | }, | 751 | }, |
752 | "file": "src/components/layout/Sidebar.js", | 752 | "file": "src/components/layout/Sidebar.js", |
753 | "id": "sidebar.unmuteApp", | 753 | "id": "sidebar.unmuteApp", |
754 | "start": { | 754 | "start": { |
755 | "column": 10, | 755 | "column": 10, |
756 | "line": 23 | 756 | "line": 25 |
757 | } | ||
758 | }, | ||
759 | { | ||
760 | "defaultMessage": "!!!Open workspace drawer", | ||
761 | "end": { | ||
762 | "column": 3, | ||
763 | "line": 32 | ||
764 | }, | ||
765 | "file": "src/components/layout/Sidebar.js", | ||
766 | "id": "sidebar.openWorkspaceDrawer", | ||
767 | "start": { | ||
768 | "column": 23, | ||
769 | "line": 29 | ||
770 | } | ||
771 | }, | ||
772 | { | ||
773 | "defaultMessage": "!!!Close workspace drawer", | ||
774 | "end": { | ||
775 | "column": 3, | ||
776 | "line": 36 | ||
777 | }, | ||
778 | "file": "src/components/layout/Sidebar.js", | ||
779 | "id": "sidebar.closeWorkspaceDrawer", | ||
780 | "start": { | ||
781 | "column": 24, | ||
782 | "line": 33 | ||
757 | } | 783 | } |
758 | } | 784 | } |
759 | ], | 785 | ], |
@@ -1276,46 +1302,59 @@ | |||
1276 | "defaultMessage": "!!!Available services", | 1302 | "defaultMessage": "!!!Available services", |
1277 | "end": { | 1303 | "end": { |
1278 | "column": 3, | 1304 | "column": 3, |
1279 | "line": 12 | 1305 | "line": 15 |
1280 | }, | 1306 | }, |
1281 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1307 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1282 | "id": "settings.navigation.availableServices", | 1308 | "id": "settings.navigation.availableServices", |
1283 | "start": { | 1309 | "start": { |
1284 | "column": 21, | 1310 | "column": 21, |
1285 | "line": 9 | 1311 | "line": 12 |
1286 | } | 1312 | } |
1287 | }, | 1313 | }, |
1288 | { | 1314 | { |
1289 | "defaultMessage": "!!!Your services", | 1315 | "defaultMessage": "!!!Your services", |
1290 | "end": { | 1316 | "end": { |
1291 | "column": 3, | 1317 | "column": 3, |
1292 | "line": 16 | 1318 | "line": 19 |
1293 | }, | 1319 | }, |
1294 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1320 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1295 | "id": "settings.navigation.yourServices", | 1321 | "id": "settings.navigation.yourServices", |
1296 | "start": { | 1322 | "start": { |
1297 | "column": 16, | 1323 | "column": 16, |
1298 | "line": 13 | 1324 | "line": 16 |
1299 | } | 1325 | } |
1300 | }, | 1326 | }, |
1301 | { | 1327 | { |
1302 | "defaultMessage": "!!!Account", | 1328 | "defaultMessage": "!!!Your workspaces", |
1303 | "end": { | 1329 | "end": { |
1304 | "column": 3, | 1330 | "column": 3, |
1331 | "line": 23 | ||
1332 | }, | ||
1333 | "file": "src/components/settings/navigation/SettingsNavigation.js", | ||
1334 | "id": "settings.navigation.yourWorkspaces", | ||
1335 | "start": { | ||
1336 | "column": 18, | ||
1305 | "line": 20 | 1337 | "line": 20 |
1338 | } | ||
1339 | }, | ||
1340 | { | ||
1341 | "defaultMessage": "!!!Account", | ||
1342 | "end": { | ||
1343 | "column": 3, | ||
1344 | "line": 27 | ||
1306 | }, | 1345 | }, |
1307 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1346 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1308 | "id": "settings.navigation.account", | 1347 | "id": "settings.navigation.account", |
1309 | "start": { | 1348 | "start": { |
1310 | "column": 11, | 1349 | "column": 11, |
1311 | "line": 17 | 1350 | "line": 24 |
1312 | } | 1351 | } |
1313 | }, | 1352 | }, |
1314 | { | 1353 | { |
1315 | "defaultMessage": "!!!Manage Team", | 1354 | "defaultMessage": "!!!Manage Team", |
1316 | "end": { | 1355 | "end": { |
1317 | "column": 3, | 1356 | "column": 3, |
1318 | "line": 24 | 1357 | "line": 31 |
1319 | }, | 1358 | }, |
1320 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1359 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1321 | "id": "settings.navigation.team", | 1360 | "id": "settings.navigation.team", |
@@ -1334,33 +1373,33 @@ | |||
1334 | "id": "settings.navigation.settings", | 1373 | "id": "settings.navigation.settings", |
1335 | "start": { | 1374 | "start": { |
1336 | "column": 12, | 1375 | "column": 12, |
1337 | "line": 25 | 1376 | "line": 28 |
1338 | } | 1377 | } |
1339 | }, | 1378 | }, |
1340 | { | 1379 | { |
1341 | "defaultMessage": "!!!Invite Friends", | 1380 | "defaultMessage": "!!!Invite Friends", |
1342 | "end": { | 1381 | "end": { |
1343 | "column": 3, | 1382 | "column": 3, |
1344 | "line": 32 | 1383 | "line": 35 |
1345 | }, | 1384 | }, |
1346 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1385 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1347 | "id": "settings.navigation.inviteFriends", | 1386 | "id": "settings.navigation.inviteFriends", |
1348 | "start": { | 1387 | "start": { |
1349 | "column": 17, | 1388 | "column": 17, |
1350 | "line": 29 | 1389 | "line": 32 |
1351 | } | 1390 | } |
1352 | }, | 1391 | }, |
1353 | { | 1392 | { |
1354 | "defaultMessage": "!!!Logout", | 1393 | "defaultMessage": "!!!Logout", |
1355 | "end": { | 1394 | "end": { |
1356 | "column": 3, | 1395 | "column": 3, |
1357 | "line": 36 | 1396 | "line": 39 |
1358 | }, | 1397 | }, |
1359 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 1398 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
1360 | "id": "settings.navigation.logout", | 1399 | "id": "settings.navigation.logout", |
1361 | "start": { | 1400 | "start": { |
1362 | "column": 10, | 1401 | "column": 10, |
1363 | "line": 33 | 1402 | "line": 36 |
1364 | } | 1403 | } |
1365 | } | 1404 | } |
1366 | ], | 1405 | ], |
@@ -2592,13 +2631,13 @@ | |||
2592 | "defaultMessage": "!!!Upgrade account", | 2631 | "defaultMessage": "!!!Upgrade account", |
2593 | "end": { | 2632 | "end": { |
2594 | "column": 3, | 2633 | "column": 3, |
2595 | "line": 17 | 2634 | "line": 18 |
2596 | }, | 2635 | }, |
2597 | "file": "src/components/ui/PremiumFeatureContainer/index.js", | 2636 | "file": "src/components/ui/PremiumFeatureContainer/index.js", |
2598 | "id": "premiumFeature.button.upgradeAccount", | 2637 | "id": "premiumFeature.button.upgradeAccount", |
2599 | "start": { | 2638 | "start": { |
2600 | "column": 10, | 2639 | "column": 10, |
2601 | "line": 14 | 2640 | "line": 15 |
2602 | } | 2641 | } |
2603 | } | 2642 | } |
2604 | ], | 2643 | ], |
@@ -2607,6 +2646,24 @@ | |||
2607 | { | 2646 | { |
2608 | "descriptors": [ | 2647 | "descriptors": [ |
2609 | { | 2648 | { |
2649 | "defaultMessage": "!!!Loading", | ||
2650 | "end": { | ||
2651 | "column": 3, | ||
2652 | "line": 14 | ||
2653 | }, | ||
2654 | "file": "src/components/ui/WebviewLoader/index.js", | ||
2655 | "id": "service.webviewLoader.loading", | ||
2656 | "start": { | ||
2657 | "column": 11, | ||
2658 | "line": 11 | ||
2659 | } | ||
2660 | } | ||
2661 | ], | ||
2662 | "path": "src/components/ui/WebviewLoader/index.json" | ||
2663 | }, | ||
2664 | { | ||
2665 | "descriptors": [ | ||
2666 | { | ||
2610 | "defaultMessage": "!!!Something went wrong.", | 2667 | "defaultMessage": "!!!Something went wrong.", |
2611 | "end": { | 2668 | "end": { |
2612 | "column": 3, | 2669 | "column": 3, |
@@ -3261,6 +3318,374 @@ | |||
3261 | { | 3318 | { |
3262 | "descriptors": [ | 3319 | "descriptors": [ |
3263 | { | 3320 | { |
3321 | "defaultMessage": "!!!Create workspace", | ||
3322 | "end": { | ||
3323 | "column": 3, | ||
3324 | "line": 16 | ||
3325 | }, | ||
3326 | "file": "src/features/workspaces/components/CreateWorkspaceForm.js", | ||
3327 | "id": "settings.workspace.add.form.submitButton", | ||
3328 | "start": { | ||
3329 | "column": 16, | ||
3330 | "line": 13 | ||
3331 | } | ||
3332 | }, | ||
3333 | { | ||
3334 | "defaultMessage": "!!!Name", | ||
3335 | "end": { | ||
3336 | "column": 3, | ||
3337 | "line": 20 | ||
3338 | }, | ||
3339 | "file": "src/features/workspaces/components/CreateWorkspaceForm.js", | ||
3340 | "id": "settings.workspace.add.form.name", | ||
3341 | "start": { | ||
3342 | "column": 8, | ||
3343 | "line": 17 | ||
3344 | } | ||
3345 | } | ||
3346 | ], | ||
3347 | "path": "src/features/workspaces/components/CreateWorkspaceForm.json" | ||
3348 | }, | ||
3349 | { | ||
3350 | "descriptors": [ | ||
3351 | { | ||
3352 | "defaultMessage": "!!!Delete workspace", | ||
3353 | "end": { | ||
3354 | "column": 3, | ||
3355 | "line": 22 | ||
3356 | }, | ||
3357 | "file": "src/features/workspaces/components/EditWorkspaceForm.js", | ||
3358 | "id": "settings.workspace.form.buttonDelete", | ||
3359 | "start": { | ||
3360 | "column": 16, | ||
3361 | "line": 19 | ||
3362 | } | ||
3363 | }, | ||
3364 | { | ||
3365 | "defaultMessage": "!!!Save workspace", | ||
3366 | "end": { | ||
3367 | "column": 3, | ||
3368 | "line": 26 | ||
3369 | }, | ||
3370 | "file": "src/features/workspaces/components/EditWorkspaceForm.js", | ||
3371 | "id": "settings.workspace.form.buttonSave", | ||
3372 | "start": { | ||
3373 | "column": 14, | ||
3374 | "line": 23 | ||
3375 | } | ||
3376 | }, | ||
3377 | { | ||
3378 | "defaultMessage": "!!!Name", | ||
3379 | "end": { | ||
3380 | "column": 3, | ||
3381 | "line": 30 | ||
3382 | }, | ||
3383 | "file": "src/features/workspaces/components/EditWorkspaceForm.js", | ||
3384 | "id": "settings.workspace.form.name", | ||
3385 | "start": { | ||
3386 | "column": 8, | ||
3387 | "line": 27 | ||
3388 | } | ||
3389 | }, | ||
3390 | { | ||
3391 | "defaultMessage": "!!!Your workspaces", | ||
3392 | "end": { | ||
3393 | "column": 3, | ||
3394 | "line": 34 | ||
3395 | }, | ||
3396 | "file": "src/features/workspaces/components/EditWorkspaceForm.js", | ||
3397 | "id": "settings.workspace.form.yourWorkspaces", | ||
3398 | "start": { | ||
3399 | "column": 18, | ||
3400 | "line": 31 | ||
3401 | } | ||
3402 | }, | ||
3403 | { | ||
3404 | "defaultMessage": "!!!Services in this Workspace", | ||
3405 | "end": { | ||
3406 | "column": 3, | ||
3407 | "line": 38 | ||
3408 | }, | ||
3409 | "file": "src/features/workspaces/components/EditWorkspaceForm.js", | ||
3410 | "id": "settings.workspace.form.servicesInWorkspaceHeadline", | ||
3411 | "start": { | ||
3412 | "column": 31, | ||
3413 | "line": 35 | ||
3414 | } | ||
3415 | } | ||
3416 | ], | ||
3417 | "path": "src/features/workspaces/components/EditWorkspaceForm.json" | ||
3418 | }, | ||
3419 | { | ||
3420 | "descriptors": [ | ||
3421 | { | ||
3422 | "defaultMessage": "!!!Workspaces", | ||
3423 | "end": { | ||
3424 | "column": 3, | ||
3425 | "line": 19 | ||
3426 | }, | ||
3427 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
3428 | "id": "workspaceDrawer.headline", | ||
3429 | "start": { | ||
3430 | "column": 12, | ||
3431 | "line": 16 | ||
3432 | } | ||
3433 | }, | ||
3434 | { | ||
3435 | "defaultMessage": "!!!All services", | ||
3436 | "end": { | ||
3437 | "column": 3, | ||
3438 | "line": 23 | ||
3439 | }, | ||
3440 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
3441 | "id": "workspaceDrawer.allServices", | ||
3442 | "start": { | ||
3443 | "column": 15, | ||
3444 | "line": 20 | ||
3445 | } | ||
3446 | }, | ||
3447 | { | ||
3448 | "defaultMessage": "!!!Workspaces settings", | ||
3449 | "end": { | ||
3450 | "column": 3, | ||
3451 | "line": 27 | ||
3452 | }, | ||
3453 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
3454 | "id": "workspaceDrawer.workspacesSettingsTooltip", | ||
3455 | "start": { | ||
3456 | "column": 29, | ||
3457 | "line": 24 | ||
3458 | } | ||
3459 | }, | ||
3460 | { | ||
3461 | "defaultMessage": "!!!Info about workspace feature", | ||
3462 | "end": { | ||
3463 | "column": 3, | ||
3464 | "line": 31 | ||
3465 | }, | ||
3466 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
3467 | "id": "workspaceDrawer.workspaceFeatureInfo", | ||
3468 | "start": { | ||
3469 | "column": 24, | ||
3470 | "line": 28 | ||
3471 | } | ||
3472 | }, | ||
3473 | { | ||
3474 | "defaultMessage": "!!!Create your first workspace", | ||
3475 | "end": { | ||
3476 | "column": 3, | ||
3477 | "line": 35 | ||
3478 | }, | ||
3479 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
3480 | "id": "workspaceDrawer.premiumCtaButtonLabel", | ||
3481 | "start": { | ||
3482 | "column": 25, | ||
3483 | "line": 32 | ||
3484 | } | ||
3485 | }, | ||
3486 | { | ||
3487 | "defaultMessage": "!!!Reactivate premium account", | ||
3488 | "end": { | ||
3489 | "column": 3, | ||
3490 | "line": 39 | ||
3491 | }, | ||
3492 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
3493 | "id": "workspaceDrawer.reactivatePremiumAccountLabel", | ||
3494 | "start": { | ||
3495 | "column": 28, | ||
3496 | "line": 36 | ||
3497 | } | ||
3498 | }, | ||
3499 | { | ||
3500 | "defaultMessage": "!!!add new workspace", | ||
3501 | "end": { | ||
3502 | "column": 3, | ||
3503 | "line": 43 | ||
3504 | }, | ||
3505 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
3506 | "id": "workspaceDrawer.addNewWorkspaceLabel", | ||
3507 | "start": { | ||
3508 | "column": 24, | ||
3509 | "line": 40 | ||
3510 | } | ||
3511 | }, | ||
3512 | { | ||
3513 | "defaultMessage": "!!!Premium feature", | ||
3514 | "end": { | ||
3515 | "column": 3, | ||
3516 | "line": 47 | ||
3517 | }, | ||
3518 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
3519 | "id": "workspaceDrawer.proFeatureBadge", | ||
3520 | "start": { | ||
3521 | "column": 23, | ||
3522 | "line": 44 | ||
3523 | } | ||
3524 | } | ||
3525 | ], | ||
3526 | "path": "src/features/workspaces/components/WorkspaceDrawer.json" | ||
3527 | }, | ||
3528 | { | ||
3529 | "descriptors": [ | ||
3530 | { | ||
3531 | "defaultMessage": "!!!No services added yet", | ||
3532 | "end": { | ||
3533 | "column": 3, | ||
3534 | "line": 15 | ||
3535 | }, | ||
3536 | "file": "src/features/workspaces/components/WorkspaceDrawerItem.js", | ||
3537 | "id": "workspaceDrawer.item.noServicesAddedYet", | ||
3538 | "start": { | ||
3539 | "column": 22, | ||
3540 | "line": 12 | ||
3541 | } | ||
3542 | }, | ||
3543 | { | ||
3544 | "defaultMessage": "!!!edit", | ||
3545 | "end": { | ||
3546 | "column": 3, | ||
3547 | "line": 19 | ||
3548 | }, | ||
3549 | "file": "src/features/workspaces/components/WorkspaceDrawerItem.js", | ||
3550 | "id": "workspaceDrawer.item.contextMenuEdit", | ||
3551 | "start": { | ||
3552 | "column": 19, | ||
3553 | "line": 16 | ||
3554 | } | ||
3555 | } | ||
3556 | ], | ||
3557 | "path": "src/features/workspaces/components/WorkspaceDrawerItem.json" | ||
3558 | }, | ||
3559 | { | ||
3560 | "descriptors": [ | ||
3561 | { | ||
3562 | "defaultMessage": "!!!Your workspaces", | ||
3563 | "end": { | ||
3564 | "column": 3, | ||
3565 | "line": 20 | ||
3566 | }, | ||
3567 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
3568 | "id": "settings.workspaces.headline", | ||
3569 | "start": { | ||
3570 | "column": 12, | ||
3571 | "line": 17 | ||
3572 | } | ||
3573 | }, | ||
3574 | { | ||
3575 | "defaultMessage": "!!!You haven't added any workspaces yet.", | ||
3576 | "end": { | ||
3577 | "column": 3, | ||
3578 | "line": 24 | ||
3579 | }, | ||
3580 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
3581 | "id": "settings.workspaces.noWorkspacesAdded", | ||
3582 | "start": { | ||
3583 | "column": 19, | ||
3584 | "line": 21 | ||
3585 | } | ||
3586 | }, | ||
3587 | { | ||
3588 | "defaultMessage": "!!!Could not load your workspaces", | ||
3589 | "end": { | ||
3590 | "column": 3, | ||
3591 | "line": 28 | ||
3592 | }, | ||
3593 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
3594 | "id": "settings.workspaces.workspacesRequestFailed", | ||
3595 | "start": { | ||
3596 | "column": 27, | ||
3597 | "line": 25 | ||
3598 | } | ||
3599 | }, | ||
3600 | { | ||
3601 | "defaultMessage": "!!!Try again", | ||
3602 | "end": { | ||
3603 | "column": 3, | ||
3604 | "line": 32 | ||
3605 | }, | ||
3606 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
3607 | "id": "settings.workspaces.tryReloadWorkspaces", | ||
3608 | "start": { | ||
3609 | "column": 23, | ||
3610 | "line": 29 | ||
3611 | } | ||
3612 | }, | ||
3613 | { | ||
3614 | "defaultMessage": "!!!Your changes have been saved", | ||
3615 | "end": { | ||
3616 | "column": 3, | ||
3617 | "line": 36 | ||
3618 | }, | ||
3619 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
3620 | "id": "settings.workspaces.updatedInfo", | ||
3621 | "start": { | ||
3622 | "column": 15, | ||
3623 | "line": 33 | ||
3624 | } | ||
3625 | }, | ||
3626 | { | ||
3627 | "defaultMessage": "!!!Workspace has been deleted", | ||
3628 | "end": { | ||
3629 | "column": 3, | ||
3630 | "line": 40 | ||
3631 | }, | ||
3632 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
3633 | "id": "settings.workspaces.deletedInfo", | ||
3634 | "start": { | ||
3635 | "column": 15, | ||
3636 | "line": 37 | ||
3637 | } | ||
3638 | }, | ||
3639 | { | ||
3640 | "defaultMessage": "!!!Info about workspace feature", | ||
3641 | "end": { | ||
3642 | "column": 3, | ||
3643 | "line": 44 | ||
3644 | }, | ||
3645 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
3646 | "id": "settings.workspaces.workspaceFeatureInfo", | ||
3647 | "start": { | ||
3648 | "column": 24, | ||
3649 | "line": 41 | ||
3650 | } | ||
3651 | }, | ||
3652 | { | ||
3653 | "defaultMessage": "!!!Less is More: Introducing Franz Workspaces", | ||
3654 | "end": { | ||
3655 | "column": 3, | ||
3656 | "line": 48 | ||
3657 | }, | ||
3658 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
3659 | "id": "settings.workspaces.workspaceFeatureHeadline", | ||
3660 | "start": { | ||
3661 | "column": 28, | ||
3662 | "line": 45 | ||
3663 | } | ||
3664 | } | ||
3665 | ], | ||
3666 | "path": "src/features/workspaces/components/WorkspacesDashboard.json" | ||
3667 | }, | ||
3668 | { | ||
3669 | "descriptors": [ | ||
3670 | { | ||
3671 | "defaultMessage": "!!!Switching to", | ||
3672 | "end": { | ||
3673 | "column": 3, | ||
3674 | "line": 15 | ||
3675 | }, | ||
3676 | "file": "src/features/workspaces/components/WorkspaceSwitchingIndicator.js", | ||
3677 | "id": "workspaces.switchingIndicator.switchingTo", | ||
3678 | "start": { | ||
3679 | "column": 15, | ||
3680 | "line": 12 | ||
3681 | } | ||
3682 | } | ||
3683 | ], | ||
3684 | "path": "src/features/workspaces/components/WorkspaceSwitchingIndicator.json" | ||
3685 | }, | ||
3686 | { | ||
3687 | "descriptors": [ | ||
3688 | { | ||
3264 | "defaultMessage": "!!!Field is required", | 3689 | "defaultMessage": "!!!Field is required", |
3265 | "end": { | 3690 | "end": { |
3266 | "column": 3, | 3691 | "column": 3, |
@@ -3417,614 +3842,679 @@ | |||
3417 | "defaultMessage": "!!!Edit", | 3842 | "defaultMessage": "!!!Edit", |
3418 | "end": { | 3843 | "end": { |
3419 | "column": 3, | 3844 | "column": 3, |
3420 | "line": 13 | 3845 | "line": 16 |
3421 | }, | 3846 | }, |
3422 | "file": "src/lib/Menu.js", | 3847 | "file": "src/lib/Menu.js", |
3423 | "id": "menu.edit", | 3848 | "id": "menu.edit", |
3424 | "start": { | 3849 | "start": { |
3425 | "column": 8, | 3850 | "column": 8, |
3426 | "line": 10 | 3851 | "line": 13 |
3427 | } | 3852 | } |
3428 | }, | 3853 | }, |
3429 | { | 3854 | { |
3430 | "defaultMessage": "!!!Undo", | 3855 | "defaultMessage": "!!!Undo", |
3431 | "end": { | 3856 | "end": { |
3432 | "column": 3, | 3857 | "column": 3, |
3433 | "line": 17 | 3858 | "line": 20 |
3434 | }, | 3859 | }, |
3435 | "file": "src/lib/Menu.js", | 3860 | "file": "src/lib/Menu.js", |
3436 | "id": "menu.edit.undo", | 3861 | "id": "menu.edit.undo", |
3437 | "start": { | 3862 | "start": { |
3438 | "column": 8, | 3863 | "column": 8, |
3439 | "line": 14 | 3864 | "line": 17 |
3440 | } | 3865 | } |
3441 | }, | 3866 | }, |
3442 | { | 3867 | { |
3443 | "defaultMessage": "!!!Redo", | 3868 | "defaultMessage": "!!!Redo", |
3444 | "end": { | 3869 | "end": { |
3445 | "column": 3, | 3870 | "column": 3, |
3446 | "line": 21 | 3871 | "line": 24 |
3447 | }, | 3872 | }, |
3448 | "file": "src/lib/Menu.js", | 3873 | "file": "src/lib/Menu.js", |
3449 | "id": "menu.edit.redo", | 3874 | "id": "menu.edit.redo", |
3450 | "start": { | 3875 | "start": { |
3451 | "column": 8, | 3876 | "column": 8, |
3452 | "line": 18 | 3877 | "line": 21 |
3453 | } | 3878 | } |
3454 | }, | 3879 | }, |
3455 | { | 3880 | { |
3456 | "defaultMessage": "!!!Cut", | 3881 | "defaultMessage": "!!!Cut", |
3457 | "end": { | 3882 | "end": { |
3458 | "column": 3, | 3883 | "column": 3, |
3459 | "line": 25 | 3884 | "line": 28 |
3460 | }, | 3885 | }, |
3461 | "file": "src/lib/Menu.js", | 3886 | "file": "src/lib/Menu.js", |
3462 | "id": "menu.edit.cut", | 3887 | "id": "menu.edit.cut", |
3463 | "start": { | 3888 | "start": { |
3464 | "column": 7, | 3889 | "column": 7, |
3465 | "line": 22 | 3890 | "line": 25 |
3466 | } | 3891 | } |
3467 | }, | 3892 | }, |
3468 | { | 3893 | { |
3469 | "defaultMessage": "!!!Copy", | 3894 | "defaultMessage": "!!!Copy", |
3470 | "end": { | 3895 | "end": { |
3471 | "column": 3, | 3896 | "column": 3, |
3472 | "line": 29 | 3897 | "line": 32 |
3473 | }, | 3898 | }, |
3474 | "file": "src/lib/Menu.js", | 3899 | "file": "src/lib/Menu.js", |
3475 | "id": "menu.edit.copy", | 3900 | "id": "menu.edit.copy", |
3476 | "start": { | 3901 | "start": { |
3477 | "column": 8, | 3902 | "column": 8, |
3478 | "line": 26 | 3903 | "line": 29 |
3479 | } | 3904 | } |
3480 | }, | 3905 | }, |
3481 | { | 3906 | { |
3482 | "defaultMessage": "!!!Paste", | 3907 | "defaultMessage": "!!!Paste", |
3483 | "end": { | 3908 | "end": { |
3484 | "column": 3, | 3909 | "column": 3, |
3485 | "line": 33 | 3910 | "line": 36 |
3486 | }, | 3911 | }, |
3487 | "file": "src/lib/Menu.js", | 3912 | "file": "src/lib/Menu.js", |
3488 | "id": "menu.edit.paste", | 3913 | "id": "menu.edit.paste", |
3489 | "start": { | 3914 | "start": { |
3490 | "column": 9, | 3915 | "column": 9, |
3491 | "line": 30 | 3916 | "line": 33 |
3492 | } | 3917 | } |
3493 | }, | 3918 | }, |
3494 | { | 3919 | { |
3495 | "defaultMessage": "!!!Paste And Match Style", | 3920 | "defaultMessage": "!!!Paste And Match Style", |
3496 | "end": { | 3921 | "end": { |
3497 | "column": 3, | 3922 | "column": 3, |
3498 | "line": 37 | 3923 | "line": 40 |
3499 | }, | 3924 | }, |
3500 | "file": "src/lib/Menu.js", | 3925 | "file": "src/lib/Menu.js", |
3501 | "id": "menu.edit.pasteAndMatchStyle", | 3926 | "id": "menu.edit.pasteAndMatchStyle", |
3502 | "start": { | 3927 | "start": { |
3503 | "column": 22, | 3928 | "column": 22, |
3504 | "line": 34 | 3929 | "line": 37 |
3505 | } | 3930 | } |
3506 | }, | 3931 | }, |
3507 | { | 3932 | { |
3508 | "defaultMessage": "!!!Delete", | 3933 | "defaultMessage": "!!!Delete", |
3509 | "end": { | 3934 | "end": { |
3510 | "column": 3, | 3935 | "column": 3, |
3511 | "line": 41 | 3936 | "line": 44 |
3512 | }, | 3937 | }, |
3513 | "file": "src/lib/Menu.js", | 3938 | "file": "src/lib/Menu.js", |
3514 | "id": "menu.edit.delete", | 3939 | "id": "menu.edit.delete", |
3515 | "start": { | 3940 | "start": { |
3516 | "column": 10, | 3941 | "column": 10, |
3517 | "line": 38 | 3942 | "line": 41 |
3518 | } | 3943 | } |
3519 | }, | 3944 | }, |
3520 | { | 3945 | { |
3521 | "defaultMessage": "!!!Select All", | 3946 | "defaultMessage": "!!!Select All", |
3522 | "end": { | 3947 | "end": { |
3523 | "column": 3, | 3948 | "column": 3, |
3524 | "line": 45 | 3949 | "line": 48 |
3525 | }, | 3950 | }, |
3526 | "file": "src/lib/Menu.js", | 3951 | "file": "src/lib/Menu.js", |
3527 | "id": "menu.edit.selectAll", | 3952 | "id": "menu.edit.selectAll", |
3528 | "start": { | 3953 | "start": { |
3529 | "column": 13, | 3954 | "column": 13, |
3530 | "line": 42 | 3955 | "line": 45 |
3531 | } | 3956 | } |
3532 | }, | 3957 | }, |
3533 | { | 3958 | { |
3534 | "defaultMessage": "!!!Speech", | 3959 | "defaultMessage": "!!!Speech", |
3535 | "end": { | 3960 | "end": { |
3536 | "column": 3, | 3961 | "column": 3, |
3537 | "line": 49 | 3962 | "line": 52 |
3538 | }, | 3963 | }, |
3539 | "file": "src/lib/Menu.js", | 3964 | "file": "src/lib/Menu.js", |
3540 | "id": "menu.edit.speech", | 3965 | "id": "menu.edit.speech", |
3541 | "start": { | 3966 | "start": { |
3542 | "column": 10, | 3967 | "column": 10, |
3543 | "line": 46 | 3968 | "line": 49 |
3544 | } | 3969 | } |
3545 | }, | 3970 | }, |
3546 | { | 3971 | { |
3547 | "defaultMessage": "!!!Start Speaking", | 3972 | "defaultMessage": "!!!Start Speaking", |
3548 | "end": { | 3973 | "end": { |
3549 | "column": 3, | 3974 | "column": 3, |
3550 | "line": 53 | 3975 | "line": 56 |
3551 | }, | 3976 | }, |
3552 | "file": "src/lib/Menu.js", | 3977 | "file": "src/lib/Menu.js", |
3553 | "id": "menu.edit.startSpeaking", | 3978 | "id": "menu.edit.startSpeaking", |
3554 | "start": { | 3979 | "start": { |
3555 | "column": 17, | 3980 | "column": 17, |
3556 | "line": 50 | 3981 | "line": 53 |
3557 | } | 3982 | } |
3558 | }, | 3983 | }, |
3559 | { | 3984 | { |
3560 | "defaultMessage": "!!!Stop Speaking", | 3985 | "defaultMessage": "!!!Stop Speaking", |
3561 | "end": { | 3986 | "end": { |
3562 | "column": 3, | 3987 | "column": 3, |
3563 | "line": 57 | 3988 | "line": 60 |
3564 | }, | 3989 | }, |
3565 | "file": "src/lib/Menu.js", | 3990 | "file": "src/lib/Menu.js", |
3566 | "id": "menu.edit.stopSpeaking", | 3991 | "id": "menu.edit.stopSpeaking", |
3567 | "start": { | 3992 | "start": { |
3568 | "column": 16, | 3993 | "column": 16, |
3569 | "line": 54 | 3994 | "line": 57 |
3570 | } | 3995 | } |
3571 | }, | 3996 | }, |
3572 | { | 3997 | { |
3573 | "defaultMessage": "!!!Start Dictation", | 3998 | "defaultMessage": "!!!Start Dictation", |
3574 | "end": { | 3999 | "end": { |
3575 | "column": 3, | 4000 | "column": 3, |
3576 | "line": 61 | 4001 | "line": 64 |
3577 | }, | 4002 | }, |
3578 | "file": "src/lib/Menu.js", | 4003 | "file": "src/lib/Menu.js", |
3579 | "id": "menu.edit.startDictation", | 4004 | "id": "menu.edit.startDictation", |
3580 | "start": { | 4005 | "start": { |
3581 | "column": 18, | 4006 | "column": 18, |
3582 | "line": 58 | 4007 | "line": 61 |
3583 | } | 4008 | } |
3584 | }, | 4009 | }, |
3585 | { | 4010 | { |
3586 | "defaultMessage": "!!!Emoji & Symbols", | 4011 | "defaultMessage": "!!!Emoji & Symbols", |
3587 | "end": { | 4012 | "end": { |
3588 | "column": 3, | 4013 | "column": 3, |
3589 | "line": 65 | 4014 | "line": 68 |
3590 | }, | 4015 | }, |
3591 | "file": "src/lib/Menu.js", | 4016 | "file": "src/lib/Menu.js", |
3592 | "id": "menu.edit.emojiSymbols", | 4017 | "id": "menu.edit.emojiSymbols", |
3593 | "start": { | 4018 | "start": { |
3594 | "column": 16, | 4019 | "column": 16, |
3595 | "line": 62 | 4020 | "line": 65 |
3596 | } | 4021 | } |
3597 | }, | 4022 | }, |
3598 | { | 4023 | { |
3599 | "defaultMessage": "!!!Actual Size", | 4024 | "defaultMessage": "!!!Actual Size", |
3600 | "end": { | 4025 | "end": { |
3601 | "column": 3, | 4026 | "column": 3, |
3602 | "line": 69 | 4027 | "line": 72 |
3603 | }, | 4028 | }, |
3604 | "file": "src/lib/Menu.js", | 4029 | "file": "src/lib/Menu.js", |
3605 | "id": "menu.view.resetZoom", | 4030 | "id": "menu.view.resetZoom", |
3606 | "start": { | 4031 | "start": { |
3607 | "column": 13, | 4032 | "column": 13, |
3608 | "line": 66 | 4033 | "line": 69 |
3609 | } | 4034 | } |
3610 | }, | 4035 | }, |
3611 | { | 4036 | { |
3612 | "defaultMessage": "!!!Zoom In", | 4037 | "defaultMessage": "!!!Zoom In", |
3613 | "end": { | 4038 | "end": { |
3614 | "column": 3, | 4039 | "column": 3, |
3615 | "line": 73 | 4040 | "line": 76 |
3616 | }, | 4041 | }, |
3617 | "file": "src/lib/Menu.js", | 4042 | "file": "src/lib/Menu.js", |
3618 | "id": "menu.view.zoomIn", | 4043 | "id": "menu.view.zoomIn", |
3619 | "start": { | 4044 | "start": { |
3620 | "column": 10, | 4045 | "column": 10, |
3621 | "line": 70 | 4046 | "line": 73 |
3622 | } | 4047 | } |
3623 | }, | 4048 | }, |
3624 | { | 4049 | { |
3625 | "defaultMessage": "!!!Zoom Out", | 4050 | "defaultMessage": "!!!Zoom Out", |
3626 | "end": { | 4051 | "end": { |
3627 | "column": 3, | 4052 | "column": 3, |
3628 | "line": 77 | 4053 | "line": 80 |
3629 | }, | 4054 | }, |
3630 | "file": "src/lib/Menu.js", | 4055 | "file": "src/lib/Menu.js", |
3631 | "id": "menu.view.zoomOut", | 4056 | "id": "menu.view.zoomOut", |
3632 | "start": { | 4057 | "start": { |
3633 | "column": 11, | 4058 | "column": 11, |
3634 | "line": 74 | 4059 | "line": 77 |
3635 | } | 4060 | } |
3636 | }, | 4061 | }, |
3637 | { | 4062 | { |
3638 | "defaultMessage": "!!!Enter Full Screen", | 4063 | "defaultMessage": "!!!Enter Full Screen", |
3639 | "end": { | 4064 | "end": { |
3640 | "column": 3, | 4065 | "column": 3, |
3641 | "line": 81 | 4066 | "line": 84 |
3642 | }, | 4067 | }, |
3643 | "file": "src/lib/Menu.js", | 4068 | "file": "src/lib/Menu.js", |
3644 | "id": "menu.view.enterFullScreen", | 4069 | "id": "menu.view.enterFullScreen", |
3645 | "start": { | 4070 | "start": { |
3646 | "column": 19, | 4071 | "column": 19, |
3647 | "line": 78 | 4072 | "line": 81 |
3648 | } | 4073 | } |
3649 | }, | 4074 | }, |
3650 | { | 4075 | { |
3651 | "defaultMessage": "!!!Exit Full Screen", | 4076 | "defaultMessage": "!!!Exit Full Screen", |
3652 | "end": { | 4077 | "end": { |
3653 | "column": 3, | 4078 | "column": 3, |
3654 | "line": 85 | 4079 | "line": 88 |
3655 | }, | 4080 | }, |
3656 | "file": "src/lib/Menu.js", | 4081 | "file": "src/lib/Menu.js", |
3657 | "id": "menu.view.exitFullScreen", | 4082 | "id": "menu.view.exitFullScreen", |
3658 | "start": { | 4083 | "start": { |
3659 | "column": 18, | 4084 | "column": 18, |
3660 | "line": 82 | 4085 | "line": 85 |
3661 | } | 4086 | } |
3662 | }, | 4087 | }, |
3663 | { | 4088 | { |
3664 | "defaultMessage": "!!!Toggle Full Screen", | 4089 | "defaultMessage": "!!!Toggle Full Screen", |
3665 | "end": { | 4090 | "end": { |
3666 | "column": 3, | 4091 | "column": 3, |
3667 | "line": 89 | 4092 | "line": 92 |
3668 | }, | 4093 | }, |
3669 | "file": "src/lib/Menu.js", | 4094 | "file": "src/lib/Menu.js", |
3670 | "id": "menu.view.toggleFullScreen", | 4095 | "id": "menu.view.toggleFullScreen", |
3671 | "start": { | 4096 | "start": { |
3672 | "column": 20, | 4097 | "column": 20, |
3673 | "line": 86 | 4098 | "line": 89 |
3674 | } | 4099 | } |
3675 | }, | 4100 | }, |
3676 | { | 4101 | { |
3677 | "defaultMessage": "!!!Toggle Developer Tools", | 4102 | "defaultMessage": "!!!Toggle Developer Tools", |
3678 | "end": { | 4103 | "end": { |
3679 | "column": 3, | 4104 | "column": 3, |
3680 | "line": 93 | 4105 | "line": 96 |
3681 | }, | 4106 | }, |
3682 | "file": "src/lib/Menu.js", | 4107 | "file": "src/lib/Menu.js", |
3683 | "id": "menu.view.toggleDevTools", | 4108 | "id": "menu.view.toggleDevTools", |
3684 | "start": { | 4109 | "start": { |
3685 | "column": 18, | 4110 | "column": 18, |
3686 | "line": 90 | 4111 | "line": 93 |
3687 | } | 4112 | } |
3688 | }, | 4113 | }, |
3689 | { | 4114 | { |
3690 | "defaultMessage": "!!!Toggle Service Developer Tools", | 4115 | "defaultMessage": "!!!Toggle Service Developer Tools", |
3691 | "end": { | 4116 | "end": { |
3692 | "column": 3, | 4117 | "column": 3, |
3693 | "line": 97 | 4118 | "line": 100 |
3694 | }, | 4119 | }, |
3695 | "file": "src/lib/Menu.js", | 4120 | "file": "src/lib/Menu.js", |
3696 | "id": "menu.view.toggleServiceDevTools", | 4121 | "id": "menu.view.toggleServiceDevTools", |
3697 | "start": { | 4122 | "start": { |
3698 | "column": 25, | 4123 | "column": 25, |
3699 | "line": 94 | 4124 | "line": 97 |
3700 | } | 4125 | } |
3701 | }, | 4126 | }, |
3702 | { | 4127 | { |
3703 | "defaultMessage": "!!!Reload Service", | 4128 | "defaultMessage": "!!!Reload Service", |
3704 | "end": { | 4129 | "end": { |
3705 | "column": 3, | 4130 | "column": 3, |
3706 | "line": 101 | 4131 | "line": 104 |
3707 | }, | 4132 | }, |
3708 | "file": "src/lib/Menu.js", | 4133 | "file": "src/lib/Menu.js", |
3709 | "id": "menu.view.reloadService", | 4134 | "id": "menu.view.reloadService", |
3710 | "start": { | 4135 | "start": { |
3711 | "column": 17, | 4136 | "column": 17, |
3712 | "line": 98 | 4137 | "line": 101 |
3713 | } | 4138 | } |
3714 | }, | 4139 | }, |
3715 | { | 4140 | { |
3716 | "defaultMessage": "!!!Reload Franz", | 4141 | "defaultMessage": "!!!Reload Franz", |
3717 | "end": { | 4142 | "end": { |
3718 | "column": 3, | 4143 | "column": 3, |
3719 | "line": 105 | 4144 | "line": 108 |
3720 | }, | 4145 | }, |
3721 | "file": "src/lib/Menu.js", | 4146 | "file": "src/lib/Menu.js", |
3722 | "id": "menu.view.reloadFranz", | 4147 | "id": "menu.view.reloadFranz", |
3723 | "start": { | 4148 | "start": { |
3724 | "column": 15, | 4149 | "column": 15, |
3725 | "line": 102 | 4150 | "line": 105 |
3726 | } | 4151 | } |
3727 | }, | 4152 | }, |
3728 | { | 4153 | { |
3729 | "defaultMessage": "!!!Minimize", | 4154 | "defaultMessage": "!!!Minimize", |
3730 | "end": { | 4155 | "end": { |
3731 | "column": 3, | 4156 | "column": 3, |
3732 | "line": 109 | 4157 | "line": 112 |
3733 | }, | 4158 | }, |
3734 | "file": "src/lib/Menu.js", | 4159 | "file": "src/lib/Menu.js", |
3735 | "id": "menu.window.minimize", | 4160 | "id": "menu.window.minimize", |
3736 | "start": { | 4161 | "start": { |
3737 | "column": 12, | 4162 | "column": 12, |
3738 | "line": 106 | 4163 | "line": 109 |
3739 | } | 4164 | } |
3740 | }, | 4165 | }, |
3741 | { | 4166 | { |
3742 | "defaultMessage": "!!!Close", | 4167 | "defaultMessage": "!!!Close", |
3743 | "end": { | 4168 | "end": { |
3744 | "column": 3, | 4169 | "column": 3, |
3745 | "line": 113 | 4170 | "line": 116 |
3746 | }, | 4171 | }, |
3747 | "file": "src/lib/Menu.js", | 4172 | "file": "src/lib/Menu.js", |
3748 | "id": "menu.window.close", | 4173 | "id": "menu.window.close", |
3749 | "start": { | 4174 | "start": { |
3750 | "column": 9, | 4175 | "column": 9, |
3751 | "line": 110 | 4176 | "line": 113 |
3752 | } | 4177 | } |
3753 | }, | 4178 | }, |
3754 | { | 4179 | { |
3755 | "defaultMessage": "!!!Learn More", | 4180 | "defaultMessage": "!!!Learn More", |
3756 | "end": { | 4181 | "end": { |
3757 | "column": 3, | 4182 | "column": 3, |
3758 | "line": 117 | 4183 | "line": 120 |
3759 | }, | 4184 | }, |
3760 | "file": "src/lib/Menu.js", | 4185 | "file": "src/lib/Menu.js", |
3761 | "id": "menu.help.learnMore", | 4186 | "id": "menu.help.learnMore", |
3762 | "start": { | 4187 | "start": { |
3763 | "column": 13, | 4188 | "column": 13, |
3764 | "line": 114 | 4189 | "line": 117 |
3765 | } | 4190 | } |
3766 | }, | 4191 | }, |
3767 | { | 4192 | { |
3768 | "defaultMessage": "!!!Changelog", | 4193 | "defaultMessage": "!!!Changelog", |
3769 | "end": { | 4194 | "end": { |
3770 | "column": 3, | 4195 | "column": 3, |
3771 | "line": 121 | 4196 | "line": 124 |
3772 | }, | 4197 | }, |
3773 | "file": "src/lib/Menu.js", | 4198 | "file": "src/lib/Menu.js", |
3774 | "id": "menu.help.changelog", | 4199 | "id": "menu.help.changelog", |
3775 | "start": { | 4200 | "start": { |
3776 | "column": 13, | 4201 | "column": 13, |
3777 | "line": 118 | 4202 | "line": 121 |
3778 | } | 4203 | } |
3779 | }, | 4204 | }, |
3780 | { | 4205 | { |
3781 | "defaultMessage": "!!!Support", | 4206 | "defaultMessage": "!!!Support", |
3782 | "end": { | 4207 | "end": { |
3783 | "column": 3, | 4208 | "column": 3, |
3784 | "line": 125 | 4209 | "line": 128 |
3785 | }, | 4210 | }, |
3786 | "file": "src/lib/Menu.js", | 4211 | "file": "src/lib/Menu.js", |
3787 | "id": "menu.help.support", | 4212 | "id": "menu.help.support", |
3788 | "start": { | 4213 | "start": { |
3789 | "column": 11, | 4214 | "column": 11, |
3790 | "line": 122 | 4215 | "line": 125 |
3791 | } | 4216 | } |
3792 | }, | 4217 | }, |
3793 | { | 4218 | { |
3794 | "defaultMessage": "!!!Terms of Service", | 4219 | "defaultMessage": "!!!Terms of Service", |
3795 | "end": { | 4220 | "end": { |
3796 | "column": 3, | 4221 | "column": 3, |
3797 | "line": 129 | 4222 | "line": 132 |
3798 | }, | 4223 | }, |
3799 | "file": "src/lib/Menu.js", | 4224 | "file": "src/lib/Menu.js", |
3800 | "id": "menu.help.tos", | 4225 | "id": "menu.help.tos", |
3801 | "start": { | 4226 | "start": { |
3802 | "column": 7, | 4227 | "column": 7, |
3803 | "line": 126 | 4228 | "line": 129 |
3804 | } | 4229 | } |
3805 | }, | 4230 | }, |
3806 | { | 4231 | { |
3807 | "defaultMessage": "!!!Privacy Statement", | 4232 | "defaultMessage": "!!!Privacy Statement", |
3808 | "end": { | 4233 | "end": { |
3809 | "column": 3, | 4234 | "column": 3, |
3810 | "line": 133 | 4235 | "line": 136 |
3811 | }, | 4236 | }, |
3812 | "file": "src/lib/Menu.js", | 4237 | "file": "src/lib/Menu.js", |
3813 | "id": "menu.help.privacy", | 4238 | "id": "menu.help.privacy", |
3814 | "start": { | 4239 | "start": { |
3815 | "column": 11, | 4240 | "column": 11, |
3816 | "line": 130 | 4241 | "line": 133 |
3817 | } | 4242 | } |
3818 | }, | 4243 | }, |
3819 | { | 4244 | { |
3820 | "defaultMessage": "!!!File", | 4245 | "defaultMessage": "!!!File", |
3821 | "end": { | 4246 | "end": { |
3822 | "column": 3, | 4247 | "column": 3, |
3823 | "line": 137 | 4248 | "line": 140 |
3824 | }, | 4249 | }, |
3825 | "file": "src/lib/Menu.js", | 4250 | "file": "src/lib/Menu.js", |
3826 | "id": "menu.file", | 4251 | "id": "menu.file", |
3827 | "start": { | 4252 | "start": { |
3828 | "column": 8, | 4253 | "column": 8, |
3829 | "line": 134 | 4254 | "line": 137 |
3830 | } | 4255 | } |
3831 | }, | 4256 | }, |
3832 | { | 4257 | { |
3833 | "defaultMessage": "!!!View", | 4258 | "defaultMessage": "!!!View", |
3834 | "end": { | 4259 | "end": { |
3835 | "column": 3, | 4260 | "column": 3, |
3836 | "line": 141 | 4261 | "line": 144 |
3837 | }, | 4262 | }, |
3838 | "file": "src/lib/Menu.js", | 4263 | "file": "src/lib/Menu.js", |
3839 | "id": "menu.view", | 4264 | "id": "menu.view", |
3840 | "start": { | 4265 | "start": { |
3841 | "column": 8, | 4266 | "column": 8, |
3842 | "line": 138 | 4267 | "line": 141 |
3843 | } | 4268 | } |
3844 | }, | 4269 | }, |
3845 | { | 4270 | { |
3846 | "defaultMessage": "!!!Services", | 4271 | "defaultMessage": "!!!Services", |
3847 | "end": { | 4272 | "end": { |
3848 | "column": 3, | 4273 | "column": 3, |
3849 | "line": 145 | 4274 | "line": 148 |
3850 | }, | 4275 | }, |
3851 | "file": "src/lib/Menu.js", | 4276 | "file": "src/lib/Menu.js", |
3852 | "id": "menu.services", | 4277 | "id": "menu.services", |
3853 | "start": { | 4278 | "start": { |
3854 | "column": 12, | 4279 | "column": 12, |
3855 | "line": 142 | 4280 | "line": 145 |
3856 | } | 4281 | } |
3857 | }, | 4282 | }, |
3858 | { | 4283 | { |
3859 | "defaultMessage": "!!!Window", | 4284 | "defaultMessage": "!!!Window", |
3860 | "end": { | 4285 | "end": { |
3861 | "column": 3, | 4286 | "column": 3, |
3862 | "line": 149 | 4287 | "line": 152 |
3863 | }, | 4288 | }, |
3864 | "file": "src/lib/Menu.js", | 4289 | "file": "src/lib/Menu.js", |
3865 | "id": "menu.window", | 4290 | "id": "menu.window", |
3866 | "start": { | 4291 | "start": { |
3867 | "column": 10, | 4292 | "column": 10, |
3868 | "line": 146 | 4293 | "line": 149 |
3869 | } | 4294 | } |
3870 | }, | 4295 | }, |
3871 | { | 4296 | { |
3872 | "defaultMessage": "!!!Help", | 4297 | "defaultMessage": "!!!Help", |
3873 | "end": { | 4298 | "end": { |
3874 | "column": 3, | 4299 | "column": 3, |
3875 | "line": 153 | 4300 | "line": 156 |
3876 | }, | 4301 | }, |
3877 | "file": "src/lib/Menu.js", | 4302 | "file": "src/lib/Menu.js", |
3878 | "id": "menu.help", | 4303 | "id": "menu.help", |
3879 | "start": { | 4304 | "start": { |
3880 | "column": 8, | 4305 | "column": 8, |
3881 | "line": 150 | 4306 | "line": 153 |
3882 | } | 4307 | } |
3883 | }, | 4308 | }, |
3884 | { | 4309 | { |
3885 | "defaultMessage": "!!!About Franz", | 4310 | "defaultMessage": "!!!About Franz", |
3886 | "end": { | 4311 | "end": { |
3887 | "column": 3, | 4312 | "column": 3, |
3888 | "line": 157 | 4313 | "line": 160 |
3889 | }, | 4314 | }, |
3890 | "file": "src/lib/Menu.js", | 4315 | "file": "src/lib/Menu.js", |
3891 | "id": "menu.app.about", | 4316 | "id": "menu.app.about", |
3892 | "start": { | 4317 | "start": { |
3893 | "column": 9, | 4318 | "column": 9, |
3894 | "line": 154 | 4319 | "line": 157 |
3895 | } | 4320 | } |
3896 | }, | 4321 | }, |
3897 | { | 4322 | { |
3898 | "defaultMessage": "!!!Settings", | 4323 | "defaultMessage": "!!!Settings", |
3899 | "end": { | 4324 | "end": { |
3900 | "column": 3, | 4325 | "column": 3, |
3901 | "line": 161 | 4326 | "line": 164 |
3902 | }, | 4327 | }, |
3903 | "file": "src/lib/Menu.js", | 4328 | "file": "src/lib/Menu.js", |
3904 | "id": "menu.app.settings", | 4329 | "id": "menu.app.settings", |
3905 | "start": { | 4330 | "start": { |
3906 | "column": 12, | 4331 | "column": 12, |
3907 | "line": 158 | 4332 | "line": 161 |
3908 | } | 4333 | } |
3909 | }, | 4334 | }, |
3910 | { | 4335 | { |
3911 | "defaultMessage": "!!!Hide", | 4336 | "defaultMessage": "!!!Hide", |
3912 | "end": { | 4337 | "end": { |
3913 | "column": 3, | 4338 | "column": 3, |
3914 | "line": 165 | 4339 | "line": 168 |
3915 | }, | 4340 | }, |
3916 | "file": "src/lib/Menu.js", | 4341 | "file": "src/lib/Menu.js", |
3917 | "id": "menu.app.hide", | 4342 | "id": "menu.app.hide", |
3918 | "start": { | 4343 | "start": { |
3919 | "column": 8, | 4344 | "column": 8, |
3920 | "line": 162 | 4345 | "line": 165 |
3921 | } | 4346 | } |
3922 | }, | 4347 | }, |
3923 | { | 4348 | { |
3924 | "defaultMessage": "!!!Hide Others", | 4349 | "defaultMessage": "!!!Hide Others", |
3925 | "end": { | 4350 | "end": { |
3926 | "column": 3, | 4351 | "column": 3, |
3927 | "line": 169 | 4352 | "line": 172 |
3928 | }, | 4353 | }, |
3929 | "file": "src/lib/Menu.js", | 4354 | "file": "src/lib/Menu.js", |
3930 | "id": "menu.app.hideOthers", | 4355 | "id": "menu.app.hideOthers", |
3931 | "start": { | 4356 | "start": { |
3932 | "column": 14, | 4357 | "column": 14, |
3933 | "line": 166 | 4358 | "line": 169 |
3934 | } | 4359 | } |
3935 | }, | 4360 | }, |
3936 | { | 4361 | { |
3937 | "defaultMessage": "!!!Unhide", | 4362 | "defaultMessage": "!!!Unhide", |
3938 | "end": { | 4363 | "end": { |
3939 | "column": 3, | 4364 | "column": 3, |
3940 | "line": 173 | 4365 | "line": 176 |
3941 | }, | 4366 | }, |
3942 | "file": "src/lib/Menu.js", | 4367 | "file": "src/lib/Menu.js", |
3943 | "id": "menu.app.unhide", | 4368 | "id": "menu.app.unhide", |
3944 | "start": { | 4369 | "start": { |
3945 | "column": 10, | 4370 | "column": 10, |
3946 | "line": 170 | 4371 | "line": 173 |
3947 | } | 4372 | } |
3948 | }, | 4373 | }, |
3949 | { | 4374 | { |
3950 | "defaultMessage": "!!!Quit", | 4375 | "defaultMessage": "!!!Quit", |
3951 | "end": { | 4376 | "end": { |
3952 | "column": 3, | 4377 | "column": 3, |
3953 | "line": 177 | 4378 | "line": 180 |
3954 | }, | 4379 | }, |
3955 | "file": "src/lib/Menu.js", | 4380 | "file": "src/lib/Menu.js", |
3956 | "id": "menu.app.quit", | 4381 | "id": "menu.app.quit", |
3957 | "start": { | 4382 | "start": { |
3958 | "column": 8, | 4383 | "column": 8, |
3959 | "line": 174 | 4384 | "line": 177 |
3960 | } | 4385 | } |
3961 | }, | 4386 | }, |
3962 | { | 4387 | { |
3963 | "defaultMessage": "!!!Add New Service...", | 4388 | "defaultMessage": "!!!Add New Service...", |
3964 | "end": { | 4389 | "end": { |
3965 | "column": 3, | 4390 | "column": 3, |
3966 | "line": 181 | 4391 | "line": 184 |
3967 | }, | 4392 | }, |
3968 | "file": "src/lib/Menu.js", | 4393 | "file": "src/lib/Menu.js", |
3969 | "id": "menu.services.addNewService", | 4394 | "id": "menu.services.addNewService", |
3970 | "start": { | 4395 | "start": { |
3971 | "column": 17, | 4396 | "column": 17, |
3972 | "line": 178 | 4397 | "line": 181 |
3973 | } | 4398 | } |
3974 | }, | 4399 | }, |
3975 | { | 4400 | { |
3976 | "defaultMessage": "!!!Activate next service...", | 4401 | "defaultMessage": "!!!Add New Workspace...", |
3977 | "end": { | 4402 | "end": { |
3978 | "column": 3, | 4403 | "column": 3, |
4404 | "line": 188 | ||
4405 | }, | ||
4406 | "file": "src/lib/Menu.js", | ||
4407 | "id": "menu.workspaces.addNewWorkspace", | ||
4408 | "start": { | ||
4409 | "column": 19, | ||
3979 | "line": 185 | 4410 | "line": 185 |
4411 | } | ||
4412 | }, | ||
4413 | { | ||
4414 | "defaultMessage": "!!!Open workspace drawer", | ||
4415 | "end": { | ||
4416 | "column": 3, | ||
4417 | "line": 192 | ||
4418 | }, | ||
4419 | "file": "src/lib/Menu.js", | ||
4420 | "id": "menu.workspaces.openWorkspaceDrawer", | ||
4421 | "start": { | ||
4422 | "column": 23, | ||
4423 | "line": 189 | ||
4424 | } | ||
4425 | }, | ||
4426 | { | ||
4427 | "defaultMessage": "!!!Close workspace drawer", | ||
4428 | "end": { | ||
4429 | "column": 3, | ||
4430 | "line": 196 | ||
4431 | }, | ||
4432 | "file": "src/lib/Menu.js", | ||
4433 | "id": "menu.workspaces.closeWorkspaceDrawer", | ||
4434 | "start": { | ||
4435 | "column": 24, | ||
4436 | "line": 193 | ||
4437 | } | ||
4438 | }, | ||
4439 | { | ||
4440 | "defaultMessage": "!!!Activate next service...", | ||
4441 | "end": { | ||
4442 | "column": 3, | ||
4443 | "line": 200 | ||
3980 | }, | 4444 | }, |
3981 | "file": "src/lib/Menu.js", | 4445 | "file": "src/lib/Menu.js", |
3982 | "id": "menu.services.setNextServiceActive", | 4446 | "id": "menu.services.setNextServiceActive", |
3983 | "start": { | 4447 | "start": { |
3984 | "column": 23, | 4448 | "column": 23, |
3985 | "line": 182 | 4449 | "line": 197 |
3986 | } | 4450 | } |
3987 | }, | 4451 | }, |
3988 | { | 4452 | { |
3989 | "defaultMessage": "!!!Activate previous service...", | 4453 | "defaultMessage": "!!!Activate previous service...", |
3990 | "end": { | 4454 | "end": { |
3991 | "column": 3, | 4455 | "column": 3, |
3992 | "line": 189 | 4456 | "line": 204 |
3993 | }, | 4457 | }, |
3994 | "file": "src/lib/Menu.js", | 4458 | "file": "src/lib/Menu.js", |
3995 | "id": "menu.services.activatePreviousService", | 4459 | "id": "menu.services.activatePreviousService", |
3996 | "start": { | 4460 | "start": { |
3997 | "column": 27, | 4461 | "column": 27, |
3998 | "line": 186 | 4462 | "line": 201 |
3999 | } | 4463 | } |
4000 | }, | 4464 | }, |
4001 | { | 4465 | { |
4002 | "defaultMessage": "!!!Disable notifications & audio", | 4466 | "defaultMessage": "!!!Disable notifications & audio", |
4003 | "end": { | 4467 | "end": { |
4004 | "column": 3, | 4468 | "column": 3, |
4005 | "line": 193 | 4469 | "line": 208 |
4006 | }, | 4470 | }, |
4007 | "file": "src/lib/Menu.js", | 4471 | "file": "src/lib/Menu.js", |
4008 | "id": "sidebar.muteApp", | 4472 | "id": "sidebar.muteApp", |
4009 | "start": { | 4473 | "start": { |
4010 | "column": 11, | 4474 | "column": 11, |
4011 | "line": 190 | 4475 | "line": 205 |
4012 | } | 4476 | } |
4013 | }, | 4477 | }, |
4014 | { | 4478 | { |
4015 | "defaultMessage": "!!!Enable notifications & audio", | 4479 | "defaultMessage": "!!!Enable notifications & audio", |
4016 | "end": { | 4480 | "end": { |
4017 | "column": 3, | 4481 | "column": 3, |
4018 | "line": 197 | 4482 | "line": 212 |
4019 | }, | 4483 | }, |
4020 | "file": "src/lib/Menu.js", | 4484 | "file": "src/lib/Menu.js", |
4021 | "id": "sidebar.unmuteApp", | 4485 | "id": "sidebar.unmuteApp", |
4022 | "start": { | 4486 | "start": { |
4023 | "column": 13, | 4487 | "column": 13, |
4024 | "line": 194 | 4488 | "line": 209 |
4489 | } | ||
4490 | }, | ||
4491 | { | ||
4492 | "defaultMessage": "!!!Workspaces", | ||
4493 | "end": { | ||
4494 | "column": 3, | ||
4495 | "line": 216 | ||
4496 | }, | ||
4497 | "file": "src/lib/Menu.js", | ||
4498 | "id": "menu.workspaces", | ||
4499 | "start": { | ||
4500 | "column": 14, | ||
4501 | "line": 213 | ||
4502 | } | ||
4503 | }, | ||
4504 | { | ||
4505 | "defaultMessage": "!!!Default", | ||
4506 | "end": { | ||
4507 | "column": 3, | ||
4508 | "line": 220 | ||
4509 | }, | ||
4510 | "file": "src/lib/Menu.js", | ||
4511 | "id": "menu.workspaces.defaultWorkspace", | ||
4512 | "start": { | ||
4513 | "column": 20, | ||
4514 | "line": 217 | ||
4025 | } | 4515 | } |
4026 | } | 4516 | } |
4027 | ], | 4517 | ], |
4028 | "path": "src/lib/Menu.json" | 4518 | "path": "src/lib/Menu.json" |
4029 | } | 4519 | } |
4030 | ] \ No newline at end of file | 4520 | ] |
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 61c25ff98..bcdfb8220 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -87,6 +87,11 @@ | |||
87 | "menu.window": "Window", | 87 | "menu.window": "Window", |
88 | "menu.window.close": "Close", | 88 | "menu.window.close": "Close", |
89 | "menu.window.minimize": "Minimize", | 89 | "menu.window.minimize": "Minimize", |
90 | "menu.workspaces": "Workspaces", | ||
91 | "menu.workspaces.addNewWorkspace": "Add New Workspace...", | ||
92 | "menu.workspaces.closeWorkspaceDrawer": "Close workspace drawer", | ||
93 | "menu.workspaces.defaultWorkspace": "All services", | ||
94 | "menu.workspaces.openWorkspaceDrawer": "Open workspace drawer", | ||
90 | "password.email.label": "Email address", | 95 | "password.email.label": "Email address", |
91 | "password.headline": "Reset password", | 96 | "password.headline": "Reset password", |
92 | "password.link.login": "Sign in to your account", | 97 | "password.link.login": "Sign in to your account", |
@@ -110,6 +115,7 @@ | |||
110 | "service.errorHandler.headline": "Oh no!", | 115 | "service.errorHandler.headline": "Oh no!", |
111 | "service.errorHandler.message": "Error", | 116 | "service.errorHandler.message": "Error", |
112 | "service.errorHandler.text": "{name} has failed to load.", | 117 | "service.errorHandler.text": "{name} has failed to load.", |
118 | "service.webviewLoader.loading": "Loading", | ||
113 | "services.getStarted": "Get started", | 119 | "services.getStarted": "Get started", |
114 | "services.welcome": "Welcome to Franz", | 120 | "services.welcome": "Welcome to Franz", |
115 | "settings.account.account.editButton": "Edit account", | 121 | "settings.account.account.editButton": "Edit account", |
@@ -170,6 +176,7 @@ | |||
170 | "settings.navigation.settings": "Settings", | 176 | "settings.navigation.settings": "Settings", |
171 | "settings.navigation.team": "Manage Team", | 177 | "settings.navigation.team": "Manage Team", |
172 | "settings.navigation.yourServices": "Your services", | 178 | "settings.navigation.yourServices": "Your services", |
179 | "settings.navigation.yourWorkspaces": "Your workspaces", | ||
173 | "settings.recipes.all": "All services", | 180 | "settings.recipes.all": "All services", |
174 | "settings.recipes.dev": "Development", | 181 | "settings.recipes.dev": "Development", |
175 | "settings.recipes.headline": "Available services", | 182 | "settings.recipes.headline": "Available services", |
@@ -231,7 +238,7 @@ | |||
231 | "settings.team.copy": "Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!", | 238 | "settings.team.copy": "Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!", |
232 | "settings.team.headline": "Team", | 239 | "settings.team.headline": "Team", |
233 | "settings.team.intro": "You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.", | 240 | "settings.team.intro": "You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.", |
234 | "settings.team.manageAction": "Manage your Team", | 241 | "settings.team.manageAction": "Manage your Team on meetfranz.com", |
235 | "settings.team.upgradeAction": "Upgrade your Account", | 242 | "settings.team.upgradeAction": "Upgrade your Account", |
236 | "settings.user.form.accountType.company": "Company", | 243 | "settings.user.form.accountType.company": "Company", |
237 | "settings.user.form.accountType.individual": "Individual", | 244 | "settings.user.form.accountType.individual": "Individual", |
@@ -242,8 +249,25 @@ | |||
242 | "settings.user.form.firstname": "First Name", | 249 | "settings.user.form.firstname": "First Name", |
243 | "settings.user.form.lastname": "Last Name", | 250 | "settings.user.form.lastname": "Last Name", |
244 | "settings.user.form.newPassword": "New password", | 251 | "settings.user.form.newPassword": "New password", |
252 | "settings.workspace.add.form.name": "Name", | ||
253 | "settings.workspace.add.form.submitButton": "Create workspace", | ||
254 | "settings.workspace.form.buttonDelete": "Delete workspace", | ||
255 | "settings.workspace.form.buttonSave": "Save workspace", | ||
256 | "settings.workspace.form.name": "Name", | ||
257 | "settings.workspace.form.servicesInWorkspaceHeadline": "Services in this Workspace", | ||
258 | "settings.workspace.form.yourWorkspaces": "Your workspaces", | ||
259 | "settings.workspaces.deletedInfo": "Workspace has been deleted", | ||
260 | "settings.workspaces.headline": "Your workspaces", | ||
261 | "settings.workspaces.noWorkspacesAdded": "You haven't added any workspaces yet.", | ||
262 | "settings.workspaces.tryReloadWorkspaces": "Try again", | ||
263 | "settings.workspaces.updatedInfo": "Your changes have been saved", | ||
264 | "settings.workspaces.workspaceFeatureHeadline": "Less is More: Introducing Franz Workspaces", | ||
265 | "settings.workspaces.workspaceFeatureInfo": "Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time. You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.", | ||
266 | "settings.workspaces.workspacesRequestFailed": "Could not load your workspaces", | ||
245 | "sidebar.addNewService": "Add new service", | 267 | "sidebar.addNewService": "Add new service", |
268 | "sidebar.closeWorkspaceDrawer": "Close workspace drawer", | ||
246 | "sidebar.muteApp": "Disable notifications & audio", | 269 | "sidebar.muteApp": "Disable notifications & audio", |
270 | "sidebar.openWorkspaceDrawer": "Open workspace drawer", | ||
247 | "sidebar.settings": "Settings", | 271 | "sidebar.settings": "Settings", |
248 | "sidebar.unmuteApp": "Enable notifications & audio", | 272 | "sidebar.unmuteApp": "Enable notifications & audio", |
249 | "signup.company.label": "Company", | 273 | "signup.company.label": "Company", |
@@ -288,5 +312,16 @@ | |||
288 | "validation.required": "{field} is required", | 312 | "validation.required": "{field} is required", |
289 | "validation.url": "{field} is not a valid URL", | 313 | "validation.url": "{field} is not a valid URL", |
290 | "welcome.loginButton": "Login to your account", | 314 | "welcome.loginButton": "Login to your account", |
291 | "welcome.signupButton": "Create a free account" | 315 | "welcome.signupButton": "Create a free account", |
292 | } \ No newline at end of file | 316 | "workspaceDrawer.addNewWorkspaceLabel": "Add new workspace", |
317 | "workspaceDrawer.allServices": "All services", | ||
318 | "workspaceDrawer.headline": "Workspaces", | ||
319 | "workspaceDrawer.item.contextMenuEdit": "edit", | ||
320 | "workspaceDrawer.item.noServicesAddedYet": "No services added yet", | ||
321 | "workspaceDrawer.premiumCtaButtonLabel": "Create your first workspace", | ||
322 | "workspaceDrawer.proFeatureBadge": "Premium feature", | ||
323 | "workspaceDrawer.reactivatePremiumAccountLabel": "Reactivate premium account", | ||
324 | "workspaceDrawer.workspaceFeatureInfo": "<p>Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.</p><p>You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.</p>", | ||
325 | "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", | ||
326 | "workspaces.switchingIndicator.switchingTo": "Switching to" | ||
327 | } | ||
diff --git a/src/i18n/messages/src/components/layout/AppLayout.json b/src/i18n/messages/src/components/layout/AppLayout.json index 07603d062..92593ed5c 100644 --- a/src/i18n/messages/src/components/layout/AppLayout.json +++ b/src/i18n/messages/src/components/layout/AppLayout.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Your services have been updated.", | 4 | "defaultMessage": "!!!Your services have been updated.", |
5 | "file": "src/components/layout/AppLayout.js", | 5 | "file": "src/components/layout/AppLayout.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 22, | 7 | "line": 25, |
8 | "column": 19 | 8 | "column": 19 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 25, | 11 | "line": 28, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!A new update for Franz is available.", | 17 | "defaultMessage": "!!!A new update for Franz is available.", |
18 | "file": "src/components/layout/AppLayout.js", | 18 | "file": "src/components/layout/AppLayout.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 26, | 20 | "line": 29, |
21 | "column": 19 | 21 | "column": 19 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 29, | 24 | "line": 32, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
@@ -30,11 +30,11 @@ | |||
30 | "defaultMessage": "!!!Reload services", | 30 | "defaultMessage": "!!!Reload services", |
31 | "file": "src/components/layout/AppLayout.js", | 31 | "file": "src/components/layout/AppLayout.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 30, | 33 | "line": 33, |
34 | "column": 24 | 34 | "column": 24 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 33, | 37 | "line": 36, |
38 | "column": 3 | 38 | "column": 3 |
39 | } | 39 | } |
40 | }, | 40 | }, |
@@ -43,11 +43,11 @@ | |||
43 | "defaultMessage": "!!!Changelog", | 43 | "defaultMessage": "!!!Changelog", |
44 | "file": "src/components/layout/AppLayout.js", | 44 | "file": "src/components/layout/AppLayout.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 34, | 46 | "line": 37, |
47 | "column": 13 | 47 | "column": 13 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 37, | 50 | "line": 40, |
51 | "column": 3 | 51 | "column": 3 |
52 | } | 52 | } |
53 | }, | 53 | }, |
@@ -56,11 +56,11 @@ | |||
56 | "defaultMessage": "!!!Restart & install update", | 56 | "defaultMessage": "!!!Restart & install update", |
57 | "file": "src/components/layout/AppLayout.js", | 57 | "file": "src/components/layout/AppLayout.js", |
58 | "start": { | 58 | "start": { |
59 | "line": 38, | 59 | "line": 41, |
60 | "column": 23 | 60 | "column": 23 |
61 | }, | 61 | }, |
62 | "end": { | 62 | "end": { |
63 | "line": 41, | 63 | "line": 44, |
64 | "column": 3 | 64 | "column": 3 |
65 | } | 65 | } |
66 | }, | 66 | }, |
@@ -69,11 +69,11 @@ | |||
69 | "defaultMessage": "!!!Could not load services and user information", | 69 | "defaultMessage": "!!!Could not load services and user information", |
70 | "file": "src/components/layout/AppLayout.js", | 70 | "file": "src/components/layout/AppLayout.js", |
71 | "start": { | 71 | "start": { |
72 | "line": 42, | 72 | "line": 45, |
73 | "column": 26 | 73 | "column": 26 |
74 | }, | 74 | }, |
75 | "end": { | 75 | "end": { |
76 | "line": 45, | 76 | "line": 48, |
77 | "column": 3 | 77 | "column": 3 |
78 | } | 78 | } |
79 | } | 79 | } |
diff --git a/src/i18n/messages/src/components/layout/Sidebar.json b/src/i18n/messages/src/components/layout/Sidebar.json index 7aa00a186..d67adc96e 100644 --- a/src/i18n/messages/src/components/layout/Sidebar.json +++ b/src/i18n/messages/src/components/layout/Sidebar.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Settings", | 4 | "defaultMessage": "!!!Settings", |
5 | "file": "src/components/layout/Sidebar.js", | 5 | "file": "src/components/layout/Sidebar.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 11, | 7 | "line": 13, |
8 | "column": 12 | 8 | "column": 12 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 14, | 11 | "line": 16, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!Add new service", | 17 | "defaultMessage": "!!!Add new service", |
18 | "file": "src/components/layout/Sidebar.js", | 18 | "file": "src/components/layout/Sidebar.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 15, | 20 | "line": 17, |
21 | "column": 17 | 21 | "column": 17 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 18, | 24 | "line": 20, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
@@ -30,11 +30,11 @@ | |||
30 | "defaultMessage": "!!!Disable notifications & audio", | 30 | "defaultMessage": "!!!Disable notifications & audio", |
31 | "file": "src/components/layout/Sidebar.js", | 31 | "file": "src/components/layout/Sidebar.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 19, | 33 | "line": 21, |
34 | "column": 8 | 34 | "column": 8 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 22, | 37 | "line": 24, |
38 | "column": 3 | 38 | "column": 3 |
39 | } | 39 | } |
40 | }, | 40 | }, |
@@ -43,11 +43,37 @@ | |||
43 | "defaultMessage": "!!!Enable notifications & audio", | 43 | "defaultMessage": "!!!Enable notifications & audio", |
44 | "file": "src/components/layout/Sidebar.js", | 44 | "file": "src/components/layout/Sidebar.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 23, | 46 | "line": 25, |
47 | "column": 10 | 47 | "column": 10 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 26, | 50 | "line": 28, |
51 | "column": 3 | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | "id": "sidebar.openWorkspaceDrawer", | ||
56 | "defaultMessage": "!!!Open workspace drawer", | ||
57 | "file": "src/components/layout/Sidebar.js", | ||
58 | "start": { | ||
59 | "line": 29, | ||
60 | "column": 23 | ||
61 | }, | ||
62 | "end": { | ||
63 | "line": 32, | ||
64 | "column": 3 | ||
65 | } | ||
66 | }, | ||
67 | { | ||
68 | "id": "sidebar.closeWorkspaceDrawer", | ||
69 | "defaultMessage": "!!!Close workspace drawer", | ||
70 | "file": "src/components/layout/Sidebar.js", | ||
71 | "start": { | ||
72 | "line": 33, | ||
73 | "column": 24 | ||
74 | }, | ||
75 | "end": { | ||
76 | "line": 36, | ||
51 | "column": 3 | 77 | "column": 3 |
52 | } | 78 | } |
53 | } | 79 | } |
diff --git a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json index 5b854641a..70a989211 100644 --- a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json +++ b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Available services", | 4 | "defaultMessage": "!!!Available services", |
5 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 5 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 9, | 7 | "line": 13, |
8 | "column": 21 | 8 | "column": 21 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 12, | 11 | "line": 16, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,24 @@ | |||
17 | "defaultMessage": "!!!Your services", | 17 | "defaultMessage": "!!!Your services", |
18 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 18 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 13, | 20 | "line": 17, |
21 | "column": 16 | 21 | "column": 16 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 16, | 24 | "line": 20, |
25 | "column": 3 | ||
26 | } | ||
27 | }, | ||
28 | { | ||
29 | "id": "settings.navigation.yourWorkspaces", | ||
30 | "defaultMessage": "!!!Your workspaces", | ||
31 | "file": "src/components/settings/navigation/SettingsNavigation.js", | ||
32 | "start": { | ||
33 | "line": 21, | ||
34 | "column": 18 | ||
35 | }, | ||
36 | "end": { | ||
37 | "line": 24, | ||
25 | "column": 3 | 38 | "column": 3 |
26 | } | 39 | } |
27 | }, | 40 | }, |
@@ -30,11 +43,11 @@ | |||
30 | "defaultMessage": "!!!Account", | 43 | "defaultMessage": "!!!Account", |
31 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 44 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
32 | "start": { | 45 | "start": { |
33 | "line": 17, | 46 | "line": 25, |
34 | "column": 11 | 47 | "column": 11 |
35 | }, | 48 | }, |
36 | "end": { | 49 | "end": { |
37 | "line": 20, | 50 | "line": 28, |
38 | "column": 3 | 51 | "column": 3 |
39 | } | 52 | } |
40 | }, | 53 | }, |
@@ -43,11 +56,11 @@ | |||
43 | "defaultMessage": "!!!Manage Team", | 56 | "defaultMessage": "!!!Manage Team", |
44 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 57 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
45 | "start": { | 58 | "start": { |
46 | "line": 21, | 59 | "line": 29, |
47 | "column": 8 | 60 | "column": 8 |
48 | }, | 61 | }, |
49 | "end": { | 62 | "end": { |
50 | "line": 24, | 63 | "line": 32, |
51 | "column": 3 | 64 | "column": 3 |
52 | } | 65 | } |
53 | }, | 66 | }, |
@@ -56,11 +69,11 @@ | |||
56 | "defaultMessage": "!!!Settings", | 69 | "defaultMessage": "!!!Settings", |
57 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 70 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
58 | "start": { | 71 | "start": { |
59 | "line": 25, | 72 | "line": 33, |
60 | "column": 12 | 73 | "column": 12 |
61 | }, | 74 | }, |
62 | "end": { | 75 | "end": { |
63 | "line": 28, | 76 | "line": 36, |
64 | "column": 3 | 77 | "column": 3 |
65 | } | 78 | } |
66 | }, | 79 | }, |
@@ -69,11 +82,11 @@ | |||
69 | "defaultMessage": "!!!Invite Friends", | 82 | "defaultMessage": "!!!Invite Friends", |
70 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 83 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
71 | "start": { | 84 | "start": { |
72 | "line": 29, | 85 | "line": 37, |
73 | "column": 17 | 86 | "column": 17 |
74 | }, | 87 | }, |
75 | "end": { | 88 | "end": { |
76 | "line": 32, | 89 | "line": 40, |
77 | "column": 3 | 90 | "column": 3 |
78 | } | 91 | } |
79 | }, | 92 | }, |
@@ -82,11 +95,11 @@ | |||
82 | "defaultMessage": "!!!Logout", | 95 | "defaultMessage": "!!!Logout", |
83 | "file": "src/components/settings/navigation/SettingsNavigation.js", | 96 | "file": "src/components/settings/navigation/SettingsNavigation.js", |
84 | "start": { | 97 | "start": { |
85 | "line": 33, | 98 | "line": 41, |
86 | "column": 10 | 99 | "column": 10 |
87 | }, | 100 | }, |
88 | "end": { | 101 | "end": { |
89 | "line": 36, | 102 | "line": 44, |
90 | "column": 3 | 103 | "column": 3 |
91 | } | 104 | } |
92 | } | 105 | } |
diff --git a/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json b/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json index 582d546fa..320d3ca3e 100644 --- a/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json +++ b/src/i18n/messages/src/components/ui/PremiumFeatureContainer/index.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Upgrade account", | 4 | "defaultMessage": "!!!Upgrade account", |
5 | "file": "src/components/ui/PremiumFeatureContainer/index.js", | 5 | "file": "src/components/ui/PremiumFeatureContainer/index.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 14, | 7 | "line": 15, |
8 | "column": 10 | 8 | "column": 10 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 17, | 11 | "line": 18, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | } | 14 | } |
diff --git a/src/i18n/messages/src/components/ui/WebviewLoader/index.json b/src/i18n/messages/src/components/ui/WebviewLoader/index.json new file mode 100644 index 000000000..ef3e4b593 --- /dev/null +++ b/src/i18n/messages/src/components/ui/WebviewLoader/index.json | |||
@@ -0,0 +1,15 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "service.webviewLoader.loading", | ||
4 | "defaultMessage": "!!!Loading", | ||
5 | "file": "src/components/ui/WebviewLoader/index.js", | ||
6 | "start": { | ||
7 | "line": 11, | ||
8 | "column": 11 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 14, | ||
12 | "column": 3 | ||
13 | } | ||
14 | } | ||
15 | ] \ No newline at end of file | ||
diff --git a/src/i18n/messages/src/features/workspaces/components/CreateWorkspaceForm.json b/src/i18n/messages/src/features/workspaces/components/CreateWorkspaceForm.json new file mode 100644 index 000000000..f62bac42c --- /dev/null +++ b/src/i18n/messages/src/features/workspaces/components/CreateWorkspaceForm.json | |||
@@ -0,0 +1,28 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "settings.workspace.add.form.submitButton", | ||
4 | "defaultMessage": "!!!Create workspace", | ||
5 | "file": "src/features/workspaces/components/CreateWorkspaceForm.js", | ||
6 | "start": { | ||
7 | "line": 13, | ||
8 | "column": 16 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 16, | ||
12 | "column": 3 | ||
13 | } | ||
14 | }, | ||
15 | { | ||
16 | "id": "settings.workspace.add.form.name", | ||
17 | "defaultMessage": "!!!Name", | ||
18 | "file": "src/features/workspaces/components/CreateWorkspaceForm.js", | ||
19 | "start": { | ||
20 | "line": 17, | ||
21 | "column": 8 | ||
22 | }, | ||
23 | "end": { | ||
24 | "line": 20, | ||
25 | "column": 3 | ||
26 | } | ||
27 | } | ||
28 | ] \ No newline at end of file | ||
diff --git a/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json b/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json new file mode 100644 index 000000000..7b0c3e1ce --- /dev/null +++ b/src/i18n/messages/src/features/workspaces/components/EditWorkspaceForm.json | |||
@@ -0,0 +1,67 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "settings.workspace.form.buttonDelete", | ||
4 | "defaultMessage": "!!!Delete workspace", | ||
5 | "file": "src/features/workspaces/components/EditWorkspaceForm.js", | ||
6 | "start": { | ||
7 | "line": 19, | ||
8 | "column": 16 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 22, | ||
12 | "column": 3 | ||
13 | } | ||
14 | }, | ||
15 | { | ||
16 | "id": "settings.workspace.form.buttonSave", | ||
17 | "defaultMessage": "!!!Save workspace", | ||
18 | "file": "src/features/workspaces/components/EditWorkspaceForm.js", | ||
19 | "start": { | ||
20 | "line": 23, | ||
21 | "column": 14 | ||
22 | }, | ||
23 | "end": { | ||
24 | "line": 26, | ||
25 | "column": 3 | ||
26 | } | ||
27 | }, | ||
28 | { | ||
29 | "id": "settings.workspace.form.name", | ||
30 | "defaultMessage": "!!!Name", | ||
31 | "file": "src/features/workspaces/components/EditWorkspaceForm.js", | ||
32 | "start": { | ||
33 | "line": 27, | ||
34 | "column": 8 | ||
35 | }, | ||
36 | "end": { | ||
37 | "line": 30, | ||
38 | "column": 3 | ||
39 | } | ||
40 | }, | ||
41 | { | ||
42 | "id": "settings.workspace.form.yourWorkspaces", | ||
43 | "defaultMessage": "!!!Your workspaces", | ||
44 | "file": "src/features/workspaces/components/EditWorkspaceForm.js", | ||
45 | "start": { | ||
46 | "line": 31, | ||
47 | "column": 18 | ||
48 | }, | ||
49 | "end": { | ||
50 | "line": 34, | ||
51 | "column": 3 | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | "id": "settings.workspace.form.servicesInWorkspaceHeadline", | ||
56 | "defaultMessage": "!!!Services in this Workspace", | ||
57 | "file": "src/features/workspaces/components/EditWorkspaceForm.js", | ||
58 | "start": { | ||
59 | "line": 35, | ||
60 | "column": 31 | ||
61 | }, | ||
62 | "end": { | ||
63 | "line": 38, | ||
64 | "column": 3 | ||
65 | } | ||
66 | } | ||
67 | ] \ No newline at end of file | ||
diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json new file mode 100644 index 000000000..9f0935620 --- /dev/null +++ b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawer.json | |||
@@ -0,0 +1,106 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "workspaceDrawer.headline", | ||
4 | "defaultMessage": "!!!Workspaces", | ||
5 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
6 | "start": { | ||
7 | "line": 16, | ||
8 | "column": 12 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 19, | ||
12 | "column": 3 | ||
13 | } | ||
14 | }, | ||
15 | { | ||
16 | "id": "workspaceDrawer.allServices", | ||
17 | "defaultMessage": "!!!All services", | ||
18 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
19 | "start": { | ||
20 | "line": 20, | ||
21 | "column": 15 | ||
22 | }, | ||
23 | "end": { | ||
24 | "line": 23, | ||
25 | "column": 3 | ||
26 | } | ||
27 | }, | ||
28 | { | ||
29 | "id": "workspaceDrawer.workspacesSettingsTooltip", | ||
30 | "defaultMessage": "!!!Workspaces settings", | ||
31 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
32 | "start": { | ||
33 | "line": 24, | ||
34 | "column": 29 | ||
35 | }, | ||
36 | "end": { | ||
37 | "line": 27, | ||
38 | "column": 3 | ||
39 | } | ||
40 | }, | ||
41 | { | ||
42 | "id": "workspaceDrawer.workspaceFeatureInfo", | ||
43 | "defaultMessage": "!!!Info about workspace feature", | ||
44 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
45 | "start": { | ||
46 | "line": 28, | ||
47 | "column": 24 | ||
48 | }, | ||
49 | "end": { | ||
50 | "line": 31, | ||
51 | "column": 3 | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | "id": "workspaceDrawer.premiumCtaButtonLabel", | ||
56 | "defaultMessage": "!!!Create your first workspace", | ||
57 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
58 | "start": { | ||
59 | "line": 32, | ||
60 | "column": 25 | ||
61 | }, | ||
62 | "end": { | ||
63 | "line": 35, | ||
64 | "column": 3 | ||
65 | } | ||
66 | }, | ||
67 | { | ||
68 | "id": "workspaceDrawer.reactivatePremiumAccountLabel", | ||
69 | "defaultMessage": "!!!Reactivate premium account", | ||
70 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
71 | "start": { | ||
72 | "line": 36, | ||
73 | "column": 28 | ||
74 | }, | ||
75 | "end": { | ||
76 | "line": 39, | ||
77 | "column": 3 | ||
78 | } | ||
79 | }, | ||
80 | { | ||
81 | "id": "workspaceDrawer.addNewWorkspaceLabel", | ||
82 | "defaultMessage": "!!!add new workspace", | ||
83 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
84 | "start": { | ||
85 | "line": 40, | ||
86 | "column": 24 | ||
87 | }, | ||
88 | "end": { | ||
89 | "line": 43, | ||
90 | "column": 3 | ||
91 | } | ||
92 | }, | ||
93 | { | ||
94 | "id": "workspaceDrawer.proFeatureBadge", | ||
95 | "defaultMessage": "!!!Premium feature", | ||
96 | "file": "src/features/workspaces/components/WorkspaceDrawer.js", | ||
97 | "start": { | ||
98 | "line": 44, | ||
99 | "column": 23 | ||
100 | }, | ||
101 | "end": { | ||
102 | "line": 47, | ||
103 | "column": 3 | ||
104 | } | ||
105 | } | ||
106 | ] \ No newline at end of file | ||
diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawerItem.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawerItem.json new file mode 100644 index 000000000..4ff190606 --- /dev/null +++ b/src/i18n/messages/src/features/workspaces/components/WorkspaceDrawerItem.json | |||
@@ -0,0 +1,28 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "workspaceDrawer.item.noServicesAddedYet", | ||
4 | "defaultMessage": "!!!No services added yet", | ||
5 | "file": "src/features/workspaces/components/WorkspaceDrawerItem.js", | ||
6 | "start": { | ||
7 | "line": 12, | ||
8 | "column": 22 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 15, | ||
12 | "column": 3 | ||
13 | } | ||
14 | }, | ||
15 | { | ||
16 | "id": "workspaceDrawer.item.contextMenuEdit", | ||
17 | "defaultMessage": "!!!edit", | ||
18 | "file": "src/features/workspaces/components/WorkspaceDrawerItem.js", | ||
19 | "start": { | ||
20 | "line": 16, | ||
21 | "column": 19 | ||
22 | }, | ||
23 | "end": { | ||
24 | "line": 19, | ||
25 | "column": 3 | ||
26 | } | ||
27 | } | ||
28 | ] \ No newline at end of file | ||
diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspaceSwitchingIndicator.json b/src/i18n/messages/src/features/workspaces/components/WorkspaceSwitchingIndicator.json new file mode 100644 index 000000000..4f3e6d55c --- /dev/null +++ b/src/i18n/messages/src/features/workspaces/components/WorkspaceSwitchingIndicator.json | |||
@@ -0,0 +1,15 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "workspaces.switchingIndicator.switchingTo", | ||
4 | "defaultMessage": "!!!Switching to", | ||
5 | "file": "src/features/workspaces/components/WorkspaceSwitchingIndicator.js", | ||
6 | "start": { | ||
7 | "line": 12, | ||
8 | "column": 15 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 15, | ||
12 | "column": 3 | ||
13 | } | ||
14 | } | ||
15 | ] \ No newline at end of file | ||
diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json new file mode 100644 index 000000000..ef8f1bebc --- /dev/null +++ b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json | |||
@@ -0,0 +1,106 @@ | |||
1 | [ | ||
2 | { | ||
3 | "id": "settings.workspaces.headline", | ||
4 | "defaultMessage": "!!!Your workspaces", | ||
5 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
6 | "start": { | ||
7 | "line": 17, | ||
8 | "column": 12 | ||
9 | }, | ||
10 | "end": { | ||
11 | "line": 20, | ||
12 | "column": 3 | ||
13 | } | ||
14 | }, | ||
15 | { | ||
16 | "id": "settings.workspaces.noWorkspacesAdded", | ||
17 | "defaultMessage": "!!!You haven't added any workspaces yet.", | ||
18 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
19 | "start": { | ||
20 | "line": 21, | ||
21 | "column": 19 | ||
22 | }, | ||
23 | "end": { | ||
24 | "line": 24, | ||
25 | "column": 3 | ||
26 | } | ||
27 | }, | ||
28 | { | ||
29 | "id": "settings.workspaces.workspacesRequestFailed", | ||
30 | "defaultMessage": "!!!Could not load your workspaces", | ||
31 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
32 | "start": { | ||
33 | "line": 25, | ||
34 | "column": 27 | ||
35 | }, | ||
36 | "end": { | ||
37 | "line": 28, | ||
38 | "column": 3 | ||
39 | } | ||
40 | }, | ||
41 | { | ||
42 | "id": "settings.workspaces.tryReloadWorkspaces", | ||
43 | "defaultMessage": "!!!Try again", | ||
44 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
45 | "start": { | ||
46 | "line": 29, | ||
47 | "column": 23 | ||
48 | }, | ||
49 | "end": { | ||
50 | "line": 32, | ||
51 | "column": 3 | ||
52 | } | ||
53 | }, | ||
54 | { | ||
55 | "id": "settings.workspaces.updatedInfo", | ||
56 | "defaultMessage": "!!!Your changes have been saved", | ||
57 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
58 | "start": { | ||
59 | "line": 33, | ||
60 | "column": 15 | ||
61 | }, | ||
62 | "end": { | ||
63 | "line": 36, | ||
64 | "column": 3 | ||
65 | } | ||
66 | }, | ||
67 | { | ||
68 | "id": "settings.workspaces.deletedInfo", | ||
69 | "defaultMessage": "!!!Workspace has been deleted", | ||
70 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
71 | "start": { | ||
72 | "line": 37, | ||
73 | "column": 15 | ||
74 | }, | ||
75 | "end": { | ||
76 | "line": 40, | ||
77 | "column": 3 | ||
78 | } | ||
79 | }, | ||
80 | { | ||
81 | "id": "settings.workspaces.workspaceFeatureInfo", | ||
82 | "defaultMessage": "!!!Info about workspace feature", | ||
83 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
84 | "start": { | ||
85 | "line": 41, | ||
86 | "column": 24 | ||
87 | }, | ||
88 | "end": { | ||
89 | "line": 44, | ||
90 | "column": 3 | ||
91 | } | ||
92 | }, | ||
93 | { | ||
94 | "id": "settings.workspaces.workspaceFeatureHeadline", | ||
95 | "defaultMessage": "!!!Less is More: Introducing Franz Workspaces", | ||
96 | "file": "src/features/workspaces/components/WorkspacesDashboard.js", | ||
97 | "start": { | ||
98 | "line": 45, | ||
99 | "column": 28 | ||
100 | }, | ||
101 | "end": { | ||
102 | "line": 48, | ||
103 | "column": 3 | ||
104 | } | ||
105 | } | ||
106 | ] \ No newline at end of file | ||
diff --git a/src/i18n/messages/src/lib/Menu.json b/src/i18n/messages/src/lib/Menu.json index 9314f5cce..3889d39e0 100644 --- a/src/i18n/messages/src/lib/Menu.json +++ b/src/i18n/messages/src/lib/Menu.json | |||
@@ -4,11 +4,11 @@ | |||
4 | "defaultMessage": "!!!Edit", | 4 | "defaultMessage": "!!!Edit", |
5 | "file": "src/lib/Menu.js", | 5 | "file": "src/lib/Menu.js", |
6 | "start": { | 6 | "start": { |
7 | "line": 10, | 7 | "line": 13, |
8 | "column": 8 | 8 | "column": 8 |
9 | }, | 9 | }, |
10 | "end": { | 10 | "end": { |
11 | "line": 13, | 11 | "line": 16, |
12 | "column": 3 | 12 | "column": 3 |
13 | } | 13 | } |
14 | }, | 14 | }, |
@@ -17,11 +17,11 @@ | |||
17 | "defaultMessage": "!!!Undo", | 17 | "defaultMessage": "!!!Undo", |
18 | "file": "src/lib/Menu.js", | 18 | "file": "src/lib/Menu.js", |
19 | "start": { | 19 | "start": { |
20 | "line": 14, | 20 | "line": 17, |
21 | "column": 8 | 21 | "column": 8 |
22 | }, | 22 | }, |
23 | "end": { | 23 | "end": { |
24 | "line": 17, | 24 | "line": 20, |
25 | "column": 3 | 25 | "column": 3 |
26 | } | 26 | } |
27 | }, | 27 | }, |
@@ -30,11 +30,11 @@ | |||
30 | "defaultMessage": "!!!Redo", | 30 | "defaultMessage": "!!!Redo", |
31 | "file": "src/lib/Menu.js", | 31 | "file": "src/lib/Menu.js", |
32 | "start": { | 32 | "start": { |
33 | "line": 18, | 33 | "line": 21, |
34 | "column": 8 | 34 | "column": 8 |
35 | }, | 35 | }, |
36 | "end": { | 36 | "end": { |
37 | "line": 21, | 37 | "line": 24, |
38 | "column": 3 | 38 | "column": 3 |
39 | } | 39 | } |
40 | }, | 40 | }, |
@@ -43,11 +43,11 @@ | |||
43 | "defaultMessage": "!!!Cut", | 43 | "defaultMessage": "!!!Cut", |
44 | "file": "src/lib/Menu.js", | 44 | "file": "src/lib/Menu.js", |
45 | "start": { | 45 | "start": { |
46 | "line": 22, | 46 | "line": 25, |
47 | "column": 7 | 47 | "column": 7 |
48 | }, | 48 | }, |
49 | "end": { | 49 | "end": { |
50 | "line": 25, | 50 | "line": 28, |
51 | "column": 3 | 51 | "column": 3 |
52 | } | 52 | } |
53 | }, | 53 | }, |
@@ -56,11 +56,11 @@ | |||
56 | "defaultMessage": "!!!Copy", | 56 | "defaultMessage": "!!!Copy", |
57 | "file": "src/lib/Menu.js", | 57 | "file": "src/lib/Menu.js", |
58 | "start": { | 58 | "start": { |
59 | "line": 26, | 59 | "line": 29, |
60 | "column": 8 | 60 | "column": 8 |
61 | }, | 61 | }, |
62 | "end": { | 62 | "end": { |
63 | "line": 29, | 63 | "line": 32, |
64 | "column": 3 | 64 | "column": 3 |
65 | } | 65 | } |
66 | }, | 66 | }, |
@@ -69,11 +69,11 @@ | |||
69 | "defaultMessage": "!!!Paste", | 69 | "defaultMessage": "!!!Paste", |
70 | "file": "src/lib/Menu.js", | 70 | "file": "src/lib/Menu.js", |
71 | "start": { | 71 | "start": { |
72 | "line": 30, | 72 | "line": 33, |
73 | "column": 9 | 73 | "column": 9 |
74 | }, | 74 | }, |
75 | "end": { | 75 | "end": { |
76 | "line": 33, | 76 | "line": 36, |
77 | "column": 3 | 77 | "column": 3 |
78 | } | 78 | } |
79 | }, | 79 | }, |
@@ -82,11 +82,11 @@ | |||
82 | "defaultMessage": "!!!Paste And Match Style", | 82 | "defaultMessage": "!!!Paste And Match Style", |
83 | "file": "src/lib/Menu.js", | 83 | "file": "src/lib/Menu.js", |
84 | "start": { | 84 | "start": { |
85 | "line": 34, | 85 | "line": 37, |
86 | "column": 22 | 86 | "column": 22 |
87 | }, | 87 | }, |
88 | "end": { | 88 | "end": { |
89 | "line": 37, | 89 | "line": 40, |
90 | "column": 3 | 90 | "column": 3 |
91 | } | 91 | } |
92 | }, | 92 | }, |
@@ -95,11 +95,11 @@ | |||
95 | "defaultMessage": "!!!Delete", | 95 | "defaultMessage": "!!!Delete", |
96 | "file": "src/lib/Menu.js", | 96 | "file": "src/lib/Menu.js", |
97 | "start": { | 97 | "start": { |
98 | "line": 38, | 98 | "line": 41, |
99 | "column": 10 | 99 | "column": 10 |
100 | }, | 100 | }, |
101 | "end": { | 101 | "end": { |
102 | "line": 41, | 102 | "line": 44, |
103 | "column": 3 | 103 | "column": 3 |
104 | } | 104 | } |
105 | }, | 105 | }, |
@@ -108,11 +108,11 @@ | |||
108 | "defaultMessage": "!!!Select All", | 108 | "defaultMessage": "!!!Select All", |
109 | "file": "src/lib/Menu.js", | 109 | "file": "src/lib/Menu.js", |
110 | "start": { | 110 | "start": { |
111 | "line": 42, | 111 | "line": 45, |
112 | "column": 13 | 112 | "column": 13 |
113 | }, | 113 | }, |
114 | "end": { | 114 | "end": { |
115 | "line": 45, | 115 | "line": 48, |
116 | "column": 3 | 116 | "column": 3 |
117 | } | 117 | } |
118 | }, | 118 | }, |
@@ -121,11 +121,11 @@ | |||
121 | "defaultMessage": "!!!Speech", | 121 | "defaultMessage": "!!!Speech", |
122 | "file": "src/lib/Menu.js", | 122 | "file": "src/lib/Menu.js", |
123 | "start": { | 123 | "start": { |
124 | "line": 46, | 124 | "line": 49, |
125 | "column": 10 | 125 | "column": 10 |
126 | }, | 126 | }, |
127 | "end": { | 127 | "end": { |
128 | "line": 49, | 128 | "line": 52, |
129 | "column": 3 | 129 | "column": 3 |
130 | } | 130 | } |
131 | }, | 131 | }, |
@@ -134,11 +134,11 @@ | |||
134 | "defaultMessage": "!!!Start Speaking", | 134 | "defaultMessage": "!!!Start Speaking", |
135 | "file": "src/lib/Menu.js", | 135 | "file": "src/lib/Menu.js", |
136 | "start": { | 136 | "start": { |
137 | "line": 50, | 137 | "line": 53, |
138 | "column": 17 | 138 | "column": 17 |
139 | }, | 139 | }, |
140 | "end": { | 140 | "end": { |
141 | "line": 53, | 141 | "line": 56, |
142 | "column": 3 | 142 | "column": 3 |
143 | } | 143 | } |
144 | }, | 144 | }, |
@@ -147,11 +147,11 @@ | |||
147 | "defaultMessage": "!!!Stop Speaking", | 147 | "defaultMessage": "!!!Stop Speaking", |
148 | "file": "src/lib/Menu.js", | 148 | "file": "src/lib/Menu.js", |
149 | "start": { | 149 | "start": { |
150 | "line": 54, | 150 | "line": 57, |
151 | "column": 16 | 151 | "column": 16 |
152 | }, | 152 | }, |
153 | "end": { | 153 | "end": { |
154 | "line": 57, | 154 | "line": 60, |
155 | "column": 3 | 155 | "column": 3 |
156 | } | 156 | } |
157 | }, | 157 | }, |
@@ -160,11 +160,11 @@ | |||
160 | "defaultMessage": "!!!Start Dictation", | 160 | "defaultMessage": "!!!Start Dictation", |
161 | "file": "src/lib/Menu.js", | 161 | "file": "src/lib/Menu.js", |
162 | "start": { | 162 | "start": { |
163 | "line": 58, | 163 | "line": 61, |
164 | "column": 18 | 164 | "column": 18 |
165 | }, | 165 | }, |
166 | "end": { | 166 | "end": { |
167 | "line": 61, | 167 | "line": 64, |
168 | "column": 3 | 168 | "column": 3 |
169 | } | 169 | } |
170 | }, | 170 | }, |
@@ -173,11 +173,11 @@ | |||
173 | "defaultMessage": "!!!Emoji & Symbols", | 173 | "defaultMessage": "!!!Emoji & Symbols", |
174 | "file": "src/lib/Menu.js", | 174 | "file": "src/lib/Menu.js", |
175 | "start": { | 175 | "start": { |
176 | "line": 62, | 176 | "line": 65, |
177 | "column": 16 | 177 | "column": 16 |
178 | }, | 178 | }, |
179 | "end": { | 179 | "end": { |
180 | "line": 65, | 180 | "line": 68, |
181 | "column": 3 | 181 | "column": 3 |
182 | } | 182 | } |
183 | }, | 183 | }, |
@@ -186,11 +186,11 @@ | |||
186 | "defaultMessage": "!!!Actual Size", | 186 | "defaultMessage": "!!!Actual Size", |
187 | "file": "src/lib/Menu.js", | 187 | "file": "src/lib/Menu.js", |
188 | "start": { | 188 | "start": { |
189 | "line": 66, | 189 | "line": 69, |
190 | "column": 13 | 190 | "column": 13 |
191 | }, | 191 | }, |
192 | "end": { | 192 | "end": { |
193 | "line": 69, | 193 | "line": 72, |
194 | "column": 3 | 194 | "column": 3 |
195 | } | 195 | } |
196 | }, | 196 | }, |
@@ -199,11 +199,11 @@ | |||
199 | "defaultMessage": "!!!Zoom In", | 199 | "defaultMessage": "!!!Zoom In", |
200 | "file": "src/lib/Menu.js", | 200 | "file": "src/lib/Menu.js", |
201 | "start": { | 201 | "start": { |
202 | "line": 70, | 202 | "line": 73, |
203 | "column": 10 | 203 | "column": 10 |
204 | }, | 204 | }, |
205 | "end": { | 205 | "end": { |
206 | "line": 73, | 206 | "line": 76, |
207 | "column": 3 | 207 | "column": 3 |
208 | } | 208 | } |
209 | }, | 209 | }, |
@@ -212,11 +212,11 @@ | |||
212 | "defaultMessage": "!!!Zoom Out", | 212 | "defaultMessage": "!!!Zoom Out", |
213 | "file": "src/lib/Menu.js", | 213 | "file": "src/lib/Menu.js", |
214 | "start": { | 214 | "start": { |
215 | "line": 74, | 215 | "line": 77, |
216 | "column": 11 | 216 | "column": 11 |
217 | }, | 217 | }, |
218 | "end": { | 218 | "end": { |
219 | "line": 77, | 219 | "line": 80, |
220 | "column": 3 | 220 | "column": 3 |
221 | } | 221 | } |
222 | }, | 222 | }, |
@@ -225,11 +225,11 @@ | |||
225 | "defaultMessage": "!!!Enter Full Screen", | 225 | "defaultMessage": "!!!Enter Full Screen", |
226 | "file": "src/lib/Menu.js", | 226 | "file": "src/lib/Menu.js", |
227 | "start": { | 227 | "start": { |
228 | "line": 78, | 228 | "line": 81, |
229 | "column": 19 | 229 | "column": 19 |
230 | }, | 230 | }, |
231 | "end": { | 231 | "end": { |
232 | "line": 81, | 232 | "line": 84, |
233 | "column": 3 | 233 | "column": 3 |
234 | } | 234 | } |
235 | }, | 235 | }, |
@@ -238,11 +238,11 @@ | |||
238 | "defaultMessage": "!!!Exit Full Screen", | 238 | "defaultMessage": "!!!Exit Full Screen", |
239 | "file": "src/lib/Menu.js", | 239 | "file": "src/lib/Menu.js", |
240 | "start": { | 240 | "start": { |
241 | "line": 82, | 241 | "line": 85, |
242 | "column": 18 | 242 | "column": 18 |
243 | }, | 243 | }, |
244 | "end": { | 244 | "end": { |
245 | "line": 85, | 245 | "line": 88, |
246 | "column": 3 | 246 | "column": 3 |
247 | } | 247 | } |
248 | }, | 248 | }, |
@@ -251,11 +251,11 @@ | |||
251 | "defaultMessage": "!!!Toggle Full Screen", | 251 | "defaultMessage": "!!!Toggle Full Screen", |
252 | "file": "src/lib/Menu.js", | 252 | "file": "src/lib/Menu.js", |
253 | "start": { | 253 | "start": { |
254 | "line": 86, | 254 | "line": 89, |
255 | "column": 20 | 255 | "column": 20 |
256 | }, | 256 | }, |
257 | "end": { | 257 | "end": { |
258 | "line": 89, | 258 | "line": 92, |
259 | "column": 3 | 259 | "column": 3 |
260 | } | 260 | } |
261 | }, | 261 | }, |
@@ -264,11 +264,11 @@ | |||
264 | "defaultMessage": "!!!Toggle Developer Tools", | 264 | "defaultMessage": "!!!Toggle Developer Tools", |
265 | "file": "src/lib/Menu.js", | 265 | "file": "src/lib/Menu.js", |
266 | "start": { | 266 | "start": { |
267 | "line": 90, | 267 | "line": 93, |
268 | "column": 18 | 268 | "column": 18 |
269 | }, | 269 | }, |
270 | "end": { | 270 | "end": { |
271 | "line": 93, | 271 | "line": 96, |
272 | "column": 3 | 272 | "column": 3 |
273 | } | 273 | } |
274 | }, | 274 | }, |
@@ -277,11 +277,11 @@ | |||
277 | "defaultMessage": "!!!Toggle Service Developer Tools", | 277 | "defaultMessage": "!!!Toggle Service Developer Tools", |
278 | "file": "src/lib/Menu.js", | 278 | "file": "src/lib/Menu.js", |
279 | "start": { | 279 | "start": { |
280 | "line": 94, | 280 | "line": 97, |
281 | "column": 25 | 281 | "column": 25 |
282 | }, | 282 | }, |
283 | "end": { | 283 | "end": { |
284 | "line": 97, | 284 | "line": 100, |
285 | "column": 3 | 285 | "column": 3 |
286 | } | 286 | } |
287 | }, | 287 | }, |
@@ -290,11 +290,11 @@ | |||
290 | "defaultMessage": "!!!Reload Service", | 290 | "defaultMessage": "!!!Reload Service", |
291 | "file": "src/lib/Menu.js", | 291 | "file": "src/lib/Menu.js", |
292 | "start": { | 292 | "start": { |
293 | "line": 98, | 293 | "line": 101, |
294 | "column": 17 | 294 | "column": 17 |
295 | }, | 295 | }, |
296 | "end": { | 296 | "end": { |
297 | "line": 101, | 297 | "line": 104, |
298 | "column": 3 | 298 | "column": 3 |
299 | } | 299 | } |
300 | }, | 300 | }, |
@@ -303,11 +303,11 @@ | |||
303 | "defaultMessage": "!!!Reload Franz", | 303 | "defaultMessage": "!!!Reload Franz", |
304 | "file": "src/lib/Menu.js", | 304 | "file": "src/lib/Menu.js", |
305 | "start": { | 305 | "start": { |
306 | "line": 102, | 306 | "line": 105, |
307 | "column": 15 | 307 | "column": 15 |
308 | }, | 308 | }, |
309 | "end": { | 309 | "end": { |
310 | "line": 105, | 310 | "line": 108, |
311 | "column": 3 | 311 | "column": 3 |
312 | } | 312 | } |
313 | }, | 313 | }, |
@@ -316,11 +316,11 @@ | |||
316 | "defaultMessage": "!!!Minimize", | 316 | "defaultMessage": "!!!Minimize", |
317 | "file": "src/lib/Menu.js", | 317 | "file": "src/lib/Menu.js", |
318 | "start": { | 318 | "start": { |
319 | "line": 106, | 319 | "line": 109, |
320 | "column": 12 | 320 | "column": 12 |
321 | }, | 321 | }, |
322 | "end": { | 322 | "end": { |
323 | "line": 109, | 323 | "line": 112, |
324 | "column": 3 | 324 | "column": 3 |
325 | } | 325 | } |
326 | }, | 326 | }, |
@@ -329,11 +329,11 @@ | |||
329 | "defaultMessage": "!!!Close", | 329 | "defaultMessage": "!!!Close", |
330 | "file": "src/lib/Menu.js", | 330 | "file": "src/lib/Menu.js", |
331 | "start": { | 331 | "start": { |
332 | "line": 110, | 332 | "line": 113, |
333 | "column": 9 | 333 | "column": 9 |
334 | }, | 334 | }, |
335 | "end": { | 335 | "end": { |
336 | "line": 113, | 336 | "line": 116, |
337 | "column": 3 | 337 | "column": 3 |
338 | } | 338 | } |
339 | }, | 339 | }, |
@@ -342,11 +342,11 @@ | |||
342 | "defaultMessage": "!!!Learn More", | 342 | "defaultMessage": "!!!Learn More", |
343 | "file": "src/lib/Menu.js", | 343 | "file": "src/lib/Menu.js", |
344 | "start": { | 344 | "start": { |
345 | "line": 114, | 345 | "line": 117, |
346 | "column": 13 | 346 | "column": 13 |
347 | }, | 347 | }, |
348 | "end": { | 348 | "end": { |
349 | "line": 117, | 349 | "line": 120, |
350 | "column": 3 | 350 | "column": 3 |
351 | } | 351 | } |
352 | }, | 352 | }, |
@@ -355,11 +355,11 @@ | |||
355 | "defaultMessage": "!!!Changelog", | 355 | "defaultMessage": "!!!Changelog", |
356 | "file": "src/lib/Menu.js", | 356 | "file": "src/lib/Menu.js", |
357 | "start": { | 357 | "start": { |
358 | "line": 118, | 358 | "line": 121, |
359 | "column": 13 | 359 | "column": 13 |
360 | }, | 360 | }, |
361 | "end": { | 361 | "end": { |
362 | "line": 121, | 362 | "line": 124, |
363 | "column": 3 | 363 | "column": 3 |
364 | } | 364 | } |
365 | }, | 365 | }, |
@@ -368,11 +368,11 @@ | |||
368 | "defaultMessage": "!!!Support", | 368 | "defaultMessage": "!!!Support", |
369 | "file": "src/lib/Menu.js", | 369 | "file": "src/lib/Menu.js", |
370 | "start": { | 370 | "start": { |
371 | "line": 122, | 371 | "line": 125, |
372 | "column": 11 | 372 | "column": 11 |
373 | }, | 373 | }, |
374 | "end": { | 374 | "end": { |
375 | "line": 125, | 375 | "line": 128, |
376 | "column": 3 | 376 | "column": 3 |
377 | } | 377 | } |
378 | }, | 378 | }, |
@@ -381,11 +381,11 @@ | |||
381 | "defaultMessage": "!!!Terms of Service", | 381 | "defaultMessage": "!!!Terms of Service", |
382 | "file": "src/lib/Menu.js", | 382 | "file": "src/lib/Menu.js", |
383 | "start": { | 383 | "start": { |
384 | "line": 126, | 384 | "line": 129, |
385 | "column": 7 | 385 | "column": 7 |
386 | }, | 386 | }, |
387 | "end": { | 387 | "end": { |
388 | "line": 129, | 388 | "line": 132, |
389 | "column": 3 | 389 | "column": 3 |
390 | } | 390 | } |
391 | }, | 391 | }, |
@@ -394,11 +394,11 @@ | |||
394 | "defaultMessage": "!!!Privacy Statement", | 394 | "defaultMessage": "!!!Privacy Statement", |
395 | "file": "src/lib/Menu.js", | 395 | "file": "src/lib/Menu.js", |
396 | "start": { | 396 | "start": { |
397 | "line": 130, | 397 | "line": 133, |
398 | "column": 11 | 398 | "column": 11 |
399 | }, | 399 | }, |
400 | "end": { | 400 | "end": { |
401 | "line": 133, | 401 | "line": 136, |
402 | "column": 3 | 402 | "column": 3 |
403 | } | 403 | } |
404 | }, | 404 | }, |
@@ -407,11 +407,11 @@ | |||
407 | "defaultMessage": "!!!File", | 407 | "defaultMessage": "!!!File", |
408 | "file": "src/lib/Menu.js", | 408 | "file": "src/lib/Menu.js", |
409 | "start": { | 409 | "start": { |
410 | "line": 134, | 410 | "line": 137, |
411 | "column": 8 | 411 | "column": 8 |
412 | }, | 412 | }, |
413 | "end": { | 413 | "end": { |
414 | "line": 137, | 414 | "line": 140, |
415 | "column": 3 | 415 | "column": 3 |
416 | } | 416 | } |
417 | }, | 417 | }, |
@@ -420,11 +420,11 @@ | |||
420 | "defaultMessage": "!!!View", | 420 | "defaultMessage": "!!!View", |
421 | "file": "src/lib/Menu.js", | 421 | "file": "src/lib/Menu.js", |
422 | "start": { | 422 | "start": { |
423 | "line": 138, | 423 | "line": 141, |
424 | "column": 8 | 424 | "column": 8 |
425 | }, | 425 | }, |
426 | "end": { | 426 | "end": { |
427 | "line": 141, | 427 | "line": 144, |
428 | "column": 3 | 428 | "column": 3 |
429 | } | 429 | } |
430 | }, | 430 | }, |
@@ -433,11 +433,11 @@ | |||
433 | "defaultMessage": "!!!Services", | 433 | "defaultMessage": "!!!Services", |
434 | "file": "src/lib/Menu.js", | 434 | "file": "src/lib/Menu.js", |
435 | "start": { | 435 | "start": { |
436 | "line": 142, | 436 | "line": 145, |
437 | "column": 12 | 437 | "column": 12 |
438 | }, | 438 | }, |
439 | "end": { | 439 | "end": { |
440 | "line": 145, | 440 | "line": 148, |
441 | "column": 3 | 441 | "column": 3 |
442 | } | 442 | } |
443 | }, | 443 | }, |
@@ -446,11 +446,11 @@ | |||
446 | "defaultMessage": "!!!Window", | 446 | "defaultMessage": "!!!Window", |
447 | "file": "src/lib/Menu.js", | 447 | "file": "src/lib/Menu.js", |
448 | "start": { | 448 | "start": { |
449 | "line": 146, | 449 | "line": 149, |
450 | "column": 10 | 450 | "column": 10 |
451 | }, | 451 | }, |
452 | "end": { | 452 | "end": { |
453 | "line": 149, | 453 | "line": 152, |
454 | "column": 3 | 454 | "column": 3 |
455 | } | 455 | } |
456 | }, | 456 | }, |
@@ -459,11 +459,11 @@ | |||
459 | "defaultMessage": "!!!Help", | 459 | "defaultMessage": "!!!Help", |
460 | "file": "src/lib/Menu.js", | 460 | "file": "src/lib/Menu.js", |
461 | "start": { | 461 | "start": { |
462 | "line": 150, | 462 | "line": 153, |
463 | "column": 8 | 463 | "column": 8 |
464 | }, | 464 | }, |
465 | "end": { | 465 | "end": { |
466 | "line": 153, | 466 | "line": 156, |
467 | "column": 3 | 467 | "column": 3 |
468 | } | 468 | } |
469 | }, | 469 | }, |
@@ -472,11 +472,11 @@ | |||
472 | "defaultMessage": "!!!About Franz", | 472 | "defaultMessage": "!!!About Franz", |
473 | "file": "src/lib/Menu.js", | 473 | "file": "src/lib/Menu.js", |
474 | "start": { | 474 | "start": { |
475 | "line": 154, | 475 | "line": 157, |
476 | "column": 9 | 476 | "column": 9 |
477 | }, | 477 | }, |
478 | "end": { | 478 | "end": { |
479 | "line": 157, | 479 | "line": 160, |
480 | "column": 3 | 480 | "column": 3 |
481 | } | 481 | } |
482 | }, | 482 | }, |
@@ -485,11 +485,11 @@ | |||
485 | "defaultMessage": "!!!Settings", | 485 | "defaultMessage": "!!!Settings", |
486 | "file": "src/lib/Menu.js", | 486 | "file": "src/lib/Menu.js", |
487 | "start": { | 487 | "start": { |
488 | "line": 158, | 488 | "line": 161, |
489 | "column": 12 | 489 | "column": 12 |
490 | }, | 490 | }, |
491 | "end": { | 491 | "end": { |
492 | "line": 161, | 492 | "line": 164, |
493 | "column": 3 | 493 | "column": 3 |
494 | } | 494 | } |
495 | }, | 495 | }, |
@@ -498,11 +498,11 @@ | |||
498 | "defaultMessage": "!!!Hide", | 498 | "defaultMessage": "!!!Hide", |
499 | "file": "src/lib/Menu.js", | 499 | "file": "src/lib/Menu.js", |
500 | "start": { | 500 | "start": { |
501 | "line": 162, | 501 | "line": 165, |
502 | "column": 8 | 502 | "column": 8 |
503 | }, | 503 | }, |
504 | "end": { | 504 | "end": { |
505 | "line": 165, | 505 | "line": 168, |
506 | "column": 3 | 506 | "column": 3 |
507 | } | 507 | } |
508 | }, | 508 | }, |
@@ -511,11 +511,11 @@ | |||
511 | "defaultMessage": "!!!Hide Others", | 511 | "defaultMessage": "!!!Hide Others", |
512 | "file": "src/lib/Menu.js", | 512 | "file": "src/lib/Menu.js", |
513 | "start": { | 513 | "start": { |
514 | "line": 166, | 514 | "line": 169, |
515 | "column": 14 | 515 | "column": 14 |
516 | }, | 516 | }, |
517 | "end": { | 517 | "end": { |
518 | "line": 169, | 518 | "line": 172, |
519 | "column": 3 | 519 | "column": 3 |
520 | } | 520 | } |
521 | }, | 521 | }, |
@@ -524,11 +524,11 @@ | |||
524 | "defaultMessage": "!!!Unhide", | 524 | "defaultMessage": "!!!Unhide", |
525 | "file": "src/lib/Menu.js", | 525 | "file": "src/lib/Menu.js", |
526 | "start": { | 526 | "start": { |
527 | "line": 170, | 527 | "line": 173, |
528 | "column": 10 | 528 | "column": 10 |
529 | }, | 529 | }, |
530 | "end": { | 530 | "end": { |
531 | "line": 173, | 531 | "line": 176, |
532 | "column": 3 | 532 | "column": 3 |
533 | } | 533 | } |
534 | }, | 534 | }, |
@@ -537,11 +537,11 @@ | |||
537 | "defaultMessage": "!!!Quit", | 537 | "defaultMessage": "!!!Quit", |
538 | "file": "src/lib/Menu.js", | 538 | "file": "src/lib/Menu.js", |
539 | "start": { | 539 | "start": { |
540 | "line": 174, | 540 | "line": 177, |
541 | "column": 8 | 541 | "column": 8 |
542 | }, | 542 | }, |
543 | "end": { | 543 | "end": { |
544 | "line": 177, | 544 | "line": 180, |
545 | "column": 3 | 545 | "column": 3 |
546 | } | 546 | } |
547 | }, | 547 | }, |
@@ -550,11 +550,50 @@ | |||
550 | "defaultMessage": "!!!Add New Service...", | 550 | "defaultMessage": "!!!Add New Service...", |
551 | "file": "src/lib/Menu.js", | 551 | "file": "src/lib/Menu.js", |
552 | "start": { | 552 | "start": { |
553 | "line": 178, | 553 | "line": 181, |
554 | "column": 17 | 554 | "column": 17 |
555 | }, | 555 | }, |
556 | "end": { | 556 | "end": { |
557 | "line": 181, | 557 | "line": 184, |
558 | "column": 3 | ||
559 | } | ||
560 | }, | ||
561 | { | ||
562 | "id": "menu.workspaces.addNewWorkspace", | ||
563 | "defaultMessage": "!!!Add New Workspace...", | ||
564 | "file": "src/lib/Menu.js", | ||
565 | "start": { | ||
566 | "line": 185, | ||
567 | "column": 19 | ||
568 | }, | ||
569 | "end": { | ||
570 | "line": 188, | ||
571 | "column": 3 | ||
572 | } | ||
573 | }, | ||
574 | { | ||
575 | "id": "menu.workspaces.openWorkspaceDrawer", | ||
576 | "defaultMessage": "!!!Open workspace drawer", | ||
577 | "file": "src/lib/Menu.js", | ||
578 | "start": { | ||
579 | "line": 189, | ||
580 | "column": 23 | ||
581 | }, | ||
582 | "end": { | ||
583 | "line": 192, | ||
584 | "column": 3 | ||
585 | } | ||
586 | }, | ||
587 | { | ||
588 | "id": "menu.workspaces.closeWorkspaceDrawer", | ||
589 | "defaultMessage": "!!!Close workspace drawer", | ||
590 | "file": "src/lib/Menu.js", | ||
591 | "start": { | ||
592 | "line": 193, | ||
593 | "column": 24 | ||
594 | }, | ||
595 | "end": { | ||
596 | "line": 196, | ||
558 | "column": 3 | 597 | "column": 3 |
559 | } | 598 | } |
560 | }, | 599 | }, |
@@ -563,11 +602,11 @@ | |||
563 | "defaultMessage": "!!!Activate next service...", | 602 | "defaultMessage": "!!!Activate next service...", |
564 | "file": "src/lib/Menu.js", | 603 | "file": "src/lib/Menu.js", |
565 | "start": { | 604 | "start": { |
566 | "line": 182, | 605 | "line": 197, |
567 | "column": 23 | 606 | "column": 23 |
568 | }, | 607 | }, |
569 | "end": { | 608 | "end": { |
570 | "line": 185, | 609 | "line": 200, |
571 | "column": 3 | 610 | "column": 3 |
572 | } | 611 | } |
573 | }, | 612 | }, |
@@ -576,11 +615,11 @@ | |||
576 | "defaultMessage": "!!!Activate previous service...", | 615 | "defaultMessage": "!!!Activate previous service...", |
577 | "file": "src/lib/Menu.js", | 616 | "file": "src/lib/Menu.js", |
578 | "start": { | 617 | "start": { |
579 | "line": 186, | 618 | "line": 201, |
580 | "column": 27 | 619 | "column": 27 |
581 | }, | 620 | }, |
582 | "end": { | 621 | "end": { |
583 | "line": 189, | 622 | "line": 204, |
584 | "column": 3 | 623 | "column": 3 |
585 | } | 624 | } |
586 | }, | 625 | }, |
@@ -589,11 +628,11 @@ | |||
589 | "defaultMessage": "!!!Disable notifications & audio", | 628 | "defaultMessage": "!!!Disable notifications & audio", |
590 | "file": "src/lib/Menu.js", | 629 | "file": "src/lib/Menu.js", |
591 | "start": { | 630 | "start": { |
592 | "line": 190, | 631 | "line": 205, |
593 | "column": 11 | 632 | "column": 11 |
594 | }, | 633 | }, |
595 | "end": { | 634 | "end": { |
596 | "line": 193, | 635 | "line": 208, |
597 | "column": 3 | 636 | "column": 3 |
598 | } | 637 | } |
599 | }, | 638 | }, |
@@ -602,11 +641,37 @@ | |||
602 | "defaultMessage": "!!!Enable notifications & audio", | 641 | "defaultMessage": "!!!Enable notifications & audio", |
603 | "file": "src/lib/Menu.js", | 642 | "file": "src/lib/Menu.js", |
604 | "start": { | 643 | "start": { |
605 | "line": 194, | 644 | "line": 209, |
606 | "column": 13 | 645 | "column": 13 |
607 | }, | 646 | }, |
608 | "end": { | 647 | "end": { |
609 | "line": 197, | 648 | "line": 212, |
649 | "column": 3 | ||
650 | } | ||
651 | }, | ||
652 | { | ||
653 | "id": "menu.workspaces", | ||
654 | "defaultMessage": "!!!Workspaces", | ||
655 | "file": "src/lib/Menu.js", | ||
656 | "start": { | ||
657 | "line": 213, | ||
658 | "column": 14 | ||
659 | }, | ||
660 | "end": { | ||
661 | "line": 216, | ||
662 | "column": 3 | ||
663 | } | ||
664 | }, | ||
665 | { | ||
666 | "id": "menu.workspaces.defaultWorkspace", | ||
667 | "defaultMessage": "!!!Default", | ||
668 | "file": "src/lib/Menu.js", | ||
669 | "start": { | ||
670 | "line": 217, | ||
671 | "column": 20 | ||
672 | }, | ||
673 | "end": { | ||
674 | "line": 220, | ||
610 | "column": 3 | 675 | "column": 3 |
611 | } | 676 | } |
612 | } | 677 | } |
diff --git a/src/index.js b/src/index.js index 05c793d98..3fe996aa7 100644 --- a/src/index.js +++ b/src/index.js | |||
@@ -305,6 +305,20 @@ const createWindow = () => { | |||
305 | }); | 305 | }); |
306 | }; | 306 | }; |
307 | 307 | ||
308 | // Allow passing command line parameters/switches to electron | ||
309 | // https://electronjs.org/docs/api/chrome-command-line-switches | ||
310 | // used for Kerberos support | ||
311 | // Usage e.g. MACOS | ||
312 | // $ Franz.app/Contents/MacOS/Franz --auth-server-whitelist *.mydomain.com --auth-negotiate-delegate-whitelist *.mydomain.com | ||
313 | const argv = require('minimist')(process.argv.slice(1)); | ||
314 | |||
315 | if (argv['auth-server-whitelist']) { | ||
316 | app.commandLine.appendSwitch('auth-server-whitelist', argv['auth-server-whitelist']); | ||
317 | } | ||
318 | if (argv['auth-negotiate-delegate-whitelist']) { | ||
319 | app.commandLine.appendSwitch('auth-negotiate-delegate-whitelist', argv['auth-negotiate-delegate-whitelist']); | ||
320 | } | ||
321 | |||
308 | // This method will be called when Electron has finished | 322 | // This method will be called when Electron has finished |
309 | // initialization and is ready to create browser windows. | 323 | // initialization and is ready to create browser windows. |
310 | // Some APIs can only be used after this event occurs. | 324 | // Some APIs can only be used after this event occurs. |
diff --git a/src/lib/Menu.js b/src/lib/Menu.js index 7a60c448f..a4e41c17c 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js | |||
@@ -3,6 +3,9 @@ import { observable, autorun } from 'mobx'; | |||
3 | import { defineMessages } from 'react-intl'; | 3 | import { defineMessages } from 'react-intl'; |
4 | 4 | ||
5 | import { isMac, ctrlKey, cmdKey } from '../environment'; | 5 | import { isMac, ctrlKey, cmdKey } from '../environment'; |
6 | import { GA_CATEGORY_WORKSPACES, workspaceStore } from '../features/workspaces/index'; | ||
7 | import { workspaceActions } from '../features/workspaces/actions'; | ||
8 | import { gaEvent } from './analytics'; | ||
6 | 9 | ||
7 | const { app, Menu, dialog } = remote; | 10 | const { app, Menu, dialog } = remote; |
8 | 11 | ||
@@ -179,6 +182,18 @@ const menuItems = defineMessages({ | |||
179 | id: 'menu.services.addNewService', | 182 | id: 'menu.services.addNewService', |
180 | defaultMessage: '!!!Add New Service...', | 183 | defaultMessage: '!!!Add New Service...', |
181 | }, | 184 | }, |
185 | addNewWorkspace: { | ||
186 | id: 'menu.workspaces.addNewWorkspace', | ||
187 | defaultMessage: '!!!Add New Workspace...', | ||
188 | }, | ||
189 | openWorkspaceDrawer: { | ||
190 | id: 'menu.workspaces.openWorkspaceDrawer', | ||
191 | defaultMessage: '!!!Open workspace drawer', | ||
192 | }, | ||
193 | closeWorkspaceDrawer: { | ||
194 | id: 'menu.workspaces.closeWorkspaceDrawer', | ||
195 | defaultMessage: '!!!Close workspace drawer', | ||
196 | }, | ||
182 | activateNextService: { | 197 | activateNextService: { |
183 | id: 'menu.services.setNextServiceActive', | 198 | id: 'menu.services.setNextServiceActive', |
184 | defaultMessage: '!!!Activate next service...', | 199 | defaultMessage: '!!!Activate next service...', |
@@ -195,6 +210,14 @@ const menuItems = defineMessages({ | |||
195 | id: 'sidebar.unmuteApp', | 210 | id: 'sidebar.unmuteApp', |
196 | defaultMessage: '!!!Enable notifications & audio', | 211 | defaultMessage: '!!!Enable notifications & audio', |
197 | }, | 212 | }, |
213 | workspaces: { | ||
214 | id: 'menu.workspaces', | ||
215 | defaultMessage: '!!!Workspaces', | ||
216 | }, | ||
217 | defaultWorkspace: { | ||
218 | id: 'menu.workspaces.defaultWorkspace', | ||
219 | defaultMessage: '!!!Default', | ||
220 | }, | ||
198 | }); | 221 | }); |
199 | 222 | ||
200 | function getActiveWebview() { | 223 | function getActiveWebview() { |
@@ -298,6 +321,11 @@ const _templateFactory = intl => [ | |||
298 | submenu: [], | 321 | submenu: [], |
299 | }, | 322 | }, |
300 | { | 323 | { |
324 | label: intl.formatMessage(menuItems.workspaces), | ||
325 | submenu: [], | ||
326 | visible: workspaceStore.isFeatureEnabled, | ||
327 | }, | ||
328 | { | ||
301 | label: intl.formatMessage(menuItems.window), | 329 | label: intl.formatMessage(menuItems.window), |
302 | role: 'window', | 330 | role: 'window', |
303 | submenu: [ | 331 | submenu: [ |
@@ -669,7 +697,7 @@ export default class FranzMenu { | |||
669 | }, | 697 | }, |
670 | ); | 698 | ); |
671 | 699 | ||
672 | tpl[4].submenu.unshift(about, { | 700 | tpl[5].submenu.unshift(about, { |
673 | type: 'separator', | 701 | type: 'separator', |
674 | }); | 702 | }); |
675 | } else { | 703 | } else { |
@@ -704,6 +732,10 @@ export default class FranzMenu { | |||
704 | tpl[3].submenu = serviceTpl; | 732 | tpl[3].submenu = serviceTpl; |
705 | } | 733 | } |
706 | 734 | ||
735 | if (workspaceStore.isFeatureEnabled) { | ||
736 | tpl[4].submenu = this.workspacesMenu(); | ||
737 | } | ||
738 | |||
707 | this.currentTemplate = tpl; | 739 | this.currentTemplate = tpl; |
708 | const menu = Menu.buildFromTemplate(tpl); | 740 | const menu = Menu.buildFromTemplate(tpl); |
709 | Menu.setApplicationMenu(menu); | 741 | Menu.setApplicationMenu(menu); |
@@ -754,6 +786,66 @@ export default class FranzMenu { | |||
754 | return menu; | 786 | return menu; |
755 | } | 787 | } |
756 | 788 | ||
789 | workspacesMenu() { | ||
790 | const { workspaces, activeWorkspace, isWorkspaceDrawerOpen } = workspaceStore; | ||
791 | const { intl } = window.franz; | ||
792 | const menu = []; | ||
793 | |||
794 | // Add new workspace item: | ||
795 | menu.push({ | ||
796 | label: intl.formatMessage(menuItems.addNewWorkspace), | ||
797 | accelerator: `${cmdKey}+Shift+N`, | ||
798 | click: () => { | ||
799 | workspaceActions.openWorkspaceSettings(); | ||
800 | }, | ||
801 | enabled: this.stores.user.isLoggedIn, | ||
802 | }); | ||
803 | |||
804 | // Open workspace drawer: | ||
805 | const drawerLabel = ( | ||
806 | isWorkspaceDrawerOpen ? menuItems.closeWorkspaceDrawer : menuItems.openWorkspaceDrawer | ||
807 | ); | ||
808 | menu.push({ | ||
809 | label: intl.formatMessage(drawerLabel), | ||
810 | accelerator: `${cmdKey}+D`, | ||
811 | click: () => { | ||
812 | workspaceActions.toggleWorkspaceDrawer(); | ||
813 | gaEvent(GA_CATEGORY_WORKSPACES, 'toggleDrawer', 'menu'); | ||
814 | }, | ||
815 | enabled: this.stores.user.isLoggedIn, | ||
816 | }, { | ||
817 | type: 'separator', | ||
818 | }); | ||
819 | |||
820 | // Default workspace | ||
821 | menu.push({ | ||
822 | label: intl.formatMessage(menuItems.defaultWorkspace), | ||
823 | accelerator: `${cmdKey}+Alt+0`, | ||
824 | type: 'radio', | ||
825 | checked: !activeWorkspace, | ||
826 | click: () => { | ||
827 | workspaceActions.deactivate(); | ||
828 | gaEvent(GA_CATEGORY_WORKSPACES, 'switch', 'menu'); | ||
829 | }, | ||
830 | }); | ||
831 | |||
832 | // Workspace items | ||
833 | if (this.stores.user.isPremium) { | ||
834 | workspaces.forEach((workspace, i) => menu.push({ | ||
835 | label: workspace.name, | ||
836 | accelerator: i < 9 ? `${cmdKey}+Alt+${i + 1}` : null, | ||
837 | type: 'radio', | ||
838 | checked: activeWorkspace ? workspace.id === activeWorkspace.id : false, | ||
839 | click: () => { | ||
840 | workspaceActions.activate({ workspace }); | ||
841 | gaEvent(GA_CATEGORY_WORKSPACES, 'switch', 'menu'); | ||
842 | }, | ||
843 | })); | ||
844 | } | ||
845 | |||
846 | return menu; | ||
847 | } | ||
848 | |||
757 | _getServiceName(service) { | 849 | _getServiceName(service) { |
758 | if (service.name) { | 850 | if (service.name) { |
759 | return service.name; | 851 | return service.name; |
diff --git a/src/lib/analytics.js b/src/lib/analytics.js index 0519192d1..e7daa9d06 100644 --- a/src/lib/analytics.js +++ b/src/lib/analytics.js | |||
@@ -28,12 +28,10 @@ ga('send', 'App'); | |||
28 | 28 | ||
29 | export function gaPage(page) { | 29 | export function gaPage(page) { |
30 | ga('send', 'pageview', page); | 30 | ga('send', 'pageview', page); |
31 | |||
32 | debug('GA track page', page); | 31 | debug('GA track page', page); |
33 | } | 32 | } |
34 | 33 | ||
35 | export function gaEvent(category, action, label) { | 34 | export function gaEvent(category, action, label) { |
36 | ga('send', 'event', category, action, label); | 35 | ga('send', 'event', category, action, label); |
37 | 36 | debug('GA track event', category, action, label); | |
38 | debug('GA track event', category, action); | ||
39 | } | 37 | } |
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index e60d79075..6200c9a16 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js | |||
@@ -1,4 +1,9 @@ | |||
1 | import { computed, observable, reaction } from 'mobx'; | 1 | import { |
2 | computed, | ||
3 | observable, | ||
4 | reaction, | ||
5 | runInAction, | ||
6 | } from 'mobx'; | ||
2 | 7 | ||
3 | import Store from './lib/Store'; | 8 | import Store from './lib/Store'; |
4 | import CachedRequest from './lib/CachedRequest'; | 9 | import CachedRequest from './lib/CachedRequest'; |
@@ -7,6 +12,7 @@ import delayApp from '../features/delayApp'; | |||
7 | import spellchecker from '../features/spellchecker'; | 12 | import spellchecker from '../features/spellchecker'; |
8 | import serviceProxy from '../features/serviceProxy'; | 13 | import serviceProxy from '../features/serviceProxy'; |
9 | import basicAuth from '../features/basicAuth'; | 14 | import basicAuth from '../features/basicAuth'; |
15 | import workspaces from '../features/workspaces'; | ||
10 | import shareFranz from '../features/shareFranz'; | 16 | import shareFranz from '../features/shareFranz'; |
11 | import settingsWS from '../features/settingsWS'; | 17 | import settingsWS from '../features/settingsWS'; |
12 | 18 | ||
@@ -17,13 +23,16 @@ export default class FeaturesStore extends Store { | |||
17 | 23 | ||
18 | @observable featuresRequest = new CachedRequest(this.api.features, 'features'); | 24 | @observable featuresRequest = new CachedRequest(this.api.features, 'features'); |
19 | 25 | ||
26 | @observable features = Object.assign({}, DEFAULT_FEATURES_CONFIG); | ||
27 | |||
20 | async setup() { | 28 | async setup() { |
21 | this.registerReactions([ | 29 | this.registerReactions([ |
30 | this._updateFeatures, | ||
22 | this._monitorLoginStatus.bind(this), | 31 | this._monitorLoginStatus.bind(this), |
23 | ]); | 32 | ]); |
24 | 33 | ||
25 | await this.featuresRequest._promise; | 34 | await this.featuresRequest._promise; |
26 | setTimeout(this._enableFeatures.bind(this), 1); | 35 | setTimeout(this._setupFeatures.bind(this), 1); |
27 | 36 | ||
28 | // single key reaction | 37 | // single key reaction |
29 | reaction(() => this.stores.user.data.isPremium, () => { | 38 | reaction(() => this.stores.user.data.isPremium, () => { |
@@ -37,13 +46,16 @@ export default class FeaturesStore extends Store { | |||
37 | return this.defaultFeaturesRequest.execute().result || DEFAULT_FEATURES_CONFIG; | 46 | return this.defaultFeaturesRequest.execute().result || DEFAULT_FEATURES_CONFIG; |
38 | } | 47 | } |
39 | 48 | ||
40 | @computed get features() { | 49 | _updateFeatures = () => { |
50 | const features = Object.assign({}, DEFAULT_FEATURES_CONFIG); | ||
41 | if (this.stores.user.isLoggedIn) { | 51 | if (this.stores.user.isLoggedIn) { |
42 | return this.featuresRequest.execute().result || DEFAULT_FEATURES_CONFIG; | 52 | const requestResult = this.featuresRequest.execute().result; |
53 | Object.assign(features, requestResult); | ||
43 | } | 54 | } |
44 | 55 | runInAction('FeaturesStore::_updateFeatures', () => { | |
45 | return DEFAULT_FEATURES_CONFIG; | 56 | this.features = features; |
46 | } | 57 | }); |
58 | }; | ||
47 | 59 | ||
48 | _monitorLoginStatus() { | 60 | _monitorLoginStatus() { |
49 | if (this.stores.user.isLoggedIn) { | 61 | if (this.stores.user.isLoggedIn) { |
@@ -53,11 +65,12 @@ export default class FeaturesStore extends Store { | |||
53 | } | 65 | } |
54 | } | 66 | } |
55 | 67 | ||
56 | _enableFeatures() { | 68 | _setupFeatures() { |
57 | delayApp(this.stores, this.actions); | 69 | delayApp(this.stores, this.actions); |
58 | spellchecker(this.stores, this.actions); | 70 | spellchecker(this.stores, this.actions); |
59 | serviceProxy(this.stores, this.actions); | 71 | serviceProxy(this.stores, this.actions); |
60 | basicAuth(this.stores, this.actions); | 72 | basicAuth(this.stores, this.actions); |
73 | workspaces(this.stores, this.actions); | ||
61 | shareFranz(this.stores, this.actions); | 74 | shareFranz(this.stores, this.actions); |
62 | settingsWS(this.stores, this.actions); | 75 | settingsWS(this.stores, this.actions); |
63 | } | 76 | } |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 69e616f0c..0ec6bf550 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -12,6 +12,7 @@ import Request from './lib/Request'; | |||
12 | import CachedRequest from './lib/CachedRequest'; | 12 | import CachedRequest from './lib/CachedRequest'; |
13 | import { matchRoute } from '../helpers/routing-helpers'; | 13 | import { matchRoute } from '../helpers/routing-helpers'; |
14 | import { gaEvent } from '../lib/analytics'; | 14 | import { gaEvent } from '../lib/analytics'; |
15 | import { workspaceStore } from '../features/workspaces'; | ||
15 | 16 | ||
16 | const debug = require('debug')('Franz:ServiceStore'); | 17 | const debug = require('debug')('Franz:ServiceStore'); |
17 | 18 | ||
@@ -99,7 +100,6 @@ export default class ServicesStore extends Store { | |||
99 | return observable(services.slice().slice().sort((a, b) => a.order - b.order)); | 100 | return observable(services.slice().slice().sort((a, b) => a.order - b.order)); |
100 | } | 101 | } |
101 | } | 102 | } |
102 | |||
103 | return []; | 103 | return []; |
104 | } | 104 | } |
105 | 105 | ||
@@ -108,13 +108,16 @@ export default class ServicesStore extends Store { | |||
108 | } | 108 | } |
109 | 109 | ||
110 | @computed get allDisplayed() { | 110 | @computed get allDisplayed() { |
111 | return this.stores.settings.all.app.showDisabledServices ? this.all : this.enabled; | 111 | const services = this.stores.settings.all.app.showDisabledServices ? this.all : this.enabled; |
112 | return workspaceStore.filterServicesByActiveWorkspace(services); | ||
112 | } | 113 | } |
113 | 114 | ||
114 | // This is just used to avoid unnecessary rerendering of resource-heavy webviews | 115 | // This is just used to avoid unnecessary rerendering of resource-heavy webviews |
115 | @computed get allDisplayedUnordered() { | 116 | @computed get allDisplayedUnordered() { |
117 | const { showDisabledServices } = this.stores.settings.all.app; | ||
116 | const services = this.allServicesRequest.execute().result || []; | 118 | const services = this.allServicesRequest.execute().result || []; |
117 | return this.stores.settings.all.app.showDisabledServices ? services : services.filter(service => service.isEnabled); | 119 | const filteredServices = showDisabledServices ? services : services.filter(service => service.isEnabled); |
120 | return workspaceStore.filterServicesByActiveWorkspace(filteredServices); | ||
118 | } | 121 | } |
119 | 122 | ||
120 | @computed get filtered() { | 123 | @computed get filtered() { |
diff --git a/src/stores/UIStore.js b/src/stores/UIStore.js index bb7965a4a..a95a8e1e0 100644 --- a/src/stores/UIStore.js +++ b/src/stores/UIStore.js | |||
@@ -21,11 +21,12 @@ export default class UIStore extends Store { | |||
21 | return (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) || !settings.isAppMuted; | 21 | return (settings.app.isAppMuted && settings.app.showMessageBadgeWhenMuted) || !settings.isAppMuted; |
22 | } | 22 | } |
23 | 23 | ||
24 | @computed get theme() { | 24 | @computed get isDarkThemeActive() { |
25 | if (this.stores.settings.all.app.darkMode) { | 25 | return this.stores.settings.all.app.darkMode; |
26 | return theme('dark'); | 26 | } |
27 | } | ||
28 | 27 | ||
28 | @computed get theme() { | ||
29 | if (this.isDarkThemeActive) return theme('dark'); | ||
29 | return theme('default'); | 30 | return theme('default'); |
30 | } | 31 | } |
31 | 32 | ||
diff --git a/src/stores/UserStore.js b/src/stores/UserStore.js index 77d84afe1..534690fbb 100644 --- a/src/stores/UserStore.js +++ b/src/stores/UserStore.js | |||
@@ -142,6 +142,10 @@ export default class UserStore extends Store { | |||
142 | return this.getUserInfoRequest.execute().result || {}; | 142 | return this.getUserInfoRequest.execute().result || {}; |
143 | } | 143 | } |
144 | 144 | ||
145 | @computed get isPremium() { | ||
146 | return !!this.data.isPremium; | ||
147 | } | ||
148 | |||
145 | @computed get legacyServices() { | 149 | @computed get legacyServices() { |
146 | return this.getLegacyServicesRequest.execute() || {}; | 150 | return this.getLegacyServicesRequest.execute() || {}; |
147 | } | 151 | } |
diff --git a/src/stores/lib/Request.js b/src/stores/lib/Request.js index 04f528156..486de8a49 100644 --- a/src/stores/lib/Request.js +++ b/src/stores/lib/Request.js | |||
@@ -85,6 +85,8 @@ export default class Request { | |||
85 | return this.execute(...this._currentApiCall.args); | 85 | return this.execute(...this._currentApiCall.args); |
86 | } | 86 | } |
87 | 87 | ||
88 | retry = () => this.reload(); | ||
89 | |||
88 | isExecutingWithArgs(...args) { | 90 | isExecutingWithArgs(...args) { |
89 | return this.isExecuting && this._currentApiCall && isEqual(this._currentApiCall.args, args); | 91 | return this.isExecuting && this._currentApiCall && isEqual(this._currentApiCall.args, args); |
90 | } | 92 | } |
@@ -107,7 +109,7 @@ export default class Request { | |||
107 | Request._hooks.forEach(hook => hook(this)); | 109 | Request._hooks.forEach(hook => hook(this)); |
108 | } | 110 | } |
109 | 111 | ||
110 | reset() { | 112 | reset = () => { |
111 | this.result = null; | 113 | this.result = null; |
112 | this.isExecuting = false; | 114 | this.isExecuting = false; |
113 | this.isError = false; | 115 | this.isError = false; |
@@ -116,5 +118,5 @@ export default class Request { | |||
116 | this._promise = Promise; | 118 | this._promise = Promise; |
117 | 119 | ||
118 | return this; | 120 | return this; |
119 | } | 121 | }; |
120 | } | 122 | } |
diff --git a/src/styles/layout.scss b/src/styles/layout.scss index 9a003a922..e858b7904 100644 --- a/src/styles/layout.scss +++ b/src/styles/layout.scss | |||
@@ -18,8 +18,14 @@ html { overflow: hidden; } | |||
18 | font-size: 22px; | 18 | font-size: 22px; |
19 | 19 | ||
20 | &:hover, | 20 | &:hover, |
21 | &:active { color: $dark-theme-gray-smoke; } | 21 | &:active { |
22 | &.is-muted { color: $theme-brand-primary; } | 22 | color: $dark-theme-gray-smoke; |
23 | } | ||
24 | |||
25 | &.is-muted, | ||
26 | &.is-active { | ||
27 | color: $theme-brand-primary; | ||
28 | } | ||
23 | } | 29 | } |
24 | } | 30 | } |
25 | 31 | ||
@@ -33,6 +39,7 @@ html { overflow: hidden; } | |||
33 | .app__content { display: flex; } | 39 | .app__content { display: flex; } |
34 | 40 | ||
35 | .app__service { | 41 | .app__service { |
42 | position: relative; | ||
36 | display: flex; | 43 | display: flex; |
37 | flex: 1; | 44 | flex: 1; |
38 | flex-direction: column; | 45 | flex-direction: column; |
@@ -84,7 +91,7 @@ html { overflow: hidden; } | |||
84 | 91 | ||
85 | &:hover, | 92 | &:hover, |
86 | &:active { color: lighten($theme-gray-light, 10%); } | 93 | &:active { color: lighten($theme-gray-light, 10%); } |
87 | &.is-muted { color: $theme-brand-primary; } | 94 | &.is-muted, &.is-active { color: $theme-brand-primary; } |
88 | &--new-service { padding-bottom: 6px; } | 95 | &--new-service { padding-bottom: 6px; } |
89 | } | 96 | } |
90 | 97 | ||
diff --git a/src/styles/settings.scss b/src/styles/settings.scss index b286c6f1b..efa0ab942 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss | |||
@@ -419,6 +419,7 @@ | |||
419 | 419 | ||
420 | .settings-navigation__link { | 420 | .settings-navigation__link { |
421 | align-items: center; | 421 | align-items: center; |
422 | justify-content: space-between; | ||
422 | color: $theme-text-color; | 423 | color: $theme-text-color; |
423 | display: flex; | 424 | display: flex; |
424 | flex-shrink: 0; | 425 | flex-shrink: 0; |
@@ -430,7 +431,9 @@ | |||
430 | &:hover { | 431 | &:hover { |
431 | background: darken($theme-gray-lightest, 5%); | 432 | background: darken($theme-gray-lightest, 5%); |
432 | 433 | ||
433 | .badge { background: #FFF; } | 434 | .badge { |
435 | background: #FFF; | ||
436 | } | ||
434 | } | 437 | } |
435 | 438 | ||
436 | &.is-active { | 439 | &.is-active { |
@@ -447,8 +450,8 @@ | |||
447 | .settings-navigation__expander { flex: 1; } | 450 | .settings-navigation__expander { flex: 1; } |
448 | 451 | ||
449 | .badge { | 452 | .badge { |
453 | |||
450 | display: initial; | 454 | display: initial; |
451 | margin-left: 5px; | ||
452 | transition: background $theme-transition-time, color $theme-transition-time; | 455 | transition: background $theme-transition-time, color $theme-transition-time; |
453 | } | 456 | } |
454 | 457 | ||