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

Rewrite the build history widget #9148

Merged
merged 54 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
91222e7
Squashed commit of the following:
janfaracik Apr 9, 2024
603e2f3
Update _job.scss
janfaracik Apr 9, 2024
df1931f
Lint
janfaracik Apr 9, 2024
80f7335
Merge branch 'master' into new-build-history-widget
janfaracik Apr 10, 2024
b3d5d5b
Update filter-build-history.js
janfaracik Apr 10, 2024
464d631
Hide controls if not navigable
janfaracik Apr 10, 2024
37aa41d
Merge branch 'master' into new-build-history-widget
janfaracik Apr 10, 2024
145715d
Update RunTest.java
janfaracik Apr 11, 2024
4a6e12b
Add basic JSDoc
janfaracik Apr 11, 2024
c954bd0
Use dataset rather than attributes
janfaracik Apr 11, 2024
f577cec
Update filter-build-history.js
janfaracik Apr 11, 2024
073f225
Rename JS
janfaracik Apr 11, 2024
eace011
Update RunTest.java
janfaracik Apr 11, 2024
bee7093
Update jenkins-test-harness version (thanks again Tim!)
janfaracik Apr 11, 2024
c450c21
Update _job.scss
janfaracik Apr 11, 2024
c1ca715
Remove unused SCSS
janfaracik Apr 11, 2024
45219ad
Update AbstractScmTagActionTest.java
janfaracik Apr 12, 2024
cefa9c8
Merge branch 'master' into new-build-history-widget
janfaracik Apr 13, 2024
a1b2833
Update builds-card.js
janfaracik Apr 13, 2024
9577313
Update builds-card.js
janfaracik Apr 13, 2024
4fb45c9
Rewrite SCSS/Jelly to handle more complex scenarios
janfaracik Apr 13, 2024
8d75772
Lint
janfaracik Apr 13, 2024
77c66f5
Tidy up
janfaracik Apr 13, 2024
da8e6df
Merge branch 'master' into new-build-history-widget
janfaracik Apr 13, 2024
477716a
Merge branch 'master' into new-build-history-widget
janfaracik Apr 15, 2024
df17fc8
Merge branch 'master' into new-build-history-widget
janfaracik Apr 20, 2024
1c581c4
Merge branch 'master' into new-build-history-widget
janfaracik Apr 23, 2024
0e5e733
Merge branch 'master' into new-build-history-widget
daniel-beck Apr 24, 2024
6f09e65
Merge branch 'master' into new-build-history-widget
janfaracik Apr 24, 2024
d0c4e9e
Update _side-panel-widgets.scss
janfaracik Apr 27, 2024
13c4e13
Merge branch 'master' into new-build-history-widget
janfaracik Apr 27, 2024
e326fe5
Merge branch 'master' into new-build-history-widget
timja Apr 29, 2024
b38742f
Add background to card
janfaracik May 12, 2024
b7f73af
Merge branch 'master' into new-build-history-widget
janfaracik May 12, 2024
b951e79
Merge branch 'master' into new-build-history-widget
timja May 12, 2024
4dfb781
Fix lint
timja May 12, 2024
8285208
Merge branch 'master' into new-build-history-widget
janfaracik May 14, 2024
45a43cd
Merge branch 'master' into new-build-history-widget
janfaracik May 18, 2024
571dabf
Update queue-items.jelly
janfaracik May 18, 2024
a8bec75
Fix cancel button
janfaracik May 20, 2024
0239995
Update queue-items.jelly
janfaracik May 20, 2024
0e61854
Use debounce properly and adjust time to make it smoother
timja May 22, 2024
0343bbd
Merge branch 'master' into new-build-history-widget
timja May 22, 2024
123c379
Use jenkins-hidden
janfaracik May 22, 2024
5f3e982
Replace TODOs with comments, fix card controls showing when there are…
janfaracik May 22, 2024
b44db16
Add hidden text for previous/next buttons
janfaracik May 22, 2024
4f44cc1
Update builds-card.js
janfaracik May 22, 2024
2b442a2
Add data-tooltip-append-to-parent="true" to tooltips
janfaracik May 23, 2024
a441f2f
Merge branch 'master' into new-build-history-widget
janfaracik May 23, 2024
7754420
Wrap badges
janfaracik May 24, 2024
6675df0
Merge branch 'master' into new-build-history-widget
janfaracik May 24, 2024
b188b92
Merge branch 'master' into new-build-history-widget
janfaracik May 31, 2024
8d2dfd6
Fix relative expandable link
janfaracik May 31, 2024
67e8f44
Use chevron-down rather than menu icon
janfaracik Jun 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 13 additions & 4 deletions core/src/main/resources/hudson/widgets/HistoryWidget/entries.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,19 @@ THE SOFTWARE.
Render build histories.
-->
<?jelly escape-by-default='true'?>
<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 target="${it}" property="nextBuildNumberToFetch" value="${it.nextBuildNumber}"/>
<!-- build history -->
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:i="jelly:fmt">
<j:set target="${it}" property="nextBuildNumberToFetch" value="${it.nextBuildNumber}" />
<j:invokeStatic className="java.time.LocalDate" method="now" var="now" />

