summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--web/package.json2
-rw-r--r--web/src/containers/build/Buildset.jsx4
-rw-r--r--web/src/containers/build/Console.jsx16
-rw-r--r--web/src/containers/build/Summary.jsx7
-rw-r--r--web/src/containers/status/ChangePanel.jsx77
-rw-r--r--web/src/index.css9
-rw-r--r--web/src/pages/Builds.jsx9
-rw-r--r--web/yarn.lock5
8 files changed, 67 insertions, 62 deletions
diff --git a/web/package.json b/web/package.json
index 4b11ac432..b811c7a24 100644
--- a/web/package.json
+++ b/web/package.json
@@ -12,6 +12,7 @@
"js-yaml": "^3.13.0",
"lodash": "^4.17.10",
"moment": "^2.22.2",
+ "moment-duration-format": "2.3.2",
"patternfly-react": "^2.13.1",
"prop-types": "^15.6.2",
"react": "^16.4.2",
@@ -36,6 +37,7 @@
"yarn": "^1.16.0"
},
"scripts": {
+ "start:opendev": "REACT_APP_ZUUL_API='https://zuul.opendev.org/api/' react-scripts start",
"start:openstack": "REACT_APP_ZUUL_API='https://zuul.openstack.org/api/' react-scripts start",
"start:multi": "REACT_APP_ZUUL_API='https://softwarefactory-project.io/zuul/api/' react-scripts start",
"start": "react-scripts start",
diff --git a/web/src/containers/build/Buildset.jsx b/web/src/containers/build/Buildset.jsx
index 803022a21..89f246c83 100644
--- a/web/src/containers/build/Buildset.jsx
+++ b/web/src/containers/build/Buildset.jsx
@@ -18,6 +18,7 @@ import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import { Panel } from 'react-bootstrap'
import * as moment from 'moment'
+import 'moment-duration-format'
class Buildset extends React.Component {
@@ -61,7 +62,8 @@ class Buildset extends React.Component {
if (column === 'job') {
row.push(build.job_name)
} else if (column === 'duration') {
- row.push(moment.duration(build.duration, 'seconds').humanize())
+ row.push(moment.duration(build.duration, 'seconds')
+ .format('h [hr] m [min] s [sec]'))
} else if (column === 'voting') {
row.push(build.voting ? 'true' : 'false')
} else if (column === 'result') {
diff --git a/web/src/containers/build/Console.jsx b/web/src/containers/build/Console.jsx
index 01b308bfe..d8810170e 100644
--- a/web/src/containers/build/Console.jsx
+++ b/web/src/containers/build/Console.jsx
@@ -12,6 +12,8 @@
// License for the specific language governing permissions and limitations
// under the License.
+import * as moment from 'moment'
+import 'moment-duration-format'
import * as React from 'react'
import PropTypes from 'prop-types'
import ReactJson from 'react-json-view'
@@ -206,6 +208,20 @@ class HostTask extends React.Component {
</ListView.InfoItem>
)
+ let duration = moment.duration(
+ moment(task.task.duration.end).diff(task.task.duration.start)
+ ).format({
+ template: 'h [hr] m [min] s [sec]',
+ largest: 2,
+ minValue: 1,
+ })
+
+ ai.push(
+ <ListView.InfoItem key="task-duration">
+ <span className="task-duration">{duration}</span>
+ </ListView.InfoItem>
+ )
+
const expand = errorIds.has(task.task.id)
let name = task.task.name
diff --git a/web/src/containers/build/Summary.jsx b/web/src/containers/build/Summary.jsx
index 90eea6af7..ef47b9ef9 100644
--- a/web/src/containers/build/Summary.jsx
+++ b/web/src/containers/build/Summary.jsx
@@ -20,6 +20,9 @@ import { Link } from 'react-router-dom'
import ArtifactList from './Artifact'
import BuildOutput from './BuildOutput'
+import * as moment from 'moment'
+import 'moment-duration-format'
+
class Summary extends React.Component {
static propTypes = {
@@ -66,6 +69,10 @@ class Summary extends React.Component {
value = 'false'
}
}
+ if (column === 'duration') {
+ value = moment.duration(value, 'seconds')
+ .format('h [hr] m [min] s [sec]')
+ }
if (value && (column === 'log_url' || column === 'ref_url')) {
value = <a href={value}>{value}</a>
}
diff --git a/web/src/containers/status/ChangePanel.jsx b/web/src/containers/status/ChangePanel.jsx
index def966e99..6600e6e8e 100644
--- a/web/src/containers/status/ChangePanel.jsx
+++ b/web/src/containers/status/ChangePanel.jsx
@@ -16,11 +16,8 @@ import * as React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
-
-const SECOND = 1000
-const MINUTE = SECOND * 60
-const HOUR = MINUTE * 60
-const DAY = HOUR * 24
+import * as moment from 'moment'
+import 'moment-duration-format'
class ChangePanel extends React.Component {
@@ -52,37 +49,13 @@ class ChangePanel extends React.Component {
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
+ time (ms) {
+ return moment.duration(ms).format({
+ template: 'h [hr] m [min]',
+ largest: 2,
+ minValue: 1,
+ usePlural: false,
+ })
}
enqueueTime (ms) {
@@ -91,7 +64,7 @@ class ChangePanel extends React.Component {
let now = Date.now()
let delta = now - ms
let status = 'text-success'
- let text = this.time(delta, true)
+ let text = this.time(delta)
if (delta > (4 * hours)) {
status = 'text-danger'
} else if (delta > (2 * hours)) {
@@ -175,7 +148,7 @@ class ChangePanel extends React.Component {
if (change.remaining_time === null) {
remainingTime = 'unknown'
} else {
- remainingTime = this.time(change.remaining_time, true)
+ remainingTime = this.time(change.remaining_time)
}
return (
<React.Fragment>
@@ -204,29 +177,11 @@ class ChangePanel extends React.Component {
className = 'progress-bar-striped progress-bar-animated'
}
if (remaining !== null) {
- title = 'Estimated time remaining: '
- if (remaining < MINUTE) {
- title = title + 'less than a minute'
- } else {
- let days = 0
- let hours = 0
- let minutes = 0
-
- days = Math.trunc(remaining/DAY)
- remaining = Math.trunc(remaining%DAY)
- hours = Math.trunc(remaining/HOUR)
- remaining = Math.trunc(remaining%HOUR)
- minutes = Math.trunc(remaining/MINUTE)
- if (days > 0) {
- title = title + days + ' days '
- }
- if (hours > 0) {
- title = title + hours + ' hours '
- }
- if (minutes > 0) {
- title = title + minutes + ' minutes '
- }
- }
+ title = 'Estimated time remaining: ' + moment.duration(remaining).format({
+ template: 'd [days] h [hours] m [minutes] s [seconds]',
+ largest: 2,
+ minValue: 30,
+ })
}
return (
diff --git a/web/src/index.css b/web/src/index.css
index b638a4600..476a55905 100644
--- a/web/src/index.css
+++ b/web/src/index.css
@@ -9,6 +9,10 @@ a.refresh {
text-decoration: none;
}
+.time {
+ white-space: nowrap;
+}
+
/* Notification bell color */
.fa-bell {
color: orange;
@@ -180,6 +184,11 @@ pre.version {
padding-top: 1px;
padding-bottom: 1px;
}
+.zuul-console .list-view-pf-additional-info-item {
+ flex-grow: 1;
+ flex-shrink: 1;
+ flex-basis: 0;
+}
.zuul-console .list-view-pf-expand
{
padding: 0;
diff --git a/web/src/pages/Builds.jsx b/web/src/pages/Builds.jsx
index 54c184d41..694608373 100644
--- a/web/src/pages/Builds.jsx
+++ b/web/src/pages/Builds.jsx
@@ -17,6 +17,8 @@ import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import { Table } from 'patternfly-react'
+import * as moment from 'moment'
+import 'moment-duration-format'
import { fetchBuilds } from '../api'
import TableFilters from '../containers/TableFilters'
@@ -77,6 +79,11 @@ class BuildsPage extends TableFilters {
<a href={rowdata.rowData.ref_url}>{value ? rowdata.rowData.change+','+rowdata.rowData.patchset : rowdata.rowData.newrev ? rowdata.rowData.newrev.substr(0, 7) : rowdata.rowData.branch}</a>
</Table.Cell>
)
+ const durationFormat = (value) => (
+ <Table.Cell>
+ {moment.duration(value, 'seconds').format('h [hr] m [min] s [sec]')}
+ </Table.Cell>
+ )
this.columns = []
this.filterTypes = []
const myColumns = [
@@ -101,6 +108,8 @@ class BuildsPage extends TableFilters {
formatter = linkChangeFormat
} else if (column === 'result') {
formatter = linkBuildFormat
+ } else if (column === 'duration') {
+ formatter = durationFormat
}
const label = column.charAt(0).toUpperCase() + column.slice(1)
this.columns.push({
diff --git a/web/yarn.lock b/web/yarn.lock
index 613645648..f572e43fc 100644
--- a/web/yarn.lock
+++ b/web/yarn.lock
@@ -6112,6 +6112,11 @@ mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@
dependencies:
minimist "0.0.8"
+moment-duration-format@2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/moment-duration-format/-/moment-duration-format-2.3.2.tgz#5fa2b19b941b8d277122ff3f87a12895ec0d6212"
+ integrity sha512-cBMXjSW+fjOb4tyaVHuaVE/A5TqkukDWiOfxxAjY+PEqmmBQlLwn+8OzwPiG3brouXKY5Un4pBjAeB6UToXHaQ==
+
moment-timezone@^0.4.0, moment-timezone@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.4.1.tgz#81f598c3ad5e22cdad796b67ecd8d88d0f5baa06"