diff options
author | Ian Wienand <iwienand@redhat.com> | 2020-09-11 11:07:27 +1000 |
---|---|---|
committer | Felix Edel <felix.edel@bmw.de> | 2020-11-04 09:19:07 +0100 |
commit | 072bf45ff8a534aebdbf8a1987d4bc902dd15b7a (patch) | |
tree | 2b6e08256db853850d433cd7687131c9a9183e20 /web/src/pages/Build.jsx | |
parent | 38f0c32cfb57e9228283a0e2fe86520d4a5558c7 (diff) | |
download | zuul-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.jsx | 69 |
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, |