<j:forEach var="pageEntry" items="${it.runs}">
<i:formatDate value="${pageEntry.entry.timestamp.time}" var="date" type="date" dateStyle="long" />
<i:formatDate value="${pageEntry.entry.timestamp.time}" var="simpleDate" type="date" pattern="YYYY-MM-dd" />

<j:if test="${pastDate != date}">
<span class="app-builds-container__heading">${simpleDate == now ? "%Today" : date}</span>
<j:set var="pastDate" value="${date}" />
</j:if>

<st:include page="/hudson/widgets/HistoryWidget/entry.jelly" />
</j:forEach>
</j:jelly>
</j:jelly>
95 changes: 49 additions & 46 deletions core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -34,54 +34,57 @@ THE SOFTWARE.
<j:if test="${h.isUserTimeZoneOverride()}">
<i:setTimeZone value="${h.getUserTimeZone()}" />
</j:if>
<tr class="build-row ${transitive} single-line" page-entry-id="${pageEntry.entryId}">
<td class="build-row-cell">
<div class="pane build-name">
<div class="build-icon">
<a class="build-status-link" href="${h.getConsoleUrl(build)}" tooltip="${build.iconColor.description} > ${%Console Output}">
<l:icon src="symbol-status-${build.iconColor.iconName}" />
</a>
</div>
<a class="model-link inside build-link display-name" update-parent-class=".build-row" href="${link}">${build.displayName}</a>
</div>
<div class="pane build-details" time="${build.timestamp.time.time}">
<j:set var="linkTitleAttr" value=""/>
<j:if test="${!build.building}">
<j:set var="linkTitleAttr">${%Took} ${build.durationString}</j:set>
</j:if>
<a class="model-link inside build-link" href="${link}" update-parent-class=".build-row" tooltip="${linkTitleAttr}">
<i:formatDate value="${build.timestamp.time}" type="both" dateStyle="medium" timeStyle="short" /> ${h.getUserTimeZonePostfix(build.timestamp.time)}
</a>
<j:if test="${build.building}">
<j:set target="${it.widget}" property="nextBuildNumberToFetch" value="${build.number}"/>
<t:buildProgressBar build="${build}"/>
</j:if>
</div>
<div class="pane build-controls">
<div class="middle-align build-badge">
<j:set var="badges" value="${build.badgeActions}"/>
<j:if test="${!empty(badges)}">
<st:nbsp/>
<j:forEach var="badge" items="${badges}">
<st:include it="${badge}" page="badge.jelly" />
</j:forEach>

<div class="app-builds-container__item" page-entry-id="${pageEntry.entryId}">
<a class="app-builds-container__item__icon"
href="${h.getConsoleUrl(build)}"
tooltip="${build.iconColor.description}">
timja marked this conversation as resolved.
Show resolved Hide resolved
<l:icon src="symbol-status-${build.iconColor.iconName}" />
</a>

