aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/layout
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/layout')
-rw-r--r--src/components/layout/AppLayout.js24
-rw-r--r--src/components/layout/Sidebar.js137
2 files changed, 105 insertions, 56 deletions
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index 200777ae6..e82275b9f 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -6,7 +6,6 @@ import { TitleBar } from 'electron-react-titlebar';
6import injectSheet from 'react-jss'; 6import injectSheet from 'react-jss';
7 7
8import InfoBar from '../ui/InfoBar'; 8import InfoBar from '../ui/InfoBar';
9import { Component as DelayApp } from '../../features/delayApp';
10import { Component as BasicAuth } from '../../features/basicAuth'; 9import { Component as BasicAuth } from '../../features/basicAuth';
11import { Component as ShareFranz } from '../../features/shareFranz'; 10import { Component as ShareFranz } from '../../features/shareFranz';
12import ErrorBoundary from '../util/ErrorBoundary'; 11import ErrorBoundary from '../util/ErrorBoundary';
@@ -37,6 +36,10 @@ const messages = defineMessages({
37 id: 'infobar.requiredRequestsFailed', 36 id: 'infobar.requiredRequestsFailed',
38 defaultMessage: '!!!Could not load services and user information', 37 defaultMessage: '!!!Could not load services and user information',
39 }, 38 },
39 authRequestFailed: {
40 id: 'infobar.authRequestFailed',
41 defaultMessage: '!!!There were errors while trying to perform an authenticated request. Please try logging out and back in if this error persists.',
42 },
40}); 43});
41 44
42const styles = theme => ({ 45const styles = theme => ({
@@ -63,6 +66,7 @@ class AppLayout extends Component {
63 showServicesUpdatedInfoBar: PropTypes.bool.isRequired, 66 showServicesUpdatedInfoBar: PropTypes.bool.isRequired,
64 appUpdateIsDownloaded: PropTypes.bool.isRequired, 67 appUpdateIsDownloaded: PropTypes.bool.isRequired,
65 nextAppReleaseVersion: PropTypes.string, 68 nextAppReleaseVersion: PropTypes.string,
69 authRequestFailed: PropTypes.bool.isRequired,
66 removeNewsItem: PropTypes.func.isRequired, 70 removeNewsItem: PropTypes.func.isRequired,
67 reloadServicesAfterUpdate: PropTypes.func.isRequired, 71 reloadServicesAfterUpdate: PropTypes.func.isRequired,
68 installAppUpdate: PropTypes.func.isRequired, 72 installAppUpdate: PropTypes.func.isRequired,
@@ -70,7 +74,6 @@ class AppLayout extends Component {
70 areRequiredRequestsSuccessful: PropTypes.bool.isRequired, 74 areRequiredRequestsSuccessful: PropTypes.bool.isRequired,
71 retryRequiredRequests: PropTypes.func.isRequired, 75 retryRequiredRequests: PropTypes.func.isRequired,
72 areRequiredRequestsLoading: PropTypes.bool.isRequired, 76 areRequiredRequestsLoading: PropTypes.bool.isRequired,
73 isDelayAppScreenVisible: PropTypes.bool.isRequired,
74 hasActivatedTrial: PropTypes.bool.isRequired, 77 hasActivatedTrial: PropTypes.bool.isRequired,
75 }; 78 };
76 79
@@ -95,6 +98,7 @@ class AppLayout extends Component {
95 showServicesUpdatedInfoBar, 98 showServicesUpdatedInfoBar,
96 appUpdateIsDownloaded, 99 appUpdateIsDownloaded,
97 nextAppReleaseVersion, 100 nextAppReleaseVersion,
101 authRequestFailed,
98 removeNewsItem, 102 removeNewsItem,
99 reloadServicesAfterUpdate, 103 reloadServicesAfterUpdate,
100 installAppUpdate, 104 installAppUpdate,
@@ -102,7 +106,6 @@ class AppLayout extends Component {
102 areRequiredRequestsSuccessful, 106 areRequiredRequestsSuccessful,
103 retryRequiredRequests, 107 retryRequiredRequests,
104 areRequiredRequestsLoading, 108 areRequiredRequestsLoading,
105 isDelayAppScreenVisible,
106 hasActivatedTrial, 109 hasActivatedTrial,
107 } = this.props; 110 } = this.props;
108 111
@@ -111,7 +114,7 @@ class AppLayout extends Component {
111 return ( 114 return (
112 <ErrorBoundary> 115 <ErrorBoundary>
113 <div className="app"> 116 <div className="app">
114 {isWindows && !isFullScreen && <TitleBar menu={window.franz.menu.template} icon="assets/images/logo.svg" />} 117 {isWindows && !isFullScreen && <TitleBar menu={window.ferdi.menu.template} icon="assets/images/logo.svg" />}
115 <div className={`app__content ${classes.appContent}`}> 118 <div className={`app__content ${classes.appContent}`}>
116 {workspacesDrawer} 119 {workspacesDrawer}
117 {sidebar} 120 {sidebar}
@@ -151,6 +154,18 @@ class AppLayout extends Component {
151 {intl.formatMessage(messages.requiredRequestsFailed)} 154 {intl.formatMessage(messages.requiredRequestsFailed)}
152 </InfoBar> 155 </InfoBar>
153 )} 156 )}
157 {authRequestFailed && (
158 <InfoBar
159 type="danger"
160 ctaLabel="Try again"
161 ctaLoading={areRequiredRequestsLoading}
162 sticky
163 onClick={retryRequiredRequests}
164 >
165 <span className="mdi mdi-flash" />
166 {intl.formatMessage(messages.authRequestFailed)}
167 </InfoBar>
168 )}
154 {showServicesUpdatedInfoBar && ( 169 {showServicesUpdatedInfoBar && (
155 <InfoBar 170 <InfoBar
156 type="primary" 171 type="primary"
@@ -168,7 +183,6 @@ class AppLayout extends Component {
168 onInstallUpdate={installAppUpdate} 183 onInstallUpdate={installAppUpdate}
169 /> 184 />
170 )} 185 )}
171 {isDelayAppScreenVisible && (<DelayApp />)}
172 <BasicAuth /> 186 <BasicAuth />
173 <ShareFranz /> 187 <ShareFranz />
174 {services} 188 {services}
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js
index 918298011..52de16508 100644
--- a/src/components/layout/Sidebar.js
+++ b/src/components/layout/Sidebar.js
@@ -2,13 +2,13 @@ import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import ReactTooltip from 'react-tooltip'; 3import ReactTooltip from 'react-tooltip';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import { observer } from 'mobx-react'; 5import { inject, observer } from 'mobx-react';
6import { Link } from 'react-router';
6 7
7import Tabbar from '../services/tabs/Tabbar'; 8import Tabbar from '../services/tabs/Tabbar';
8import { ctrlKey } from '../../environment'; 9import { ctrlKey } from '../../environment';
9import { GA_CATEGORY_WORKSPACES, workspaceStore } from '../../features/workspaces'; 10import { workspaceStore } from '../../features/workspaces';
10import { gaEvent } from '../../lib/analytics'; 11import { todosStore } from '../../features/todos';
11import { todosStore, GA_CATEGORY_TODOS } from '../../features/todos';
12import { todoActions } from '../../features/todos/actions'; 12import { todoActions } from '../../features/todos/actions';
13 13
14const messages = defineMessages({ 14const messages = defineMessages({
@@ -44,9 +44,13 @@ const messages = defineMessages({
44 id: 'sidebar.closeTodosDrawer', 44 id: 'sidebar.closeTodosDrawer',
45 defaultMessage: '!!!Close Franz Todos', 45 defaultMessage: '!!!Close Franz Todos',
46 }, 46 },
47 lockFerdi: {
48 id: 'sidebar.lockFerdi',
49 defaultMessage: '!!!Lock Ferdi',
50 },
47}); 51});
48 52
49export default @observer class Sidebar extends Component { 53export default @inject('stores', 'actions') @observer class Sidebar extends Component {
50 static propTypes = { 54 static propTypes = {
51 openSettings: PropTypes.func.isRequired, 55 openSettings: PropTypes.func.isRequired,
52 toggleMuteApp: PropTypes.func.isRequired, 56 toggleMuteApp: PropTypes.func.isRequired,
@@ -87,6 +91,8 @@ export default @observer class Sidebar extends Component {
87 isAppMuted, 91 isAppMuted,
88 isWorkspaceDrawerOpen, 92 isWorkspaceDrawerOpen,
89 toggleWorkspaceDrawer, 93 toggleWorkspaceDrawer,
94 stores,
95 actions,
90 } = this.props; 96 } = this.props;
91 const { intl } = this.context; 97 const { intl } = this.context;
92 const todosToggleMessage = ( 98 const todosToggleMessage = (
@@ -96,6 +102,7 @@ export default @observer class Sidebar extends Component {
96 const workspaceToggleMessage = ( 102 const workspaceToggleMessage = (
97 isWorkspaceDrawerOpen ? messages.closeWorkspaceDrawer : messages.openWorkspaceDrawer 103 isWorkspaceDrawerOpen ? messages.closeWorkspaceDrawer : messages.openWorkspaceDrawer
98 ); 104 );
105 const isLoggedIn = Boolean(localStorage.getItem('authToken'));
99 106
100 return ( 107 return (
101 <div className="sidebar"> 108 <div className="sidebar">
@@ -104,53 +111,81 @@ export default @observer class Sidebar extends Component {
104 enableToolTip={() => this.enableToolTip()} 111 enableToolTip={() => this.enableToolTip()}
105 disableToolTip={() => this.disableToolTip()} 112 disableToolTip={() => this.disableToolTip()}
106 /> 113 />
107 {todosStore.isFeatureEnabled && todosStore.isFeatureEnabledByUser ? ( 114 { isLoggedIn ? (
108 <button 115 <>
109 type="button" 116 { stores.settings.all.app.lockingFeatureEnabled ? (
110 onClick={() => { 117 <button
111 todoActions.toggleTodosPanel(); 118 type="button"
112 this.updateToolTip(); 119 className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`}
113 gaEvent(GA_CATEGORY_TODOS, 'toggleDrawer', 'sidebar'); 120 onClick={() => {
114 }} 121 actions.settings.update({
115 className={`sidebar__button sidebar__button--todos ${todosStore.isTodosPanelVisible ? 'is-active' : ''}`} 122 type: 'app',
116 data-tip={`${intl.formatMessage(todosToggleMessage)} (${ctrlKey}+T)`} 123 data: {
117 > 124 locked: true,
118 <i className="mdi mdi-check-all" /> 125 },
119 </button> 126 });
120 ) : null} 127 }}
121 {workspaceStore.isFeatureEnabled ? ( 128 data-tip={`${intl.formatMessage(messages.lockFerdi)} (${ctrlKey}+Shift+L)`}
122 <button 129 >
123 type="button" 130 <i className="mdi mdi-lock" />
124 onClick={() => { 131 </button>
125 toggleWorkspaceDrawer(); 132 ) : null}
126 this.updateToolTip(); 133 {todosStore.isFeatureEnabled && todosStore.isFeatureEnabledByUser ? (
127 gaEvent(GA_CATEGORY_WORKSPACES, 'toggleDrawer', 'sidebar'); 134 <button
128 }} 135 type="button"
129 className={`sidebar__button sidebar__button--workspaces ${isWorkspaceDrawerOpen ? 'is-active' : ''}`} 136 onClick={() => {
130 data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${ctrlKey}+D)`} 137 todoActions.toggleTodosPanel();
138 this.updateToolTip();
139 gaEvent(GA_CATEGORY_TODOS, 'toggleDrawer', 'sidebar');
140 }}
141 className={`sidebar__button sidebar__button--todos ${todosStore.isTodosPanelVisible ? 'is-active' : ''}`}
142 data-tip={`${intl.formatMessage(todosToggleMessage)} (${ctrlKey}+T)`}
143 >
144 <i className="mdi mdi-check-all" />
145 </button>
146 ) : null}
147 {workspaceStore.isFeatureEnabled ? (
148 <button
149 type="button"
150 onClick={() => {
151 toggleWorkspaceDrawer();
152 this.updateToolTip();
153 }}
154 className={`sidebar__button sidebar__button--workspaces ${isWorkspaceDrawerOpen ? 'is-active' : ''}`}
155 data-tip={`${intl.formatMessage(workspaceToggleMessage)} (${ctrlKey}+D)`}
156 >
157 <i className="mdi mdi-view-grid" />
158 </button>
159 ) : null}
160 <button
161 type="button"
162 onClick={() => {
163 toggleMuteApp();
164 this.updateToolTip();
165 }}
166 className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`}
167 data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${ctrlKey}+Shift+M)`}
168 >
169 <i className={`mdi mdi-bell${isAppMuted ? '-off' : ''}`} />
170 </button>
171 <button
172 type="button"
173 onClick={() => openSettings({ path: 'recipes' })}
174 className="sidebar__button sidebar__button--new-service"
175 data-tip={`${intl.formatMessage(messages.addNewService)} (${ctrlKey}+N)`}
176 >
177 <i className="mdi mdi-plus-box" />
178 </button>
179 </>
180 ) : (
181 <Link
182 to="/auth/welcome"
183 className="sidebar__button sidebar__button--new-service"
184 data-tip="Login"
131 > 185 >
132 <i className="mdi mdi-view-grid" /> 186 <i className="mdi mdi-login-variant" />
133 </button> 187 </Link>
134 ) : null} 188 )}
135 <button
136 type="button"
137 onClick={() => {
138 toggleMuteApp();
139 this.updateToolTip();
140 }}
141 className={`sidebar__button sidebar__button--audio ${isAppMuted ? 'is-muted' : ''}`}
142 data-tip={`${intl.formatMessage(isAppMuted ? messages.unmute : messages.mute)} (${ctrlKey}+Shift+M)`}
143 >
144 <i className={`mdi mdi-bell${isAppMuted ? '-off' : ''}`} />
145 </button>
146 <button
147 type="button"
148 onClick={() => openSettings({ path: 'recipes' })}
149 className="sidebar__button sidebar__button--new-service"
150 data-tip={`${intl.formatMessage(messages.addNewService)} (${ctrlKey}+N)`}
151 >
152 <i className="mdi mdi-plus-box" />
153 </button>
154 <button 189 <button
155 type="button" 190 type="button"
156 onClick={() => openSettings({ path: 'app' })} 191 onClick={() => openSettings({ path: 'app' })}