Skip to content

Commit b45fc38

Browse files
committed
Add experimental Parameters details for builds
1 parent 7aa3447 commit b45fc38

File tree

12 files changed

+243
-18
lines changed

12 files changed

+243
-18
lines changed

core/src/main/java/hudson/model/ParametersAction.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import java.util.logging.Level;
4949
import java.util.logging.Logger;
5050
import jenkins.model.RunAction2;
51+
import jenkins.model.experimentalflags.NewBuildPageUserExperimentalFlag;
5152
import jenkins.util.SystemProperties;
5253
import org.kohsuke.accmod.Restricted;
5354
import org.kohsuke.accmod.restrictions.NoExternalUse;
@@ -208,6 +209,12 @@ public String getDisplayName() {
208209

209210
@Override
210211
public String getIconFileName() {
212+
Boolean newBuildPageEnabled = new NewBuildPageUserExperimentalFlag().getFlagValue();
213+
214+
if (newBuildPageEnabled) {
215+
return null;
216+
}
217+
211218
return "symbol-parameters";
212219
}
213220

core/src/main/java/jenkins/model/ParameterizedJobMixIn.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import static jakarta.servlet.http.HttpServletResponse.SC_CREATED;
3030

3131
import edu.umd.cs.findbugs.annotations.CheckForNull;
32+
import edu.umd.cs.findbugs.annotations.NonNull;
33+
import hudson.Extension;
3234
import hudson.Util;
3335
import hudson.cli.declarative.CLIMethod;
3436
import hudson.cli.declarative.CLIResolver;
@@ -60,6 +62,9 @@
6062
import java.util.Collections;
6163
import java.util.List;
6264
import java.util.concurrent.TimeUnit;
65+
import jenkins.model.details.Detail;
66+
import jenkins.model.details.DetailFactory;
67+
import jenkins.model.details.ParameterizedDetail;
6368
import jenkins.model.lazy.LazyBuildMixIn;
6469
import jenkins.security.stapler.StaplerNotDispatchable;
6570
import jenkins.triggers.SCMTriggerItem;
@@ -561,6 +566,25 @@ default boolean isBuildable() {
561566
return !isDisabled() && !((Job) this).isHoldOffBuildUntilSave();
562567
}
563568

569+
@Extension
570+
final class ParameterizedDetailFactory extends DetailFactory<Run> {
571+
572+
@Override
573+
public Class<Run> type() {
574+
return Run.class;
575+
}
576+
577+
@NonNull
578+
@Override public List<? extends Detail> createFor(@NonNull Run target) {
579+
var action = target.getAction(ParametersAction.class);
580+
581+
if (action == null || action.getParameters().isEmpty()) {
582+
return List.of();
583+
}
584+
585+
return List.of(new ParameterizedDetail(target));
586+
}
587+
}
564588
}
565589

566590
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package jenkins.model.details;
2+
3+
import edu.umd.cs.findbugs.annotations.Nullable;
4+
import hudson.model.ParametersAction;
5+
import hudson.model.Run;
6+
7+
/**
8+
* Displays if a run has parameters
9+
*/
10+
public class ParameterizedDetail extends Detail {
11+
12+
public final ParametersAction action;
13+
14+
public ParameterizedDetail(Run<?, ?> run) {
15+
super(run);
16+
this.action = getObject().getAction(ParametersAction.class);
17+
}
18+
19+
public @Nullable String getIconClassName() {
20+
return "symbol-parameters";
21+
}
22+
23+
@Override
24+
public @Nullable String getDisplayName() {
25+
return action.getDisplayName();
26+
}
27+
}

core/src/main/resources/hudson/model/BooleanParameterValue/value.jelly

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ THE SOFTWARE.
2727
xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"
2828
xmlns:i="jelly:fmt" xmlns:p="/lib/hudson/project">
2929
<j:set var="escapeEntryTitleAndDescription" value="false"/>
30-
<f:entry description="${it.formattedDescription}">
31-
<j:set var="readOnlyMode" value="true"/>
32-
<f:checkbox title="${h.escape(it.name)}" name="value" checked="${it.value}"/>
33-
</f:entry>
30+
<j:set var="readOnlyMode" value="true"/>
31+
<div>
32+
<f:checkbox title="${h.escape(it.name)}" name="value" checked="${it.value}" description="${it.formattedDescription}" />
33+
</div>
3434
</j:jelly>