<div class="app-builds-container__item__inner">
<a href="${link}" class="app-builds-container__item__inner__link">
${build.displayName}
<span class="app-builds-container__item__time" time="${build.timestamp.time.time}">
<j:set var="linkTitleAttr" value="${null}" />
<j:if test="${!build.building}">
<j:set var="linkTitleAttr">${%Took} ${build.durationString}</j:set>
</j:if>
</div>
<j:if test="${build.building}">
<div class="build-stop">
<!-- Check CANCEL permission for Project, Admin permission otherwise -->
<j:if test="${empty(it.widget.owner.CANCEL) ? h.hasPermission(app.ADMINISTER) : it.widget.owner.hasPermission(it.widget.owner.CANCEL)}">
<l:stopButton href="${link}stop" alt="${%Cancel}" confirm="${%confirm(build.fullDisplayName)}" />
</j:if>
<div tooltip="${linkTitleAttr}">
timja marked this conversation as resolved.
Show resolved Hide resolved
<i:formatDate value="${build.timestamp.time}" type="time" timeStyle="short" />
${h.getUserTimeZonePostfix()}
</div>
</span>
</a>
<div class="app-builds-container__item__inner__controls">
<j:if test="${build.building}">
<j:if test="${build.building}">
<j:set target="${it.widget}" property="nextBuildNumberToFetch" value="${build.number}"/>
<t:buildProgressBar build="${build}"/>
</j:if>

<!-- Check CANCEL permission for Project, Admin permission otherwise -->
<j:if test="${empty(it.widget.owner.CANCEL) ? h.hasPermission(app.ADMINISTER) : it.widget.owner.hasPermission(it.widget.owner.CANCEL)}">
<l:stopButton href="${link}stop" alt="${%Cancel}" confirm="${%confirm(build.fullDisplayName)}" />
</j:if>
</j:if>

<j:set var="badges" value="${build.badgeActions}"/>
<j:if test="${!empty(badges)}">
<j:forEach var="badge" items="${badges}">
<st:include it="${badge}" page="badge.jelly" />
</j:forEach>
</j:if>
</div>
</div>

<button class="jenkins-card__reveal jenkins-jumplist-link" data-href="${link}">
<l:icon src="symbol-menu" />
</button>
<j:if test="${!empty build.truncatedDescription}">
<div class="app-builds-container__item__description">
<j:out value="${app.markupFormatter.translate(build.truncatedDescription)}"/>
</div>
<j:if test="${!empty build.truncatedDescription}">
<div class="pane desc indent-multiline">
<j:out value="${app.markupFormatter.translate(build.truncatedDescription)}"/>
</div>
</j:if>
<div class="left-bar" />
</td>
</tr>
</j:if>
</div>
</j:jelly>
104 changes: 40 additions & 64 deletions core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly
Original file line number Diff line number Diff line change
Expand Up @@ -23,76 +23,52 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<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:parse var="paneTitle">
<j:invokeStatic var="currentThread" className="java.lang.Thread" method="currentThread"/>
<j:invoke var="jobClass" on="${currentThread.contextClassLoader}" method="loadClass">
<j:arg value="hudson.model.Job"/>
</j:invoke>
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:dd="/lib/layout/dropdowns">
<script src="${resURL}/jsbundles/pages/project/builds-card.js" type="text/javascript" defer="true" />

<div class="jenkins-pane__header--build-history">
<j:if test="${jobClass.isAssignableFrom(it.owner.class)}">
<t:buildHealth job="${it.owner}" iconSizeClass="icon-sm" link="${it.baseUrl}/lastBuild"/>
</j:if>
${it.displayName}
<j:if test="${jobClass.isAssignableFrom(it.owner.class)}">
<a href="${it.baseUrl}/buildTimeTrend">${%trend}</a>
</j:if>
</div>
</j:parse>
<j:set var="page" value="${it.historyPageFilter}" />

<j:parse var="paneFooter">
<!--
RSS link
-->
<span class="build-rss-links">
<a class="build-rss-all-link" href="${it.baseUrl}/rssAll">
<span class="build-rss-all-icon">
<l:icon src="symbol-rss" />
</span>
Atom feed ${%for all}
</a>
<a class="build-rss-failed-link" href="${it.baseUrl}/rssFailed">
<span class="build-rss-failed-icon">
<l:icon src="symbol-rss" />
</span>
Atom feed ${%for failures}
</a>
</span>
</j:parse>
<j:set var="controls">
<l:overflowButton icon="symbol-menu" clazz="jenkins-card__reveal">
<dd:item icon="symbol-rss"
text="Atom feed ${%for all}"
href="${it.baseUrl}/rssAll" />
<dd:item icon="symbol-rss"
text="Atom feed ${%for failures}"
href="${it.baseUrl}/rssFailed" />
</l:overflowButton>
</j:set>

