summaryrefslogtreecommitdiff
path: root/web/src/pages/Build.jsx
diff options
context:
space:
mode:
authorIan Wienand <iwienand@redhat.com>2020-09-11 11:07:27 +1000
committerFelix Edel <felix.edel@bmw.de>2020-11-04 09:19:07 +0100
commit072bf45ff8a534aebdbf8a1987d4bc902dd15b7a (patch)
tree2b6e08256db853850d433cd7687131c9a9183e20 /web/src/pages/Build.jsx
parent38f0c32cfb57e9228283a0e2fe86520d4a5558c7 (diff)
downloadzuul-072bf45ff8a534aebdbf8a1987d4bc902dd15b7a.tar.gz
PF4: Rework of log viewer page
I think the log-viewer page could do with some PF4-ness. This incorporates the previous log-viewer page into the builds page. When selecting a logfile from the listing in the logs tab, the log will directly show inside the tab rather than on a new page. Breadcrumbs are used to show the path to the current log file relative to the logs directory. Additionally, this change improves the state handling of log files in redux and allows multiple log files to be stored in the redux state. This enables fast switching between different logfiles without always downloading them again. To remove some boilerplate code, the LogFile component is changed into a functional component rather than a class component. The filters are moved from jammed-together links into a button toggle-group, which is a mutually-exclusive set perfect for this interface. This component requires the latest release of PF4, which is why the packages have been updated. Change-Id: Ibcbc2bd9497f1d8b75acd9e4979a289173d014b2
Diffstat (limited to 'web/src/pages/Build.jsx')
-rw-r--r--web/src/pages/Build.jsx69
1 files changed, 55 insertions, 14 deletions
diff --git a/web/src/pages/Build.jsx b/web/src/pages/Build.jsx
index fcd9c2c95..18bd150aa 100644
--- a/web/src/pages/Build.jsx
+++ b/web/src/pages/Build.jsx
@@ -16,6 +16,7 @@ import * as React from 'react'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import PropTypes from 'prop-types'
+import { parse } from 'query-string'
import {
EmptyState,
EmptyStateVariant,
@@ -37,6 +38,7 @@ import {
} from '@patternfly/react-icons'
import { fetchBuildAllInfo } from '../actions/build'
+import { fetchLogfile } from '../actions/logfile'
import { EmptyPage } from '../containers/Errors'
import { Fetchable, Fetching } from '../containers/Fetching'
import ArtifactList from '../containers/build/Artifact'
@@ -44,14 +46,17 @@ import Build from '../containers/build/Build'
import BuildOutput from '../containers/build/BuildOutput'
import Console from '../containers/build/Console'
import Manifest from '../containers/build/Manifest'
+import LogFile from '../containers/logfile/LogFile'
class BuildPage extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
build: PropTypes.object,
+ logfile: PropTypes.object,
isFetching: PropTypes.bool.isRequired,
isFetchingManifest: PropTypes.bool.isRequired,
isFetchingOutput: PropTypes.bool.isRequired,
+ isFetchingLogfile: PropTypes.bool.isRequired,
tenant: PropTypes.object.isRequired,
fetchBuildAllInfo: PropTypes.func.isRequired,
activeTab: PropTypes.string.isRequired,
@@ -60,12 +65,13 @@ class BuildPage extends React.Component {
}
updateData = () => {
- if (!this.props.build) {
- this.props.fetchBuildAllInfo(
- this.props.tenant,
- this.props.match.params.buildId
- )
- }
+ // The related fetchBuild...() methods won't do anything if the data is
+ // already available in the local state, so just call them.
+ this.props.fetchBuildAllInfo(
+ this.props.tenant,
+ this.props.match.params.buildId,
+ this.props.match.params.file
+ )
}
componentDidMount() {
@@ -103,22 +109,34 @@ class BuildPage extends React.Component {
history.push(`${tenant.linkPrefix}/build/${build.uuid}/console`)
break
default:
- // results
+ // task summary
history.push(`${tenant.linkPrefix}/build/${build.uuid}`)
}
}
+ handleBreadcrumbItemClick = () => {
+ // Simply link back to the logs tab without an active logfile
+ this.handleTabClick('logs', this.props.build)
+ }
+
render() {
const {
build,
+ logfile,
isFetching,
isFetchingManifest,
isFetchingOutput,
+ isFetchingLogfile,
activeTab,
+ history,
location,
tenant,
} = this.props
const hash = location.hash.substring(1).split('/')
+ const severity = parseInt(parse(location.search).severity)
+
+ // Get the logfile from react-routers URL parameters
+ const logfileName = this.props.match.params.file
if (!build && isFetching) {
return <Fetching />
@@ -164,12 +182,27 @@ class BuildPage extends React.Component {
</EmptyState>
)
- const logsTabContent =
- !build.manifest && isFetchingManifest ? (
- <Fetching />
- ) : build.manifest ? (
- <Manifest tenant={this.props.tenant} build={build} />
- ) : (
+ let logsTabContent = null
+ if (!build.manifest && isFetchingManifest) {
+ logsTabContent = <Fetching />
+ } else if (logfileName) {
+ logsTabContent = (
+ <LogFile
+ logfileContent={logfile}
+ logfileName={logfileName}
+ isFetching={isFetchingLogfile}
+ // We let the LogFile component itself handle the severity default
+ // value in case it's not set via the URL.
+ severity={severity ? severity : undefined}
+ handleBreadcrumbItemClick={this.handleBreadcrumbItemClick}
+ location={location}
+ history={history}
+ />
+ )
+ } else if (build.manifest) {
+ logsTabContent = <Manifest tenant={this.props.tenant} build={build} />
+ } else {
+ logsTabContent = (
<EmptyState variant={EmptyStateVariant.small}>
<EmptyStateIcon icon={FileCodeIcon} />
<Title headingLevel="h4" size="lg">
@@ -177,6 +210,7 @@ class BuildPage extends React.Component {
</Title>
</EmptyState>
)
+ }
const consoleTabContent =
!build.output && isFetchingOutput ? (
@@ -277,16 +311,23 @@ function mapStateToProps(state, ownProps) {
buildId && Object.keys(state.build.builds).length > 0
? state.build.builds[buildId]
: null
+ const logfileName = ownProps.match.params.file
+ const logfile =
+ logfileName && Object.keys(state.logfile.files).length > 0
+ ? state.logfile.files[buildId][logfileName]
+ : null
return {
build,
+ logfile,
tenant: state.tenant,
isFetching: state.build.isFetching,
isFetchingManifest: state.build.isFetchingManifest,
isFetchingOutput: state.build.isFetchingOutput,
+ isFetchingLogfile: state.logfile.isFetching,
}
}
-const mapDispatchToProps = { fetchBuildAllInfo }
+const mapDispatchToProps = { fetchBuildAllInfo, fetchLogfile }
export default connect(
mapStateToProps,