@sapui5/sap.suite.ui.commons 1.144.0 → 1.145.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/package.json +1 -1
  2. package/src/sap/suite/ui/commons/.library +1 -1
  3. package/src/sap/suite/ui/commons/AriaProperties.js +1 -1
  4. package/src/sap/suite/ui/commons/CalculationBuilder.js +8 -4
  5. package/src/sap/suite/ui/commons/CalculationBuilderExpression.js +1 -1
  6. package/src/sap/suite/ui/commons/CalculationBuilderFunction.js +1 -1
  7. package/src/sap/suite/ui/commons/CalculationBuilderGroup.js +1 -1
  8. package/src/sap/suite/ui/commons/CalculationBuilderItem.js +1 -1
  9. package/src/sap/suite/ui/commons/CalculationBuilderValidationResult.js +1 -1
  10. package/src/sap/suite/ui/commons/CalculationBuilderVariable.js +1 -1
  11. package/src/sap/suite/ui/commons/CloudFilePicker.js +1 -3
  12. package/src/sap/suite/ui/commons/MicroProcessFlow.js +1 -1
  13. package/src/sap/suite/ui/commons/MicroProcessFlowItem.js +1 -1
  14. package/src/sap/suite/ui/commons/Timeline.js +9 -0
  15. package/src/sap/suite/ui/commons/TimelineNavigator.js +37 -5
  16. package/src/sap/suite/ui/commons/TimelineRenderer.js +3 -3
  17. package/src/sap/suite/ui/commons/collaboration/BaseHelperService.js +0 -1
  18. package/src/sap/suite/ui/commons/collaboration/CollaborationHelper.js +0 -3
  19. package/src/sap/suite/ui/commons/collaboration/CollaborationManagerService.js +0 -1
  20. package/src/sap/suite/ui/commons/collaboration/ContactHelper.js +7 -0
  21. package/src/sap/suite/ui/commons/collaboration/ContactPopover.fragment.xml +4 -1
  22. package/src/sap/suite/ui/commons/collaboration/MinimalContactPopover.fragment.xml +2 -1
  23. package/src/sap/suite/ui/commons/collaboration/TeamsHelperService.js +0 -6
  24. package/src/sap/suite/ui/commons/collaboration/channels/MessageChannel.js +0 -2
  25. package/src/sap/suite/ui/commons/collaboration/flpplugins/msplugin/Component-preload.js +1 -1
  26. package/src/sap/suite/ui/commons/collaboration/flpplugins/msplugin/Component.js +1 -2
  27. package/src/sap/suite/ui/commons/flexibility/changeHandler/PropertyChangeMapper.js +1 -1
  28. package/src/sap/suite/ui/commons/imageeditor/CropCustomShapeHistoryItem.js +1 -1
  29. package/src/sap/suite/ui/commons/imageeditor/CropEllipseHistoryItem.js +1 -1
  30. package/src/sap/suite/ui/commons/imageeditor/CropRectangleHistoryItem.js +1 -1
  31. package/src/sap/suite/ui/commons/imageeditor/CustomSizeItem.js +1 -1
  32. package/src/sap/suite/ui/commons/imageeditor/FilterHistoryItem.js +1 -1
  33. package/src/sap/suite/ui/commons/imageeditor/FlipHistoryItem.js +1 -1
  34. package/src/sap/suite/ui/commons/imageeditor/HistoryItem.js +1 -1
  35. package/src/sap/suite/ui/commons/imageeditor/ImageEditor.js +1 -1
  36. package/src/sap/suite/ui/commons/imageeditor/ImageEditorContainer.js +1 -1
  37. package/src/sap/suite/ui/commons/imageeditor/ImageEditorResponsiveContainer.js +1 -1
  38. package/src/sap/suite/ui/commons/imageeditor/ResizeHistoryItem.js +1 -1
  39. package/src/sap/suite/ui/commons/imageeditor/RotateHistoryItem.js +1 -1
  40. package/src/sap/suite/ui/commons/library.js +25 -1
  41. package/src/sap/suite/ui/commons/messagebundle.properties +16 -9
  42. package/src/sap/suite/ui/commons/messagebundle_ar.properties +17 -2
  43. package/src/sap/suite/ui/commons/messagebundle_bg.properties +18 -3
  44. package/src/sap/suite/ui/commons/messagebundle_ca.properties +18 -3
  45. package/src/sap/suite/ui/commons/messagebundle_cnr.properties +18 -3
  46. package/src/sap/suite/ui/commons/messagebundle_cs.properties +17 -2
  47. package/src/sap/suite/ui/commons/messagebundle_cy.properties +17 -2
  48. package/src/sap/suite/ui/commons/messagebundle_da.properties +17 -2
  49. package/src/sap/suite/ui/commons/messagebundle_de.properties +30 -15
  50. package/src/sap/suite/ui/commons/messagebundle_el.properties +18 -3
  51. package/src/sap/suite/ui/commons/messagebundle_en.properties +18 -3
  52. package/src/sap/suite/ui/commons/messagebundle_en_GB.properties +18 -3
  53. package/src/sap/suite/ui/commons/messagebundle_en_US_saprigi.properties +2 -0
  54. package/src/sap/suite/ui/commons/messagebundle_es.properties +18 -3
  55. package/src/sap/suite/ui/commons/messagebundle_es_MX.properties +18 -3
  56. package/src/sap/suite/ui/commons/messagebundle_et.properties +17 -2
  57. package/src/sap/suite/ui/commons/messagebundle_fi.properties +17 -2
  58. package/src/sap/suite/ui/commons/messagebundle_fr.properties +26 -11
  59. package/src/sap/suite/ui/commons/messagebundle_fr_CA.properties +17 -2
  60. package/src/sap/suite/ui/commons/messagebundle_hi.properties +18 -3
  61. package/src/sap/suite/ui/commons/messagebundle_hr.properties +18 -3
  62. package/src/sap/suite/ui/commons/messagebundle_hu.properties +17 -2
  63. package/src/sap/suite/ui/commons/messagebundle_id.properties +18 -3
  64. package/src/sap/suite/ui/commons/messagebundle_it.properties +17 -2
  65. package/src/sap/suite/ui/commons/messagebundle_iw.properties +17 -2
  66. package/src/sap/suite/ui/commons/messagebundle_ja.properties +18 -3
  67. package/src/sap/suite/ui/commons/messagebundle_kk.properties +17 -2
  68. package/src/sap/suite/ui/commons/messagebundle_ko.properties +17 -2
  69. package/src/sap/suite/ui/commons/messagebundle_lt.properties +17 -2
  70. package/src/sap/suite/ui/commons/messagebundle_lv.properties +18 -3
  71. package/src/sap/suite/ui/commons/messagebundle_mk.properties +17 -2
  72. package/src/sap/suite/ui/commons/messagebundle_ms.properties +17 -2
  73. package/src/sap/suite/ui/commons/messagebundle_nl.properties +17 -2
  74. package/src/sap/suite/ui/commons/messagebundle_no.properties +18 -3
  75. package/src/sap/suite/ui/commons/messagebundle_pl.properties +17 -2
  76. package/src/sap/suite/ui/commons/messagebundle_pt.properties +17 -2
  77. package/src/sap/suite/ui/commons/messagebundle_pt_PT.properties +17 -2
  78. package/src/sap/suite/ui/commons/messagebundle_ro.properties +17 -2
  79. package/src/sap/suite/ui/commons/messagebundle_ru.properties +17 -2
  80. package/src/sap/suite/ui/commons/messagebundle_sh.properties +18 -3
  81. package/src/sap/suite/ui/commons/messagebundle_sk.properties +17 -2
  82. package/src/sap/suite/ui/commons/messagebundle_sl.properties +17 -2
  83. package/src/sap/suite/ui/commons/messagebundle_sr.properties +18 -3
  84. package/src/sap/suite/ui/commons/messagebundle_sv.properties +17 -2
  85. package/src/sap/suite/ui/commons/messagebundle_th.properties +18 -3
  86. package/src/sap/suite/ui/commons/messagebundle_tr.properties +17 -2
  87. package/src/sap/suite/ui/commons/messagebundle_uk.properties +17 -2
  88. package/src/sap/suite/ui/commons/messagebundle_vi.properties +19 -4
  89. package/src/sap/suite/ui/commons/messagebundle_zh_CN.properties +17 -2
  90. package/src/sap/suite/ui/commons/messagebundle_zh_TW.properties +19 -4
  91. package/src/sap/suite/ui/commons/networkgraph/Graph.js +45 -16
  92. package/src/sap/suite/ui/commons/networkgraph/KeyboardNavigator.js +45 -4
  93. package/src/sap/suite/ui/commons/networkgraph/Line.js +52 -0
  94. package/src/sap/suite/ui/commons/networkgraph/Node.js +289 -86
  95. package/src/sap/suite/ui/commons/networkgraph/util/DependencyLayoutHelper.js +143 -70
  96. package/src/sap/suite/ui/commons/networkgraph/util/PortManager.js +2 -3
  97. package/src/sap/suite/ui/commons/statusindicator/Circle.js +1 -1
  98. package/src/sap/suite/ui/commons/statusindicator/CustomShape.js +1 -1
  99. package/src/sap/suite/ui/commons/statusindicator/DiscreteThreshold.js +1 -1
  100. package/src/sap/suite/ui/commons/statusindicator/FillingOption.js +1 -1
  101. package/src/sap/suite/ui/commons/statusindicator/LibraryShape.js +1 -1
  102. package/src/sap/suite/ui/commons/statusindicator/Path.js +1 -1
  103. package/src/sap/suite/ui/commons/statusindicator/PropertyThreshold.js +1 -1
  104. package/src/sap/suite/ui/commons/statusindicator/Rectangle.js +1 -1
  105. package/src/sap/suite/ui/commons/statusindicator/Shape.js +1 -1
  106. package/src/sap/suite/ui/commons/statusindicator/ShapeGroup.js +1 -1
  107. package/src/sap/suite/ui/commons/statusindicator/SimpleShape.js +1 -1
  108. package/src/sap/suite/ui/commons/statusindicator/StatusIndicator.js +1 -1
  109. package/src/sap/suite/ui/commons/taccount/TAccount.js +1 -1
  110. package/src/sap/suite/ui/commons/taccount/TAccountGroup.js +1 -1
  111. package/src/sap/suite/ui/commons/taccount/TAccountItem.js +1 -1
  112. package/src/sap/suite/ui/commons/taccount/TAccountItemProperty.js +1 -1
  113. package/src/sap/suite/ui/commons/taccount/TAccountPanel.js +1 -1
  114. package/src/sap/suite/ui/commons/themes/base/NetworkLine.less +26 -5
