summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2019-03-07 21:50:12 +0000
committerGerrit Code Review <review@openstack.org>2019-03-07 21:50:12 +0000
commite9900ca1d4570908592491d7eb7cbb1fc1da9ba4 (patch)
tree767c6b345ee62a83708bdff602e54764d696bc45
parent7ca96c254824e542cd13dfec3b7933c28ad52c51 (diff)
parent84fefd146d7e4f69c04c0f2abadc93ad802381c7 (diff)
Merge "web: add buildsets page"
-rw-r--r--web/src/api.js8
-rw-r--r--web/src/pages/Buildsets.jsx150
-rw-r--r--web/src/pages/Tenants.jsx5
-rw-r--r--web/src/routes.js6
4 files changed, 168 insertions, 1 deletions
diff --git a/web/src/api.js b/web/src/api.js
index 7354226..429afbc 100644
--- a/web/src/api.js
+++ b/web/src/api.js
@@ -128,6 +128,13 @@ function fetchBuilds (apiPrefix, queryString) {
128 } 128 }
129 return Axios.get(apiUrl + apiPrefix + path) 129 return Axios.get(apiUrl + apiPrefix + path)
130} 130}
131function fetchBuildsets (apiPrefix, queryString) {
132 let path = 'buildsets'
133 if (queryString) {
134 path += '?' + queryString.slice(1)
135 }
136 return Axios.get(apiUrl + apiPrefix + path)
137}
131function fetchProject (apiPrefix, projectName) { 138function fetchProject (apiPrefix, projectName) {
132 return Axios.get(apiUrl + apiPrefix + 'project/' + projectName) 139 return Axios.get(apiUrl + apiPrefix + 'project/' + projectName)
133} 140}
@@ -155,6 +162,7 @@ export {
155 fetchStatus, 162 fetchStatus,
156 fetchBuild, 163 fetchBuild,
157 fetchBuilds, 164 fetchBuilds,
165 fetchBuildsets,
158 fetchProject, 166 fetchProject,
159 fetchProjects, 167 fetchProjects,
160 fetchJob, 168 fetchJob,
diff --git a/web/src/pages/Buildsets.jsx b/web/src/pages/Buildsets.jsx
new file mode 100644
index 0000000..2d5721b
--- /dev/null
+++ b/web/src/pages/Buildsets.jsx
@@ -0,0 +1,150 @@
1// Copyright 2019 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 * as React from 'react'
16import PropTypes from 'prop-types'
17import { connect } from 'react-redux'
18import { Table } from 'patternfly-react'
19
20import { fetchBuildsets } from '../api'
21import TableFilters from '../containers/TableFilters'
22
23
24class BuildsetsPage extends TableFilters {
25 static propTypes = {
26 tenant: PropTypes.object
27 }
28
29 constructor () {
30 super()
31
32 this.prepareTableHeaders()
33 this.state = {
34 buildsets: null,
35 currentFilterType: this.filterTypes[0],
36 activeFilters: [],
37 currentValue: ''
38 }
39 }
40
41 updateData = (filters) => {
42 let queryString = ''
43 if (filters) {
44 filters.forEach(item => queryString += '&' + item.key + '=' + item.value)
45 }
46 this.setState({buildsets: null})
47 fetchBuildsets(this.props.tenant.apiPrefix, queryString).then(response => {
48 this.setState({buildsets: response.data})
49 })
50 }
51
52 componentDidMount () {
53 document.title = 'Zuul Buildsets'
54 if (this.props.tenant.name) {
55 this.updateData(this.getFilterFromUrl())
56 }
57 }
58
59 componentDidUpdate (prevProps) {
60 if (this.props.tenant.name !== prevProps.tenant.name) {
61 this.updateData(this.getFilterFromUrl())
62 }
63 }
64
65 prepareTableHeaders() {
66 const headerFormat = value => <Table.Heading>{value}</Table.Heading>
67 const cellFormat = (value) => <Table.Cell>{value}</Table.Cell>
68 const linkChangeFormat = (value, rowdata) => (
69 <Table.Cell>
70 <a href={rowdata.rowData.ref_url}>
71 {value ?
72 rowdata.rowData.change + ',' + rowdata.rowData.patchset :
73 rowdata.rowData.newrev ?
74 rowdata.rowData.newrev.substr(0, 7) :
75 rowdata.rowData.branch}
76 </a>
77 </Table.Cell>
78 )
79 this.columns = []
80 this.filterTypes = []
81 const myColumns = [
82 'project',
83 'branch',
84 'pipeline',
85 'change',
86 'result']
87 myColumns.forEach(column => {
88 let prop = column
89 let formatter = cellFormat
90 if (column === 'change') {
91 formatter = linkChangeFormat
92 }
93 const label = column.charAt(0).toUpperCase() + column.slice(1)
94 this.columns.push({
95 header: {label: label, formatters: [headerFormat]},
96 property: prop,
97 cell: {formatters: [formatter]}
98 })
99 if (column !== 'builds') {
100 this.filterTypes.push({
101 id: prop,
102 title: label,
103 placeholder: 'Filter by ' + label,
104 filterType: 'text',
105 })
106 }
107 })
108 // Add buildset filter at the end
109 this.filterTypes.push({
110 id: 'uuid',
111 title: 'Buildset',
112 palceholder: 'Filter by Buildset UUID',
113 fileterType: 'text',
114 })
115 }
116
117 renderTable (buildsets) {
118 return (
119 <Table.PfProvider
120 striped
121 bordered
122 columns={this.columns}
123 >
124 <Table.Header/>
125 <Table.Body
126 rows={buildsets}
127 rowKey='uuid'
128 onRow={(row) => {
129 switch (row.result) {
130 case 'SUCCESS':
131 return { className: 'success' }
132 default:
133 return { className: 'warning' }
134 }
135 }} />
136 </Table.PfProvider>)
137 }
138
139 render() {
140 const { buildsets } = this.state
141 return (
142 <React.Fragment>
143 {this.renderFilter()}
144 {buildsets ? this.renderTable(buildsets) : <p>Loading...</p>}
145 </React.Fragment>
146 )
147 }
148}
149
150export default connect(state => ({tenant: state.tenant}))(BuildsetsPage)
diff --git a/web/src/pages/Tenants.jsx b/web/src/pages/Tenants.jsx
index f7be37b..b439c72 100644
--- a/web/src/pages/Tenants.jsx
+++ b/web/src/pages/Tenants.jsx
@@ -48,7 +48,8 @@ class TenantsPage extends Refreshable {
48 <Table.Cell>{value}</Table.Cell>) 48 <Table.Cell>{value}</Table.Cell>)
49 const columns = [] 49 const columns = []
50 const myColumns = [ 50 const myColumns = [
51 'name', 'status', 'projects', 'jobs', 'builds', 'projects count', 'queue'] 51 'name', 'status', 'projects', 'jobs', 'builds', 'buildsets',
52 'projects count', 'queue']
52 myColumns.forEach(column => { 53 myColumns.forEach(column => {
53 let prop = column 54 let prop = column
54 if (column === 'projects count') { 55 if (column === 'projects count') {
@@ -72,6 +73,8 @@ class TenantsPage extends Refreshable {
72 <Link to={'/t/' + tenant.name + '/jobs'}>Jobs</Link>) 73 <Link to={'/t/' + tenant.name + '/jobs'}>Jobs</Link>)
73 tenant.builds = ( 74 tenant.builds = (
74 <Link to={'/t/' + tenant.name + '/builds'}>Builds</Link>) 75 <Link to={'/t/' + tenant.name + '/builds'}>Builds</Link>)
76 tenant.buildsets = (
77 <Link to={'/t/' + tenant.name + '/buildsets'}>Buildsets</Link>)
75 }) 78 })
76 return ( 79 return (
77 <React.Fragment> 80 <React.Fragment>
diff --git a/web/src/routes.js b/web/src/routes.js
index ee93ab4..c8e9cc8 100644
--- a/web/src/routes.js
+++ b/web/src/routes.js
@@ -22,6 +22,7 @@ import LabelsPage from './pages/Labels'
22import NodesPage from './pages/Nodes' 22import NodesPage from './pages/Nodes'
23import BuildPage from './pages/Build' 23import BuildPage from './pages/Build'
24import BuildsPage from './pages/Builds' 24import BuildsPage from './pages/Builds'
25import BuildsetsPage from './pages/Buildsets'
25import ConfigErrorsPage from './pages/ConfigErrors' 26import ConfigErrorsPage from './pages/ConfigErrors'
26import TenantsPage from './pages/Tenants' 27import TenantsPage from './pages/Tenants'
27import StreamPage from './pages/Stream' 28import StreamPage from './pages/Stream'
@@ -62,6 +63,11 @@ const routes = () => [
62 component: BuildsPage 63 component: BuildsPage
63 }, 64 },
64 { 65 {
66 title: 'Buildsets',
67 to: '/buildsets',
68 component: BuildsetsPage
69 },
70 {
65 to: '/status/change/:changeId', 71 to: '/status/change/:changeId',
66 component: ChangeStatusPage 72 component: ChangeStatusPage
67 }, 73 },