Skip to content

Commit 06bda8c

Browse files
committed
Improved backend polling behavior
1 parent f2274a5 commit 06bda8c

File tree

8 files changed

+130
-48
lines changed

8 files changed

+130
-48
lines changed

dashboard/package-lock.json

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dashboard/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"react-dom": "^16.4.1",
1010
"react-emotion": "^9.2.4",
1111
"react-router-dom": "^4.3.1",
12+
"react-timeout": "^1.1.1",
1213
"semantic-ui-less": "^2.2.12",
1314
"semantic-ui-react": "^0.81.3"
1415
},

dashboard/src/App.js

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { Component } from 'react';
2+
import ReactTimeout from 'react-timeout';
23
import DeploymentOperator from './deployment/DeploymentOperator.js';
34
import NoOperator from './NoOperator.js';
45
import Loading from './util/Loading.js';
@@ -15,11 +16,13 @@ const PodInfoView = ({pod, namespace}) => (
1516
</Segment>
1617
);
1718

18-
const OperatorsView = ({deployment, pod, namespace}) => (
19-
<div>
20-
{deployment ? <DeploymentOperator pod-info={<PodInfoView pod={pod} namespace={namespace}/>}/> : <NoOperator />}
21-
</div>
22-
);
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}/>);
25+
}
2326

