mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-10-26 19:15:09 +00:00
Refine experimental Run overflow menu (#26524)
This commit is contained in:
1 parent
210527646d
commit
6f384824f4
6 files changed
+60
-39
No files matched your search
@@ -170,6 +170,7 @@ import jenkins.model.SimplePageDecorator;
|
||||
import jenkins.model.details.Detail;
|
||||
import jenkins.model.details.DetailFactory;
|
||||
import jenkins.model.details.DetailGroup;
|
||||
import jenkins.model.menu.Group;
|
||||
import jenkins.telemetry.impl.PasswordMasking;
|
||||
import jenkins.util.SystemProperties;
|
||||
import net.sf.json.JSONObject;
|
||||
@@ -181,6 +182,7 @@ import org.apache.commons.jexl.parser.ASTSizeFunction;
|
||||
import org.apache.commons.jexl.util.Introspector;
|
||||
import org.jenkins.ui.icon.Icon;
|
||||
import org.jenkins.ui.icon.IconSet;
|
||||
import org.jenkins.ui.icon.IconSpec;
|
||||
import org.jvnet.tiger_types.Types;
|
||||
import org.kohsuke.accmod.Restricted;
|
||||
import org.kohsuke.accmod.restrictions.DoNotUse;
|
||||
@@ -2669,7 +2671,10 @@ public class Functions {
|
||||
ModelObjectWithContextMenu.ContextMenu contextMenu = new ModelObjectWithContextMenu.ContextMenu();
|
||||
contextMenu.addAll(actions
|
||||
.stream()
|
||||
.filter(action -> action.getIconFileName() != null)
|
||||
.filter(action ->
|
||||
action.getIconFileName() != null
|
||||
|| (action instanceof IconSpec iconSpec && iconSpec.getIconClassName() != null)
|
||||
).filter(action -> action.getGroup().getOrder() < Group.FIRST_IN_MENU.getOrder())
|
||||
.toList());
|
||||
JSONObject jsonObject = JSONObject.fromObject(contextMenu);
|
||||
jsonObject.put("url", Util.ensureEndsWith(baseUrl, "/"));
|
||||
|
||||
@@ -292,8 +292,17 @@ public interface ModelObjectWithContextMenu extends ModelObject {
|
||||
public ContextMenu from(ModelObjectWithContextMenu self, StaplerRequest2 request, StaplerResponse2 response, String view) throws JellyException, IOException {
|
||||
// Only Runs support getAppBarActions currently
|
||||
if (self instanceof Run) {
|
||||
this.addAll(((Actionable) self).getAppBarActions());
|
||||
return this;
|
||||
boolean menuOnly = Boolean.parseBoolean(request.getParameter("menu-only"));
|
||||
|
||||
List<Action> actions = ((Actionable) self).getAppBarActions().stream()
|
||||
.filter(action ->
|
||||
action.getIconFileName() != null
|
||||
|| (action instanceof IconSpec iconSpec && iconSpec.getIconClassName() != null)
|
||||
)
|
||||
.filter(action -> !menuOnly || action.getGroup().getOrder() >= Group.FIRST_IN_MENU.getOrder())
|
||||
.toList();
|
||||
|
||||
return new ModelObjectWithContextMenu.ContextMenu().addAll(actions);
|
||||
}
|
||||
|
||||
WebApp webApp = WebApp.getCurrent();
|
||||
|
||||
+12
-7
@@ -25,17 +25,22 @@ THE SOFTWARE.
|
||||
<?jelly escape-by-default='true'?>
|
||||
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler">
|
||||
<st:documentation>
|
||||
Generates a strip of controls based on the given actions parameter.
|
||||
Generates a strip of actions based on the given Actionable.
|
||||
|
||||
<st:attribute name="actions">
|
||||
The actions to show.
|
||||
<st:attribute name="it" use="required" type="hudson.model.Actionable">
|
||||
The object to display actions for.
|
||||
</st:attribute>
|
||||
</st:documentation>
|
||||
|
||||
<j:set var="url" value="${h.getNearestAncestorUrl(request2, it)}/" />
|
||||
<j:set var="actions" value="${attrs.it.appBarActions}" />
|
||||
|
||||
<j:if test="${actions != null}">
|
||||
<button id="auto-overflow"
|
||||
class="jenkins-button"
|
||||
<button data-type="auto-overflow"
|
||||
class="jenkins-button jenkins-jumplist-link"
|
||||
tooltip="${%More actions}"
|
||||
data-href="${url}"
|
||||
data-jumplist-type="menu"
|
||||
data-testid="app-bar-overflow-button"
|
||||
type="button">
|
||||
<div class="jenkins-overflow-button__ellipsis">
|
||||
@@ -44,9 +49,9 @@ THE SOFTWARE.
|
||||
<span />
|
||||
</div>
|
||||
</button>
|
||||
<j:set var="url" value="${h.getNearestAncestorUrl(request2,it.object)}"/>
|
||||
|
||||
<template>
|
||||
${h.convertActionsToJson(url, actions)}
|
||||
${h.convertActionsToJson(url, attrs.it.appBarActions)}
|
||||
</template>
|
||||
</j:if>
|
||||
</j:jelly>
|
||||
@@ -68,7 +68,7 @@ THE SOFTWARE.
|
||||
</div>
|
||||
|
||||
<div class="app-build-bar__controls">
|
||||
<l:app-bar-controls actions="${it.object.appBarActions}" />
|
||||
<l:actions it="${it.object}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,38 +2,34 @@ import behaviorShim from "@/util/behavior-shim";
|
||||
import Utils from "@/components/dropdowns/utils";
|
||||
import Templates from "@/components/dropdowns/templates";
|
||||
|
||||
/**
|
||||
* Generates inline actions and an overflow menu if necessary.
|
||||
*/
|
||||
function init() {
|
||||
behaviorShim.specify("#auto-overflow", "-dropdowns-", 1000, (element) => {
|
||||
const template = JSON.parse(element.nextSibling.content.textContent);
|
||||
const appBarItems = Utils.mapChildrenItemsToDropdownItems(
|
||||
template.items.filter((e) => e.group.order <= 2),
|
||||
);
|
||||
const overflowItems = Utils.mapChildrenItemsToDropdownItems(
|
||||
template.items.filter((e) => e.group.order > 2),
|
||||
);
|
||||
|
||||
// Append top-level items to the app bar
|
||||
appBarItems.forEach((item, index) => {
|
||||
// Only the first button in an app bar should have an icon
|
||||
if (index > 0) {
|
||||
item.icon = null;
|
||||
item.iconXml = null;
|
||||
}
|
||||
element.parentNode.insertBefore(
|
||||
Templates.menuItem(item, "jenkins-button", template.url),
|
||||
element,
|
||||
behaviorShim.specify(
|
||||
"[data-type='auto-overflow']",
|
||||
"-dropdowns-",
|
||||
1000,
|
||||
(element) => {
|
||||
const template = JSON.parse(element.nextSibling.content.textContent);
|
||||
const topLevelActions = Utils.mapChildrenItemsToDropdownItems(
|
||||
template.items.filter((e) => e.group.order <= 2),
|
||||
);
|
||||
});
|
||||
|
||||
// Add any additional items as an overflow menu
|
||||
if (overflowItems.length > 0) {
|
||||
Utils.generateDropdown(element, (instance) => {
|
||||
instance.setContent(
|
||||
Utils.generateDropdownItems(overflowItems, false, template.url),
|
||||
// Append top-level items next to the overflow menu
|
||||
topLevelActions.forEach((item, index) => {
|
||||
// Only the first button in an app bar should have an icon
|
||||
if (index > 0) {
|
||||
item.icon = null;
|
||||
item.iconXml = null;
|
||||
}
|
||||
element.parentNode.insertBefore(
|
||||
Templates.menuItem(item, "jenkins-button", template.url),
|
||||
element,
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export default { init };
|
||||
@@ -95,7 +95,13 @@ function generateDropdowns() {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(Path.combinePath(href, jumplistType))
|
||||
// If requested, only return menu actions rather than top-level app bar actions
|
||||
let query = "";
|
||||
if (element.dataset.jumplistType === "menu") {
|
||||
query = "?menu-only=true";
|
||||
}
|
||||
|
||||
fetch(Path.combinePath(href, jumplistType) + query)
|
||||
.then((response) => response.json())
|
||||
.then((json) =>
|
||||
instance.setContent(
|
||||
|
||||
Reference in new issue
Block a user