summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2018-12-31 05:28:25 +0000
committerGerrit Code Review <review@openstack.org>2018-12-31 05:28:25 +0000
commit572065397074837b4137fb3d3b3404deb50d41ea (patch)
treeacdea0d8a7cb38c724a346be169c6c1070e1c317
parentafa918bfcd88163dfe28b2a62d61505194c1aa04 (diff)
parent753d79c13a6a5d486ceb8bc693b9b5b348bf4c36 (diff)
Merge "web: refactor projects page to use a reducer"
-rw-r--r--web/src/actions/projects.js62
-rw-r--r--web/src/pages/Projects.jsx68
-rw-r--r--web/src/reducers/index.js2
-rw-r--r--web/src/reducers/projects.js47
4 files changed, 145 insertions, 34 deletions
diff --git a/web/src/actions/projects.js b/web/src/actions/projects.js
new file mode 100644
index 0000000..18c91ea
--- /dev/null
+++ b/web/src/actions/projects.js
@@ -0,0 +1,62 @@
1/* global Promise */
2// Copyright 2018 Red Hat, Inc
3//
4// Licensed under the Apache License, Version 2.0 (the "License"); you may
5// not use this file except in compliance with the License. You may obtain
6// a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13// License for the specific language governing permissions and limitations
14// under the License.
15
16import * as API from '../api'
17
18export const PROJECTS_FETCH_REQUEST = 'PROJECTS_FETCH_REQUEST'
19export const PROJECTS_FETCH_SUCCESS = 'PROJECTS_FETCH_SUCCESS'
20export const PROJECTS_FETCH_FAIL = 'PROJECTS_FETCH_FAIL'
21
22export const requestProjects = () => ({
23 type: PROJECTS_FETCH_REQUEST
24})
25
26export const receiveProjects = (tenant, json) => ({
27 type: PROJECTS_FETCH_SUCCESS,
28 tenant: tenant,
29 projects: json,
30 receivedAt: Date.now()
31})
32
33const failedProjects = error => ({
34 type: PROJECTS_FETCH_FAIL,
35 error
36})
37
38const fetchProjects = (tenant) => dispatch => {
39 dispatch(requestProjects())
40 return API.fetchProjects(tenant.apiPrefix)
41 .then(response => dispatch(receiveProjects(tenant.name, response.data)))
42 .catch(error => dispatch(failedProjects(error)))
43}
44
45const shouldFetchProjects = (tenant, state) => {
46 const projects = state.projects.projects[tenant.name]
47 if (!projects || projects.length === 0) {
48 return true
49 }
50 if (projects.isFetching) {
51 return false
52 }
53 return false
54}
55
56export const fetchProjectsIfNeeded = (tenant, force) => (
57 dispatch, getState) => {
58 if (force || shouldFetchProjects(tenant, getState())) {
59 return dispatch(fetchProjects(tenant))
60 }
61 return Promise.resolve()
62}
diff --git a/web/src/pages/Projects.jsx b/web/src/pages/Projects.jsx
index a8b9dec..06c0960 100644
--- a/web/src/pages/Projects.jsx
+++ b/web/src/pages/Projects.jsx
@@ -18,39 +18,30 @@ import { connect } from 'react-redux'
18import { Link } from 'react-router-dom' 18import { Link } from 'react-router-dom'
19import { Table } from 'patternfly-react' 19import { Table } from 'patternfly-react'
20 20
21import { fetchProjects } from '../api' 21import { fetchProjectsIfNeeded } from '../actions/projects'
22import Refreshable from '../containers/Refreshable'
22 23
23 24
24class ProjectsPage extends React.Component { 25class ProjectsPage extends Refreshable {
25 static propTypes = { 26 static propTypes = {
26 tenant: PropTypes.object 27 tenant: PropTypes.object,
28 remoteData: PropTypes.object,
29 dispatch: PropTypes.func
27 } 30 }
28 31
29 state = { 32 updateData (force) {
30 projects: null 33 this.props.dispatch(fetchProjectsIfNeeded(this.props.tenant, force))
31 }
32
33 updateData () {
34 fetchProjects(this.props.tenant.apiPrefix).then(response => {
35 this.setState({projects: response.data})
36 })
37 } 34 }
38 35
39 componentDidMount () { 36 componentDidMount () {
40 document.title = 'Zuul Projects' 37 document.title = 'Zuul Projects'
41 if (this.props.tenant.name) { 38 super.componentDidMount()
42 this.updateData()
43 }
44 }
45
46 componentDidUpdate (prevProps) {
47 if (this.props.tenant.name !== prevProps.tenant.name) {
48 this.updateData()
49 }
50 } 39 }
51 40
52 render () { 41 render () {
53 const { projects } = this.state 42 const { remoteData } = this.props
43 const projects = remoteData.projects[this.props.tenant.name]
44
54 if (!projects) { 45 if (!projects) {
55 return (<p>Loading...</p>) 46 return (<p>Loading...</p>)
56 } 47 }
@@ -91,19 +82,28 @@ class ProjectsPage extends React.Component {
91 }) 82 })
92 }) 83 })
93 return ( 84 return (
94 <Table.PfProvider 85 <React.Fragment>
95 striped 86 <div style={{float: 'right'}}>
96 bordered 87 {this.renderSpinner()}
97 hover 88 </div>
98 columns={columns} 89 <Table.PfProvider
99 > 90 striped
100 <Table.Header/> 91 bordered
101 <Table.Body 92 hover
102 rows={projects} 93 columns={columns}
103 rowKey="name" 94 >
104 /> 95 <Table.Header/>
105 </Table.PfProvider>) 96 <Table.Body
97 rows={projects}
98 rowKey="name"
99 />
100 </Table.PfProvider>
101 </React.Fragment>
102 )
106 } 103 }
107} 104}
108 105
109export default connect(state => ({tenant: state.tenant}))(ProjectsPage) 106export default connect(state => ({
107 tenant: state.tenant,
108 remoteData: state.projects,
109}))(ProjectsPage)
diff --git a/web/src/reducers/index.js b/web/src/reducers/index.js
index 1b59fb8..4089f27 100644
--- a/web/src/reducers/index.js
+++ b/web/src/reducers/index.js
@@ -20,6 +20,7 @@ import errors from './errors'
20import info from './info' 20import info from './info'
21import job from './job' 21import job from './job'
22import jobs from './jobs' 22import jobs from './jobs'
23import projects from './projects'
23import status from './status' 24import status from './status'
24import tenant from './tenant' 25import tenant from './tenant'
25import tenants from './tenants' 26import tenants from './tenants'
@@ -29,6 +30,7 @@ const reducers = {
29 info, 30 info,
30 job, 31 job,
31 jobs, 32 jobs,
33 projects,
32 configErrors, 34 configErrors,
33 errors, 35 errors,
34 status, 36 status,
diff --git a/web/src/reducers/projects.js b/web/src/reducers/projects.js
new file mode 100644
index 0000000..758e2ce
--- /dev/null
+++ b/web/src/reducers/projects.js
@@ -0,0 +1,47 @@
1// Copyright 2018 Red Hat, Inc
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations
13// under the License.
14
15import {
16 PROJECTS_FETCH_FAIL,
17 PROJECTS_FETCH_REQUEST,
18 PROJECTS_FETCH_SUCCESS
19} from '../actions/projects'
20
21import update from 'immutability-helper'
22
23export default (state = {
24 isFetching: false,
25 projects: {},
26}, action) => {
27 switch (action.type) {
28 case PROJECTS_FETCH_REQUEST:
29 return {
30 isFetching: true,
31 projects: state.projects,
32 }
33 case PROJECTS_FETCH_SUCCESS:
34 return {
35 isFetching: false,
36 projects: update(
37 state.projects, {$merge: {[action.tenant]: action.projects}}),
38 }
39 case PROJECTS_FETCH_FAIL:
40 return {
41 isFetching: false,
42 projects: state.projects,
43 }
44 default:
45 return state
46 }
47}