Browse Source

Merge "web: refactor projects page to use a reducer"

tags/3.4.0
Zuul 5 months ago
parent
commit
5720653970
4 changed files with 145 additions and 34 deletions
  1. 62
    0
      web/src/actions/projects.js
  2. 34
    34
      web/src/pages/Projects.jsx
  3. 2
    0
      web/src/reducers/index.js
  4. 47
    0
      web/src/reducers/projects.js

+ 62
- 0
web/src/actions/projects.js View File

@@ -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
+
16
+import * as API from '../api'
17
+
18
+export const PROJECTS_FETCH_REQUEST = 'PROJECTS_FETCH_REQUEST'
19
+export const PROJECTS_FETCH_SUCCESS = 'PROJECTS_FETCH_SUCCESS'
20
+export const PROJECTS_FETCH_FAIL = 'PROJECTS_FETCH_FAIL'
21
+
22
+export const requestProjects = () => ({
23
+  type: PROJECTS_FETCH_REQUEST
24
+})
25
+
26
+export const receiveProjects = (tenant, json) => ({
27
+  type: PROJECTS_FETCH_SUCCESS,
28
+  tenant: tenant,
29
+  projects: json,
30
+  receivedAt: Date.now()
31
+})
32
+
33
+const failedProjects = error => ({
34
+  type: PROJECTS_FETCH_FAIL,
35
+  error
36
+})
37
+
38
+const 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
+
45
+const 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
+
56
+export const fetchProjectsIfNeeded = (tenant, force) => (
57
+  dispatch, getState) => {
58
+    if (force || shouldFetchProjects(tenant, getState())) {
59
+      return dispatch(fetchProjects(tenant))
60
+    }
61
+    return Promise.resolve()
62
+}

+ 34
- 34
web/src/pages/Projects.jsx View File

@@ -18,39 +18,30 @@ import { connect } from 'react-redux'
18 18
 import { Link } from 'react-router-dom'
19 19
 import { Table } from 'patternfly-react'
20 20
 
21
-import { fetchProjects } from '../api'
21
+import { fetchProjectsIfNeeded } from '../actions/projects'
22
+import Refreshable from '../containers/Refreshable'
22 23
 
23 24
 
24
-class ProjectsPage extends React.Component {
25
+class ProjectsPage extends Refreshable {
25 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 = {
30
-    projects: null
31
-  }
32
-
33
-  updateData () {
34
-    fetchProjects(this.props.tenant.apiPrefix).then(response => {
35
-      this.setState({projects: response.data})
36
-    })
32
+  updateData (force) {
33
+    this.props.dispatch(fetchProjectsIfNeeded(this.props.tenant, force))
37 34
   }
38 35
 
39 36
   componentDidMount () {
40 37
     document.title = 'Zuul Projects'
41
-    if (this.props.tenant.name) {
42
-      this.updateData()
43
-    }
44
-  }
45
-
46
-  componentDidUpdate (prevProps) {
47
-    if (this.props.tenant.name !== prevProps.tenant.name) {
48
-      this.updateData()
49
-    }
38
+    super.componentDidMount()
50 39
   }
51 40
 
52 41
   render () {
53
-    const { projects } = this.state
42
+    const { remoteData } = this.props
43
+    const projects = remoteData.projects[this.props.tenant.name]
44
+
54 45
     if (!projects) {
55 46
       return (<p>Loading...</p>)
56 47
     }
@@ -91,19 +82,28 @@ class ProjectsPage extends React.Component {
91 82
       })
92 83
     })
93 84
     return (
94
-      <Table.PfProvider
95
-        striped
96
-        bordered
97
-        hover
98
-        columns={columns}
99
-      >
100
-        <Table.Header/>
101
-        <Table.Body
102
-          rows={projects}
103
-          rowKey="name"
104
-        />
105
-      </Table.PfProvider>)
85
+      <React.Fragment>
86
+        <div style={{float: 'right'}}>
87
+          {this.renderSpinner()}
88
+        </div>
89
+        <Table.PfProvider
90
+          striped
91
+          bordered
92
+          hover
93
+          columns={columns}
94
+        >
95
+          <Table.Header/>
96
+          <Table.Body
97
+            rows={projects}
98
+            rowKey="name"
99
+          />
100
+        </Table.PfProvider>
101
+      </React.Fragment>
102
+    )
106 103
   }
107 104
 }
108 105
 
109
-export default connect(state => ({tenant: state.tenant}))(ProjectsPage)
106
+export default connect(state => ({
107
+  tenant: state.tenant,
108
+  remoteData: state.projects,
109
+}))(ProjectsPage)

+ 2
- 0
web/src/reducers/index.js View File

@@ -20,6 +20,7 @@ import errors from './errors'
20 20
 import info from './info'
21 21
 import job from './job'
22 22
 import jobs from './jobs'
23
+import projects from './projects'
23 24
 import status from './status'
24 25
 import tenant from './tenant'
25 26
 import tenants from './tenants'
@@ -29,6 +30,7 @@ const reducers = {
29 30
   info,
30 31
   job,
31 32
   jobs,
33
+  projects,
32 34
   configErrors,
33 35
   errors,
34 36
   status,

+ 47
- 0
web/src/reducers/projects.js View File

@@ -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
+
15
+import {
16
+  PROJECTS_FETCH_FAIL,
17
+  PROJECTS_FETCH_REQUEST,
18
+  PROJECTS_FETCH_SUCCESS
19
+} from '../actions/projects'
20
+
21
+import update from 'immutability-helper'
22
+
23
+export 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
+}

Loading…
Cancel
Save