Browse Source

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

tags/3.4.0
Zuul 5 months ago
parent
commit
000c92b81b
4 changed files with 135 additions and 37 deletions
  1. 60
    0
      web/src/actions/build.js
  2. 34
    37
      web/src/pages/Build.jsx
  3. 39
    0
      web/src/reducers/build.js
  4. 2
    0
      web/src/reducers/index.js

+ 60
- 0
web/src/actions/build.js View File

@@ -0,0 +1,60 @@
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 * as API from '../api'
16
+
17
+export const BUILD_FETCH_REQUEST = 'BUILD_FETCH_REQUEST'
18
+export const BUILD_FETCH_SUCCESS = 'BUILD_FETCH_SUCCESS'
19
+export const BUILD_FETCH_FAIL = 'BUILD_FETCH_FAIL'
20
+
21
+export const requestBuild = () => ({
22
+  type: BUILD_FETCH_REQUEST
23
+})
24
+
25
+export const receiveBuild = (buildId, build) => ({
26
+  type: BUILD_FETCH_SUCCESS,
27
+  buildId: buildId,
28
+  build: build,
29
+  receivedAt: Date.now()
30
+})
31
+
32
+const failedBuild = error => ({
33
+  type: BUILD_FETCH_FAIL,
34
+  error
35
+})
36
+
37
+const fetchBuild = (tenant, build) => dispatch => {
38
+  dispatch(requestBuild())
39
+  return API.fetchBuild(tenant.apiPrefix, build)
40
+    .then(response => dispatch(receiveBuild(build, response.data)))
41
+    .catch(error => dispatch(failedBuild(error)))
42
+}
43
+
44
+const shouldFetchBuild = (buildId, state) => {
45
+  const build = state.build.builds[buildId]
46
+  if (!build) {
47
+    return true
48
+  }
49
+  if (build.isFetching) {
50
+    return false
51
+  }
52
+  return false
53
+}
54
+
55
+export const fetchBuildIfNeeded = (tenant, buildId, force) => (
56
+  dispatch, getState) => {
57
+    if (force || shouldFetchBuild(buildId, getState())) {
58
+      return dispatch(fetchBuild(tenant, buildId))
59
+    }
60
+}

+ 34
- 37
web/src/pages/Build.jsx View File

@@ -18,41 +18,30 @@ import PropTypes from 'prop-types'
18 18
 import { Link } from 'react-router-dom'
19 19
 import { Panel } from 'react-bootstrap'
20 20
 
21
-import { fetchBuild } from '../api'
21
+import { fetchBuildIfNeeded } from '../actions/build'
22
+import Refreshable from '../containers/Refreshable'
22 23
 
23 24
 
24
-class BuildPage extends React.Component {
25
+class BuildPage extends Refreshable {
25 26
   static propTypes = {
26 27
     match: PropTypes.object.isRequired,
28
+    remoteData: PropTypes.object,
27 29
     tenant: PropTypes.object
28 30
   }
29 31
 
30
-  state = {
31
-    build: null
32
-  }
33
-
34
-  updateData = () => {
35
-    fetchBuild(this.props.tenant.apiPrefix, this.props.match.params.buildId)
36
-      .then(response => {
37
-        this.setState({build: response.data})
38
-      })
32
+  updateData = (force) => {
33
+    this.props.dispatch(fetchBuildIfNeeded(
34
+      this.props.tenant, this.props.match.params.buildId, force))
39 35
   }
40 36
 
41 37
   componentDidMount () {
42 38
     document.title = 'Zuul Build'
43
-    if (this.props.tenant.name) {
44
-      this.updateData()
45
-    }
46
-  }
47
-
48
-  componentDidUpdate (prevProps) {
49
-    if (this.props.tenant.name !== prevProps.tenant.name) {
50
-      this.updateData()
51
-    }
39
+    super.componentDidMount()
52 40
   }
53 41
 
54 42
   render () {
55
-    const { build } = this.state
43
+    const { remoteData } = this.props
44
+    const build = remoteData.builds[this.props.match.params.buildId]
56 45
     if (!build) {
57 46
       return (<p>Loading...</p>)
58 47
     }
@@ -95,23 +84,31 @@ class BuildPage extends React.Component {
95 84
       }
96 85
     })
97 86
     return (
98
-      <Panel>
99
-        <Panel.Heading>Build result {build.uuid}</Panel.Heading>
100
-        <Panel.Body>
101
-          <table className="table table-striped table-bordered">
102
-            <tbody>
103
-              {rows.map(item => (
104
-                <tr key={item.key}>
105
-                  <td>{item.key}</td>
106
-                  <td>{item.value}</td>
107
-                </tr>
108
-              ))}
109
-            </tbody>
110
-          </table>
111
-        </Panel.Body>
112
-      </Panel>
87
+      <React.Fragment>
88
+        <div style={{float: 'right'}}>
89
+          {this.renderSpinner()}
90
+        </div>
91
+        <Panel>
92
+          <Panel.Heading>Build result {build.uuid}</Panel.Heading>
93
+          <Panel.Body>
94
+            <table className="table table-striped table-bordered">
95
+              <tbody>
96
+                {rows.map(item => (
97
+                  <tr key={item.key}>
98
+                    <td>{item.key}</td>
99
+                    <td>{item.value}</td>
100
+                  </tr>
101
+                ))}
102
+              </tbody>
103
+            </table>
104
+          </Panel.Body>
105
+        </Panel>
106
+      </React.Fragment>
113 107
     )
114 108
   }
115 109
 }
116 110
 
117
-export default connect(state => ({tenant: state.tenant}))(BuildPage)
111
+export default connect(state => ({
112
+  tenant: state.tenant,
113
+  remoteData: state.build,
114
+}))(BuildPage)

+ 39
- 0
web/src/reducers/build.js View File

@@ -0,0 +1,39 @@
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
+  BUILD_FETCH_FAIL,
17
+  BUILD_FETCH_REQUEST,
18
+  BUILD_FETCH_SUCCESS
19
+} from '../actions/build'
20
+
21
+import update from 'immutability-helper'
22
+
23
+export default (state = {
24
+  isFetching: false,
25
+  builds: {},
26
+}, action) => {
27
+  switch (action.type) {
28
+    case BUILD_FETCH_REQUEST:
29
+      return update(state, {$merge: {isFetching: true}})
30
+    case BUILD_FETCH_SUCCESS:
31
+      state.builds = update(
32
+        state.builds, {$merge: {[action.buildId]: action.build}})
33
+      return update(state, {$merge: {isFetching: false}})
34
+    case BUILD_FETCH_FAIL:
35
+      return update(state, {$merge: {isFetching: false}})
36
+    default:
37
+      return state
38
+  }
39
+}

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

@@ -17,6 +17,7 @@ import { combineReducers } from 'redux'
17 17
 import configErrors from './configErrors'
18 18
 import change from './change'
19 19
 import errors from './errors'
20
+import build from './build'
20 21
 import info from './info'
21 22
 import job from './job'
22 23
 import jobs from './jobs'
@@ -30,6 +31,7 @@ import tenants from './tenants'
30 31
 
31 32
 const reducers = {
32 33
   change,
34
+  build,
33 35
   info,
34 36
   job,
35 37
   jobs,

Loading…
Cancel
Save