<j:set var="page" value="${it.historyPageFilter}" />
<div id="buildHistoryPage" page-ajax="${it.baseUrl}/buildHistory/ajax" page-entry-newest="${page.newestOnPage}" page-entry-oldest="${page.oldestOnPage}" page-has-up="${page.hasUpPage}" page-has-down="${page.hasDownPage}">
<div id="buildHistoryPageNav">
<div class="buildHistoryPageNav__item buildHistoryPageNav__item--page-one pageOne" title="Page 1 (Newest/Latest Builds)">
<div class="buildHistoryPageNav__item-page-one-top"></div>
<l:svgIcon href="${resURL}/images/svgs/go-up.svg#arrow" viewBox="0 0 16 16" />
</div>
<div class="buildHistoryPageNav__item pageUp" title="Newer Builds">
<l:svgIcon href="${resURL}/images/svgs/go-up.svg#arrow" viewBox="0 0 16 16" />
</div>
<div class="buildHistoryPageNav__item pageDown" title="Older Builds">
<l:svgIcon href="${resURL}/images/svgs/go-down.svg#arrow" viewBox="0 0 16 16" />
</div>
</div>
<div id="buildHistoryPage" page-ajax="${it.baseUrl}/buildHistory/ajax"
data-page-entry-newest="${page.newestOnPage}"
data-page-entry-oldest="${page.oldestOnPage}"
data-page-has-up="${page.hasUpPage}"
data-page-has-down="${page.hasDownPage}">
<l:card id="jenkins-builds" title="Builds" controls="${controls}" expandable="buildTimeTrend">
<l:search-bar placeholder="${%find}"
clazz="${page.runs.isEmpty() and page.queueItems.isEmpty() ? 'jenkins-hidden' : ''}"/>

<l:pane width="3" title="${h.runScript(paneTitle)}" footer="${h.runScript(paneFooter)}" id="buildHistory" class="jenkins-pane stripped">
<tr class="build-search-row">
<td>
<l:search-bar placeholder="${%find}" clazz="${page.runs.isEmpty() and page.queueItems.isEmpty() ? 'jenkins-hidden' : ''}"/>
<div id="no-builds" class="jenkins-pane__information" style="${page.runs.isEmpty() and page.queueItems.isEmpty() ? '' : 'display: none;'}">
${%No builds}
</div>
</td>
</tr>
<div class="app-builds-container">
<div id="no-builds" class="app-builds-container__placeholder">
${%No builds}
</div>

<st:include page="entries.jelly" it="${page}" />
<div id="jenkins-build-history" class="app-builds-container__items">
</div>

</l:pane>
<div class="app-builds-container__controls" id="controls">
<button class="jenkins-button jenkins-button--tertiary jenkins-card__unveil" id="up">
<l:icon src="symbol-arrow-left" />
</button>
<button class="jenkins-button jenkins-button--tertiary jenkins-card__unveil" id="down">
timja marked this conversation as resolved.
Show resolved Hide resolved
<l:icon src="symbol-arrow-right" />
</button>
timja marked this conversation as resolved.
Show resolved Hide resolved
</div>
</div>

<!--The value for `page-next-build` is modified inside of `entries.jelly` on render, so set the attribute-->
<!--after that component has been rendered to get the correct value to use in `filter-build-history.js`-->
<div id="properties" page-next-build="${it.nextBuildNumberToFetch ?: it.owner.nextBuildNumber}"/>
<!--The value for `page-next-build` is modified inside of `entries.jelly` on render, so set the attribute-->
<!--after that component has been rendered to get the correct value to use in `builds-card.js`-->
<div id="properties" page-next-build="${it.nextBuildNumberToFetch ?: it.owner.nextBuildNumber}"/>
</l:card>
</div>
<script src="${resURL}/jsbundles/filter-build-history.js" type="text/javascript"/>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
find=Filter...
find=Filter
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,16 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-->

