summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2018-12-31 05:28:24 +0000
committerGerrit Code Review <review@openstack.org>2018-12-31 05:28:24 +0000
commitafa918bfcd88163dfe28b2a62d61505194c1aa04 (patch)
tree189cfa377f75a4634b944bf57aaa564907076bf6
parent566bc2173f15bdf96bb4f78a417db4284ff77739 (diff)
parentc3ca0527773179411a8820a783edb9bff1074de0 (diff)
Merge "web: add projects page"
-rw-r--r--web/src/App.test.jsx4
-rw-r--r--web/src/api.js4
-rw-r--r--web/src/pages/Projects.jsx109
-rw-r--r--web/src/pages/Tenants.jsx13
-rw-r--r--web/src/routes.js6
5 files changed, 132 insertions, 4 deletions
diff --git a/web/src/App.test.jsx b/web/src/App.test.jsx
index 2b94e60..de68c6a 100644
--- a/web/src/App.test.jsx
+++ b/web/src/App.test.jsx
@@ -59,7 +59,7 @@ it('renders multi tenant', () => {
59 const topMenuLinks = ReactTestUtils.scryRenderedComponentsWithType( 59 const topMenuLinks = ReactTestUtils.scryRenderedComponentsWithType(
60 application, Link) 60 application, Link)
61 expect(topMenuLinks[0].props.to).toEqual('/t/openstack/status') 61 expect(topMenuLinks[0].props.to).toEqual('/t/openstack/status')
62 expect(topMenuLinks[1].props.to).toEqual('/t/openstack/jobs') 62 expect(topMenuLinks[1].props.to).toEqual('/t/openstack/projects')
63 // Location should be /tenants 63 // Location should be /tenants
64 expect(location.pathname).toEqual('/tenants') 64 expect(location.pathname).toEqual('/tenants')
65 // Info should tell multi tenants 65 // Info should tell multi tenants
@@ -91,7 +91,7 @@ it('renders single tenant', () => {
91 const topMenuLinks = ReactTestUtils.scryRenderedComponentsWithType( 91 const topMenuLinks = ReactTestUtils.scryRenderedComponentsWithType(
92 application, Link) 92 application, Link)
93 expect(topMenuLinks[0].props.to).toEqual('/status') 93 expect(topMenuLinks[0].props.to).toEqual('/status')
94 expect(topMenuLinks[1].props.to).toEqual('/jobs') 94 expect(topMenuLinks[1].props.to).toEqual('/projects')
95 // Location should be /status 95 // Location should be /status
96 expect(location.pathname).toEqual('/status') 96 expect(location.pathname).toEqual('/status')
97 // Info should tell white label tenant openstack 97 // Info should tell white label tenant openstack
diff --git a/web/src/api.js b/web/src/api.js
index 75efe68..409aec8 100644
--- a/web/src/api.js
+++ b/web/src/api.js
@@ -128,6 +128,9 @@ function fetchBuilds (apiPrefix, queryString) {
128 } 128 }
129 return Axios.get(apiUrl + apiPrefix + path) 129 return Axios.get(apiUrl + apiPrefix + path)
130} 130}
131function fetchProjects (apiPrefix) {
132 return Axios.get(apiUrl + apiPrefix + 'projects')
133}
131function fetchJob (apiPrefix, jobName) { 134function fetchJob (apiPrefix, jobName) {
132 return Axios.get(apiUrl + apiPrefix + 'job/' + jobName) 135 return Axios.get(apiUrl + apiPrefix + 'job/' + jobName)
133} 136}
@@ -143,6 +146,7 @@ export {
143 fetchStatus, 146 fetchStatus,
144 fetchBuild, 147 fetchBuild,
145 fetchBuilds, 148 fetchBuilds,
149 fetchProjects,
146 fetchJob, 150 fetchJob,
147 fetchJobs, 151 fetchJobs,
148 fetchTenants, 152 fetchTenants,
diff --git a/web/src/pages/Projects.jsx b/web/src/pages/Projects.jsx
new file mode 100644
index 0000000..a8b9dec
--- /dev/null
+++ b/web/src/pages/Projects.jsx
@@ -0,0 +1,109 @@
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 * as React from 'react'
16import PropTypes from 'prop-types'
17import { connect } from 'react-redux'
18import { Link } from 'react-router-dom'
19import { Table } from 'patternfly-react'
20
21import { fetchProjects } from '../api'
22
23
24class ProjectsPage extends React.Component {
25 static propTypes = {
26 tenant: PropTypes.object
27 }
28
29 state = {
30 projects: null
31 }
32
33 updateData () {
34 fetchProjects(this.props.tenant.apiPrefix).then(response => {
35 this.setState({projects: response.data})
36 })
37 }
38
39 componentDidMount () {
40 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 }
50 }
51
52 render () {
53 const { projects } = this.state
54 if (!projects) {
55 return (<p>Loading...</p>)
56 }
57
58 const headerFormat = value => <Table.Heading>{value}</Table.Heading>
59 const cellFormat = (value) => (
60 <Table.Cell>{value}</Table.Cell>)
61 const cellProjectFormat = (value) => (
62 <Table.Cell>
63 {value}
64 </Table.Cell>)
65 const cellBuildFormat = (value) => (
66 <Table.Cell>
67 <Link to={this.props.tenant.linkPrefix + '/builds?project=' + value}>
68 builds
69 </Link>
70 </Table.Cell>)
71 const columns = []
72 const myColumns = ['name', 'connection', 'type', 'last builds']
73 myColumns.forEach(column => {
74 let formatter = cellFormat
75 let prop = column
76 if (column === 'name') {
77 formatter = cellProjectFormat
78 }
79 if (column === 'connection') {
80 prop = 'connection_name'
81 }
82 if (column === 'last builds') {
83 prop = 'name'
84 formatter = cellBuildFormat
85 }
86 columns.push({
87 header: {label: column,
88 formatters: [headerFormat]},
89 property: prop,
90 cell: {formatters: [formatter]}
91 })
92 })
93 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>)
106 }
107}
108
109export default connect(state => ({tenant: state.tenant}))(ProjectsPage)
diff --git a/web/src/pages/Tenants.jsx b/web/src/pages/Tenants.jsx
index f3646cf..f7be37b 100644
--- a/web/src/pages/Tenants.jsx
+++ b/web/src/pages/Tenants.jsx
@@ -47,18 +47,27 @@ class TenantsPage extends Refreshable {
47 const cellFormat = (value) => ( 47 const cellFormat = (value) => (
48 <Table.Cell>{value}</Table.Cell>) 48 <Table.Cell>{value}</Table.Cell>)
49 const columns = [] 49 const columns = []
50 const myColumns = ['name', 'status', 'jobs', 'builds', 'projects', 'queue'] 50 const myColumns = [
51 'name', 'status', 'projects', 'jobs', 'builds', 'projects count', 'queue']
51 myColumns.forEach(column => { 52 myColumns.forEach(column => {
53 let prop = column
54 if (column === 'projects count') {
55 prop = 'projects'
56 } else if (column === 'projects') {
57 prop = 'projects_link'
58 }
52 columns.push({ 59 columns.push({
53 header: {label: column, 60 header: {label: column,
54 formatters: [headerFormat]}, 61 formatters: [headerFormat]},
55 property: column, 62 property: prop,
56 cell: {formatters: [cellFormat]} 63 cell: {formatters: [cellFormat]}
57 }) 64 })
58 }) 65 })
59 tenants.forEach(tenant => { 66 tenants.forEach(tenant => {
60 tenant.status = ( 67 tenant.status = (
61 <Link to={'/t/' + tenant.name + '/status'}>Status</Link>) 68 <Link to={'/t/' + tenant.name + '/status'}>Status</Link>)
69 tenant.projects_link = (
70 <Link to={'/t/' + tenant.name + '/projects'}>Projects</Link>)
62 tenant.jobs = ( 71 tenant.jobs = (
63 <Link to={'/t/' + tenant.name + '/jobs'}>Jobs</Link>) 72 <Link to={'/t/' + tenant.name + '/jobs'}>Jobs</Link>)
64 tenant.builds = ( 73 tenant.builds = (
diff --git a/web/src/routes.js b/web/src/routes.js
index db6d001..77aad78 100644
--- a/web/src/routes.js
+++ b/web/src/routes.js
@@ -14,6 +14,7 @@
14 14
15import StatusPage from './pages/Status' 15import StatusPage from './pages/Status'
16import ChangeStatusPage from './pages/ChangeStatus' 16import ChangeStatusPage from './pages/ChangeStatus'
17import ProjectsPage from './pages/Projects'
17import JobPage from './pages/Job' 18import JobPage from './pages/Job'
18import JobsPage from './pages/Jobs' 19import JobsPage from './pages/Jobs'
19import BuildPage from './pages/Build' 20import BuildPage from './pages/Build'
@@ -33,6 +34,11 @@ const routes = () => [
33 component: StatusPage 34 component: StatusPage
34 }, 35 },
35 { 36 {
37 title: 'Projects',
38 to: '/projects',
39 component: ProjectsPage
40 },
41 {
36 title: 'Jobs', 42 title: 'Jobs',
37 to: '/jobs', 43 to: '/jobs',
38 component: JobsPage 44 component: JobsPage