Skip to content

Commit f0bf02d

Browse files
janfaraciklewisbirkstimja
authored
Redesign the UI (#727)
Co-authored-by: Lewis Birks <[email protected]> Co-authored-by: Tim Jacomb <[email protected]>
1 parent fed194a commit f0bf02d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+970
-411
lines changed

pom.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
<properties>
3333
<changelist>999999-SNAPSHOT</changelist>
3434
<gitHubRepo>jenkinsci/${project.artifactId}-plugin</gitHubRepo>
35-
<jenkins.baseline>2.479</jenkins.baseline>
35+
<jenkins.baseline>2.504</jenkins.baseline>
3636
<jenkins.version>${jenkins.baseline}.3</jenkins.version>
3737
<no-test-jar>false</no-test-jar>
3838
<spotless.check.skip>false</spotless.check.skip>
@@ -44,7 +44,7 @@
4444
<dependency>
4545
<groupId>io.jenkins.tools.bom</groupId>
4646
<artifactId>bom-${jenkins.baseline}.x</artifactId>
47-
<version>5054.v620b_5d2b_d5e6</version>
47+
<version>5506.va_222b_131ec34</version>
4848
<type>pom</type>
4949
<scope>import</scope>
5050
</dependency>
@@ -85,6 +85,10 @@
8585
<groupId>io.jenkins.plugins</groupId>
8686
<artifactId>plugin-util-api</artifactId>
8787
</dependency>
88+
<dependency>
89+
<groupId>io.jenkins.plugins</groupId>
90+
<artifactId>prism-api</artifactId>
91+
</dependency>
8892
<dependency>
8993
<groupId>org.jenkins-ci.plugins</groupId>
9094
<artifactId>display-url-api</artifactId>

src/main/java/hudson/tasks/junit/CaseResult.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,15 +1003,27 @@ public Status getStatus() {
10031003
if (skipped) {
10041004
return Status.SKIPPED;
10051005
}
1006+
1007+
return isPassed() ? Status.PASSED : Status.FAILED;
1008+
}
1009+
1010+
/**
1011+
* Gets the condition for a test result, e.g., has the test regressed since it last ran
1012+
*/
1013+
public Status getCondition() {
1014+
if (skipped) {
1015+
return null;
1016+
}
1017+
10061018
CaseResult pr = getPreviousResult();
10071019
if (pr == null) {
1008-
return isPassed() ? Status.PASSED : Status.FAILED;
1020+
return null;
10091021
}
10101022

10111023
if (pr.isPassed()) {
1012-
return isPassed() ? Status.PASSED : Status.REGRESSION;
1024+
return isPassed() ? null : Status.REGRESSION;
10131025
} else {
1014-
return isPassed() ? Status.FIXED : Status.FAILED;
1026+
return isPassed() ? Status.FIXED : null;
10151027
}
10161028
}
10171029

@@ -1034,24 +1046,24 @@ public enum Status {
10341046
/**
10351047
* This test runs OK, just like its previous run.
10361048
*/
1037-
PASSED("result-passed", Messages._CaseResult_Status_Passed(), true),
1049+
PASSED("jp-pill jenkins-!-success-color", Messages._CaseResult_Status_Passed(), true),
10381050
/**
10391051
* This test was skipped due to configuration or the
10401052
* failure or skipping of a method that it depends on.
10411053
*/
1042-
SKIPPED("result-skipped", Messages._CaseResult_Status_Skipped(), false),
1054+
SKIPPED("jp-pill jenkins-!-skipped-color", Messages._CaseResult_Status_Skipped(), false),
10431055
/**
10441056
* This test failed, just like its previous run.
10451057
*/
1046-
FAILED("result-failed", Messages._CaseResult_Status_Failed(), false),
1058+
FAILED("jp-pill jenkins-!-error-color", Messages._CaseResult_Status_Failed(), false),
10471059
/**
10481060
* This test has been failing, but now it runs OK.
10491061
*/
1050-
FIXED("result-fixed", Messages._CaseResult_Status_Fixed(), true),
1062+
FIXED("jp-pill jenkins-!-success-color", Messages._CaseResult_Status_Fixed(), true),
10511063
/**
10521064
* This test has been running OK, but now it failed.
10531065
*/
1054-
REGRESSION("result-regression", Messages._CaseResult_Status_Regression(), false);
1066+
REGRESSION("jp-pill jenkins-!-error-color", Messages._CaseResult_Status_Regression(), false);
10551067

10561068
private final String cssClass;
10571069
private final Localizable message;

src/main/java/hudson/tasks/junit/TestResult.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import hudson.tasks.test.TabulatedResult;
3636
import hudson.tasks.test.TestObject;
3737
import io.jenkins.plugins.junit.storage.TestResultImpl;
38+
import io.jenkins.plugins.prism.PrismConfiguration;
3839
import java.io.File;
3940
import java.io.IOException;
4041
import java.io.PrintWriter;
@@ -60,6 +61,8 @@
6061
import jenkins.util.SystemProperties;
6162
import org.apache.tools.ant.DirectoryScanner;
6263
import org.dom4j.DocumentException;
64+
import org.kohsuke.accmod.Restricted;
65+
import org.kohsuke.accmod.restrictions.NoExternalUse;
6366
import org.kohsuke.stapler.StaplerRequest2;
6467
import org.kohsuke.stapler.StaplerResponse2;
6568
import org.kohsuke.stapler.export.Exported;
@@ -1244,4 +1247,9 @@ public CaseResult getCase(String suiteName, String transformedFullDisplayName) {
12441247
.findFirst()
12451248
.orElse(null);
12461249
}
1250+
1251+
@Restricted(NoExternalUse.class)
1252+
public PrismConfiguration getPrismConfiguration() {
1253+
return PrismConfiguration.getInstance();
1254+
}
12471255
}

src/main/java/hudson/tasks/test/AbstractTestResultAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ public String getUrlName() {
177177

178178
@Override
179179
public String getIconFileName() {
180-
return "clipboard.png";
180+
return "symbol-flask-outline plugin-ionicons-api";
181181
}
182182

183183
@Override

src/main/resources/hudson/tasks/junit/CaseResult/index.jelly

Lines changed: 69 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -23,80 +23,89 @@ THE SOFTWARE.
2323
-->
2424

2525
<?jelly escape-by-default='true'?>
26-
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
27-
xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
28-
<l:layout title="${it.run} test - ${it.displayName}">
29-
<st:include page="sidepanel.jelly" />
26+
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:test="/lib/hudson/test">
27+
<l:layout title="${it.displayName} - ${it.run}" type="one-column" xmlns:p="/prism">
3028
<l:main-panel>
29+
<p:prism configuration="${it.prismConfiguration}" />
30+
<link rel="stylesheet" href="${resURL}/plugin/junit/styles.css" defer="true" />
31+
3132
<j:set var="st" value="${it.status}" />
32-
<h1 class="${st.cssClass}">
33-
<st:out value="${st.message}" />
34-
</h1>
35-
<p>
36-
<span style="font-weight:bold">
37-
<st:out value="${it.fullDisplayName}"/>
38-
</span>
39-
<j:if test="${it.suiteResult != null &amp;&amp; it.className != it.suiteResult.name}">
40-
(from <st:out value="${it.suiteResult.name}"/>)
41-
</j:if>
42-
</p>
43-
<j:if test="${!it.passed}">
44-
<div style="text-align:right;">
45-
<j:choose>
46-
<j:when test="${it.skipped}">
47-
${%skippedFor(it.age)}
48-
</j:when>
49-
<j:otherwise>
50-
${%failingFor(it.age)}
51-
</j:otherwise>
52-
</j:choose>
53-
(${%since.before}<t:buildLink job="${it.run.parent}" number="${it.failedSince}"/>${%since.after})
33+
34+
<div class="jenkins-app-bar">
35+
<div class="jenkins-app-bar__content">
36+
<h1>
37+
<span class="jenkins-!-margin-right-3">
38+
${it.displayName}
39+
</span>
40+
41+
<span class="jenkins-!-text-color-secondary" style="font-family: var(--font-family-mono)">
42+
${it.className}
43+
</span>
44+
</h1>
5445
</div>
55-
</j:if>
46+
<div class="jenkins-app-bar__controls">
47+
<a href="history" class="jenkins-button">
48+
<l:icon src="symbol-bar-chart-outline plugin-ionicons-api" />
49+
${%History}
50+
</a>
51+
</div>
52+
</div>
53+
<div class="jp-details">
54+
<div class="${it.status.cssClass}">
55+
<l:icon src="${it.status == 'PASSED' ? 'symbol-checkmark-outline plugin-ionicons-api' : 'symbol-close-outline plugin-ionicons-api'}" />
56+
${it.status.message}
57+
</div>
58+
59+
<test:condition-tag test="${it}" />
5660

57-
<div style="text-align:right;">
58-
<a href="history">
61+
<j:if test="${!it.passed}">
62+
<a href="${rootURL}/${it.run.url}" class="jp-pill jp-pill--tertiary">
63+
<j:choose>
64+
<j:when test="${it.skipped}">
65+
<l:icon src="symbol-play-skip-forward-circle-outline plugin-ionicons-api" />
66+
</j:when>
67+
<j:otherwise>
68+
<l:icon src="symbol-close-circle-outline plugin-ionicons-api" />
69+
</j:otherwise>
70+
</j:choose>
71+
72+
<j:choose>
73+
<j:when test="${it.skipped}">
74+
${%skippedFor(it.age)}
75+
</j:when>
76+
<j:otherwise>
77+
${%failingFor(it.age)}
78+
</j:otherwise>
79+
</j:choose>
80+
${%since.before}
81+
#${it.failedSince}
82+
${%since.after}
83+
</a>
84+
</j:if>
85+
86+
<div class="jp-pill jp-pill--tertiary">
87+
<l:icon src="symbol-timer-outline plugin-ionicons-api" />
5988
${%took(it.durationString)}
60-
</a>
89+
90+
<j:if test="${it.suiteResult != null &amp;&amp; it.className != it.suiteResult.name}">
91+
(from <st:out value="${it.suiteResult.name}"/>)
92+
</j:if>
93+
</div>
94+
95+
<test:edit-description-button permission="${it.run.UPDATE}" />
6196
</div>
6297

63-
<t:editableDescription permission="${it.run.UPDATE}"/>
98+
<t:editableDescription permission="${it.run.UPDATE}" hideButton="true" />
6499

65100
<table style="margin-top: 1em; margin-left:0em;">
66101
<j:forEach var="action" items="${it.testActions}">
67102
<st:include page="summary.jelly" from="${action}" optional="true" it="${action}" />
68103
</j:forEach>
69104
</table>
70105

71-
<j:forEach var="p" items="${it.properties}">
72-
<h3>${p.key}</h3>
73-
<pre><j:out value="${p.value}"/></pre>
74-
</j:forEach>
75-
76-
<j:if test="${!empty(it.skippedMessage)}">
77-
<h3>${%Skip Message}</h3>
78-
<pre><j:out value="${it.annotate(it.skippedMessage)}"/></pre>
79-
</j:if>
80-
81-
<j:if test="${!empty(it.errorDetails)}">
82-
<h3>${%Error Message}</h3>
83-
<pre><j:out value="${it.annotate(it.errorDetails)}"/></pre>
84-
</j:if>
85-
86-
<j:if test="${!empty(it.errorStackTrace)}">
87-
<h3>${%Stacktrace}</h3>
88-
<pre><j:out value="${it.annotate(it.errorStackTrace)}"/></pre>
89-
</j:if>
90-
91-
<j:if test="${!empty(it.stdout)}">
92-
<h3>${%Standard Output}</h3>
93-
<pre><j:out value="${it.annotate(it.stdout)}"/></pre>
94-
</j:if>
95-
96-
<j:if test="${!empty(it.stderr)}">
97-
<h3>${%Standard Error}</h3>
98-
<pre><j:out value="${it.annotate(it.stderr)}"/></pre>
99-
</j:if>
106+
<div class="jp-code-list">
107+
<st:include page="test-output.jelly" />
108+
</div>
100109
</l:main-panel>
101110
</l:layout>
102111
</j:jelly>

src/main/resources/hudson/tasks/junit/CaseResult/index.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@
2222

2323
failingFor=Failing for the past {0} {0,choice,0#builds|1#build|1<builds}
2424
skippedFor=Skipped for the past {0} {0,choice,0#builds|1#build|1<builds}
25-
took=Took {0}.
26-
since.before=Since' '
25+
took=Took {0}
26+
since.before=since' '
2727
since.after=' '

src/main/resources/hudson/tasks/junit/CaseResult/summary.jelly

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,40 +24,13 @@ THE SOFTWARE.
2424

2525
<!-- this is loaded on demand in the failed test results summary -->
2626
<?jelly escape-by-default='true'?>
27-
<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:local="local">
28-
<d:taglib uri="local">
29-
<d:tag name="item">
30-
<j:if test="${value!=null and !empty value}">
31-
<j:set var="id" value="${attrs.id}-${attrs.name}"/>
32-
<j:set var="display" value="${attrs.opened ? '' : 'none'}"/>
33-
<j:set var="idisplay" value="${attrs.opened ? 'none' : ''}"/>
34-
<st:adjunct includes="lib.hudson.test.js.failureSummary" />
35-
<h4>
36-
<a id="${id}-showlink" title="Show ${title}" style="display: ${idisplay}">
37-
<l:icon src="symbol-add-outline plugin-ionicons-api" class="icon-sm"/><st:nbsp/>${title}
38-
</a>
39-
<a id="${id}-hidelink" title="Hide ${title}" style="display: ${display}">
40-
<l:icon src="symbol-remove-outline plugin-ionicons-api" class="icon-sm"/><st:nbsp/>${title}
41-
</a>
42-
</h4>
43-
<pre id="${id}" style="display: ${display}">
44-
<st:out value="${value}"/>
45-
</pre>
46-
</j:if>
47-
</d:tag>
48-
</d:taglib>
27+
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler">
4928
<st:contentType value="text/plain;charset=UTF-8"/>
5029

5130
<j:new var="h" className="hudson.Functions" />
5231
${h.initPageVariables(context)}
5332

54-
<j:set var="id" value="${h.generateId()}"/>
55-
56-
<local:item id="${id}" name="error" title="${%Error Details}" value="${it.errorDetails}" opened="true"/>
57-
<j:forEach var="p" items="${it.properties}">
58-
<local:item id="${id}" name="${p.key}" title="${p.key}" value="${p.value}"/>
59-
</j:forEach>
60-
<local:item id="${id}" name="stacktrace" title="${%Stack Trace}" value="${it.errorStackTrace}"/>
61-
<local:item id="${id}" name="stdout" title="${%Standard Output}" value="${it.stdout}"/>
62-
<local:item id="${id}" name="stderr" title="${%Standard Error}" value="${it.stderr}"/>
33+
<div class="jp-code-list jp-code-list--inline">
34+
<st:include page="test-output.jelly" />
35+
</div>
6336
</j:jelly>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<!--
2+
The MIT License
3+
4+
Copyright (c) 2025 Jan Faracik
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.
23+
-->
24+
25+
<?jelly escape-by-default='true'?>
26+
<j:jelly xmlns:j="jelly:core" xmlns:d="jelly:define" xmlns:local="local" xmlns:l="/lib/layout">
27+
<d:taglib uri="local">
28+
<d:tag name="item">
29+
<j:if test="${value!=null and !empty value}">
30+
<div class="jp-code-card">
31+
<details open="true">
32+
<summary>
33+
${title}
34+
<l:icon src="symbol-chevron-forward-outline plugin-ionicons-api" />
35+
<l:copyButton text="${value}" iconOnly="true" clazz="jenkins-mobile-hide" />
36+
</summary>
37+
38+
<pre class="jdl-component-code__code">
39+
<code class="language-javastacktrace">
40+
${value}
41+
</code>
42+
</pre>
43+
</details>
44+
</div>
45+
</j:if>
46+
</d:tag>
47+
</d:taglib>
48+
49+
<local:item id="${id}" name="error" title="${%Error Details}" value="${it.errorDetails}" />
50+
<j:forEach var="p" items="${it.properties}">
51+
<local:item id="${id}" name="${p.key}" title="${p.key}" value="${p.value}" />
52+
</j:forEach>
53+
<local:item id="${id}" name="stacktrace" title="${%Stack Trace}" value="${it.errorStackTrace}" />
54+
<local:item id="${id}" name="stdout" title="${%Standard Output}" value="${it.stdout}" />
55+
<local:item id="${id}" name="stderr" title="${%Standard Error}" value="${it.stderr}" />
56+
</j:jelly>

src/main/resources/hudson/tasks/junit/CaseResult/summary_da.properties renamed to src/main/resources/hudson/tasks/junit/CaseResult/test-output_da.properties

File renamed without changes.

0 commit comments

Comments
 (0)