web: refactor status page to use a reducer
This change updates the status page component to use a fetchStatusAction instead of direct axios call. This enables using the generic error reducers. This change also refactors the refresh button into a parent component to enable re-use on the other pages. Change-Id: Iac8a317263f84f14f28d2ea015f918268b903407
This commit is contained in:
parent
f312f68ec6
commit
833dbd257b
|
@ -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 STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'
|
||||
export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS'
|
||||
export const STATUS_FETCH_FAIL = 'STATUS_FETCH_FAIL'
|
||||
|
||||
export const requestStatus = () => ({
|
||||
type: STATUS_FETCH_REQUEST
|
||||
})
|
||||
|
||||
export const receiveStatus = json => ({
|
||||
type: STATUS_FETCH_SUCCESS,
|
||||
status: json,
|
||||
receivedAt: Date.now()
|
||||
})
|
||||
|
||||
const failedStatus = error => ({
|
||||
type: STATUS_FETCH_FAIL,
|
||||
error
|
||||
})
|
||||
|
||||
// Create fake delay
|
||||
//function sleeper(ms) {
|
||||
// return function(x) {
|
||||
// return new Promise(resolve => setTimeout(() => resolve(x), ms));
|
||||
// };
|
||||
//}
|
||||
|
||||
const fetchStatus = (tenant) => dispatch => {
|
||||
dispatch(requestStatus())
|
||||
return API.fetchStatus(tenant.apiPrefix)
|
||||
.then(response => dispatch(receiveStatus(response.data)))
|
||||
.catch(error => dispatch(failedStatus(error)))
|
||||
}
|
||||
|
||||
const shouldFetchStatus = state => {
|
||||
const status = state.status
|
||||
if (!status) {
|
||||
return true
|
||||
}
|
||||
if (status.isFetching) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export const fetchStatusIfNeeded = (tenant) => (dispatch, getState) => {
|
||||
if (shouldFetchStatus(getState())) {
|
||||
return dispatch(fetchStatus(tenant))
|
||||
}
|
||||
return Promise.resolve()
|
||||
}
|
|
@ -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.
|
||||
|
||||
// Boiler plate code to manage refresh button
|
||||
|
||||
import * as React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {
|
||||
Icon,
|
||||
Spinner
|
||||
} from 'patternfly-react'
|
||||
|
||||
|
||||
class Refreshable extends React.Component {
|
||||
static propTypes = {
|
||||
tenant: PropTypes.object,
|
||||
remoteData: PropTypes.object,
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
if (this.props.tenant.name) {
|
||||
this.updateData()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
if (this.props.tenant.name !== prevProps.tenant.name) {
|
||||
this.updateData()
|
||||
}
|
||||
}
|
||||
|
||||
renderSpinner () {
|
||||
const { remoteData } = this.props
|
||||
return (
|
||||
<Spinner loading={ remoteData.isFetching }>
|
||||
<a className="refresh" onClick={() => {this.updateData(true)}}>
|
||||
<Icon type="fa" name="refresh" /> refresh
|
||||
</a>
|
||||
</Spinner>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Refreshable
|
|
@ -17,31 +17,29 @@ import * as React from 'react'
|
|||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import {
|
||||
Alert,
|
||||
Checkbox,
|
||||
Icon,
|
||||
Form,
|
||||
FormGroup,
|
||||
FormControl,
|
||||
Spinner
|
||||
} from 'patternfly-react'
|
||||
|
||||
import { fetchStatus } from '../api'
|
||||
import { fetchStatusIfNeeded } from '../actions/status'
|
||||
import Pipeline from '../containers/status/Pipeline'
|
||||
import Refreshable from '../containers/Refreshable'
|
||||
|
||||
|
||||
class StatusPage extends React.Component {
|
||||
class StatusPage extends Refreshable {
|
||||
static propTypes = {
|
||||
location: PropTypes.object,
|
||||
tenant: PropTypes.object
|
||||
tenant: PropTypes.object,
|
||||
remoteData: PropTypes.object,
|
||||
dispatch: PropTypes.func
|
||||
}
|
||||
|
||||
state = {
|
||||
status: null,
|
||||
filter: null,
|
||||
expanded: false,
|
||||
error: null,
|
||||
loading: false,
|
||||
autoReload: true
|
||||
}
|
||||
|
||||
|
@ -84,29 +82,11 @@ class StatusPage extends React.Component {
|
|||
}
|
||||
|
||||
updateData = (force) => {
|
||||
/* // Create fake delay
|
||||
function sleeper(ms) {
|
||||
return function(x) {
|
||||
return new Promise(resolve => setTimeout(() => resolve(x), ms));
|
||||
};
|
||||
}
|
||||
*/
|
||||
|
||||
if (force || (this.visible && this.state.autoReload)) {
|
||||
this.setState({error: null, loading: true})
|
||||
fetchStatus(this.props.tenant.apiPrefix)
|
||||
// .then(sleeper(2000))
|
||||
.then(response => {
|
||||
this.setState({status: response.data, loading: false})
|
||||
if (this.state.autoReload) {
|
||||
this.timer = setTimeout(this.updateData, 5000)
|
||||
}
|
||||
}).catch(error => {
|
||||
this.setState({error: error.message, status: null})
|
||||
if (this.state.autoReload) {
|
||||
this.timer = setTimeout(this.updateData, 5000)
|
||||
}
|
||||
})
|
||||
this.props.dispatch(fetchStatusIfNeeded(this.props.tenant))
|
||||
.then(() => {if (this.state.autoReload) {
|
||||
this.timer = setTimeout(this.updateData, 5000)
|
||||
}})
|
||||
}
|
||||
// Clear any running timer
|
||||
if (this.timer) {
|
||||
|
@ -118,18 +98,7 @@ class StatusPage extends React.Component {
|
|||
componentDidMount () {
|
||||
document.title = 'Zuul Status'
|
||||
this.loadState()
|
||||
if (this.props.tenant.name) {
|
||||
this.updateData()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps, prevState) {
|
||||
// When autoReload is set, also call updateData to retrigger the setTimeout
|
||||
if (this.props.tenant.name !== prevProps.tenant.name || (
|
||||
this.state.autoReload &&
|
||||
this.state.autoReload !== prevState.autoReload)) {
|
||||
this.updateData()
|
||||
}
|
||||
super.componentDidMount()
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
|
@ -221,10 +190,9 @@ class StatusPage extends React.Component {
|
|||
}
|
||||
|
||||
render () {
|
||||
const { autoReload, error, status, filter, expanded, loading } = this.state
|
||||
if (error) {
|
||||
return (<Alert>{this.state.error}</Alert>)
|
||||
}
|
||||
const { remoteData } = this.props
|
||||
const { autoReload, filter, expanded } = this.state
|
||||
const status = remoteData.status
|
||||
if (this.filter && !this.filterLoaded && filter) {
|
||||
this.filterLoaded = true
|
||||
this.filter.value = filter
|
||||
|
@ -261,11 +229,7 @@ class StatusPage extends React.Component {
|
|||
return (
|
||||
<React.Fragment>
|
||||
<div className="pull-right" style={{display: 'flex'}}>
|
||||
<Spinner loading={loading}>
|
||||
<a className="refresh" onClick={() => {this.updateData(true)}}>
|
||||
<Icon type="fa" name="refresh" /> refresh
|
||||
</a>
|
||||
</Spinner>
|
||||
{this.renderSpinner()}
|
||||
<Checkbox
|
||||
defaultChecked={autoReload}
|
||||
onChange={(e) => {this.setState({autoReload: e.target.checked})}}
|
||||
|
@ -291,4 +255,7 @@ class StatusPage extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
export default connect(state => ({tenant: state.tenant}))(StatusPage)
|
||||
export default connect(state => ({
|
||||
tenant: state.tenant,
|
||||
remoteData: state.status,
|
||||
}))(StatusPage)
|
||||
|
|
|
@ -17,12 +17,14 @@ import { combineReducers } from 'redux'
|
|||
import configErrors from './configErrors'
|
||||
import errors from './errors'
|
||||
import info from './info'
|
||||
import status from './status'
|
||||
import tenant from './tenant'
|
||||
|
||||
const reducers = {
|
||||
info,
|
||||
configErrors,
|
||||
errors,
|
||||
status,
|
||||
tenant,
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// 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 {
|
||||
STATUS_FETCH_FAIL,
|
||||
STATUS_FETCH_REQUEST,
|
||||
STATUS_FETCH_SUCCESS
|
||||
} from '../actions/status'
|
||||
|
||||
export default (state = {
|
||||
isFetching: false,
|
||||
status: null
|
||||
}, action) => {
|
||||
switch (action.type) {
|
||||
case STATUS_FETCH_REQUEST:
|
||||
return {
|
||||
isFetching: true,
|
||||
status: state.status
|
||||
}
|
||||
case STATUS_FETCH_SUCCESS:
|
||||
return {
|
||||
isFetching: false,
|
||||
status: action.status,
|
||||
}
|
||||
case STATUS_FETCH_FAIL:
|
||||
return {
|
||||
isFetching: false,
|
||||
status: state.status,
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue