Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better build hist wrapping #1466

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,21 @@ THE SOFTWARE.
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt">
<j:set var="link" value="${it.baseUrl}/${build.number}/" />
<j:set var="transitive" value="${(it.firstTransientBuildKey!=null and (it.adapter.compare(build,it.firstTransientBuildKey) ge 0)) ? 'transitive' : null}" />
<tr class="build-row ${transitive}">
<tr class="build-row ${transitive}" buildTimeMillis="${build.timestamp.time.time}">
<td class="pane build-name">
<a class="build-status-link" href="${link}console"><l:icon alt="${build.iconColor.description} &gt; ${%Console Output}" class="${build.buildStatusIconClassName} icon-sm" tooltip="${build.iconColor.description} &gt; ${%Console Output}"/></a><st:nbsp/>
${build.displayName}
<span class="break-words" breakAfter="3">${build.displayName}</span>
</td>
<td class="pane build-details">
<a class="tip model-link inside" href="${link}">
<i:formatDate value="${build.timestamp.time}" type="both" dateStyle="medium" timeStyle="medium"/>
<i:formatDate value="${build.timestamp.time}" type="time" pattern="HH:mm" />
</a>
<j:if test="${build.building}">
<j:set target="${it}" property="nextBuildNumberToFetch" value="${build.number}"/>
<t:buildProgressBar build="${build}"/>
</j:if>
<j:if test="${!empty build.description}">
<div class="desc">
<div class="desc break-words" breakAfter="15">
<j:out value="${app.markupFormatter.translate(build.truncatedDescription)}"/>
</div>
</j:if>
Expand Down
26 changes: 24 additions & 2 deletions war/src/main/webapp/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,23 @@ pre.console {
width: 480px;
}

.build-date-separator {
font-weight: bold;
}

.build-date-separator .build-date-today {
font-weight: normal;
color: #ababab;
margin-left: 10px;
}

.build-date-separator div {
padding: 5px 0px;
border: 1px dashed #cacaca;
border-left: none;
border-right: none;
}

.build-row {
padding: 3px 4px 3px 4px;
}
Expand Down Expand Up @@ -937,15 +954,20 @@ table.parameters > tbody:hover {
padding: 0;
margin-top: 5px;
white-space: normal;
max-width: 200px;
}

#buildHistory .build-rss-links {
float: right;
}

#buildHistory .build-name {
max-width: 120px;
width: 25%;
}
#buildHistory .build-details {
width: 45%;
}
#buildHistory .build-stop, #buildHistory .build-badge {
width: 15%;
}

/* ========================= editable combobox style ========================= */
Expand Down
195 changes: 164 additions & 31 deletions war/src/main/webapp/scripts/hudson-behavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -1552,53 +1552,186 @@ Form.findMatchingInput = function(base, name) {
return null; // not found
}

function breakWords(container) {
container.getElementsBySelector(".break-words").each(function(element) {
if (Element.hasClassName(element, 'words-broken')) {
// already done.
return;
}

var maxWordSize = element.getAttribute('breakAfter');
var words = element.textContent.split(/\s+/);
var newTextContent = '';

var splitRegex = new RegExp('.{1,' + maxWordSize + '}', 'g');
for (var i = 0; i < words.length; i++) {
var word = words[i];
var wordTokens = word.match(splitRegex);
if (wordTokens) {
for (var ii = 0; ii < wordTokens.length; ii++) {
if (newTextContent.length === 0) {
newTextContent += wordTokens[ii];
} else {
newTextContent += String.fromCharCode(8203) + wordTokens[ii];
}
}
} else {
newTextContent += word;
}
newTextContent += ' ';
}

element.textContent = newTextContent;
Element.addClassName(element, 'words-broken');
});
}