@@ -187,13 +187,15 @@ sap.ui.define([
187
187
  };
188
188
 
189
189
  KeyboardNavigator.prototype.onkeyup = function(oEvent) {
190
- if (oEvent.keyCode === KeyCodes.SPACE){
191
- this._handleEnter();
192
- if (this._oGraph.getFocusDomRef() === document.activeElement) {
190
+ if (oEvent.keyCode === KeyCodes.SPACE){
191
+ this._handleEnter();
192
+ if (this._oGraph.getFocusDomRef() === document.activeElement) {
193
193
  oEvent.stopPropagation();
194
194
  oEvent.preventDefault();
195
- }
196
195
  }
196
+ } else if (oEvent.keyCode === KeyCodes.DELETE || oEvent.keyCode === KeyCodes.BACKSPACE) {
197
+ this._handleDelete(oEvent);
198
+ }
197
199
  };
198
200
 
199
201
  KeyboardNavigator.prototype.onsapenter = function (oEvent) {
@@ -331,6 +333,45 @@ sap.ui.define([
331
333
  }
332
334
  };
333
335
 
336
+ KeyboardNavigator.prototype._handleDelete = function (oEvent) {
337
+ // Only handle delete when DnD is enabled
338
+ if (!this._oGraph._isDnDEnabled()) {
339
+ return;
340
+ }
341
+
342
+ var oFocus = this.getFocus();
343
+ if (!oFocus) {
344
+ return;
345
+ }
346
+
347
+ var oItem = oFocus.item;
348
+
349
+ // Only allow delete for Node and Line, not Group
350
+ if (oItem instanceof Node || oItem instanceof Line) {
351
+ oItem.setSelected(false);
352
+
353
+ // Clear focus before delete to prevent stale reference issues
354
+ if (this._oGraph._oFocus && this._oGraph._oFocus.item === oItem) {
355
+ this._oGraph._oFocus = null;
356
+ }
357
+
358
+ // Fire the itemDeleted event on the graph
359
+ var bExecuteDefault = this._oGraph.fireEvent("itemDeleted", {
360
+ item: oItem
361
+ }, true);
362
+
363
+ if (bExecuteDefault) {
364
+ oEvent.stopPropagation();
365
+ oEvent.preventDefault();
366
+ }
367
+
368
+ // Restore focus after a small timeout (to let any rerender settle)
369
+ setTimeout(function () {
370
+ this._oGraph.setFocus(oFocus)
371
+ }.bind(this), 0);
372
+ }
373
+ };
374
+
334
375
  KeyboardNavigator.prototype._handleTab = function (oEvent, sDirection) {
335
376
  var oResourceBundle = CoreLib.getResourceBundleFor("sap.suite.ui.commons");
336
377
  this._oWrapperDom.setAttribute("aria-live","assertive");
@@ -905,6 +905,11 @@ sap.ui.define([
905
905
 
906
906
  aSentenceParts.push(oResourceBundle.getText('NETWORK_GRAPH_ACCESSIBILITY_TOGGLE_STATE'));
907
907
 
908
+ const iIncomingConnectors = this.getFromNode().getChildLines().length;
909
+ if (iIncomingConnectors > 1) {
910
+ aSentenceParts.push(oResourceBundle.getText('NETWORK_GRAPH_LINE_NAVIGATION_ARROW_KEYS', [sFromNodeText]));
911
+ }
912
+
908
913
  aSentenceParts.push(oResourceBundle.getText('NETWORK_GRAPH_LINE_NAVIGATION_TAB_TO_TARGET', [sToNodeText]));
909
914
  aSentenceParts.push(oResourceBundle.getText('NETWORK_GRAPH_LINE_NAVIGATION_SHIFT_TAB_TO_SOURCE', [sFromNodeText]));
910
915
 
@@ -1106,10 +1111,39 @@ sap.ui.define([
1106
1111
  $line.on("mouseout", function (oEvent) {
1107
1112
  this._mouseOut();
1108
1113
  }.bind(this));
1114
+
1115
+ // Setup events for text box
1116
+ var oParent = this.getParent();
1117
+ if (oParent) {
1118
+ var sLineId = this._getLineId();
1119
+ var $textBox = oParent.$("line-texts").find('[data-line-id="' + sLineId + '"]');
1120
+
1121
+ $textBox.on("click", function (oEvent) {
1122
+ this._click({
1123
+ ctrlKey: oEvent.ctrlKey,
1124
+ clientX: oEvent.clientX,
1125
+ clientY: oEvent.clientY
1126
+ });
1127
+ }.bind(this));
1128
+
1129
+ $textBox.on("mouseover", function (oEvent) {
1130
+ this._mouseOver();
1131
+ }.bind(this));
1132
+
1133
+ $textBox.on("mouseout", function (oEvent) {
1134
+ this._mouseOut();
1135
+ }.bind(this));
1136
+ }
1109
1137
  };
1110
1138
 
1111
1139
  Line.prototype._mouseOut = function () {
1112
1140
  this.$().removeClass(this.HIGHLIGHT_CLASS);
1141
+ // Remove highlight class from text box using data-line-id attribute
1142
+ var oParent = this.getParent();
1143
+ if (oParent) {
1144
+ var sLineId = this._getLineId();
1145
+ oParent.$("line-texts").find('[data-line-id="' + sLineId + '"]').removeClass(this.HIGHLIGHT_CLASS);
1146
+ }
1113
1147
  if (!this.getSelected()) {
1114
1148
  this._setStatusColors("");
1115
1149
  }
@@ -1121,6 +1155,12 @@ sap.ui.define([
1121
1155
  if (!this.getSelected() && bExecuteDefault) {
1122
1156
  this._setStatusColors("Hover");
1123
1157
  this.$().addClass(this.HIGHLIGHT_CLASS);
1158
+ // Add highlight class to text box using data-line-id attribute
1159
+ var oParent = this.getParent();
1160
+ if (oParent) {
1161
+ var sLineId = this._getLineId();
1162
+ oParent.$("line-texts").find('[data-line-id="' + sLineId + '"]').addClass(this.HIGHLIGHT_CLASS);
1163
+ }
1124
1164
  }
1125
1165
  };
1126
1166
 
@@ -1434,6 +1474,18 @@ sap.ui.define([
1434
1474
  if (bFocus) {
1435
1475
  this._renderFocusWrapper();
1436
1476
  }
1477
+
1478
+ // Apply focus class to text box for blue border
1479
+ var oParent = this.getParent();
1480
+ if (oParent) {
1481
+ var sLineId = this._getLineId();
1482
+ var $textBox = oParent.$("line-texts").find('[data-line-id="' + sLineId + '"]');
1483
+ if (bFocus) {
1484
+ $textBox.addClass(this.FOCUS_CLASS);
1485
+ } else {
1486
+ $textBox.removeClass(this.FOCUS_CLASS);
1487
+ }
1488
+ }
1437
1489
  };
1438
1490
 
1439
1491
  Line.prototype._isEndPosition = function () {
@@ -24,20 +24,24 @@ sap.ui.define([
24
24
  "sap/base/Log",
25
25
  "./util/DragDropManager",
26
26
  "./util/PortManager",
27
- "./util/CreateConnectionPopover"
28
- ], function(jQuery, library, ElementBase, ElementAttribute, IconPool, Device, encodeXML, sanitizeHTML, CheckBox, Text, NodeRenderer, Core, Theming, CoreLib, Utils, Log, DragDropManager, PortManager, CreateConnectionPopover) {
27
+ "./util/CreateConnectionPopover",
28
+ "sap/m/Menu",
29
+ "sap/m/MenuItem"
30
+ ], function(jQuery, library, ElementBase, ElementAttribute, IconPool, Device, encodeXML, sanitizeHTML, CheckBox, Text, NodeRenderer, Core, Theming, CoreLib, Utils, Log, DragDropManager, PortManager, CreateConnectionPopover, Menu, MenuItem) {
29
31
  "use strict";
30
32
 
31
33
  var Shape = library.networkgraph.NodeShape,
32
34
  ActionButtonPosition = library.networkgraph.ActionButtonPosition,
33
35
  HeaderCheckboxState = library.networkgraph.HeaderCheckboxState,
34
- SemanticColorType = library.SemanticColorType;
36
+ SemanticColorType = library.SemanticColorType,
37
+ NodePorts = library.networkgraph.NodePorts;
35
38
 
36
39
  var HEADER_SIZE = 32,
37
40
  TITLE_OFFSET = 5,
38
41
  MIN_WIDTH = 160,
39
42
  MAX_ACTION_BUTTONS = 4,
40
- ACTION_BUTTONS_OFFSET = -34;
43
+ ACTION_BUTTONS_OFFSET = -34,
44
+ MAX_VISIBLE_BUTTONS_ON_TOP = 3;
41
45
 
42
46
  var Size = {
43
47
  Circle: {
@@ -96,6 +100,21 @@ sap.ui.define([
96
100
 
97
101
  var oResourceBundle = CoreLib.getResourceBundleFor("sap.suite.ui.commons");
98
102
 
103
+ // Register BusinessSuiteInAppSymbols font for custom icons
104
+ // IconPool.registerFont({
105
+ // fontFamily: "BusinessSuiteInAppSymbols",
106
+ // collectionName: "BusinessSuiteInAppSymbols",
107
+ // fontURI: sap.ui.require.toUrl("sap/ushell/themes/base/fonts/")
108
+ // });
109
+
110
+ // register TNT icon font
111
+ IconPool.registerFont({
112
+ collectionName: "tnt",
113
+ fontFamily: "SAP-icons-TNT",
114
+ fontURI: sap.ui.require.toUrl("sap/tnt/themes/base/fonts"),
115
+ lazy: false
116
+ });
117
+
99
118
  var Status = library.networkgraph.ElementStatus;
100
119
  var oStatusIconMap = {
101
120
  [Status.Success]: 'sap-icon://sys-enter-2',
@@ -280,6 +299,27 @@ sap.ui.define([
280
299
  */
281
300
  nodeTitleBackground: {
282
301
  type: "boolean", group: "Appearance", defaultValue: false
302
+ },
303
+ /**
304
+ * Determines the port configuration for this node. When set, it overrides the graph-level nodePorts setting.
305
+ * If not set (defaults to None), the graph-level setting is used.
306
+ * Ports are available only when the layout algorithm is set to "NoopLayout", and when the drag and drop is enabled.
307
+ * @public
308
+ * @since 1.145
309
+ */
310
+ nodePorts: {
311
+ type: "sap.suite.ui.commons.networkgraph.NodePorts", group: "Behavior"
312
+ },
313
+ /**
314
+ * Determines whether the 'Create Connection' action button is displayed on this node.
315
+ * When set, it overrides the graph-level showCreateConnectionButton setting.
316
+ * If set to default (true), the graph-level setting is used.
317
+ * The button is used to create connections between nodes as an accessible alternative to node ports.
318
+ * @public
319
+ * @since 1.145
320
+ */
321
+ showCreateConnectionButton: {
322
+ type: "boolean", group: "Behavior", defaultValue: true
283
323
  }
284
324
  },
285
325
  aggregations: {
@@ -651,8 +691,9 @@ sap.ui.define([
651
691
  $right = this.$("rightdivbuttons"),
652
692
  $left = this.$("leftdivbuttons"),
653
693
  oGraph = this.getParent(),
654
- bShouldShowPortButton = oGraph._supportsNodePorts(),
655
- bShowButtonsOnTop = oGraph && oGraph.getEnableDragAndDrop() && oGraph.getNodePorts() !== "None";
694
+ bShouldShowPortButton = this._showCreateConnectionButton() && oGraph?.getEnableDragAndDrop(),
695
+ oLayoutAlgorithm = oGraph.getLayoutAlgorithm(),
696
+ bShowButtonsOnTop = oGraph._isNoopLayout() && oLayoutAlgorithm.getEnableOptimizedLineAlgorithm();
656
697
 
657
698
  // Force re-render if buttons haven't been rendered yet
658
699
  if (bShow && !this._bActionButtonsRendered) {
@@ -664,28 +705,36 @@ sap.ui.define([
664
705
  var iButtonTop = 0,
665
706
  iButtonRight = 0,
666
707
  iButtonLeft = 0,
667
- $defaultWrapper = bShowButtonsOnTop ? $top : $right;
708
+ $defaultWrapper = bShowButtonsOnTop ? $top : $right,
709
+ aOverflowButtons = [];
710
+
711
+ // When buttons are on top, only count enabled buttons for overflow calculation
712
+ // Disabled buttons are hidden with display:none so shouldn't count toward limit
668
713
 
669
714
  if (this.getShowExpandButton()) {
670
- this._appendActionButton({
715
+ var oExpandButtonConfig = {
671
716
  "class": "sapSuiteUiCommonsNetworkNodeActionCollapseIcon",
672
717
  icon: this._getExpandIcon(true),
673
718
  enable: this._hasVisibleChildren(),
674
719
  title: this._getExpandStateTitle(),
675
720
  id: this._getDomId("actionCollapse"),
676
721
  click: this._expandClick.bind(this)
677
- }, $defaultWrapper);
722
+ };
678
723
 
679
- if (bShowButtonsOnTop) {
680
- iButtonTop++;
681
- } else {
682
- iButtonRight++;
724
+ this._appendActionButton(oExpandButtonConfig, $defaultWrapper);
725
+ // Only increment counter if button is enabled (disabled buttons are hidden)
726
+ if (oExpandButtonConfig.enable) {
727
+ if (bShowButtonsOnTop) {
728
+ iButtonTop++;
729
+ } else {
730
+ iButtonRight++;
731
+ }
683
732
  }
684
733
  }
685
734
 
686
735
  if (this.getShowDetailButton()) {
687
736
  var sNodeTitle = this.getTitle();
688
- this._appendActionButton({
737
+ var oDetailButtonConfig = {
689
738
  icon: "sap-icon://menu2",
690
739
  enable: this._hasDetailData() || (sNodeTitle ? sNodeTitle : this.getAltText()),
691
740
  id: this._getDomId("actionDetail"),
@@ -693,10 +742,35 @@ sap.ui.define([
693
742
  click: function(evt) {
694
743
  this._detailClick(evt.target);
695
744
  }.bind(this)
696
- }, $defaultWrapper);
745
+ };
746
+
747
+ this._appendActionButton(oDetailButtonConfig, $defaultWrapper);
697
748
  if (document.getElementById(this._getDomId("actionDetail"))) {
698
749
  document.getElementById(this._getDomId("actionDetail")).setAttribute("aria-haspopup", "dialog");
699
750
  }
751
+ // Only increment counter if button is enabled (disabled buttons are hidden)
752
+ if (oDetailButtonConfig.enable) {
753
+ if (bShowButtonsOnTop) {
754
+ iButtonTop++;
755
+ } else {
756
+ iButtonRight++;
757
+ }
758
+ }
759
+ }
760
+
761
+ // Add port action button if nodePorts is not "None"
762
+ if (bShouldShowPortButton) {
763
+ var oPortButtonConfig = {
764
+ icon: "sap-icon://tnt/item-flow",
765
+ enable: true,
766
+ title: oResourceBundle.getText("NETWORK_GRAPH_CREATE_CONNECTION"),
767
+ id: this._getDomId("actionPorts"),
768
+ click: function(evt) {
769
+ this._showConnectionPopover(evt);
770
+ }.bind(this)
771
+ };
772
+
773
+ this._appendActionButton(oPortButtonConfig, $defaultWrapper);
700
774
  if (bShowButtonsOnTop) {
701
775
  iButtonTop++;
702
776
  } else {
@@ -705,7 +779,7 @@ sap.ui.define([
705
779
  }
706
780
 
707
781
  if (this.getShowActionLinksButton()) {
708
- this._appendActionButton({
782
+ var oLinksButtonConfig = {
709
783
  icon: "sap-icon://chain-link",
710
784
  enable: this._hasActionLinks(),
711
785
  title: oResourceBundle.getText("NETWORK_GRAPH_NODE_LINKS"),
@@ -713,40 +787,38 @@ sap.ui.define([
713
787
  click: function(evt) {
714
788
  this._linksClick(evt.target);
715
789
  }.bind(this)
716
- }, $defaultWrapper);
717
- if (document.getElementById(this._getDomId("actionLinks"))) {
718
- document.getElementById(this._getDomId("actionLinks")).setAttribute("aria-haspopup", "dialog");
719
- }
720
- if (bShowButtonsOnTop) {
721
- iButtonTop++;
722
- } else {
723
- iButtonRight++;
724
- }
725
- }
790
+ };
726
791
 
727
- // Add port action button if nodePorts is not "None"
728
- if (bShouldShowPortButton) {
729
- this._appendActionButton({
730
- icon: "sap-icon://sys-add",
731
- enable: true,
732
- title: "Create Connection",
733
- id: this._getDomId("actionPorts"),
734
- click: function(evt) {
735
- this._showConnectionPopover(evt);
736
- }.bind(this)
737
- }, $defaultWrapper);
738
- if (bShowButtonsOnTop) {
739
- iButtonTop++;
792
+ // Overflow logic: button goes to overflow if we've already placed 3 enabled buttons
793
+ if (bShowButtonsOnTop && iButtonTop >= MAX_VISIBLE_BUTTONS_ON_TOP && oLinksButtonConfig.enable) {
794
+ aOverflowButtons.push(oLinksButtonConfig);
740
795
  } else {
741
- iButtonRight++;
796
+ this._appendActionButton(oLinksButtonConfig, $defaultWrapper);
797
+ if (document.getElementById(this._getDomId("actionLinks"))) {
798
+ document.getElementById(this._getDomId("actionLinks")).setAttribute("aria-haspopup", "dialog");
799
+ }
800
+ // Only increment counter if button is enabled (disabled buttons are hidden)
801
+ if (oLinksButtonConfig.enable) {
802
+ if (bShowButtonsOnTop) {
803
+ iButtonTop++;
804
+ } else {
805
+ iButtonRight++;
806
+ }
807
+ }
742
808
  }
743
809
  }
744
810
 
745
811
  for (var i = 0; (iButtonTop + iButtonRight + iButtonLeft) < (MAX_ACTION_BUTTONS * 3) && i < this.getActionButtons().length; i++) {
746
- (function(oButton) { // eslint-disable-line
747
- var sPosition = oButton.getPosition();
748
- var iIndex, $wrapper;
812
+ (function(oButton) { // eslint-disable-line
813
+ var sPosition = oButton.getPosition();
814
+ var iIndex, $wrapper;
749
815
 
816
+ // When buttons are shown on top, custom action buttons always go to top position
817
+ if (bShowButtonsOnTop) {
818
+ sPosition = "Top";
819
+ iIndex = iButtonTop;
820
+ $wrapper = $top;
821
+ } else {
750
822
  if (sPosition === ActionButtonPosition.Right) {
751
823
  iIndex = iButtonRight;
752
824
  $wrapper = $right;
@@ -771,35 +843,62 @@ sap.ui.define([
771
843
  $wrapper = $right;
772
844
  }
773
845
  }
846
+ }
774
847
 
775
- that._appendActionButton({
776
- icon: oButton.getIcon(),
777
- enable: oButton.getEnabled(),
778
- title: oButton.getTitle(),
779
- id: oButton.getId(),
780
- click: function(evt) {
781
- oButton.firePress({
782
- buttonElement: evt.target
783
- });
784
- // Restore focus after a small timeout (to let any rerender settle)
785
- setTimeout(function () {
786
- if (oButton && oButton.getDomRef()) {
787
- that.getParent().setFocus({item:oButton.getParent(), button: oButton.getDomRef()});
788
- }
789
- }, 0);
790
- }
791
- }, $wrapper);
848
+ var oButtonConfig = {
849
+ icon: oButton.getIcon(),
850
+ enable: oButton.getEnabled(),
851
+ title: oButton.getTitle(),
852
+ id: oButton.getId(),
853
+ click: function(evt) {
854
+ oButton.firePress({
855
+ buttonElement: evt.target
856
+ });
857
+ // Restore focus after a small timeout (to let any rerender settle)
858
+ setTimeout(function () {
859
+ if (oButton && oButton.getDomRef()) {
860
+ that.getParent().setFocus({item:oButton.getParent(), button: oButton.getDomRef()});
861
+ }
862
+ }, 0);
863
+ }
864
+ };
792
865
 
793
- // Increment the correct counter
794
- if (sPosition === ActionButtonPosition.Right) {
795
- iButtonRight++;
796
- } else if (sPosition === ActionButtonPosition.Left) {
797
- iButtonLeft++;
798
- } else {
799
- iButtonTop++;
866
+ // Apply overflow logic only when buttons are shown on top
867
+ // Custom buttons go to overflow if we've already placed 3 enabled buttons
868
+ if (bShowButtonsOnTop && iButtonTop >= MAX_VISIBLE_BUTTONS_ON_TOP && oButtonConfig.enable) {
869
+ aOverflowButtons.push(oButtonConfig);
870
+ } else {
871
+ that._appendActionButton(oButtonConfig, $wrapper);
872
+ // Only increment counter if button is enabled (disabled buttons are hidden)
873
+ if (oButtonConfig.enable) {
874
+ // Increment the correct counter
875
+ if (bShowButtonsOnTop) {
876
+ iButtonTop++;
877
+ } else if (sPosition === ActionButtonPosition.Right) {
878
+ iButtonRight++;
879
+ } else if (sPosition === ActionButtonPosition.Left) {
880
+ iButtonLeft++;
881
+ } else {
882
+ iButtonTop++;
883
+ }
800
884
  }
801
- })(this.getActionButtons()[i]);
885
+ }
886
+ })(this.getActionButtons()[i], i);
887
+ }
888
+
889
+ // Add overflow button if there are overflow items
890
+ if (bShowButtonsOnTop && aOverflowButtons.length > 0) {
891
+ this._appendActionButton({
892
+ icon: "sap-icon://overflow",
893
+ enable: true,
894
+ title: "More Actions",
895
+ id: this._getDomId("actionOverflow"),
896
+ click: function(evt) {
897
+ this._showOverflowPopover(evt.target, aOverflowButtons);
898
+ }.bind(this)
899
+ }, $top);
802
900
  }
901
+
803
902
  this._bActionButtonsRendered = true;
804
903
  }
805
904
 
@@ -1935,21 +2034,21 @@ sap.ui.define([
1935
2034
 
1936
2035
  //Recursive Traversal ensures all shared parents of collapsed descendants have their action buttons re-rendered correctly.
1937
2036
  Node.prototype._invalidateSharedParents = function(oNode, oOrigin = oNode, oVisited = new Set()) {
1938
- if (oVisited.has(oNode)) {
1939
- return;
1940
- }
1941
- oVisited.add(oNode);
1942
-
1943
- oNode.getParentNodes().forEach(parent => {
1944
- if (parent !== oOrigin) {
1945
- parent._bActionButtonsRendered = false;
2037
+ if (oVisited.has(oNode)) {
2038
+ return;
1946
2039
  }
1947
- });
2040
+ oVisited.add(oNode);
1948
2041
 
1949
- oNode.getChildNodes().forEach(oChild => {
1950
- this._invalidateSharedParents(oChild, oOrigin, oVisited);
1951
- });
1952
- }
2042
+ oNode.getParentNodes().forEach(parent => {
2043
+ if (parent !== oOrigin) {
2044
+ parent._bActionButtonsRendered = false;
2045
+ }
2046
+ });
2047
+
2048
+ oNode.getChildNodes().forEach(oChild => {
2049
+ this._invalidateSharedParents(oChild, oOrigin, oVisited);
2050
+ });
2051
+ }
1953
2052
 
1954
2053
  Node.prototype._setTextHeight = function($el, iMaxLines) {
1955
2054
  if ($el[0] && iMaxLines > 0) {
@@ -3941,8 +4040,7 @@ sap.ui.define([
3941
4040
  * @private
3942
4041
  */
3943
4042
  Node.prototype._hasPortActionButton = function() {
3944
- var oGraph = this.getParent();
3945
- return oGraph && oGraph.getNodePorts() !== "None" && oGraph._supportsNodePorts();
4043
+ return this._showCreateConnectionButton();
3946
4044
  };
3947
4045
 
3948
4046
  /**
@@ -3951,7 +4049,7 @@ sap.ui.define([
3951
4049
  */
3952
4050
  Node.prototype._togglePortsOnNode = function() {
3953
4051
  // Check if the layout algorithm supports node ports
3954
- if (this.getParent()?._supportsNodePorts()) {
4052
+ if (this._supportsNodePortsForNode()) {
3955
4053
  // Ports are only available for supported layout algorithms
3956
4054
  this._addPortsToNode(true);
3957
4055
  }
@@ -3965,8 +4063,9 @@ sap.ui.define([
3965
4063
  Node.prototype._addPortsToNode = function (bTriggerNode) {
3966
4064
  var oGraph = this.getParent();
3967
4065
 
3968
- // Check if ports are enabled for this graph
3969
- if (!oGraph || oGraph.getNodePorts() === "None") {
4066
+ // Check if ports are enabled for this node
4067
+ if (!oGraph || this._getNodePorts() === "None") {
4068
+ PortManager.removeAllPorts();
3970
4069
  return;
3971
4070
  }
3972
4071
 
@@ -3984,6 +4083,59 @@ sap.ui.define([
3984
4083
  PortManager.addPortsToNode(this, true);
3985
4084
  };
3986
4085
 
4086
+ /**
4087
+ * Uses node-level setting if explicitly set, otherwise it reverts to the graph-level setting.
4088
+ * If the node-level property is set to any value (including None), it takes precedence over the graph-level setting.
4089
+ * @returns {string} The effective nodePorts value
4090
+ * @private
4091
+ */
4092
+ Node.prototype._getNodePorts = function() {
4093
+ // Check if the property was explicitly set on the node (stored in mProperties)
4094
+ var mProperties = this.mProperties;
4095
+ if (mProperties && mProperties.hasOwnProperty("nodePorts")) {
4096
+ var sNodePorts = this.getNodePorts();
4097
+ // Validate that the value is one of the valid NodePorts enum values
4098
+ var bIsValidValue = Object.values(NodePorts).indexOf(sNodePorts) !== -1;
4099
+ if (bIsValidValue) {
4100
+ // Use node-level setting if it's a valid enum value
4101
+ return sNodePorts;
4102
+ }
4103
+ }
4104
+ // Otherwise, fall back to graph-level setting
4105
+ var oGraph = this.getParent();
4106
+ return oGraph ? oGraph.getNodePorts() : NodePorts.None;
4107
+ };
4108
+
4109
+ /**
4110
+ * Gets the effective showCreateConnectionButton setting for this node.
4111
+ * Uses node-level setting if explicitly set, otherwise falls back to graph-level setting.
4112
+ * @returns {boolean} The effective showCreateConnectionButton value
4113
+ * @private
4114
+ */
4115
+ Node.prototype._showCreateConnectionButton = function() {
4116
+ // Check if the property was explicitly set on the node (stored in mProperties)
4117
+ var mProperties = this.mProperties;
4118
+ if (mProperties && mProperties.hasOwnProperty("showCreateConnectionButton")) {
4119
+ return this.getShowCreateConnectionButton();
4120
+ }
4121
+ // Otherwise, fall back to graph-level setting
4122
+ var oGraph = this.getParent();
4123
+ return oGraph ? oGraph.getShowCreateConnectionButton() : true;
4124
+ };
4125
+
4126
+ /**
4127
+ * Checks if node ports are supported for this node based on node-level or graph-level settings.
4128
+ * @returns {boolean} True if node ports are supported
4129
+ * @private
4130
+ */
4131
+ Node.prototype._supportsNodePortsForNode = function() {
4132
+ var oGraph = this.getParent();
4133
+ if (!oGraph) {
4134
+ return false;
4135
+ }
4136
+ return this._getNodePorts() !== "None" && oGraph.getEnableDragAndDrop();
4137
+ };
4138
+
3987
4139
  /**
3988
4140
  * Shows the connection popover instead of toggling ports.
3989
4141
  * @param {Event} oEvent - The click event from the action button
@@ -4009,5 +4161,56 @@ sap.ui.define([
4009
4161
  });
4010
4162
  };
4011
4163
 
4164
+ /**
4165
+ * Shows the overflow menu with additional action buttons.
4166
+ * @param {sap.ui.core.Control} oControl The control to open the menu next to
4167
+ * @param {Array} aOverflowButtons Array of button configurations to display in the overflow
4168
+ * @private
4169
+ */
4170
+ Node.prototype._showOverflowPopover = function(oControl, aOverflowButtons) {
4171
+ var that = this;
4172
+
4173
+ // Filter out disabled buttons (same behavior as _appendActionButton which hides disabled buttons)
4174
+ var aEnabledButtons = aOverflowButtons.filter(function(oButtonConfig) {
4175
+ return oButtonConfig.enable !== false;
4176
+ });
4177
+
4178
+ // If no enabled buttons, don't show the menu
4179
+ if (aEnabledButtons.length === 0) {
4180
+ return;
4181
+ }
4182
+
4183
+ // Create menu items for each enabled overflow item
4184
+ var aMenuItems = aEnabledButtons.map(function(oButtonConfig) {
4185
+ return new MenuItem({
4186
+ id: oButtonConfig.id ? oButtonConfig.id + "-overflow" : undefined,
4187
+ text: oButtonConfig.title,
4188
+ icon: oButtonConfig.icon,
4189
+ customData: [new sap.ui.core.CustomData({
4190
+ key: "buttonConfig",
4191
+ value: oButtonConfig
4192
+ })]
4193
+ });
4194
+ });
4195
+
4196
+ // Create the menu
4197
+ var oMenu = new Menu({
4198
+ items: aMenuItems,
4199
+ itemSelected: function(oEvent) {
4200
+ var oItem = oEvent.getParameter("item");
4201
+ var oButtonConfig = oItem.data("buttonConfig");
4202
+ if (oButtonConfig && oButtonConfig.click) {
4203
+ // Call the click handler with the overflow button as the target (not the menu item)
4204
+ oButtonConfig.click({ target: oControl });
4205
+ }
4206
+ },
4207
+ closed: function() {
4208
+ oMenu.destroy();
4209
+ }
4210
+ });
4211
+
4212
+ oMenu.openBy(oControl);
4213
+ };
4214
+
4012
4215
  return Node;
4013
4216
  });