Merge "web: refactor build page to use a reducer"

This commit is contained in:
Zuul 2018-12-31 17:11:56 +00:00 committed by Gerrit Code Review
commit 000c92b81b
4 changed files with 135 additions and 37 deletions

60
web/src/actions/build.js Normal file
View File

@ -0,0 +1,60 @@
// Copyright 2018 Red Hat, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import * as API from '../api'
export const BUILD_FETCH_REQUEST = 'BUILD_FETCH_REQUEST'
export const BUILD_FETCH_SUCCESS = 'BUILD_FETCH_SUCCESS'
export const BUILD_FETCH_FAIL = 'BUILD_FETCH_FAIL'
export const requestBuild = () => ({
type: BUILD_FETCH_REQUEST
})
export const receiveBuild = (buildId, build) => ({
type: BUILD_FETCH_SUCCESS,
buildId: buildId,
build: build,
receivedAt: Date.now()
})
const failedBuild = error => ({
type: BUILD_FETCH_FAIL,
error
})
const fetchBuild = (tenant, build) => dispatch => {
dispatch(requestBuild())
return API.fetchBuild(tenant.apiPrefix, build)
.then(response => dispatch(receiveBuild(build, response.data)))
.catch(error => dispatch(failedBuild(error)))
}
const shouldFetchBuild = (buildId, state) => {
const build = state.build.builds[buildId]
if (!build) {
return true
}
if (build.isFetching) {
return false
}
return false
}
export const fetchBuildIfNeeded = (tenant, buildId, force) => (
dispatch, getState) => {
if (force || shouldFetchBuild(buildId, getState())) {
return dispatch(fetchBuild(tenant, buildId))
}
}

View File

@ -18,41 +18,30 @@ import PropTypes from 'prop-types'
import { Link } from 'react-router-dom'
import { Panel } from 'react-bootstrap'
import { fetchBuild } from '../api'
import { fetchBuildIfNeeded } from '../actions/build'
import Refreshable from '../containers/Refreshable'
class BuildPage extends React.Component {
class BuildPage extends Refreshable {
static propTypes = {
match: PropTypes.object.isRequired,
remoteData: PropTypes.object,
tenant: PropTypes.object
}
state = {
build: null
}
updateData = () => {
fetchBuild(this.props.tenant.apiPrefix, this.props.match.params.buildId)
.then(response => {
this.setState({build: response.data})
})
updateData = (force) => {
this.props.dispatch(fetchBuildIfNeeded(
this.props.tenant, this.props.match.params.buildId, force))
}
componentDidMount () {
document.title = 'Zuul Build'
if (this.props.tenant.name) {
this.updateData()
}
}
componentDidUpdate (prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
super.componentDidMount()
}
render () {
const { build } = this.state
const { remoteData } = this.props
const build = remoteData.builds[this.props.match.params.buildId]
if (!build) {
return (<p>Loading...</p>)
}
@ -95,23 +84,31 @@ class BuildPage extends React.Component {
}
})
return (
<Panel>
<Panel.Heading>Build result {build.uuid}</Panel.Heading>
<Panel.Body>
<table className="table table-striped table-bordered">
<tbody>
{rows.map(item => (
<tr key={item.key}>
<td>{item.key}</td>
<td>{item.value}</td>
</tr>
))}
</tbody>
</table>
</Panel.Body>
</Panel>
<React.Fragment>
<div style={{float: 'right'}}>
{this.renderSpinner()}
</div>
<Panel>
<Panel.Heading>Build result {build.uuid}</Panel.Heading>
<Panel.Body>
<table className="table table-striped table-bordered">
<tbody>
{rows.map(item => (
<tr key={item.key}>
<td>{item.key}</td>
<td>{item.value}</td>
</tr>
))}
</tbody>
</table>
</Panel.Body>
</Panel>
</React.Fragment>
)
}
}
export default connect(state => ({tenant: state.tenant}))(BuildPage)
export default connect(state => ({
tenant: state.tenant,
remoteData: state.build,
}))(BuildPage)

39
web/src/reducers/build.js Normal file
View File

@ -0,0 +1,39 @@
// Copyright 2018 Red Hat, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import {
BUILD_FETCH_FAIL,
BUILD_FETCH_REQUEST,
BUILD_FETCH_SUCCESS
} from '../actions/build'
import update from 'immutability-helper'
export default (state = {
isFetching: false,
builds: {},
}, action) => {
switch (action.type) {
case BUILD_FETCH_REQUEST:
return update(state, {$merge: {isFetching: true}})
case BUILD_FETCH_SUCCESS:
state.builds = update(
state.builds, {$merge: {[action.buildId]: action.build}})
return update(state, {$merge: {isFetching: false}})
case BUILD_FETCH_FAIL:
return update(state, {$merge: {isFetching: false}})
default:
return state
}
}

View File

@ -17,6 +17,7 @@ import { combineReducers } from 'redux'
import configErrors from './configErrors'
import change from './change'
import errors from './errors'
import build from './build'
import info from './info'
import job from './job'
import jobs from './jobs'
@ -30,6 +31,7 @@ import tenants from './tenants'
const reducers = {
change,
build,
info,
job,
jobs,