diff --git a/web/src/api.js b/web/src/api.js
index 7354226fbe..429afbcbec 100644
--- a/web/src/api.js
+++ b/web/src/api.js
@@ -128,6 +128,13 @@ function fetchBuilds (apiPrefix, queryString) {
}
return Axios.get(apiUrl + apiPrefix + path)
}
+function fetchBuildsets (apiPrefix, queryString) {
+ let path = 'buildsets'
+ if (queryString) {
+ path += '?' + queryString.slice(1)
+ }
+ return Axios.get(apiUrl + apiPrefix + path)
+}
function fetchProject (apiPrefix, projectName) {
return Axios.get(apiUrl + apiPrefix + 'project/' + projectName)
}
@@ -155,6 +162,7 @@ export {
fetchStatus,
fetchBuild,
fetchBuilds,
+ fetchBuildsets,
fetchProject,
fetchProjects,
fetchJob,
diff --git a/web/src/pages/Buildsets.jsx b/web/src/pages/Buildsets.jsx
new file mode 100644
index 0000000000..2d5721b224
--- /dev/null
+++ b/web/src/pages/Buildsets.jsx
@@ -0,0 +1,150 @@
+// Copyright 2019 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 React from 'react'
+import PropTypes from 'prop-types'
+import { connect } from 'react-redux'
+import { Table } from 'patternfly-react'
+
+import { fetchBuildsets } from '../api'
+import TableFilters from '../containers/TableFilters'
+
+
+class BuildsetsPage extends TableFilters {
+ static propTypes = {
+ tenant: PropTypes.object
+ }
+
+ constructor () {
+ super()
+
+ this.prepareTableHeaders()
+ this.state = {
+ buildsets: null,
+ currentFilterType: this.filterTypes[0],
+ activeFilters: [],
+ currentValue: ''
+ }
+ }
+
+ updateData = (filters) => {
+ let queryString = ''
+ if (filters) {
+ filters.forEach(item => queryString += '&' + item.key + '=' + item.value)
+ }
+ this.setState({buildsets: null})
+ fetchBuildsets(this.props.tenant.apiPrefix, queryString).then(response => {
+ this.setState({buildsets: response.data})
+ })
+ }
+
+ componentDidMount () {
+ document.title = 'Zuul Buildsets'
+ if (this.props.tenant.name) {
+ this.updateData(this.getFilterFromUrl())
+ }
+ }
+
+ componentDidUpdate (prevProps) {
+ if (this.props.tenant.name !== prevProps.tenant.name) {
+ this.updateData(this.getFilterFromUrl())
+ }
+ }
+
+ prepareTableHeaders() {
+ const headerFormat = value =>
{value}
+ const cellFormat = (value) => {value}
+ const linkChangeFormat = (value, rowdata) => (
+
+
+ {value ?
+ rowdata.rowData.change + ',' + rowdata.rowData.patchset :
+ rowdata.rowData.newrev ?
+ rowdata.rowData.newrev.substr(0, 7) :
+ rowdata.rowData.branch}
+
+
+ )
+ this.columns = []
+ this.filterTypes = []
+ const myColumns = [
+ 'project',
+ 'branch',
+ 'pipeline',
+ 'change',
+ 'result']
+ myColumns.forEach(column => {
+ let prop = column
+ let formatter = cellFormat
+ if (column === 'change') {
+ formatter = linkChangeFormat
+ }
+ const label = column.charAt(0).toUpperCase() + column.slice(1)
+ this.columns.push({
+ header: {label: label, formatters: [headerFormat]},
+ property: prop,
+ cell: {formatters: [formatter]}
+ })
+ if (column !== 'builds') {
+ this.filterTypes.push({
+ id: prop,
+ title: label,
+ placeholder: 'Filter by ' + label,
+ filterType: 'text',
+ })
+ }
+ })
+ // Add buildset filter at the end
+ this.filterTypes.push({
+ id: 'uuid',
+ title: 'Buildset',
+ palceholder: 'Filter by Buildset UUID',
+ fileterType: 'text',
+ })
+ }
+
+ renderTable (buildsets) {
+ return (
+
+
+ {
+ switch (row.result) {
+ case 'SUCCESS':
+ return { className: 'success' }
+ default:
+ return { className: 'warning' }
+ }
+ }} />
+ )
+ }
+
+ render() {
+ const { buildsets } = this.state
+ return (
+
+ {this.renderFilter()}
+ {buildsets ? this.renderTable(buildsets) : Loading...
}
+
+ )
+ }
+}
+
+export default connect(state => ({tenant: state.tenant}))(BuildsetsPage)
diff --git a/web/src/pages/Tenants.jsx b/web/src/pages/Tenants.jsx
index f7be37b00a..b439c7252b 100644
--- a/web/src/pages/Tenants.jsx
+++ b/web/src/pages/Tenants.jsx
@@ -48,7 +48,8 @@ class TenantsPage extends Refreshable {
{value})
const columns = []
const myColumns = [
- 'name', 'status', 'projects', 'jobs', 'builds', 'projects count', 'queue']
+ 'name', 'status', 'projects', 'jobs', 'builds', 'buildsets',
+ 'projects count', 'queue']
myColumns.forEach(column => {
let prop = column
if (column === 'projects count') {
@@ -72,6 +73,8 @@ class TenantsPage extends Refreshable {
Jobs)
tenant.builds = (
Builds)
+ tenant.buildsets = (
+ Buildsets)
})
return (
diff --git a/web/src/routes.js b/web/src/routes.js
index ee93ab44a5..c8e9cc8468 100644
--- a/web/src/routes.js
+++ b/web/src/routes.js
@@ -22,6 +22,7 @@ import LabelsPage from './pages/Labels'
import NodesPage from './pages/Nodes'
import BuildPage from './pages/Build'
import BuildsPage from './pages/Builds'
+import BuildsetsPage from './pages/Buildsets'
import ConfigErrorsPage from './pages/ConfigErrors'
import TenantsPage from './pages/Tenants'
import StreamPage from './pages/Stream'
@@ -61,6 +62,11 @@ const routes = () => [
to: '/builds',
component: BuildsPage
},
+ {
+ title: 'Buildsets',
+ to: '/buildsets',
+ component: BuildsetsPage
+ },
{
to: '/status/change/:changeId',
component: ChangeStatusPage