aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar Dominik Guzei <dominik.guzei@gmail.com>2019-06-06 13:40:08 +0200
committerLibravatar GitHub <noreply@github.com>2019-06-06 13:40:08 +0200
commit6359ca14b2da42e3c92618f3ea3760837a15ec91 (patch)
tree27ebac2ecc17e5c01ec8c2df789f01c8a589f6a6 /src
parentMerge pull request #1470 from meetfranz/chore/update-some-dependencies (diff)
parentfix eslint issues (diff)
downloadferdium-app-6359ca14b2da42e3c92618f3ea3760837a15ec91.tar.gz
ferdium-app-6359ca14b2da42e3c92618f3ea3760837a15ec91.tar.zst
ferdium-app-6359ca14b2da42e3c92618f3ea3760837a15ec91.zip
Merge pull request #1469 from meetfranz/feature/check-for-updates-in-menu
Add check for updates menu item
Diffstat (limited to 'src')
-rw-r--r--src/components/AppUpdateInfoBar.js66
-rw-r--r--src/components/auth/AuthLayout.js17
-rw-r--r--src/components/layout/AppLayout.js35
-rw-r--r--src/containers/auth/AuthLayoutContainer.js3
-rw-r--r--src/dev-app-update.yml3
-rw-r--r--src/i18n/locales/defaultMessages.json160
-rw-r--r--src/i18n/locales/en-US.json1
-rw-r--r--src/i18n/messages/src/components/AppUpdateInfoBar.json41
-rw-r--r--src/i18n/messages/src/components/layout/AppLayout.json47
-rw-r--r--src/i18n/messages/src/lib/Menu.json69
-rw-r--r--src/lib/Menu.js10
11 files changed, 280 insertions, 172 deletions
diff --git a/src/components/AppUpdateInfoBar.js b/src/components/AppUpdateInfoBar.js
new file mode 100644
index 000000000..4fb3a8b71
--- /dev/null
+++ b/src/components/AppUpdateInfoBar.js
@@ -0,0 +1,66 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { defineMessages, intlShape } from 'react-intl';
4
5import { announcementActions } from '../features/announcements/actions';
6import InfoBar from './ui/InfoBar';
7
8const messages = defineMessages({
9 updateAvailable: {
10 id: 'infobar.updateAvailable',
11 defaultMessage: '!!!A new update for Franz is available.',
12 },
13 changelog: {
14 id: 'infobar.buttonChangelog',
15 defaultMessage: '!!!Changelog',
16 },
17 buttonInstallUpdate: {
18 id: 'infobar.buttonInstallUpdate',
19 defaultMessage: '!!!Restart & install update',
20 },
21});
22
23class AppUpdateInfoBar extends Component {
24 static propTypes = {
25 onInstallUpdate: PropTypes.func.isRequired,
26 nextAppReleaseVersion: PropTypes.string,
27 };
28
29 static defaultProps = {
30 nextAppReleaseVersion: null,
31 };
32
33 static contextTypes = {
34 intl: intlShape,
35 };
36
37 render() {
38 const { intl } = this.context;
39 const {
40 onInstallUpdate,
41 nextAppReleaseVersion,
42 } = this.props;
43
44 return (
45 <InfoBar
46 type="primary"
47 ctaLabel={intl.formatMessage(messages.buttonInstallUpdate)}
48 onClick={onInstallUpdate}
49 sticky
50 >
51 <span className="mdi mdi-information" />
52 {intl.formatMessage(messages.updateAvailable)}
53 {' '}
54 <button
55 className="info-bar__inline-button"
56 type="button"
57 onClick={() => announcementActions.show({ targetVersion: nextAppReleaseVersion })}
58 >
59 <u>{intl.formatMessage(messages.changelog)}</u>
60 </button>
61 </InfoBar>
62 );
63 }
64}
65
66export default AppUpdateInfoBar;
diff --git a/src/components/auth/AuthLayout.js b/src/components/auth/AuthLayout.js
index ac8fdbe5b..3d43d4e5c 100644
--- a/src/components/auth/AuthLayout.js
+++ b/src/components/auth/AuthLayout.js
@@ -11,6 +11,7 @@ import { oneOrManyChildElements, globalError as globalErrorPropType } from '../.
11import globalMessages from '../../i18n/globalMessages'; 11import globalMessages from '../../i18n/globalMessages';
12 12
13import { isWindows } from '../../environment'; 13import { isWindows } from '../../environment';
14import AppUpdateInfoBar from '../AppUpdateInfoBar';
14 15
15export default @observer class AuthLayout extends Component { 16export default @observer class AuthLayout extends Component {
16 static propTypes = { 17 static propTypes = {
@@ -22,6 +23,13 @@ export default @observer class AuthLayout extends Component {
22 isHealthCheckLoading: PropTypes.bool.isRequired, 23 isHealthCheckLoading: PropTypes.bool.isRequired,
23 isFullScreen: PropTypes.bool.isRequired, 24 isFullScreen: PropTypes.bool.isRequired,
24 darkMode: PropTypes.bool.isRequired, 25 darkMode: PropTypes.bool.isRequired,
26 nextAppReleaseVersion: PropTypes.string,
27 installAppUpdate: PropTypes.func.isRequired,
28 appUpdateIsDownloaded: PropTypes.bool.isRequired,
29 };
30
31 static defaultProps = {
32 nextAppReleaseVersion: null,
25 }; 33 };
26 34
27 static contextTypes = { 35 static contextTypes = {
@@ -38,6 +46,9 @@ export default @observer class AuthLayout extends Component {
38 isHealthCheckLoading, 46 isHealthCheckLoading,
39 isFullScreen, 47 isFullScreen,
40 darkMode, 48 darkMode,
49 nextAppReleaseVersion,
50 installAppUpdate,
51 appUpdateIsDownloaded,
41 } = this.props; 52 } = this.props;
42 const { intl } = this.context; 53 const { intl } = this.context;
43 54
@@ -53,6 +64,12 @@ export default @observer class AuthLayout extends Component {
53 {intl.formatMessage(globalMessages.notConnectedToTheInternet)} 64 {intl.formatMessage(globalMessages.notConnectedToTheInternet)}
54 </InfoBar> 65 </InfoBar>
55 )} 66 )}
67 {appUpdateIsDownloaded && (
68 <AppUpdateInfoBar
69 nextAppReleaseVersion={nextAppReleaseVersion}
70 onInstallUpdate={installAppUpdate}
71 />
72 )}
56 {isOnline && !isAPIHealthy && ( 73 {isOnline && !isAPIHealthy && (
57 <InfoBar 74 <InfoBar
58 type="danger" 75 type="danger"
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index b31c00f54..499bc097a 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -16,7 +16,7 @@ import ErrorBoundary from '../util/ErrorBoundary';
16import { isWindows } from '../../environment'; 16import { 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 { announcementActions } from '../../features/announcements/actions'; 19import AppUpdateInfoBar from '../AppUpdateInfoBar';
20 20
21function createMarkup(HTMLString) { 21function createMarkup(HTMLString) {
22 return { __html: HTMLString }; 22 return { __html: HTMLString };
@@ -27,22 +27,10 @@ const messages = defineMessages({
27 id: 'infobar.servicesUpdated', 27 id: 'infobar.servicesUpdated',
28 defaultMessage: '!!!Your services have been updated.', 28 defaultMessage: '!!!Your services have been updated.',
29 }, 29 },
30 updateAvailable: {
31 id: 'infobar.updateAvailable',
32 defaultMessage: '!!!A new update for Franz is available.',
33 },
34 buttonReloadServices: { 30 buttonReloadServices: {
35 id: 'infobar.buttonReloadServices', 31 id: 'infobar.buttonReloadServices',
36 defaultMessage: '!!!Reload services', 32 defaultMessage: '!!!Reload services',
37 }, 33 },
38 changelog: {
39 id: 'infobar.buttonChangelog',
40 defaultMessage: '!!!Changelog',
41 },
42 buttonInstallUpdate: {
43 id: 'infobar.buttonInstallUpdate',
44 defaultMessage: '!!!Restart & install update',
45 },
46 requiredRequestsFailed: { 34 requiredRequestsFailed: {
47 id: 'infobar.requiredRequestsFailed', 35 id: 'infobar.requiredRequestsFailed',
48 defaultMessage: '!!!Could not load services and user information', 36 defaultMessage: '!!!Could not load services and user information',
@@ -173,23 +161,10 @@ class AppLayout extends Component {
173 </InfoBar> 161 </InfoBar>
174 )} 162 )}
175 {appUpdateIsDownloaded && ( 163 {appUpdateIsDownloaded && (
176 <InfoBar 164 <AppUpdateInfoBar
177 type="primary" 165 nextAppReleaseVersion={nextAppReleaseVersion}
178 ctaLabel={intl.formatMessage(messages.buttonInstallUpdate)} 166 onInstallUpdate={installAppUpdate}
179 onClick={installAppUpdate} 167 />
180 sticky
181 >
182 <span className="mdi mdi-information" />
183 {intl.formatMessage(messages.updateAvailable)}
184 {' '}
185 <button
186 className="info-bar__inline-button"
187 type="button"
188 onClick={() => announcementActions.show({ targetVersion: nextAppReleaseVersion })}
189 >
190 <u>{intl.formatMessage(messages.changelog)}</u>
191 </button>
192 </InfoBar>
193 )} 168 )}
194 {isDelayAppScreenVisible && (<DelayApp />)} 169 {isDelayAppScreenVisible && (<DelayApp />)}
195 <BasicAuth /> 170 <BasicAuth />
diff --git a/src/containers/auth/AuthLayoutContainer.js b/src/containers/auth/AuthLayoutContainer.js
index e63f40c06..1f9c1ea61 100644
--- a/src/containers/auth/AuthLayoutContainer.js
+++ b/src/containers/auth/AuthLayoutContainer.js
@@ -51,6 +51,9 @@ export default @inject('stores', 'actions') @observer class AuthLayoutContainer
51 isHealthCheckLoading={app.healthCheckRequest.isExecuting} 51 isHealthCheckLoading={app.healthCheckRequest.isExecuting}
52 isFullScreen={app.isFullScreen} 52 isFullScreen={app.isFullScreen}
53 darkMode={app.isSystemDarkModeEnabled} 53 darkMode={app.isSystemDarkModeEnabled}
54 installAppUpdate={actions.app.installUpdate}
55 nextAppReleaseVersion={app.nextAppReleaseVersion}
56 appUpdateIsDownloaded={app.updateStatus === app.updateStatusTypes.DOWNLOADED}
54 > 57 >
55 {children} 58 {children}
56 </AuthLayout> 59 </AuthLayout>
diff --git a/src/dev-app-update.yml b/src/dev-app-update.yml
new file mode 100644
index 000000000..8ddca71e3
--- /dev/null
+++ b/src/dev-app-update.yml
@@ -0,0 +1,3 @@
1owner: meetfranz
2repo: franz
3provider: github
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json
index 0d5c526fa..d517b456b 100644
--- a/src/i18n/locales/defaultMessages.json
+++ b/src/i18n/locales/defaultMessages.json
@@ -2,6 +2,50 @@
2 { 2 {
3 "descriptors": [ 3 "descriptors": [
4 { 4 {
5 "defaultMessage": "!!!A new update for Franz is available.",
6 "end": {
7 "column": 3,
8 "line": 12
9 },
10 "file": "src/components/AppUpdateInfoBar.js",
11 "id": "infobar.updateAvailable",
12 "start": {
13 "column": 19,
14 "line": 9
15 }
16 },
17 {
18 "defaultMessage": "!!!Changelog",
19 "end": {
20 "column": 3,
21 "line": 16
22 },
23 "file": "src/components/AppUpdateInfoBar.js",
24 "id": "infobar.buttonChangelog",
25 "start": {
26 "column": 13,
27 "line": 13
28 }
29 },
30 {
31 "defaultMessage": "!!!Restart & install update",
32 "end": {
33 "column": 3,
34 "line": 20
35 },
36 "file": "src/components/AppUpdateInfoBar.js",
37 "id": "infobar.buttonInstallUpdate",
38 "start": {
39 "column": 23,
40 "line": 17
41 }
42 }
43 ],
44 "path": "src/components/AppUpdateInfoBar.json"
45 },
46 {
47 "descriptors": [
48 {
5 "defaultMessage": "!!!Import your Franz 4 services", 49 "defaultMessage": "!!!Import your Franz 4 services",
6 "end": { 50 "end": {
7 "column": 3, 51 "column": 3,
@@ -635,68 +679,29 @@
635 } 679 }
636 }, 680 },
637 { 681 {
638 "defaultMessage": "!!!A new update for Franz is available.",
639 "end": {
640 "column": 3,
641 "line": 33
642 },
643 "file": "src/components/layout/AppLayout.js",
644 "id": "infobar.updateAvailable",
645 "start": {
646 "column": 19,
647 "line": 30
648 }
649 },
650 {
651 "defaultMessage": "!!!Reload services", 682 "defaultMessage": "!!!Reload services",
652 "end": { 683 "end": {
653 "column": 3, 684 "column": 3,
654 "line": 37 685 "line": 33
655 }, 686 },
656 "file": "src/components/layout/AppLayout.js", 687 "file": "src/components/layout/AppLayout.js",
657 "id": "infobar.buttonReloadServices", 688 "id": "infobar.buttonReloadServices",
658 "start": { 689 "start": {
659 "column": 24, 690 "column": 24,
660 "line": 34 691 "line": 30
661 }
662 },
663 {
664 "defaultMessage": "!!!Changelog",
665 "end": {
666 "column": 3,
667 "line": 41
668 },
669 "file": "src/components/layout/AppLayout.js",
670 "id": "infobar.buttonChangelog",
671 "start": {
672 "column": 13,
673 "line": 38
674 }
675 },
676 {
677 "defaultMessage": "!!!Restart & install update",
678 "end": {
679 "column": 3,
680 "line": 45
681 },
682 "file": "src/components/layout/AppLayout.js",
683 "id": "infobar.buttonInstallUpdate",
684 "start": {
685 "column": 23,
686 "line": 42
687 } 692 }
688 }, 693 },
689 { 694 {
690 "defaultMessage": "!!!Could not load services and user information", 695 "defaultMessage": "!!!Could not load services and user information",
691 "end": { 696 "end": {
692 "column": 3, 697 "column": 3,
693 "line": 49 698 "line": 37
694 }, 699 },
695 "file": "src/components/layout/AppLayout.js", 700 "file": "src/components/layout/AppLayout.js",
696 "id": "infobar.requiredRequestsFailed", 701 "id": "infobar.requiredRequestsFailed",
697 "start": { 702 "start": {
698 "column": 26, 703 "column": 26,
699 "line": 46 704 "line": 34
700 } 705 }
701 } 706 }
702 ], 707 ],
@@ -4416,185 +4421,198 @@
4416 } 4421 }
4417 }, 4422 },
4418 { 4423 {
4419 "defaultMessage": "!!!Hide", 4424 "defaultMessage": "!!!Check for updates",
4420 "end": { 4425 "end": {
4421 "column": 3, 4426 "column": 3,
4422 "line": 174 4427 "line": 174
4423 }, 4428 },
4424 "file": "src/lib/Menu.js", 4429 "file": "src/lib/Menu.js",
4430 "id": "menu.app.checkForUpdates",
4431 "start": {
4432 "column": 19,
4433 "line": 171
4434 }
4435 },
4436 {
4437 "defaultMessage": "!!!Hide",
4438 "end": {
4439 "column": 3,
4440 "line": 178
4441 },
4442 "file": "src/lib/Menu.js",
4425 "id": "menu.app.hide", 4443 "id": "menu.app.hide",
4426 "start": { 4444 "start": {
4427 "column": 8, 4445 "column": 8,
4428 "line": 171 4446 "line": 175
4429 } 4447 }
4430 }, 4448 },
4431 { 4449 {
4432 "defaultMessage": "!!!Hide Others", 4450 "defaultMessage": "!!!Hide Others",
4433 "end": { 4451 "end": {
4434 "column": 3, 4452 "column": 3,
4435 "line": 178 4453 "line": 182
4436 }, 4454 },
4437 "file": "src/lib/Menu.js", 4455 "file": "src/lib/Menu.js",
4438 "id": "menu.app.hideOthers", 4456 "id": "menu.app.hideOthers",
4439 "start": { 4457 "start": {
4440 "column": 14, 4458 "column": 14,
4441 "line": 175 4459 "line": 179
4442 } 4460 }
4443 }, 4461 },
4444 { 4462 {
4445 "defaultMessage": "!!!Unhide", 4463 "defaultMessage": "!!!Unhide",
4446 "end": { 4464 "end": {
4447 "column": 3, 4465 "column": 3,
4448 "line": 182 4466 "line": 186
4449 }, 4467 },
4450 "file": "src/lib/Menu.js", 4468 "file": "src/lib/Menu.js",
4451 "id": "menu.app.unhide", 4469 "id": "menu.app.unhide",
4452 "start": { 4470 "start": {
4453 "column": 10, 4471 "column": 10,
4454 "line": 179 4472 "line": 183
4455 } 4473 }
4456 }, 4474 },
4457 { 4475 {
4458 "defaultMessage": "!!!Quit", 4476 "defaultMessage": "!!!Quit",
4459 "end": { 4477 "end": {
4460 "column": 3, 4478 "column": 3,
4461 "line": 186 4479 "line": 190
4462 }, 4480 },
4463 "file": "src/lib/Menu.js", 4481 "file": "src/lib/Menu.js",
4464 "id": "menu.app.quit", 4482 "id": "menu.app.quit",
4465 "start": { 4483 "start": {
4466 "column": 8, 4484 "column": 8,
4467 "line": 183 4485 "line": 187
4468 } 4486 }
4469 }, 4487 },
4470 { 4488 {
4471 "defaultMessage": "!!!Add New Service...", 4489 "defaultMessage": "!!!Add New Service...",
4472 "end": { 4490 "end": {
4473 "column": 3, 4491 "column": 3,
4474 "line": 190 4492 "line": 194
4475 }, 4493 },
4476 "file": "src/lib/Menu.js", 4494 "file": "src/lib/Menu.js",
4477 "id": "menu.services.addNewService", 4495 "id": "menu.services.addNewService",
4478 "start": { 4496 "start": {
4479 "column": 17, 4497 "column": 17,
4480 "line": 187 4498 "line": 191
4481 } 4499 }
4482 }, 4500 },
4483 { 4501 {
4484 "defaultMessage": "!!!Add New Workspace...", 4502 "defaultMessage": "!!!Add New Workspace...",
4485 "end": { 4503 "end": {
4486 "column": 3, 4504 "column": 3,
4487 "line": 194 4505 "line": 198
4488 }, 4506 },
4489 "file": "src/lib/Menu.js", 4507 "file": "src/lib/Menu.js",
4490 "id": "menu.workspaces.addNewWorkspace", 4508 "id": "menu.workspaces.addNewWorkspace",
4491 "start": { 4509 "start": {
4492 "column": 19, 4510 "column": 19,
4493 "line": 191 4511 "line": 195
4494 } 4512 }
4495 }, 4513 },
4496 { 4514 {
4497 "defaultMessage": "!!!Open workspace drawer", 4515 "defaultMessage": "!!!Open workspace drawer",
4498 "end": { 4516 "end": {
4499 "column": 3, 4517 "column": 3,
4500 "line": 198 4518 "line": 202
4501 }, 4519 },
4502 "file": "src/lib/Menu.js", 4520 "file": "src/lib/Menu.js",
4503 "id": "menu.workspaces.openWorkspaceDrawer", 4521 "id": "menu.workspaces.openWorkspaceDrawer",
4504 "start": { 4522 "start": {
4505 "column": 23, 4523 "column": 23,
4506 "line": 195 4524 "line": 199
4507 } 4525 }
4508 }, 4526 },
4509 { 4527 {
4510 "defaultMessage": "!!!Close workspace drawer", 4528 "defaultMessage": "!!!Close workspace drawer",
4511 "end": { 4529 "end": {
4512 "column": 3, 4530 "column": 3,
4513 "line": 202 4531 "line": 206
4514 }, 4532 },
4515 "file": "src/lib/Menu.js", 4533 "file": "src/lib/Menu.js",
4516 "id": "menu.workspaces.closeWorkspaceDrawer", 4534 "id": "menu.workspaces.closeWorkspaceDrawer",
4517 "start": { 4535 "start": {
4518 "column": 24, 4536 "column": 24,
4519 "line": 199 4537 "line": 203
4520 } 4538 }
4521 }, 4539 },
4522 { 4540 {
4523 "defaultMessage": "!!!Activate next service...", 4541 "defaultMessage": "!!!Activate next service...",
4524 "end": { 4542 "end": {
4525 "column": 3, 4543 "column": 3,
4526 "line": 206 4544 "line": 210
4527 }, 4545 },
4528 "file": "src/lib/Menu.js", 4546 "file": "src/lib/Menu.js",
4529 "id": "menu.services.setNextServiceActive", 4547 "id": "menu.services.setNextServiceActive",
4530 "start": { 4548 "start": {
4531 "column": 23, 4549 "column": 23,
4532 "line": 203 4550 "line": 207
4533 } 4551 }
4534 }, 4552 },
4535 { 4553 {
4536 "defaultMessage": "!!!Activate previous service...", 4554 "defaultMessage": "!!!Activate previous service...",
4537 "end": { 4555 "end": {
4538 "column": 3, 4556 "column": 3,
4539 "line": 210 4557 "line": 214
4540 }, 4558 },
4541 "file": "src/lib/Menu.js", 4559 "file": "src/lib/Menu.js",
4542 "id": "menu.services.activatePreviousService", 4560 "id": "menu.services.activatePreviousService",
4543 "start": { 4561 "start": {
4544 "column": 27, 4562 "column": 27,
4545 "line": 207 4563 "line": 211
4546 } 4564 }
4547 }, 4565 },
4548 { 4566 {
4549 "defaultMessage": "!!!Disable notifications & audio", 4567 "defaultMessage": "!!!Disable notifications & audio",
4550 "end": { 4568 "end": {
4551 "column": 3, 4569 "column": 3,
4552 "line": 214 4570 "line": 218
4553 }, 4571 },
4554 "file": "src/lib/Menu.js", 4572 "file": "src/lib/Menu.js",
4555 "id": "sidebar.muteApp", 4573 "id": "sidebar.muteApp",
4556 "start": { 4574 "start": {
4557 "column": 11, 4575 "column": 11,
4558 "line": 211 4576 "line": 215
4559 } 4577 }
4560 }, 4578 },
4561 { 4579 {
4562 "defaultMessage": "!!!Enable notifications & audio", 4580 "defaultMessage": "!!!Enable notifications & audio",
4563 "end": { 4581 "end": {
4564 "column": 3, 4582 "column": 3,
4565 "line": 218 4583 "line": 222
4566 }, 4584 },
4567 "file": "src/lib/Menu.js", 4585 "file": "src/lib/Menu.js",
4568 "id": "sidebar.unmuteApp", 4586 "id": "sidebar.unmuteApp",
4569 "start": { 4587 "start": {
4570 "column": 13, 4588 "column": 13,
4571 "line": 215 4589 "line": 219
4572 } 4590 }
4573 }, 4591 },
4574 { 4592 {
4575 "defaultMessage": "!!!Workspaces", 4593 "defaultMessage": "!!!Workspaces",
4576 "end": { 4594 "end": {
4577 "column": 3, 4595 "column": 3,
4578 "line": 222 4596 "line": 226
4579 }, 4597 },
4580 "file": "src/lib/Menu.js", 4598 "file": "src/lib/Menu.js",
4581 "id": "menu.workspaces", 4599 "id": "menu.workspaces",
4582 "start": { 4600 "start": {
4583 "column": 14, 4601 "column": 14,
4584 "line": 219 4602 "line": 223
4585 } 4603 }
4586 }, 4604 },
4587 { 4605 {
4588 "defaultMessage": "!!!Default", 4606 "defaultMessage": "!!!Default",
4589 "end": { 4607 "end": {
4590 "column": 3, 4608 "column": 3,
4591 "line": 226 4609 "line": 230
4592 }, 4610 },
4593 "file": "src/lib/Menu.js", 4611 "file": "src/lib/Menu.js",
4594 "id": "menu.workspaces.defaultWorkspace", 4612 "id": "menu.workspaces.defaultWorkspace",
4595 "start": { 4613 "start": {
4596 "column": 20, 4614 "column": 20,
4597 "line": 223 4615 "line": 227
4598 } 4616 }
4599 } 4617 }
4600 ], 4618 ],
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 6c2759dcc..e2edbd596 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -45,6 +45,7 @@
45 "login.tokenExpired": "Your session expired, please login again.", 45 "login.tokenExpired": "Your session expired, please login again.",
46 "menu.app.about": "About Franz", 46 "menu.app.about": "About Franz",
47 "menu.app.announcement": "What's new?", 47 "menu.app.announcement": "What's new?",
48 "menu.app.checkForUpdates": "Check for updates",
48 "menu.app.hide": "Hide", 49 "menu.app.hide": "Hide",
49 "menu.app.hideOthers": "Hide Others", 50 "menu.app.hideOthers": "Hide Others",
50 "menu.app.quit": "Quit", 51 "menu.app.quit": "Quit",
diff --git a/src/i18n/messages/src/components/AppUpdateInfoBar.json b/src/i18n/messages/src/components/AppUpdateInfoBar.json
new file mode 100644
index 000000000..c4c2d0cae
--- /dev/null
+++ b/src/i18n/messages/src/components/AppUpdateInfoBar.json
@@ -0,0 +1,41 @@
1[
2 {
3 "id": "infobar.updateAvailable",
4 "defaultMessage": "!!!A new update for Franz is available.",
5 "file": "src/components/AppUpdateInfoBar.js",
6 "start": {
7 "line": 9,
8 "column": 19
9 },
10 "end": {
11 "line": 12,
12 "column": 3
13 }
14 },
15 {
16 "id": "infobar.buttonChangelog",
17 "defaultMessage": "!!!Changelog",
18 "file": "src/components/AppUpdateInfoBar.js",
19 "start": {
20 "line": 13,
21 "column": 13
22 },
23 "end": {
24 "line": 16,
25 "column": 3
26 }
27 },
28 {
29 "id": "infobar.buttonInstallUpdate",
30 "defaultMessage": "!!!Restart & install update",
31 "file": "src/components/AppUpdateInfoBar.js",
32 "start": {
33 "line": 17,
34 "column": 23
35 },
36 "end": {
37 "line": 20,
38 "column": 3
39 }
40 }
41] \ 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 4dd354afc..190c5dff7 100644
--- a/src/i18n/messages/src/components/layout/AppLayout.json
+++ b/src/i18n/messages/src/components/layout/AppLayout.json
@@ -13,54 +13,15 @@
13 } 13 }
14 }, 14 },
15 { 15 {
16 "id": "infobar.updateAvailable",
17 "defaultMessage": "!!!A new update for Franz is available.",
18 "file": "src/components/layout/AppLayout.js",
19 "start": {
20 "line": 30,
21 "column": 19
22 },
23 "end": {
24 "line": 33,
25 "column": 3
26 }
27 },
28 {
29 "id": "infobar.buttonReloadServices", 16 "id": "infobar.buttonReloadServices",
30 "defaultMessage": "!!!Reload services", 17 "defaultMessage": "!!!Reload services",
31 "file": "src/components/layout/AppLayout.js", 18 "file": "src/components/layout/AppLayout.js",
32 "start": { 19 "start": {
33 "line": 34, 20 "line": 30,
34 "column": 24 21 "column": 24
35 }, 22 },
36 "end": { 23 "end": {
37 "line": 37, 24 "line": 33,
38 "column": 3
39 }
40 },
41 {
42 "id": "infobar.buttonChangelog",
43 "defaultMessage": "!!!Changelog",
44 "file": "src/components/layout/AppLayout.js",
45 "start": {
46 "line": 38,
47 "column": 13
48 },
49 "end": {
50 "line": 41,
51 "column": 3
52 }
53 },
54 {
55 "id": "infobar.buttonInstallUpdate",
56 "defaultMessage": "!!!Restart & install update",
57 "file": "src/components/layout/AppLayout.js",
58 "start": {
59 "line": 42,
60 "column": 23
61 },
62 "end": {
63 "line": 45,
64 "column": 3 25 "column": 3
65 } 26 }
66 }, 27 },
@@ -69,11 +30,11 @@
69 "defaultMessage": "!!!Could not load services and user information", 30 "defaultMessage": "!!!Could not load services and user information",
70 "file": "src/components/layout/AppLayout.js", 31 "file": "src/components/layout/AppLayout.js",
71 "start": { 32 "start": {
72 "line": 46, 33 "line": 34,
73 "column": 26 34 "column": 26
74 }, 35 },
75 "end": { 36 "end": {
76 "line": 49, 37 "line": 37,
77 "column": 3 38 "column": 3
78 } 39 }
79 } 40 }
diff --git a/src/i18n/messages/src/lib/Menu.json b/src/i18n/messages/src/lib/Menu.json
index 2adf5b787..daafb0900 100644
--- a/src/i18n/messages/src/lib/Menu.json
+++ b/src/i18n/messages/src/lib/Menu.json
@@ -507,15 +507,28 @@
507 } 507 }
508 }, 508 },
509 { 509 {
510 "id": "menu.app.checkForUpdates",
511 "defaultMessage": "!!!Check for updates",
512 "file": "src/lib/Menu.js",
513 "start": {
514 "line": 171,
515 "column": 19
516 },
517 "end": {
518 "line": 174,
519 "column": 3
520 }
521 },
522 {
510 "id": "menu.app.hide", 523 "id": "menu.app.hide",
511 "defaultMessage": "!!!Hide", 524 "defaultMessage": "!!!Hide",
512 "file": "src/lib/Menu.js", 525 "file": "src/lib/Menu.js",
513 "start": { 526 "start": {
514 "line": 171, 527 "line": 175,
515 "column": 8 528 "column": 8
516 }, 529 },
517 "end": { 530 "end": {
518 "line": 174, 531 "line": 178,
519 "column": 3 532 "column": 3
520 } 533 }
521 }, 534 },
@@ -524,11 +537,11 @@
524 "defaultMessage": "!!!Hide Others", 537 "defaultMessage": "!!!Hide Others",
525 "file": "src/lib/Menu.js", 538 "file": "src/lib/Menu.js",
526 "start": { 539 "start": {
527 "line": 175, 540 "line": 179,
528 "column": 14 541 "column": 14
529 }, 542 },
530 "end": { 543 "end": {
531 "line": 178, 544 "line": 182,
532 "column": 3 545 "column": 3
533 } 546 }
534 }, 547 },
@@ -537,11 +550,11 @@
537 "defaultMessage": "!!!Unhide", 550 "defaultMessage": "!!!Unhide",
538 "file": "src/lib/Menu.js", 551 "file": "src/lib/Menu.js",
539 "start": { 552 "start": {
540 "line": 179, 553 "line": 183,
541 "column": 10 554 "column": 10
542 }, 555 },
543 "end": { 556 "end": {
544 "line": 182, 557 "line": 186,
545 "column": 3 558 "column": 3
546 } 559 }
547 }, 560 },
@@ -550,11 +563,11 @@
550 "defaultMessage": "!!!Quit", 563 "defaultMessage": "!!!Quit",
551 "file": "src/lib/Menu.js", 564 "file": "src/lib/Menu.js",
552 "start": { 565 "start": {
553 "line": 183, 566 "line": 187,
554 "column": 8 567 "column": 8
555 }, 568 },
556 "end": { 569 "end": {
557 "line": 186, 570 "line": 190,
558 "column": 3 571 "column": 3
559 } 572 }
560 }, 573 },
@@ -563,11 +576,11 @@
563 "defaultMessage": "!!!Add New Service...", 576 "defaultMessage": "!!!Add New Service...",
564 "file": "src/lib/Menu.js", 577 "file": "src/lib/Menu.js",
565 "start": { 578 "start": {
566 "line": 187, 579 "line": 191,
567 "column": 17 580 "column": 17
568 }, 581 },
569 "end": { 582 "end": {
570 "line": 190, 583 "line": 194,
571 "column": 3 584 "column": 3
572 } 585 }
573 }, 586 },
@@ -576,11 +589,11 @@
576 "defaultMessage": "!!!Add New Workspace...", 589 "defaultMessage": "!!!Add New Workspace...",
577 "file": "src/lib/Menu.js", 590 "file": "src/lib/Menu.js",
578 "start": { 591 "start": {
579 "line": 191, 592 "line": 195,
580 "column": 19 593 "column": 19
581 }, 594 },
582 "end": { 595 "end": {
583 "line": 194, 596 "line": 198,
584 "column": 3 597 "column": 3
585 } 598 }
586 }, 599 },
@@ -589,11 +602,11 @@
589 "defaultMessage": "!!!Open workspace drawer", 602 "defaultMessage": "!!!Open workspace drawer",
590 "file": "src/lib/Menu.js", 603 "file": "src/lib/Menu.js",
591 "start": { 604 "start": {
592 "line": 195, 605 "line": 199,
593 "column": 23 606 "column": 23
594 }, 607 },
595 "end": { 608 "end": {
596 "line": 198, 609 "line": 202,
597 "column": 3 610 "column": 3
598 } 611 }
599 }, 612 },
@@ -602,11 +615,11 @@
602 "defaultMessage": "!!!Close workspace drawer", 615 "defaultMessage": "!!!Close workspace drawer",
603 "file": "src/lib/Menu.js", 616 "file": "src/lib/Menu.js",
604 "start": { 617 "start": {
605 "line": 199, 618 "line": 203,
606 "column": 24 619 "column": 24
607 }, 620 },
608 "end": { 621 "end": {
609 "line": 202, 622 "line": 206,
610 "column": 3 623 "column": 3
611 } 624 }
612 }, 625 },
@@ -615,11 +628,11 @@
615 "defaultMessage": "!!!Activate next service...", 628 "defaultMessage": "!!!Activate next service...",
616 "file": "src/lib/Menu.js", 629 "file": "src/lib/Menu.js",
617 "start": { 630 "start": {
618 "line": 203, 631 "line": 207,
619 "column": 23 632 "column": 23
620 }, 633 },
621 "end": { 634 "end": {
622 "line": 206, 635 "line": 210,
623 "column": 3 636 "column": 3
624 } 637 }
625 }, 638 },
@@ -628,11 +641,11 @@
628 "defaultMessage": "!!!Activate previous service...", 641 "defaultMessage": "!!!Activate previous service...",
629 "file": "src/lib/Menu.js", 642 "file": "src/lib/Menu.js",
630 "start": { 643 "start": {
631 "line": 207, 644 "line": 211,
632 "column": 27 645 "column": 27
633 }, 646 },
634 "end": { 647 "end": {
635 "line": 210, 648 "line": 214,
636 "column": 3 649 "column": 3
637 } 650 }
638 }, 651 },
@@ -641,11 +654,11 @@
641 "defaultMessage": "!!!Disable notifications & audio", 654 "defaultMessage": "!!!Disable notifications & audio",
642 "file": "src/lib/Menu.js", 655 "file": "src/lib/Menu.js",
643 "start": { 656 "start": {
644 "line": 211, 657 "line": 215,
645 "column": 11 658 "column": 11
646 }, 659 },
647 "end": { 660 "end": {
648 "line": 214, 661 "line": 218,
649 "column": 3 662 "column": 3
650 } 663 }
651 }, 664 },
@@ -654,11 +667,11 @@
654 "defaultMessage": "!!!Enable notifications & audio", 667 "defaultMessage": "!!!Enable notifications & audio",
655 "file": "src/lib/Menu.js", 668 "file": "src/lib/Menu.js",
656 "start": { 669 "start": {
657 "line": 215, 670 "line": 219,
658 "column": 13 671 "column": 13
659 }, 672 },
660 "end": { 673 "end": {
661 "line": 218, 674 "line": 222,
662 "column": 3 675 "column": 3
663 } 676 }
664 }, 677 },
@@ -667,11 +680,11 @@
667 "defaultMessage": "!!!Workspaces", 680 "defaultMessage": "!!!Workspaces",
668 "file": "src/lib/Menu.js", 681 "file": "src/lib/Menu.js",
669 "start": { 682 "start": {
670 "line": 219, 683 "line": 223,
671 "column": 14 684 "column": 14
672 }, 685 },
673 "end": { 686 "end": {
674 "line": 222, 687 "line": 226,
675 "column": 3 688 "column": 3
676 } 689 }
677 }, 690 },
@@ -680,11 +693,11 @@
680 "defaultMessage": "!!!Default", 693 "defaultMessage": "!!!Default",
681 "file": "src/lib/Menu.js", 694 "file": "src/lib/Menu.js",
682 "start": { 695 "start": {
683 "line": 223, 696 "line": 227,
684 "column": 20 697 "column": 20
685 }, 698 },
686 "end": { 699 "end": {
687 "line": 226, 700 "line": 230,
688 "column": 3 701 "column": 3
689 } 702 }
690 } 703 }
diff --git a/src/lib/Menu.js b/src/lib/Menu.js
index 061c83160..e0dfd736e 100644
--- a/src/lib/Menu.js
+++ b/src/lib/Menu.js
@@ -168,6 +168,10 @@ const menuItems = defineMessages({
168 id: 'menu.app.settings', 168 id: 'menu.app.settings',
169 defaultMessage: '!!!Settings', 169 defaultMessage: '!!!Settings',
170 }, 170 },
171 checkForUpdates: {
172 id: 'menu.app.checkForUpdates',
173 defaultMessage: '!!!Check for updates',
174 },
171 hide: { 175 hide: {
172 id: 'menu.app.hide', 176 id: 'menu.app.hide',
173 defaultMessage: '!!!Hide', 177 defaultMessage: '!!!Hide',
@@ -643,6 +647,12 @@ export default class FranzMenu {
643 enabled: this.stores.user.isLoggedIn, 647 enabled: this.stores.user.isLoggedIn,
644 }, 648 },
645 { 649 {
650 label: intl.formatMessage(menuItems.checkForUpdates),
651 click: () => {
652 this.actions.app.checkForUpdates();
653 },
654 },
655 {
646 type: 'separator', 656 type: 'separator',
647 }, 657 },
648 { 658 {