mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-10-26 19:15:09 +00:00
Add experimental job page UI (#11194)
Co-authored-by: Tim Jacomb <21194782+timja@users.noreply.github.com>
This commit is contained in:
1 parent
2b583fb069
commit
a2146f3c41
22 files changed
+820
-110
No files matched your search
@@ -89,6 +89,7 @@ import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Stream;
|
||||
import jenkins.model.BuildDiscarder;
|
||||
import jenkins.model.BuildDiscarderProperty;
|
||||
import jenkins.model.DirectlyModifiableTopLevelItemGroup;
|
||||
@@ -98,6 +99,12 @@ import jenkins.model.JenkinsLocationConfiguration;
|
||||
import jenkins.model.ModelObjectWithChildren;
|
||||
import jenkins.model.PeepholePermalink;
|
||||
import jenkins.model.ProjectNamingStrategy;
|
||||
import jenkins.model.Tab;
|
||||
import jenkins.model.details.Detail;
|
||||
import jenkins.model.details.DetailFactory;
|
||||
import jenkins.model.details.DownstreamProjectsDetail;
|
||||
import jenkins.model.details.ProjectNameDetail;
|
||||
import jenkins.model.details.UpstreamProjectsDetail;
|
||||
import jenkins.model.lazy.LazyBuildMixIn;
|
||||
import jenkins.scm.RunWithSCM;
|
||||
import jenkins.security.HexStringConfidentialKey;
|
||||
@@ -1689,4 +1696,30 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
|
||||
}
|
||||
|
||||
private static final HexStringConfidentialKey SERVER_COOKIE = new HexStringConfidentialKey(Job.class, "serverCookie", 16);
|
||||
|
||||
@Extension
|
||||
public static final class BasicJobDetailFactory extends DetailFactory<Job> {
|
||||
|
||||
@Override
|
||||
public Class<Job> type() {
|
||||
return Job.class;
|
||||
}
|
||||
|
||||
@NonNull @Override public List<? extends Detail> createFor(@NonNull Job target) {
|
||||
return Stream.of(new UpstreamProjectsDetail(target), new DownstreamProjectsDetail(target), new ProjectNameDetail(target)).filter(e -> e.getIconClassName() != null).toList();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the tabs for a given job
|
||||
*/
|
||||
@Restricted(NoExternalUse.class)
|
||||
public List<Tab> getJobTabs() {
|
||||
return getActions(Tab.class);
|
||||
}
|
||||
|
||||
@Restricted(NoExternalUse.class)
|
||||
public final ParametersDefinitionProperty getParametersDefinitionProperty() {
|
||||
return getProperty(ParametersDefinitionProperty.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2025, Jan Faracik
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package jenkins.job;
|
||||
|
||||
import hudson.model.Actionable;
|
||||
import jenkins.model.Tab;
|
||||
|
||||
public class OverviewTab extends Tab {
|
||||
|
||||
public OverviewTab(Actionable object) {
|
||||
super(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIconFileName() {
|
||||
return "symbol-overview";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "Overview";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrlName() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2025, Jan Faracik
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package jenkins.job;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.NonNull;
|
||||
import hudson.Extension;
|
||||
import hudson.model.Job;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import jenkins.model.Tab;
|
||||
import jenkins.model.TransientActionFactory;
|
||||
import jenkins.model.experimentalflags.NewJobPageUserExperimentalFlag;
|
||||
|
||||
@Extension(ordinal = Integer.MAX_VALUE)
|
||||
public class OverviewTabFactory extends TransientActionFactory<Job> {
|
||||
|
||||
@Override
|
||||
public Class<Job> type() {
|
||||
return Job.class;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Collection<? extends Tab> createFor(@NonNull Job target) {
|
||||
boolean isExperimentalUiEnabled = new NewJobPageUserExperimentalFlag().getFlagValue();
|
||||
|
||||
if (!isExperimentalUiEnabled) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
return Collections.singleton(new OverviewTab(target));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package jenkins.model.details;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.Nullable;
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.model.Actionable;
|
||||
import hudson.model.Item;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Displays downstream projects of a project (if any)
|
||||
*/
|
||||
public class DownstreamProjectsDetail extends Detail {
|
||||
|
||||
public DownstreamProjectsDetail(Actionable object) {
|
||||
super(object);
|
||||
}
|
||||
|
||||
public @Nullable String getIconClassName() {
|
||||
if (getProjects().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return "symbol-arrow-down-circle-outline plugin-ionicons-api";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getDisplayName() {
|
||||
int projectSize = getProjects().size();
|
||||
|
||||
if (projectSize == 1) {
|
||||
return "1 downstream project";
|
||||
}
|
||||
|
||||
return projectSize + " downstream projects";
|
||||
}
|
||||
|
||||
public List<AbstractProject> getProjects() {
|
||||
if (!(getObject() instanceof AbstractProject)) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<AbstractProject> projects = ((AbstractProject) getObject()).getDownstreamProjects();
|
||||
return projects.stream().filter(e -> e.hasPermission(Item.READ)).toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package jenkins.model.details;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.Nullable;
|
||||
import hudson.model.Actionable;
|
||||
import hudson.model.Hudson;
|
||||
import hudson.model.Job;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Displays the full name of a project (if necessary)
|
||||
*/
|
||||
public class ProjectNameDetail extends Detail {
|
||||
|
||||
public ProjectNameDetail(Actionable object) {
|
||||
super(object);
|
||||
}
|
||||
|
||||
public @Nullable String getIconClassName() {
|
||||
if (getDisplayName() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return "symbol-information-circle";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getDisplayName() {
|
||||
var it = (Job<?, ?>) getObject();
|
||||
|
||||
if (Objects.equals(it.getFullName(), it.getFullDisplayName()) || it.getClass().getName().equals("MatrixConfiguration")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean nested = it.getParent().getClass() != Hudson.class;
|
||||
String label = nested ? "Full project name" : "Project name";
|
||||
|
||||
return label + ": " + it.getFullName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package jenkins.model.details;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.Nullable;
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.model.Actionable;
|
||||
import hudson.model.Item;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Displays upstream projects of a project (if any)
|
||||
*/
|
||||
public class UpstreamProjectsDetail extends Detail {
|
||||
|
||||
public UpstreamProjectsDetail(Actionable object) {
|
||||
super(object);
|
||||
}
|
||||
|
||||
public @Nullable String getIconClassName() {
|
||||
if (getProjects().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return "symbol-arrow-up-circle-outline plugin-ionicons-api";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getDisplayName() {
|
||||
int projectSize = getProjects().size();
|
||||
|
||||
if (projectSize == 1) {
|
||||
return "1 upstream project";
|
||||
}
|
||||
|
||||
return projectSize + " upstream projects";
|
||||
}
|
||||
|
||||
public List<AbstractProject> getProjects() {
|
||||
if (!(getObject() instanceof AbstractProject)) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<AbstractProject> projects = ((AbstractProject) getObject()).getUpstreamProjects();
|
||||
return projects.stream().filter(e -> e.hasPermission(Item.READ)).toList();
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2025, Jan Faracik
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package jenkins.model.experimentalflags;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.Nullable;
|
||||
import hudson.Extension;
|
||||
import org.kohsuke.accmod.Restricted;
|
||||
import org.kohsuke.accmod.restrictions.NoExternalUse;
|
||||
|
||||
@Extension
|
||||
@Restricted(NoExternalUse.class)
|
||||
public class NewJobPageUserExperimentalFlag extends BooleanUserExperimentalFlag {
|
||||
public NewJobPageUserExperimentalFlag() {
|
||||
super("new-job-page.flag");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "New job page";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getShortDescription() {
|
||||
return "Enables a revamped job page. This feature is still a work in progress, so some things might not work perfectly yet.";
|
||||
}
|
||||
}
|
||||
@@ -46,5 +46,8 @@ THE SOFTWARE.
|
||||
<st:include page="jobMain.jelly" it="${a}" optional="true" />
|
||||
</j:forEach>
|
||||
|
||||
<p:upstream-downstream />
|
||||
<l:userExperimentalFlag var="newJobPage" flagClassName="jenkins.model.experimentalflags.NewJobPageUserExperimentalFlag" />
|
||||
<j:if test="${!newJobPage}">
|
||||
<p:upstream-downstream />
|
||||
</j:if>
|
||||
</j:jelly>
|
||||
@@ -35,23 +35,44 @@ THE SOFTWARE.
|
||||
<link rel="alternate" title="Jenkins:${it.name} (changelog) (RSS 2.0)" href="rssChangelog?flavor=rss20" type="application/rss+xml" />
|
||||
</l:header>
|
||||
<l:side-panel>
|
||||
<l:tasks>
|
||||
<j:set var="url" value="${h.getNearestAncestorUrl(request2,it)}"/>
|
||||
<l:task contextMenu="false" href="${url}/" icon="symbol-details" title="${%Status}"/>
|
||||
<l:task href="${url}/changes" icon="symbol-changes" title="${%Changes}"/>
|
||||
<l:task icon="symbol-folder" href="${url}/ws/" title="${%Workspace}" permission="${it.WORKSPACE}">
|
||||
<l:task confirmationMessage="${%wipe.out.confirm}" href="${url}/doWipeOutWorkspace" icon="symbol-trash" permission="${h.isWipeOutPermissionEnabled() ? it.WIPEOUT : it.BUILD}" post="true" requiresConfirmation="true" title="${%Wipe Out Workspace}"/>
|
||||
</l:task>
|
||||
<j:if test="${it.configurable}">
|
||||
<p:configurable/>
|
||||
</j:if>
|
||||
<st:include page="actions.jelly" />
|
||||
</l:tasks>
|
||||
<l:userExperimentalFlag var="newJobPage" flagClassName="jenkins.model.experimentalflags.NewJobPageUserExperimentalFlag" />
|
||||
|
||||
<st:include page="sidepanel2.jelly" optional="true" />
|
||||
<j:choose>
|
||||
<j:when test="${newJobPage}">
|
||||
<l:tasks>
|
||||
<j:set var="url" value="${h.getNearestAncestorUrl(request2,it)}"/>
|
||||
<l:task href="${url}/changes" icon="symbol-changes" title="${%Changes}"/>
|
||||
<l:task icon="symbol-folder" href="${url}/ws/" title="${%Workspace}" permission="${it.WORKSPACE}">
|
||||
<l:task confirmationMessage="${%wipe.out.confirm}" href="${url}/doWipeOutWorkspace" icon="symbol-trash" permission="${h.isWipeOutPermissionEnabled() ? it.WIPEOUT : it.BUILD}" post="true" requiresConfirmation="true" title="${%Wipe Out Workspace}"/>
|
||||
</l:task>
|
||||
<st:include page="actions.jelly" />
|
||||
<j:if test="${it.configurable}">
|
||||
<p:configurable/>
|
||||
</j:if>
|
||||
</l:tasks>
|
||||
|
||||
<j:forEach var="w" items="${it.widgets}">
|
||||
<st:include it="${w}" page="index.jelly" />
|
||||
</j:forEach>
|
||||
<st:include page="sidepanel2.jelly" optional="true" />
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
<l:tasks>
|
||||
<j:set var="url" value="${h.getNearestAncestorUrl(request2,it)}"/>
|
||||
<l:task contextMenu="false" href="${url}/" icon="symbol-details" title="${%Status}"/>
|
||||
<l:task href="${url}/changes" icon="symbol-changes" title="${%Changes}"/>
|
||||
<l:task icon="symbol-folder" href="${url}/ws/" title="${%Workspace}" permission="${it.WORKSPACE}">
|
||||
<l:task confirmationMessage="${%wipe.out.confirm}" href="${url}/doWipeOutWorkspace" icon="symbol-trash" permission="${h.isWipeOutPermissionEnabled() ? it.WIPEOUT : it.BUILD}" post="true" requiresConfirmation="true" title="${%Wipe Out Workspace}"/>
|
||||
</l:task>
|
||||
<j:if test="${it.configurable}">
|
||||
<p:configurable/>
|
||||
</j:if>
|
||||
<st:include page="actions.jelly" />
|
||||
</l:tasks>
|
||||
|
||||
<st:include page="sidepanel2.jelly" optional="true" />
|
||||
|
||||
<j:forEach var="w" items="${it.widgets}">
|
||||
<st:include it="${w}" page="index.jelly" />
|
||||
</j:forEach>
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
</l:side-panel>
|
||||
</j:jelly>
|
||||
@@ -24,44 +24,53 @@ THE SOFTWARE.
|
||||
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout" xmlns:t="/lib/hudson">
|
||||
<l:layout title="${it.displayName}${not empty it.parent.fullDisplayName?' ['+it.parent.fullDisplayName+']':''}">
|
||||
<st:include page="sidepanel.jelly" />
|
||||
<!-- no need for additional breadcrumb here as we're on an index page already including breadcrumb -->
|
||||
<l:main-panel>
|
||||
<div class="jenkins-app-bar">
|
||||
<div class="jenkins-app-bar__content jenkins-build-caption">
|
||||
<j:set var="lastBuild" value="${it.lastBuild}" />
|
||||
<j:if test="${lastBuild != null}">
|
||||
<a href="${rootURL + '/' + lastBuild.url}" class="jenkins-!-display-contents" tabindex="-1">
|
||||
<l:icon src="symbol-status-${lastBuild.iconColor.iconName}" tooltip="${lastBuild.iconColor.description}"/>
|
||||
</a>
|
||||
<l:userExperimentalFlag var="newJobPage" flagClassName="jenkins.model.experimentalflags.NewJobPageUserExperimentalFlag" />
|
||||
|
||||
<j:choose>
|
||||
<j:when test="${newJobPage}">
|
||||
<st:include page="new-job-page.jelly" />
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
<l:layout title="${it.displayName}${not empty it.parent.fullDisplayName?' ['+it.parent.fullDisplayName+']':''}">
|
||||
<st:include page="sidepanel.jelly" />
|
||||
<!-- no need for additional breadcrumb here as we're on an index page already including breadcrumb -->
|
||||
<l:main-panel>
|
||||
<div class="jenkins-app-bar">
|
||||
<div class="jenkins-app-bar__content jenkins-build-caption">
|
||||
<j:set var="lastBuild" value="${it.lastBuild}" />
|
||||
<j:if test="${lastBuild != null}">
|
||||
<a href="${rootURL + '/' + lastBuild.url}" class="jenkins-!-display-contents" tabindex="-1">
|
||||
<l:icon src="symbol-status-${lastBuild.iconColor.iconName}" tooltip="${lastBuild.iconColor.description}"/>
|
||||
</a>
|
||||
</j:if>
|
||||
<h1 class="job-index-headline page-headline">
|
||||
<l:breakable value="${it.displayName}"/>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="jenkins-app-bar__controls">
|
||||
<t:editDescriptionButton permission="${it.CONFIGURE}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<j:if test="${(it.fullName!=it.fullDisplayName) and (it.class.name!='hudson.matrix.MatrixConfiguration')}"> <!-- TODO rather check for TopLevelItem (how to do this from Jelly?) -->
|
||||
<j:choose>
|
||||
<j:when test="${it.parent!=app}">
|
||||
${%Full project name}: ${it.fullName}
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
${%Project name}: ${it.fullName}
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
</j:if>
|
||||
<h1 class="job-index-headline page-headline">
|
||||
<l:breakable value="${it.displayName}"/>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="jenkins-app-bar__controls">
|
||||
<t:editDescriptionButton permission="${it.CONFIGURE}"/>
|
||||
</div>
|
||||
</div>
|
||||
<t:editableDescription permission="${it.CONFIGURE}" hideButton="true"/>
|
||||
|
||||
<j:if test="${(it.fullName!=it.fullDisplayName) and (it.class.name!='hudson.matrix.MatrixConfiguration')}"> <!-- TODO rather check for TopLevelItem (how to do this from Jelly?) -->
|
||||
<j:choose>
|
||||
<j:when test="${it.parent!=app}">
|
||||
${%Full project name}: ${it.fullName}
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
${%Project name}: ${it.fullName}
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
</j:if>
|
||||
<t:editableDescription permission="${it.CONFIGURE}" hideButton="true"/>
|
||||
<st:include page="jobpropertysummaries.jelly" />
|
||||
<!-- inject main part here -->
|
||||
<st:include page="main.jelly" />
|
||||
|
||||
<st:include page="jobpropertysummaries.jelly" />
|
||||
<!-- inject main part here -->
|
||||
<st:include page="main.jelly" />
|
||||
|
||||
<st:include page="permalinks.jelly" />
|
||||
</l:main-panel>
|
||||
</l:layout>
|
||||
<st:include page="permalinks.jelly" />
|
||||
</l:main-panel>
|
||||
</l:layout>
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
</j:jelly>
|
||||
@@ -0,0 +1,32 @@
|
||||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2025, Jan Faracik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
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">
|
||||
<j:new className="jenkins.job.OverviewTab" var="it">
|
||||
<j:arg value="${it}"/>
|
||||
</j:new>
|
||||
|
||||
<st:include page="index.jelly" />
|
||||
</j:jelly>
|
||||
@@ -0,0 +1,58 @@
|
||||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2025, Jan Faracik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
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:f="/lib/form" xmlns:l="/lib/layout">
|
||||
<j:set var="delay" value="${request2.getParameter('delay')}" />
|
||||
<f:form method="post" action="build${empty(delay)?'':'?delay='+delay}" name="parameters"
|
||||
tableClass="parameters" class="jenkins-form">
|
||||
<j:forEach var="parameterDefinition" items="${it.parameterDefinitions}">
|
||||
<j:set var="escapeEntryTitleAndDescription" value="true"/> <!-- SECURITY-353 defense unless overridden -->
|
||||
<tbody>
|
||||
<st:include it="${parameterDefinition}"
|
||||
page="${parameterDefinition.descriptor.valuePage}" />
|
||||
</tbody>
|
||||
</j:forEach>
|
||||
<f:bottomButtonBar>
|
||||
<!--
|
||||
When used from the UI, use 303 redirect and send back to the job top page.
|
||||
When neither of those options are given, we'll report "201 Created".
|
||||
|
||||
We can't use XHR for submitting this as there might be file parameters,
|
||||
and submitting to IFRAME won't work either because 201 can't have HTML response.
|
||||
|
||||
So I think all we can do is this somewhat clunky workaround.
|
||||
-->
|
||||
<input type="hidden" name="statusCode" value="303" />
|
||||
<input type="hidden" name="redirectTo" value="." />
|
||||
<button class="jenkins-button jenkins-button--primary jenkins-!-build-color">
|
||||
<l:icon src="symbol-play" />
|
||||
${it.buildButtonText}
|
||||
</button>
|
||||
<a href="./" class="jenkins-button">
|
||||
${%Cancel}
|
||||
</a>
|
||||
</f:bottomButtonBar>
|
||||
</f:form>
|
||||
</j:jelly>
|
||||
@@ -40,37 +40,7 @@ THE SOFTWARE.
|
||||
<l:main-panel>
|
||||
<h1>${it.job.pronoun} ${it.job.displayName}</h1>
|
||||
<p class="jenkins-description">${%description}</p>
|
||||
<j:set var="delay" value="${request2.getParameter('delay')}" />
|
||||
<f:form method="post" action="build${empty(delay)?'':'?delay='+delay}" name="parameters"
|
||||
tableClass="parameters" class="jenkins-form">
|
||||
<j:forEach var="parameterDefinition" items="${it.parameterDefinitions}">
|
||||
<j:set var="escapeEntryTitleAndDescription" value="true"/> <!-- SECURITY-353 defense unless overridden -->
|
||||
<tbody>
|
||||
<st:include it="${parameterDefinition}"
|
||||
page="${parameterDefinition.descriptor.valuePage}" />
|
||||
</tbody>
|
||||
</j:forEach>
|
||||
<f:bottomButtonBar>
|
||||
<!--
|
||||
When used from the UI, use 303 redirect and send back to the job top page.
|
||||
When neither of those options are given, we'll report "201 Created".
|
||||
|
||||
We can't use XHR for submitting this as there might be file parameters,
|
||||
and submitting to IFRAME won't work either because 201 can't have HTML response.
|
||||
|
||||
So I think all we can do is this somewhat clunky workaround.
|
||||
-->
|
||||
<input type="hidden" name="statusCode" value="303" />
|
||||
<input type="hidden" name="redirectTo" value="." />
|
||||
<button class="jenkins-button jenkins-button--primary jenkins-!-build-color">
|
||||
<l:icon src="symbol-play" />
|
||||
${it.buildButtonText}
|
||||
</button>
|
||||
<a href="./" class="jenkins-button">
|
||||
${%Cancel}
|
||||
</a>
|
||||
</f:bottomButtonBar>
|
||||
</f:form>
|
||||
<st:include page="contents.jelly" />
|
||||
</l:main-panel>
|
||||
</l:layout>
|
||||
</j:jelly>
|
||||
@@ -0,0 +1,52 @@
|
||||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2025, Jan Faracik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
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" xmlns:t="/lib/hudson" xmlns:dd="/lib/layout/dropdowns">
|
||||
<l:job-subpage>
|
||||
<j:set var="it" value="${it.object}" />
|
||||
|
||||
<l:app-bar title="Overview">
|
||||
<l:details-bar it="${it}">
|
||||
<t:editDescriptionButton permission="${it.CONFIGURE}" compact="true" />
|
||||
</l:details-bar>
|
||||
</l:app-bar>
|
||||
|
||||
<t:editableDescription permission="${it.CONFIGURE}" hideButton="true"/>
|
||||
|
||||
<j:forEach var="w" items="${it.widgets}">
|
||||
<st:include it="${w}" page="index.jelly" />
|
||||
</j:forEach>
|
||||
|
||||
<l:card title="${%Legacy}">
|
||||
<div>
|
||||
<st:include page="jobpropertysummaries.jelly" />
|
||||
|
||||
<st:include page="main.jelly" />
|
||||
|
||||
<st:include page="permalinks.jelly" />
|
||||
</div>
|
||||
</l:card>
|
||||
</l:job-subpage>
|
||||
</j:jelly>
|
||||
@@ -0,0 +1,53 @@
|
||||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2025 Jan Faracik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
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" xmlns:t="/lib/hudson">
|
||||
<l:dialog title="${it.displayName}">
|
||||
<ul style="list-style-type: none; margin: 0; padding: 0;">
|
||||
<j:forEach var="item" items="${it.projects}">
|
||||
<li>
|
||||
<t:jobLink job="${item}" />
|
||||
<j:if test="${it.fingerprintConfigured and item.fingerprintConfigured}">
|
||||
<st:nbsp />
|
||||
<a href="${rootURL}/projectRelationship?item=${h.urlEncode(it.name)}&rhs=${h.urlEncode(item.name)}">
|
||||
<l:icon class="icon-fingerprint icon-sm" />
|
||||
</a>
|
||||
</j:if>
|
||||
</li>
|
||||
</j:forEach>
|
||||
</ul>
|
||||
</l:dialog>
|
||||
|
||||
<button class="jenkins-details__item"
|
||||
data-type="dialog-opener"
|
||||
data-dialog-id="${dialogId}">
|
||||
<div class="jenkins-details__item__icon">
|
||||
<l:icon src="${it.iconClassName}" />
|
||||
</div>
|
||||
<span>
|
||||
${it.displayName}
|
||||
</span>
|
||||
</button>
|
||||
</j:jelly>
|
||||
@@ -0,0 +1,53 @@
|
||||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2025 Jan Faracik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
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" xmlns:t="/lib/hudson">
|
||||
<l:dialog title="${it.displayName}">
|
||||
<ul style="list-style-type: none; margin: 0; padding: 0;">
|
||||
<j:forEach var="item" items="${it.projects}">
|
||||
<li>
|
||||
<t:jobLink job="${item}" />
|
||||
<j:if test="${item.fingerprintConfigured and it.fingerprintConfigured}">
|
||||
<st:nbsp />
|
||||
<a href="${rootURL}/projectRelationship?item=${h.urlEncode(item.name)}&rhs=${h.urlEncode(it.name)}">
|
||||
<l:icon class="icon-fingerprint icon-sm" />
|
||||
</a>
|
||||
</j:if>
|
||||
</li>
|
||||
</j:forEach>
|
||||
</ul>
|
||||
</l:dialog>
|
||||
|
||||
<button class="jenkins-details__item"
|
||||
data-type="dialog-opener"
|
||||
data-dialog-id="${dialogId}">
|
||||
<div class="jenkins-details__item__icon">
|
||||
<l:icon src="${it.iconClassName}" />
|
||||
</div>
|
||||
<span>
|
||||
${it.displayName}
|
||||
</span>
|
||||
</button>
|
||||
</j:jelly>
|
||||
@@ -25,17 +25,21 @@ THE SOFTWARE.
|
||||
<?jelly escape-by-default='true'?>
|
||||
<!-- Displayed by projects (assignable to ParameterizedJobMixIn.ParameterizedJob) which can be configured and built. -->
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:l="/lib/layout" xmlns:st="jelly:stapler">
|
||||
<j:if test="${it.buildable}">
|
||||
<l:userExperimentalFlag var="newJobPage" flagClassName="jenkins.model.experimentalflags.NewJobPageUserExperimentalFlag" />
|
||||
|
||||
<j:if test="${!newJobPage}">
|
||||
<j:if test="${it.buildable}">
|
||||
<st:adjunct includes="lib.hudson.project.configurable.configurable"/>
|
||||
<l:task href="${url}/build?delay=0sec" icon="icon-clock icon-md" permission="${it.BUILD}" post="${!it.parameterized}" data-callback="lib_hudson_project_configurable_build_now_callback" data-build-failure="${%buildFailed}" data-build-success="${%Build scheduled}" data-parameterized="${it.parameterized}" title="${it.buildNowText}"/>
|
||||
</j:if>
|
||||
<j:choose>
|
||||
</j:if>
|
||||
<j:choose>
|
||||
<j:when test="${h.hasPermission(it,it.CONFIGURE)}">
|
||||
<l:task href="${url}/configure" icon="symbol-settings" title="${%Configure}"/>
|
||||
<l:task href="${url}/configure" icon="symbol-settings" title="${%Configure}"/>
|
||||
</j:when>
|
||||
<j:when test="${h.hasPermission(it,it.EXTENDED_READ)}">
|
||||
<l:task href="${url}/configure" icon="symbol-settings" title="${%View Configuration}"/>
|
||||
<l:task href="${url}/configure" icon="symbol-settings" title="${%View Configuration}"/>
|
||||
</j:when>
|
||||
</j:choose>
|
||||
</j:choose>
|
||||
</j:if>
|
||||
<l:delete message="${%delete.confirm(it.pronoun, it.displayName)}" urlPrefix="${url}" permission="${it.DELETE}" title="${%delete(it.pronoun)}"/>
|
||||
</j:jelly>
|
||||
@@ -0,0 +1,131 @@
|
||||
<!--
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2025, Jan Faracik
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
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:l="/lib/layout" xmlns:d="jelly:define" xmlns:dd="/lib/layout/dropdowns"
|
||||
xmlns:st="jelly:stapler">
|
||||
<st:documentation>
|
||||
A reusable container for subpages relating to Jobs in Jenkins.
|
||||
Renders a tabbed layout for jobs, including build status and actions.
|
||||
</st:documentation>
|
||||
|
||||
<l:layout title="${it.displayName} - ${it.object.displayName}">
|
||||
<l:userExperimentalFlag var="newJobPage" flagClassName="jenkins.model.experimentalflags.NewJobPageUserExperimentalFlag" />
|
||||
|
||||
<j:choose>
|
||||
<j:when test="${newJobPage}">
|
||||
<l:main-panel>
|
||||
<div class="app-build-bar">
|
||||
<div class="app-build-bar__content">
|
||||
<j:set var="lastBuild" value="${it.object.lastBuild}" />
|
||||
<j:if test="${lastBuild != null}">
|
||||
<a href="${rootURL + '/' + lastBuild.url}" class="jenkins-!-display-contents" tabindex="-1">
|
||||
<l:icon src="symbol-status-${lastBuild.iconColor.iconName}" tooltip="${lastBuild.iconColor.description}" class="icon-md" />
|
||||
</a>
|
||||
</j:if>
|
||||
<h1 class="job-index-headline page-headline">
|
||||
<l:breakable value="${it.object.displayName}"/>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<j:set var="url" value="${h.getNearestAncestorUrl(request2, it.object)}"/>
|
||||
|
||||
<div class="app-build-bar__tabs">
|
||||
<l:tabs items="${it.object.jobTabs}" />
|
||||
</div>
|
||||
|
||||
<div class="app-build-bar__controls">
|
||||
<j:if test="${it.object.buildable and h.hasPermission(it.object, it.object.BUILD)}">
|
||||
<j:choose>
|
||||
<j:when test="${!it.object.parameterized}">
|
||||
<a class="jenkins-button jenkins-!-build-color task-link-no-confirm"
|
||||
data-callback="lib_hudson_project_configurable_build_now_callback"
|
||||
data-build-failure="${%Build failed}"
|
||||
data-build-success="${%Build scheduled}"
|
||||
data-parameterized="false"
|
||||
data-task-post="true"
|
||||
href="${url}/build?delay=0sec">
|
||||
<l:icon src="symbol-play" />
|
||||
${it.object.buildNowText}
|
||||
</a>
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
<l:dialog title="${it.object.buildNowText}" hash="build-with-parameters">
|
||||
<div>
|
||||
<st:include page="contents.jelly" it="${it.object.parametersDefinitionProperty}" />
|
||||
</div>
|
||||
</l:dialog>
|
||||
|
||||
<button class="jenkins-button jenkins-!-build-color"
|
||||
data-type="dialog-opener"
|
||||
data-dialog-id="${dialogId}">
|
||||
<l:icon src="symbol-play" />
|
||||
${it.object.buildNowText}
|
||||
</button>
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
|
||||
<st:adjunct includes="lib.hudson.project.configurable.configurable"/>
|
||||
<st:adjunct includes="lib.layout.task.task" />
|
||||
</j:if>
|
||||
|
||||
<j:choose>
|
||||
<j:when test="${h.hasPermission(it.object, it.object.CONFIGURE)}">
|
||||
<a href="${url}/configure" class="jenkins-button">
|
||||
${%Configure}
|
||||
</a>
|
||||
</j:when>
|
||||
<j:when test="${h.hasPermission(it.object, it.object.EXTENDED_READ)}">
|
||||
<a href="${url}/configure" class="jenkins-button">
|
||||
${%View Configuration}
|
||||
</a>
|
||||
</j:when>
|
||||
</j:choose>
|
||||
|
||||
<l:overflowButton>
|
||||
<dd:custom>
|
||||
<div class="app-build-overflow">
|
||||
<j:set var="mode" value="side-panel" />
|
||||
<st:include page="sidepanel.jelly" it="${it.object}" />
|
||||
</div>
|
||||
</dd:custom>
|
||||
</l:overflowButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="app-build-content">
|
||||
<d:invokeBody />
|
||||
</div>
|
||||
</l:main-panel>
|
||||
</j:when>
|
||||
<j:otherwise>
|
||||
<st:include page="sidepanel.jelly" it="${it.object}" />
|
||||
|
||||
<l:main-panel>
|
||||
<d:invokeBody />
|
||||
</l:main-panel>
|
||||
</j:otherwise>
|
||||
</j:choose>
|
||||
</l:layout>
|
||||
</j:jelly>
|
||||
@@ -32,20 +32,22 @@ THE SOFTWARE.
|
||||
</st:attribute>
|
||||
</st:documentation>
|
||||
|
||||
<div class="app-build-tabs">
|
||||
<j:forEach var="tab" items="${items}">
|
||||
<a href="${url}/${tab.urlName}"
|
||||
class="jenkins-button ${h.hyperlinkMatchesCurrentPage(tab.urlName ?: url) ? '' : 'jenkins-button--tertiary'}">
|
||||
<j:if test="${tab.iconFileName != null}">
|
||||
<l:icon src="${tab.iconFileName}" />
|
||||
</j:if>
|
||||
${tab.displayName}
|
||||
<j:if test="${tab.badge != null}">
|
||||
<div class="pill jenkins-!-${tab.badge.severity}-color" aria-label="${tab.badge.tooltip}">
|
||||
${tab.badge.text}
|
||||
</div>
|
||||
</j:if>
|
||||
</a>
|
||||
</j:forEach>
|
||||
</div>
|
||||
<j:if test="${items.size() gt 1}">
|
||||
<div class="app-build-tabs">
|
||||
<j:forEach var="tab" items="${items}">
|
||||
<a href="${url}/${tab.urlName}"
|
||||
class="jenkins-button ${h.hyperlinkMatchesCurrentPage(tab.urlName ?: url) ? '' : 'jenkins-button--tertiary'}">
|
||||
<j:if test="${tab.iconFileName != null}">
|
||||
<l:icon src="${tab.iconFileName}" />
|
||||
</j:if>
|
||||
${tab.displayName}
|
||||
<j:if test="${tab.badge != null}">
|
||||
<div class="pill jenkins-!-${tab.badge.severity}-color" aria-label="${tab.badge.tooltip}">
|
||||
${tab.badge.text}
|
||||
</div>
|
||||
</j:if>
|
||||
</a>
|
||||
</j:forEach>
|
||||
</div>
|
||||
</j:if>
|
||||
</j:jelly>
|
||||
@@ -1,6 +1,8 @@
|
||||
$jenkins-dialog-padding: 1.25rem;
|
||||
|
||||
.jenkins-dialog {
|
||||
--background: var(--dialog-background);
|
||||
|
||||
border-radius: 1rem;
|
||||
border: none;
|
||||
background-color: var(--dialog-background);
|
||||
|
||||
@@ -154,7 +154,7 @@ body:has(.app-build-bar) {
|
||||
min-height: 2.875rem;
|
||||
margin-top: -5px;
|
||||
padding-bottom: 0.75rem;
|
||||
z-index: 2;
|
||||
z-index: 102;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
@use "../abstracts/mixins";
|
||||
|
||||
#buildHistoryPage {
|
||||
margin: 10px 0 10px 10px;
|
||||
#side-panel {
|
||||
#buildHistoryPage {
|
||||
margin: 10px 0 10px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
#buildHistoryPage {
|
||||
.jenkins-search {
|
||||
margin-inline: -0.25rem;
|
||||
margin-bottom: 5px;
|
||||
|
||||
Reference in new issue
Block a user