Render /manage using ManageJenkinsAction, handle links using StaplerF… (#6126)

Co-authored-by: Daniel Beck <daniel-beck@users.noreply.github.com>
Co-authored-by: Basil Crow <me@basilcrow.com>
Co-authored-by: Tim Jacomb <timjacomb1+github@gmail.com>
Co-authored-by: Tim Jacomb <21194782+timja@users.noreply.github.com>
This commit is contained in:
Daniel Beck 2022-07-13 00:03:45 +02:00 committed by GitHub
parent 788aaadb2f
commit a990ebcda4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 51 additions and 12 deletions

View File

@ -25,8 +25,18 @@
package hudson.model;
import hudson.Extension;
import hudson.Util;
import java.io.IOException;
import jenkins.model.Jenkins;
import jenkins.model.ModelObjectWithContextMenu;
import org.apache.commons.jelly.JellyException;
import org.jenkinsci.Symbol;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerFallback;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
/**
* Adds the "Manage Jenkins" link to the top page.
@ -34,7 +44,7 @@ import org.jenkinsci.Symbol;
* @author Kohsuke Kawaguchi
*/
@Extension(ordinal = 100) @Symbol("manageJenkins")
public class ManageJenkinsAction implements RootAction {
public class ManageJenkinsAction implements RootAction, StaplerFallback, ModelObjectWithContextMenu {
@Override
public String getIconFileName() {
if (Jenkins.get().hasAnyPermission(Jenkins.MANAGE, Jenkins.SYSTEM_READ))
@ -52,4 +62,29 @@ public class ManageJenkinsAction implements RootAction {
public String getUrlName() {
return "/manage";
}
@Override
public Object getStaplerFallback() {
return Jenkins.get();
}
@Override
public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws JellyException, IOException {
return new ContextMenu().from(this, request, response, "index");
}
/**
* Workaround to ensuring that links in context menus resolve correctly in the submenu of the top-level 'Dashboard'
* menu.
*/
@Restricted(NoExternalUse.class)
public void addContextMenuItem(ContextMenu menu, String url, String icon, String iconXml, String text, boolean post, boolean requiresConfirmation) {
if (Stapler.getCurrentRequest().findAncestorObject(this.getClass()) != null || !Util.isSafeToRedirectTo(url)) {
// Default behavior if the URL is absolute or scheme-relative, or the current object is an ancestor (i.e. would resolve correctly)
menu.add(url, icon, iconXml, text, post, requiresConfirmation);
return;
}
// If neither is the case, rewrite the relative URL to point to inside the /manage/ URL space
menu.add("manage/" + url, icon, iconXml, text, post, requiresConfirmation);
}
}

View File

@ -115,6 +115,7 @@ import hudson.model.Label;
import hudson.model.ListView;
import hudson.model.LoadBalancer;
import hudson.model.LoadStatistics;
import hudson.model.ManageJenkinsAction;
import hudson.model.ManagementLink;
import hudson.model.Messages;
import hudson.model.ModifiableViewGroup;
@ -4415,7 +4416,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
for (MenuItem i : menu.items) {
if (i.url.equals(request.getContextPath() + "/manage")) {
// add "Manage Jenkins" subitems
i.subMenu = new ContextMenu().from(this, request, response, "manage");
i.subMenu = new ContextMenu().from(ExtensionList.lookupSingleton(ManageJenkinsAction.class), request, response, "index");
}
}
return menu;

View File

@ -30,7 +30,7 @@ l.side_panel {
l.task(icon:"icon-up icon-md", href:rootURL+'/', title:_("Back to Dashboard"))
l.task(icon:"symbol-settings", href:"${rootURL}/manage", title:_("Manage Jenkins"))
if (!app.updateCenter.jobs.isEmpty()) {
l.task(icon: "symbol-download", href:"${rootURL}/updateCenter/", title:_("Update Center"))
l.task(icon: "symbol-download", href:"../updateCenter/", title:_("Update Center"))
}
}
}

View File

@ -34,7 +34,7 @@ THE SOFTWARE.
<l:task href="${rootURL}/" icon="icon-up icon-md" title="${%Back to Dashboard}"/>
<l:task href="${rootURL}/manage" icon="symbol-settings" permissions="${app.MANAGE_AND_SYSTEM_READ}" title="${%Manage Jenkins}"/>
<l:task href="new" icon="symbol-add" permission="${createPermission}" title="${%New Node}"/>
<l:task href="${rootURL}/configureClouds" icon="symbol-cloud" permission="${app.SYSTEM_READ}"
<l:task href="../configureClouds" icon="symbol-cloud" permission="${app.SYSTEM_READ}"
title="${app.hasPermission(app.ADMINISTER) ? '%Configure Clouds' : '%View Clouds'}"/>
<l:task href="configure" icon="symbol-settings" permissions="${app.MANAGE_AND_SYSTEM_READ}" title="${%Node Monitoring}"/>
</l:tasks>

View File

@ -31,7 +31,7 @@ THE SOFTWARE.
<l:app-bar title="${%Manage Jenkins}" />
<j:if test="${taskTags==null}">
<st:include page="sidepanel.jelly" />
<st:include page="sidepanel.jelly" it="${app}" />
</j:if>
<l:main-panel>
@ -39,10 +39,10 @@ THE SOFTWARE.
<j:forEach var="am" items="${app.activeAdministrativeMonitors}">
<st:include page="message.jelly" it="${am}" />
</j:forEach>
<st:include page="downgrade.jelly" />
<st:include page="downgrade.jelly" it="${app}" />
</section>
<j:forEach var="category" items="${it.categorizedManagementLinks.entrySet()}">
<j:forEach var="category" items="${app.categorizedManagementLinks.entrySet()}">
<section class="jenkins-section jenkins-section--bottom-padding">
<h2 class="jenkins-section__title">${category.key.label}</h2>
${taskTags!=null and attrs.contextMenu!='false' ? taskTags.addHeader(category.key.label) : null}
@ -55,7 +55,7 @@ THE SOFTWARE.
<j:set var="iconXml">
<l:icon src="${m.iconFileName}" />
</j:set>
${taskTags!=null and attrs.contextMenu!='false' ? taskTags.add(m.urlName, iconSrc, iconXml, m.displayName, m.requiresPOST, m.requiresConfirmation) : null}
${taskTags!=null and attrs.contextMenu!='false' ? it.addContextMenuItem(taskTags, m.urlName, iconSrc, iconXml, m.displayName, m.requiresPOST, m.requiresConfirmation) : null}
<j:choose>
<j:when test="${m.requiresConfirmation}">
<l:confirmationLink href="${m.urlName}" post="${m.requiresPOST}" message="${%are.you.sure(m.displayName)}">

View File

@ -32,7 +32,7 @@ THE SOFTWARE.
<l:tasks>
<l:task href="${rootURL}/" icon="icon-up icon-md" title="${%Back to Dashboard}"/>
<l:task href="${rootURL}/manage" icon="symbol-settings" title="${%Manage Jenkins}"/>
<l:task href="${rootURL}/pluginManager/" icon="icon-plugin icon-lg" title="${%Manage Plugins}"/>
<l:task href="../pluginManager/" icon="icon-plugin icon-lg" title="${%Manage Plugins}"/>
</l:tasks>
</l:side-panel>
</j:jelly>

View File

@ -13,7 +13,7 @@ l.layout(norefresh:true, permission:app.SYSTEM_READ, title:my.displayName) {
l.side_panel {
l.tasks {
l.task(icon:"icon-up icon-md", href:rootURL+'/', title:_("Back to Dashboard"))
l.task(icon:"symbol-settings", href:"${rootURL}/computer/", title:_("Manage Nodes"))
l.task(icon:"symbol-settings", href: "../computer/", title:_("Manage Nodes"))
}
}
l.app_bar(title: my.displayName)

View File

@ -26,9 +26,10 @@ 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">
<l:layout title="${it.displayName} ${%Load Statistics}">
<st:include page="sidepanel.jelly" />
<l:breadcrumb title="${%Load Statistics}"/>
<l:main-panel>
<j:set var="prefix" value="overallLoad" />
<st:include page="main.jelly" from="${it.overallLoad}" />
</l:main-panel>
</l:layout>
</j:jelly>
</j:jelly>

View File

@ -29,6 +29,7 @@ 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">
<l:layout permissions="${app.MANAGE_AND_SYSTEM_READ}" title="${%System Information}">
<st:include page="sidepanel.jelly" />
<l:breadcrumb title="${%System Information}"/>
<l:main-panel>
<l:hasPermission permission="${app.SYSTEM_READ}">
<div class="jenkins-app-bar">

View File

@ -30,6 +30,7 @@ THE SOFTWARE.
<l:layout permission="${h.ADMINISTER}" title="${%Script Console}">
<st:include page="sidepanel.jelly" />
<l:breadcrumb title="${%Script Console}"/>
<l:main-panel>
<h1>${%Script Console}</h1>

View File

@ -86,7 +86,7 @@ public class Jenkins64991Test {
final Page redirectedPage = HtmlFormUtil.submit(loginPage.getFormByName("login"));
assertTrue(redirectedPage.isHtmlPage());
assertEquals(j.getURL() + "manage", redirectedPage.getUrl().toExternalForm());
assertEquals(j.getURL() + "manage/", redirectedPage.getUrl().toExternalForm());
assertThat(redirectedPage.getWebResponse().getContentAsString(), containsStringIgnoringCase(Messages.GlobalSecurityConfiguration_DisplayName()));
}