summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2018-12-31 17:11:38 +0000
committerGerrit Code Review <review@openstack.org>2018-12-31 17:11:38 +0000
commitc66af50f64638684898bc98647e250f802a6e6f6 (patch)
tree8508a60a78c5734bb914b94cda4c3207b59306ee
parent144ab10ba792383fbed25a5c6de172cb69efa11c (diff)
parentd061c33415f40aa21f64d6b0a9d51622821b3d99 (diff)
Merge "web: refactor nodes page to use a reducer"
-rw-r--r--web/src/actions/nodes.js63
-rw-r--r--web/src/pages/Nodes.jsx70
-rw-r--r--web/src/reducers/index.js2
-rw-r--r--web/src/reducers/nodes.js42
4 files changed, 140 insertions, 37 deletions
diff --git a/web/src/actions/nodes.js b/web/src/actions/nodes.js
new file mode 100644
index 0000000..a456c3f
--- /dev/null
+++ b/web/src/actions/nodes.js
@@ -0,0 +1,63 @@
1// Copyright 2018 Red Hat, Inc
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations
13// under the License.
14
15import * as API from '../api'
16
17export const NODES_FETCH_REQUEST = 'NODES_FETCH_REQUEST'
18export const NODES_FETCH_SUCCESS = 'NODES_FETCH_SUCCESS'
19export const NODES_FETCH_FAIL = 'NODES_FETCH_FAIL'
20
21export const requestNodes = () => ({
22 type: NODES_FETCH_REQUEST
23})
24
25export const receiveNodes = (tenant, json) => ({
26 type: NODES_FETCH_SUCCESS,
27 nodes: json,
28 receivedAt: Date.now()
29})
30
31const failedNodes = error => ({
32 type: NODES_FETCH_FAIL,
33 error
34})
35
36const fetchNodes = (tenant) => dispatch => {
37 dispatch(requestNodes())
38 return API.fetchNodes(tenant.apiPrefix)
39 .then(response => dispatch(receiveNodes(tenant.name, response.data)))
40 .catch(error => dispatch(failedNodes(error)))
41}
42
43const shouldFetchNodes = (tenant, state) => {
44 const nodes = state.nodes
45 if (!nodes || nodes.nodes.length === 0) {
46 return true
47 }
48 if (nodes.isFetching) {
49 return false
50 }
51 if (Date.now() - nodes.receivedAt > 60000) {
52 // Refetch after 1 minutes
53 return true
54 }
55 return false
56}
57
58export const fetchNodesIfNeeded = (tenant, force) => (
59 dispatch, getState) => {
60 if (force || shouldFetchNodes(tenant, getState())) {
61 return dispatch(fetchNodes(tenant))
62 }
63}
diff --git a/web/src/pages/Nodes.jsx b/web/src/pages/Nodes.jsx
index 6e77341..33a7e6d 100644
--- a/web/src/pages/Nodes.jsx
+++ b/web/src/pages/Nodes.jsx
@@ -18,42 +18,29 @@ import { connect } from 'react-redux'
18import { Table } from 'patternfly-react' 18import { Table } from 'patternfly-react'
19import * as moment from 'moment' 19import * as moment from 'moment'
20 20
21import { fetchNodes } from '../api' 21import { fetchNodesIfNeeded } from '../actions/nodes'
22import Refreshable from '../containers/Refreshable'
22 23
23 24
24class NodesPage extends React.Component { 25class NodesPage extends Refreshable {
25 static propTypes = { 26 static propTypes = {
26 tenant: PropTypes.object 27 tenant: PropTypes.object,
28 remoteData: PropTypes.object,
29 dispatch: PropTypes.func
27 } 30 }
28 31
29 state = { 32 updateData (force) {
30 nodes: null 33 this.props.dispatch(fetchNodesIfNeeded(this.props.tenant, force))
31 }
32
33 updateData () {
34 fetchNodes(this.props.tenant.apiPrefix).then(response => {
35 this.setState({nodes: response.data})
36 })
37 } 34 }
38 35
39 componentDidMount () { 36 componentDidMount () {
40 document.title = 'Zuul Nodes' 37 document.title = 'Zuul Nodes'
41 if (this.props.tenant.name) { 38 super.componentDidMount()
42 this.updateData()
43 }
44 }
45
46 componentDidUpdate (prevProps) {
47 if (this.props.tenant.name !== prevProps.tenant.name) {
48 this.updateData()
49 }
50 } 39 }
51 40
52 render () { 41 render () {
53 const { nodes } = this.state 42 const { remoteData } = this.props
54 if (!nodes) { 43 const nodes = remoteData.nodes
55 return (<p>Loading...</p>)
56 }
57 44
58 const headerFormat = value => <Table.Heading>{value}</Table.Heading> 45 const headerFormat = value => <Table.Heading>{value}</Table.Heading>
59 const cellFormat = value => <Table.Cell>{value}</Table.Cell> 46 const cellFormat = value => <Table.Cell>{value}</Table.Cell>
@@ -92,19 +79,28 @@ class NodesPage extends React.Component {
92 }) 79 })
93 }) 80 })
94 return ( 81 return (
95 <Table.PfProvider 82 <React.Fragment>
96 striped 83 <div style={{float: 'right'}}>
97 bordered 84 {this.renderSpinner()}
98 hover 85 </div>
99 columns={columns} 86 <Table.PfProvider
100 > 87 striped
101 <Table.Header/> 88 bordered
102 <Table.Body 89 hover
103 rows={nodes} 90 columns={columns}
104 rowKey="id" 91 >
105 /> 92 <Table.Header/>
106 </Table.PfProvider>) 93 <Table.Body
94 rows={nodes}
95 rowKey="id"
96 />
97 </Table.PfProvider>
98 </React.Fragment>
99 )
107 } 100 }
108} 101}
109 102
110export default connect(state => ({tenant: state.tenant}))(NodesPage) 103export default connect(state => ({
104 tenant: state.tenant,
105 remoteData: state.nodes,
106}))(NodesPage)
diff --git a/web/src/reducers/index.js b/web/src/reducers/index.js
index b4e3a8b..88abc1a 100644
--- a/web/src/reducers/index.js
+++ b/web/src/reducers/index.js
@@ -21,6 +21,7 @@ import info from './info'
21import job from './job' 21import job from './job'
22import jobs from './jobs' 22import jobs from './jobs'
23import labels from './labels' 23import labels from './labels'
24import nodes from './nodes'
24import project from './project' 25import project from './project'
25import projects from './projects' 26import projects from './projects'
26import status from './status' 27import status from './status'
@@ -33,6 +34,7 @@ const reducers = {
33 job, 34 job,
34 jobs, 35 jobs,
35 labels, 36 labels,
37 nodes,
36 project, 38 project,
37 projects, 39 projects,
38 configErrors, 40 configErrors,
diff --git a/web/src/reducers/nodes.js b/web/src/reducers/nodes.js
new file mode 100644
index 0000000..0d8ec5f
--- /dev/null
+++ b/web/src/reducers/nodes.js
@@ -0,0 +1,42 @@
1// Copyright 2018 Red Hat, Inc
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations
13// under the License.
14
15import {
16 NODES_FETCH_FAIL,
17 NODES_FETCH_REQUEST,
18 NODES_FETCH_SUCCESS
19} from '../actions/nodes'
20
21import update from 'immutability-helper'
22
23export default (state = {
24 receivedAt: 0,
25 isFetching: false,
26 nodes: [],
27}, action) => {
28 switch (action.type) {
29 case NODES_FETCH_REQUEST:
30 return update(state, {$merge: {isFetching: true}})
31 case NODES_FETCH_SUCCESS:
32 return update(state, {$merge: {
33 isFetching: false,
34 nodes: action.nodes,
35 receivedAt: action.receivedAt
36 }})
37 case NODES_FETCH_FAIL:
38 return update(state, {$merge: {isFetching: false}})
39 default:
40 return state
41 }
42}