2427
const LoadingView = () => (
2528
<Container>
@@ -28,25 +31,29 @@ const LoadingView = () => (
2831
);
2932

3033
class App extends Component {
31-
state = {};
34+
state = {
35+
operators: undefined,
36+
error: undefined
37+
};
3238

3339
componentDidMount() {
34-
this.intervalId = setInterval(this.reloadOperators, 5000);
3540
this.reloadOperators();
3641
}
3742

38-
componentWillUnmount() {
39-
clearInterval(this.intervalId);
40-
}
41-
4243
reloadOperators = async() => {
43-
const operators = await api.get('/api/operators');
44-
this.setState({operators});
44+
try {
45+
const operators = await api.get('/api/operators');
46+
this.setState({operators, error: undefined});
47+
} catch (e) {
48+
this.setState({error: e.message});
49+
}
50+
this.props.setTimeout(this.reloadOperators, 10000);
4551
}
4652

4753
render() {
4854
if (this.state.operators) {
4955
return <OperatorsView
56+
error={this.state.error}
5057
deployment={this.state.operators.deployment}
5158
pod={this.state.operators.pod}
5259
namespace={this.state.operators.namespace}
@@ -56,4 +63,4 @@ class App extends Component {
5663
}
5764
}
5865

59-
export default App;
66+
export default ReactTimeout(App);

dashboard/src/NoOperator.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { Component } from 'react';
22
import logo from './logo.svg';
33
import './App.css';
4+
import { Message } from 'semantic-ui-react';
45

56
class NoOperator extends Component {
67
render() {
@@ -13,7 +14,8 @@ class NoOperator extends Component {
1314
<p className="App-intro">
1415
There are no operators available yet.
1516
</p>
16-
{this.props["pod-info"]}
17+
{this.props.podInfoView}
18+
{(this.props.error) ? <Message error content={this.props.error}/> : null}
1719
</div>
1820
);
1921
}

dashboard/src/auth/Auth.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { Component } from 'react';
22
import api from '../api/api.js';
33
import Login from './Login.js';
4+
import Loading from '../util/Loading.js';
45
import LogoutContext from './LogoutContext.js';
56
import { getSessionItem, setSessionItem } from "../util/Storage.js";
67

@@ -9,6 +10,7 @@ const tokenSessionKey = "auth-token";
910
class Auth extends Component {
1011
state = {
1112
authenticated: false,
13+
showLoading: true,
1214
token: getSessionItem(tokenSessionKey) || ""
1315
};
1416

@@ -18,11 +20,13 @@ class Auth extends Component {
1820
await api.get('/api/operators');
1921
this.setState({
2022
authenticated: true,
23+
showLoading: false,
2124
token: api.token
2225
});
2326
} catch (e) {
2427
this.setState({
2528
authenticated: false,
29+
showLoading: false,
2630
token: ''
2731
});
2832
}
@@ -65,9 +69,10 @@ class Auth extends Component {
6569
render() {
6670
return (
6771
<LogoutContext.Provider value={this.handleLogout}>
68-
{(!this.state.authenticated) ?
69-
<Login doLogin={this.handleLogin} error={this.state.error}/> :
70-
this.props.children
72+
{(this.state.showLoading) ? <Loading/> :
73+
(!this.state.authenticated) ?
74+
<Login doLogin={this.handleLogin} error={this.state.error}/> :
75+
this.props.children
7176
}
7277
</LogoutContext.Provider>
7378
);
Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
1+
import ReactTimeout from 'react-timeout';
12
import React, { Component } from 'react';
23
import api from '../api/api.js';
34
import Loading from '../util/Loading.js';
45
import MemberList from './MemberList.js';
6+
import styled from 'react-emotion';
7+
import { Loader } from 'semantic-ui-react';
8+
9+
const LoaderBox = styled('span')`
10+
float: right;
11+
width: 0;
12+
padding-right: 1em;
13+
margin-right: 1em;
14+
margin-top: 1em;
15+
max-width: 0;
16+
display: inline-block;
17+
`;
518

619
const MemberGroupsView = ({memberGroups, namespace}) => (
720
<div>
@@ -15,21 +28,31 @@ const MemberGroupsView = ({memberGroups, namespace}) => (
1528
);
1629

1730
class DeploymentDetails extends Component {
18-
state = {};
31+
state = {
32+
loading: true,
33+
error: undefined
34+
};
1935

2036
componentDidMount() {
21-
this.intervalId = setInterval(this.reloadDeployment, 5000);
2237
this.reloadDeployment();
2338
}
2439

25-
componentWillUnmount() {
26-
clearInterval(this.intervalId);
27-
}
28-
2940
reloadDeployment = async() => {
30-
// TODO
31-
const result = await api.get(`/api/deployment/${this.props.name}`);
32-
this.setState({deployment:result});
41+
try {
42+
this.setState({loading:true});
43+
const result = await api.get(`/api/deployment/${this.props.name}`);
44+
this.setState({
45+
deployment: result,
46+
loading: false,
47+
error: undefined
48+
});
49+
} catch (e) {
50+
this.setState({
51+
loading: false,
52+
error: e.message
53+
});
54+
}
55+
this.props.setTimeout(this.reloadDeployment, 5000);
3356
}
3457

3558
render() {
@@ -39,10 +62,11 @@ class DeploymentDetails extends Component {
3962
}
4063
return (
4164
<div>
65+
<LoaderBox><Loader size="mini" active={this.state.loading} inline/></LoaderBox>
4266
<MemberGroupsView memberGroups={d.member_groups} namespace={d.namespace}/>
4367
</div>
4468
);
4569
}
4670
}
4771

48-
export default DeploymentDetails;
72+
export default ReactTimeout(DeploymentDetails);

dashboard/src/deployment/DeploymentList.js

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
1-
import React, { Component } from 'react';
1+
import { Icon, Loader, Popup, Table } from 'semantic-ui-react';
2+
import { Link } from "react-router-dom";
23
import api from '../api/api.js';
3-
import { Icon, Popup, Table } from 'semantic-ui-react';
4-
import Loading from '../util/Loading.js';
54
import CommandInstruction from '../util/CommandInstruction.js';
6-
import { Link } from "react-router-dom";
5+
import Loading from '../util/Loading.js';
6+
import React, { Component } from 'react';
7+
import ReactTimeout from 'react-timeout';
8+
import styled from 'react-emotion';
9+
10+
const LoaderBox = styled('span')`
11+
float: right;
12+
width: 0;
13+
padding-right: 1em;
14+
max-width: 0;
15+
display: inline-block;
16+
`;
717

8-
const HeaderView = () => (
18+
const HeaderView = ({loading}) => (
919
<Table.Header>
1020
<Table.Row>
1121
<Table.HeaderCell>State</Table.HeaderCell>
@@ -15,7 +25,10 @@ const HeaderView = () => (
1525
<Table.HeaderCell><Popup trigger={<span>Pods</span>}>Ready / Total</Popup></Table.HeaderCell>
1626
<Table.HeaderCell><Popup trigger={<span>Volumes</span>}>Bound / Total</Popup></Table.HeaderCell>
1727
<Table.HeaderCell>StorageClass</Table.HeaderCell>
18-
<Table.HeaderCell>Actions</Table.HeaderCell>
28+
<Table.HeaderCell>
29+
Actions
30+
<LoaderBox><Loader size="mini" active={loading} inline/></LoaderBox>
31+
</Table.HeaderCell>
1932
</Table.Row>
2033
</Table.Header>
2134
);
@@ -83,9 +96,9 @@ const RowView = ({name, mode, environment, stateColor, version, license, readyPo
8396
</Table.Row>
8497
);
8598

86-
const ListView = ({items}) => (
99+
const ListView = ({items, loading}) => (
87100
<Table striped celled>
88-
<HeaderView/>
101+
<HeaderView loading={loading}/>
89102
<Table.Body>
90103
{
91104
(items) ? items.map((item) =>
@@ -138,20 +151,29 @@ function getStateColorDescription(stateColor) {
138151
}
139152

140153
class DeploymentList extends Component {
141-
state = {};
154+
state = {
155+
items: undefined,
156+
error: undefined,
157+
loading: true
158+
};
142159

143160
componentDidMount() {
144-
this.intervalId = setInterval(this.reloadDeployments, 5000);
145161
this.reloadDeployments();
146162
}
147163

148-
componentWillUnmount() {
149-
clearInterval(this.intervalId);
150-
}
151-
152164
reloadDeployments = async() => {
153-
const result = await api.get('/api/deployment');
154-
this.setState({items:result.deployments});
165+
try {
166+
this.setState({loading: true});
167+
const result = await api.get('/api/deployment');
168+
this.setState({
169+
items: result.deployments,
170+
loading: false,
171+
error: undefined
172+
});
173+
} catch (e) {
174+
this.setState({error: e.message, loading: false});
175+
}
176+
this.props.setTimeout(this.reloadDeployments, 5000);
155177
}
156178

157179
render() {
@@ -162,8 +184,8 @@ class DeploymentList extends Component {
162184
if (items.length === 0) {
163185
return (<EmptyView/>);
164186
}
165-
return (<ListView items={items}/>);
187+
return (<ListView items={items} loading={this.state.loading}/>);
166188
}
167189
}
168190

169-
export default DeploymentList;
191+
export default ReactTimeout(DeploymentList);

dashboard/src/deployment/DeploymentOperator.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
22
import LogoutContext from '../auth/LogoutContext.js';
33
import DeploymentDetails from './DeploymentDetails.js';
44
import DeploymentList from './DeploymentList.js';
5-
import { Header, Menu, Segment } from 'semantic-ui-react';
5+
import { Header, Menu, Message, Segment } from 'semantic-ui-react';
66
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
77
import styled from 'react-emotion';
88

@@ -62,7 +62,8 @@ class DeploymentOperator extends Component {
6262
<Route path="/deployment/:name" component={DetailView} />
6363
</div>
6464
</Segment>
65-
{this.props["pod-info"]}
65+
{this.props.podInfoView}
66+
{(this.props.error) ? <Segment basic><Message error content={this.props.error}/></Segment> : null}
6667
</StyledContentBox>
6768
</div>
6869
</Router>

0 commit comments

Comments
 (0)