web: refactor job page to use a reducer
This change updates the job page component to dispatch reducer action instead of direct axios call. This enables using the generic error reducers as well as keeping the tenant jobs in the store to avoid repeated query. Change-Id: I142493c3a89379a75d97d247fbe1fcc0858e9723
This commit is contained in:
parent
839fe0cceb
commit
51e5259477
|
@ -0,0 +1,67 @@
|
|||
/* global Promise */
|
||||
// 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 JOB_FETCH_REQUEST = 'JOB_FETCH_REQUEST'
|
||||
export const JOB_FETCH_SUCCESS = 'JOB_FETCH_SUCCESS'
|
||||
export const JOB_FETCH_FAIL = 'JOB_FETCH_FAIL'
|
||||
|
||||
export const requestJob = () => ({
|
||||
type: JOB_FETCH_REQUEST
|
||||
})
|
||||
|
||||
export const receiveJob = (tenant, jobname, json) => ({
|
||||
type: JOB_FETCH_SUCCESS,
|
||||
tenant: tenant,
|
||||
jobname: jobname,
|
||||
job: json,
|
||||
receivedAt: Date.now()
|
||||
})
|
||||
|
||||
const failedJob = error => ({
|
||||
type: JOB_FETCH_FAIL,
|
||||
error
|
||||
})
|
||||
|
||||
const fetchJob = (tenant, jobname) => dispatch => {
|
||||
dispatch(requestJob())
|
||||
return API.fetchJob(tenant.apiPrefix, jobname)
|
||||
.then(response => dispatch(receiveJob(tenant.name, jobname, response.data)))
|
||||
.catch(error => dispatch(failedJob(error)))
|
||||
}
|
||||
|
||||
const shouldFetchJob = (tenant, jobname, state) => {
|
||||
const tenantJobs = state.job.jobs[tenant.name]
|
||||
if (tenantJobs) {
|
||||
const job = tenantJobs[jobname]
|
||||
if (!job) {
|
||||
return true
|
||||
}
|
||||
if (job.isFetching) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export const fetchJobIfNeeded = (tenant, jobname, force) => (
|
||||
dispatch, getState) => {
|
||||
if (force || shouldFetchJob(tenant, jobname, getState())) {
|
||||
return dispatch(fetchJob(tenant, jobname))
|
||||
}
|
||||
return Promise.resolve()
|
||||
}
|
|
@ -17,31 +17,26 @@ import { connect } from 'react-redux'
|
|||
import PropTypes from 'prop-types'
|
||||
|
||||
import Job from '../containers/job/Job'
|
||||
import { fetchJob } from '../api'
|
||||
import Refreshable from '../containers/Refreshable'
|
||||
import { fetchJobIfNeeded } from '../actions/job'
|
||||
|
||||
|
||||
class JobPage extends React.Component {
|
||||
class JobPage extends Refreshable {
|
||||
static propTypes = {
|
||||
match: PropTypes.object.isRequired,
|
||||
tenant: PropTypes.object
|
||||
tenant: PropTypes.object,
|
||||
remoteData: PropTypes.object,
|
||||
dispatch: PropTypes.func
|
||||
}
|
||||
|
||||
state = {
|
||||
job: null
|
||||
}
|
||||
|
||||
updateData = () => {
|
||||
fetchJob(this.props.tenant.apiPrefix, this.props.match.params.jobName)
|
||||
.then(response => {
|
||||
this.setState({job: response.data})
|
||||
})
|
||||
updateData = (force) => {
|
||||
this.props.dispatch(fetchJobIfNeeded(
|
||||
this.props.tenant, this.props.match.params.jobName, force))
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
document.title = 'Zuul Job | ' + this.props.match.params.jobName
|
||||
if (this.props.tenant.name) {
|
||||
this.updateData()
|
||||
}
|
||||
super.componentDidMount()
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
|
@ -52,14 +47,21 @@ class JobPage extends React.Component {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { job } = this.state
|
||||
if (!job) {
|
||||
return (<p>Loading...</p>)
|
||||
}
|
||||
const { remoteData } = this.props
|
||||
const tenantJobs = remoteData.jobs[this.props.tenant.name]
|
||||
const jobName = this.props.match.params.jobName
|
||||
return (
|
||||
<Job job={job} />
|
||||
<React.Fragment>
|
||||
<div style={{float: 'right'}}>
|
||||
{this.renderSpinner()}
|
||||
</div>
|
||||
{tenantJobs && tenantJobs[jobName] && <Job job={tenantJobs[jobName]} />}
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(state => ({tenant: state.tenant}))(JobPage)
|
||||
export default connect(state => ({
|
||||
tenant: state.tenant,
|
||||
remoteData: state.job,
|
||||
}))(JobPage)
|
||||
|
|
|
@ -42,7 +42,7 @@ class JobsPage extends Refreshable {
|
|||
const jobs = remoteData.jobs[this.props.tenant.name]
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="pull-right" style={{display: 'flex'}}>
|
||||
<div style={{float: 'right'}}>
|
||||
{this.renderSpinner()}
|
||||
</div>
|
||||
{jobs && jobs.length > 0 &&
|
||||
|
|
|
@ -17,12 +17,14 @@ import { combineReducers } from 'redux'
|
|||
import configErrors from './configErrors'
|
||||
import errors from './errors'
|
||||
import info from './info'
|
||||
import job from './job'
|
||||
import jobs from './jobs'
|
||||
import status from './status'
|
||||
import tenant from './tenant'
|
||||
|
||||
const reducers = {
|
||||
info,
|
||||
job,
|
||||
jobs,
|
||||
configErrors,
|
||||
errors,
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
// 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 {
|
||||
JOB_FETCH_FAIL,
|
||||
JOB_FETCH_REQUEST,
|
||||
JOB_FETCH_SUCCESS
|
||||
} from '../actions/job'
|
||||
|
||||
import update from 'immutability-helper'
|
||||
|
||||
export default (state = {
|
||||
isFetching: false,
|
||||
jobs: {},
|
||||
}, action) => {
|
||||
switch (action.type) {
|
||||
case JOB_FETCH_REQUEST:
|
||||
return {
|
||||
isFetching: true,
|
||||
jobs: state.jobs,
|
||||
}
|
||||
case JOB_FETCH_SUCCESS:
|
||||
if (!state.jobs[action.tenant]) {
|
||||
state.jobs = update(state.jobs, {$merge: {[action.tenant]: {}}})
|
||||
}
|
||||
return {
|
||||
isFetching: false,
|
||||
jobs: update(state.jobs, {
|
||||
[action.tenant]: {
|
||||
$merge: {
|
||||
[action.jobname]: action.job
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
case JOB_FETCH_FAIL:
|
||||
return {
|
||||
isFetching: false,
|
||||
jobs: state.jobs,
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue