aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.eslintrc3
-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.js5
-rw-r--r--src/config.js4
-rw-r--r--src/environment.js24
-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.json280
-rw-r--r--src/i18n/locales/en-US.json6
-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
24 files changed, 1001 insertions, 248 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/packages/theme/src/themes/dark/index.ts b/packages/theme/src/themes/dark/index.ts
index 1ea46cd1a..93c18efde 100644
--- a/packages/theme/src/themes/dark/index.ts
+++ b/packages/theme/src/themes/dark/index.ts
@@ -128,3 +128,18 @@ export const signup = merge({}, defaultStyles.signup, {
128 }, 128 },
129 }, 129 },
130}); 130});
131
132// Todos
133export const todos = merge({}, defaultStyles.todos, {
134 todosLayer: {
135 borderLeftColor: legacyStyles.darkThemeGrayDarker,
136 },
137 toggleButton: {
138 background: defaultStyles.styleTypes.primary.accent,
139 textColor: defaultStyles.styleTypes.primary.contrast,
140 shadowColor: 'rgba(0, 0, 0, 0.2)',
141 },
142 dragIndicator: {
143 background: legacyStyles.themeGrayLight,
144 },
145});
diff --git a/packages/theme/src/themes/default/index.ts b/packages/theme/src/themes/default/index.ts
index 0d99bc4be..7edf8331f 100644
--- a/packages/theme/src/themes/default/index.ts
+++ b/packages/theme/src/themes/default/index.ts
@@ -217,3 +217,21 @@ export const signup = {
217 }, 217 },
218 }, 218 },
219}; 219};
220
221// Todos
222export const todos = {
223 todosLayer: {
224 borderLeftColor: legacyStyles.themeGrayLighter,
225 },
226 toggleButton: {
227 background: styleTypes.primary.accent,
228 textColor: styleTypes.primary.contrast,
229 shadowColor: 'rgba(0, 0, 0, 0.2)',
230 },
231 dragIndicator: {
232 background: legacyStyles.themeGrayLight,
233 },
234 resizeHandler: {
235 backgroundHover: styleTypes.primary.accent,
236 },
237};
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 1976f5a50..941e60bfd 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -18,6 +18,7 @@ import WorkspaceSwitchingIndicator from '../../features/workspaces/components/Wo
18import { workspaceStore } from '../../features/workspaces'; 18import { workspaceStore } from '../../features/workspaces';
19import AppUpdateInfoBar from '../AppUpdateInfoBar'; 19import AppUpdateInfoBar from '../AppUpdateInfoBar';
20import TrialActivationInfoBar from '../TrialActivationInfoBar'; 20import TrialActivationInfoBar from '../TrialActivationInfoBar';
21import Todos from '../../features/todos/containers/TodosScreen';
21 22
22function createMarkup(HTMLString) { 23function createMarkup(HTMLString) {
23 return { __html: HTMLString }; 24 return { __html: HTMLString };
@@ -40,7 +41,8 @@ const messages = defineMessages({
40 41
41const styles = theme => ({ 42const styles = theme => ({
42 appContent: { 43 appContent: {
43 width: `calc(100% + ${theme.workspaces.drawer.width}px)`, 44 // width: `calc(100% + ${theme.workspaces.drawer.width}px)`,
45 width: '100%',
44 transition: 'transform 0.5s ease', 46 transition: 'transform 0.5s ease',
45 transform() { 47 transform() {
46 return workspaceStore.isWorkspaceDrawerOpen ? 'translateX(0)' : `translateX(-${theme.workspaces.drawer.width}px)`; 48 return workspaceStore.isWorkspaceDrawerOpen ? 'translateX(0)' : `translateX(-${theme.workspaces.drawer.width}px)`;
@@ -164,6 +166,7 @@ class AppLayout extends Component {
164 {services} 166 {services}
165 {children} 167 {children}
166 </div> 168 </div>
169 <Todos />
167 </div> 170 </div>
168 </div> 171 </div>
169 </ErrorBoundary> 172 </ErrorBoundary>
diff --git a/src/config.js b/src/config.js
index c0b5fe954..405cc5253 100644
--- a/src/config.js
+++ b/src/config.js
@@ -25,6 +25,10 @@ export const LIVE_API_WEBSITE = 'https://meetfranz.com';
25 25
26export const STATS_API = 'https://stats.franzinfra.com'; 26export const STATS_API = 'https://stats.franzinfra.com';
27 27
28export const LOCAL_TODOS_FRONTEND_URL = 'http://localhost:4000';
29export const PRODUCTION_TODOS_FRONTEND_URL = 'https://app.franztodos.com';
30export const DEVELOPMENT_TODOS_FRONTEND_URL = 'https://development--franz-todos.netlify.com';
31
28export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12'; 32export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12';
29 33
30export const DEFAULT_APP_SETTINGS = { 34export const DEFAULT_APP_SETTINGS = {
diff --git a/src/environment.js b/src/environment.js
index 36d505eed..707449e09 100644
--- a/src/environment.js
+++ b/src/environment.js
@@ -1,15 +1,18 @@
1import isDev from 'electron-is-dev'; 1import isDev from 'electron-is-dev';
2 2
3import { 3import {
4 // LIVE_API, 4 LIVE_API,
5 DEV_API, 5 DEV_API,
6 LOCAL_API, 6 LOCAL_API,
7 LOCAL_API_WEBSITE, 7 LOCAL_API_WEBSITE,
8 DEV_API_WEBSITE, 8 DEV_API_WEBSITE,
9 // LIVE_API_WEBSITE, 9 LIVE_API_WEBSITE,
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,25 +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;
38 // TODO: switch back to live API 42 todos = PRODUCTION_TODOS_FRONTEND_URL;
39 api = DEV_API;
40 wsApi = DEV_WS_API;
41 web = DEV_API_WEBSITE;
42} else if (isDevMode && useLocalAPI) { 43} else if (isDevMode && useLocalAPI) {
43 api = LOCAL_API; 44 api = LOCAL_API;
44 wsApi = LOCAL_WS_API; 45 wsApi = LOCAL_WS_API;
45 web = LOCAL_API_WEBSITE; 46 web = LOCAL_API_WEBSITE;
47 todos = LOCAL_TODOS_FRONTEND_URL;
46} else { 48} else {
47 api = DEV_API; 49 api = DEV_API;
48 wsApi = DEV_WS_API; 50 wsApi = DEV_WS_API;
49 web = DEV_API_WEBSITE; 51 web = DEV_API_WEBSITE;
52 todos = DEVELOPMENT_TODOS_FRONTEND_URL;
50} 53}
51 54
52export const API = api; 55export const API = api;
53export const API_VERSION = 'v1'; 56export const API_VERSION = 'v1';
54export const WS_API = wsApi; 57export const WS_API = wsApi;
55export 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 1a571c904..2f134c5ee 100644
--- a/src/i18n/locales/defaultMessages.json
+++ b/src/i18n/locales/defaultMessages.json
@@ -4503,741 +4503,793 @@
4503 "defaultMessage": "!!!Edit", 4503 "defaultMessage": "!!!Edit",
4504 "end": { 4504 "end": {
4505 "column": 3, 4505 "column": 3,
4506 "line": 18 4506 "line": 21
4507 }, 4507 },
4508 "file": "src/lib/Menu.js", 4508 "file": "src/lib/Menu.js",
4509 "id": "menu.edit", 4509 "id": "menu.edit",
4510 "start": { 4510 "start": {
4511 "column": 8, 4511 "column": 8,
4512 "line": 15 4512 "line": 18
4513 } 4513 }
4514 }, 4514 },
4515 { 4515 {
4516 "defaultMessage": "!!!Undo", 4516 "defaultMessage": "!!!Undo",
4517 "end": { 4517 "end": {
4518 "column": 3, 4518 "column": 3,
4519 "line": 22 4519 "line": 25
4520 }, 4520 },
4521 "file": "src/lib/Menu.js", 4521 "file": "src/lib/Menu.js",
4522 "id": "menu.edit.undo", 4522 "id": "menu.edit.undo",
4523 "start": { 4523 "start": {
4524 "column": 8, 4524 "column": 8,
4525 "line": 19 4525 "line": 22
4526 } 4526 }
4527 }, 4527 },
4528 { 4528 {
4529 "defaultMessage": "!!!Redo", 4529 "defaultMessage": "!!!Redo",
4530 "end": { 4530 "end": {
4531 "column": 3, 4531 "column": 3,
4532 "line": 26 4532 "line": 29
4533 }, 4533 },
4534 "file": "src/lib/Menu.js", 4534 "file": "src/lib/Menu.js",
4535 "id": "menu.edit.redo", 4535 "id": "menu.edit.redo",
4536 "start": { 4536 "start": {
4537 "column": 8, 4537 "column": 8,
4538 "line": 23 4538 "line": 26
4539 } 4539 }
4540 }, 4540 },
4541 { 4541 {
4542 "defaultMessage": "!!!Cut", 4542 "defaultMessage": "!!!Cut",
4543 "end": { 4543 "end": {
4544 "column": 3, 4544 "column": 3,
4545 "line": 30 4545 "line": 33
4546 }, 4546 },
4547 "file": "src/lib/Menu.js", 4547 "file": "src/lib/Menu.js",
4548 "id": "menu.edit.cut", 4548 "id": "menu.edit.cut",
4549 "start": { 4549 "start": {
4550 "column": 7, 4550 "column": 7,
4551 "line": 27 4551 "line": 30
4552 } 4552 }
4553 }, 4553 },
4554 { 4554 {
4555 "defaultMessage": "!!!Copy", 4555 "defaultMessage": "!!!Copy",
4556 "end": { 4556 "end": {
4557 "column": 3, 4557 "column": 3,
4558 "line": 34 4558 "line": 37
4559 }, 4559 },
4560 "file": "src/lib/Menu.js", 4560 "file": "src/lib/Menu.js",
4561 "id": "menu.edit.copy", 4561 "id": "menu.edit.copy",
4562 "start": { 4562 "start": {
4563 "column": 8, 4563 "column": 8,
4564 "line": 31 4564 "line": 34
4565 } 4565 }
4566 }, 4566 },
4567 { 4567 {
4568 "defaultMessage": "!!!Paste", 4568 "defaultMessage": "!!!Paste",
4569 "end": { 4569 "end": {
4570 "column": 3, 4570 "column": 3,
4571 "line": 38 4571 "line": 41
4572 }, 4572 },
4573 "file": "src/lib/Menu.js", 4573 "file": "src/lib/Menu.js",
4574 "id": "menu.edit.paste", 4574 "id": "menu.edit.paste",
4575 "start": { 4575 "start": {
4576 "column": 9, 4576 "column": 9,
4577 "line": 35 4577 "line": 38
4578 } 4578 }
4579 }, 4579 },
4580 { 4580 {
4581 "defaultMessage": "!!!Paste And Match Style", 4581 "defaultMessage": "!!!Paste And Match Style",
4582 "end": { 4582 "end": {
4583 "column": 3, 4583 "column": 3,
4584 "line": 42 4584 "line": 45
4585 }, 4585 },
4586 "file": "src/lib/Menu.js", 4586 "file": "src/lib/Menu.js",
4587 "id": "menu.edit.pasteAndMatchStyle", 4587 "id": "menu.edit.pasteAndMatchStyle",
4588 "start": { 4588 "start": {
4589 "column": 22, 4589 "column": 22,
4590 "line": 39 4590 "line": 42
4591 } 4591 }
4592 }, 4592 },
4593 { 4593 {
4594 "defaultMessage": "!!!Delete", 4594 "defaultMessage": "!!!Delete",
4595 "end": { 4595 "end": {
4596 "column": 3, 4596 "column": 3,
4597 "line": 46 4597 "line": 49
4598 }, 4598 },
4599 "file": "src/lib/Menu.js", 4599 "file": "src/lib/Menu.js",
4600 "id": "menu.edit.delete", 4600 "id": "menu.edit.delete",
4601 "start": { 4601 "start": {
4602 "column": 10, 4602 "column": 10,
4603 "line": 43 4603 "line": 46
4604 } 4604 }
4605 }, 4605 },
4606 { 4606 {
4607 "defaultMessage": "!!!Select All", 4607 "defaultMessage": "!!!Select All",
4608 "end": { 4608 "end": {
4609 "column": 3, 4609 "column": 3,
4610 "line": 50 4610 "line": 53
4611 }, 4611 },
4612 "file": "src/lib/Menu.js", 4612 "file": "src/lib/Menu.js",
4613 "id": "menu.edit.selectAll", 4613 "id": "menu.edit.selectAll",
4614 "start": { 4614 "start": {
4615 "column": 13, 4615 "column": 13,
4616 "line": 47 4616 "line": 50
4617 } 4617 }
4618 }, 4618 },
4619 { 4619 {
4620 "defaultMessage": "!!!Speech", 4620 "defaultMessage": "!!!Speech",
4621 "end": { 4621 "end": {
4622 "column": 3, 4622 "column": 3,
4623 "line": 54 4623 "line": 57
4624 }, 4624 },
4625 "file": "src/lib/Menu.js", 4625 "file": "src/lib/Menu.js",
4626 "id": "menu.edit.speech", 4626 "id": "menu.edit.speech",
4627 "start": { 4627 "start": {
4628 "column": 10, 4628 "column": 10,
4629 "line": 51 4629 "line": 54
4630 } 4630 }
4631 }, 4631 },
4632 { 4632 {
4633 "defaultMessage": "!!!Start Speaking", 4633 "defaultMessage": "!!!Start Speaking",
4634 "end": { 4634 "end": {
4635 "column": 3, 4635 "column": 3,
4636 "line": 58 4636 "line": 61
4637 }, 4637 },
4638 "file": "src/lib/Menu.js", 4638 "file": "src/lib/Menu.js",
4639 "id": "menu.edit.startSpeaking", 4639 "id": "menu.edit.startSpeaking",
4640 "start": { 4640 "start": {
4641 "column": 17, 4641 "column": 17,
4642 "line": 55 4642 "line": 58
4643 } 4643 }
4644 }, 4644 },
4645 { 4645 {
4646 "defaultMessage": "!!!Stop Speaking", 4646 "defaultMessage": "!!!Stop Speaking",
4647 "end": { 4647 "end": {
4648 "column": 3, 4648 "column": 3,
4649 "line": 62 4649 "line": 65
4650 }, 4650 },
4651 "file": "src/lib/Menu.js", 4651 "file": "src/lib/Menu.js",
4652 "id": "menu.edit.stopSpeaking", 4652 "id": "menu.edit.stopSpeaking",
4653 "start": { 4653 "start": {
4654 "column": 16, 4654 "column": 16,
4655 "line": 59 4655 "line": 62
4656 } 4656 }
4657 }, 4657 },
4658 { 4658 {
4659 "defaultMessage": "!!!Start Dictation", 4659 "defaultMessage": "!!!Start Dictation",
4660 "end": { 4660 "end": {
4661 "column": 3, 4661 "column": 3,
4662 "line": 66 4662 "line": 69
4663 }, 4663 },
4664 "file": "src/lib/Menu.js", 4664 "file": "src/lib/Menu.js",
4665 "id": "menu.edit.startDictation", 4665 "id": "menu.edit.startDictation",
4666 "start": { 4666 "start": {
4667 "column": 18, 4667 "column": 18,
4668 "line": 63 4668 "line": 66
4669 } 4669 }
4670 }, 4670 },
4671 { 4671 {
4672 "defaultMessage": "!!!Emoji & Symbols", 4672 "defaultMessage": "!!!Emoji & Symbols",
4673 "end": { 4673 "end": {
4674 "column": 3, 4674 "column": 3,
4675 "line": 70 4675 "line": 73
4676 }, 4676 },
4677 "file": "src/lib/Menu.js", 4677 "file": "src/lib/Menu.js",
4678 "id": "menu.edit.emojiSymbols", 4678 "id": "menu.edit.emojiSymbols",
4679 "start": { 4679 "start": {
4680 "column": 16, 4680 "column": 16,
4681 "line": 67 4681 "line": 70
4682 } 4682 }
4683 }, 4683 },
4684 { 4684 {
4685 "defaultMessage": "!!!Actual Size", 4685 "defaultMessage": "!!!Actual Size",
4686 "end": { 4686 "end": {
4687 "column": 3, 4687 "column": 3,
4688 "line": 74 4688 "line": 77
4689 }, 4689 },
4690 "file": "src/lib/Menu.js", 4690 "file": "src/lib/Menu.js",
4691 "id": "menu.view.resetZoom", 4691 "id": "menu.view.resetZoom",
4692 "start": { 4692 "start": {
4693 "column": 13, 4693 "column": 13,
4694 "line": 71 4694 "line": 74
4695 } 4695 }
4696 }, 4696 },
4697 { 4697 {
4698 "defaultMessage": "!!!Zoom In", 4698 "defaultMessage": "!!!Zoom In",
4699 "end": { 4699 "end": {
4700 "column": 3, 4700 "column": 3,
4701 "line": 78 4701 "line": 81
4702 }, 4702 },
4703 "file": "src/lib/Menu.js", 4703 "file": "src/lib/Menu.js",
4704 "id": "menu.view.zoomIn", 4704 "id": "menu.view.zoomIn",
4705 "start": { 4705 "start": {
4706 "column": 10, 4706 "column": 10,
4707 "line": 75 4707 "line": 78
4708 } 4708 }
4709 }, 4709 },
4710 { 4710 {
4711 "defaultMessage": "!!!Zoom Out", 4711 "defaultMessage": "!!!Zoom Out",
4712 "end": { 4712 "end": {
4713 "column": 3, 4713 "column": 3,
4714 "line": 82 4714 "line": 85
4715 }, 4715 },
4716 "file": "src/lib/Menu.js", 4716 "file": "src/lib/Menu.js",
4717 "id": "menu.view.zoomOut", 4717 "id": "menu.view.zoomOut",
4718 "start": { 4718 "start": {
4719 "column": 11, 4719 "column": 11,
4720 "line": 79 4720 "line": 82
4721 } 4721 }
4722 }, 4722 },
4723 { 4723 {
4724 "defaultMessage": "!!!Enter Full Screen", 4724 "defaultMessage": "!!!Enter Full Screen",
4725 "end": { 4725 "end": {
4726 "column": 3, 4726 "column": 3,
4727 "line": 86 4727 "line": 89
4728 }, 4728 },
4729 "file": "src/lib/Menu.js", 4729 "file": "src/lib/Menu.js",
4730 "id": "menu.view.enterFullScreen", 4730 "id": "menu.view.enterFullScreen",
4731 "start": { 4731 "start": {
4732 "column": 19, 4732 "column": 19,
4733 "line": 83 4733 "line": 86
4734 } 4734 }
4735 }, 4735 },
4736 { 4736 {
4737 "defaultMessage": "!!!Exit Full Screen", 4737 "defaultMessage": "!!!Exit Full Screen",
4738 "end": { 4738 "end": {
4739 "column": 3, 4739 "column": 3,
4740 "line": 90 4740 "line": 93
4741 }, 4741 },
4742 "file": "src/lib/Menu.js", 4742 "file": "src/lib/Menu.js",
4743 "id": "menu.view.exitFullScreen", 4743 "id": "menu.view.exitFullScreen",
4744 "start": { 4744 "start": {
4745 "column": 18, 4745 "column": 18,
4746 "line": 87 4746 "line": 90
4747 } 4747 }
4748 }, 4748 },
4749 { 4749 {
4750 "defaultMessage": "!!!Toggle Full Screen", 4750 "defaultMessage": "!!!Toggle Full Screen",
4751 "end": { 4751 "end": {
4752 "column": 3, 4752 "column": 3,
4753 "line": 94 4753 "line": 97
4754 }, 4754 },
4755 "file": "src/lib/Menu.js", 4755 "file": "src/lib/Menu.js",
4756 "id": "menu.view.toggleFullScreen", 4756 "id": "menu.view.toggleFullScreen",
4757 "start": { 4757 "start": {
4758 "column": 20, 4758 "column": 20,
4759 "line": 91 4759 "line": 94
4760 } 4760 }
4761 }, 4761 },
4762 { 4762 {
4763 "defaultMessage": "!!!Toggle Developer Tools", 4763 "defaultMessage": "!!!Toggle Developer Tools",
4764 "end": { 4764 "end": {
4765 "column": 3, 4765 "column": 3,
4766 "line": 98 4766 "line": 101
4767 }, 4767 },
4768 "file": "src/lib/Menu.js", 4768 "file": "src/lib/Menu.js",
4769 "id": "menu.view.toggleDevTools", 4769 "id": "menu.view.toggleDevTools",
4770 "start": { 4770 "start": {
4771 "column": 18, 4771 "column": 18,
4772 "line": 95 4772 "line": 98
4773 } 4773 }
4774 }, 4774 },
4775 { 4775 {
4776 "defaultMessage": "!!!Toggle Service Developer Tools", 4776 "defaultMessage": "!!!Toggle Todos Developer Tools",
4777 "end": { 4777 "end": {
4778 "column": 3, 4778 "column": 3,
4779 "line": 105
4780 },
4781 "file": "src/lib/Menu.js",
4782 "id": "menu.view.toggleTodosDevTools",
4783 "start": {
4784 "column": 23,
4779 "line": 102 4785 "line": 102
4786 }
4787 },
4788 {
4789 "defaultMessage": "!!!Toggle Service Developer Tools",
4790 "end": {
4791 "column": 3,
4792 "line": 109
4780 }, 4793 },
4781 "file": "src/lib/Menu.js", 4794 "file": "src/lib/Menu.js",
4782 "id": "menu.view.toggleServiceDevTools", 4795 "id": "menu.view.toggleServiceDevTools",
4783 "start": { 4796 "start": {
4784 "column": 25, 4797 "column": 25,
4785 "line": 99 4798 "line": 106
4786 } 4799 }
4787 }, 4800 },
4788 { 4801 {
4789 "defaultMessage": "!!!Reload Service", 4802 "defaultMessage": "!!!Reload Service",
4790 "end": { 4803 "end": {
4791 "column": 3, 4804 "column": 3,
4792 "line": 106 4805 "line": 113
4793 }, 4806 },
4794 "file": "src/lib/Menu.js", 4807 "file": "src/lib/Menu.js",
4795 "id": "menu.view.reloadService", 4808 "id": "menu.view.reloadService",
4796 "start": { 4809 "start": {
4797 "column": 17, 4810 "column": 17,
4798 "line": 103 4811 "line": 110
4799 } 4812 }
4800 }, 4813 },
4801 { 4814 {
4802 "defaultMessage": "!!!Reload Franz", 4815 "defaultMessage": "!!!Reload Franz",
4803 "end": { 4816 "end": {
4804 "column": 3, 4817 "column": 3,
4805 "line": 110 4818 "line": 117
4806 }, 4819 },
4807 "file": "src/lib/Menu.js", 4820 "file": "src/lib/Menu.js",
4808 "id": "menu.view.reloadFranz", 4821 "id": "menu.view.reloadFranz",
4809 "start": { 4822 "start": {
4810 "column": 15, 4823 "column": 15,
4811 "line": 107 4824 "line": 114
4812 } 4825 }
4813 }, 4826 },
4814 { 4827 {
4815 "defaultMessage": "!!!Minimize", 4828 "defaultMessage": "!!!Minimize",
4816 "end": { 4829 "end": {
4817 "column": 3, 4830 "column": 3,
4818 "line": 114 4831 "line": 121
4819 }, 4832 },
4820 "file": "src/lib/Menu.js", 4833 "file": "src/lib/Menu.js",
4821 "id": "menu.window.minimize", 4834 "id": "menu.window.minimize",
4822 "start": { 4835 "start": {
4823 "column": 12, 4836 "column": 12,
4824 "line": 111 4837 "line": 118
4825 } 4838 }
4826 }, 4839 },
4827 { 4840 {
4828 "defaultMessage": "!!!Close", 4841 "defaultMessage": "!!!Close",
4829 "end": { 4842 "end": {
4830 "column": 3, 4843 "column": 3,
4831 "line": 118 4844 "line": 125
4832 }, 4845 },
4833 "file": "src/lib/Menu.js", 4846 "file": "src/lib/Menu.js",
4834 "id": "menu.window.close", 4847 "id": "menu.window.close",
4835 "start": { 4848 "start": {
4836 "column": 9, 4849 "column": 9,
4837 "line": 115 4850 "line": 122
4838 } 4851 }
4839 }, 4852 },
4840 { 4853 {
4841 "defaultMessage": "!!!Learn More", 4854 "defaultMessage": "!!!Learn More",
4842 "end": { 4855 "end": {
4843 "column": 3, 4856 "column": 3,
4844 "line": 122 4857 "line": 129
4845 }, 4858 },
4846 "file": "src/lib/Menu.js", 4859 "file": "src/lib/Menu.js",
4847 "id": "menu.help.learnMore", 4860 "id": "menu.help.learnMore",
4848 "start": { 4861 "start": {
4849 "column": 13, 4862 "column": 13,
4850 "line": 119 4863 "line": 126
4851 } 4864 }
4852 }, 4865 },
4853 { 4866 {
4854 "defaultMessage": "!!!Changelog", 4867 "defaultMessage": "!!!Changelog",
4855 "end": { 4868 "end": {
4856 "column": 3, 4869 "column": 3,
4857 "line": 126 4870 "line": 133
4858 }, 4871 },
4859 "file": "src/lib/Menu.js", 4872 "file": "src/lib/Menu.js",
4860 "id": "menu.help.changelog", 4873 "id": "menu.help.changelog",
4861 "start": { 4874 "start": {
4862 "column": 13, 4875 "column": 13,
4863 "line": 123 4876 "line": 130
4864 } 4877 }
4865 }, 4878 },
4866 { 4879 {
4867 "defaultMessage": "!!!Support", 4880 "defaultMessage": "!!!Support",
4868 "end": { 4881 "end": {
4869 "column": 3, 4882 "column": 3,
4870 "line": 130 4883 "line": 137
4871 }, 4884 },
4872 "file": "src/lib/Menu.js", 4885 "file": "src/lib/Menu.js",
4873 "id": "menu.help.support", 4886 "id": "menu.help.support",
4874 "start": { 4887 "start": {
4875 "column": 11, 4888 "column": 11,
4876 "line": 127 4889 "line": 134
4877 } 4890 }
4878 }, 4891 },
4879 { 4892 {
4880 "defaultMessage": "!!!Copy Debug Information", 4893 "defaultMessage": "!!!Copy Debug Information",
4881 "end": { 4894 "end": {
4882 "column": 3, 4895 "column": 3,
4883 "line": 134 4896 "line": 141
4884 }, 4897 },
4885 "file": "src/lib/Menu.js", 4898 "file": "src/lib/Menu.js",
4886 "id": "menu.help.debugInfo", 4899 "id": "menu.help.debugInfo",
4887 "start": { 4900 "start": {
4888 "column": 13, 4901 "column": 13,
4889 "line": 131 4902 "line": 138
4890 } 4903 }
4891 }, 4904 },
4892 { 4905 {
4893 "defaultMessage": "!!!Franz Debug Information", 4906 "defaultMessage": "!!!Franz Debug Information",
4894 "end": { 4907 "end": {
4895 "column": 3, 4908 "column": 3,
4896 "line": 138 4909 "line": 145
4897 }, 4910 },
4898 "file": "src/lib/Menu.js", 4911 "file": "src/lib/Menu.js",
4899 "id": "menu.help.debugInfoCopiedHeadline", 4912 "id": "menu.help.debugInfoCopiedHeadline",
4900 "start": { 4913 "start": {
4901 "column": 27, 4914 "column": 27,
4902 "line": 135 4915 "line": 142
4903 } 4916 }
4904 }, 4917 },
4905 { 4918 {
4906 "defaultMessage": "!!!Your Debug Information has been copied to your clipboard.", 4919 "defaultMessage": "!!!Your Debug Information has been copied to your clipboard.",
4907 "end": { 4920 "end": {
4908 "column": 3, 4921 "column": 3,
4909 "line": 142 4922 "line": 149
4910 }, 4923 },
4911 "file": "src/lib/Menu.js", 4924 "file": "src/lib/Menu.js",
4912 "id": "menu.help.debugInfoCopiedBody", 4925 "id": "menu.help.debugInfoCopiedBody",
4913 "start": { 4926 "start": {
4914 "column": 23, 4927 "column": 23,
4915 "line": 139 4928 "line": 146
4916 } 4929 }
4917 }, 4930 },
4918 { 4931 {
4919 "defaultMessage": "!!!Terms of Service", 4932 "defaultMessage": "!!!Terms of Service",
4920 "end": { 4933 "end": {
4921 "column": 3, 4934 "column": 3,
4922 "line": 146 4935 "line": 153
4923 }, 4936 },
4924 "file": "src/lib/Menu.js", 4937 "file": "src/lib/Menu.js",
4925 "id": "menu.help.tos", 4938 "id": "menu.help.tos",
4926 "start": { 4939 "start": {
4927 "column": 7, 4940 "column": 7,
4928 "line": 143 4941 "line": 150
4929 } 4942 }
4930 }, 4943 },
4931 { 4944 {
4932 "defaultMessage": "!!!Privacy Statement", 4945 "defaultMessage": "!!!Privacy Statement",
4933 "end": { 4946 "end": {
4934 "column": 3, 4947 "column": 3,
4935 "line": 150 4948 "line": 157
4936 }, 4949 },
4937 "file": "src/lib/Menu.js", 4950 "file": "src/lib/Menu.js",
4938 "id": "menu.help.privacy", 4951 "id": "menu.help.privacy",
4939 "start": { 4952 "start": {
4940 "column": 11, 4953 "column": 11,
4941 "line": 147 4954 "line": 154
4942 } 4955 }
4943 }, 4956 },
4944 { 4957 {
4945 "defaultMessage": "!!!File", 4958 "defaultMessage": "!!!File",
4946 "end": { 4959 "end": {
4947 "column": 3, 4960 "column": 3,
4948 "line": 154 4961 "line": 161
4949 }, 4962 },
4950 "file": "src/lib/Menu.js", 4963 "file": "src/lib/Menu.js",
4951 "id": "menu.file", 4964 "id": "menu.file",
4952 "start": { 4965 "start": {
4953 "column": 8, 4966 "column": 8,
4954 "line": 151 4967 "line": 158
4955 } 4968 }
4956 }, 4969 },
4957 { 4970 {
4958 "defaultMessage": "!!!View", 4971 "defaultMessage": "!!!View",
4959 "end": { 4972 "end": {
4960 "column": 3, 4973 "column": 3,
4961 "line": 158 4974 "line": 165
4962 }, 4975 },
4963 "file": "src/lib/Menu.js", 4976 "file": "src/lib/Menu.js",
4964 "id": "menu.view", 4977 "id": "menu.view",
4965 "start": { 4978 "start": {
4966 "column": 8, 4979 "column": 8,
4967 "line": 155 4980 "line": 162
4968 } 4981 }
4969 }, 4982 },
4970 { 4983 {
4971 "defaultMessage": "!!!Services", 4984 "defaultMessage": "!!!Services",
4972 "end": { 4985 "end": {
4973 "column": 3, 4986 "column": 3,
4974 "line": 162 4987 "line": 169
4975 }, 4988 },
4976 "file": "src/lib/Menu.js", 4989 "file": "src/lib/Menu.js",
4977 "id": "menu.services", 4990 "id": "menu.services",
4978 "start": { 4991 "start": {
4979 "column": 12, 4992 "column": 12,
4980 "line": 159 4993 "line": 166
4981 } 4994 }
4982 }, 4995 },
4983 { 4996 {
4984 "defaultMessage": "!!!Window", 4997 "defaultMessage": "!!!Window",
4985 "end": { 4998 "end": {
4986 "column": 3, 4999 "column": 3,
4987 "line": 166 5000 "line": 173
4988 }, 5001 },
4989 "file": "src/lib/Menu.js", 5002 "file": "src/lib/Menu.js",
4990 "id": "menu.window", 5003 "id": "menu.window",
4991 "start": { 5004 "start": {
4992 "column": 10, 5005 "column": 10,
4993 "line": 163 5006 "line": 170
4994 } 5007 }
4995 }, 5008 },
4996 { 5009 {
4997 "defaultMessage": "!!!Help", 5010 "defaultMessage": "!!!Help",
4998 "end": { 5011 "end": {
4999 "column": 3, 5012 "column": 3,
5000 "line": 170 5013 "line": 177
5001 }, 5014 },
5002 "file": "src/lib/Menu.js", 5015 "file": "src/lib/Menu.js",
5003 "id": "menu.help", 5016 "id": "menu.help",
5004 "start": { 5017 "start": {
5005 "column": 8, 5018 "column": 8,
5006 "line": 167 5019 "line": 174
5007 } 5020 }
5008 }, 5021 },
5009 { 5022 {
5010 "defaultMessage": "!!!About Franz", 5023 "defaultMessage": "!!!About Franz",
5011 "end": { 5024 "end": {
5012 "column": 3, 5025 "column": 3,
5013 "line": 174 5026 "line": 181
5014 }, 5027 },
5015 "file": "src/lib/Menu.js", 5028 "file": "src/lib/Menu.js",
5016 "id": "menu.app.about", 5029 "id": "menu.app.about",
5017 "start": { 5030 "start": {
5018 "column": 9, 5031 "column": 9,
5019 "line": 171 5032 "line": 178
5020 } 5033 }
5021 }, 5034 },
5022 { 5035 {
5023 "defaultMessage": "!!!What's new?", 5036 "defaultMessage": "!!!What's new?",
5024 "end": { 5037 "end": {
5025 "column": 3, 5038 "column": 3,
5026 "line": 178 5039 "line": 185
5027 }, 5040 },
5028 "file": "src/lib/Menu.js", 5041 "file": "src/lib/Menu.js",
5029 "id": "menu.app.announcement", 5042 "id": "menu.app.announcement",
5030 "start": { 5043 "start": {
5031 "column": 16, 5044 "column": 16,
5032 "line": 175 5045 "line": 182
5033 } 5046 }
5034 }, 5047 },
5035 { 5048 {
5036 "defaultMessage": "!!!Settings", 5049 "defaultMessage": "!!!Settings",
5037 "end": { 5050 "end": {
5038 "column": 3, 5051 "column": 3,
5039 "line": 182 5052 "line": 189
5040 }, 5053 },
5041 "file": "src/lib/Menu.js", 5054 "file": "src/lib/Menu.js",
5042 "id": "menu.app.settings", 5055 "id": "menu.app.settings",
5043 "start": { 5056 "start": {
5044 "column": 12, 5057 "column": 12,
5045 "line": 179 5058 "line": 186
5046 } 5059 }
5047 }, 5060 },
5048 { 5061 {
5049 "defaultMessage": "!!!Check for updates", 5062 "defaultMessage": "!!!Check for updates",
5050 "end": { 5063 "end": {
5051 "column": 3, 5064 "column": 3,
5052 "line": 186 5065 "line": 193
5053 }, 5066 },
5054 "file": "src/lib/Menu.js", 5067 "file": "src/lib/Menu.js",
5055 "id": "menu.app.checkForUpdates", 5068 "id": "menu.app.checkForUpdates",
5056 "start": { 5069 "start": {
5057 "column": 19, 5070 "column": 19,
5058 "line": 183 5071 "line": 190
5059 } 5072 }
5060 }, 5073 },
5061 { 5074 {
5062 "defaultMessage": "!!!Hide", 5075 "defaultMessage": "!!!Hide",
5063 "end": { 5076 "end": {
5064 "column": 3, 5077 "column": 3,
5065 "line": 190 5078 "line": 197
5066 }, 5079 },
5067 "file": "src/lib/Menu.js", 5080 "file": "src/lib/Menu.js",
5068 "id": "menu.app.hide", 5081 "id": "menu.app.hide",
5069 "start": { 5082 "start": {
5070 "column": 8, 5083 "column": 8,
5071 "line": 187 5084 "line": 194
5072 } 5085 }
5073 }, 5086 },
5074 { 5087 {
5075 "defaultMessage": "!!!Hide Others", 5088 "defaultMessage": "!!!Hide Others",
5076 "end": { 5089 "end": {
5077 "column": 3, 5090 "column": 3,
5078 "line": 194 5091 "line": 201
5079 }, 5092 },
5080 "file": "src/lib/Menu.js", 5093 "file": "src/lib/Menu.js",
5081 "id": "menu.app.hideOthers", 5094 "id": "menu.app.hideOthers",
5082 "start": { 5095 "start": {
5083 "column": 14, 5096 "column": 14,
5084 "line": 191 5097 "line": 198
5085 } 5098 }
5086 }, 5099 },
5087 { 5100 {
5088 "defaultMessage": "!!!Unhide", 5101 "defaultMessage": "!!!Unhide",
5089 "end": { 5102 "end": {
5090 "column": 3, 5103 "column": 3,
5091 "line": 198 5104 "line": 205
5092 }, 5105 },
5093 "file": "src/lib/Menu.js", 5106 "file": "src/lib/Menu.js",
5094 "id": "menu.app.unhide", 5107 "id": "menu.app.unhide",
5095 "start": { 5108 "start": {
5096 "column": 10, 5109 "column": 10,
5097 "line": 195 5110 "line": 202
5098 } 5111 }
5099 }, 5112 },
5100 { 5113 {
5101 "defaultMessage": "!!!Quit", 5114 "defaultMessage": "!!!Quit",
5102 "end": { 5115 "end": {
5103 "column": 3, 5116 "column": 3,
5104 "line": 202 5117 "line": 209
5105 }, 5118 },
5106 "file": "src/lib/Menu.js", 5119 "file": "src/lib/Menu.js",
5107 "id": "menu.app.quit", 5120 "id": "menu.app.quit",
5108 "start": { 5121 "start": {
5109 "column": 8, 5122 "column": 8,
5110 "line": 199 5123 "line": 206
5111 } 5124 }
5112 }, 5125 },
5113 { 5126 {
5114 "defaultMessage": "!!!Add New Service...", 5127 "defaultMessage": "!!!Add New Service...",
5115 "end": { 5128 "end": {
5116 "column": 3, 5129 "column": 3,
5117 "line": 206 5130 "line": 213
5118 }, 5131 },
5119 "file": "src/lib/Menu.js", 5132 "file": "src/lib/Menu.js",
5120 "id": "menu.services.addNewService", 5133 "id": "menu.services.addNewService",
5121 "start": { 5134 "start": {
5122 "column": 17, 5135 "column": 17,
5123 "line": 203 5136 "line": 210
5124 } 5137 }
5125 }, 5138 },
5126 { 5139 {
5127 "defaultMessage": "!!!Add New Workspace...", 5140 "defaultMessage": "!!!Add New Workspace...",
5128 "end": { 5141 "end": {
5129 "column": 3, 5142 "column": 3,
5130 "line": 210 5143 "line": 217
5131 }, 5144 },
5132 "file": "src/lib/Menu.js", 5145 "file": "src/lib/Menu.js",
5133 "id": "menu.workspaces.addNewWorkspace", 5146 "id": "menu.workspaces.addNewWorkspace",
5134 "start": { 5147 "start": {
5135 "column": 19, 5148 "column": 19,
5136 "line": 207 5149 "line": 214
5137 } 5150 }
5138 }, 5151 },
5139 { 5152 {
5140 "defaultMessage": "!!!Open workspace drawer", 5153 "defaultMessage": "!!!Open workspace drawer",
5141 "end": { 5154 "end": {
5142 "column": 3, 5155 "column": 3,
5143 "line": 214 5156 "line": 221
5144 }, 5157 },
5145 "file": "src/lib/Menu.js", 5158 "file": "src/lib/Menu.js",
5146 "id": "menu.workspaces.openWorkspaceDrawer", 5159 "id": "menu.workspaces.openWorkspaceDrawer",
5147 "start": { 5160 "start": {
5148 "column": 23, 5161 "column": 23,
5149 "line": 211 5162 "line": 218
5150 } 5163 }
5151 }, 5164 },
5152 { 5165 {
5153 "defaultMessage": "!!!Close workspace drawer", 5166 "defaultMessage": "!!!Close workspace drawer",
5154 "end": { 5167 "end": {
5155 "column": 3, 5168 "column": 3,
5156 "line": 218 5169 "line": 225
5157 }, 5170 },
5158 "file": "src/lib/Menu.js", 5171 "file": "src/lib/Menu.js",
5159 "id": "menu.workspaces.closeWorkspaceDrawer", 5172 "id": "menu.workspaces.closeWorkspaceDrawer",
5160 "start": { 5173 "start": {
5161 "column": 24, 5174 "column": 24,
5162 "line": 215 5175 "line": 222
5163 } 5176 }
5164 }, 5177 },
5165 { 5178 {
5166 "defaultMessage": "!!!Activate next service...", 5179 "defaultMessage": "!!!Activate next service...",
5167 "end": { 5180 "end": {
5168 "column": 3, 5181 "column": 3,
5169 "line": 222 5182 "line": 229
5170 }, 5183 },
5171 "file": "src/lib/Menu.js", 5184 "file": "src/lib/Menu.js",
5172 "id": "menu.services.setNextServiceActive", 5185 "id": "menu.services.setNextServiceActive",
5173 "start": { 5186 "start": {
5174 "column": 23, 5187 "column": 23,
5175 "line": 219 5188 "line": 226
5176 } 5189 }
5177 }, 5190 },
5178 { 5191 {
5179 "defaultMessage": "!!!Activate previous service...", 5192 "defaultMessage": "!!!Activate previous service...",
5180 "end": { 5193 "end": {
5181 "column": 3, 5194 "column": 3,
5182 "line": 226 5195 "line": 233
5183 }, 5196 },
5184 "file": "src/lib/Menu.js", 5197 "file": "src/lib/Menu.js",
5185 "id": "menu.services.activatePreviousService", 5198 "id": "menu.services.activatePreviousService",
5186 "start": { 5199 "start": {
5187 "column": 27, 5200 "column": 27,
5188 "line": 223 5201 "line": 230
5189 } 5202 }
5190 }, 5203 },
5191 { 5204 {
5192 "defaultMessage": "!!!Disable notifications & audio", 5205 "defaultMessage": "!!!Disable notifications & audio",
5193 "end": { 5206 "end": {
5194 "column": 3, 5207 "column": 3,
5195 "line": 230 5208 "line": 237
5196 }, 5209 },
5197 "file": "src/lib/Menu.js", 5210 "file": "src/lib/Menu.js",
5198 "id": "sidebar.muteApp", 5211 "id": "sidebar.muteApp",
5199 "start": { 5212 "start": {
5200 "column": 11, 5213 "column": 11,
5201 "line": 227 5214 "line": 234
5202 } 5215 }
5203 }, 5216 },
5204 { 5217 {
5205 "defaultMessage": "!!!Enable notifications & audio", 5218 "defaultMessage": "!!!Enable notifications & audio",
5206 "end": { 5219 "end": {
5207 "column": 3, 5220 "column": 3,
5208 "line": 234 5221 "line": 241
5209 }, 5222 },
5210 "file": "src/lib/Menu.js", 5223 "file": "src/lib/Menu.js",
5211 "id": "sidebar.unmuteApp", 5224 "id": "sidebar.unmuteApp",
5212 "start": { 5225 "start": {
5213 "column": 13, 5226 "column": 13,
5214 "line": 231 5227 "line": 238
5215 } 5228 }
5216 }, 5229 },
5217 { 5230 {
5218 "defaultMessage": "!!!Workspaces", 5231 "defaultMessage": "!!!Workspaces",
5219 "end": { 5232 "end": {
5220 "column": 3, 5233 "column": 3,
5221 "line": 238 5234 "line": 245
5222 }, 5235 },
5223 "file": "src/lib/Menu.js", 5236 "file": "src/lib/Menu.js",
5224 "id": "menu.workspaces", 5237 "id": "menu.workspaces",
5225 "start": { 5238 "start": {
5226 "column": 14, 5239 "column": 14,
5227 "line": 235 5240 "line": 242
5228 } 5241 }
5229 }, 5242 },
5230 { 5243 {
5231 "defaultMessage": "!!!Default", 5244 "defaultMessage": "!!!Default",
5232 "end": { 5245 "end": {
5233 "column": 3, 5246 "column": 3,
5234 "line": 242 5247 "line": 249
5235 }, 5248 },
5236 "file": "src/lib/Menu.js", 5249 "file": "src/lib/Menu.js",
5237 "id": "menu.workspaces.defaultWorkspace", 5250 "id": "menu.workspaces.defaultWorkspace",
5238 "start": { 5251 "start": {
5239 "column": 20, 5252 "column": 20,
5240 "line": 239 5253 "line": 246
5254 }
5255 },
5256 {
5257 "defaultMessage": "!!!Todos",
5258 "end": {
5259 "column": 3,
5260 "line": 253
5261 },
5262 "file": "src/lib/Menu.js",
5263 "id": "menu.todos",
5264 "start": {
5265 "column": 9,
5266 "line": 250
5267 }
5268 },
5269 {
5270 "defaultMessage": "!!!Open Todos drawer",
5271 "end": {
5272 "column": 3,
5273 "line": 257
5274 },
5275 "file": "src/lib/Menu.js",
5276 "id": "menu.Todoss.openTodosDrawer",
5277 "start": {
5278 "column": 19,
5279 "line": 254
5280 }
5281 },
5282 {
5283 "defaultMessage": "!!!Close Todos drawer",
5284 "end": {
5285 "column": 3,
5286 "line": 261
5287 },
5288 "file": "src/lib/Menu.js",
5289 "id": "menu.Todoss.closeTodosDrawer",
5290 "start": {
5291 "column": 20,
5292 "line": 258
5241 } 5293 }
5242 } 5294 }
5243 ], 5295 ],
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 82a9c0fb4..e8680f2d9 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -47,6 +47,8 @@
47 "login.serverLogout": "Your session expired, please login again.", 47 "login.serverLogout": "Your session expired, please login again.",
48 "login.submit.label": "Sign in", 48 "login.submit.label": "Sign in",
49 "login.tokenExpired": "Your session expired, please login again.", 49 "login.tokenExpired": "Your session expired, please login again.",
50 "menu.Todoss.closeTodosDrawer": "Close Todos drawer",
51 "menu.Todoss.openTodosDrawer": "Open Todos drawer",
50 "menu.app.about": "About Franz", 52 "menu.app.about": "About Franz",
51 "menu.app.announcement": "What's new?", 53 "menu.app.announcement": "What's new?",
52 "menu.app.checkForUpdates": "Check for updates", 54 "menu.app.checkForUpdates": "Check for updates",
@@ -83,6 +85,7 @@
83 "menu.services.activatePreviousService": "Activate previous service", 85 "menu.services.activatePreviousService": "Activate previous service",
84 "menu.services.addNewService": "Add New Service...", 86 "menu.services.addNewService": "Add New Service...",
85 "menu.services.setNextServiceActive": "Activate next service", 87 "menu.services.setNextServiceActive": "Activate next service",
88 "menu.todos": "Todos",
86 "menu.view": "View", 89 "menu.view": "View",
87 "menu.view.enterFullScreen": "Enter Full Screen", 90 "menu.view.enterFullScreen": "Enter Full Screen",
88 "menu.view.exitFullScreen": "Exit Full Screen", 91 "menu.view.exitFullScreen": "Exit Full Screen",
@@ -92,6 +95,7 @@
92 "menu.view.toggleDevTools": "Toggle Developer Tools", 95 "menu.view.toggleDevTools": "Toggle Developer Tools",
93 "menu.view.toggleFullScreen": "Toggle Full Screen", 96 "menu.view.toggleFullScreen": "Toggle Full Screen",
94 "menu.view.toggleServiceDevTools": "Toggle Service Developer Tools", 97 "menu.view.toggleServiceDevTools": "Toggle Service Developer Tools",
98 "menu.view.toggleTodosDevTools": "!!!Toggle Todos Developer Tools",
95 "menu.view.zoomIn": "Zoom In", 99 "menu.view.zoomIn": "Zoom In",
96 "menu.view.zoomOut": "Zoom Out", 100 "menu.view.zoomOut": "Zoom Out",
97 "menu.window": "Window", 101 "menu.window": "Window",
@@ -367,4 +371,4 @@
367 "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>", 371 "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>",
368 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", 372 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
369 "workspaces.switchingIndicator.switchingTo": "Switching to" 373 "workspaces.switchingIndicator.switchingTo": "Switching to"
370} 374} \ No newline at end of file
diff --git a/src/i18n/messages/src/lib/Menu.json b/src/i18n/messages/src/lib/Menu.json
index 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 27334c9a2..cf28b6bec 100644
--- a/src/stores/FeaturesStore.js
+++ b/src/stores/FeaturesStore.js
@@ -18,6 +18,7 @@ import announcements from '../features/announcements';
18import settingsWS from '../features/settingsWS'; 18import settingsWS from '../features/settingsWS';
19import serviceLimit from '../features/serviceLimit'; 19import serviceLimit from '../features/serviceLimit';
20import communityRecipes from '../features/communityRecipes'; 20import communityRecipes from '../features/communityRecipes';
21import todos from '../features/todos';
21 22
22import { DEFAULT_FEATURES_CONFIG } from '../config'; 23import { DEFAULT_FEATURES_CONFIG } from '../config';
23 24
@@ -79,5 +80,6 @@ export default class FeaturesStore extends Store {
79 settingsWS(this.stores, this.actions); 80 settingsWS(this.stores, this.actions);
80 serviceLimit(this.stores, this.actions); 81 serviceLimit(this.stores, this.actions);
81 communityRecipes(this.stores, this.actions); 82 communityRecipes(this.stores, this.actions);
83 todos(this.stores, this.actions);
82 } 84 }
83} 85}
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js
index e3b3fcf21..2fc543192 100644
--- a/src/stores/ServicesStore.js
+++ b/src/stores/ServicesStore.js
@@ -448,6 +448,9 @@ export default class ServicesStore extends Store {
448 redirect: false, 448 redirect: false,
449 }); 449 });
450 } 450 }
451 } else if (channel === 'feature:todos') {
452 Object.assign(args[0].data, { serviceId });
453 this.actions.todos.handleHostMessage(args[0]);
451 } 454 }
452 } 455 }
453 456
diff --git a/src/stores/index.js b/src/stores/index.js
index c9ec77612..10dd56665 100644
--- a/src/stores/index.js
+++ b/src/stores/index.js
@@ -14,6 +14,7 @@ import { workspaceStore } from '../features/workspaces';
14import { announcementsStore } from '../features/announcements'; 14import { announcementsStore } from '../features/announcements';
15import { serviceLimitStore } from '../features/serviceLimit'; 15import { serviceLimitStore } from '../features/serviceLimit';
16import { communityRecipesStore } from '../features/communityRecipes'; 16import { communityRecipesStore } from '../features/communityRecipes';
17import { todosStore } from '../features/todos';
17 18
18export default (api, actions, router) => { 19export default (api, actions, router) => {
19 const stores = {}; 20 const stores = {};
@@ -35,6 +36,7 @@ export default (api, actions, router) => {
35 announcements: announcementsStore, 36 announcements: announcementsStore,
36 serviceLimit: serviceLimitStore, 37 serviceLimit: serviceLimitStore,
37 communityRecipes: communityRecipesStore, 38 communityRecipes: communityRecipesStore,
39 todos: todosStore,
38 }); 40 });
39 // Initialize all stores 41 // Initialize all stores
40 Object.keys(stores).forEach((name) => { 42 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,