<!--
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout">
<l:ajax>
<j:choose>
<j:when test="${it.size() > 0}">
<table class="pane hasPageData" page-entry-newest="${it.newestOnPage}" page-entry-oldest="${it.oldestOnPage}" page-has-up="${it.hasUpPage}" page-has-down="${it.hasDownPage}">
<st:include page="entries.jelly" />
</table>
</j:when>
<j:otherwise>
<table class="pane"></table>
</j:otherwise>
</j:choose>
<j:if test="${it.size() > 0}">
<div data-page-entry-newest="${it.newestOnPage}"
data-page-entry-oldest="${it.oldestOnPage}"
data-page-has-up="${it.hasUpPage}"
data-page-has-down="${it.hasDownPage}">
<st:include page="entries.jelly" />
</div>
</j:if>
</l:ajax>
</j:jelly>
</j:jelly>
Original file line number Diff line number Diff line change
Expand Up @@ -28,50 +28,47 @@ THE SOFTWARE.
-->
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout">
<!-- pending build -->
<j:set var="queuedItems" value="${it.queueItems}" />
<j:if test="${!queuedItems.isEmpty()}">
<j:forEach var="pageEntry" items="${queuedItems}" indexVar="i">
<j:set var="item" value="${pageEntry.entry}"/>
<j:set var="id" value="${h.generateId()}"/>
<tr class="build-row build-pending transitive single-line" id="${item.id}" page-entry-id="${pageEntry.entryId}">
<td class="build-row-cell">
<div class="pane build-name">
<div class="build-icon">
<l:icon src="symbol-status-nobuilt" class="icon-sm"/>
</div>
<!-- Don't use math unless needed, in case nextBuildNumber is not numeric -->
<div class="display-name" title="${%Expected build number}">
#${queuedItems.size()==1 ? it.widget.owner.nextBuildNumber
: it.widget.owner.nextBuildNumber+queuedItems.size()-i-1}
</div>
</div>
<div class="pane build-details indent-multiline">
<j:set var="cause" value="${item.getCauseOfBlockage()}"/>
<j:choose>
<j:when test="${cause!=null}">
(${%pending}—<st:include it="${cause}" page="summary.jelly"/>)
</j:when>
<j:otherwise>
(${%pending})
</j:otherwise>
</j:choose>
<j:if test="${!item.params.isEmpty()}">
<div style="float:right;margin-right:10px;">
<l:icon src="symbol-parameters" class="icon-sm" tooltip="Build Parameters:${item.params}"/>
</div>
</j:if>
</div>
<div class="pane build-controls">
<div class="build-stop">
<j:if test="${item.hasCancelPermission()}">
<l:stopButton href="${rootURL}/queue/cancelItem?id=${item.id}" alt="${%Cancel this build}"/>
</j:if>
</div>
</div>
<div class="left-bar"></div>
</td>
</tr>
</j:forEach>
</j:if>
<!-- pending build -->
<j:set var="queuedItems" value="${it.queueItems}"/>
<j:if test="${!queuedItems.isEmpty()}">
<span class="app-builds-container__heading">${%Pending}</span>
<j:forEach var="pageEntry" items="${queuedItems}">
<j:set var="item" value="${pageEntry.entry}"/>
<j:set var="id" value="${h.generateId()}"/>

<div class="app-builds-container__item app-builds-container__item--not-interactable" page-entry-id="${pageEntry.entryId}">
<div class="app-builds-container__item__icon">
<l:icon src="symbol-status-nobuilt" />
</div>
<div class="app-builds-container__item__inner">
<div class="app-builds-container__item__inner__link">
<!-- Don't use math unless needed, in case nextBuildNumber is not numeric -->
#${queuedItems.size() == 1 ? it.widget.owner.nextBuildNumber : it.widget.owner.nextBuildNumber+queuedItems.size()-i-1}
</div>
<j:if test="${build.building}">
<div class="app-builds-container__item__inner__controls">
<j:if test="${item.hasCancelPermission()}">
<l:stopButton href="${rootURL}/queue/cancelItem?id=${item.id}" alt="${%cancel this build}"/>
</j:if>
</div>
</j:if>
<div class="app-builds-container__item__inner__controls">
<j:if test="${!item.params.isEmpty()}">
<div tooltip="Build Parameters: ${item.params}">
<l:icon class="icon-notepad icon-sm"/>
</div>
</j:if>
</div>
</div>
<div class="app-builds-container__item__description">
<j:set var="cause" value="${item.getCauseOfBlockage()}"/>
<j:choose>
<j:when test="${cause!=null}">
<st:include it="${cause}" page="summary.jelly"/>
</j:when>
</j:choose>
</div>
</div>
</j:forEach>
</j:if>
</j:jelly>