mirror of
https://gitlab.silvrtree.co.uk/martind2000/nci.git
synced 2025-01-25 17:46:18 +00:00
progress bar and project status
This commit is contained in:
parent
a8e9516546
commit
f6a1a7bfe1
@ -3,6 +3,7 @@
|
||||
var Steppy = require('twostep').Steppy,
|
||||
_ = require('underscore'),
|
||||
Node = require('./node').Node,
|
||||
getAvgProjectBuildDuration = require('./project').getAvgProjectBuildDuration,
|
||||
EventEmitter = require('events').EventEmitter,
|
||||
inherits = require('util').inherits,
|
||||
notifier = require('./notifier'),
|
||||
@ -226,8 +227,10 @@ Distributor.prototype.run = function(params, callback) {
|
||||
} else {
|
||||
this.pass(null);
|
||||
}
|
||||
|
||||
getAvgProjectBuildDuration(params.projectName, this.slot());
|
||||
},
|
||||
function(err, hasScmChanges) {
|
||||
function(err, hasScmChanges, avgProjectBuildDuration) {
|
||||
if (params.withScmChangesOnly && !hasScmChanges) {
|
||||
logger.log(
|
||||
'Building of "%s" skipped coz no scm changes',
|
||||
@ -236,6 +239,8 @@ Distributor.prototype.run = function(params, callback) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
project.avgBuildDuration = avgProjectBuildDuration;
|
||||
|
||||
self._updateBuild({}, {
|
||||
project: project,
|
||||
initiator: params.initiator,
|
||||
|
@ -5,6 +5,7 @@ var Steppy = require('twostep').Steppy,
|
||||
path = require('path'),
|
||||
_ = require('underscore'),
|
||||
reader = require('./reader'),
|
||||
db = require('../db'),
|
||||
utils = require('./utils');
|
||||
|
||||
|
||||
@ -99,3 +100,27 @@ exports.create = function(baseDir, config, callback) {
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
||||
exports.getAvgProjectBuildDuration = function(projectName, callback) {
|
||||
Steppy(
|
||||
function() {
|
||||
// get last done builds to calc avg build time
|
||||
db.builds.find({
|
||||
start: {
|
||||
projectName: projectName,
|
||||
status: 'done',
|
||||
descCreateDate: ''
|
||||
},
|
||||
limit: 10
|
||||
}, this.slot());
|
||||
},
|
||||
function(err, doneBuilds) {
|
||||
var durationsSum = _(doneBuilds).reduce(function(memo, build) {
|
||||
return memo + (build.endDate - build.startDate);
|
||||
}, 0);
|
||||
|
||||
this.pass(Math.round(durationsSum / doneBuilds.length));
|
||||
},
|
||||
callback
|
||||
);
|
||||
};
|
||||
|
@ -30,7 +30,9 @@ module.exports = function(app) {
|
||||
_(builds).each(function(build) {
|
||||
delete build.stepTimings;
|
||||
delete build.scm.changes;
|
||||
build.project = _(build.project).pick('name', 'scm');
|
||||
build.project = _(build.project).pick(
|
||||
'name', 'scm', 'avgBuildDuration'
|
||||
);
|
||||
});
|
||||
|
||||
res.send(builds);
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
var Steppy = require('twostep').Steppy,
|
||||
_ = require('underscore'),
|
||||
getAvgProjectBuildDuration =
|
||||
require('../lib/project').getAvgProjectBuildDuration,
|
||||
createBuildDataResource = require('../distributor').createBuildDataResource,
|
||||
logger = require('../lib/logger')('projects resource'),
|
||||
db = require('../db');
|
||||
@ -26,14 +28,16 @@ module.exports = function(app) {
|
||||
function() {
|
||||
project = _(app.projects).findWhere(req.data);
|
||||
|
||||
// get last done builds to calc avg build time
|
||||
getAvgProjectBuildDuration(project.name, this.slot());
|
||||
|
||||
// get last done build
|
||||
db.builds.find({
|
||||
start: {
|
||||
projectName: project.name,
|
||||
status: 'done',
|
||||
descCreateDate: ''
|
||||
},
|
||||
limit: 10
|
||||
limit: 1
|
||||
}, this.slot());
|
||||
|
||||
// tricky but effective streak counting inside filter goes below
|
||||
@ -60,17 +64,9 @@ module.exports = function(app) {
|
||||
doneBuildsStreakCallback(err, doneBuildsStreak);
|
||||
});
|
||||
},
|
||||
function(err, doneBuilds, doneBuildsStreak) {
|
||||
project.lastDoneBuild = doneBuilds[0];
|
||||
|
||||
var durationsSum = _(doneBuilds).reduce(function(memo, build) {
|
||||
return memo + (build.endDate - build.startDate);
|
||||
}, 0);
|
||||
|
||||
project.avgBuildDuration = Math.round(
|
||||
durationsSum / doneBuilds.length
|
||||
);
|
||||
|
||||
function(err, avgProjectBuildDuration, lastDoneBuilds, doneBuildsStreak) {
|
||||
project.lastDoneBuild = lastDoneBuilds[0];
|
||||
project.avgBuildDuration = avgProjectBuildDuration;
|
||||
project.doneBuildsStreak = doneBuildsStreak;
|
||||
|
||||
res.send(project);
|
||||
|
@ -14,15 +14,12 @@
|
||||
.row();
|
||||
padding: 15px 0;
|
||||
margin-bottom: 3px;
|
||||
background: lighten(@well-bg, 3%);
|
||||
|
||||
&__in-progress {
|
||||
background: lighten(@brand-info, 40%);
|
||||
}
|
||||
&__done {
|
||||
background: lighten(@brand-success, 50%);
|
||||
}
|
||||
&__error {
|
||||
background: lighten(@brand-danger, 30%);
|
||||
&_status {
|
||||
float: left;
|
||||
padding-top: 14px;
|
||||
margin-right: 13px;
|
||||
}
|
||||
|
||||
&_info {
|
||||
@ -34,8 +31,21 @@
|
||||
.make-md-column(3);
|
||||
.make-xs-column(3);
|
||||
.text-right;
|
||||
margin-top: 8px;
|
||||
|
||||
&_buttons {
|
||||
margin-top: 8px;
|
||||
transition: opacity 0.2s ease;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&_progress {
|
||||
padding-top: 14px;
|
||||
.progress {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&_content {
|
||||
.make-md-column(9);
|
||||
.make-xs-column(9);
|
||||
@ -48,4 +58,72 @@
|
||||
font-size: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.build_controls_buttons {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@animation-duration: 1.5s;
|
||||
|
||||
.status {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
border-radius: 50%;
|
||||
|
||||
&__in-progress {
|
||||
background: @brand-info;
|
||||
|
||||
-webkit-animation: pulsate @animation-duration ease-out;
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
-moz-animation: pulsate @animation-duration ease-out;
|
||||
-moz-animation-iteration-count: infinite;
|
||||
-o-animation: pulsate @animation-duration ease-out;
|
||||
-o-animation-iteration-count: infinite;
|
||||
animation: pulsate @animation-duration ease-out;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
&__done {
|
||||
background: @link-color;
|
||||
}
|
||||
&__error {
|
||||
background: @brand-danger;
|
||||
}
|
||||
&__queued {
|
||||
background: @brand-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.pulsate-frames() {
|
||||
.transform(@scaleX, @scaleY) {
|
||||
-webkit-transform: scale(@scaleX, @scaleY); opacity: 1;
|
||||
-moz-transform: scale(@scaleX, @scaleY); opacity: 1;
|
||||
-ms-transform: scale(@scaleX, @scaleY); opacity: 1;
|
||||
-o-transform: scale(@scaleX, @scaleY); opacity: 1;
|
||||
transform: scale(@scaleX, @scaleY); opacity: 1;
|
||||
}
|
||||
|
||||
0% {
|
||||
.transform(1.0, 1.0);
|
||||
}
|
||||
25% {
|
||||
opacity: 1.0;
|
||||
}
|
||||
50% {
|
||||
.transform(0.75, 0.75);
|
||||
}
|
||||
50% {
|
||||
opacity: 1.0;
|
||||
}
|
||||
100% {
|
||||
.transform(1.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes pulsate {.pulsate-frames}
|
||||
@-moz-keyframes pulsate {.pulsate-frames}
|
||||
@-ms-keyframes pulsate {.pulsate-frames}
|
||||
@-o-keyframes pulsate {.pulsate-frames}
|
||||
@keyframes pulsate {.pulsate-frames}
|
||||
|
@ -13,16 +13,27 @@ mixin statusText(build)
|
||||
|
||||
- var build = this.props.build;
|
||||
|
||||
.build(class="build__#{build.status}")
|
||||
.build(class="")
|
||||
.build_content
|
||||
.build_status
|
||||
.status(class="status__#{build.status}")
|
||||
div.build_header
|
||||
if build.project
|
||||
span
|
||||
Scm(scm=build.project.scm.type)
|
||||
|
|
||||
Link(to="project", params={name: build.project.name})
|
||||
span= build.project.name
|
||||
|
|
||||
if build.number
|
||||
span(style={fontSize: '15px', color: '#a6a6a6'}) build
|
||||
|
|
||||
if build.status !== 'queued'
|
||||
Link(to="build", params={id: build.id})
|
||||
span Build #
|
||||
span #
|
||||
span= build.number
|
||||
else
|
||||
span Build #
|
||||
span #
|
||||
span= build.number
|
||||
|
||||
if build.waitReason
|
||||
@ -36,12 +47,6 @@ mixin statusText(build)
|
||||
span )
|
||||
|
||||
div
|
||||
if build.project
|
||||
span.build_info
|
||||
Scm(scm=build.project.scm.type)
|
||||
|
|
||||
Link(to="project", params={name: build.project.name})
|
||||
span= build.project.name
|
||||
if build.endDate
|
||||
span.build_info
|
||||
i.fa.fa-fw.fa-clock-o
|
||||
@ -69,11 +74,13 @@ mixin statusText(build)
|
||||
|
||||
.build_controls
|
||||
if build.completed
|
||||
a.btn.btn-sm.btn-default(href="javascript:void(0);", onClick=this.onRebuildProject(build.project.name))
|
||||
i.fa.fa-fw.fa-repeat(title="Rebuild")
|
||||
|
|
||||
| Build again
|
||||
else
|
||||
//-.progress
|
||||
//-.progress-bar.progress-bar-success(style={width: '60%'})
|
||||
.build_controls_buttons
|
||||
a.btn.btn-sm.btn-default(href="javascript:void(0);", onClick=this.onRebuildProject(build.project.name))
|
||||
i.fa.fa-fw.fa-repeat(title="Rebuild")
|
||||
|
|
||||
| Build again
|
||||
if build.status === 'in-progress'
|
||||
.build_controls_progress
|
||||
if build.project.avgBuildDuration
|
||||
Progress(build=build)
|
||||
|
||||
|
@ -12,6 +12,7 @@ define([
|
||||
template = template.locals({
|
||||
DateTime: CommonComponents.DateTime,
|
||||
Duration: CommonComponents.Duration,
|
||||
Progress: CommonComponents.Progress,
|
||||
Scm: CommonComponents.Scm,
|
||||
Terminal: TerminalComponent,
|
||||
Link: Router.Link
|
||||
@ -24,7 +25,6 @@ define([
|
||||
};
|
||||
},
|
||||
onRebuildProject: function(projectName) {
|
||||
console.log('onRebuildProject');
|
||||
ProjectActions.run(projectName)
|
||||
},
|
||||
onShowTerminal: function(build) {
|
||||
|
@ -3,11 +3,13 @@
|
||||
define([
|
||||
'./dateTime/index',
|
||||
'./scm/index',
|
||||
'./duration/index'
|
||||
], function(DateTime, Scm, Duration) {
|
||||
'./duration/index',
|
||||
'./progress/index'
|
||||
], function(DateTime, Scm, Duration, Progress) {
|
||||
return {
|
||||
DateTime: DateTime,
|
||||
Scm: Scm,
|
||||
Duration: Duration
|
||||
Duration: Duration,
|
||||
Progress: Progress
|
||||
};
|
||||
});
|
||||
|
2
static/js/app/components/common/progress/index.jade
Normal file
2
static/js/app/components/common/progress/index.jade
Normal file
@ -0,0 +1,2 @@
|
||||
.progress
|
||||
.progress-bar.progress-bar-success(style={width: this.state.percent + '%'})
|
31
static/js/app/components/common/progress/index.js
Normal file
31
static/js/app/components/common/progress/index.js
Normal file
@ -0,0 +1,31 @@
|
||||
'use strict';
|
||||
|
||||
define([
|
||||
'underscore',
|
||||
'react',
|
||||
'templates/app/components/common/progress/index'
|
||||
], function(_, React, template) {
|
||||
return React.createClass({
|
||||
render: template,
|
||||
_computePercent: function() {
|
||||
var build = this.props.build;
|
||||
return Math.round((Date.now() - build.startDate) /
|
||||
build.project.avgBuildDuration * 100);
|
||||
},
|
||||
componentDidMount: function() {
|
||||
var self = this,
|
||||
updateCallback = function() {
|
||||
if (self.props.build.status === 'in-progress') {
|
||||
self.setState({percent: self._computePercent()});
|
||||
_.delay(updateCallback, 100);
|
||||
}
|
||||
}
|
||||
updateCallback();
|
||||
},
|
||||
getInitialState: function() {
|
||||
return {
|
||||
percent: this._computePercent()
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user