From 2d0c9c537f7b69838f0cdc5ed6547a0c4ddc7d93 Mon Sep 17 00:00:00 2001 From: David Kaltschmidt Date: Mon, 1 Aug 2016 15:02:34 +0200 Subject: [PATCH 1/2] Adds PrivatePage container to wrap internal components * PrivatePage wraps components that are only accessible when logged in * PrivatePage contains the toolbar * It does a cookie-check and redirects to login when no cookie Fixes #702 Fixes #679 --- .../client/src/components/private-page.jsx | 54 ++++++++++++++++++ ui-server/client/src/components/toolbar.jsx | 31 +++++++--- ui-server/client/src/pages/account/page.jsx | 24 ++------ ui-server/client/src/pages/instances/page.jsx | 53 ++---------------- .../client/src/pages/organization/page.jsx | 20 ++----- ui-server/client/src/pages/wrapper/page.jsx | 56 +++---------------- 6 files changed, 98 insertions(+), 140 deletions(-) create mode 100644 ui-server/client/src/components/private-page.jsx diff --git a/ui-server/client/src/components/private-page.jsx b/ui-server/client/src/components/private-page.jsx new file mode 100644 index 000000000..80f57dad4 --- /dev/null +++ b/ui-server/client/src/components/private-page.jsx @@ -0,0 +1,54 @@ +import React from 'react'; + +import { getInstance } from '../common/api'; +import { trackException } from '../common/tracking'; +import Toolbar from './toolbar'; + +export default class PrivatePage extends React.Component { + + constructor() { + super(); + this.state = { + instance: null + }; + + this.handleInstanceSuccess = this.handleInstanceSuccess.bind(this); + this.handleInstanceError = this.handleInstanceError.bind(this); + } + + handleInstanceSuccess(instance) { + this.setState({ instance }); + } + + handleInstanceError(res) { + trackException(res); + } + + componentDidMount() { + if (this.props.orgId) { + // includes a cookie check + getInstance(this.props.orgId) + .then(this.handleInstanceSuccess) + .catch(this.handleInstanceError); + } + } + + render() { + const styles = { + backgroundContainer: { + height: '100%', + position: 'relative' + } + }; + + return ( +
+ + {this.props.children} +
+ ); + } +} diff --git a/ui-server/client/src/components/toolbar.jsx b/ui-server/client/src/components/toolbar.jsx index 717cd9655..613d5b7d4 100644 --- a/ui-server/client/src/components/toolbar.jsx +++ b/ui-server/client/src/components/toolbar.jsx @@ -5,6 +5,7 @@ import Paper from 'material-ui/Paper'; import { encodeURIs } from '../common/request'; import Colors from '../common/colors'; +import { Logo } from './logo'; export default class Toolbar extends React.Component { @@ -12,15 +13,15 @@ export default class Toolbar extends React.Component { return [{ iconClass: 'fa fa-cog', title: 'Settings for this instance', - route: encodeURIs`#/org/${this.props.organization}` + route: encodeURIs`#/org/${this.props.orgId}` }, { title: 'Manage instances', iconClass: 'fa fa-cubes', - route: encodeURIs`#/instance/${this.props.organization}` + route: encodeURIs`#/instance/${this.props.orgId}` }, { title: 'User account', iconClass: 'fa fa-user', - route: encodeURIs`#/account/${this.props.organization}` + route: encodeURIs`#/account/${this.props.orgId}` }]; } @@ -61,11 +62,19 @@ export default class Toolbar extends React.Component { height: 50, }, toolbar: { + display: 'flex', + justifyContent: 'space-between', width: '100%' }, + toolbarCenter: { + padding: 15 + }, toolbarLeft: { - float: 'left', - padding: '16px 24px' + top: 2, + left: 12, + padding: 8, + width: 160, + position: 'relative' }, toolbarOrganization: { color: Colors.text2, @@ -79,7 +88,6 @@ export default class Toolbar extends React.Component { marginLeft: '0.5em' }, toolbarRight: { - float: 'right', padding: 15, }, toolbarWrapper: { @@ -96,14 +104,19 @@ export default class Toolbar extends React.Component {
- + +
+
+
+ {this.props.instance && View Instance - {this.props.organization} + {this.props.instance.name} - + }
{links} diff --git a/ui-server/client/src/pages/account/page.jsx b/ui-server/client/src/pages/account/page.jsx index 3d29a2d7f..58e4e3ae6 100644 --- a/ui-server/client/src/pages/account/page.jsx +++ b/ui-server/client/src/pages/account/page.jsx @@ -8,9 +8,8 @@ import FontIcon from 'material-ui/FontIcon'; import { FlexContainer } from '../../components/flex-container'; import { Column } from '../../components/column'; -import { Logo } from '../../components/logo'; import Logins from './logins'; -import Toolbar from '../../components/toolbar'; +import PrivatePage from '../../components/private-page'; import { trackView, trackException } from '../../common/tracking'; import { getOrganizations } from '../../common/api'; @@ -66,14 +65,7 @@ export default class AccountPage extends React.Component { textAlign: 'center' }, container: { - marginTop: 128 - }, - logoWrapper: { - position: 'absolute', - width: 250, - height: 64, - left: 64, - top: 32 + 51 - 3 + marginTop: 32 }, avatar: { top: 19, @@ -82,7 +74,6 @@ export default class AccountPage extends React.Component { } }; - const orgId = this.props.params.orgId; const logoutButton = ( ); return ( -
- -
- -
+
@@ -121,7 +105,7 @@ export default class AccountPage extends React.Component {
-
+ ); } diff --git a/ui-server/client/src/pages/instances/page.jsx b/ui-server/client/src/pages/instances/page.jsx index 251fdb372..e585db8e8 100644 --- a/ui-server/client/src/pages/instances/page.jsx +++ b/ui-server/client/src/pages/instances/page.jsx @@ -1,53 +1,17 @@ import React from 'react'; -import { hashHistory } from 'react-router'; import { FlexContainer } from '../../components/flex-container'; import { Column } from '../../components/column'; -import { Logo } from '../../components/logo'; import InstancesList from '../instances/instances-list'; -import Toolbar from '../../components/toolbar'; -import { trackView, trackException } from '../../common/tracking'; -import { getOrganizations } from '../../common/api'; +import PrivatePage from '../../components/private-page'; +import { trackView } from '../../common/tracking'; export default class InstancesPage extends React.Component { - constructor() { - super(); - this.state = { - user: '', - organizations: [], - }; - - this.checkCookie = this.checkCookie.bind(this); - this.handleLoginSuccess = this.handleLoginSuccess.bind(this); - this.handleLoginError = this.handleLoginError.bind(this); - } - componentDidMount() { - this.checkCookie(); trackView('Instances'); } - checkCookie() { - return getOrganizations().then(this.handleLoginSuccess, this.handleLoginError); - } - - handleLoginSuccess(resp) { - this.setState({ - user: resp.email, - organizations: resp.organizations - }); - } - - handleLoginError(resp) { - if (resp.status === 401) { - hashHistory.push('/login'); - } else { - const err = resp.errors[0]; - trackException(err.message); - } - } - render() { const styles = { activity: { @@ -55,7 +19,7 @@ export default class InstancesPage extends React.Component { textAlign: 'center' }, container: { - marginTop: 128 + marginTop: 32 }, logoWrapper: { position: 'absolute', @@ -69,14 +33,7 @@ export default class InstancesPage extends React.Component { const orgId = this.props.params.orgId; return ( -
- -
- -
+
@@ -87,7 +44,7 @@ export default class InstancesPage extends React.Component {
-
+ ); } diff --git a/ui-server/client/src/pages/organization/page.jsx b/ui-server/client/src/pages/organization/page.jsx index 887a39de8..4a87aa623 100644 --- a/ui-server/client/src/pages/organization/page.jsx +++ b/ui-server/client/src/pages/organization/page.jsx @@ -13,12 +13,11 @@ import { getData, encodeURIs } from '../../common/request'; import { Box } from '../../components/box'; import { FlexContainer } from '../../components/flex-container'; import { Column } from '../../components/column'; -import { Logo } from '../../components/logo'; import InstancesDelete from '../instances/instances-delete'; +import PrivatePage from '../../components/private-page'; import Probes from './probes'; import Users from './users'; import Name from './name'; -import Toolbar from '../../components/toolbar'; import { trackEvent, trackException, trackView } from '../../common/tracking'; export default class OrganizationPage extends React.Component { @@ -142,7 +141,7 @@ export default class OrganizationPage extends React.Component { marginBottom: 24 }, container: { - marginTop: 96 + marginTop: 32 }, help: { borderTop: `2px dotted ${grey200}`, @@ -160,13 +159,6 @@ export default class OrganizationPage extends React.Component { display: this.state.showHelp ? 'block' : 'none', marginLeft: '-1em' }, - logoWrapper: { - position: 'absolute', - width: 250, - height: 64, - left: 64, - top: 32 + 51 - 3 - }, circle: { position: 'absolute', left: -56, @@ -194,7 +186,7 @@ export default class OrganizationPage extends React.Component { }; return ( -
+ - -
- -
{this.state.id &&
@@ -298,7 +286,7 @@ export default class OrganizationPage extends React.Component {
}
} -
+ ); } diff --git a/ui-server/client/src/pages/wrapper/page.jsx b/ui-server/client/src/pages/wrapper/page.jsx index 34e581592..10897380e 100644 --- a/ui-server/client/src/pages/wrapper/page.jsx +++ b/ui-server/client/src/pages/wrapper/page.jsx @@ -3,10 +3,9 @@ import React from 'react'; import ReactDOM from 'react-dom'; import CircularProgress from 'material-ui/CircularProgress'; import debug from 'debug'; -import { hashHistory } from 'react-router'; import { getData, encodeURIs } from '../../common/request'; -import Toolbar from '../../components/toolbar'; +import PrivatePage from '../../components/private-page'; import { trackView } from '../../common/tracking'; const log = debug('service:wrapper'); @@ -18,23 +17,18 @@ export default class Wrapper extends React.Component { this.state = { activityText: '', - frameBaseUrl: '', - id: '', - user: '' + frameBaseUrl: '' }; - this._checkCookie = this._checkCookie.bind(this); this._checkInstance = this._checkInstance.bind(this); this._handleInstanceError = this._handleInstanceError.bind(this); this._handleInstanceSuccess = this._handleInstanceSuccess.bind(this); - this._handleLoginSuccess = this._handleLoginSuccess.bind(this); - this._handleLoginError = this._handleLoginError.bind(this); this._handleFrameLoad = this._handleFrameLoad.bind(this); } componentDidMount() { - // check if we're logged in - this._checkCookie(); + // check if scope instance is ready + this._checkInstance(); trackView('Wrapper'); } @@ -65,44 +59,13 @@ export default class Wrapper extends React.Component { _onFrameStateChanged() { } - _checkCookie() { - const url = encodeURIs`/api/users/org/${this.props.params.orgId}`; - getData(url).then(this._handleLoginSuccess, this._handleLoginError); - } - - _checkInstance(id) { - const org = id || this.state.id; - const url = encodeURIs`/api/app/${org}/api`; + _checkInstance() { + const url = encodeURIs`/api/app/${this.props.params.orgId}/api`; getData(url).then(this._handleInstanceSuccess, this._handleInstanceError); } - _handleLoginSuccess(resp) { - this.setState({ - user: resp.user, - id: resp.id - }); - // check if scope instance is ready - this._checkInstance(resp.id); - } - - _handleLoginError(resp) { - if (resp.status === 401) { - // if unauthorized, send to login page - hashHistory.push('/login'); - } else if (resp.status === 403) { - hashHistory.push('/login/forbidden'); - } else { - const err = resp.errors[0]; - log(err); - this.setState({ - activityText: '', - errorText: err.message - }); - } - } - _handleInstanceSuccess() { - const url = encodeURIs`/api/app/${this.state.id}/`; + const url = encodeURIs`/api/app/${this.props.params.orgId}/`; this.setState({ activityText: '', frameBaseUrl: url @@ -145,8 +108,7 @@ export default class Wrapper extends React.Component { const frameUrl = `${this.state.frameBaseUrl}`; return ( -
- + {this.state.activityText &&

{this.state.activityText}

@@ -155,7 +117,7 @@ export default class Wrapper extends React.Component {
} {this.state.frameBaseUrl &&