mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-11 11:06:25 +00:00
Manage Jenkins with flow layout and categories
Co-authored-by: Félix Queiruga <fqueiruga@cloudbees.com>
This commit is contained in:
1 parent
1e5112a106
commit
61dfeaf113
22 files changed
+208
-7
No files matched your search
@@ -46,4 +46,10 @@ public class AboutJenkins extends ManagementLink {
|
||||
public Permission getRequiredPermission() {
|
||||
return Jenkins.SYSTEM_READ;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.STATUS.toString();
|
||||
}
|
||||
}
|
||||
@@ -440,6 +440,11 @@ public class OldDataMonitor extends AdministrativeMonitor {
|
||||
|
||||
@Extension @Symbol("oldData")
|
||||
public static class ManagementLinkImpl extends ManagementLink {
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.TROUBLESHOOTING.toString();
|
||||
}
|
||||
@Override
|
||||
public String getIconFileName() {
|
||||
return "document.png";
|
||||
|
||||
@@ -53,6 +53,7 @@ import org.apache.tools.ant.DefaultLogger;
|
||||
import org.apache.tools.ant.types.FileSet;
|
||||
import org.kohsuke.stapler.interceptor.RequirePOST;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.servlet.ServletException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -100,6 +101,13 @@ public class WindowsInstallerLink extends ManagementLink {
|
||||
return Messages.WindowsInstallerLink_Description();
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.CONFIGURATION.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the installation successful?
|
||||
*/
|
||||
|
||||
@@ -30,7 +30,9 @@ import hudson.ExtensionList;
|
||||
import hudson.security.Permission;
|
||||
import jenkins.model.Jenkins;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.List;
|
||||
|
||||
import org.kohsuke.stapler.interceptor.RequirePOST;
|
||||
|
||||
import javax.annotation.CheckForNull;
|
||||
@@ -131,4 +133,37 @@ public abstract class ManagementLink implements ExtensionPoint, Action {
|
||||
public boolean getRequiresPOST() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Category for management link, uses {@code String} so it can be done with core dependency pre-dating the version this feature was added.
|
||||
*
|
||||
* @return An enum value of {@link Category}.
|
||||
* @since TODO
|
||||
*/
|
||||
public @Nonnull String getCategory() {
|
||||
return Category.UNCATEGORIZED.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Categories supported by this version of core.
|
||||
*
|
||||
* @since TODO
|
||||
*/
|
||||
public enum Category {
|
||||
CONFIGURATION,
|
||||
SECURITY,
|
||||
STATUS,
|
||||
TROUBLESHOOTING,
|
||||
TOOLS,
|
||||
MISC,
|
||||
UNCATEGORIZED;
|
||||
|
||||
public @Nonnull String getLabel() {
|
||||
try {
|
||||
return Messages.class.getMethod("ManagementLink_Category_" + this.toString()).invoke(null).toString();
|
||||
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||
return Messages.ManagementLink_Category_UNCATEGORIZED();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import java.util.function.Predicate;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import jenkins.model.GlobalConfigurationCategory;
|
||||
@@ -93,6 +94,11 @@ public class GlobalSecurityConfiguration extends ManagementLink implements Descr
|
||||
return Jenkins.get().isDisableRememberMe();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.SECURITY.toString();
|
||||
}
|
||||
@POST
|
||||
public synchronized void doConfigure(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
|
||||
// for compatibility reasons, the actual value is stored in Jenkins
|
||||
|
||||
@@ -771,6 +771,12 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
|
||||
public String getDescription() {
|
||||
return Messages.HudsonPrivateSecurityRealm_ManageUserLinks_Description();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.SECURITY.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -62,4 +62,10 @@ public class CliLink extends ManagementLink {
|
||||
public String getUrlName() {
|
||||
return "cli";
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.TOOLS.toString();
|
||||
}
|
||||
}
|
||||
@@ -62,4 +62,10 @@ public class ConfigureLink extends ManagementLink {
|
||||
public String getUrlName() {
|
||||
return "configure";
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.CONFIGURATION.toString();
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,8 @@ import hudson.security.Permission;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.jenkinsci.Symbol;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
|
||||
*/
|
||||
@@ -59,4 +61,10 @@ public class ConsoleLink extends ManagementLink {
|
||||
public Permission getRequiredPermission() {
|
||||
return Jenkins.ADMINISTER;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.TOOLS.toString();
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,6 @@ package jenkins.management;
|
||||
import hudson.Extension;
|
||||
import hudson.model.ManagementLink;
|
||||
import hudson.security.Permission;
|
||||
import jenkins.management.Messages;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.jenkinsci.Symbol;
|
||||
|
||||
@@ -63,4 +62,10 @@ public class NodesLink extends ManagementLink {
|
||||
public String getUrlName() {
|
||||
return "computer";
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.CONFIGURATION.toString();
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,8 @@ import hudson.Extension;
|
||||
import hudson.model.ManagementLink;
|
||||
import org.jenkinsci.Symbol;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
|
||||
*/
|
||||
@@ -52,4 +54,10 @@ public class PluginsLink extends ManagementLink {
|
||||
public String getUrlName() {
|
||||
return "pluginManager";
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.CONFIGURATION.toString();
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,8 @@ import hudson.Extension;
|
||||
import hudson.model.ManagementLink;
|
||||
import org.jenkinsci.Symbol;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
|
||||
*/
|
||||
@@ -61,4 +63,10 @@ public class ReloadLink extends ManagementLink {
|
||||
public boolean getRequiresPOST() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.TOOLS.toString();
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ import hudson.model.ManagementLink;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.jenkinsci.Symbol;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
|
||||
*/
|
||||
@@ -58,4 +60,10 @@ public class ShutdownLink extends ManagementLink {
|
||||
public boolean getRequiresPOST() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.TOOLS.toString();
|
||||
}
|
||||
}
|
||||
@@ -62,4 +62,10 @@ public class StatisticsLink extends ManagementLink {
|
||||
public String getUrlName() {
|
||||
return "load-statistics";
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.STATUS.toString();
|
||||
}
|
||||
}
|
||||
@@ -31,8 +31,6 @@ import javax.annotation.Nonnull;
|
||||
import jenkins.model.Jenkins;
|
||||
import org.jenkinsci.Symbol;
|
||||
|
||||
import javax.annotation.CheckForNull;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
|
||||
*/
|
||||
@@ -63,4 +61,10 @@ public class SystemInfoLink extends ManagementLink {
|
||||
public String getUrlName() {
|
||||
return "systemInfo";
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.STATUS.toString();
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,8 @@ import hudson.Extension;
|
||||
import hudson.model.ManagementLink;
|
||||
import org.jenkinsci.Symbol;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
|
||||
*/
|
||||
@@ -52,4 +54,10 @@ public class SystemLogLink extends ManagementLink {
|
||||
public String getUrlName() {
|
||||
return "log";
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.STATUS.toString();
|
||||
}
|
||||
}
|
||||
@@ -4705,6 +4705,29 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
|
||||
public List<ManagementLink> getManagementLinks() {
|
||||
return ManagementLink.all();
|
||||
}
|
||||
|
||||
// for Jelly
|
||||
@Restricted(NoExternalUse.class)
|
||||
public Map<ManagementLink.Category, List<ManagementLink>> getCategorizedManagementLinks() {
|
||||
Map<ManagementLink.Category, List<ManagementLink>> byCategory = new TreeMap<>();
|
||||
for (ManagementLink link : ManagementLink.all()) {
|
||||
if (link.getIconFileName() == null) {
|
||||
continue;
|
||||
}
|
||||
if (!Jenkins.get().hasPermission(link.getRequiredPermission())) {
|
||||
continue;
|
||||
}
|
||||
String categoryName = link.getCategory();
|
||||
ManagementLink.Category category;
|
||||
try {
|
||||
category = ManagementLink.Category.valueOf(categoryName);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
category = ManagementLink.Category.UNCATEGORIZED;
|
||||
}
|
||||
byCategory.computeIfAbsent(category, c -> new ArrayList<>()).add(link);
|
||||
}
|
||||
return byCategory;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set, a currently active setup wizard - e.g. installation
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.kohsuke.stapler.StaplerRequest;
|
||||
import org.kohsuke.stapler.StaplerResponse;
|
||||
import org.kohsuke.stapler.verb.POST;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.servlet.ServletException;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
@@ -73,6 +74,12 @@ public class GlobalToolConfiguration extends ManagementLink {
|
||||
return Jenkins.ADMINISTER;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return Category.CONFIGURATION.toString();
|
||||
}
|
||||
|
||||
@POST
|
||||
public synchronized void doConfigure(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException {
|
||||
boolean result = configure(req, req.getSubmittedForm());
|
||||
|
||||
@@ -404,3 +404,11 @@ User.IllegalFullname="{0}" is prohibited as a full name for security reasons.
|
||||
|
||||
TimeZoneProperty.DisplayName=User Defined Time Zone
|
||||
TimeZoneProperty.DisplayDefaultTimeZone=Default
|
||||
|
||||
ManagementLink.Category.CONFIGURATION=System Configuration
|
||||
ManagementLink.Category.SECURITY=Security
|
||||
ManagementLink.Category.STATUS=Status Information
|
||||
ManagementLink.Category.TROUBLESHOOTING=Troubleshooting
|
||||
ManagementLink.Category.TOOLS=Tools and Actions
|
||||
ManagementLink.Category.MISC=Other
|
||||
ManagementLink.Category.UNCATEGORIZED=Uncategorized
|
||||
@@ -47,11 +47,13 @@ THE SOFTWARE.
|
||||
<st:include page="downgrade.jelly" />
|
||||
</div>
|
||||
|
||||
<j:forEach var="m" items="${it.managementLinks}">
|
||||
<l:hasPermission permission="${m.requiredPermission}">
|
||||
<j:forEach var="category" items="${it.categorizedManagementLinks.entrySet()}">
|
||||
<h2>${category.key.label}</h2>
|
||||
<div class="manage-page__row">
|
||||
<j:forEach var="m" items="${category.value}">
|
||||
<j:set var="icon" value="${m.iconClassName != null ? m.iconClassName : m.iconFileName}" />
|
||||
<j:if test="${icon!=null}">
|
||||
<div class="manage-option">
|
||||
<div class="manage-option manage-page__column">
|
||||
<j:set var="iconUrl" value="${icon.startsWith('/') ? resURL+icon : imagesURL + '/48x48/' + icon}" />
|
||||
<j:set var="alt" value="${icon.replaceAll('\\d*\\.[^.]+$', '')}"/>
|
||||
${taskTags!=null and attrs.contextMenu!='false' ? taskTags.add(m.urlName, iconUrl, m.displayName, m.requiresPOST, m.requiresConfirmation) : null}
|
||||
@@ -89,7 +91,8 @@ THE SOFTWARE.
|
||||
</j:choose>
|
||||
</div>
|
||||
</j:if>
|
||||
</l:hasPermission>
|
||||
</j:forEach>
|
||||
</div>
|
||||
</j:forEach>
|
||||
|
||||
</l:main-panel>
|
||||
|
||||
@@ -15,3 +15,5 @@ html {
|
||||
// Keep page header code in this bundle to avoid loading multiple files
|
||||
// that are always needed
|
||||
@import './modules/page-header.less';
|
||||
|
||||
@import './modules/manage-jenkins.less';
|
||||
@@ -0,0 +1,25 @@
|
||||
.manage-page__row {
|
||||
display: block;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.manage-page__column {
|
||||
width: 100%;
|
||||
// TODO: set padding
|
||||
// TODO: set margin bottom
|
||||
}
|
||||
@media screen and (min-width: 992px) {
|
||||
.manage-page__column {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1200px) {
|
||||
.manage-page__column {
|
||||
width: 33.333%;
|
||||
}
|
||||
}
|
||||
@media screen and (min-width: 1800px) {
|
||||
.manage-page__column {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user