aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.eslintrc3
-rw-r--r--package-lock.json2
-rw-r--r--packages/theme/src/themes/dark/index.ts15
-rw-r--r--packages/theme/src/themes/default/index.ts18
-rw-r--r--src/actions/index.js2
-rw-r--r--src/components/layout/AppLayout.js15
-rw-r--r--src/config.js4
-rw-r--r--src/environment.js8
-rw-r--r--src/features/todos/actions.js22
-rw-r--r--src/features/todos/components/TodosWebview.js237
-rw-r--r--src/features/todos/constants.js4
-rw-r--r--src/features/todos/containers/TodosScreen.js32
-rw-r--r--src/features/todos/index.js34
-rw-r--r--src/features/todos/preload.js23
-rw-r--r--src/features/todos/store.js147
-rw-r--r--src/i18n/locales/defaultMessages.json292
-rw-r--r--src/i18n/locales/en-US.json6
-rw-r--r--src/i18n/messages/src/components/layout/AppLayout.json12
-rw-r--r--src/i18n/messages/src/lib/Menu.json280
-rw-r--r--src/index.html11
-rw-r--r--src/lib/Menu.js64
-rw-r--r--src/stores/FeaturesStore.js2
-rw-r--r--src/stores/ServicesStore.js3
-rw-r--r--src/stores/index.js2
-rw-r--r--src/styles/layout.scss14
-rw-r--r--src/webview/contextMenu.js17
26 files changed, 1008 insertions, 261 deletions
diff --git a/.eslintrc b/.eslintrc
index c85bee1fa..47ecfb054 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -55,7 +55,8 @@
55 "atob": true, 55 "atob": true,
56 "btoa": true, 56 "btoa": true,
57 "ga": true, 57 "ga": true,
58 "mocha": true 58 "mocha": true,
59 "Element": true
59 }, 60 },
60 "env": { 61 "env": {
61 "jest/globals": true 62 "jest/globals": true
diff --git a/package-lock.json b/package-lock.json
index b4d86c5e1..607ebc31a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
1{ 1{
2 "name": "franz", 2 "name": "franz",
3 "version": "5.2.0-beta.3", 3 "version": "5.2.1-beta.1",
4 "lockfileVersion": 1, 4 "lockfileVersion": 1,
5 "requires": true, 5 "requires": true,
6 "dependencies": { 6 "dependencies": {
diff --git a/packages/theme/src/themes/dark/index.ts b/packages/theme/src/themes/dark/index.ts
index bd9f001e8..d29345298 100644
--- a/packages/theme/src/themes/dark/index.ts
+++ b/packages/theme/src/themes/dark/index.ts
@@ -118,3 +118,18 @@ export const announcements = merge({}, defaultStyles.announcements, {
118 background: legacyStyles.darkThemeGrayDark, 118 background: legacyStyles.darkThemeGrayDark,
119 }, 119 },
120}); 120});
121
122// Todos
123export const todos = merge({}, defaultStyles.todos, {
124 todosLayer: {
125 borderLeftColor: legacyStyles.darkThemeGrayDarker,
126 },
127 toggleButton: {
128 background: defaultStyles.styleTypes.primary.accent,
129 textColor: defaultStyles.styleTypes.primary.contrast,
130 shadowColor: 'rgba(0, 0, 0, 0.2)',
131 },
132 dragIndicator: {
133 background: legacyStyles.themeGrayLight,
134 },
135});
diff --git a/packages/theme/src/themes/default/index.ts b/packages/theme/src/themes/default/index.ts
index 0f02fa3c8..9f9c39f9a 100644
--- a/packages/theme/src/themes/default/index.ts
+++ b/packages/theme/src/themes/default/index.ts
@@ -207,3 +207,21 @@ export const announcements = {
207 background: legacyStyles.themeGrayLightest, 207 background: legacyStyles.themeGrayLightest,
208 }, 208 },
209}; 209};
210
211// Todos
212export const todos = {
213 todosLayer: {
214 borderLeftColor: legacyStyles.themeGrayLighter,
215 },
216 toggleButton: {
217 background: styleTypes.primary.accent,
218 textColor: styleTypes.primary.contrast,
219 shadowColor: 'rgba(0, 0, 0, 0.2)',
220 },
221 dragIndicator: {
222 background: legacyStyles.themeGrayLight,
223 },
224 resizeHandler: {
225 backgroundHover: styleTypes.primary.accent,
226 }
227};
diff --git a/src/actions/index.js b/src/actions/index.js
index fc525afeb..336344d76 100644
--- a/src/actions/index.js
+++ b/src/actions/index.js
@@ -13,6 +13,7 @@ import settings from './settings';
13import requests from './requests'; 13import requests from './requests';
14import announcements from '../features/announcements/actions'; 14import announcements from '../features/announcements/actions';
15import workspaces from '../features/workspaces/actions'; 15import workspaces from '../features/workspaces/actions';
16import todos from '../features/todos/actions';
16 17
17const actions = Object.assign({}, { 18const actions = Object.assign({}, {
18 service, 19 service,
@@ -31,4 +32,5 @@ export default Object.assign(
31 defineActions(actions, PropTypes.checkPropTypes), 32 defineActions(actions, PropTypes.checkPropTypes),
32 { announcements }, 33 { announcements },
33 { workspaces }, 34 { workspaces },
35 { todos },
34); 36);
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index ebb9849ea..dbf7d3c21 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -17,6 +17,7 @@ import { isWindows } from '../../environment';
17import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator'; 17import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator';
18import { workspaceStore } from '../../features/workspaces'; 18import { workspaceStore } from '../../features/workspaces';
19import AppUpdateInfoBar from '../AppUpdateInfoBar'; 19import AppUpdateInfoBar from '../AppUpdateInfoBar';
20import Todos from '../../features/todos/containers/TodosScreen';
20 21
21function createMarkup(HTMLString) { 22function createMarkup(HTMLString) {
22 return { __html: HTMLString }; 23 return { __html: HTMLString };
@@ -39,7 +40,8 @@ const messages = defineMessages({
39 40
40const styles = theme => ({ 41const styles = theme => ({
41 appContent: { 42 appContent: {
42 width: `calc(100% + ${theme.workspaces.drawer.width}px)`, 43 // width: `calc(100% + ${theme.workspaces.drawer.width}px)`,
44 width: '100%',
43 transition: 'transform 0.5s ease', 45 transition: 'transform 0.5s ease',
44 transform() { 46 transform() {
45 return workspaceStore.isWorkspaceDrawerOpen ? 'translateX(0)' : `translateX(-${theme.workspaces.drawer.width}px)`; 47 return workspaceStore.isWorkspaceDrawerOpen ? 'translateX(0)' : `translateX(-${theme.workspaces.drawer.width}px)`;
@@ -57,7 +59,6 @@ class AppLayout extends Component {
57 services: PropTypes.element.isRequired, 59 services: PropTypes.element.isRequired,
58 children: PropTypes.element, 60 children: PropTypes.element,
59 news: MobxPropTypes.arrayOrObservableArray.isRequired, 61 news: MobxPropTypes.arrayOrObservableArray.isRequired,
60 // isOnline: PropTypes.bool.isRequired,
61 showServicesUpdatedInfoBar: PropTypes.bool.isRequired, 62 showServicesUpdatedInfoBar: PropTypes.bool.isRequired,
62 appUpdateIsDownloaded: PropTypes.bool.isRequired, 63 appUpdateIsDownloaded: PropTypes.bool.isRequired,
63 nextAppReleaseVersion: PropTypes.string, 64 nextAppReleaseVersion: PropTypes.string,
@@ -125,15 +126,6 @@ class AppLayout extends Component {
125 <span dangerouslySetInnerHTML={createMarkup(item.message)} /> 126 <span dangerouslySetInnerHTML={createMarkup(item.message)} />
126 </InfoBar> 127 </InfoBar>
127 ))} 128 ))}
128 {/* {!isOnline && (
129 <InfoBar
130 type="danger"
131 sticky
132 >
133 <span className="mdi mdi-flash" />
134 {intl.formatMessage(globalMessages.notConnectedToTheInternet)}
135 </InfoBar>
136 )} */}
137 {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( 129 {!areRequiredRequestsSuccessful && showRequiredRequestsError && (
138 <InfoBar 130 <InfoBar
139 type="danger" 131 type="danger"
@@ -169,6 +161,7 @@ class AppLayout extends Component {
169 {services} 161 {services}
170 {children} 162 {children}
171 </div> 163 </div>
164 <Todos />
172 </div> 165 </div>
173 </div> 166 </div>
174 </ErrorBoundary> 167 </ErrorBoundary>
diff --git a/src/config.js b/src/config.js
index 5bc318545..471f8d5a6 100644
--- a/src/config.js
+++ b/src/config.js
@@ -24,6 +24,10 @@ export const LIVE_API_WEBSITE = 'https://meetfranz.com';
24 24
25export const STATS_API = 'https://stats.franzinfra.com'; 25export const STATS_API = 'https://stats.franzinfra.com';
26 26
27export const LOCAL_TODOS_FRONTEND_URL = 'http://localhost:4000';
28export const PRODUCTION_TODOS_FRONTEND_URL = 'https://app.franztodos.com';
29export const DEVELOPMENT_TODOS_FRONTEND_URL = 'https://development--franz-todos.netlify.com';
30
27export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12'; 31export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12';
28 32
29export const DEFAULT_APP_SETTINGS = { 33export const DEFAULT_APP_SETTINGS = {
diff --git a/src/environment.js b/src/environment.js
index ae7a67e4d..707449e09 100644
--- a/src/environment.js
+++ b/src/environment.js
@@ -10,6 +10,9 @@ import {
10 LIVE_WS_API, 10 LIVE_WS_API,
11 LOCAL_WS_API, 11 LOCAL_WS_API,
12 DEV_WS_API, 12 DEV_WS_API,
13 LOCAL_TODOS_FRONTEND_URL,
14 PRODUCTION_TODOS_FRONTEND_URL,
15 DEVELOPMENT_TODOS_FRONTEND_URL,
13} from './config'; 16} from './config';
14 17
15export const isDevMode = isDev; 18export const isDevMode = isDev;
@@ -31,21 +34,26 @@ export const cmdKey = isMac ? 'Cmd' : 'Ctrl';
31let api; 34let api;
32let wsApi; 35let wsApi;
33let web; 36let web;
37let todos;
34if (!isDevMode || (isDevMode && useLiveAPI)) { 38if (!isDevMode || (isDevMode && useLiveAPI)) {
35 api = LIVE_API; 39 api = LIVE_API;
36 wsApi = LIVE_WS_API; 40 wsApi = LIVE_WS_API;
37 web = LIVE_API_WEBSITE; 41 web = LIVE_API_WEBSITE;
42 todos = PRODUCTION_TODOS_FRONTEND_URL;
38} else if (isDevMode && useLocalAPI) { 43} else if (isDevMode && useLocalAPI) {
39 api = LOCAL_API; 44 api = LOCAL_API;
40 wsApi = LOCAL_WS_API; 45 wsApi = LOCAL_WS_API;
41 web = LOCAL_API_WEBSITE; 46 web = LOCAL_API_WEBSITE;
47 todos = LOCAL_TODOS_FRONTEND_URL;
42} else { 48} else {
43 api = DEV_API; 49 api = DEV_API;
44 wsApi = DEV_WS_API; 50 wsApi = DEV_WS_API;
45 web = DEV_API_WEBSITE; 51 web = DEV_API_WEBSITE;
52 todos = DEVELOPMENT_TODOS_FRONTEND_URL;
46} 53}
47 54
48export const API = api; 55export const API = api;
49export const API_VERSION = 'v1'; 56export const API_VERSION = 'v1';
50export const WS_API = wsApi; 57export const WS_API = wsApi;
51export const WEBSITE = web; 58export const WEBSITE = web;
59export const TODOS_FRONTEND = todos;
diff --git a/src/features/todos/actions.js b/src/features/todos/actions.js
new file mode 100644
index 000000000..dc63d5fcd
--- /dev/null
+++ b/src/features/todos/actions.js
@@ -0,0 +1,22 @@
1import PropTypes from 'prop-types';
2import { createActionsFromDefinitions } from '../../actions/lib/actions';
3
4export const todoActions = createActionsFromDefinitions({
5 resize: {
6 width: PropTypes.number.isRequired,
7 },
8 toggleTodosPanel: {},
9 setTodosWebview: {
10 webview: PropTypes.instanceOf(Element).isRequired,
11 },
12 handleHostMessage: {
13 action: PropTypes.string.isRequired,
14 data: PropTypes.object,
15 },
16 handleClientMessage: {
17 action: PropTypes.string.isRequired,
18 data: PropTypes.object,
19 },
20}, PropTypes.checkPropTypes);
21
22export default todoActions;
diff --git a/src/features/todos/components/TodosWebview.js b/src/features/todos/components/TodosWebview.js
new file mode 100644
index 000000000..288c1906f
--- /dev/null
+++ b/src/features/todos/components/TodosWebview.js
@@ -0,0 +1,237 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import injectSheet from 'react-jss';
5import Webview from 'react-electron-web-view';
6import { Icon } from '@meetfranz/ui';
7
8import * as environment from '../../../environment';
9
10const OPEN_TODOS_BUTTON_SIZE = 45;
11const CLOSE_TODOS_BUTTON_SIZE = 35;
12
13const styles = theme => ({
14 root: {
15 background: theme.colorBackground,
16 position: 'relative',
17 borderLeft: [1, 'solid', theme.todos.todosLayer.borderLeftColor],
18 zIndex: 300,
19
20 transform: ({ isVisible, width }) => `translateX(${isVisible ? 0 : width}px)`,
21
22 '&:hover $closeTodosButton': {
23 opacity: 1,
24 },
25 },
26 webview: {
27 height: '100%',
28
29 '& webview': {
30 height: '100%',
31 },
32 },
33 resizeHandler: {
34 position: 'absolute',
35 left: 0,
36 marginLeft: -5,
37 width: 10,
38 zIndex: 400,
39 cursor: 'col-resize',
40 },
41 dragIndicator: {
42 position: 'absolute',
43 left: 0,
44 width: 5,
45 zIndex: 400,
46 background: theme.todos.dragIndicator.background,
47
48 },
49 openTodosButton: {
50 width: OPEN_TODOS_BUTTON_SIZE,
51 height: OPEN_TODOS_BUTTON_SIZE,
52 background: theme.todos.toggleButton.background,
53 position: 'absolute',
54 bottom: 80,
55 right: props => (props.width + (props.isVisible ? -OPEN_TODOS_BUTTON_SIZE / 2 : 0)),
56 borderRadius: OPEN_TODOS_BUTTON_SIZE / 2,
57 opacity: props => (props.isVisible ? 0 : 1),
58 transition: 'right 0.5s',
59 zIndex: 600,
60 display: 'flex',
61 alignItems: 'center',
62 justifyContent: 'center',
63 boxShadow: [0, 0, 10, theme.todos.toggleButton.shadowColor],
64
65 borderTopRightRadius: props => (props.isVisible ? null : 0),
66 borderBottomRightRadius: props => (props.isVisible ? null : 0),
67
68 '& svg': {
69 fill: theme.todos.toggleButton.textColor,
70 transition: 'all 0.5s',
71 },
72 },
73 closeTodosButton: {
74 width: CLOSE_TODOS_BUTTON_SIZE,
75 height: CLOSE_TODOS_BUTTON_SIZE,
76 background: theme.todos.toggleButton.background,
77 position: 'absolute',
78 bottom: 80,
79 right: ({ width }) => (width + -CLOSE_TODOS_BUTTON_SIZE / 2),
80 borderRadius: CLOSE_TODOS_BUTTON_SIZE / 2,
81 opacity: 0,
82 transition: 'opacity 0.5s',
83 zIndex: 600,
84 display: 'flex',
85 alignItems: 'center',
86 justifyContent: 'center',
87 boxShadow: [0, 0, 10, theme.todos.toggleButton.shadowColor],
88
89 '& svg': {
90 fill: theme.todos.toggleButton.textColor,
91 },
92 },
93});
94
95@injectSheet(styles) @observer
96class TodosWebview extends Component {
97 static propTypes = {
98 classes: PropTypes.object.isRequired,
99 isVisible: PropTypes.bool.isRequired,
100 togglePanel: PropTypes.func.isRequired,
101 handleClientMessage: PropTypes.func.isRequired,
102 setTodosWebview: PropTypes.func.isRequired,
103 resize: PropTypes.func.isRequired,
104 width: PropTypes.number.isRequired,
105 minWidth: PropTypes.number.isRequired,
106 };
107
108 state = {
109 isDragging: false,
110 width: 300,
111 };
112
113 componentWillMount() {
114 const { width } = this.props;
115
116 this.setState({
117 width,
118 });
119 }
120
121 componentDidMount() {
122 this.node.addEventListener('mousemove', this.resizePanel.bind(this));
123 this.node.addEventListener('mouseup', this.stopResize.bind(this));
124 this.node.addEventListener('mouseleave', this.stopResize.bind(this));
125 }
126
127 startResize = (event) => {
128 this.setState({
129 isDragging: true,
130 initialPos: event.clientX,
131 delta: 0,
132 });
133 };
134
135 resizePanel(e) {
136 const { minWidth } = this.props;
137
138 const {
139 isDragging,
140 initialPos,
141 } = this.state;
142
143 if (isDragging && Math.abs(e.clientX - window.innerWidth) > minWidth) {
144 const delta = e.clientX - initialPos;
145
146 this.setState({
147 delta,
148 });
149 }
150 }
151
152 stopResize() {
153 const {
154 resize,
155 minWidth,
156 } = this.props;
157
158 const {
159 isDragging,
160 delta,
161 width,
162 } = this.state;
163
164 if (isDragging) {
165 let newWidth = width + (delta < 0 ? Math.abs(delta) : -Math.abs(delta));
166
167 if (newWidth < minWidth) {
168 newWidth = minWidth;
169 }
170
171 this.setState({
172 isDragging: false,
173 delta: 0,
174 width: newWidth,
175 });
176
177 resize(newWidth);
178 }
179 }
180
181 startListeningToIpcMessages() {
182 const { handleClientMessage } = this.props;
183 if (!this.webview) return;
184 this.webview.addEventListener('ipc-message', e => handleClientMessage(e.args[0]));
185 }
186
187 render() {
188 const {
189 classes, isVisible, togglePanel,
190 } = this.props;
191 const { width, delta, isDragging } = this.state;
192
193 return (
194 <>
195 <div
196 className={classes.root}
197 style={{ width: isVisible ? width : 0 }}
198 onMouseUp={() => this.stopResize()}
199 ref={(node) => { this.node = node; }}
200 >
201 <button
202 onClick={() => togglePanel()}
203 className={isVisible ? classes.closeTodosButton : classes.openTodosButton}
204 type="button"
205 >
206 <Icon icon={isVisible ? 'mdiChevronRight' : 'mdiCheckAll'} size={2} />
207 </button>
208 <div
209 className={classes.resizeHandler}
210 style={Object.assign({ left: delta }, isDragging ? { width: 600, marginLeft: -200 } : {})} // This hack is required as resizing with webviews beneath behaves quite bad
211 onMouseDown={e => this.startResize(e)}
212 />
213 {isDragging && (
214 <div
215 className={classes.dragIndicator}
216 style={{ left: delta }} // This hack is required as resizing with webviews beneath behaves quite bad
217 />
218 )}
219 <Webview
220 className={classes.webview}
221 onDidAttach={() => {
222 const { setTodosWebview } = this.props;
223 setTodosWebview(this.webview);
224 this.startListeningToIpcMessages();
225 }}
226 partition="persist:todos"
227 preload="./features/todos/preload.js"
228 ref={(webview) => { this.webview = webview ? webview.view : null; }}
229 src={environment.TODOS_FRONTEND}
230 />
231 </div>
232 </>
233 );
234 }
235}
236
237export default TodosWebview;
diff --git a/src/features/todos/constants.js b/src/features/todos/constants.js
new file mode 100644
index 000000000..2e8a431cc
--- /dev/null
+++ b/src/features/todos/constants.js
@@ -0,0 +1,4 @@
1export const IPC = {
2 TODOS_HOST_CHANNEL: 'TODOS_HOST_CHANNEL',
3 TODOS_CLIENT_CHANNEL: 'TODOS_CLIENT_CHANNEL',
4};
diff --git a/src/features/todos/containers/TodosScreen.js b/src/features/todos/containers/TodosScreen.js
new file mode 100644
index 000000000..d071d0677
--- /dev/null
+++ b/src/features/todos/containers/TodosScreen.js
@@ -0,0 +1,32 @@
1import React, { Component } from 'react';
2import { observer } from 'mobx-react';
3
4import TodosWebview from '../components/TodosWebview';
5import ErrorBoundary from '../../../components/util/ErrorBoundary';
6import { TODOS_MIN_WIDTH, todosStore } from '..';
7import { todoActions } from '../actions';
8
9@observer
10class TodosScreen extends Component {
11 render() {
12 if (!todosStore || !todosStore.isFeatureActive) {
13 return null;
14 }
15
16 return (
17 <ErrorBoundary>
18 <TodosWebview
19 isVisible={todosStore.isTodosPanelVisible}
20 togglePanel={todoActions.toggleTodosPanel}
21 handleClientMessage={todoActions.handleClientMessage}
22 setTodosWebview={webview => todoActions.setTodosWebview({ webview })}
23 width={todosStore.width}
24 minWidth={TODOS_MIN_WIDTH}
25 resize={width => todoActions.resize({ width })}
26 />
27 </ErrorBoundary>
28 );
29 }
30}
31
32export default TodosScreen;
diff --git a/src/features/todos/index.js b/src/features/todos/index.js
new file mode 100644
index 000000000..00b165cc5
--- /dev/null
+++ b/src/features/todos/index.js
@@ -0,0 +1,34 @@
1import { reaction } from 'mobx';
2import TodoStore from './store';
3
4const debug = require('debug')('Franz:feature:todos');
5
6export const GA_CATEGORY_TODOS = 'Todos';
7
8export const DEFAULT_TODOS_WIDTH = 300;
9export const TODOS_MIN_WIDTH = 200;
10export const DEFAULT_TODOS_VISIBLE = true;
11
12export const todosStore = new TodoStore();
13
14export default function initTodos(stores, actions) {
15 stores.todos = todosStore;
16 const { features } = stores;
17
18 // Toggle todos feature
19 reaction(
20 () => features.features.isTodosEnabled,
21 (isEnabled) => {
22 if (isEnabled) {
23 debug('Initializing `todos` feature');
24 todosStore.start(stores, actions);
25 } else if (todosStore.isFeatureActive) {
26 debug('Disabling `todos` feature');
27 todosStore.stop();
28 }
29 },
30 {
31 fireImmediately: true,
32 },
33 );
34}
diff --git a/src/features/todos/preload.js b/src/features/todos/preload.js
new file mode 100644
index 000000000..6e38a2ef3
--- /dev/null
+++ b/src/features/todos/preload.js
@@ -0,0 +1,23 @@
1import { ipcRenderer } from 'electron';
2import { IPC } from './constants';
3
4const debug = require('debug')('Franz:feature:todos:preload');
5
6debug('Preloading Todos Webview');
7
8let hostMessageListener = () => {};
9
10window.franz = {
11 onInitialize(ipcHostMessageListener) {
12 hostMessageListener = ipcHostMessageListener;
13 ipcRenderer.sendToHost(IPC.TODOS_CLIENT_CHANNEL, { action: 'todos:initialized' });
14 },
15 sendToHost(message) {
16 ipcRenderer.sendToHost(IPC.TODOS_CLIENT_CHANNEL, message);
17 },
18};
19
20ipcRenderer.on(IPC.TODOS_HOST_CHANNEL, (event, message) => {
21 debug('Received host message', event, message);
22 hostMessageListener(message);
23});
diff --git a/src/features/todos/store.js b/src/features/todos/store.js
new file mode 100644
index 000000000..acf95df0d
--- /dev/null
+++ b/src/features/todos/store.js
@@ -0,0 +1,147 @@
1import { ThemeType } from '@meetfranz/theme';
2import {
3 computed,
4 action,
5 observable,
6} from 'mobx';
7import localStorage from 'mobx-localstorage';
8
9import { todoActions } from './actions';
10import { FeatureStore } from '../utils/FeatureStore';
11import { createReactions } from '../../stores/lib/Reaction';
12import { createActionBindings } from '../utils/ActionBinding';
13import { DEFAULT_TODOS_WIDTH, TODOS_MIN_WIDTH, DEFAULT_TODOS_VISIBLE } from '.';
14import { IPC } from './constants';
15
16const debug = require('debug')('Franz:feature:todos:store');
17
18export default class TodoStore extends FeatureStore {
19 @observable isFeatureEnabled = false;
20
21 @observable isFeatureActive = false;
22
23 webview = null;
24
25 @computed get width() {
26 const width = this.settings.width || DEFAULT_TODOS_WIDTH;
27
28 return width < TODOS_MIN_WIDTH ? TODOS_MIN_WIDTH : width;
29 }
30
31 @computed get isTodosPanelVisible() {
32 if (this.settings.isTodosPanelVisible === undefined) return DEFAULT_TODOS_VISIBLE;
33
34 return this.settings.isTodosPanelVisible;
35 }
36
37 @computed get settings() {
38 return localStorage.getItem('todos') || {};
39 }
40
41 // ========== PUBLIC API ========= //
42
43 @action start(stores, actions) {
44 debug('TodoStore::start');
45 this.stores = stores;
46 this.actions = actions;
47
48 // ACTIONS
49
50 this._registerActions(createActionBindings([
51 [todoActions.resize, this._resize],
52 [todoActions.toggleTodosPanel, this._toggleTodosPanel],
53 [todoActions.setTodosWebview, this._setTodosWebview],
54 [todoActions.handleHostMessage, this._handleHostMessage],
55 [todoActions.handleClientMessage, this._handleClientMessage],
56 ]));
57
58 // REACTIONS
59
60 this._allReactions = createReactions([
61 this._setFeatureEnabledReaction,
62 ]);
63
64 this._registerReactions(this._allReactions);
65
66 this.isFeatureActive = true;
67 }
68
69 @action stop() {
70 super.stop();
71 debug('TodoStore::stop');
72 this.reset();
73 this.isFeatureActive = false;
74 }
75
76 // ========== PRIVATE METHODS ========= //
77
78 _updateSettings = (changes) => {
79 localStorage.setItem('todos', {
80 ...this.settings,
81 ...changes,
82 });
83 };
84
85 // Actions
86
87 @action _resize = ({ width }) => {
88 this._updateSettings({
89 width,
90 });
91 };
92
93 @action _toggleTodosPanel = () => {
94 this._updateSettings({
95 isTodosPanelVisible: !this.isTodosPanelVisible,
96 });
97 };
98
99 @action _setTodosWebview = ({ webview }) => {
100 debug('_setTodosWebview', webview);
101 this.webview = webview;
102 };
103
104 @action _handleHostMessage = (message) => {
105 debug('_handleHostMessage', message);
106 if (message.action === 'todos:create') {
107 this.webview.send(IPC.TODOS_HOST_CHANNEL, message);
108 }
109 };
110
111 @action _handleClientMessage = (message) => {
112 debug('_handleClientMessage', message);
113 switch (message.action) {
114 case 'todos:initialized': this._onTodosClientInitialized(); break;
115 case 'todos:goToService': this._goToService(message.data); break;
116 default:
117 debug('Unknown client message reiceived', message);
118 }
119 };
120
121 // Todos client message handlers
122
123 _onTodosClientInitialized = () => {
124 this.webview.send(IPC.TODOS_HOST_CHANNEL, {
125 action: 'todos:configure',
126 data: {
127 authToken: this.stores.user.authToken,
128 theme: this.stores.ui.isDarkThemeActive ? ThemeType.dark : ThemeType.default,
129 },
130 });
131 };
132
133 _goToService = ({ url, serviceId }) => {
134 if (url) {
135 this.stores.services.one(serviceId).webview.loadURL(url);
136 }
137 this.actions.service.setActive({ serviceId });
138 };
139
140 // Reactions
141
142 _setFeatureEnabledReaction = () => {
143 const { isTodosEnabled } = this.stores.features.features;
144
145 this.isFeatureEnabled = isTodosEnabled;
146 };
147}
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json
index eca3062c2..5959fb059 100644
--- a/src/i18n/locales/defaultMessages.json
+++ b/src/i18n/locales/defaultMessages.json
@@ -669,39 +669,39 @@
669 "defaultMessage": "!!!Your services have been updated.", 669 "defaultMessage": "!!!Your services have been updated.",
670 "end": { 670 "end": {
671 "column": 3, 671 "column": 3,
672 "line": 29 672 "line": 30
673 }, 673 },
674 "file": "src/components/layout/AppLayout.js", 674 "file": "src/components/layout/AppLayout.js",
675 "id": "infobar.servicesUpdated", 675 "id": "infobar.servicesUpdated",
676 "start": { 676 "start": {
677 "column": 19, 677 "column": 19,
678 "line": 26 678 "line": 27
679 } 679 }
680 }, 680 },
681 { 681 {
682 "defaultMessage": "!!!Reload services", 682 "defaultMessage": "!!!Reload services",
683 "end": { 683 "end": {
684 "column": 3, 684 "column": 3,
685 "line": 33 685 "line": 34
686 }, 686 },
687 "file": "src/components/layout/AppLayout.js", 687 "file": "src/components/layout/AppLayout.js",
688 "id": "infobar.buttonReloadServices", 688 "id": "infobar.buttonReloadServices",
689 "start": { 689 "start": {
690 "column": 24, 690 "column": 24,
691 "line": 30 691 "line": 31
692 } 692 }
693 }, 693 },
694 { 694 {
695 "defaultMessage": "!!!Could not load services and user information", 695 "defaultMessage": "!!!Could not load services and user information",
696 "end": { 696 "end": {
697 "column": 3, 697 "column": 3,
698 "line": 37 698 "line": 38
699 }, 699 },
700 "file": "src/components/layout/AppLayout.js", 700 "file": "src/components/layout/AppLayout.js",
701 "id": "infobar.requiredRequestsFailed", 701 "id": "infobar.requiredRequestsFailed",
702 "start": { 702 "start": {
703 "column": 26, 703 "column": 26,
704 "line": 34 704 "line": 35
705 } 705 }
706 } 706 }
707 ], 707 ],
@@ -3917,741 +3917,793 @@
3917 "defaultMessage": "!!!Edit", 3917 "defaultMessage": "!!!Edit",
3918 "end": { 3918 "end": {
3919 "column": 3, 3919 "column": 3,
3920 "line": 18 3920 "line": 21
3921 }, 3921 },
3922 "file": "src/lib/Menu.js", 3922 "file": "src/lib/Menu.js",
3923 "id": "menu.edit", 3923 "id": "menu.edit",
3924 "start": { 3924 "start": {
3925 "column": 8, 3925 "column": 8,
3926 "line": 15 3926 "line": 18
3927 } 3927 }
3928 }, 3928 },
3929 { 3929 {
3930 "defaultMessage": "!!!Undo", 3930 "defaultMessage": "!!!Undo",
3931 "end": { 3931 "end": {
3932 "column": 3, 3932 "column": 3,
3933 "line": 22 3933 "line": 25
3934 }, 3934 },
3935 "file": "src/lib/Menu.js", 3935 "file": "src/lib/Menu.js",
3936 "id": "menu.edit.undo", 3936 "id": "menu.edit.undo",
3937 "start": { 3937 "start": {
3938 "column": 8, 3938 "column": 8,
3939 "line": 19 3939 "line": 22
3940 } 3940 }
3941 }, 3941 },
3942 { 3942 {
3943 "defaultMessage": "!!!Redo", 3943 "defaultMessage": "!!!Redo",
3944 "end": { 3944 "end": {
3945 "column": 3, 3945 "column": 3,
3946 "line": 26 3946 "line": 29
3947 }, 3947 },
3948 "file": "src/lib/Menu.js", 3948 "file": "src/lib/Menu.js",
3949 "id": "menu.edit.redo", 3949 "id": "menu.edit.redo",
3950 "start": { 3950 "start": {
3951 "column": 8, 3951 "column": 8,
3952 "line": 23 3952 "line": 26
3953 } 3953 }
3954 }, 3954 },
3955 { 3955 {
3956 "defaultMessage": "!!!Cut", 3956 "defaultMessage": "!!!Cut",
3957 "end": { 3957 "end": {
3958 "column": 3, 3958 "column": 3,
3959 "line": 30 3959 "line": 33
3960 }, 3960 },
3961 "file": "src/lib/Menu.js", 3961 "file": "src/lib/Menu.js",
3962 "id": "menu.edit.cut", 3962 "id": "menu.edit.cut",
3963 "start": { 3963 "start": {
3964 "column": 7, 3964 "column": 7,
3965 "line": 27 3965 "line": 30
3966 } 3966 }
3967 }, 3967 },
3968 { 3968 {
3969 "defaultMessage": "!!!Copy", 3969 "defaultMessage": "!!!Copy",
3970 "end": { 3970 "end": {
3971 "column": 3, 3971 "column": 3,
3972 "line": 34 3972 "line": 37
3973 }, 3973 },
3974 "file": "src/lib/Menu.js", 3974 "file": "src/lib/Menu.js",
3975 "id": "menu.edit.copy", 3975 "id": "menu.edit.copy",
3976 "start": { 3976 "start": {
3977 "column": 8, 3977 "column": 8,
3978 "line": 31 3978 "line": 34
3979 } 3979 }
3980 }, 3980 },
3981 { 3981 {
3982 "defaultMessage": "!!!Paste", 3982 "defaultMessage": "!!!Paste",
3983 "end": { 3983 "end": {
3984 "column": 3, 3984 "column": 3,
3985 "line": 38 3985 "line": 41
3986 }, 3986 },
3987 "file": "src/lib/Menu.js", 3987 "file": "src/lib/Menu.js",
3988 "id": "menu.edit.paste", 3988 "id": "menu.edit.paste",
3989 "start": { 3989 "start": {
3990 "column": 9, 3990 "column": 9,
3991 "line": 35 3991 "line": 38
3992 } 3992 }
3993 }, 3993 },
3994 { 3994 {
3995 "defaultMessage": "!!!Paste And Match Style", 3995 "defaultMessage": "!!!Paste And Match Style",
3996 "end": { 3996 "end": {
3997 "column": 3, 3997 "column": 3,
3998 "line": 42 3998 "line": 45
3999 }, 3999 },
4000 "file": "src/lib/Menu.js", 4000 "file": "src/lib/Menu.js",
4001 "id": "menu.edit.pasteAndMatchStyle", 4001 "id": "menu.edit.pasteAndMatchStyle",
4002 "start": { 4002 "start": {
4003 "column": 22, 4003 "column": 22,
4004 "line": 39 4004 "line": 42
4005 } 4005 }
4006 }, 4006 },
4007 { 4007 {
4008 "defaultMessage": "!!!Delete", 4008 "defaultMessage": "!!!Delete",
4009 "end": { 4009 "end": {
4010 "column": 3, 4010 "column": 3,
4011 "line": 46 4011 "line": 49
4012 }, 4012 },
4013 "file": "src/lib/Menu.js", 4013 "file": "src/lib/Menu.js",
4014 "id": "menu.edit.delete", 4014 "id": "menu.edit.delete",
4015 "start": { 4015 "start": {
4016 "column": 10, 4016 "column": 10,
4017 "line": 43 4017 "line": 46
4018 } 4018 }
4019 }, 4019 },
4020 { 4020 {
4021 "defaultMessage": "!!!Select All", 4021 "defaultMessage": "!!!Select All",
4022 "end": { 4022 "end": {
4023 "column": 3, 4023 "column": 3,
4024 "line": 50 4024 "line": 53
4025 }, 4025 },
4026 "file": "src/lib/Menu.js", 4026 "file": "src/lib/Menu.js",
4027 "id": "menu.edit.selectAll", 4027 "id": "menu.edit.selectAll",
4028 "start": { 4028 "start": {
4029 "column": 13, 4029 "column": 13,
4030 "line": 47 4030 "line": 50
4031 } 4031 }
4032 }, 4032 },
4033 { 4033 {
4034 "defaultMessage": "!!!Speech", 4034 "defaultMessage": "!!!Speech",
4035 "end": { 4035 "end": {
4036 "column": 3, 4036 "column": 3,
4037 "line": 54 4037 "line": 57
4038 }, 4038 },
4039 "file": "src/lib/Menu.js", 4039 "file": "src/lib/Menu.js",
4040 "id": "menu.edit.speech", 4040 "id": "menu.edit.speech",
4041 "start": { 4041 "start": {
4042 "column": 10, 4042 "column": 10,
4043 "line": 51 4043 "line": 54
4044 } 4044 }
4045 }, 4045 },
4046 { 4046 {
4047 "defaultMessage": "!!!Start Speaking", 4047 "defaultMessage": "!!!Start Speaking",
4048 "end": { 4048 "end": {
4049 "column": 3, 4049 "column": 3,
4050 "line": 58 4050 "line": 61
4051 }, 4051 },
4052 "file": "src/lib/Menu.js", 4052 "file": "src/lib/Menu.js",
4053 "id": "menu.edit.startSpeaking", 4053 "id": "menu.edit.startSpeaking",
4054 "start": { 4054 "start": {
4055 "column": 17, 4055 "column": 17,
4056 "line": 55 4056 "line": 58
4057 } 4057 }
4058 }, 4058 },
4059 { 4059 {
4060 "defaultMessage": "!!!Stop Speaking", 4060 "defaultMessage": "!!!Stop Speaking",
4061 "end": { 4061 "end": {
4062 "column": 3, 4062 "column": 3,
4063 "line": 62 4063 "line": 65
4064 }, 4064 },
4065 "file": "src/lib/Menu.js", 4065 "file": "src/lib/Menu.js",
4066 "id": "menu.edit.stopSpeaking", 4066 "id": "menu.edit.stopSpeaking",
4067 "start": { 4067 "start": {
4068 "column": 16, 4068 "column": 16,
4069 "line": 59 4069 "line": 62
4070 } 4070 }
4071 }, 4071 },
4072 { 4072 {
4073 "defaultMessage": "!!!Start Dictation", 4073 "defaultMessage": "!!!Start Dictation",
4074 "end": { 4074 "end": {
4075 "column": 3, 4075 "column": 3,
4076 "line": 66 4076 "line": 69
4077 }, 4077 },
4078 "file": "src/lib/Menu.js", 4078 "file": "src/lib/Menu.js",
4079 "id": "menu.edit.startDictation", 4079 "id": "menu.edit.startDictation",
4080 "start": { 4080 "start": {
4081 "column": 18, 4081 "column": 18,
4082 "line": 63 4082 "line": 66
4083 } 4083 }
4084 }, 4084 },
4085 { 4085 {
4086 "defaultMessage": "!!!Emoji & Symbols", 4086 "defaultMessage": "!!!Emoji & Symbols",
4087 "end": { 4087 "end": {
4088 "column": 3, 4088 "column": 3,
4089 "line": 70 4089 "line": 73
4090 }, 4090 },
4091 "file": "src/lib/Menu.js", 4091 "file": "src/lib/Menu.js",
4092 "id": "menu.edit.emojiSymbols", 4092 "id": "menu.edit.emojiSymbols",
4093 "start": { 4093 "start": {
4094 "column": 16, 4094 "column": 16,
4095 "line": 67 4095 "line": 70
4096 } 4096 }
4097 }, 4097 },
4098 { 4098 {
4099 "defaultMessage": "!!!Actual Size", 4099 "defaultMessage": "!!!Actual Size",
4100 "end": { 4100 "end": {
4101 "column": 3, 4101 "column": 3,
4102 "line": 74 4102 "line": 77
4103 }, 4103 },
4104 "file": "src/lib/Menu.js", 4104 "file": "src/lib/Menu.js",
4105 "id": "menu.view.resetZoom", 4105 "id": "menu.view.resetZoom",
4106 "start": { 4106 "start": {
4107 "column": 13, 4107 "column": 13,
4108 "line": 71 4108 "line": 74
4109 } 4109 }
4110 }, 4110 },
4111 { 4111 {
4112 "defaultMessage": "!!!Zoom In", 4112 "defaultMessage": "!!!Zoom In",
4113 "end": { 4113 "end": {
4114 "column": 3, 4114 "column": 3,
4115 "line": 78 4115 "line": 81
4116 }, 4116 },
4117 "file": "src/lib/Menu.js", 4117 "file": "src/lib/Menu.js",
4118 "id": "menu.view.zoomIn", 4118 "id": "menu.view.zoomIn",
4119 "start": { 4119 "start": {
4120 "column": 10, 4120 "column": 10,
4121 "line": 75 4121 "line": 78
4122 } 4122 }
4123 }, 4123 },
4124 { 4124 {
4125 "defaultMessage": "!!!Zoom Out", 4125 "defaultMessage": "!!!Zoom Out",
4126 "end": { 4126 "end": {
4127 "column": 3, 4127 "column": 3,
4128 "line": 82 4128 "line": 85
4129 }, 4129 },
4130 "file": "src/lib/Menu.js", 4130 "file": "src/lib/Menu.js",
4131 "id": "menu.view.zoomOut", 4131 "id": "menu.view.zoomOut",
4132 "start": { 4132 "start": {
4133 "column": 11, 4133 "column": 11,
4134 "line": 79 4134 "line": 82
4135 } 4135 }
4136 }, 4136 },
4137 { 4137 {
4138 "defaultMessage": "!!!Enter Full Screen", 4138 "defaultMessage": "!!!Enter Full Screen",
4139 "end": { 4139 "end": {
4140 "column": 3, 4140 "column": 3,
4141 "line": 86 4141 "line": 89
4142 }, 4142 },
4143 "file": "src/lib/Menu.js", 4143 "file": "src/lib/Menu.js",
4144 "id": "menu.view.enterFullScreen", 4144 "id": "menu.view.enterFullScreen",
4145 "start": { 4145 "start": {
4146 "column": 19, 4146 "column": 19,
4147 "line": 83 4147 "line": 86
4148 } 4148 }
4149 }, 4149 },
4150 { 4150 {
4151 "defaultMessage": "!!!Exit Full Screen", 4151 "defaultMessage": "!!!Exit Full Screen",
4152 "end": { 4152 "end": {
4153 "column": 3, 4153 "column": 3,
4154 "line": 90 4154 "line": 93
4155 }, 4155 },
4156 "file": "src/lib/Menu.js", 4156 "file": "src/lib/Menu.js",
4157 "id": "menu.view.exitFullScreen", 4157 "id": "menu.view.exitFullScreen",
4158 "start": { 4158 "start": {
4159 "column": 18, 4159 "column": 18,
4160 "line": 87 4160 "line": 90
4161 } 4161 }
4162 }, 4162 },
4163 { 4163 {
4164 "defaultMessage": "!!!Toggle Full Screen", 4164 "defaultMessage": "!!!Toggle Full Screen",
4165 "end": { 4165 "end": {
4166 "column": 3, 4166 "column": 3,
4167 "line": 94 4167 "line": 97
4168 }, 4168 },
4169 "file": "src/lib/Menu.js", 4169 "file": "src/lib/Menu.js",
4170 "id": "menu.view.toggleFullScreen", 4170 "id": "menu.view.toggleFullScreen",
4171 "start": { 4171 "start": {
4172 "column": 20, 4172 "column": 20,
4173 "line": 91 4173 "line": 94
4174 } 4174 }
4175 }, 4175 },
4176 { 4176 {
4177 "defaultMessage": "!!!Toggle Developer Tools", 4177 "defaultMessage": "!!!Toggle Developer Tools",
4178 "end": { 4178 "end": {
4179 "column": 3, 4179 "column": 3,
4180 "line": 98 4180 "line": 101
4181 }, 4181 },
4182 "file": "src/lib/Menu.js", 4182 "file": "src/lib/Menu.js",
4183 "id": "menu.view.toggleDevTools", 4183 "id": "menu.view.toggleDevTools",
4184 "start": { 4184 "start": {
4185 "column": 18, 4185 "column": 18,
4186 "line": 95 4186 "line": 98
4187 } 4187 }
4188 }, 4188 },
4189 { 4189 {
4190 "defaultMessage": "!!!Toggle Service Developer Tools", 4190 "defaultMessage": "!!!Toggle Todos Developer Tools",
4191 "end": { 4191 "end": {
4192 "column": 3, 4192 "column": 3,
4193 "line": 105
4194 },
4195 "file": "src/lib/Menu.js",
4196 "id": "menu.view.toggleTodosDevTools",
4197 "start": {
4198 "column": 23,
4193 "line": 102 4199 "line": 102
4200 }
4201 },
4202 {
4203 "defaultMessage": "!!!Toggle Service Developer Tools",
4204 "end": {
4205 "column": 3,
4206 "line": 109
4194 }, 4207 },
4195 "file": "src/lib/Menu.js", 4208 "file": "src/lib/Menu.js",
4196 "id": "menu.view.toggleServiceDevTools", 4209 "id": "menu.view.toggleServiceDevTools",
4197 "start": { 4210 "start": {
4198 "column": 25, 4211 "column": 25,
4199 "line": 99 4212 "line": 106
4200 } 4213 }
4201 }, 4214 },
4202 { 4215 {
4203 "defaultMessage": "!!!Reload Service", 4216 "defaultMessage": "!!!Reload Service",
4204 "end": { 4217 "end": {
4205 "column": 3, 4218 "column": 3,
4206 "line": 106 4219 "line": 113
4207 }, 4220 },
4208 "file": "src/lib/Menu.js", 4221 "file": "src/lib/Menu.js",
4209 "id": "menu.view.reloadService", 4222 "id": "menu.view.reloadService",
4210 "start": { 4223 "start": {
4211 "column": 17, 4224 "column": 17,
4212 "line": 103 4225 "line": 110
4213 } 4226 }
4214 }, 4227 },
4215 { 4228 {
4216 "defaultMessage": "!!!Reload Franz", 4229 "defaultMessage": "!!!Reload Franz",
4217 "end": { 4230 "end": {
4218 "column": 3, 4231 "column": 3,
4219 "line": 110 4232 "line": 117
4220 }, 4233 },
4221 "file": "src/lib/Menu.js", 4234 "file": "src/lib/Menu.js",
4222 "id": "menu.view.reloadFranz", 4235 "id": "menu.view.reloadFranz",
4223 "start": { 4236 "start": {
4224 "column": 15, 4237 "column": 15,
4225 "line": 107 4238 "line": 114
4226 } 4239 }
4227 }, 4240 },
4228 { 4241 {
4229 "defaultMessage": "!!!Minimize", 4242 "defaultMessage": "!!!Minimize",
4230 "end": { 4243 "end": {
4231 "column": 3, 4244 "column": 3,
4232 "line": 114 4245 "line": 121
4233 }, 4246 },
4234 "file": "src/lib/Menu.js", 4247 "file": "src/lib/Menu.js",
4235 "id": "menu.window.minimize", 4248 "id": "menu.window.minimize",
4236 "start": { 4249 "start": {
4237 "column": 12, 4250 "column": 12,
4238 "line": 111 4251 "line": 118
4239 } 4252 }
4240 }, 4253 },
4241 { 4254 {
4242 "defaultMessage": "!!!Close", 4255 "defaultMessage": "!!!Close",
4243 "end": { 4256 "end": {
4244 "column": 3, 4257 "column": 3,
4245 "line": 118 4258 "line": 125
4246 }, 4259 },
4247 "file": "src/lib/Menu.js", 4260 "file": "src/lib/Menu.js",
4248 "id": "menu.window.close", 4261 "id": "menu.window.close",
4249 "start": { 4262 "start": {
4250 "column": 9, 4263 "column": 9,
4251 "line": 115 4264 "line": 122
4252 } 4265 }
4253 }, 4266 },
4254 { 4267 {
4255 "defaultMessage": "!!!Learn More", 4268 "defaultMessage": "!!!Learn More",
4256 "end": { 4269 "end": {
4257 "column": 3, 4270 "column": 3,
4258 "line": 122 4271 "line": 129
4259 }, 4272 },
4260 "file": "src/lib/Menu.js", 4273 "file": "src/lib/Menu.js",
4261 "id": "menu.help.learnMore", 4274 "id": "menu.help.learnMore",
4262 "start": { 4275 "start": {
4263 "column": 13, 4276 "column": 13,
4264 "line": 119 4277 "line": 126
4265 } 4278 }
4266 }, 4279 },
4267 { 4280 {
4268 "defaultMessage": "!!!Changelog", 4281 "defaultMessage": "!!!Changelog",
4269 "end": { 4282 "end": {
4270 "column": 3, 4283 "column": 3,
4271 "line": 126 4284 "line": 133
4272 }, 4285 },
4273 "file": "src/lib/Menu.js", 4286 "file": "src/lib/Menu.js",
4274 "id": "menu.help.changelog", 4287 "id": "menu.help.changelog",
4275 "start": { 4288 "start": {
4276 "column": 13, 4289 "column": 13,
4277 "line": 123 4290 "line": 130
4278 } 4291 }
4279 }, 4292 },
4280 { 4293 {
4281 "defaultMessage": "!!!Support", 4294 "defaultMessage": "!!!Support",
4282 "end": { 4295 "end": {
4283 "column": 3, 4296 "column": 3,
4284 "line": 130 4297 "line": 137
4285 }, 4298 },
4286 "file": "src/lib/Menu.js", 4299 "file": "src/lib/Menu.js",
4287 "id": "menu.help.support", 4300 "id": "menu.help.support",
4288 "start": { 4301 "start": {
4289 "column": 11, 4302 "column": 11,
4290 "line": 127 4303 "line": 134
4291 } 4304 }
4292 }, 4305 },
4293 { 4306 {
4294 "defaultMessage": "!!!Copy Debug Information", 4307 "defaultMessage": "!!!Copy Debug Information",
4295 "end": { 4308 "end": {
4296 "column": 3, 4309 "column": 3,
4297 "line": 134 4310 "line": 141
4298 }, 4311 },
4299 "file": "src/lib/Menu.js", 4312 "file": "src/lib/Menu.js",
4300 "id": "menu.help.debugInfo", 4313 "id": "menu.help.debugInfo",
4301 "start": { 4314 "start": {
4302 "column": 13, 4315 "column": 13,
4303 "line": 131 4316 "line": 138
4304 } 4317 }
4305 }, 4318 },
4306 { 4319 {
4307 "defaultMessage": "!!!Franz Debug Information", 4320 "defaultMessage": "!!!Franz Debug Information",
4308 "end": { 4321 "end": {
4309 "column": 3, 4322 "column": 3,
4310 "line": 138 4323 "line": 145
4311 }, 4324 },
4312 "file": "src/lib/Menu.js", 4325 "file": "src/lib/Menu.js",
4313 "id": "menu.help.debugInfoCopiedHeadline", 4326 "id": "menu.help.debugInfoCopiedHeadline",
4314 "start": { 4327 "start": {
4315 "column": 27, 4328 "column": 27,
4316 "line": 135 4329 "line": 142
4317 } 4330 }
4318 }, 4331 },
4319 { 4332 {
4320 "defaultMessage": "!!!Your Debug Information has been copied to your clipboard.", 4333 "defaultMessage": "!!!Your Debug Information has been copied to your clipboard.",
4321 "end": { 4334 "end": {
4322 "column": 3, 4335 "column": 3,
4323 "line": 142 4336 "line": 149
4324 }, 4337 },
4325 "file": "src/lib/Menu.js", 4338 "file": "src/lib/Menu.js",
4326 "id": "menu.help.debugInfoCopiedBody", 4339 "id": "menu.help.debugInfoCopiedBody",
4327 "start": { 4340 "start": {
4328 "column": 23, 4341 "column": 23,
4329 "line": 139 4342 "line": 146
4330 } 4343 }
4331 }, 4344 },
4332 { 4345 {
4333 "defaultMessage": "!!!Terms of Service", 4346 "defaultMessage": "!!!Terms of Service",
4334 "end": { 4347 "end": {
4335 "column": 3, 4348 "column": 3,
4336 "line": 146 4349 "line": 153
4337 }, 4350 },
4338 "file": "src/lib/Menu.js", 4351 "file": "src/lib/Menu.js",
4339 "id": "menu.help.tos", 4352 "id": "menu.help.tos",
4340 "start": { 4353 "start": {
4341 "column": 7, 4354 "column": 7,
4342 "line": 143 4355 "line": 150
4343 } 4356 }
4344 }, 4357 },
4345 { 4358 {
4346 "defaultMessage": "!!!Privacy Statement", 4359 "defaultMessage": "!!!Privacy Statement",
4347 "end": { 4360 "end": {
4348 "column": 3, 4361 "column": 3,
4349 "line": 150 4362 "line": 157
4350 }, 4363 },
4351 "file": "src/lib/Menu.js", 4364 "file": "src/lib/Menu.js",
4352 "id": "menu.help.privacy", 4365 "id": "menu.help.privacy",
4353 "start": { 4366 "start": {
4354 "column": 11, 4367 "column": 11,
4355 "line": 147 4368 "line": 154
4356 } 4369 }
4357 }, 4370 },
4358 { 4371 {
4359 "defaultMessage": "!!!File", 4372 "defaultMessage": "!!!File",
4360 "end": { 4373 "end": {
4361 "column": 3, 4374 "column": 3,
4362 "line": 154 4375 "line": 161
4363 }, 4376 },
4364 "file": "src/lib/Menu.js", 4377 "file": "src/lib/Menu.js",
4365 "id": "menu.file", 4378 "id": "menu.file",
4366 "start": { 4379 "start": {
4367 "column": 8, 4380 "column": 8,
4368 "line": 151 4381 "line": 158
4369 } 4382 }
4370 }, 4383 },
4371 { 4384 {
4372 "defaultMessage": "!!!View", 4385 "defaultMessage": "!!!View",
4373 "end": { 4386 "end": {
4374 "column": 3, 4387 "column": 3,
4375 "line": 158 4388 "line": 165
4376 }, 4389 },
4377 "file": "src/lib/Menu.js", 4390 "file": "src/lib/Menu.js",
4378 "id": "menu.view", 4391 "id": "menu.view",
4379 "start": { 4392 "start": {
4380 "column": 8, 4393 "column": 8,
4381 "line": 155 4394 "line": 162
4382 } 4395 }
4383 }, 4396 },
4384 { 4397 {
4385 "defaultMessage": "!!!Services", 4398 "defaultMessage": "!!!Services",
4386 "end": { 4399 "end": {
4387 "column": 3, 4400 "column": 3,
4388 "line": 162 4401 "line": 169
4389 }, 4402 },
4390 "file": "src/lib/Menu.js", 4403 "file": "src/lib/Menu.js",
4391 "id": "menu.services", 4404 "id": "menu.services",
4392 "start": { 4405 "start": {
4393 "column": 12, 4406 "column": 12,
4394 "line": 159 4407 "line": 166
4395 } 4408 }
4396 }, 4409 },
4397 { 4410 {
4398 "defaultMessage": "!!!Window", 4411 "defaultMessage": "!!!Window",
4399 "end": { 4412 "end": {
4400 "column": 3, 4413 "column": 3,
4401 "line": 166 4414 "line": 173
4402 }, 4415 },
4403 "file": "src/lib/Menu.js", 4416 "file": "src/lib/Menu.js",
4404 "id": "menu.window", 4417 "id": "menu.window",
4405 "start": { 4418 "start": {
4406 "column": 10, 4419 "column": 10,
4407 "line": 163 4420 "line": 170
4408 } 4421 }
4409 }, 4422 },
4410 { 4423 {
4411 "defaultMessage": "!!!Help", 4424 "defaultMessage": "!!!Help",
4412 "end": { 4425 "end": {
4413 "column": 3, 4426 "column": 3,
4414 "line": 170 4427 "line": 177
4415 }, 4428 },
4416 "file": "src/lib/Menu.js", 4429 "file": "src/lib/Menu.js",
4417 "id": "menu.help", 4430 "id": "menu.help",
4418 "start": { 4431 "start": {
4419 "column": 8, 4432 "column": 8,
4420 "line": 167 4433 "line": 174
4421 } 4434 }
4422 }, 4435 },
4423 { 4436 {
4424 "defaultMessage": "!!!About Franz", 4437 "defaultMessage": "!!!About Franz",
4425 "end": { 4438 "end": {
4426 "column": 3, 4439 "column": 3,
4427 "line": 174 4440 "line": 181
4428 }, 4441 },
4429 "file": "src/lib/Menu.js", 4442 "file": "src/lib/Menu.js",
4430 "id": "menu.app.about", 4443 "id": "menu.app.about",
4431 "start": { 4444 "start": {
4432 "column": 9, 4445 "column": 9,
4433 "line": 171 4446 "line": 178
4434 } 4447 }
4435 }, 4448 },
4436 { 4449 {
4437 "defaultMessage": "!!!What's new?", 4450 "defaultMessage": "!!!What's new?",
4438 "end": { 4451 "end": {
4439 "column": 3, 4452 "column": 3,
4440 "line": 178 4453 "line": 185
4441 }, 4454 },
4442 "file": "src/lib/Menu.js", 4455 "file": "src/lib/Menu.js",
4443 "id": "menu.app.announcement", 4456 "id": "menu.app.announcement",
4444 "start": { 4457 "start": {
4445 "column": 16, 4458 "column": 16,
4446 "line": 175 4459 "line": 182
4447 } 4460 }
4448 }, 4461 },
4449 { 4462 {
4450 "defaultMessage": "!!!Settings", 4463 "defaultMessage": "!!!Settings",
4451 "end": { 4464 "end": {
4452 "column": 3, 4465 "column": 3,
4453 "line": 182 4466 "line": 189
4454 }, 4467 },
4455 "file": "src/lib/Menu.js", 4468 "file": "src/lib/Menu.js",
4456 "id": "menu.app.settings", 4469 "id": "menu.app.settings",
4457 "start": { 4470 "start": {
4458 "column": 12, 4471 "column": 12,
4459 "line": 179 4472 "line": 186
4460 } 4473 }
4461 }, 4474 },
4462 { 4475 {
4463 "defaultMessage": "!!!Check for updates", 4476 "defaultMessage": "!!!Check for updates",
4464 "end": { 4477 "end": {
4465 "column": 3, 4478 "column": 3,
4466 "line": 186 4479 "line": 193
4467 }, 4480 },
4468 "file": "src/lib/Menu.js", 4481 "file": "src/lib/Menu.js",
4469 "id": "menu.app.checkForUpdates", 4482 "id": "menu.app.checkForUpdates",
4470 "start": { 4483 "start": {
4471 "column": 19, 4484 "column": 19,
4472 "line": 183 4485 "line": 190
4473 } 4486 }
4474 }, 4487 },
4475 { 4488 {
4476 "defaultMessage": "!!!Hide", 4489 "defaultMessage": "!!!Hide",
4477 "end": { 4490 "end": {
4478 "column": 3, 4491 "column": 3,
4479 "line": 190 4492 "line": 197
4480 }, 4493 },
4481 "file": "src/lib/Menu.js", 4494 "file": "src/lib/Menu.js",
4482 "id": "menu.app.hide", 4495 "id": "menu.app.hide",
4483 "start": { 4496 "start": {
4484 "column": 8, 4497 "column": 8,
4485 "line": 187 4498 "line": 194
4486 } 4499 }
4487 }, 4500 },
4488 { 4501 {
4489 "defaultMessage": "!!!Hide Others", 4502 "defaultMessage": "!!!Hide Others",
4490 "end": { 4503 "end": {
4491 "column": 3, 4504 "column": 3,
4492 "line": 194 4505 "line": 201
4493 }, 4506 },
4494 "file": "src/lib/Menu.js", 4507 "file": "src/lib/Menu.js",
4495 "id": "menu.app.hideOthers", 4508 "id": "menu.app.hideOthers",
4496 "start": { 4509 "start": {
4497 "column": 14, 4510 "column": 14,
4498 "line": 191 4511 "line": 198
4499 } 4512 }
4500 }, 4513 },
4501 { 4514 {
4502 "defaultMessage": "!!!Unhide", 4515 "defaultMessage": "!!!Unhide",
4503 "end": { 4516 "end": {
4504 "column": 3, 4517 "column": 3,
4505 "line": 198 4518 "line": 205
4506 }, 4519 },
4507 "file": "src/lib/Menu.js", 4520 "file": "src/lib/Menu.js",
4508 "id": "menu.app.unhide", 4521 "id": "menu.app.unhide",
4509 "start": { 4522 "start": {
4510 "column": 10, 4523 "column": 10,
4511 "line": 195 4524 "line": 202
4512 } 4525 }
4513 }, 4526 },
4514 { 4527 {
4515 "defaultMessage": "!!!Quit", 4528 "defaultMessage": "!!!Quit",
4516 "end": { 4529 "end": {
4517 "column": 3, 4530 "column": 3,
4518 "line": 202 4531 "line": 209
4519 }, 4532 },
4520 "file": "src/lib/Menu.js", 4533 "file": "src/lib/Menu.js",
4521 "id": "menu.app.quit", 4534 "id": "menu.app.quit",
4522 "start": { 4535 "start": {
4523 "column": 8, 4536 "column": 8,
4524 "line": 199 4537 "line": 206
4525 } 4538 }
4526 }, 4539 },
4527 { 4540 {
4528 "defaultMessage": "!!!Add New Service...", 4541 "defaultMessage": "!!!Add New Service...",
4529 "end": { 4542 "end": {
4530 "column": 3, 4543 "column": 3,
4531 "line": 206 4544 "line": 213
4532 }, 4545 },
4533 "file": "src/lib/Menu.js", 4546 "file": "src/lib/Menu.js",
4534 "id": "menu.services.addNewService", 4547 "id": "menu.services.addNewService",
4535 "start": { 4548 "start": {
4536 "column": 17, 4549 "column": 17,
4537 "line": 203 4550 "line": 210
4538 } 4551 }
4539 }, 4552 },
4540 { 4553 {
4541 "defaultMessage": "!!!Add New Workspace...", 4554 "defaultMessage": "!!!Add New Workspace...",
4542 "end": { 4555 "end": {
4543 "column": 3, 4556 "column": 3,
4544 "line": 210 4557 "line": 217
4545 }, 4558 },
4546 "file": "src/lib/Menu.js", 4559 "file": "src/lib/Menu.js",
4547 "id": "menu.workspaces.addNewWorkspace", 4560 "id": "menu.workspaces.addNewWorkspace",
4548 "start": { 4561 "start": {
4549 "column": 19, 4562 "column": 19,
4550 "line": 207 4563 "line": 214
4551 } 4564 }
4552 }, 4565 },
4553 { 4566 {
4554 "defaultMessage": "!!!Open workspace drawer", 4567 "defaultMessage": "!!!Open workspace drawer",
4555 "end": { 4568 "end": {
4556 "column": 3, 4569 "column": 3,
4557 "line": 214 4570 "line": 221
4558 }, 4571 },
4559 "file": "src/lib/Menu.js", 4572 "file": "src/lib/Menu.js",
4560 "id": "menu.workspaces.openWorkspaceDrawer", 4573 "id": "menu.workspaces.openWorkspaceDrawer",
4561 "start": { 4574 "start": {
4562 "column": 23, 4575 "column": 23,
4563 "line": 211 4576 "line": 218
4564 } 4577 }
4565 }, 4578 },
4566 { 4579 {
4567 "defaultMessage": "!!!Close workspace drawer", 4580 "defaultMessage": "!!!Close workspace drawer",
4568 "end": { 4581 "end": {
4569 "column": 3, 4582 "column": 3,
4570 "line": 218 4583 "line": 225
4571 }, 4584 },
4572 "file": "src/lib/Menu.js", 4585 "file": "src/lib/Menu.js",
4573 "id": "menu.workspaces.closeWorkspaceDrawer", 4586 "id": "menu.workspaces.closeWorkspaceDrawer",
4574 "start": { 4587 "start": {
4575 "column": 24, 4588 "column": 24,
4576 "line": 215 4589 "line": 222
4577 } 4590 }
4578 }, 4591 },
4579 { 4592 {
4580 "defaultMessage": "!!!Activate next service...", 4593 "defaultMessage": "!!!Activate next service...",
4581 "end": { 4594 "end": {
4582 "column": 3, 4595 "column": 3,
4583 "line": 222 4596 "line": 229
4584 }, 4597 },
4585 "file": "src/lib/Menu.js", 4598 "file": "src/lib/Menu.js",
4586 "id": "menu.services.setNextServiceActive", 4599 "id": "menu.services.setNextServiceActive",
4587 "start": { 4600 "start": {
4588 "column": 23, 4601 "column": 23,
4589 "line": 219 4602 "line": 226
4590 } 4603 }
4591 }, 4604 },
4592 { 4605 {
4593 "defaultMessage": "!!!Activate previous service...", 4606 "defaultMessage": "!!!Activate previous service...",
4594 "end": { 4607 "end": {
4595 "column": 3, 4608 "column": 3,
4596 "line": 226 4609 "line": 233
4597 }, 4610 },
4598 "file": "src/lib/Menu.js", 4611 "file": "src/lib/Menu.js",
4599 "id": "menu.services.activatePreviousService", 4612 "id": "menu.services.activatePreviousService",
4600 "start": { 4613 "start": {
4601 "column": 27, 4614 "column": 27,
4602 "line": 223 4615 "line": 230
4603 } 4616 }
4604 }, 4617 },
4605 { 4618 {
4606 "defaultMessage": "!!!Disable notifications & audio", 4619 "defaultMessage": "!!!Disable notifications & audio",
4607 "end": { 4620 "end": {
4608 "column": 3, 4621 "column": 3,
4609 "line": 230 4622 "line": 237
4610 }, 4623 },
4611 "file": "src/lib/Menu.js", 4624 "file": "src/lib/Menu.js",
4612 "id": "sidebar.muteApp", 4625 "id": "sidebar.muteApp",
4613 "start": { 4626 "start": {
4614 "column": 11, 4627 "column": 11,
4615 "line": 227 4628 "line": 234
4616 } 4629 }
4617 }, 4630 },
4618 { 4631 {
4619 "defaultMessage": "!!!Enable notifications & audio", 4632 "defaultMessage": "!!!Enable notifications & audio",
4620 "end": { 4633 "end": {
4621 "column": 3, 4634 "column": 3,
4622 "line": 234 4635 "line": 241
4623 }, 4636 },
4624 "file": "src/lib/Menu.js", 4637 "file": "src/lib/Menu.js",
4625 "id": "sidebar.unmuteApp", 4638 "id": "sidebar.unmuteApp",
4626 "start": { 4639 "start": {
4627 "column": 13, 4640 "column": 13,
4628 "line": 231 4641 "line": 238
4629 } 4642 }
4630 }, 4643 },
4631 { 4644 {
4632 "defaultMessage": "!!!Workspaces", 4645 "defaultMessage": "!!!Workspaces",
4633 "end": { 4646 "end": {
4634 "column": 3, 4647 "column": 3,
4635 "line": 238 4648 "line": 245
4636 }, 4649 },
4637 "file": "src/lib/Menu.js", 4650 "file": "src/lib/Menu.js",
4638 "id": "menu.workspaces", 4651 "id": "menu.workspaces",
4639 "start": { 4652 "start": {
4640 "column": 14, 4653 "column": 14,
4641 "line": 235 4654 "line": 242
4642 } 4655 }
4643 }, 4656 },
4644 { 4657 {
4645 "defaultMessage": "!!!Default", 4658 "defaultMessage": "!!!Default",
4646 "end": { 4659 "end": {
4647 "column": 3, 4660 "column": 3,
4648 "line": 242 4661 "line": 249
4649 }, 4662 },
4650 "file": "src/lib/Menu.js", 4663 "file": "src/lib/Menu.js",
4651 "id": "menu.workspaces.defaultWorkspace", 4664 "id": "menu.workspaces.defaultWorkspace",
4652 "start": { 4665 "start": {
4653 "column": 20, 4666 "column": 20,
4654 "line": 239 4667 "line": 246
4668 }
4669 },
4670 {
4671 "defaultMessage": "!!!Todos",
4672 "end": {
4673 "column": 3,
4674 "line": 253
4675 },
4676 "file": "src/lib/Menu.js",
4677 "id": "menu.todos",
4678 "start": {
4679 "column": 9,
4680 "line": 250
4681 }
4682 },
4683 {
4684 "defaultMessage": "!!!Open Todos drawer",
4685 "end": {
4686 "column": 3,
4687 "line": 257
4688 },
4689 "file": "src/lib/Menu.js",
4690 "id": "menu.Todoss.openTodosDrawer",
4691 "start": {
4692 "column": 19,
4693 "line": 254
4694 }
4695 },
4696 {
4697 "defaultMessage": "!!!Close Todos drawer",
4698 "end": {
4699 "column": 3,
4700 "line": 261
4701 },
4702 "file": "src/lib/Menu.js",
4703 "id": "menu.Todoss.closeTodosDrawer",
4704 "start": {
4705 "column": 20,
4706 "line": 258
4655 } 4707 }
4656 } 4708 }
4657 ], 4709 ],
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 27987e5b7..cee42c350 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -43,6 +43,8 @@
43 "login.serverLogout": "Your session expired, please login again.", 43 "login.serverLogout": "Your session expired, please login again.",
44 "login.submit.label": "Sign in", 44 "login.submit.label": "Sign in",
45 "login.tokenExpired": "Your session expired, please login again.", 45 "login.tokenExpired": "Your session expired, please login again.",
46 "menu.Todoss.closeTodosDrawer": "Close Todos drawer",
47 "menu.Todoss.openTodosDrawer": "Open Todos drawer",
46 "menu.app.about": "About Franz", 48 "menu.app.about": "About Franz",
47 "menu.app.announcement": "What's new?", 49 "menu.app.announcement": "What's new?",
48 "menu.app.checkForUpdates": "Check for updates", 50 "menu.app.checkForUpdates": "Check for updates",
@@ -79,6 +81,7 @@
79 "menu.services.activatePreviousService": "Activate previous service", 81 "menu.services.activatePreviousService": "Activate previous service",
80 "menu.services.addNewService": "Add New Service...", 82 "menu.services.addNewService": "Add New Service...",
81 "menu.services.setNextServiceActive": "Activate next service", 83 "menu.services.setNextServiceActive": "Activate next service",
84 "menu.todos": "Todos",
82 "menu.view": "View", 85 "menu.view": "View",
83 "menu.view.enterFullScreen": "Enter Full Screen", 86 "menu.view.enterFullScreen": "Enter Full Screen",
84 "menu.view.exitFullScreen": "Exit Full Screen", 87 "menu.view.exitFullScreen": "Exit Full Screen",
@@ -88,6 +91,7 @@
88 "menu.view.toggleDevTools": "Toggle Developer Tools", 91 "menu.view.toggleDevTools": "Toggle Developer Tools",
89 "menu.view.toggleFullScreen": "Toggle Full Screen", 92 "menu.view.toggleFullScreen": "Toggle Full Screen",
90 "menu.view.toggleServiceDevTools": "Toggle Service Developer Tools", 93 "menu.view.toggleServiceDevTools": "Toggle Service Developer Tools",
94 "menu.view.toggleTodosDevTools": "!!!Toggle Todos Developer Tools",
91 "menu.view.zoomIn": "Zoom In", 95 "menu.view.zoomIn": "Zoom In",
92 "menu.view.zoomOut": "Zoom Out", 96 "menu.view.zoomOut": "Zoom Out",
93 "menu.window": "Window", 97 "menu.window": "Window",
@@ -332,4 +336,4 @@
332 "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>", 336 "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>",
333 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", 337 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
334 "workspaces.switchingIndicator.switchingTo": "Switching to" 338 "workspaces.switchingIndicator.switchingTo": "Switching to"
335} 339} \ No newline at end of file
diff --git a/src/i18n/messages/src/components/layout/AppLayout.json b/src/i18n/messages/src/components/layout/AppLayout.json
index 190c5dff7..b71889155 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": 26, 7 "line": 27,
8 "column": 19 8 "column": 19
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 29, 11 "line": 30,
12 "column": 3 12 "column": 3
13 } 13 }
14 }, 14 },
@@ -17,11 +17,11 @@
17 "defaultMessage": "!!!Reload services", 17 "defaultMessage": "!!!Reload services",
18 "file": "src/components/layout/AppLayout.js", 18 "file": "src/components/layout/AppLayout.js",
19 "start": { 19 "start": {
20 "line": 30, 20 "line": 31,
21 "column": 24 21 "column": 24
22 }, 22 },
23 "end": { 23 "end": {
24 "line": 33, 24 "line": 34,
25 "column": 3 25 "column": 3
26 } 26 }
27 }, 27 },
@@ -30,11 +30,11 @@
30 "defaultMessage": "!!!Could not load services and user information", 30 "defaultMessage": "!!!Could not load services and user information",
31 "file": "src/components/layout/AppLayout.js", 31 "file": "src/components/layout/AppLayout.js",
32 "start": { 32 "start": {
33 "line": 34, 33 "line": 35,
34 "column": 26 34 "column": 26
35 }, 35 },
36 "end": { 36 "end": {
37 "line": 37, 37 "line": 38,
38 "column": 3 38 "column": 3
39 } 39 }
40 } 40 }
diff --git a/src/i18n/messages/src/lib/Menu.json b/src/i18n/messages/src/lib/Menu.json
index 6f878cbd1..cee46608c 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": 15, 7 "line": 18,
8 "column": 8 8 "column": 8
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 18, 11 "line": 21,
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": 19, 20 "line": 22,
21 "column": 8 21 "column": 8
22 }, 22 },
23 "end": { 23 "end": {
24 "line": 22, 24 "line": 25,
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": 23, 33 "line": 26,
34 "column": 8 34 "column": 8
35 }, 35 },
36 "end": { 36 "end": {
37 "line": 26, 37 "line": 29,
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": 27, 46 "line": 30,
47 "column": 7 47 "column": 7
48 }, 48 },
49 "end": { 49 "end": {
50 "line": 30, 50 "line": 33,
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": 31, 59 "line": 34,
60 "column": 8 60 "column": 8
61 }, 61 },
62 "end": { 62 "end": {
63 "line": 34, 63 "line": 37,
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": 35, 72 "line": 38,
73 "column": 9 73 "column": 9
74 }, 74 },
75 "end": { 75 "end": {
76 "line": 38, 76 "line": 41,
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": 39, 85 "line": 42,
86 "column": 22 86 "column": 22
87 }, 87 },
88 "end": { 88 "end": {
89 "line": 42, 89 "line": 45,
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": 43, 98 "line": 46,
99 "column": 10 99 "column": 10
100 }, 100 },
101 "end": { 101 "end": {
102 "line": 46, 102 "line": 49,
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": 47, 111 "line": 50,
112 "column": 13 112 "column": 13
113 }, 113 },
114 "end": { 114 "end": {
115 "line": 50, 115 "line": 53,
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": 51, 124 "line": 54,
125 "column": 10 125 "column": 10
126 }, 126 },
127 "end": { 127 "end": {
128 "line": 54, 128 "line": 57,
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": 55, 137 "line": 58,
138 "column": 17 138 "column": 17
139 }, 139 },
140 "end": { 140 "end": {
141 "line": 58, 141 "line": 61,
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": 59, 150 "line": 62,
151 "column": 16 151 "column": 16
152 }, 152 },
153 "end": { 153 "end": {
154 "line": 62, 154 "line": 65,
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": 63, 163 "line": 66,
164 "column": 18 164 "column": 18
165 }, 165 },
166 "end": { 166 "end": {
167 "line": 66, 167 "line": 69,
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": 67, 176 "line": 70,
177 "column": 16 177 "column": 16
178 }, 178 },
179 "end": { 179 "end": {
180 "line": 70, 180 "line": 73,
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": 71, 189 "line": 74,
190 "column": 13 190 "column": 13
191 }, 191 },
192 "end": { 192 "end": {
193 "line": 74, 193 "line": 77,
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": 75, 202 "line": 78,
203 "column": 10 203 "column": 10
204 }, 204 },
205 "end": { 205 "end": {
206 "line": 78, 206 "line": 81,
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": 79, 215 "line": 82,
216 "column": 11 216 "column": 11
217 }, 217 },
218 "end": { 218 "end": {
219 "line": 82, 219 "line": 85,
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": 83, 228 "line": 86,
229 "column": 19 229 "column": 19
230 }, 230 },
231 "end": { 231 "end": {
232 "line": 86, 232 "line": 89,
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": 87, 241 "line": 90,
242 "column": 18 242 "column": 18
243 }, 243 },
244 "end": { 244 "end": {
245 "line": 90, 245 "line": 93,
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": 91, 254 "line": 94,
255 "column": 20 255 "column": 20
256 }, 256 },
257 "end": { 257 "end": {
258 "line": 94, 258 "line": 97,
259 "column": 3 259 "column": 3
260 } 260 }
261 }, 261 },
@@ -264,11 +264,24 @@
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": 95, 267 "line": 98,
268 "column": 18 268 "column": 18
269 }, 269 },
270 "end": { 270 "end": {
271 "line": 98, 271 "line": 101,
272 "column": 3
273 }
274 },
275 {
276 "id": "menu.view.toggleTodosDevTools",
277 "defaultMessage": "!!!Toggle Todos Developer Tools",
278 "file": "src/lib/Menu.js",
279 "start": {
280 "line": 102,
281 "column": 23
282 },
283 "end": {
284 "line": 105,
272 "column": 3 285 "column": 3
273 } 286 }
274 }, 287 },
@@ -277,11 +290,11 @@
277 "defaultMessage": "!!!Toggle Service Developer Tools", 290 "defaultMessage": "!!!Toggle Service Developer Tools",
278 "file": "src/lib/Menu.js", 291 "file": "src/lib/Menu.js",
279 "start": { 292 "start": {
280 "line": 99, 293 "line": 106,
281 "column": 25 294 "column": 25
282 }, 295 },
283 "end": { 296 "end": {
284 "line": 102, 297 "line": 109,
285 "column": 3 298 "column": 3
286 } 299 }
287 }, 300 },
@@ -290,11 +303,11 @@
290 "defaultMessage": "!!!Reload Service", 303 "defaultMessage": "!!!Reload Service",
291 "file": "src/lib/Menu.js", 304 "file": "src/lib/Menu.js",
292 "start": { 305 "start": {
293 "line": 103, 306 "line": 110,
294 "column": 17 307 "column": 17
295 }, 308 },
296 "end": { 309 "end": {
297 "line": 106, 310 "line": 113,
298 "column": 3 311 "column": 3
299 } 312 }
300 }, 313 },
@@ -303,11 +316,11 @@
303 "defaultMessage": "!!!Reload Franz", 316 "defaultMessage": "!!!Reload Franz",
304 "file": "src/lib/Menu.js", 317 "file": "src/lib/Menu.js",
305 "start": { 318 "start": {
306 "line": 107, 319 "line": 114,
307 "column": 15 320 "column": 15
308 }, 321 },
309 "end": { 322 "end": {
310 "line": 110, 323 "line": 117,
311 "column": 3 324 "column": 3
312 } 325 }
313 }, 326 },
@@ -316,11 +329,11 @@
316 "defaultMessage": "!!!Minimize", 329 "defaultMessage": "!!!Minimize",
317 "file": "src/lib/Menu.js", 330 "file": "src/lib/Menu.js",
318 "start": { 331 "start": {
319 "line": 111, 332 "line": 118,
320 "column": 12 333 "column": 12
321 }, 334 },
322 "end": { 335 "end": {
323 "line": 114, 336 "line": 121,
324 "column": 3 337 "column": 3
325 } 338 }
326 }, 339 },
@@ -329,11 +342,11 @@
329 "defaultMessage": "!!!Close", 342 "defaultMessage": "!!!Close",
330 "file": "src/lib/Menu.js", 343 "file": "src/lib/Menu.js",
331 "start": { 344 "start": {
332 "line": 115, 345 "line": 122,
333 "column": 9 346 "column": 9
334 }, 347 },
335 "end": { 348 "end": {
336 "line": 118, 349 "line": 125,
337 "column": 3 350 "column": 3
338 } 351 }
339 }, 352 },
@@ -342,11 +355,11 @@
342 "defaultMessage": "!!!Learn More", 355 "defaultMessage": "!!!Learn More",
343 "file": "src/lib/Menu.js", 356 "file": "src/lib/Menu.js",
344 "start": { 357 "start": {
345 "line": 119, 358 "line": 126,
346 "column": 13 359 "column": 13
347 }, 360 },
348 "end": { 361 "end": {
349 "line": 122, 362 "line": 129,
350 "column": 3 363 "column": 3
351 } 364 }
352 }, 365 },
@@ -355,11 +368,11 @@
355 "defaultMessage": "!!!Changelog", 368 "defaultMessage": "!!!Changelog",
356 "file": "src/lib/Menu.js", 369 "file": "src/lib/Menu.js",
357 "start": { 370 "start": {
358 "line": 123, 371 "line": 130,
359 "column": 13 372 "column": 13
360 }, 373 },
361 "end": { 374 "end": {
362 "line": 126, 375 "line": 133,
363 "column": 3 376 "column": 3
364 } 377 }
365 }, 378 },
@@ -368,11 +381,11 @@
368 "defaultMessage": "!!!Support", 381 "defaultMessage": "!!!Support",
369 "file": "src/lib/Menu.js", 382 "file": "src/lib/Menu.js",
370 "start": { 383 "start": {
371 "line": 127, 384 "line": 134,
372 "column": 11 385 "column": 11
373 }, 386 },
374 "end": { 387 "end": {
375 "line": 130, 388 "line": 137,
376 "column": 3 389 "column": 3
377 } 390 }
378 }, 391 },
@@ -381,11 +394,11 @@
381 "defaultMessage": "!!!Copy Debug Information", 394 "defaultMessage": "!!!Copy Debug Information",
382 "file": "src/lib/Menu.js", 395 "file": "src/lib/Menu.js",
383 "start": { 396 "start": {
384 "line": 131, 397 "line": 138,
385 "column": 13 398 "column": 13
386 }, 399 },
387 "end": { 400 "end": {
388 "line": 134, 401 "line": 141,
389 "column": 3 402 "column": 3
390 } 403 }
391 }, 404 },
@@ -394,11 +407,11 @@
394 "defaultMessage": "!!!Franz Debug Information", 407 "defaultMessage": "!!!Franz Debug Information",
395 "file": "src/lib/Menu.js", 408 "file": "src/lib/Menu.js",
396 "start": { 409 "start": {
397 "line": 135, 410 "line": 142,
398 "column": 27 411 "column": 27
399 }, 412 },
400 "end": { 413 "end": {
401 "line": 138, 414 "line": 145,
402 "column": 3 415 "column": 3
403 } 416 }
404 }, 417 },
@@ -407,11 +420,11 @@
407 "defaultMessage": "!!!Your Debug Information has been copied to your clipboard.", 420 "defaultMessage": "!!!Your Debug Information has been copied to your clipboard.",
408 "file": "src/lib/Menu.js", 421 "file": "src/lib/Menu.js",
409 "start": { 422 "start": {
410 "line": 139, 423 "line": 146,
411 "column": 23 424 "column": 23
412 }, 425 },
413 "end": { 426 "end": {
414 "line": 142, 427 "line": 149,
415 "column": 3 428 "column": 3
416 } 429 }
417 }, 430 },
@@ -420,11 +433,11 @@
420 "defaultMessage": "!!!Terms of Service", 433 "defaultMessage": "!!!Terms of Service",
421 "file": "src/lib/Menu.js", 434 "file": "src/lib/Menu.js",
422 "start": { 435 "start": {
423 "line": 143, 436 "line": 150,
424 "column": 7 437 "column": 7
425 }, 438 },
426 "end": { 439 "end": {
427 "line": 146, 440 "line": 153,
428 "column": 3 441 "column": 3
429 } 442 }
430 }, 443 },
@@ -433,11 +446,11 @@
433 "defaultMessage": "!!!Privacy Statement", 446 "defaultMessage": "!!!Privacy Statement",
434 "file": "src/lib/Menu.js", 447 "file": "src/lib/Menu.js",
435 "start": { 448 "start": {
436 "line": 147, 449 "line": 154,
437 "column": 11 450 "column": 11
438 }, 451 },
439 "end": { 452 "end": {
440 "line": 150, 453 "line": 157,
441 "column": 3 454 "column": 3
442 } 455 }
443 }, 456 },
@@ -446,11 +459,11 @@
446 "defaultMessage": "!!!File", 459 "defaultMessage": "!!!File",
447 "file": "src/lib/Menu.js", 460 "file": "src/lib/Menu.js",
448 "start": { 461 "start": {
449 "line": 151, 462 "line": 158,
450 "column": 8 463 "column": 8
451 }, 464 },
452 "end": { 465 "end": {
453 "line": 154, 466 "line": 161,
454 "column": 3 467 "column": 3
455 } 468 }
456 }, 469 },
@@ -459,11 +472,11 @@
459 "defaultMessage": "!!!View", 472 "defaultMessage": "!!!View",
460 "file": "src/lib/Menu.js", 473 "file": "src/lib/Menu.js",
461 "start": { 474 "start": {
462 "line": 155, 475 "line": 162,
463 "column": 8 476 "column": 8
464 }, 477 },
465 "end": { 478 "end": {
466 "line": 158, 479 "line": 165,
467 "column": 3 480 "column": 3
468 } 481 }
469 }, 482 },
@@ -472,11 +485,11 @@
472 "defaultMessage": "!!!Services", 485 "defaultMessage": "!!!Services",
473 "file": "src/lib/Menu.js", 486 "file": "src/lib/Menu.js",
474 "start": { 487 "start": {
475 "line": 159, 488 "line": 166,
476 "column": 12 489 "column": 12
477 }, 490 },
478 "end": { 491 "end": {
479 "line": 162, 492 "line": 169,
480 "column": 3 493 "column": 3
481 } 494 }
482 }, 495 },
@@ -485,11 +498,11 @@
485 "defaultMessage": "!!!Window", 498 "defaultMessage": "!!!Window",
486 "file": "src/lib/Menu.js", 499 "file": "src/lib/Menu.js",
487 "start": { 500 "start": {
488 "line": 163, 501 "line": 170,
489 "column": 10 502 "column": 10
490 }, 503 },
491 "end": { 504 "end": {
492 "line": 166, 505 "line": 173,
493 "column": 3 506 "column": 3
494 } 507 }
495 }, 508 },
@@ -498,11 +511,11 @@
498 "defaultMessage": "!!!Help", 511 "defaultMessage": "!!!Help",
499 "file": "src/lib/Menu.js", 512 "file": "src/lib/Menu.js",
500 "start": { 513 "start": {
501 "line": 167, 514 "line": 174,
502 "column": 8 515 "column": 8
503 }, 516 },
504 "end": { 517 "end": {
505 "line": 170, 518 "line": 177,
506 "column": 3 519 "column": 3
507 } 520 }
508 }, 521 },
@@ -511,11 +524,11 @@
511 "defaultMessage": "!!!About Franz", 524 "defaultMessage": "!!!About Franz",
512 "file": "src/lib/Menu.js", 525 "file": "src/lib/Menu.js",
513 "start": { 526 "start": {
514 "line": 171, 527 "line": 178,
515 "column": 9 528 "column": 9
516 }, 529 },
517 "end": { 530 "end": {
518 "line": 174, 531 "line": 181,
519 "column": 3 532 "column": 3
520 } 533 }
521 }, 534 },
@@ -524,11 +537,11 @@
524 "defaultMessage": "!!!What's new?", 537 "defaultMessage": "!!!What's new?",
525 "file": "src/lib/Menu.js", 538 "file": "src/lib/Menu.js",
526 "start": { 539 "start": {
527 "line": 175, 540 "line": 182,
528 "column": 16 541 "column": 16
529 }, 542 },
530 "end": { 543 "end": {
531 "line": 178, 544 "line": 185,
532 "column": 3 545 "column": 3
533 } 546 }
534 }, 547 },
@@ -537,11 +550,11 @@
537 "defaultMessage": "!!!Settings", 550 "defaultMessage": "!!!Settings",
538 "file": "src/lib/Menu.js", 551 "file": "src/lib/Menu.js",
539 "start": { 552 "start": {
540 "line": 179, 553 "line": 186,
541 "column": 12 554 "column": 12
542 }, 555 },
543 "end": { 556 "end": {
544 "line": 182, 557 "line": 189,
545 "column": 3 558 "column": 3
546 } 559 }
547 }, 560 },
@@ -550,11 +563,11 @@
550 "defaultMessage": "!!!Check for updates", 563 "defaultMessage": "!!!Check for updates",
551 "file": "src/lib/Menu.js", 564 "file": "src/lib/Menu.js",
552 "start": { 565 "start": {
553 "line": 183, 566 "line": 190,
554 "column": 19 567 "column": 19
555 }, 568 },
556 "end": { 569 "end": {
557 "line": 186, 570 "line": 193,
558 "column": 3 571 "column": 3
559 } 572 }
560 }, 573 },
@@ -563,11 +576,11 @@
563 "defaultMessage": "!!!Hide", 576 "defaultMessage": "!!!Hide",
564 "file": "src/lib/Menu.js", 577 "file": "src/lib/Menu.js",
565 "start": { 578 "start": {
566 "line": 187, 579 "line": 194,
567 "column": 8 580 "column": 8
568 }, 581 },
569 "end": { 582 "end": {
570 "line": 190, 583 "line": 197,
571 "column": 3 584 "column": 3
572 } 585 }
573 }, 586 },
@@ -576,11 +589,11 @@
576 "defaultMessage": "!!!Hide Others", 589 "defaultMessage": "!!!Hide Others",
577 "file": "src/lib/Menu.js", 590 "file": "src/lib/Menu.js",
578 "start": { 591 "start": {
579 "line": 191, 592 "line": 198,
580 "column": 14 593 "column": 14
581 }, 594 },
582 "end": { 595 "end": {
583 "line": 194, 596 "line": 201,
584 "column": 3 597 "column": 3
585 } 598 }
586 }, 599 },
@@ -589,11 +602,11 @@
589 "defaultMessage": "!!!Unhide", 602 "defaultMessage": "!!!Unhide",
590 "file": "src/lib/Menu.js", 603 "file": "src/lib/Menu.js",
591 "start": { 604 "start": {
592 "line": 195, 605 "line": 202,
593 "column": 10 606 "column": 10
594 }, 607 },
595 "end": { 608 "end": {
596 "line": 198, 609 "line": 205,
597 "column": 3 610 "column": 3
598 } 611 }
599 }, 612 },
@@ -602,11 +615,11 @@
602 "defaultMessage": "!!!Quit", 615 "defaultMessage": "!!!Quit",
603 "file": "src/lib/Menu.js", 616 "file": "src/lib/Menu.js",
604 "start": { 617 "start": {
605 "line": 199, 618 "line": 206,
606 "column": 8 619 "column": 8
607 }, 620 },
608 "end": { 621 "end": {
609 "line": 202, 622 "line": 209,
610 "column": 3 623 "column": 3
611 } 624 }
612 }, 625 },
@@ -615,11 +628,11 @@
615 "defaultMessage": "!!!Add New Service...", 628 "defaultMessage": "!!!Add New Service...",
616 "file": "src/lib/Menu.js", 629 "file": "src/lib/Menu.js",
617 "start": { 630 "start": {
618 "line": 203, 631 "line": 210,
619 "column": 17 632 "column": 17
620 }, 633 },
621 "end": { 634 "end": {
622 "line": 206, 635 "line": 213,
623 "column": 3 636 "column": 3
624 } 637 }
625 }, 638 },
@@ -628,11 +641,11 @@
628 "defaultMessage": "!!!Add New Workspace...", 641 "defaultMessage": "!!!Add New Workspace...",
629 "file": "src/lib/Menu.js", 642 "file": "src/lib/Menu.js",
630 "start": { 643 "start": {
631 "line": 207, 644 "line": 214,
632 "column": 19 645 "column": 19
633 }, 646 },
634 "end": { 647 "end": {
635 "line": 210, 648 "line": 217,
636 "column": 3 649 "column": 3
637 } 650 }
638 }, 651 },
@@ -641,11 +654,11 @@
641 "defaultMessage": "!!!Open workspace drawer", 654 "defaultMessage": "!!!Open workspace drawer",
642 "file": "src/lib/Menu.js", 655 "file": "src/lib/Menu.js",
643 "start": { 656 "start": {
644 "line": 211, 657 "line": 218,
645 "column": 23 658 "column": 23
646 }, 659 },
647 "end": { 660 "end": {
648 "line": 214, 661 "line": 221,
649 "column": 3 662 "column": 3
650 } 663 }
651 }, 664 },
@@ -654,11 +667,11 @@
654 "defaultMessage": "!!!Close workspace drawer", 667 "defaultMessage": "!!!Close workspace drawer",
655 "file": "src/lib/Menu.js", 668 "file": "src/lib/Menu.js",
656 "start": { 669 "start": {
657 "line": 215, 670 "line": 222,
658 "column": 24 671 "column": 24
659 }, 672 },
660 "end": { 673 "end": {
661 "line": 218, 674 "line": 225,
662 "column": 3 675 "column": 3
663 } 676 }
664 }, 677 },
@@ -667,11 +680,11 @@
667 "defaultMessage": "!!!Activate next service...", 680 "defaultMessage": "!!!Activate next service...",
668 "file": "src/lib/Menu.js", 681 "file": "src/lib/Menu.js",
669 "start": { 682 "start": {
670 "line": 219, 683 "line": 226,
671 "column": 23 684 "column": 23
672 }, 685 },
673 "end": { 686 "end": {
674 "line": 222, 687 "line": 229,
675 "column": 3 688 "column": 3
676 } 689 }
677 }, 690 },
@@ -680,11 +693,11 @@
680 "defaultMessage": "!!!Activate previous service...", 693 "defaultMessage": "!!!Activate previous service...",
681 "file": "src/lib/Menu.js", 694 "file": "src/lib/Menu.js",
682 "start": { 695 "start": {
683 "line": 223, 696 "line": 230,
684 "column": 27 697 "column": 27
685 }, 698 },
686 "end": { 699 "end": {
687 "line": 226, 700 "line": 233,
688 "column": 3 701 "column": 3
689 } 702 }
690 }, 703 },
@@ -693,11 +706,11 @@
693 "defaultMessage": "!!!Disable notifications & audio", 706 "defaultMessage": "!!!Disable notifications & audio",
694 "file": "src/lib/Menu.js", 707 "file": "src/lib/Menu.js",
695 "start": { 708 "start": {
696 "line": 227, 709 "line": 234,
697 "column": 11 710 "column": 11
698 }, 711 },
699 "end": { 712 "end": {
700 "line": 230, 713 "line": 237,
701 "column": 3 714 "column": 3
702 } 715 }
703 }, 716 },
@@ -706,11 +719,11 @@
706 "defaultMessage": "!!!Enable notifications & audio", 719 "defaultMessage": "!!!Enable notifications & audio",
707 "file": "src/lib/Menu.js", 720 "file": "src/lib/Menu.js",
708 "start": { 721 "start": {
709 "line": 231, 722 "line": 238,
710 "column": 13 723 "column": 13
711 }, 724 },
712 "end": { 725 "end": {
713 "line": 234, 726 "line": 241,
714 "column": 3 727 "column": 3
715 } 728 }
716 }, 729 },
@@ -719,11 +732,11 @@
719 "defaultMessage": "!!!Workspaces", 732 "defaultMessage": "!!!Workspaces",
720 "file": "src/lib/Menu.js", 733 "file": "src/lib/Menu.js",
721 "start": { 734 "start": {
722 "line": 235, 735 "line": 242,
723 "column": 14 736 "column": 14
724 }, 737 },
725 "end": { 738 "end": {
726 "line": 238, 739 "line": 245,
727 "column": 3 740 "column": 3
728 } 741 }
729 }, 742 },
@@ -732,11 +745,50 @@
732 "defaultMessage": "!!!Default", 745 "defaultMessage": "!!!Default",
733 "file": "src/lib/Menu.js", 746 "file": "src/lib/Menu.js",
734 "start": { 747 "start": {
735 "line": 239, 748 "line": 246,
736 "column": 20 749 "column": 20
737 }, 750 },
738 "end": { 751 "end": {
739 "line": 242, 752 "line": 249,
753 "column": 3
754 }
755 },
756 {
757 "id": "menu.todos",
758 "defaultMessage": "!!!Todos",
759 "file": "src/lib/Menu.js",
760 "start": {
761 "line": 250,
762 "column": 9
763 },
764 "end": {
765 "line": 253,
766 "column": 3
767 }
768 },
769 {
770 "id": "menu.Todoss.openTodosDrawer",
771 "defaultMessage": "!!!Open Todos drawer",
772 "file": "src/lib/Menu.js",
773 "start": {
774 "line": 254,
775 "column": 19
776 },
777 "end": {
778 "line": 257,
779 "column": 3
780 }
781 },
782 {
783 "id": "menu.Todoss.closeTodosDrawer",
784 "defaultMessage": "!!!Close Todos drawer",
785 "file": "src/lib/Menu.js",
786 "start": {
787 "line": 258,
788 "column": 20
789 },
790 "end": {
791 "line": 261,
740 "column": 3 792 "column": 3
741 } 793 }
742 } 794 }
diff --git a/src/index.html b/src/index.html
index f29aa2686..198c1ab7b 100644
--- a/src/index.html
+++ b/src/index.html
@@ -35,11 +35,16 @@
35 const originalReloadBehaviour = window._onLiveReloadFileChanged; 35 const originalReloadBehaviour = window._onLiveReloadFileChanged;
36 36
37 window._onLiveReloadFileChanged = (file) => { 37 window._onLiveReloadFileChanged = (file) => {
38 if (!file.path.includes('/build/webview/') && !file.path.includes('/build/index.js') && !file.path.includes('/build/electron/')) { 38 const isTodoPreloadPath = file.path.includes('/build/features/todos/preload.js');
39 if (!file.path.includes('/build/webview/') && !file.path.includes('/build/index.js') && !file.path.includes('/build/electron/') && !isTodoPreloadPath) {
39 originalReloadBehaviour(file); 40 originalReloadBehaviour(file);
40 } else { 41 } else {
41 if (file.path.includes('/build/webview/')) { 42 if (isTodoPreloadPath) {
42 debug('Livereload: Reloading all webvies'); 43 debug('Livereload: Reloading all webviews');
44 const webview = document.querySelector('webview[partition="persist:todos"]');
45 if (webview) webview.reload();
46 } else if (file.path.includes('/build/webview/')) {
47 debug('Livereload: Reloading all webviews');
43 const webviews = document.querySelectorAll('webview').forEach(webview => webview.reload()); 48 const webviews = document.querySelectorAll('webview').forEach(webview => webview.reload());
44 } else { 49 } else {
45 debug('Livereload: skip reload as only main process files have changed'); 50 debug('Livereload: skip reload as only main process files have changed');
diff --git a/src/lib/Menu.js b/src/lib/Menu.js
index 22d788918..81efaf18f 100644
--- a/src/lib/Menu.js
+++ b/src/lib/Menu.js
@@ -8,6 +8,9 @@ import { workspaceActions } from '../features/workspaces/actions';
8import { gaEvent } from './analytics'; 8import { gaEvent } from './analytics';
9import { announcementActions } from '../features/announcements/actions'; 9import { announcementActions } from '../features/announcements/actions';
10import { announcementsStore } from '../features/announcements'; 10import { announcementsStore } from '../features/announcements';
11import TodoStore from '../features/todos/store';
12import { GA_CATEGORY_TODOS, todosStore } from '../features/todos';
13import { todoActions } from '../features/todos/actions';
11 14
12const { app, Menu, dialog } = remote; 15const { app, Menu, dialog } = remote;
13 16
@@ -96,6 +99,10 @@ const menuItems = defineMessages({
96 id: 'menu.view.toggleDevTools', 99 id: 'menu.view.toggleDevTools',
97 defaultMessage: '!!!Toggle Developer Tools', 100 defaultMessage: '!!!Toggle Developer Tools',
98 }, 101 },
102 toggleTodosDevTools: {
103 id: 'menu.view.toggleTodosDevTools',
104 defaultMessage: '!!!Toggle Todos Developer Tools',
105 },
99 toggleServiceDevTools: { 106 toggleServiceDevTools: {
100 id: 'menu.view.toggleServiceDevTools', 107 id: 'menu.view.toggleServiceDevTools',
101 defaultMessage: '!!!Toggle Service Developer Tools', 108 defaultMessage: '!!!Toggle Service Developer Tools',
@@ -240,6 +247,18 @@ const menuItems = defineMessages({
240 id: 'menu.workspaces.defaultWorkspace', 247 id: 'menu.workspaces.defaultWorkspace',
241 defaultMessage: '!!!Default', 248 defaultMessage: '!!!Default',
242 }, 249 },
250 todos: {
251 id: 'menu.todos',
252 defaultMessage: '!!!Todos',
253 },
254 openTodosDrawer: {
255 id: 'menu.Todoss.openTodosDrawer',
256 defaultMessage: '!!!Open Todos drawer',
257 },
258 closeTodosDrawer: {
259 id: 'menu.Todoss.closeTodosDrawer',
260 defaultMessage: '!!!Close Todos drawer',
261 },
243}); 262});
244 263
245function getActiveWebview() { 264function getActiveWebview() {
@@ -348,6 +367,11 @@ const _templateFactory = intl => [
348 visible: workspaceStore.isFeatureEnabled, 367 visible: workspaceStore.isFeatureEnabled,
349 }, 368 },
350 { 369 {
370 label: intl.formatMessage(menuItems.todos),
371 submenu: [],
372 visible: todosStore.isFeatureEnabled,
373 },
374 {
351 label: intl.formatMessage(menuItems.window), 375 label: intl.formatMessage(menuItems.window),
352 role: 'window', 376 role: 'window',
353 submenu: [ 377 submenu: [
@@ -620,6 +644,17 @@ export default class FranzMenu {
620 enabled: this.stores.user.isLoggedIn && this.stores.services.enabled.length > 0, 644 enabled: this.stores.user.isLoggedIn && this.stores.services.enabled.length > 0,
621 }); 645 });
622 646
647 if (this.stores.features.features.isTodosEnabled) {
648 tpl[1].submenu.push({
649 label: intl.formatMessage(menuItems.toggleTodosDevTools),
650 accelerator: `${cmdKey}+Shift+Alt+O`,
651 click: () => {
652 const webview = document.querySelector('webview[partition="persist:todos"]');
653 if (webview) webview.openDevTools();
654 },
655 });
656 }
657
623 tpl[1].submenu.unshift({ 658 tpl[1].submenu.unshift({
624 label: intl.formatMessage(menuItems.reloadService), 659 label: intl.formatMessage(menuItems.reloadService),
625 id: 'reloadService', // TODO: needed? 660 id: 'reloadService', // TODO: needed?
@@ -772,6 +807,10 @@ export default class FranzMenu {
772 tpl[4].submenu = this.workspacesMenu(); 807 tpl[4].submenu = this.workspacesMenu();
773 } 808 }
774 809
810 if (todosStore.isFeatureEnabled) {
811 tpl[5].submenu = this.todosMenu();
812 }
813
775 tpl[tpl.length - 1].submenu.push({ 814 tpl[tpl.length - 1].submenu.push({
776 type: 'separator', 815 type: 'separator',
777 }, this.debugMenu()); 816 }, this.debugMenu());
@@ -886,6 +925,31 @@ export default class FranzMenu {
886 return menu; 925 return menu;
887 } 926 }
888 927
928 todosMenu() {
929 const { isTodosPanelVisible } = TodoStore;
930 const { intl } = window.franz;
931 const menu = [];
932
933 // Open todos drawer:
934 const drawerLabel = (
935 isTodosPanelVisible ? menuItems.closeTodosDrawer : menuItems.openTodosDrawer
936 );
937 menu.push({
938 label: intl.formatMessage(drawerLabel),
939 accelerator: `${cmdKey}+T`,
940 click: () => {
941 todoActions.toggleTodosPanel();
942 gaEvent(GA_CATEGORY_TODOS, 'toggleDrawer', 'menu');
943 },
944 enabled: this.stores.user.isLoggedIn,
945 }, {
946 type: 'separator',
947 });
948
949 return menu;
950 }
951
952
889 debugMenu() { 953 debugMenu() {
890 const { intl } = window.franz; 954 const { intl } = window.franz;
891 955
diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js
index e7832088b..35a050c67 100644
--- a/src/stores/FeaturesStore.js
+++ b/src/stores/FeaturesStore.js
@@ -16,6 +16,7 @@ import workspaces from '../features/workspaces';
16import shareFranz from '../features/shareFranz'; 16import shareFranz from '../features/shareFranz';
17import announcements from '../features/announcements'; 17import announcements from '../features/announcements';
18import settingsWS from '../features/settingsWS'; 18import settingsWS from '../features/settingsWS';
19import todos from '../features/todos';
19 20
20import { DEFAULT_FEATURES_CONFIG } from '../config'; 21import { DEFAULT_FEATURES_CONFIG } from '../config';
21 22
@@ -75,5 +76,6 @@ export default class FeaturesStore extends Store {
75 shareFranz(this.stores, this.actions); 76 shareFranz(this.stores, this.actions);
76 announcements(this.stores, this.actions); 77 announcements(this.stores, this.actions);
77 settingsWS(this.stores, this.actions); 78 settingsWS(this.stores, this.actions);
79 todos(this.stores, this.actions);
78 } 80 }
79} 81}
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js
index 109ac5cd7..b13425249 100644
--- a/src/stores/ServicesStore.js
+++ b/src/stores/ServicesStore.js
@@ -440,6 +440,9 @@ export default class ServicesStore extends Store {
440 redirect: false, 440 redirect: false,
441 }); 441 });
442 } 442 }
443 } else if (channel === 'feature:todos') {
444 Object.assign(args[0].data, { serviceId });
445 this.actions.todos.handleHostMessage(args[0]);
443 } 446 }
444 } 447 }
445 448
diff --git a/src/stores/index.js b/src/stores/index.js
index 1912418a2..e9ef523f8 100644
--- a/src/stores/index.js
+++ b/src/stores/index.js
@@ -12,6 +12,7 @@ import RequestStore from './RequestStore';
12import GlobalErrorStore from './GlobalErrorStore'; 12import GlobalErrorStore from './GlobalErrorStore';
13import { workspaceStore } from '../features/workspaces'; 13import { workspaceStore } from '../features/workspaces';
14import { announcementsStore } from '../features/announcements'; 14import { announcementsStore } from '../features/announcements';
15import { todosStore } from '../features/todos';
15 16
16export default (api, actions, router) => { 17export default (api, actions, router) => {
17 const stores = {}; 18 const stores = {};
@@ -31,6 +32,7 @@ export default (api, actions, router) => {
31 globalError: new GlobalErrorStore(stores, api, actions), 32 globalError: new GlobalErrorStore(stores, api, actions),
32 workspaces: workspaceStore, 33 workspaces: workspaceStore,
33 announcements: announcementsStore, 34 announcements: announcementsStore,
35 todos: todosStore,
34 }); 36 });
35 // Initialize all stores 37 // Initialize all stores
36 Object.keys(stores).forEach((name) => { 38 Object.keys(stores).forEach((name) => {
diff --git a/src/styles/layout.scss b/src/styles/layout.scss
index 9f226b61c..10027da60 100644
--- a/src/styles/layout.scss
+++ b/src/styles/layout.scss
@@ -33,13 +33,19 @@ html { overflow: hidden; }
33} 33}
34 34
35.app { 35.app {
36 display: flex; 36 //display: flex;
37 flex-direction: column;
38 37
39 .app__content { display: flex; } 38 .app__content {
39 display: flex;
40 width: calc(100% + 300px);
41 }
42
43 .app__main-content {
44 display: flex;
45 width: 100%;
46 }
40 47
41 .app__service { 48 .app__service {
42 // position: relative;
43 display: flex; 49 display: flex;
44 flex: 1; 50 flex: 1;
45 flex-direction: column; 51 flex-direction: column;
diff --git a/src/webview/contextMenu.js b/src/webview/contextMenu.js
index a4a6ab899..663b1ebca 100644
--- a/src/webview/contextMenu.js
+++ b/src/webview/contextMenu.js
@@ -39,6 +39,23 @@ const buildMenuTpl = (props, suggestions, isSpellcheckEnabled, defaultSpellcheck
39 { 39 {
40 type: 'separator', 40 type: 'separator',
41 }, { 41 }, {
42 id: 'createTodo',
43 label: `Create todo: "${textSelection.length > 15 ? `${textSelection.slice(0, 15)}...` : textSelection}"`,
44 visible: hasText,
45 click() {
46 debug('Create todo from selected text', textSelection);
47 ipcRenderer.sendToHost('feature:todos', {
48 action: 'create:todo',
49 data: {
50 title: textSelection,
51 url: window.location.href,
52 },
53 });
54 },
55 },
56 {
57 type: 'separator',
58 }, {
42 id: 'lookup', 59 id: 'lookup',
43 label: `Look Up "${textSelection.length > 15 ? `${textSelection.slice(0, 15)}...` : textSelection}"`, 60 label: `Look Up "${textSelection.length > 15 ? `${textSelection.slice(0, 15)}...` : textSelection}"`,
44 visible: isMac && props.mediaType === 'none' && hasText, 61 visible: isMac && props.mediaType === 'none' && hasText,