Skip to content

Commit f124554

Browse files
authored
Merge pull request #213 from arangodb/feature/dashboard-storage
Dashboard for ArangoLocalStorage operator
2 parents 4648865 + 8369d6e commit f124554

26 files changed

+941
-140
lines changed

.dockerignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ docs
55
pkg
66
tools
77
deps
8-
8+
dashboard

dashboard/assets.go

Lines changed: 49 additions & 60 deletions
Large diffs are not rendered by default.

dashboard/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"devDependencies": {
1717
"react-scripts": "1.1.4"
1818
},
19-
"proxy": "https://192.168.140.208:8528",
19+
"proxy": "https://192.168.140.211:8528",
2020
"scripts": {
2121
"start": "react-scripts start",
2222
"build": "react-scripts build",

dashboard/src/App.css

Lines changed: 0 additions & 28 deletions
This file was deleted.

dashboard/src/App.js

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import React, { Component } from 'react';
22
import ReactTimeout from 'react-timeout';
33
import DeploymentOperator from './deployment/DeploymentOperator.js';
4+
import StorageOperator from './storage/StorageOperator.js';
45
import NoOperator from './NoOperator.js';
56
import Loading from './util/Loading.js';
6-
import api from './api/api.js';
7+
import api, { isUnauthorized } from './api/api.js';
78
import { Container, Segment, Message } from 'semantic-ui-react';
8-
import './App.css';
9+
import { withAuth } from './auth/Auth.js';
910

1011
const PodInfoView = ({pod, namespace}) => (
1112
<Segment basic>
@@ -16,12 +17,18 @@ const PodInfoView = ({pod, namespace}) => (
1617
</Segment>
1718
);
1819

19-
const OperatorsView = ({error, deployment, pod, namespace}) => {
20-
const podInfoView = (<PodInfoView pod={pod} namespace={namespace}/>);
21-
if (deployment) {
22-
return (<DeploymentOperator podInfoView={podInfoView} error={error}/>);
23-
}
24-
return (<NoOperator podInfoView={podInfoView} error={error}/>);
20+
const OperatorsView = ({error, deployment, storage, pod, namespace}) => {
21+
let Operator = NoOperator;
22+
if (deployment)
23+
Operator = DeploymentOperator;
24+
else if (storage)
25+
Operator = StorageOperator;
26+
return (
27+
<Operator
28+
podInfoView={<PodInfoView pod={pod} namespace={namespace} />}
29+
error={error}
30+
/>
31+
);
2532
}
2633

2734
const LoadingView = () => (
@@ -43,24 +50,33 @@ class App extends Component {
4350
reloadOperators = async() => {
4451
try {
4552
const operators = await api.get('/api/operators');
46-
this.setState({operators, error: undefined});
53+
this.setState({
54+
operators,
55+
error: undefined
56+
});
4757
} catch (e) {
48-
this.setState({error: e.message});
58+
this.setState({
59+
error: e.message
60+
});
61+
if (isUnauthorized(e)) {
62+
this.props.doLogout();
63+
}
4964
}
5065
this.props.setTimeout(this.reloadOperators, 10000);
5166
}
5267

5368
render() {
5469
if (this.state.operators) {
55-
return <OperatorsView
70+
return <OperatorsView
5671
error={this.state.error}
57-
deployment={this.state.operators.deployment}
58-
pod={this.state.operators.pod}
59-
namespace={this.state.operators.namespace}
60-
/>;
72+
deployment={this.state.operators.deployment}
73+
storage={this.state.operators.storage}
74+
pod={this.state.operators.pod}
75+
namespace={this.state.operators.namespace}
76+
/>;
6177
}
6278
return (<LoadingView/>);
6379
}
6480
}
6581

66-
export default ReactTimeout(App);
82+
export default ReactTimeout(withAuth(App));

dashboard/src/App.test.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

dashboard/src/NoOperator.js

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
import React, { Component } from 'react';
2-
import logo from './logo.svg';
3-
import './App.css';
4-
import { Message } from 'semantic-ui-react';
2+
import { Container, Message, Modal, Segment } from 'semantic-ui-react';
53

64
class NoOperator extends Component {
75
render() {
86
return (
9-
<div className="App">
10-
<header className="App-header">
11-
<img src={logo} className="App-logo" alt="logo" />
12-
<h1 className="App-title">Welcome to Kube-ArangoDB</h1>
13-
</header>
14-
<p className="App-intro">
15-
There are no operators available yet.
16-
</p>
17-
{this.props.podInfoView}
18-
{(this.props.error) ? <Message error content={this.props.error}/> : null}
19-
</div>
7+
<Container>
8+
<Modal open>
9+
<Modal.Header>Welcome to Kube-ArangoDB</Modal.Header>
10+
<Modal.Content>
11+
<Segment basic>
12+
<Message color="orange">
13+
There are no operators available yet.
14+
</Message>
15+
</Segment>
16+
{this.props.podInfoView}
17+
{(this.props.error) ? <Message error content={this.props.error}/> : null}
18+
</Modal.Content>
19+
</Modal>
20+
</Container>
2021
);
2122
}
2223
}

dashboard/src/api/api.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
1+
export function isUnauthorized(e) {
2+
return (e.status === 401);
3+
}
4+
15
export default {
26
token: '',
37

48
async decodeResults(result) {
59
const decoded = await result.json();
6-
if (result.status === 401) {
7-
throw Error(decoded.error || "Unauthorized")
8-
}
910
if (result.status !== 200) {
10-
throw Error(`Unexpected status ${result.status}`);
11+
let message = decoded.error;
12+
if (!message) {
13+
if (result.status === 401) {
14+
message = "Unauthorized";
15+
} else {
16+
message = `Unexpected status ${result.status}`;
17+
}
18+
}
19+
throw Object.assign(new Error(message), { status: result.status });
1120
}
1221
return decoded;
1322
},

dashboard/src/auth/Auth.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ import { getSessionItem, setSessionItem } from "../util/Storage.js";
77

88
const tokenSessionKey = "auth-token";
99

10+
11+
// withAuth adds a doLogout property to the given component.
12+
export function withAuth(WrappedComponent) {
13+
return function AuthAwareComponent(props) {
14+
return (
15+
<LogoutContext.Consumer>
16+
{doLogout => <WrappedComponent {...props} doLogout={doLogout} />}
17+
</LogoutContext.Consumer>
18+
);
19+
}
20+
}
21+
1022
class Auth extends Component {
1123
state = {
1224
authenticated: false,

dashboard/src/auth/Login.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { Component } from 'react';
22
import { Button, Container, Form, Icon, Message, Modal } from 'semantic-ui-react';
3+
import { css } from 'react-emotion';
34

45
const LoginView = ({username, password, onUsernameChanged, onPasswordChanged, doLogin, error}) => (
56
<Container>
@@ -12,6 +13,7 @@ const LoginView = ({username, password, onUsernameChanged, onPasswordChanged, do
1213
<label>Password</label>
1314
<input type="password" value={password} onChange={(e) => onPasswordChanged(e.target.value)}/>
1415
</Form.Field>
16+
<Form.Button className={css`display:none`} type="submit" />
1517
</Form>
1618
{(error) ? <Message error content={error}/> : null}
1719
</Container>

0 commit comments

Comments
 (0)