Merge "web: refactor nodes page to use a reducer"
This commit is contained in:
commit
c66af50f64
|
@ -0,0 +1,63 @@
|
||||||
|
// 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 NODES_FETCH_REQUEST = 'NODES_FETCH_REQUEST'
|
||||||
|
export const NODES_FETCH_SUCCESS = 'NODES_FETCH_SUCCESS'
|
||||||
|
export const NODES_FETCH_FAIL = 'NODES_FETCH_FAIL'
|
||||||
|
|
||||||
|
export const requestNodes = () => ({
|
||||||
|
type: NODES_FETCH_REQUEST
|
||||||
|
})
|
||||||
|
|
||||||
|
export const receiveNodes = (tenant, json) => ({
|
||||||
|
type: NODES_FETCH_SUCCESS,
|
||||||
|
nodes: json,
|
||||||
|
receivedAt: Date.now()
|
||||||
|
})
|
||||||
|
|
||||||
|
const failedNodes = error => ({
|
||||||
|
type: NODES_FETCH_FAIL,
|
||||||
|
error
|
||||||
|
})
|
||||||
|
|
||||||
|
const fetchNodes = (tenant) => dispatch => {
|
||||||
|
dispatch(requestNodes())
|
||||||
|
return API.fetchNodes(tenant.apiPrefix)
|
||||||
|
.then(response => dispatch(receiveNodes(tenant.name, response.data)))
|
||||||
|
.catch(error => dispatch(failedNodes(error)))
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldFetchNodes = (tenant, state) => {
|
||||||
|
const nodes = state.nodes
|
||||||
|
if (!nodes || nodes.nodes.length === 0) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (nodes.isFetching) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (Date.now() - nodes.receivedAt > 60000) {
|
||||||
|
// Refetch after 1 minutes
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fetchNodesIfNeeded = (tenant, force) => (
|
||||||
|
dispatch, getState) => {
|
||||||
|
if (force || shouldFetchNodes(tenant, getState())) {
|
||||||
|
return dispatch(fetchNodes(tenant))
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,42 +18,29 @@ import { connect } from 'react-redux'
|
||||||
import { Table } from 'patternfly-react'
|
import { Table } from 'patternfly-react'
|
||||||
import * as moment from 'moment'
|
import * as moment from 'moment'
|
||||||
|
|
||||||
import { fetchNodes } from '../api'
|
import { fetchNodesIfNeeded } from '../actions/nodes'
|
||||||
|
import Refreshable from '../containers/Refreshable'
|
||||||
|
|
||||||
|
|
||||||
class NodesPage extends React.Component {
|
class NodesPage extends Refreshable {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
tenant: PropTypes.object
|
tenant: PropTypes.object,
|
||||||
|
remoteData: PropTypes.object,
|
||||||
|
dispatch: PropTypes.func
|
||||||
}
|
}
|
||||||
|
|
||||||
state = {
|
updateData (force) {
|
||||||
nodes: null
|
this.props.dispatch(fetchNodesIfNeeded(this.props.tenant, force))
|
||||||
}
|
|
||||||
|
|
||||||
updateData () {
|
|
||||||
fetchNodes(this.props.tenant.apiPrefix).then(response => {
|
|
||||||
this.setState({nodes: response.data})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
document.title = 'Zuul Nodes'
|
document.title = 'Zuul Nodes'
|
||||||
if (this.props.tenant.name) {
|
super.componentDidMount()
|
||||||
this.updateData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
|
||||||
if (this.props.tenant.name !== prevProps.tenant.name) {
|
|
||||||
this.updateData()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { nodes } = this.state
|
const { remoteData } = this.props
|
||||||
if (!nodes) {
|
const nodes = remoteData.nodes
|
||||||
return (<p>Loading...</p>)
|
|
||||||
}
|
|
||||||
|
|
||||||
const headerFormat = value => <Table.Heading>{value}</Table.Heading>
|
const headerFormat = value => <Table.Heading>{value}</Table.Heading>
|
||||||
const cellFormat = value => <Table.Cell>{value}</Table.Cell>
|
const cellFormat = value => <Table.Cell>{value}</Table.Cell>
|
||||||
|
@ -92,19 +79,28 @@ class NodesPage extends React.Component {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return (
|
return (
|
||||||
<Table.PfProvider
|
<React.Fragment>
|
||||||
striped
|
<div style={{float: 'right'}}>
|
||||||
bordered
|
{this.renderSpinner()}
|
||||||
hover
|
</div>
|
||||||
columns={columns}
|
<Table.PfProvider
|
||||||
>
|
striped
|
||||||
<Table.Header/>
|
bordered
|
||||||
<Table.Body
|
hover
|
||||||
rows={nodes}
|
columns={columns}
|
||||||
rowKey="id"
|
>
|
||||||
/>
|
<Table.Header/>
|
||||||
</Table.PfProvider>)
|
<Table.Body
|
||||||
|
rows={nodes}
|
||||||
|
rowKey="id"
|
||||||
|
/>
|
||||||
|
</Table.PfProvider>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(state => ({tenant: state.tenant}))(NodesPage)
|
export default connect(state => ({
|
||||||
|
tenant: state.tenant,
|
||||||
|
remoteData: state.nodes,
|
||||||
|
}))(NodesPage)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import info from './info'
|
||||||
import job from './job'
|
import job from './job'
|
||||||
import jobs from './jobs'
|
import jobs from './jobs'
|
||||||
import labels from './labels'
|
import labels from './labels'
|
||||||
|
import nodes from './nodes'
|
||||||
import project from './project'
|
import project from './project'
|
||||||
import projects from './projects'
|
import projects from './projects'
|
||||||
import status from './status'
|
import status from './status'
|
||||||
|
@ -33,6 +34,7 @@ const reducers = {
|
||||||
job,
|
job,
|
||||||
jobs,
|
jobs,
|
||||||
labels,
|
labels,
|
||||||
|
nodes,
|
||||||
project,
|
project,
|
||||||
projects,
|
projects,
|
||||||
configErrors,
|
configErrors,
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
// 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 {
|
||||||
|
NODES_FETCH_FAIL,
|
||||||
|
NODES_FETCH_REQUEST,
|
||||||
|
NODES_FETCH_SUCCESS
|
||||||
|
} from '../actions/nodes'
|
||||||
|
|
||||||
|
import update from 'immutability-helper'
|
||||||
|
|
||||||
|
export default (state = {
|
||||||
|
receivedAt: 0,
|
||||||
|
isFetching: false,
|
||||||
|
nodes: [],
|
||||||
|
}, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case NODES_FETCH_REQUEST:
|
||||||
|
return update(state, {$merge: {isFetching: true}})
|
||||||
|
case NODES_FETCH_SUCCESS:
|
||||||
|
return update(state, {$merge: {
|
||||||
|
isFetching: false,
|
||||||
|
nodes: action.nodes,
|
||||||
|
receivedAt: action.receivedAt
|
||||||
|
}})
|
||||||
|
case NODES_FETCH_FAIL:
|
||||||
|
return update(state, {$merge: {isFetching: false}})
|
||||||
|
default:
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue