From e5da1e11491e429c6427c8f46f2c2db2bf620682 Mon Sep 17 00:00:00 2001 From: Tristan Cacqueray Date: Fri, 14 Dec 2018 03:42:16 +0000 Subject: [PATCH] web: refactor change page to use a reducer This change updates the change page component to dispatch reducer action instead of direct axios call. This enables using the generic error reducers. Change-Id: If5fedff89e55eddfd08ea224c0124f3b2f9255c4 --- web/src/actions/change.js | 61 ++++++++++++++++++++++++++++++++++ web/src/pages/ChangeStatus.jsx | 55 +++++++++++------------------- web/src/reducers/change.js | 44 ++++++++++++++++++++++++ web/src/reducers/index.js | 2 ++ 4 files changed, 127 insertions(+), 35 deletions(-) create mode 100644 web/src/actions/change.js create mode 100644 web/src/reducers/change.js diff --git a/web/src/actions/change.js b/web/src/actions/change.js new file mode 100644 index 0000000000..9029828e58 --- /dev/null +++ b/web/src/actions/change.js @@ -0,0 +1,61 @@ +/* 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 CHANGE_FETCH_REQUEST = 'CHANGE_FETCH_REQUEST' +export const CHANGE_FETCH_SUCCESS = 'CHANGE_FETCH_SUCCESS' +export const CHANGE_FETCH_FAIL = 'CHANGE_FETCH_FAIL' + +export const requestChange = () => ({ + type: CHANGE_FETCH_REQUEST +}) + +export const receiveChange = json => ({ + type: CHANGE_FETCH_SUCCESS, + change: json, + receivedAt: Date.now() +}) + +const failedChange = error => ({ + type: CHANGE_FETCH_FAIL, + error +}) + +const fetchChange = (tenant, changeId) => dispatch => { + dispatch(requestChange()) + return API.fetchChangeStatus(tenant.apiPrefix, changeId) + .then(response => dispatch(receiveChange(response.data))) + .catch(error => dispatch(failedChange(error))) +} + +const shouldFetchChange = state => { + const change = state.change + if (!change) { + return true + } + if (change.isFetching) { + return false + } + return true +} + +export const fetchChangeIfNeeded = (tenant, change, force) => ( + dispatch, getState) => { + if (force || shouldFetchChange(getState())) { + return dispatch(fetchChange(tenant, change)) + } + return Promise.resolve() +} diff --git a/web/src/pages/ChangeStatus.jsx b/web/src/pages/ChangeStatus.jsx index 3ffb88e81d..0abbf6d7cc 100644 --- a/web/src/pages/ChangeStatus.jsx +++ b/web/src/pages/ChangeStatus.jsx @@ -16,53 +16,34 @@ import * as React from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' -import { - Alert, -} from 'patternfly-react' -import { fetchChangeStatus } from '../api' +import { fetchChangeIfNeeded } from '../actions/change' import ChangePanel from '../containers/status/ChangePanel' +import Refreshable from '../containers/Refreshable' -class ChangeStatusPage extends React.Component { +class ChangeStatusPage extends Refreshable { static propTypes = { match: PropTypes.object.isRequired, - tenant: PropTypes.object + tenant: PropTypes.object, + remoteData: PropTypes.object, + dispatch: PropTypes.func } - state = { - change: null, - error: null, - } - - updateData = () => { + updateData = (force) => { + this.props.dispatch(fetchChangeIfNeeded( + this.props.tenant, this.props.match.params.changeId, force)) + .then(() => {this.timer = setTimeout(this.updateData, 5000)}) // Clear any running timer if (this.timer) { clearTimeout(this.timer) this.timer = null } - this.setState({error: null}) - fetchChangeStatus( - this.props.tenant.apiPrefix, this.props.match.params.changeId) - .then(response => { - this.setState({change: response.data}) - }).catch(error => { - this.setState({error: error.message, change: null}) - }) - this.timer = setTimeout(this.updateData, 5000) } componentDidMount () { document.title = this.props.match.params.changeId + ' | Zuul Status' - if (this.props.tenant.name) { - this.updateData() - } - } - - componentDidUpdate (prevProps) { - if (this.props.tenant.name !== prevProps.tenant.name) { - this.updateData() - } + super.componentDidMount() } componentWillUnmount () { @@ -73,12 +54,13 @@ class ChangeStatusPage extends React.Component { } render () { - const { error, change } = this.state - if (error) { - return ({this.state.error}) - } + const { remoteData } = this.props + const change = remoteData.change return ( +
+ {this.renderSpinner()} +

{change && change.map((item, idx) => (
({tenant: state.tenant}))(ChangeStatusPage) +export default connect(state => ({ + tenant: state.tenant, + remoteData: state.change +}))(ChangeStatusPage) diff --git a/web/src/reducers/change.js b/web/src/reducers/change.js new file mode 100644 index 0000000000..73bb545110 --- /dev/null +++ b/web/src/reducers/change.js @@ -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 { + CHANGE_FETCH_FAIL, + CHANGE_FETCH_REQUEST, + CHANGE_FETCH_SUCCESS +} from '../actions/change' + +export default (state = { + isFetching: false, + change: null +}, action) => { + switch (action.type) { + case CHANGE_FETCH_REQUEST: + return { + isFetching: true, + change: state.change + } + case CHANGE_FETCH_SUCCESS: + return { + isFetching: false, + change: action.change, + } + case CHANGE_FETCH_FAIL: + return { + isFetching: false, + change: state.change, + } + default: + return state + } +} diff --git a/web/src/reducers/index.js b/web/src/reducers/index.js index fd7014844a..1b59fb835d 100644 --- a/web/src/reducers/index.js +++ b/web/src/reducers/index.js @@ -15,6 +15,7 @@ import { combineReducers } from 'redux' import configErrors from './configErrors' +import change from './change' import errors from './errors' import info from './info' import job from './job' @@ -24,6 +25,7 @@ import tenant from './tenant' import tenants from './tenants' const reducers = { + change, info, job, jobs,