summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2022-08-17 03:09:33 +0000
committerGerrit Code Review <review@openstack.org>2022-08-17 03:09:33 +0000
commit48f1dcef736f1b1ac54c05e34b763717fcf83cfe (patch)
tree6945be326a333ca01ac74ec7bb691d2a7c6799fa
parent15c2a42969011275304652df68cebe154a9126e6 (diff)
parent8494ebf397115a86ad222417d0a66baa08e5721a (diff)
downloadzuul-48f1dcef736f1b1ac54c05e34b763717fcf83cfe.tar.gz
Merge "Web: fix tabs on project page"
-rw-r--r--web/src/containers/project/Project.jsx79
-rw-r--r--web/src/containers/project/ProjectVariant.jsx106
-rw-r--r--web/src/index.css6
-rw-r--r--web/src/pages/Project.jsx92
4 files changed, 139 insertions, 144 deletions
diff --git a/web/src/containers/project/Project.jsx b/web/src/containers/project/Project.jsx
index c355b6af7..993d4d927 100644
--- a/web/src/containers/project/Project.jsx
+++ b/web/src/containers/project/Project.jsx
@@ -1,4 +1,5 @@
// Copyright 2018 Red Hat, Inc
+// Copyright 2022 Acme Gating, LLC
//
// 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
@@ -12,68 +13,44 @@
// License for the specific language governing permissions and limitations
// under the License.
-import * as React from 'react'
+import React, { useState } from 'react'
import PropTypes from 'prop-types'
import {
- Nav,
- NavItem,
- TabContainer,
- TabPane,
- TabContent,
-} from 'patternfly-react'
+ Tabs,
+ Tab,
+} from '@patternfly/react-core'
import ProjectVariant from './ProjectVariant'
-class Project extends React.Component {
- static propTypes = {
- project: PropTypes.object.isRequired,
- }
-
- state = {
- variantIdx: 0,
- }
+function Project(props) {
+ const [variantIdx, setVariantIdx] = useState(0)
+ const { project } = props
- renderVariantTitle (variant, selected) {
- let title = variant.default_branch
- if (selected) {
- title = <strong>{title}</strong>
- }
+ function renderVariantTitle (variant) {
+ let title = variant.source_context.project === project.name ?
+ variant.source_context.branch : variant.source_context.project
return title
}
- render () {
- const { project } = this.props
- const { variantIdx } = this.state
+ return (
+ <React.Fragment>
+ <Tabs activeKey={variantIdx}
+ onSelect={(event, tabIndex) => setVariantIdx(tabIndex)}
+ isBox>
+ {project.configs.map((variant, idx) => (
+ <Tab key={idx} eventKey={idx}
+ title={renderVariantTitle(variant)}>
+ <ProjectVariant variant={variant} />
+ </Tab>
+ ))}
+ </Tabs>
+ </React.Fragment>
+ )
+}
- return (
- <React.Fragment>
- <h2>{project.canonical_name}</h2>
- <TabContainer id="zuul-project">
- <div>
- <Nav bsClass="nav nav-tabs nav-tabs-pf">
- {project.configs.map((variant, idx) => (
- <NavItem
- key={idx}
- onClick={() => this.setState({variantIdx: idx})}>
- <div>
- {this.renderVariantTitle(variant, variantIdx === idx)}
- </div>
- </NavItem>
- ))}
- </Nav>
- <TabContent>
- <TabPane>
- {project.configs[variantIdx] && (
- <ProjectVariant variant={project.configs[variantIdx]} />
- )}
- </TabPane>
- </TabContent>
- </div>
- </TabContainer>
- </React.Fragment>
- )
- }
+Project.propTypes = {
+ project: PropTypes.object.isRequired,
}
export default Project
diff --git a/web/src/containers/project/ProjectVariant.jsx b/web/src/containers/project/ProjectVariant.jsx
index 74be10a55..51a093a32 100644
--- a/web/src/containers/project/ProjectVariant.jsx
+++ b/web/src/containers/project/ProjectVariant.jsx
@@ -18,64 +18,68 @@ import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
-class ProjectVariant extends React.Component {
- static propTypes = {
- tenant: PropTypes.object,
- variant: PropTypes.object.isRequired
- }
+function ProjectVariant(props) {
+ const { tenant, variant } = props
+ const rows = []
- render () {
- const { tenant, variant } = this.props
- const rows = []
+ rows.push({label: 'Merge mode', value: variant.merge_mode})
- rows.push({label: 'Merge mode', value: variant.merge_mode})
+ if (variant.templates.length > 0) {
+ const templateList = (
+ <ul className='list-group'>
+ {variant.templates.map((item, idx) => (
+ <li className='list-group-item' key={idx}>{item}</li>))}
+ </ul>
+ )
+ rows.push({label: 'Templates', value: templateList})
+ }
- if (variant.templates.length > 0) {
- const templateList = (
+ variant.pipelines.forEach(pipeline => {
+ // TODO: either adds job link anchor to load the right variant
+ // and/or show the job variant config in a modal?
+ const jobList = (
+ <React.Fragment>
+ {pipeline.queue_name && (
+ <p><strong>Queue: </strong> {pipeline.queue_name} </p>)}
<ul className='list-group'>
- {variant.templates.map((item, idx) => (
- <li className='list-group-item' key={idx}>{item}</li>))}
+ {pipeline.jobs.map((item, idx) => (
+ <li className='list-group-item' key={idx}>
+ <Link to={tenant.linkPrefix + '/job/' + item[0].name}>
+ {item[0].name}
+ </Link>
+ </li>
+ ))}
</ul>
- )
- rows.push({label: 'Templates', value: templateList})
- }
+ </React.Fragment>
+ )
+ rows.push({label: pipeline.name + ' jobs', value: jobList})
+ })
- variant.pipelines.forEach(pipeline => {
- // TODO: either adds job link anchor to load the right variant
- // and/or show the job variant config in a modal?
- const jobList = (
- <React.Fragment>
- {pipeline.queue_name && (
- <p><strong>Queue: </strong> {pipeline.queue_name} </p>)}
- <ul className='list-group'>
- {pipeline.jobs.map((item, idx) => (
- <li className='list-group-item' key={idx}>
- <Link to={tenant.linkPrefix + '/job/' + item[0].name}>
- {item[0].name}
- </Link>
- </li>
- ))}
- </ul>
- </React.Fragment>
- )
- rows.push({label: pipeline.name + ' jobs', value: jobList})
- })
+ return (
+ <div>
+ <table className='table table-striped table-bordered'>
+ <tbody>
+ {rows.map(item => (
+ <tr key={item.label}>
+ <td style={{width: '10%'}}>{item.label}</td>
+ <td>{item.value}</td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ </div>
+ )
+}
- return (
- <div>
- <table className='table table-striped table-bordered'>
- <tbody>
- {rows.map(item => (
- <tr key={item.label}>
- <td style={{width: '10%'}}>{item.label}</td>
- <td>{item.value}</td>
- </tr>
- ))}
- </tbody>
- </table>
- </div>
- )
+ProjectVariant.propTypes = {
+ tenant: PropTypes.object,
+ variant: PropTypes.object.isRequired
+}
+
+function mapStateToProps(state) {
+ return {
+ tenant: state.tenant,
}
}
-export default connect(state => ({tenant: state.tenant}))(ProjectVariant)
+export default connect(mapStateToProps)(ProjectVariant)
diff --git a/web/src/index.css b/web/src/index.css
index e186eeeda..e47cfc63c 100644
--- a/web/src/index.css
+++ b/web/src/index.css
@@ -3,6 +3,12 @@ body {
padding: 0;
}
+/* Make the H2 header inline-block so that the refresh icon/button can
+ share space with it floating on the right. */
+h2 {
+ display: inline-block;
+}
+
.pf-c-title {
padding-bottom: 10px;
}
diff --git a/web/src/pages/Project.jsx b/web/src/pages/Project.jsx
index 1ef757cd2..06e8612c7 100644
--- a/web/src/pages/Project.jsx
+++ b/web/src/pages/Project.jsx
@@ -1,4 +1,5 @@
// Copyright 2018 Red Hat, Inc
+// Copyright 2022 Acme Gating, LLC
//
// 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
@@ -12,67 +13,74 @@
// License for the specific language governing permissions and limitations
// under the License.
-import * as React from 'react'
+import React, { useEffect, useCallback } from 'react'
import { connect } from 'react-redux'
import PropTypes from 'prop-types'
-import { PageSection, PageSectionVariants } from '@patternfly/react-core'
-
+import {
+ PageSection,
+ PageSectionVariants,
+ Text,
+ TextContent,
+} from '@patternfly/react-core'
import Project from '../containers/project/Project'
import JobGraph from '../containers/jobgraph/JobGraph'
import { fetchProjectIfNeeded } from '../actions/project'
import { Fetchable } from '../containers/Fetching'
-class ProjectPage extends React.Component {
- static propTypes = {
- match: PropTypes.object.isRequired,
- tenant: PropTypes.object,
- remoteData: PropTypes.object,
- dispatch: PropTypes.func
- }
-
- updateData = (force) => {
- this.props.dispatch(fetchProjectIfNeeded(
- this.props.tenant, this.props.match.params.projectName, force))
- }
+function ProjectPage(props) {
+ const { tenant, fetchProjectIfNeeded, remoteData } = props
+ const { projectName } = props.match.params
+ const tenantProjects = remoteData.projects[tenant.name]
- componentDidMount () {
- document.title = 'Zuul Project | ' + this.props.match.params.projectName
- if (this.props.tenant.name) {
- this.updateData()
+ const updateData = useCallback((force) => {
+ if (tenant.name) {
+ fetchProjectIfNeeded(tenant, projectName, force)
}
- }
+ }, [tenant, projectName, fetchProjectIfNeeded])
- componentDidUpdate (prevProps) {
- if (this.props.tenant.name !== prevProps.tenant.name) {
- this.updateData()
- }
- }
+ useEffect(() => {
+ document.title = 'Zuul Project | ' + projectName
+ updateData()
+ }, [tenant, projectName, updateData])
- render () {
- const { remoteData } = this.props
- const tenantProjects = remoteData.projects[this.props.tenant.name]
- const projectName = this.props.match.params.projectName
- return (
+ return (
+ <>
<PageSection variant={PageSectionVariants.light}>
- <PageSection style={{paddingRight: '5px'}}>
- <Fetchable
- isFetching={remoteData.isFetching}
- fetchCallback={this.updateData}
- />
- </PageSection>
+ <TextContent>
+ <Text component="h2">Project {projectName}</Text>
+ <Fetchable
+ isFetching={remoteData.isFetching}
+ fetchCallback={updateData}
+ />
+ </TextContent>
{tenantProjects && tenantProjects[projectName] &&
<>
<Project project={tenantProjects[projectName]} />
<JobGraph project={tenantProjects[projectName]} />
</>
}
- </PageSection>
- )
+ </PageSection>
+ </>
+ )
+}
+
+ProjectPage.propTypes = {
+ match: PropTypes.object.isRequired,
+ tenant: PropTypes.object,
+ remoteData: PropTypes.object,
+ fetchProjectIfNeeded: PropTypes.func,
+}
+
+function mapStateToProps(state) {
+ return {
+ tenant: state.tenant,
+ remoteData: state.project,
}
}
-export default connect(state => ({
- tenant: state.tenant,
- remoteData: state.project,
-}))(ProjectPage)
+const mapDispatchToProps = {
+ fetchProjectIfNeeded,
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(ProjectPage)