summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2018-12-31 17:11:56 +0000
committerGerrit Code Review <review@openstack.org>2018-12-31 17:11:56 +0000
commit000c92b81b0222f3c0b535f124114dad2f3c7b3b (patch)
tree15018348bce4facfb890b9b3992a1a0797802687
parentc66af50f64638684898bc98647e250f802a6e6f6 (diff)
parent342c29c994a937b89a63eb18a608b9dabc7a78ad (diff)
Merge "web: refactor build page to use a reducer"
-rw-r--r--web/src/actions/build.js60
-rw-r--r--web/src/pages/Build.jsx71
-rw-r--r--web/src/reducers/build.js39
-rw-r--r--web/src/reducers/index.js2
4 files changed, 135 insertions, 37 deletions
diff --git a/web/src/actions/build.js b/web/src/actions/build.js
new file mode 100644
index 0000000..78f69f9
--- /dev/null
+++ b/web/src/actions/build.js
@@ -0,0 +1,60 @@
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 BUILD_FETCH_REQUEST = 'BUILD_FETCH_REQUEST'
18export const BUILD_FETCH_SUCCESS = 'BUILD_FETCH_SUCCESS'
19export const BUILD_FETCH_FAIL = 'BUILD_FETCH_FAIL'
20
21export const requestBuild = () => ({
22 type: BUILD_FETCH_REQUEST
23})
24
25export const receiveBuild = (buildId, build) => ({
26 type: BUILD_FETCH_SUCCESS,
27 buildId: buildId,
28 build: build,
29 receivedAt: Date.now()
30})
31
32const failedBuild = error => ({
33 type: BUILD_FETCH_FAIL,
34 error
35})
36
37const fetchBuild = (tenant, build) => dispatch => {
38 dispatch(requestBuild())
39 return API.fetchBuild(tenant.apiPrefix, build)
40 .then(response => dispatch(receiveBuild(build, response.data)))
41 .catch(error => dispatch(failedBuild(error)))
42}
43
44const shouldFetchBuild = (buildId, state) => {
45 const build = state.build.builds[buildId]
46 if (!build) {
47 return true
48 }
49 if (build.isFetching) {
50 return false
51 }
52 return false
53}
54
55export const fetchBuildIfNeeded = (tenant, buildId, force) => (
56 dispatch, getState) => {
57 if (force || shouldFetchBuild(buildId, getState())) {
58 return dispatch(fetchBuild(tenant, buildId))
59 }
60}
diff --git a/web/src/pages/Build.jsx b/web/src/pages/Build.jsx
index 1ba176c..818b2a8 100644
--- a/web/src/pages/Build.jsx
+++ b/web/src/pages/Build.jsx
@@ -18,41 +18,30 @@ import PropTypes from 'prop-types'
18import { Link } from 'react-router-dom' 18import { Link } from 'react-router-dom'
19import { Panel } from 'react-bootstrap' 19import { Panel } from 'react-bootstrap'
20 20
21import { fetchBuild } from '../api' 21import { fetchBuildIfNeeded } from '../actions/build'
22import Refreshable from '../containers/Refreshable'
22 23
23 24
24class BuildPage extends React.Component { 25class BuildPage extends Refreshable {
25 static propTypes = { 26 static propTypes = {
26 match: PropTypes.object.isRequired, 27 match: PropTypes.object.isRequired,
28 remoteData: PropTypes.object,
27 tenant: PropTypes.object 29 tenant: PropTypes.object
28 } 30 }
29 31
30 state = { 32 updateData = (force) => {
31 build: null 33 this.props.dispatch(fetchBuildIfNeeded(
32 } 34 this.props.tenant, this.props.match.params.buildId, force))
33
34 updateData = () => {
35 fetchBuild(this.props.tenant.apiPrefix, this.props.match.params.buildId)
36 .then(response => {
37 this.setState({build: response.data})
38 })
39 } 35 }
40 36
41 componentDidMount () { 37 componentDidMount () {
42 document.title = 'Zuul Build' 38 document.title = 'Zuul Build'
43 if (this.props.tenant.name) { 39 super.componentDidMount()
44 this.updateData()
45 }
46 }
47
48 componentDidUpdate (prevProps) {
49 if (this.props.tenant.name !== prevProps.tenant.name) {
50 this.updateData()
51 }
52 } 40 }
53 41
54 render () { 42 render () {
55 const { build } = this.state 43 const { remoteData } = this.props
44 const build = remoteData.builds[this.props.match.params.buildId]
56 if (!build) { 45 if (!build) {
57 return (<p>Loading...</p>) 46 return (<p>Loading...</p>)
58 } 47 }
@@ -95,23 +84,31 @@ class BuildPage extends React.Component {
95 } 84 }
96 }) 85 })
97 return ( 86 return (
98 <Panel> 87 <React.Fragment>
99 <Panel.Heading>Build result {build.uuid}</Panel.Heading> 88 <div style={{float: 'right'}}>
100 <Panel.Body> 89 {this.renderSpinner()}
101 <table className="table table-striped table-bordered"> 90 </div>
102 <tbody> 91 <Panel>
103 {rows.map(item => ( 92 <Panel.Heading>Build result {build.uuid}</Panel.Heading>
104 <tr key={item.key}> 93 <Panel.Body>
105 <td>{item.key}</td> 94 <table className="table table-striped table-bordered">
106 <td>{item.value}</td> 95 <tbody>
107 </tr> 96 {rows.map(item => (
108 ))} 97 <tr key={item.key}>
109 </tbody> 98 <td>{item.key}</td>
110 </table> 99 <td>{item.value}</td>
111 </Panel.Body> 100 </tr>
112 </Panel> 101 ))}
102 </tbody>
103 </table>
104 </Panel.Body>
105 </Panel>
106 </React.Fragment>
113 ) 107 )
114 } 108 }
115} 109}
116 110
117export default connect(state => ({tenant: state.tenant}))(BuildPage) 111export default connect(state => ({
112 tenant: state.tenant,
113 remoteData: state.build,
114}))(BuildPage)
diff --git a/web/src/reducers/build.js b/web/src/reducers/build.js
new file mode 100644
index 0000000..86aaad8
--- /dev/null
+++ b/web/src/reducers/build.js
@@ -0,0 +1,39 @@
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 BUILD_FETCH_FAIL,
17 BUILD_FETCH_REQUEST,
18 BUILD_FETCH_SUCCESS
19} from '../actions/build'
20
21import update from 'immutability-helper'
22
23export default (state = {
24 isFetching: false,
25 builds: {},
26}, action) => {
27 switch (action.type) {
28 case BUILD_FETCH_REQUEST:
29 return update(state, {$merge: {isFetching: true}})
30 case BUILD_FETCH_SUCCESS:
31 state.builds = update(
32 state.builds, {$merge: {[action.buildId]: action.build}})
33 return update(state, {$merge: {isFetching: false}})
34 case BUILD_FETCH_FAIL:
35 return update(state, {$merge: {isFetching: false}})
36 default:
37 return state
38 }
39}
diff --git a/web/src/reducers/index.js b/web/src/reducers/index.js
index 88abc1a..0f94402 100644
--- a/web/src/reducers/index.js
+++ b/web/src/reducers/index.js
@@ -17,6 +17,7 @@ import { combineReducers } from 'redux'
17import configErrors from './configErrors' 17import configErrors from './configErrors'
18import change from './change' 18import change from './change'
19import errors from './errors' 19import errors from './errors'
20import build from './build'
20import info from './info' 21import info from './info'
21import job from './job' 22import job from './job'
22import jobs from './jobs' 23import jobs from './jobs'
@@ -30,6 +31,7 @@ import tenants from './tenants'
30 31
31const reducers = { 32const reducers = {
32 change, 33 change,
34 build,
33 info, 35 info,
34 job, 36 job,
35 jobs, 37 jobs,