summaryrefslogtreecommitdiff
path: root/web/src/pages/Build.jsx
diff options
context:
space:
mode:
authorFelix Edel <felix.edel@bmw.de>2020-09-08 13:53:44 +0000
committerFelix Edel <felix.edel@bmw.de>2020-09-14 14:47:49 +0200
commit23e2d6a13a3d7bee1e7cefb5294b01a97faf02c9 (patch)
tree303daa9d4de4a712a7f068889e55683b80b339ca /web/src/pages/Build.jsx
parent9a729b6b4b22f5a28502d45b2e17be58dade1ff0 (diff)
downloadzuul-23e2d6a13a3d7bee1e7cefb5294b01a97faf02c9.tar.gz
Revert "Revert PF4 build page"
The original change was reverted to fix a scrolling bug that was introduced by a different change. Using this commit in combination with [1] should restore the old behaviour. Applying [2] on top of them should finally get rid of the scrolling issues. [1]: https://review.opendev.org/#/c/750361/ [2]: https://review.opendev.org/#/c/750322/ This reverts commit b4b5b9fd58dd5d5aeb9d32331e4882d7ef5faf06. Change-Id: Icd498314762a8edca751413b7ee07b9b72317c5b
Diffstat (limited to 'web/src/pages/Build.jsx')
-rw-r--r--web/src/pages/Build.jsx233
1 files changed, 215 insertions, 18 deletions
diff --git a/web/src/pages/Build.jsx b/web/src/pages/Build.jsx
index d4975d972..6384eeb2d 100644
--- a/web/src/pages/Build.jsx
+++ b/web/src/pages/Build.jsx
@@ -14,13 +14,36 @@
import * as React from 'react'
import { connect } from 'react-redux'
+import { withRouter } from 'react-router-dom'
import PropTypes from 'prop-types'
-import { PageSection, PageSectionVariants } from '@patternfly/react-core'
+import {
+ EmptyState,
+ EmptyStateVariant,
+ EmptyStateIcon,
+ PageSection,
+ PageSectionVariants,
+ Tab,
+ Tabs,
+ TabTitleIcon,
+ TabTitleText,
+ Title,
+} from '@patternfly/react-core'
+import {
+ BuildIcon,
+ FileArchiveIcon,
+ FileCodeIcon,
+ TerminalIcon,
+ PollIcon,
+} from '@patternfly/react-icons'
import { fetchBuildIfNeeded } from '../actions/build'
-import { Fetchable } from '../containers/Fetching'
+import { EmptyPage } from '../containers/Errors'
+import { Fetchable, Fetching } from '../containers/Fetching'
+import ArtifactList from '../containers/build/Artifact'
import Build from '../containers/build/Build'
-
+import BuildOutput from '../containers/build/BuildOutput'
+import Console from '../containers/build/Console'
+import Manifest from '../containers/build/Manifest'
class BuildPage extends React.Component {
static propTypes = {
@@ -30,45 +53,219 @@ class BuildPage extends React.Component {
dispatch: PropTypes.func,
activeTab: PropTypes.string.isRequired,
location: PropTypes.object,
+ history: PropTypes.object,
}
updateData = (force) => {
- this.props.dispatch(fetchBuildIfNeeded(
- this.props.tenant, this.props.match.params.buildId, null, force))
+ this.props.dispatch(
+ fetchBuildIfNeeded(
+ this.props.tenant,
+ this.props.match.params.buildId,
+ force
+ )
+ )
}
- componentDidMount () {
+ componentDidMount() {
document.title = 'Zuul Build'
if (this.props.tenant.name) {
this.updateData()
}
}
- componentDidUpdate (prevProps) {
+ componentDidUpdate(prevProps) {
if (this.props.tenant.name !== prevProps.tenant.name) {
this.updateData()
}
}
- render () {
- const { remoteData, activeTab, location } = this.props
+ handleTabClick = (tabIndex, build) => {
+ // Usually tabs should only be used to display content in-page and not link
+ // to other pages:
+ // "Tabs are used to present a set on tabs for organizing content on a
+ // .page. It must always be used together with a tab content component."
+ // https://www.patternfly.org/v4/documentation/react/components/tabs
+ // But as want to be able to reach every tab's content via a dedicated URL
+ // while having the look and feel of tabs, we could hijack this onClick
+ // handler to do the link/routing stuff.
+ const { history, tenant } = this.props
+
+ switch (tabIndex) {
+ case 'artifacts':
+ history.push(`${tenant.linkPrefix}/build/${build.uuid}/artifacts`)
+ break
+ case 'logs':
+ history.push(`${tenant.linkPrefix}/build/${build.uuid}/logs`)
+ break
+ case 'console':
+ history.push(`${tenant.linkPrefix}/build/${build.uuid}/console`)
+ break
+ default:
+ // results
+ history.push(`${tenant.linkPrefix}/build/${build.uuid}`)
+ }
+ }
+
+ render() {
+ const { remoteData, activeTab, location, tenant } = this.props
const build = remoteData.builds[this.props.match.params.buildId]
const hash = location.hash.substring(1).split('/')
+
+ if (!build && remoteData.isFetching) {
+ return <Fetching />
+ }
+
+ if (!build) {
+ return (
+ <EmptyPage
+ title="This build does not exist"
+ icon={BuildIcon}
+ linkTarget={`${tenant.linkPrefix}/builds`}
+ linkText="Show all builds"
+ />
+ )
+ }
+
+ const fetchable = (
+ <Fetchable
+ isFetching={remoteData.isFetching}
+ fetchCallback={this.updateData}
+ />
+ )
+
+ const resultsTabContent =
+ !build.hosts && remoteData.isFetchingOutput ? (
+ <Fetching />
+ ) : build.hosts ? (
+ <BuildOutput output={build.hosts} />
+ ) : (
+ <EmptyState variant={EmptyStateVariant.small}>
+ <EmptyStateIcon icon={PollIcon} />
+ <Title headingLevel="h4" size="lg">
+ This build does not provide any results
+ </Title>
+ </EmptyState>
+ )
+
+ const artifactsTabContent = build.artifacts.length ? (
+ <ArtifactList artifacts={build.artifacts} />
+ ) : (
+ <EmptyState variant={EmptyStateVariant.small}>
+ <EmptyStateIcon icon={FileArchiveIcon} />
+ <Title headingLevel="h4" size="lg">
+ This build does not provide any artifacts
+ </Title>
+ </EmptyState>
+ )
+
+ const logsTabContent =
+ !build.manifest && remoteData.isFetchingManifest ? (
+ <Fetching />
+ ) : build.manifest ? (
+ <Manifest tenant={this.props.tenant} build={build} />
+ ) : (
+ <EmptyState variant={EmptyStateVariant.small}>
+ <EmptyStateIcon icon={FileCodeIcon} />
+ <Title headingLevel="h4" size="lg">
+ This build does not provide any logs
+ </Title>
+ </EmptyState>
+ )
+
+ const consoleTabContent =
+ !build.output && remoteData.isFetchingOutput ? (
+ <Fetching />
+ ) : build.output ? (
+ <Console
+ output={build.output}
+ errorIds={build.errorIds}
+ displayPath={hash.length > 0 ? hash : undefined}
+ />
+ ) : (
+ <EmptyState variant={EmptyStateVariant.small}>
+ <EmptyStateIcon icon={TerminalIcon} />
+ <Title headingLevel="h4" size="lg">
+ This build does not provide any console information
+ </Title>
+ </EmptyState>
+ )
+
return (
- <PageSection variant={PageSectionVariants.light}>
- <PageSection style={{paddingRight: '5px'}}>
- <Fetchable
- isFetching={remoteData.isFetching}
- fetchCallback={this.updateData}
+ <>
+ <PageSection variant={PageSectionVariants.light}>
+ <Build
+ build={build}
+ active={activeTab}
+ hash={hash}
+ fetchable={fetchable}
/>
</PageSection>
- {build && <Build build={build} active={activeTab} hash={hash}/>}
- </PageSection>
+ <PageSection variant={PageSectionVariants.light}>
+ <Tabs
+ isFilled
+ activeKey={activeTab}
+ onSelect={(event, tabIndex) => this.handleTabClick(tabIndex, build)}
+ >
+ <Tab
+ eventKey="results"
+ title={
+ <>
+ <TabTitleIcon>
+ <PollIcon />
+ </TabTitleIcon>
+ <TabTitleText>Results</TabTitleText>
+ </>
+ }
+ >
+ {resultsTabContent}
+ </Tab>
+ <Tab
+ eventKey="artifacts"
+ title={
+ <>
+ <TabTitleIcon>
+ <FileArchiveIcon />
+ </TabTitleIcon>
+ <TabTitleText>Artifacts</TabTitleText>
+ </>
+ }
+ >
+ {artifactsTabContent}
+ </Tab>
+ <Tab
+ eventKey="logs"
+ title={
+ <>
+ <TabTitleIcon>
+ <FileCodeIcon />
+ </TabTitleIcon>
+ <TabTitleText>Logs</TabTitleText>
+ </>
+ }
+ >
+ {logsTabContent}
+ </Tab>
+ <Tab
+ eventKey="console"
+ title={
+ <>
+ <TabTitleIcon>
+ <TerminalIcon />
+ </TabTitleIcon>
+ <TabTitleText>Console</TabTitleText>
+ </>
+ }
+ >
+ {consoleTabContent}
+ </Tab>
+ </Tabs>
+ </PageSection>
+ </>
)
}
}
-export default connect(state => ({
+export default connect((state) => ({
tenant: state.tenant,
remoteData: state.build,
-}))(BuildPage)
+}))(withRouter(BuildPage))