diff --git a/core/src/main/java/hudson/model/ManageJenkinsAction.java b/core/src/main/java/hudson/model/ManageJenkinsAction.java index 776b37c4f2..9590289330 100644 --- a/core/src/main/java/hudson/model/ManageJenkinsAction.java +++ b/core/src/main/java/hudson/model/ManageJenkinsAction.java @@ -27,6 +27,10 @@ package hudson.model; import hudson.Extension; import hudson.Util; import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import jenkins.management.AdministrativeMonitorsDecorator; import jenkins.management.Badge; import jenkins.model.Jenkins; import jenkins.model.ModelObjectWithContextMenu; @@ -40,11 +44,11 @@ import org.kohsuke.stapler.StaplerRequest2; import org.kohsuke.stapler.StaplerResponse2; /** - * Adds the "Manage Jenkins" link to the top page. + * Adds the "Manage Jenkins" link to the navigation bar. * * @author Kohsuke Kawaguchi */ -@Extension(ordinal = 100) @Symbol("manageJenkins") +@Extension(ordinal = 998) @Symbol("manageJenkins") public class ManageJenkinsAction implements RootAction, StaplerFallback, ModelObjectWithContextMenu { @Override public String getIconFileName() { @@ -88,4 +92,29 @@ public class ManageJenkinsAction implements RootAction, StaplerFallback, ModelOb // 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, badge, message); } + + @Override + public Badge getBadge() { + Jenkins jenkins = Jenkins.get(); + AdministrativeMonitorsDecorator decorator = jenkins.getExtensionList(PageDecorator.class) + .get(AdministrativeMonitorsDecorator.class); + + if (decorator == null) { + return null; + } + + Collection activeAdministrativeMonitors = Optional.ofNullable(decorator.getMonitorsToDisplay()).orElse(Collections.emptyList()); + boolean anySecurity = activeAdministrativeMonitors.stream().anyMatch(AdministrativeMonitor::isSecurity); + + if (activeAdministrativeMonitors.isEmpty()) { + return null; + } + + int size = activeAdministrativeMonitors.size(); + String tooltip = size > 1 ? Messages.ManageJenkinsAction_notifications(size) : Messages.ManageJenkinsAction_notification(size); + + return new Badge(String.valueOf(size), + tooltip, + anySecurity ? Badge.Severity.DANGER : Badge.Severity.WARNING); + } } diff --git a/core/src/main/java/hudson/model/MyViewsProperty.java b/core/src/main/java/hudson/model/MyViewsProperty.java index 2c5f9f49ab..2437b44a6e 100644 --- a/core/src/main/java/hudson/model/MyViewsProperty.java +++ b/core/src/main/java/hudson/model/MyViewsProperty.java @@ -321,7 +321,7 @@ public class MyViewsProperty extends UserProperty implements ModifiableViewGroup return Jenkins.get().getMyViewsTabBar(); } - @Extension @Symbol("myView") + @Symbol("myView") public static class GlobalAction implements RootAction { @Override diff --git a/core/src/main/java/hudson/model/RootAction.java b/core/src/main/java/hudson/model/RootAction.java index 9c431ee635..8226e67507 100644 --- a/core/src/main/java/hudson/model/RootAction.java +++ b/core/src/main/java/hudson/model/RootAction.java @@ -24,8 +24,10 @@ package hudson.model; +import edu.umd.cs.findbugs.annotations.CheckForNull; import hudson.Extension; import hudson.ExtensionPoint; +import jenkins.management.Badge; /** * Marker interface for actions that are added to {@link jenkins.model.Jenkins}. @@ -38,4 +40,14 @@ import hudson.ExtensionPoint; * @since 1.311 */ public interface RootAction extends Action, ExtensionPoint { + + /** + * A {@link Badge} shown on the button for the action. + * + * @return badge or {@code null} if no badge should be shown. + * @since TODO + */ + default @CheckForNull Badge getBadge() { + return null; + } } diff --git a/core/src/main/java/jenkins/management/AdministrativeMonitorsDecorator.java b/core/src/main/java/jenkins/management/AdministrativeMonitorsDecorator.java index d531f898c0..578c8d9055 100644 --- a/core/src/main/java/jenkins/management/AdministrativeMonitorsDecorator.java +++ b/core/src/main/java/jenkins/management/AdministrativeMonitorsDecorator.java @@ -28,7 +28,6 @@ import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; import hudson.diagnosis.ReverseProxySetupMonitor; import hudson.model.AdministrativeMonitor; -import hudson.model.ManageJenkinsAction; import hudson.model.PageDecorator; import hudson.util.HudsonIsLoading; import hudson.util.HudsonIsRestarting; @@ -56,9 +55,6 @@ public class AdministrativeMonitorsDecorator extends PageDecorator { public AdministrativeMonitorsDecorator() { // otherwise this would be added to every internal context menu building request ignoredJenkinsRestOfUrls.add("contextMenu"); - - // don't show here to allow admins to disable malfunctioning monitors via AdministrativeMonitorsDecorator - ignoredJenkinsRestOfUrls.add("configure"); } @NonNull @@ -163,11 +159,6 @@ public class AdministrativeMonitorsDecorator extends PageDecorator { return null; } - // Don't show on Manage Jenkins - if (o instanceof ManageJenkinsAction) { - return null; - } - // don't show for some URLs served directly by Jenkins if (o instanceof Jenkins) { String url = a.getRestOfUrl(); diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 904613f74d..7c43695fd4 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -2369,7 +2369,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve public SearchIndexBuilder makeSearchIndex() { SearchIndexBuilder builder = super.makeSearchIndex(); - this.actions.stream().filter(e -> e.getIconFileName() != null).forEach(action -> builder.add(new SearchItem() { + this.actions.stream().filter(e -> !(e.getIconFileName() == null || e.getUrlName() == null)).forEach(action -> builder.add(new SearchItem() { @Override public String getSearchName() { return action.getDisplayName(); diff --git a/test/src/test/java/lib/hudson/ActionsTest.java b/core/src/main/java/jenkins/model/navigation/SearchAction.java similarity index 65% rename from test/src/test/java/lib/hudson/ActionsTest.java rename to core/src/main/java/jenkins/model/navigation/SearchAction.java index 287138d2a3..36a56bda2f 100644 --- a/test/src/test/java/lib/hudson/ActionsTest.java +++ b/core/src/main/java/jenkins/model/navigation/SearchAction.java @@ -1,7 +1,7 @@ /* * The MIT License * - * Copyright (c) 2011, CloudBees, Inc. + * 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 @@ -22,31 +22,29 @@ * THE SOFTWARE. */ -package lib.hudson; +package jenkins.model.navigation; -import static org.junit.Assert.assertNotNull; - -import hudson.model.InvisibleAction; +import hudson.Extension; import hudson.model.RootAction; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.TestExtension; /** - * @author Kohsuke Kawaguchi + * TODO */ -public class ActionsTest { +@Extension(ordinal = 999) +public class SearchAction implements RootAction { - @Rule - public JenkinsRule j = new JenkinsRule(); - - @Test - public void override() throws Exception { - assertNotNull(j.createWebClient().goTo("").getElementById("bravo")); + @Override + public String getIconFileName() { + return "symbol-search"; } - @TestExtension - public static class RootActionImpl extends InvisibleAction implements RootAction { + @Override + public String getDisplayName() { + return "Search"; + } + + @Override + public String getUrlName() { + return null; } } diff --git a/core/src/main/java/jenkins/model/navigation/UserAction.java b/core/src/main/java/jenkins/model/navigation/UserAction.java new file mode 100644 index 0000000000..5900e3d097 --- /dev/null +++ b/core/src/main/java/jenkins/model/navigation/UserAction.java @@ -0,0 +1,96 @@ +/* + * 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.navigation; + +import static hudson.Functions.getAvatar; + +import hudson.Extension; +import hudson.model.Action; +import hudson.model.RootAction; +import hudson.model.User; +import java.util.ArrayList; +import java.util.List; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +/** + * Display the user avatar in the navigation bar. + * Provides a handy jumplist for common user actions. + */ +@Extension(ordinal = -1) +public class UserAction implements RootAction { + + @Override + public String getIconFileName() { + User current = User.current(); + + if (current == null) { + return null; + } + + return getAvatar(current, "96x96"); + } + + @Override + public String getDisplayName() { + User current = User.current(); + + if (current == null) { + return null; + } + + return current.getFullName(); + } + + @Override + public String getUrlName() { + User current = User.current(); + + if (current == null) { + return null; + } + + return current.getUrl(); + } + + @Restricted(NoExternalUse.class) + public User getUser() { + return User.current(); + } + + @Restricted(NoExternalUse.class) + public List getActions() { + User current = User.current(); + + if (User.current() == null) { + return null; + } + + List actions = new ArrayList<>(); + actions.addAll(current.getPropertyActions()); + actions.addAll(current.getTransientActions()); + return actions.stream().filter(e -> e.getIconFileName() != null).toList(); + } +} diff --git a/core/src/main/java/jenkins/views/Header.java b/core/src/main/java/jenkins/views/Header.java index 8418ccb871..083f241340 100644 --- a/core/src/main/java/jenkins/views/Header.java +++ b/core/src/main/java/jenkins/views/Header.java @@ -1,8 +1,17 @@ package jenkins.views; +import hudson.ExtensionComponent; import hudson.ExtensionList; import hudson.ExtensionPoint; +import hudson.model.Action; +import hudson.model.RootAction; +import java.util.Comparator; +import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; +import jenkins.model.Jenkins; +import org.jenkins.ui.icon.IconSpec; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -54,4 +63,28 @@ public abstract class Header implements ExtensionPoint { return header.orElseGet(JenkinsHeader::new); } + /** + * @return a list of {@link Action} to show in the header, defaults to {@link hudson.model.RootAction} extensions + */ + @Restricted(NoExternalUse.class) + public List getActions() { + // There's an issue where new actions (e.g. a new plugin installation) don't appear in the order + // of their ordinal annotation - to work around that we manually sort the list + Map rootActionsOrdinal = ExtensionList.lookup(RootAction.class) + .getComponents() + .stream() + .collect(Collectors.toMap( + c -> c.getInstance().getClass().getName(), + ExtensionComponent::ordinal + )); + + return Jenkins.get() + .getActions() + .stream() + .filter(e -> e.getIconFileName() != null || (e instanceof IconSpec is && is.getIconClassName() != null)) + .sorted(Comparator.comparingDouble( + a -> rootActionsOrdinal.getOrDefault(a.getClass().getName(), Double.MAX_VALUE) + ).reversed()) + .toList(); + } } diff --git a/core/src/main/java/jenkins/views/PartialHeader.java b/core/src/main/java/jenkins/views/PartialHeader.java index 964ccbb3b0..7a19468e6d 100644 --- a/core/src/main/java/jenkins/views/PartialHeader.java +++ b/core/src/main/java/jenkins/views/PartialHeader.java @@ -25,7 +25,7 @@ public abstract class PartialHeader extends Header { * * Increment this number when an incompatible change is made to the header (like the search form API). */ - private static final int compatibilityHeaderVersion = 1; + private static final int compatibilityHeaderVersion = 2; @Override public final boolean isCompatible() { diff --git a/core/src/main/resources/hudson/model/ManageJenkinsAction/index.jelly b/core/src/main/resources/hudson/model/ManageJenkinsAction/index.jelly index eb76bed16c..4b3d408d06 100644 --- a/core/src/main/resources/hudson/model/ManageJenkinsAction/index.jelly +++ b/core/src/main/resources/hudson/model/ManageJenkinsAction/index.jelly @@ -28,11 +28,6 @@ THE SOFTWARE. - - - - - @@ -52,58 +47,58 @@ THE SOFTWARE.

${category.key.label}

${taskTags!=null and attrs.contextMenu!='false' ? taskTags.addHeader(category.key.label) : null}
- - -
- - - - - - - ${taskTags!=null and attrs.contextMenu!='false' ? it.addContextMenuItem(taskTags, m.urlName, iconSrc, iconXml, m.displayName, m.requiresPOST, m.requiresConfirmation, m.badge, sure) : null} - - - - -
-
${m.displayName}
-
-
-
-
-
- - - -
-
${m.displayName}
-
-
-
-
-
- - - -
-
${m.displayName}
-
-
-
-
-
-
-
-
-
+ + +
+ + + + + + + ${taskTags!=null and attrs.contextMenu!='false' ? it.addContextMenuItem(taskTags, m.urlName, iconSrc, iconXml, m.displayName, m.requiresPOST, m.requiresConfirmation, m.badge, sure) : null} + + + + +
+
${m.displayName}
+
+
+
+
+
+ + + +
+
${m.displayName}
+
+
+
+
+
+ + + +
+
${m.displayName}
+
+
+
+
+
+
+
+
+
diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index f8a0279fe1..9b92c3bce5 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -199,6 +199,8 @@ LabelExpression.LabelLink=Label {1} matches {3,choice,0#no LabelExpression.NoMatch=No agent/cloud matches this label expression. LabelExpression.NoMatch_DidYouMean=No agent/cloud matches this label expression. Did you mean ‘{1}’ instead of ‘{0}’? ManageJenkinsAction.DisplayName=Manage Jenkins +ManageJenkinsAction.notification={0} notification +ManageJenkinsAction.notifications={0} notifications MultiStageTimeSeries.EMPTY_STRING= ParametersDefinitionProperty.BuildButtonText=Build Queue.AllNodesOffline=All nodes of label ‘{0}’ are offline diff --git a/core/src/main/resources/hudson/model/View/sidepanel.jelly b/core/src/main/resources/hudson/model/View/sidepanel.jelly index e174117add..bfdcf80cc0 100644 --- a/core/src/main/resources/hudson/model/View/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/View/sidepanel.jelly @@ -60,7 +60,6 @@ THE SOFTWARE. - diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/loginLink.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/loginLink.jelly index cd989c23f0..ae5fa40935 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/loginLink.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/loginLink.jelly @@ -25,7 +25,4 @@ THE SOFTWARE. - - ${%sign up} - diff --git a/core/src/main/resources/hudson/security/SecurityRealm/loginLink.jelly b/core/src/main/resources/hudson/security/SecurityRealm/loginLink.jelly index 8fb92ed3dd..7d3c1268f4 100644 --- a/core/src/main/resources/hudson/security/SecurityRealm/loginLink.jelly +++ b/core/src/main/resources/hudson/security/SecurityRealm/loginLink.jelly @@ -24,6 +24,12 @@ THE SOFTWARE. --> - - ${%login} + + + ${%signIn} + diff --git a/core/src/main/resources/hudson/security/SecurityRealm/loginLink.properties b/core/src/main/resources/hudson/security/SecurityRealm/loginLink.properties index a02dabb171..f32eb6aaae 100644 --- a/core/src/main/resources/hudson/security/SecurityRealm/loginLink.properties +++ b/core/src/main/resources/hudson/security/SecurityRealm/loginLink.properties @@ -21,3 +21,5 @@ # THE SOFTWARE. login=log in +signIn=Sign in +signInTooltip=Sign in to access and manage your Jenkins jobs diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer.jelly b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer.jelly deleted file mode 100644 index ff40bc5436..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer.jelly +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - -
- - - - -
- - - - - - diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer.properties b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer.properties deleted file mode 100644 index 59c787763b..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer.properties +++ /dev/null @@ -1,2 +0,0 @@ -tooltip=There are {0} active administrative monitors. -tooltipSec=There are {0} active security administrative monitors. diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_bg.properties b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_bg.properties deleted file mode 100644 index 53275bc89b..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_bg.properties +++ /dev/null @@ -1,27 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2017, Alexander Shopov -# -# 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. - -# There are {0} active administrative monitors. -tooltip=\ - В момента има {0} предупреждения. -Manage\ Jenkins=\ - Управление на Jenkins diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_de.properties b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_de.properties deleted file mode 100644 index df9d5a8ab8..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_de.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2017 Daniel Beck and a number of other of contributors -# -# 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. - -Manage\ Jenkins=Jenkins verwalten -tooltip={0,choice,0#Keine Administrator-Warnungen sind|1#{0} Administrator-Warnung ist|1<{0} Administrator-Warnungen sind} aktiv. diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_fr.properties b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_fr.properties deleted file mode 100644 index 870a942ce7..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_fr.properties +++ /dev/null @@ -1,2 +0,0 @@ -tooltip=Il existe {0} moniteurs d''administration activés. -tooltipSec=Il existe {0} moniteurs d''administration de sécurité activés. diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_it.properties b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_it.properties deleted file mode 100644 index 9967613a71..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_it.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Italian localization plugin for Jenkins -# Copyright © 2020 Alessandro Menti -# -# 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. - -Manage\ Jenkins=Gestisci Jenkins -tooltip=Ci sono {0} monitor amministrativi attivi. diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_pl.properties b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_pl.properties deleted file mode 100644 index 963548d361..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_pl.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2016-2017, Damian Szczepanik -# -# 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. -# There are {0} active administrative monitors. -tooltip=Znaleziono {0} aktywnych powiadomień dla administratorów -Manage\ Jenkins=Zarządzaj Jenkinsem diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_pt_BR.properties b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_pt_BR.properties deleted file mode 100644 index 103fb02ed7..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_pt_BR.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors -# -# 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. - -tooltip=Existem {0} monitores administrativos ativos. -tooltipSec=Existem {0} monitores administrativos de segurança ativos. diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_sv_SE.properties b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_sv_SE.properties deleted file mode 100644 index 477e8b1001..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_sv_SE.properties +++ /dev/null @@ -1,2 +0,0 @@ -tooltip=Det finns {0} aktiva administrativa övervakningar. -tooltipSec=Det finns {0} aktiva säkerhetsadministrativa övervakningar. diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_tr.properties b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_tr.properties deleted file mode 100644 index 8447c064c4..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_tr.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2021, Mustafa Ulu -# -# 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. - -Manage\ Jenkins=Jenkins''i Yönet -tooltip={0} adet aktif yönetimsel gösterge var. -tooltipSec={0} adet aktif yönetimsel güvenlik göstergesi var. diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_zh_TW.properties b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_zh_TW.properties deleted file mode 100644 index 8fb68379da..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/footer_zh_TW.properties +++ /dev/null @@ -1,2 +0,0 @@ -tooltip=有 {0} 個啟用中的管理監視器。 -tooltipSec=有 {0} 個啟用中的安全性管理監視器。 diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/resources.css b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/resources.css deleted file mode 100644 index 27540b350d..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/resources.css +++ /dev/null @@ -1,184 +0,0 @@ -.am-container { - display: contents; -} - -.am-button { - position: relative; -} - -.am-button .am-monitor__indicator-mobile { - display: none; - position: absolute; - top: 0.25rem; - right: 0.25rem; - border-radius: 50%; - width: 0.65rem; - height: 0.65rem; - background-color: var(--warning-color); -} -.security-am .am-monitor__indicator-mobile { - background-color: var(--error-color); -} - -.am-button .am-monitor__count { - display: inline-flex; - justify-content: center; - align-items: center; - height: 18px; - min-width: 18px; - - color: #fff; - background-color: var(--warning-color); - font-weight: var(--font-bold-weight); - font-size: var(--font-size-xs); - - border-radius: 16px; -} -.am-button.security-am .am-monitor__count { - color: #fff; - background-color: var(--error-color); -} -.am-container div.am-list { - position: absolute; - top: 48px; - right: 2%; - height: auto; - padding: var(--section-padding); - text-align: left; - display: block; - background-color: var(--background); - box-shadow: var(--dropdown-box-shadow); - border-radius: 15px; - opacity: 0; - z-index: 0; - transform: scale(0); -} - -.am-container.am-hidden div.am-list { - animation: hide-am-list 300ms ease-in 1 normal; -} - -.am-container.visible div.am-list { - opacity: 1; - animation: show-am-list 300ms ease-in 1 normal forwards; - z-index: 1000; -} - -@keyframes show-am-list { - from { - opacity: 0; - visibility: hidden; - transform: translateY(-10px) scale(0.975); - } - to { - opacity: 1; - visibility: visible; - transform: scale(1); - } -} - -@keyframes hide-am-list { - from { - opacity: 1; - visibility: visible; - transform: scale(1); - z-index: 1000; - } - to { - opacity: 0; - visibility: hidden; - transform: translateY(-10px) scale(0.975); - z-index: 1000; - } -} - -.am-container .am-message { - display: block; - line-height: 1.4em; - margin-bottom: 1.4em; -} -.am-container.visible .am-button:after { - background: var(--button-background--hover); -} - -.am-message-list { - padding: 0; - margin: 0; -} - -.am-container .am-message .alert form, -.am-container .am-message .jenkins-alert form { - position: relative; - float: right; - margin: -6px 0 0 0 !important; - gap: 0.5rem; - display: flex; - padding-left: 0.5rem; -} - -.am-container .am-message .alert form span, -.am-container .am-message .jenkins-alert form span { - margin: 0 0 0 4px !important; -} - -.am-container .am-message .alert, -.am-container .am-message .jenkins-alert { - margin-bottom: 0 !important; -} - -.am-container .am-message dl dt::after { - content: ": "; -} - -/* Restore hyperlink style overriden by the page header */ -.am-container .am-list a:link { - display: inline-block; - color: var(--link-color); - text-decoration: underline; - margin-right: 0; - padding: 0; - font-weight: var(--link-font-weight); -} -.am-container .am-list a:visited { - color: var(--link-color); -} -.am-container .am-list a:hover, -.am-container .am-list a:focus, -.am-container .am-list a:active { - color: var(--link-color); - background-color: transparent; - text-decoration: underline; - text-decoration: var(--link-text-decoration--hover); -} - -.am-container .am-list .jenkins-alert-success a { - color: var(--alert-success-text-color); -} - -.am-container .am-list .jenkins-alert-info a { - color: var(--alert-info-text-color); -} - -.am-container .am-list .jenkins-alert-warning a { - color: var(--alert-warning-text-color); -} - -.am-container .am-list .jenkins-alert-danger a { - color: var(--alert-danger-text-color); -} - -@media screen and (max-width: 576px) { - /* Hide non-security monitors on mobile view to avoid messing up the heading */ - #visible-am-container { - display: none; - } -} - -@media screen and (max-width: 768px) { - .am-button .am-monitor__indicator-mobile { - display: block; - } - .am-button .am-monitor__count { - display: none; - } -} diff --git a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/resources.js b/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/resources.js deleted file mode 100644 index 5982e03025..0000000000 --- a/core/src/main/resources/jenkins/management/AdministrativeMonitorsDecorator/resources.js +++ /dev/null @@ -1,128 +0,0 @@ -(function () { - function initializeAmMonitor(amMonitorRoot, options) { - var button = amMonitorRoot.querySelector(".am-button"); - var amList = amMonitorRoot.querySelector(".am-list"); - if (button === null || amList === null) { - return null; - } - - var url = button.getAttribute("data-href"); - - function onClose(e) { - var list = amList; - var el = e.target; - while (el) { - if (el === list) { - return; // clicked in the list - } - el = el.parentElement; - } - close(); - } - - function onEscClose(e) { - var escapeKeyCode = 27; - if (e.keyCode === escapeKeyCode) { - close(); - } - } - - function show() { - if (options.closeAll) { - options.closeAll(); - } - - fetch(url).then((rsp) => { - if (rsp.ok) { - rsp.text().then((responseText) => { - var popupContent = responseText; - amList.innerHTML = popupContent; - amMonitorRoot.classList.add("visible"); - amMonitorRoot.classList.remove("am-hidden"); - document.addEventListener("click", onClose); - document.addEventListener("keydown", onEscClose); - - // Applies all initialization code to the elements within the popup - // Among other things, this sets the CSRF crumb to the forms within - Behaviour.applySubtree(amList); - }); - } - }); - } - - function close() { - if (amMonitorRoot.classList.contains("visible")) { - amMonitorRoot.classList.add("am-hidden"); - } - amMonitorRoot.classList.remove("visible"); - document.removeEventListener("click", onClose); - document.removeEventListener("keydown", onEscClose); - } - - function toggle(e) { - if (amMonitorRoot.classList.contains("visible")) { - close(); - } else { - show(); - } - e.preventDefault(); - } - - function startListeners() { - button.addEventListener("click", toggle); - } - - return { - close: close, - startListeners: startListeners, - }; - } - - document.addEventListener("DOMContentLoaded", function () { - var monitorWidgets; - - function closeAll() { - monitorWidgets.forEach(function (widget) { - widget.close(); - }); - } - - var normalMonitors = initializeAmMonitor( - document.getElementById("visible-am-container"), - { - closeAll: closeAll, - }, - ); - var securityMonitors = initializeAmMonitor( - document.getElementById("visible-sec-am-container"), - { - closeAll: closeAll, - }, - ); - monitorWidgets = [normalMonitors, securityMonitors].filter( - function (widget) { - return widget !== null; - }, - ); - - monitorWidgets.forEach(function (widget) { - widget.startListeners(); - }); - }); -})(); - -document.addEventListener("DOMContentLoaded", function () { - var amContainer = document.getElementById("visible-am-container"); - var amInsertion = document.getElementById("visible-am-insertion"); - - if (amInsertion) { - amInsertion.appendChild(amContainer); - } - - var secAmContainer = document.getElementById("visible-sec-am-container"); - var secAmInsertion = document.getElementById("visible-sec-am-insertion"); - - if (secAmInsertion) { - secAmInsertion.appendChild(secAmContainer); - } -}); diff --git a/core/src/main/resources/jenkins/model/Jenkins/configure.jelly b/core/src/main/resources/jenkins/model/Jenkins/configure.jelly index 91d01c69f5..7b7ce31aed 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/configure.jelly +++ b/core/src/main/resources/jenkins/model/Jenkins/configure.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/jenkins/model/navigation/SearchAction/tooltip.jelly b/core/src/main/resources/jenkins/model/navigation/SearchAction/tooltip.jelly new file mode 100644 index 0000000000..400875cd3d --- /dev/null +++ b/core/src/main/resources/jenkins/model/navigation/SearchAction/tooltip.jelly @@ -0,0 +1,9 @@ + + +
+ + ${%Search} + + +
+
diff --git a/core/src/main/resources/jenkins/model/navigation/UserAction/jumplist.jelly b/core/src/main/resources/jenkins/model/navigation/UserAction/jumplist.jelly new file mode 100644 index 0000000000..6d5138ea03 --- /dev/null +++ b/core/src/main/resources/jenkins/model/navigation/UserAction/jumplist.jelly @@ -0,0 +1,25 @@ + + + + +
+ +
+ ${it.user.fullName} +
+
+ + + + + + + + + + +
\ No newline at end of file diff --git a/core/src/main/resources/jenkins/views/JenkinsHeader/headerContent.jelly b/core/src/main/resources/jenkins/views/JenkinsHeader/headerContent.jelly index 1f22ef5063..941787db6a 100644 --- a/core/src/main/resources/jenkins/views/JenkinsHeader/headerContent.jelly +++ b/core/src/main/resources/jenkins/views/JenkinsHeader/headerContent.jelly @@ -1,8 +1,20 @@ - - + + + +