// Copyright 2018 Red Hat, Inc // // 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 // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. import * as React from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' import { Link } from 'react-router-dom' class ChangePanel extends React.Component { static propTypes = { globalExpanded: PropTypes.bool.isRequired, change: PropTypes.object.isRequired, tenant: PropTypes.object } constructor () { super() this.state = { expanded: false } this.onClick = this.onClick.bind(this) this.clicked = false } onClick () { let expanded = this.state.expanded if (!this.clicked) { expanded = this.props.globalExpanded } this.clicked = true this.setState({ expanded: !expanded }) } time (ms, words) { if (typeof (words) === 'undefined') { words = false } let seconds = (+ms) / 1000 let minutes = Math.floor(seconds / 60) let hours = Math.floor(minutes / 60) seconds = Math.floor(seconds % 60) minutes = Math.floor(minutes % 60) let r = '' if (words) { if (hours) { r += hours r += ' hr ' } r += minutes + ' min' } else { if (hours < 10) { r += '0' } r += hours + ':' if (minutes < 10) { r += '0' } r += minutes + ':' if (seconds < 10) { r += '0' } r += seconds } return r } enqueueTime (ms) { // Special format case for enqueue time to add style let hours = 60 * 60 * 1000 let now = Date.now() let delta = now - ms let status = 'text-success' let text = this.time(delta, true) if (delta > (4 * hours)) { status = 'text-danger' } else if (delta > (2 * hours)) { status = 'text-warning' } return {text} } renderChangeLink (change) { let changeId = change.id || 'NA' let changeTitle = changeId let changeText = '' if (change.url !== null) { let githubId = changeId.match(/^([0-9]+),([0-9a-f]{40})$/) if (githubId) { changeTitle = githubId changeText = '#' + githubId[1] } else if (/^[0-9a-f]{40}$/.test(changeId)) { changeText = changeId.slice(0, 7) } } else if (changeId.length === 40) { changeText = changeId.slice(0, 7) } return ( {changeText !== '' ? ( {changeText}) : changeTitle} ) } renderProgressBar (change) { let jobPercent = Math.floor(100 / change.jobs.length) return (
{change.jobs.map((job, idx) => { let result = job.result ? job.result.toLowerCase() : null if (result === null) { result = job.url ? 'in progress' : 'queued' } if (result !== 'queued') { let className = '' switch (result) { case 'success': className = ' progress-bar-success' break case 'lost': case 'failure': className = ' progress-bar-danger' break case 'unstable': className = ' progress-bar-warning' break case 'in progress': case 'queued': break default: break } return
} else { return '' } })}
) } renderTimer (change) { let remainingTime if (change.remaining_time === null) { remainingTime = 'unknown' } else { remainingTime = this.time(change.remaining_time, true) } return ( {remainingTime}
{this.enqueueTime(change.enqueue_time)}
) } renderJobProgressBar (elapsedTime, remainingTime) { let progressPercent = 100 * (elapsedTime / (elapsedTime + remainingTime)) return (
) } renderJobStatusLabel (result) { let className switch (result) { case 'success': className = 'label-success' break case 'failure': className = 'label-danger' break case 'unstable': className = 'label-warning' break case 'skipped': className = 'label-info' break // 'in progress' 'queued' 'lost' 'aborted' ... default: className = 'label-default' } return ( {result} ) } renderJob (job) { const { tenant } = this.props let name = '' if (job.result !== null) { name = {job.name} } else if (job.url !== null) { let url = job.url if (job.url.match('stream.html')) { const buildUuid = job.url.split('?')[1].split('&')[0].split('=')[1] const to = ( tenant.linkPrefix + '/stream/' + buildUuid + '?logfile=console.log' ) name = {job.name} } else { name = {job.name} } } else { name = {job.name} } let resultBar let result = job.result ? job.result.toLowerCase() : null if (result === null) { if (job.url === null) { result = 'queued' } else if (job.paused !== null && job.paused) { result = 'paused' } else { result = 'in progress' } } if (result === 'in progress') { resultBar = this.renderJobProgressBar( job.elapsed_time, job.remaining_time) } else { resultBar = this.renderJobStatusLabel(result) } return ( {name} {resultBar} {job.voting === false ? ( (non-voting)) : ''}
) } renderJobList (jobs) { return (
    {jobs.map((job, idx) => (
  • {this.renderJob(job)}
  • ))}
) } render () { const { expanded } = this.state const { change, globalExpanded } = this.props let expand = globalExpanded if (this.clicked) { expand = expanded } const header = (
{change.project}
{this.renderChangeLink(change)}
{this.renderProgressBar(change)}
{change.live === true ? (
{this.renderTimer(change)}
) : ''}
{expand ? this.renderJobList(change.jobs) : ''}
) return ( {header} ) } } export default connect(state => ({tenant: state.tenant}))(ChangePanel)