function updateBuildHistory(ajaxUrl,nBuild) {
if(isRunAsTest) return;
$('buildHistory').headers = ["n",nBuild];

var bh = $('buildHistory');
bh.headers = ["n",nBuild];

function getDataTable(buildHistoryDiv) {
return $(buildHistoryDiv).getElementsBySelector('table.pane')[0];
}

function removeDateSeparatorRows() {
var dataTable = getDataTable(bh);
var rows = dataTable.rows;
var i = rows.length - 1;

while (i >= 0) {
if (Element.hasClassName(rows[i], 'build-date-separator')) {
Element.remove(rows[i]);
}
i--;
}
}

var month = new Array("Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec");
function toDateInfo(timeMillis) {
var date = new Date(parseInt(timeMillis));
return {
date: date,
asString: month[date.getMonth()] + ' ' + date.getDate() + ', ' + date.getFullYear()
};
}

function isSameDay(date1, date2) {
if (date1.getDate() !== date2.getDate()) {
return false;
}
if (date1.getMonth() !== date2.getMonth()) {
return false;
}
if (date1.getFullYear() !== date2.getFullYear()) {
return false;
}
return true;
}

function insertDateSeparatorRows() {
var dataTable = getDataTable(bh);
var rows = dataTable.rows;
var i = rows.length - 1;
var currentDateInfo = undefined;
var timeNow = new Date();

function insertDateSeparatorRow(dateInfo, atIndex) {
var separatorRow = document.createElement('tr');
var td = document.createElement('td');
var div = document.createElement('div');

Element.addClassName(separatorRow, 'build-date-separator');
separatorRow.appendChild(td);
td.appendChild(div);
td.setAttribute('colspan', '4')

var dateSpan = document.createElement('span');
div.appendChild(dateSpan);
dateSpan.textContent = dateInfo.asString;

if (isSameDay(timeNow, dateInfo.date)) {
var todaySpan = document.createElement('span');

todaySpan.textContent = '(today)';
Element.addClassName(todaySpan, 'build-date-today');
div.appendChild(todaySpan);
}

rows[atIndex].parentNode.insertBefore(separatorRow, rows[atIndex]);
}

while (i >= 0) {
if (Element.hasClassName(rows[i], "build-row")) {
var buildRow = rows[i];
var buildTimeMillis = buildRow.getAttribute("buildTimeMillis");
var dateInfo = toDateInfo(buildTimeMillis);

if (currentDateInfo === undefined) {
currentDateInfo = dateInfo;
}

if (dateInfo.asString !== currentDateInfo.asString) {
// A different date. Insert the "current" date row into the table.
insertDateSeparatorRow(currentDateInfo, (i + 1));
currentDateInfo = dateInfo;
}
}
i--;
}

if (currentDateInfo !== undefined) {
insertDateSeparatorRow(currentDateInfo, 0);
}
}

insertDateSeparatorRows();
breakWords($(bh));

function updateBuilds() {
if(isPageVisible()){
var bh = $('buildHistory');
if (bh.headers == null) {
// Yahoo.log("Missing headers in buildHistory element");
}

function getDataTable(buildHistoryDiv) {
return $(buildHistoryDiv).getElementsBySelector('table.pane')[0];
}

new Ajax.Request(ajaxUrl, {
requestHeaders: bh.headers,
onSuccess: function(rsp) {
var dataTable = getDataTable(bh);
var rows = dataTable.rows;

//delete rows with transitive data
while (rows.length > 0 && Element.hasClassName(rows[0], "transitive")) {
Element.remove(rows[0]);
}

// insert new rows
var div = document.createElement('div');
div.innerHTML = rsp.responseText;
Behaviour.applySubtree(div);

var pivot = rows[0];
var newRows = getDataTable(div).rows;
while (newRows.length > 0) {
if (pivot !== undefined) {
// The data table has rows. Insert before a "pivot" row (first row).
pivot.parentNode.insertBefore(newRows[0], pivot);
} else {
// The data table has no rows. In this case, we just add all new rows directly to the
// table, one after the other i.e. we don't insert before a "pivot" row (first row).
dataTable.appendChild(newRows[0]);
function updateBuildRows() {
var dataTable = getDataTable(bh);
var rows = dataTable.rows;
//delete rows with transitive data
while (rows.length > 0 && Element.hasClassName(rows[0], "transitive")) {
Element.remove(rows[0]);
}
// insert new rows
var div = document.createElement('div');
div.innerHTML = rsp.responseText;
Behaviour.applySubtree(div);
var pivot = rows[0];
var newRows = getDataTable(div).rows;
while (newRows.length > 0) {
if (pivot !== undefined) {
// The data table has rows. Insert before a "pivot" row (first row).
pivot.parentNode.insertBefore(newRows[0], pivot);
} else {
// The data table has no rows. In this case, we just add all new rows directly to the
// table, one after the other i.e. we don't insert before a "pivot" row (first row).
dataTable.appendChild(newRows[0]);
}
}
// next update
bh.headers = ["n", rsp.getResponseHeader("n")];
window.setTimeout(updateBuilds, 5000);
}

// next update
bh.headers = ["n",rsp.getResponseHeader("n")];
window.setTimeout(updateBuilds, 5000);
removeDateSeparatorRows();
updateBuildRows();
insertDateSeparatorRows();
breakWords($(bh));
}
});
} else {
Expand Down