woodpecker/pkg/template/pages/repo_commit.html
Michael Nutt 6e92e73a98 logline output buffers rather than updating on every ws message
In builds with lots of output, trying to reload the page partway
through the build results in thousands of websocket messages (one
per line) that each update the DOM.  This can cause the browser to
freeze.  Instead, use requestAnimation frame to delay the DOM
updates.
2014-03-01 19:51:14 -05:00

171 lines
No EOL
4.8 KiB
HTML

{{ define "title" }}{{.Repo.Slug}} · {{ .Commit.HashShort }}{{ end }}
{{ define "content" }}
<div class="subhead">
<div class="container">
<ul class="nav nav-tabs pull-right">
<li class="active"><a href="/{{.Repo.Slug}}/commit/{{ .Commit.Hash }}">{{ .Commit.HashShort }}</a></li>
<li><a href="/{{.Repo.Slug}}">Commits</a></li>
<li><a href="/{{.Repo.Slug}}/settings">Settings</a></li>
</ul> <!-- ./nav -->
<h1>
<span>{{.Repo.Name}}</span>
<small>{{.Repo.Owner}}</small>
</h1>
</div><!-- ./container -->
</div><!-- ./subhead -->
<div class="container">
<div class="alert alert-build-{{ .Build.Status }}">
<a href="/{{.Repo.Slug}}/commit/{{.Commit.Hash }}" class="btn btn-{{ .Build.Status }}"></a>
{{ if .Commit.PullRequest }}
<span>opened pull request <span># {{ .Commit.PullRequest }}</span></span>
{{ else }}
<span>commit <span>{{ .Commit.HashShort }}</span> to <span>{{.Commit.Branch}}</span> branch</span>
{{ end }}
</div>
<div class="build-details container affix-top" data-spy="affix" data-offset-top="248">
<div class="build-summary">
<dt>Status</dt>
<dd>{{.Build.Status}}</dd>
<dt>Started</dt>
<dd><span class="timeago" title="{{ .Build.StartedString }}"></span></dd>
<dt>Duration</dt>
<dd>{{ if .Build.IsRunning }}--{{else}}{{ .Build.HumanDuration }}{{end}}</dd>
</div>
<img src="{{.Commit.Image}}?d=identicon">
<div class="commit-summary">
<dt>Commit</dt>
<dd><u>{{ .Commit.HashShort }}</u></dd>
<dt>Committer</dt>
<dd>{{ .Commit.Author }}</dd>
<dt>Message</dt>
<dd>{{ .Commit.Message }}</dd>
</div>
</div>
<pre id="stdout"></pre>
<span id="follow">Follow</span>
</div><!-- ./container -->
{{ end }}
{{ define "script" }}
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-timeago/1.1.0/jquery.timeago.js"></script>
<script>
window.autofollow = false;
$(document).ready(function() {
$(".timeago").timeago();
$("#follow").bind("click", function(ev) {
if (window.autofollow) {
window.autofollow = false;
$("#follow").text("Follow");
} else {
window.autofollow = true;
$("#follow").text("Stop following");
}
});
});
</script>
<script>
var re = /\u001B\[([0-9]+;?)*[Km]/g;
var styles = new Array();
var formatLine = function(s) {
// Check for newline and early exit?
s = s.replace(/</g, "&lt;");
s = s.replace(/>/g, "&gt;");
var final = "";
var current = 0;
while (m = re.exec(s)) {
var part = s.substring(current, m.index+1);
current = re.lastIndex;
var token = s.substr(m.index, re.lastIndex - m.index);
var code = token.substr(2, token.length-2);
var pre = "";
var post = "";
switch (code) {
case 'm':
case '0m':
var len = styles.length;
for (var i=0; i < len; i++) {
styles.pop();
post += "</span>"
}
break;
case '30;42m': pre = '<span style="color:black;background:lime">'; break;
case '36m':
case '36;1m': pre = '<span style="color:cyan;">'; break;
case '31m':
case '31;31m': pre = '<span style="color:red;">'; break;
case '33m':
case '33;33m': pre = '<span style="color:yellow;">'; break;
case '32m':
case '0;32m': pre = '<span style="color:lime;">'; break;
case '90m': pre = '<span style="color:gray;">'; break;
case 'K':
case '0K':
case '1K':
case '2K': break;
}
if (pre !== "") {
styles.push(pre);
}
final += part + pre + post;
}
var part = s.substring(current, s.length);
final += part;
return final;
};
</script>
<script>
{{ if .Build.IsRunning }}
var outputBox = document.getElementById('stdout');
var outputWS = new WebSocket((window.location.protocol=='http:'?'ws':'wss')+'://'+window.location.host+'/feed?token='+{{ .Token }});
outputWS.onopen = function () { console.log('output websocket open'); };
outputWS.onerror = function (e) { console.log('websocket error: ' + e); };
outputWS.onclose = function (e) { window.location.reload(); };
window.requestAnimationFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
function(callback, element) {
return window.setTimeout(function() {
callback(+new Date());
}, 1000 / 60);
};
var lineBuffer = "";
outputWS.onmessage = function (e) {
lineBuffer += formatLine(e.data);
};
function updateScreen() {
if(lineBuffer.length > 0) {
outputBox.innerHTML += lineBuffer;
lineBuffer = '';
if (window.autofollow) {
window.scrollTo(0, document.body.scrollHeight);
}
}
requestAnimationFrame(updateScreen);
}
requestAnimationFrame(updateScreen);
{{ else }}
$.get("/{{ .Repo.Slug }}/commit/{{ .Commit.Hash }}/build/{{ .Build.Slug }}/out.txt", function( data ) {
$( "#stdout" ).html(formatLine(data));
});
{{ end }}
</script>
{{ end }}