core/src/main/resources/hudson/model/StringParameterValue/value.jelly

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ THE SOFTWARE.
2828
xmlns:i="jelly:fmt" xmlns:p="/lib/hudson/project">
2929
<j:set var="escapeEntryTitleAndDescription" value="false"/>
3030
<f:entry title="${h.escape(it.name)}" description="${it.formattedDescription}">
31-
<j:set var="readOnlyMode" value="true"/>
32-
<f:textbox name="value" value="${it.value}"/>
31+
<div class="jenkins-quote jenkins-quote--full-width jenkins-quote--monospace" id="example">
32+
${it.value}
33+
<l:copyButton text="${it.value}" iconOnly="true" />
34+
</div>
3335
</f:entry>
3436
</j:jelly>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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:st="jelly:stapler" xmlns:l="/lib/layout">
27+
<l:dialog title="${it.displayName}">
28+
<div class="app-parameters-dialog">
29+
<j:invokeStatic var="currentThread" className="java.lang.Thread" method="currentThread" />
30+
<j:invoke var="buildClass" on="${currentThread.contextClassLoader}" method="loadClass">
31+
<j:arg value="hudson.model.Run" />
32+
</j:invoke>
33+
<j:set var="build" value="${request2.findAncestorObject(buildClass)}" />
34+
<j:set var="escapeEntryTitleAndDescription" value="true" /> <!-- SECURITY-353 defense unless overridden -->
35+
<j:set var="readOnlyMode" value="true"/>
36+
<j:forEach var="parameterValue" items="${it.action.parameters}">
37+
<st:include it="${parameterValue}" page="value.jelly" />
38+
</j:forEach>
39+
</div>
40+
</l:dialog>
41+
42+
<button class="jenkins-details__item"
43+
data-type="dialog-opener"
44+
data-dialog-id="${dialogId}">
45+
<div class="jenkins-details__item__icon">
46+
<l:icon src="${it.iconClassName}" />
47+
</div>
48+
<span>
49+
${it.displayName}
50+
</span>
51+
</button>
52+
</j:jelly>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
<?jelly escape-by-default='true'?>
25+
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout">
26+
<st:documentation>
27+
<st:attribute name="title" use="required">
28+
The title for the dialog.
29+
</st:attribute>
30+
31+
A lazy-loaded dialog. Set 'data-type="dialog-opener"' and 'data-dialog-id="${dialogId}"'
32+
on your button to open the dialog.
33+
</st:documentation>
34+
35+
<j:set var="dialogId" value="${h.generateId()}" scope="parent" />
36+
37+
<l:renderOnDemand clazz="${dialogId}-template" tag="template" capture="it,dialogId">
38+
<l:ajax>
39+
<template id="${dialogId}-template" data-title="${attrs.title}">
40+
<d:invokeBody />
41+
</template>
42+
</l:ajax>
43+
</l:renderOnDemand>
44+
</j:jelly>

src/main/js/components/dialogs/index.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,36 @@ function init() {
292292
return dialog.show();
293293
},
294294
};
295+
296+
behaviorShim.specify(
297+
"[data-type='dialog-opener']",
298+
"-dialog-",
299+
1000,
300+
(element) => {
301+
element.addEventListener("click", () => {
302+
const templateId = element.dataset.dialogId + "-template";
303+
304+
function render() {
305+
const template = document.querySelector("#" + templateId);
306+
const title = template.dataset.title;
307+
const content = template.content.firstElementChild.cloneNode(true);
308+
309+
behaviorShim.applySubtree(content, false);
310+
dialog.modal(content, {
311+
maxWidth: "550px",
312+
title: title,
313+
});
314+
}
315+
316+
if (document.querySelector("#" + templateId)) {
317+
render();
318+
return;
319+
}
320+
321+
renderOnDemand(document.querySelector("." + templateId), render);
322+
});
323+
},
324+
);
295325
}
296326

297327
export default { init };

src/main/scss/components/_details.scss

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,41 @@
1+
@use "../abstracts/mixins";
2+
13
$icon-size: 1.125rem;
24

35
.jenkins-details {
46
display: flex;
7+
align-items: center;
58
gap: 0.75rem 1.25rem;
69
flex-wrap: wrap;
710

11+
button.jenkins-details__item,
12+
a.jenkins-details__item {
13+
@include mixins.item($border: false);
14+
15+
&::before,
16+
&::after {
17+
inset: 0 -0.5rem;
18+
pointer-events: all;
19+
}
20+
}
21+
822
&__item {
9-
display: grid;
10-
grid-template-columns: auto 1fr;
23+
display: flex;
24+
align-items: center;
25+
justify-content: center;
1126
gap: 0.5rem;
1227
font-weight: normal;
13-
color: var(--text-color-secondary);
28+
color: var(--text-color-secondary) !important;
29+
padding: 0;
30+
min-height: 2rem;
1431

1532
&__icon {
1633
display: flex;
1734
align-items: center;
1835
justify-content: center;
1936
align-self: start;
2037
width: $icon-size;
21-
height: 1lh;
38+
height: 2rem;
2239

2340
svg {
2441
width: $icon-size;

src/main/scss/components/_dialogs.scss

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
$jenkins-dialog-padding: 1.5rem;
2-
$jenkins-dialog-font-size: 0.9375rem;
1+
$jenkins-dialog-padding: 1.25rem;
32

43
.jenkins-dialog {
54
border-radius: 1rem;
@@ -25,20 +24,20 @@ $jenkins-dialog-font-size: 0.9375rem;
2524
}
2625

2726
&__title {
28-
font-size: 1.125rem;
27+
font-size: 1rem;
2928
font-weight: var(--font-bold-weight);
3029
padding: 0 $jenkins-dialog-padding;
3130
color: var(--text-color);
3231
overflow-wrap: anywhere;
3332
text-box: cap alphabetic;
33+
margin-top: 0.5625rem;
3434
}
3535

3636
&__contents {
3737
overflow-y: auto;
3838
overflow-wrap: break-word;
3939
padding: 0 $jenkins-dialog-padding;
4040
max-height: 75vh;
41-
font-size: $jenkins-dialog-font-size;
4241
color: var(--text-color-secondary);
4342

4443
&--modal {
@@ -72,7 +71,7 @@ $jenkins-dialog-font-size: 0.9375rem;
7271
}
7372

7473
&__subtitle {
75-
font-size: 1rem;
74+
font-size: var(--font-size-sm);
7675
font-weight: var(--font-bold-weight);
7776
color: var(--text-color-secondary);
7877
padding: 0;
@@ -81,10 +80,11 @@ $jenkins-dialog-font-size: 0.9375rem;
8180

8281
&__close-button {
8382
position: absolute;
84-
top: $jenkins-dialog-padding - 0.5rem;
85-
right: $jenkins-dialog-padding - 0.5rem;
86-
aspect-ratio: 1;
83+
top: $jenkins-dialog-padding;
84+
right: $jenkins-dialog-padding;
8785
padding: 0;
86+
width: 2rem;
87+
min-height: 2rem;
8888
border-radius: 100%;
8989
}
9090

0 commit comments

Comments
 (0)