@sapui5/sap.suite.ui.commons 1.145.0 → 1.146.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 (110) 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 +28 -3
  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/CalculationBuilderInput.js +11 -0
  9. package/src/sap/suite/ui/commons/CalculationBuilderItem.js +1 -1
  10. package/src/sap/suite/ui/commons/CalculationBuilderValidationResult.js +1 -1
  11. package/src/sap/suite/ui/commons/CalculationBuilderVariable.js +1 -1
  12. package/src/sap/suite/ui/commons/CloudFilePicker.js +1 -1
  13. package/src/sap/suite/ui/commons/ControlProxy.js +7 -4
  14. package/src/sap/suite/ui/commons/MicroProcessFlow.js +1 -1
  15. package/src/sap/suite/ui/commons/MicroProcessFlowItem.js +1 -1
  16. package/src/sap/suite/ui/commons/ProcessFlow.js +79 -75
  17. package/src/sap/suite/ui/commons/ProcessFlowRenderer.js +3 -0
  18. package/src/sap/suite/ui/commons/collaboration/ContactHelper.js +5 -1
  19. package/src/sap/suite/ui/commons/collaboration/ContactPopover.fragment.xml +3 -3
  20. package/src/sap/suite/ui/commons/collaboration/MinimalContactPopover.fragment.xml +8 -6
  21. package/src/sap/suite/ui/commons/collaboration/ServiceContainer.js +12 -2
  22. package/src/sap/suite/ui/commons/flexibility/changeHandler/PropertyChangeMapper.js +1 -1
  23. package/src/sap/suite/ui/commons/imageeditor/CropCustomShapeHistoryItem.js +1 -1
  24. package/src/sap/suite/ui/commons/imageeditor/CropEllipseHistoryItem.js +1 -1
  25. package/src/sap/suite/ui/commons/imageeditor/CropRectangleHistoryItem.js +1 -1
  26. package/src/sap/suite/ui/commons/imageeditor/CustomSizeItem.js +1 -1
  27. package/src/sap/suite/ui/commons/imageeditor/FilterHistoryItem.js +1 -1
  28. package/src/sap/suite/ui/commons/imageeditor/FlipHistoryItem.js +1 -1
  29. package/src/sap/suite/ui/commons/imageeditor/HistoryItem.js +1 -1
  30. package/src/sap/suite/ui/commons/imageeditor/ImageEditor.js +1 -1
  31. package/src/sap/suite/ui/commons/imageeditor/ImageEditorContainer.js +1 -1
  32. package/src/sap/suite/ui/commons/imageeditor/ImageEditorResponsiveContainer.js +9 -6
  33. package/src/sap/suite/ui/commons/imageeditor/ResizeHistoryItem.js +1 -1
  34. package/src/sap/suite/ui/commons/imageeditor/RotateHistoryItem.js +1 -1
  35. package/src/sap/suite/ui/commons/library.js +1 -1
  36. package/src/sap/suite/ui/commons/messagebundle.properties +4 -0
  37. package/src/sap/suite/ui/commons/messagebundle_ar.properties +11 -5
  38. package/src/sap/suite/ui/commons/messagebundle_bg.properties +11 -5
  39. package/src/sap/suite/ui/commons/messagebundle_ca.properties +10 -4
  40. package/src/sap/suite/ui/commons/messagebundle_cnr.properties +11 -5
  41. package/src/sap/suite/ui/commons/messagebundle_cs.properties +7 -1
  42. package/src/sap/suite/ui/commons/messagebundle_cy.properties +11 -5
  43. package/src/sap/suite/ui/commons/messagebundle_da.properties +10 -4
  44. package/src/sap/suite/ui/commons/messagebundle_de.properties +8 -2
  45. package/src/sap/suite/ui/commons/messagebundle_el.properties +11 -5
  46. package/src/sap/suite/ui/commons/messagebundle_en.properties +11 -5
  47. package/src/sap/suite/ui/commons/messagebundle_en_GB.properties +11 -5
  48. package/src/sap/suite/ui/commons/messagebundle_en_US_saprigi.properties +9 -5
  49. package/src/sap/suite/ui/commons/messagebundle_es.properties +11 -5
  50. package/src/sap/suite/ui/commons/messagebundle_es_MX.properties +10 -4
  51. package/src/sap/suite/ui/commons/messagebundle_et.properties +6 -0
  52. package/src/sap/suite/ui/commons/messagebundle_fi.properties +10 -4
  53. package/src/sap/suite/ui/commons/messagebundle_fr.properties +11 -5
  54. package/src/sap/suite/ui/commons/messagebundle_fr_CA.properties +11 -5
  55. package/src/sap/suite/ui/commons/messagebundle_hi.properties +11 -5
  56. package/src/sap/suite/ui/commons/messagebundle_hr.properties +10 -4
  57. package/src/sap/suite/ui/commons/messagebundle_hu.properties +9 -3
  58. package/src/sap/suite/ui/commons/messagebundle_id.properties +12 -6
  59. package/src/sap/suite/ui/commons/messagebundle_it.properties +11 -5
  60. package/src/sap/suite/ui/commons/messagebundle_iw.properties +11 -5
  61. package/src/sap/suite/ui/commons/messagebundle_ja.properties +9 -3
  62. package/src/sap/suite/ui/commons/messagebundle_kk.properties +10 -4
  63. package/src/sap/suite/ui/commons/messagebundle_ko.properties +10 -4
  64. package/src/sap/suite/ui/commons/messagebundle_lt.properties +11 -5
  65. package/src/sap/suite/ui/commons/messagebundle_lv.properties +11 -5
  66. package/src/sap/suite/ui/commons/messagebundle_mk.properties +8 -2
  67. package/src/sap/suite/ui/commons/messagebundle_ms.properties +11 -5
  68. package/src/sap/suite/ui/commons/messagebundle_nl.properties +8 -2
  69. package/src/sap/suite/ui/commons/messagebundle_no.properties +10 -4
  70. package/src/sap/suite/ui/commons/messagebundle_pl.properties +11 -5
  71. package/src/sap/suite/ui/commons/messagebundle_pt.properties +11 -5
  72. package/src/sap/suite/ui/commons/messagebundle_pt_PT.properties +11 -5
  73. package/src/sap/suite/ui/commons/messagebundle_ro.properties +11 -5
  74. package/src/sap/suite/ui/commons/messagebundle_ru.properties +12 -6
  75. package/src/sap/suite/ui/commons/messagebundle_sh.properties +11 -5
  76. package/src/sap/suite/ui/commons/messagebundle_sk.properties +10 -4
  77. package/src/sap/suite/ui/commons/messagebundle_sl.properties +10 -4
  78. package/src/sap/suite/ui/commons/messagebundle_sr.properties +11 -5
  79. package/src/sap/suite/ui/commons/messagebundle_sv.properties +10 -4
  80. package/src/sap/suite/ui/commons/messagebundle_th.properties +11 -5
  81. package/src/sap/suite/ui/commons/messagebundle_tr.properties +8 -2
  82. package/src/sap/suite/ui/commons/messagebundle_uk.properties +14 -8
  83. package/src/sap/suite/ui/commons/messagebundle_vi.properties +11 -5
  84. package/src/sap/suite/ui/commons/messagebundle_zh_CN.properties +11 -5
  85. package/src/sap/suite/ui/commons/messagebundle_zh_TW.properties +11 -5
  86. package/src/sap/suite/ui/commons/networkgraph/Graph.js +11 -13
  87. package/src/sap/suite/ui/commons/networkgraph/Line.js +105 -11
  88. package/src/sap/suite/ui/commons/networkgraph/Utils.js +239 -10
  89. package/src/sap/suite/ui/commons/networkgraph/layout/NoopLayout.js +55 -8
  90. package/src/sap/suite/ui/commons/networkgraph/util/DependencyLayoutHelper.js +18 -9
  91. package/src/sap/suite/ui/commons/networkgraph/util/DragDropManager.js +52 -50
  92. package/src/sap/suite/ui/commons/networkgraph/util/PortManager.js +12 -3
  93. package/src/sap/suite/ui/commons/statusindicator/Circle.js +1 -1
  94. package/src/sap/suite/ui/commons/statusindicator/CustomShape.js +1 -1
  95. package/src/sap/suite/ui/commons/statusindicator/DiscreteThreshold.js +1 -1
  96. package/src/sap/suite/ui/commons/statusindicator/FillingOption.js +1 -1
  97. package/src/sap/suite/ui/commons/statusindicator/LibraryShape.js +1 -1
  98. package/src/sap/suite/ui/commons/statusindicator/Path.js +1 -1
  99. package/src/sap/suite/ui/commons/statusindicator/PropertyThreshold.js +1 -1
  100. package/src/sap/suite/ui/commons/statusindicator/Rectangle.js +1 -1
  101. package/src/sap/suite/ui/commons/statusindicator/Shape.js +1 -1
  102. package/src/sap/suite/ui/commons/statusindicator/ShapeGroup.js +1 -1
  103. package/src/sap/suite/ui/commons/statusindicator/SimpleShape.js +1 -1
  104. package/src/sap/suite/ui/commons/statusindicator/StatusIndicator.js +1 -1
  105. package/src/sap/suite/ui/commons/taccount/TAccount.js +1 -1
  106. package/src/sap/suite/ui/commons/taccount/TAccountGroup.js +1 -1
  107. package/src/sap/suite/ui/commons/taccount/TAccountItem.js +1 -1
  108. package/src/sap/suite/ui/commons/taccount/TAccountItemProperty.js +1 -1
  109. package/src/sap/suite/ui/commons/taccount/TAccountPanel.js +1 -1
  110. package/src/sap/suite/ui/commons/windowmessages/CollaborationMessageConsumer.js +3 -3
@@ -5,7 +5,7 @@
5
5
 
6
6
  */
7
7
 
8
- sap.ui.define([], function () {
8
+ sap.ui.define(["sap/base/Log"], function (Log) {
9
9
  "use strict";
10
10
 
11
11
  /**
@@ -73,15 +73,244 @@ sap.ui.define([], function () {
73
73
  * @returns {function} throttled function.
74
74
  */
75
75
  Utils.throttle = (mainFunction, delay) => {
76
- return (...args) => {
77
- if (timeFlag === null) {
78
- mainFunction(...args);
79
- timeFlag = setTimeout(() => {
80
- timeFlag = null;
81
- }, delay);
82
- }
83
- };
84
- };
76
+ return (...args) => {
77
+ if (timeFlag === null) {
78
+ mainFunction(...args);
79
+ timeFlag = setTimeout(() => {
80
+ timeFlag = null;
81
+ }, delay);
82
+ }
83
+ };
84
+ };
85
+
86
+ /**
87
+ * Helper function to convert CSS outline to border for drag image elements.
88
+ * This is needed because some browsers don't capture outline in drag images.
89
+ *
90
+ * @param {HTMLElement} oElement - The DOM element to apply border to
91
+ * @param {CSSStyleDeclaration} oComputedStyle - The computed style of the element
92
+ * @param {string} [sBorderProperty="border"] - The CSS border property to set ("border", "borderBottom", etc.)
93
+ * @private
94
+ */
95
+ var _applyOutlineAsBorder = function (oElement, oComputedStyle, sBorderProperty) {
96
+ var sOutlineWidth = oComputedStyle.outlineWidth;
97
+ if (sOutlineWidth && sOutlineWidth !== "0px") {
98
+ var sBorderValue = sOutlineWidth + " " + oComputedStyle.outlineStyle + " " + oComputedStyle.outlineColor;
99
+ oElement.style[sBorderProperty || "border"] = sBorderValue;
100
+ oElement.style.outline = "none";
101
+ }
102
+ };
103
+
104
+ /**
105
+ * Clones the inner div element and applies basic styles for drag image.
106
+ *
107
+ * @param {HTMLElement} oInnerDiv - Inner div element to clone
108
+ * @returns {HTMLElement} The cloned and styled node
109
+ * @private
110
+ */
111
+ var _cloneAndStyleNode = function (oInnerDiv) {
112
+ var oClonedNode = oInnerDiv.cloneNode(true);
113
+ var oComputedStyle = window.getComputedStyle(oInnerDiv);
114
+
115
+ // Apply computed styles to ensure the clone looks identical
116
+ oClonedNode.style.width = oComputedStyle.width;
117
+ oClonedNode.style.height = oComputedStyle.height;
118
+ oClonedNode.style.position = "absolute";
119
+ oClonedNode.style.top = "-9999px";
120
+ oClonedNode.style.left = "-9999px";
121
+ oClonedNode.style.pointerEvents = "none";
122
+
123
+ // Convert outline to border for the drag image
124
+ _applyOutlineAsBorder(oClonedNode, oComputedStyle);
125
+
126
+ // Retain border-radius for rounded corners
127
+ var sBorderRadius = oComputedStyle.borderRadius;
128
+ if (sBorderRadius && sBorderRadius !== "0px") {
129
+ oClonedNode.style.borderRadius = sBorderRadius;
130
+ }
131
+
132
+ // Retain background color
133
+ var sBackgroundColor = oComputedStyle.backgroundColor;
134
+ if (sBackgroundColor) {
135
+ oClonedNode.style.backgroundColor = sBackgroundColor;
136
+ }
137
+
138
+ return oClonedNode;
139
+ };
140
+
141
+ /**
142
+ * Processes header element styling in the cloned node.
143
+ *
144
+ * @param {HTMLElement} oClonedNode - The cloned node to process
145
+ * @param {HTMLElement} oInnerDiv - Original inner div element
146
+ * @private
147
+ */
148
+ var _processHeaderElement = function (oClonedNode, oInnerDiv) {
149
+ var oOriginalHeader = oInnerDiv.querySelector(".sapSuiteUiCommonsNetworkGraphDivHeader");
150
+ if (!oOriginalHeader) {
151
+ return;
152
+ }
153
+
154
+ var oHeaderComputedStyle = window.getComputedStyle(oOriginalHeader);
155
+ var oHeaderElement = oClonedNode.querySelector(".sapSuiteUiCommonsNetworkGraphDivHeader");
156
+
157
+ if (!oHeaderElement) {
158
+ return;
159
+ }
160
+
161
+ // Retain header background color
162
+ if (oHeaderComputedStyle.backgroundColor) {
163
+ oHeaderElement.style.backgroundColor = oHeaderComputedStyle.backgroundColor;
164
+ }
165
+
166
+ // Convert header outline to border
167
+ _applyOutlineAsBorder(oHeaderElement, oHeaderComputedStyle, "borderBottom");
168
+
169
+ // Process separate header color wrapper if it exists (skip if combined class)
170
+ if (!oHeaderElement.classList.contains("sapSuiteUiCommonsNetworkGraphDivHeaderColor")) {
171
+ var oOriginalHeaderColor = oInnerDiv.querySelector(".sapSuiteUiCommonsNetworkGraphDivHeaderColor");
172
+ if (oOriginalHeaderColor) {
173
+ var oHeaderColorComputedStyle = window.getComputedStyle(oOriginalHeaderColor);
174
+ var oHeaderColorElement = oHeaderElement.querySelector(".sapSuiteUiCommonsNetworkGraphDivHeaderColor");
175
+
176
+ if (oHeaderColorElement) {
177
+ // Retain border
178
+ if (oHeaderColorComputedStyle.border && oHeaderColorComputedStyle.border !== "0px none rgb(0, 0, 0)") {
179
+ oHeaderColorElement.style.border = oHeaderColorComputedStyle.border;
180
+ }
181
+
182
+ // Retain border-radius
183
+ if (oHeaderColorComputedStyle.borderRadius && oHeaderColorComputedStyle.borderRadius !== "0px") {
184
+ oHeaderColorElement.style.borderRadius = oHeaderColorComputedStyle.borderRadius;
185
+ }
186
+
187
+ // Retain background color
188
+ if (oHeaderColorComputedStyle.backgroundColor) {
189
+ oHeaderColorElement.style.backgroundColor = oHeaderColorComputedStyle.backgroundColor;
190
+ }
191
+
192
+ // Retain color
193
+ if (oHeaderColorComputedStyle.color) {
194
+ oHeaderColorElement.style.color = oHeaderColorComputedStyle.color;
195
+ }
196
+ }
197
+ }
198
+ }
199
+ };
200
+
201
+ /**
202
+ * Creates a custom drag image for the node that includes borders, border-radius, and background colors.
203
+ * This is necessary because the default browser drag image doesn't capture CSS outline properties for few browsers e.g. Chrome.
204
+ *
205
+ * @param {sap.suite.ui.commons.networkgraph.Node} oNode - The node being dragged
206
+ * @param {Event} oBrowserEvent - The native browser drag event
207
+ * @returns {HTMLElement|null} The cloned node attached to DOM, or null if creation failed. Caller is responsible for cleanup.
208
+ */
209
+ Utils.createCustomDragImage = function (oNode, oBrowserEvent) {
210
+ if (!oNode || !oBrowserEvent || !oBrowserEvent.dataTransfer) {
211
+ return null;
212
+ }
213
+
214
+ // Get the graph instance to check the ghost image mode
215
+ var oGraph = oNode.getParent();
216
+ if (!oGraph) {
217
+ return null;
218
+ }
219
+
220
+ try {
221
+ var oDomRef = oNode.getDomRef();
222
+ if (!oDomRef) {
223
+ return null;
224
+ }
225
+
226
+ var oInnerDiv = oDomRef.querySelector(".sapSuiteUiCommonsNetworkGraphDivInner");
227
+ if (!oInnerDiv) {
228
+ return null;
229
+ }
230
+
231
+ // Clone and apply basic styles
232
+ var oClonedNode = _cloneAndStyleNode(oInnerDiv);
233
+
234
+ // Process header element styling
235
+ _processHeaderElement(oClonedNode, oInnerDiv);
236
+
237
+ // Attach to DOM temporarily
238
+ document.body.appendChild(oClonedNode);
239
+
240
+ // Set drag image with correct offset
241
+ var oRect = oInnerDiv.getBoundingClientRect();
242
+ var iOffsetX = oBrowserEvent.clientX - oRect.left;
243
+ var iOffsetY = oBrowserEvent.clientY - oRect.top;
244
+ oBrowserEvent.dataTransfer.setDragImage(oClonedNode, iOffsetX, iOffsetY);
245
+
246
+ // Return the cloned node for cleanup by caller
247
+ return oClonedNode;
248
+ } catch (oError) {
249
+ Log.warning("Utils: Failed to create custom drag image", oError);
250
+ return null;
251
+ }
252
+ };
253
+
254
+ /**
255
+ * Retains the scroll position of the graph after DOM operations.
256
+ * This method ensures that the viewport remains stable after operations like
257
+ * drag-drop, connection creation, or other DOM manipulations.
258
+ *
259
+ * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The graph control
260
+ * @param {number} scrollLeft - The horizontal scroll position to maintain
261
+ * @param {number} scrollTop - The vertical scroll position to maintain
262
+ */
263
+ Utils.retainScrollPosition = function (oGraph, scrollLeft, scrollTop) {
264
+ if (!oGraph || !oGraph.$scroller || !oGraph.$scroller[0]) {
265
+ return;
266
+ }
267
+
268
+ const scrollerElement = oGraph.$scroller[0];
269
+
270
+ // Use requestAnimationFrame for better performance and timing
271
+ requestAnimationFrame(() => {
272
+ try {
273
+ scrollerElement.scrollLeft = scrollLeft;
274
+ scrollerElement.scrollTop = scrollTop;
275
+
276
+ // Fallback verification - ensure the scroll position was actually set
277
+ if (Math.abs(scrollerElement.scrollLeft - scrollLeft) > 1 ||
278
+ Math.abs(scrollerElement.scrollTop - scrollTop) > 1) {
279
+
280
+ // If the scroll position wasn't set correctly, try again after DOM updates
281
+ setTimeout(() => {
282
+ scrollerElement.scrollLeft = scrollLeft;
283
+ scrollerElement.scrollTop = scrollTop;
284
+ }, 10);
285
+ }
286
+ } catch (error) {
287
+ Log.error("retainScrollPosition: Error setting scroll position - " + error.message, "sap.suite.ui.commons.networkgraph.Utils");
288
+ }
289
+ });
290
+ };
291
+
292
+ /**
293
+ * Preserves the scroll position of the graph by scheduling restoration after DOM updates.
294
+ * This is a convenience wrapper that handles the setTimeout + restoration logic.
295
+ *
296
+ * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The graph control
297
+ * @param {number} scrollLeft - The horizontal scroll position to restore
298
+ * @param {number} scrollTop - The vertical scroll position to restore
299
+ * @param {number} [iDelay=0] - Delay in milliseconds before restoring scroll position
300
+ * @public
301
+ */
302
+ Utils.preserveScrollPosition = function (oGraph, scrollLeft, scrollTop, iDelay) {
303
+ if (!oGraph || !oGraph.$scroller || !oGraph.$scroller[0]) {
304
+ return;
305
+ }
306
+
307
+ const delay = typeof iDelay === "number" ? iDelay : 0;
308
+
309
+ // Schedule restoration after DOM updates
310
+ setTimeout(() => {
311
+ Utils.retainScrollPosition(oGraph, scrollLeft, scrollTop);
312
+ }, delay);
313
+ };
85
314
 
86
315
  return Utils;
87
316
  }, true);
@@ -9,11 +9,13 @@ sap.ui.define([
9
9
  "sap/suite/ui/commons/library",
10
10
  "./LayoutAlgorithm",
11
11
  "./LayoutTask",
12
- "../util/ConnectionPathUtils"
13
- ], function (library, LayoutAlgorithm, LayoutTask, ConnectionPathUtils) {
12
+ "../util/ConnectionPathUtils",
13
+ "../util/DependencyLayoutHelper"
14
+ ], function (library, LayoutAlgorithm, LayoutTask, ConnectionPathUtils, DependencyLayoutHelper) {
14
15
  "use strict";
15
16
 
16
- var LayoutRenderType = library.networkgraph.LayoutRenderType;
17
+ var oLayoutRenderType = library.networkgraph.LayoutRenderType,
18
+ oComponentArrangement = library.networkgraph.ComponentArrangement;
17
19
 
18
20
  /**
19
21
  * Constructor for a new NoopLayout.
@@ -37,9 +39,17 @@ sap.ui.define([
37
39
  * Enables advanced line routing algorithm that creates orthogonal bends along the pathfinding process for line creation.
38
40
  *
39
41
  * @public
40
- * @since 1.144
41
42
  */
42
- enableOptimizedLineAlgorithm: { type: "boolean", group: "Behavior", defaultValue: false }
43
+ enableOptimizedLineAlgorithm: { type: "boolean", group: "Behavior", defaultValue: false },
44
+
45
+ /**
46
+ * Defines how separate connected components should be arranged in the graph.
47
+ * Components can be arranged either horizontally (side-by-side) or vertically (stacked).
48
+ *
49
+ * @since 1.146
50
+ * @public
51
+ */
52
+ componentArrangement: { type: "sap.suite.ui.commons.networkgraph.ComponentArrangement", group: "Behavior", defaultValue: oComponentArrangement.Horizontal }
43
53
  }
44
54
  }
45
55
  });
@@ -54,11 +64,14 @@ sap.ui.define([
54
64
  * @public
55
65
  */
56
66
  NoopLayout.prototype.getLayoutRenderType = function () {
57
- return LayoutRenderType.LayeredWithGroups;
67
+ return oLayoutRenderType.LayeredWithGroups;
58
68
  };
59
69
 
60
70
  /**
61
71
  * Executes the layout algorithm.
72
+ * Automatically calculates initial positions for unpositioned nodes using DependencyLayoutHelper,
73
+ * then normalizes line coordinates.
74
+ *
62
75
  * @returns {sap.suite.ui.commons.networkgraph.layout.LayoutTask} Task to get the layout calculated.
63
76
  * @public
64
77
  */
@@ -76,6 +89,19 @@ sap.ui.define([
76
89
  return;
77
90
  }
78
91
 
92
+ // Check if positioning should be calculated
93
+ // Note: DependencyLayoutHelper only repositions nodes without valid coordinates
94
+ if (this._shouldCalculatePositions(oGraph)) {
95
+ DependencyLayoutHelper.calculatePositions(oGraph, {
96
+ componentArrangement: this.getComponentArrangement()
97
+ });
98
+
99
+ // Reset flag after calculation
100
+ if (oGraph._bTriggerLayoutCalculation) {
101
+ oGraph._bTriggerLayoutCalculation = false;
102
+ }
103
+ }
104
+
79
105
  if (this.getEnableOptimizedLineAlgorithm()) {
80
106
  // Use the ConnectionPathUtils utility to normalize lines
81
107
  ConnectionPathUtils.normalizeLines(oGraph, {
@@ -86,11 +112,32 @@ sap.ui.define([
86
112
  this._normalizeLines();
87
113
  }
88
114
 
89
-
90
-
91
115
  fnResolve();
92
116
  }.bind(this));
93
117
  };
94
118
 
119
+ /**
120
+ * Determines if initial positions should be calculated.
121
+ * Only returns true if there are unpositioned nodes or if explicitly triggered.
122
+ *
123
+ * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The graph instance
124
+ * @returns {boolean} True if positions should be calculated
125
+ * @private
126
+ */
127
+ NoopLayout.prototype._shouldCalculatePositions = function (oGraph) {
128
+ // Check if explicit trigger flag is set
129
+ // Even when triggered, DependencyLayoutHelper only affects unpositioned nodes
130
+ if (oGraph._bTriggerLayoutCalculation) {
131
+ return true;
132
+ }
133
+
134
+ // Auto-detect unpositioned nodes (coordinates 0,0 or undefined)
135
+ return oGraph.getNodes().some(function (oNode) {
136
+ var fX = oNode.getX();
137
+ var fY = oNode.getY();
138
+ return (fX === 0 || fX === undefined) && (fY === 0 || fY === undefined);
139
+ });
140
+ };
141
+
95
142
  return NoopLayout;
96
143
  });
@@ -7,8 +7,8 @@
7
7
  sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (library, Log) {
8
8
  "use strict";
9
9
 
10
- const ConnectionType = library.networkgraph.ConnectionType,
11
- ComponentArrangement = library.networkgraph.ComponentArrangement;
10
+ const oConnectionType = library.networkgraph.ConnectionType,
11
+ oComponentArrangement = library.networkgraph.ComponentArrangement;
12
12
  const DEFAULT_HORIZONTAL_SPACING = 240;
13
13
  const DEFAULT_VERTICAL_SPACING = 100;
14
14
 
@@ -32,12 +32,14 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
32
32
  * Calculates and sets positions for nodes without coordinates based on their dependency relationships.
33
33
  * Uses topological sorting (Kahn's algorithm) and DFS-based cycle detection to arrange nodes
34
34
  * in layers from left to right, ensuring no overlaps and minimal line crossings.
35
+ * Note: Drag and drop functionality is only available for nodes. Groups cannot be dragged and dropped, even when NoopLayout is used and enableDragAndDrop is set to true.
35
36
  *
36
- * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
37
+ * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The graph instance
37
38
  * @param {object} [mConfig] - Configuration object
38
39
  * @param {number} [mConfig.horizontalSpacing=240] - Horizontal spacing between layers
39
40
  * @param {number} [mConfig.verticalSpacing=100] - Vertical spacing between nodes
40
41
  * @param {sap.suite.ui.commons.networkgraph.ComponentArrangement} [mConfig.componentArrangement=Horizontal] - Component arrangement: "Horizontal" or "Vertical"
42
+ * @param {boolean} [mConfig.clearCache=false] - Clear the position cache to force recalculation of all nodes
41
43
  * @public
42
44
  */
43
45
  calculatePositions: function (oGraph, mConfig) {
@@ -49,10 +51,17 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
49
51
  {
50
52
  horizontalSpacing: DEFAULT_HORIZONTAL_SPACING,
51
53
  verticalSpacing: DEFAULT_VERTICAL_SPACING,
52
- componentArrangement: ComponentArrangement.Horizontal,
54
+ componentArrangement: oComponentArrangement.Horizontal,
55
+ clearCache: false
53
56
  },
54
57
  mConfig || {}
55
58
  );
59
+
60
+ // Clear cache if requested (e.g., when changing arrangement)
61
+ if (config.clearCache) {
62
+ this._lastCalculated = new WeakMap();
63
+ }
64
+
56
65
  try {
57
66
  this._detectUserChanges(oGraph);
58
67
  this._buildDependencyGraph(oGraph);
@@ -129,13 +138,13 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
129
138
  this._lineMap.get(sFromKey).set(sToKey, oLine);
130
139
 
131
140
  switch (sConnectionType) {
132
- case ConnectionType.RightToRight:
133
- case ConnectionType.LeftToLeft:
141
+ case oConnectionType.RightToRight:
142
+ case oConnectionType.LeftToLeft:
134
143
  oFromNode._layoutData.parallelNodes.push(oToNode);
135
144
  oToNode._layoutData.parallelNodes.push(oFromNode);
136
145
  break;
137
- case ConnectionType.RightToLeft:
138
- case ConnectionType.LeftToRight:
146
+ case oConnectionType.RightToLeft:
147
+ case oConnectionType.LeftToRight:
139
148
  default:
140
149
  oFromNode._layoutData.outgoing.push(oToNode);
141
150
  oToNode._layoutData.incoming.push(oFromNode);
@@ -279,7 +288,7 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
279
288
  aConnectedComponents.push(aComponentNodes);
280
289
  }
281
290
  });
282
- const bSideBySide = componentArrangement !== ComponentArrangement.Vertical;
291
+ const bSideBySide = componentArrangement !== oComponentArrangement.Vertical;
283
292
  let iMaxVerticalPosition = 0;
284
293
  let iMaxLayerAcrossAll = 0;
285
294
 
@@ -7,8 +7,9 @@
7
7
  sap.ui.define([
8
8
  "sap/ui/core/dnd/DragInfo",
9
9
  "sap/ui/core/dnd/DropInfo",
10
- "sap/base/Log"
11
- ], function (DragInfo, DropInfo, Log) {
10
+ "sap/base/Log",
11
+ "sap/suite/ui/commons/networkgraph/Utils"
12
+ ], function (DragInfo, DropInfo, Log, Utils) {
12
13
  "use strict";
13
14
 
14
15
  // constants
@@ -22,12 +23,32 @@ sap.ui.define([
22
23
  AUTO_SCROLL_SPEED: 10, // Pixels to scroll per frame (16ms)
23
24
  };
24
25
 
26
+ /**
27
+ * Minimum position offsets to ensure action buttons remain visible.
28
+ * LEFT: 60px accounts for line and port
29
+ * TOP: 40px accounts for top action buttons (-2.25rem ≈ 36px) plus margin
30
+ */
31
+ const POSITION_CLAMP_OFFSET = {
32
+ LEFT: 60,
33
+ TOP: 40
34
+ };
35
+
25
36
  // Instance object: Only one will exist
26
37
  var instance = null;
27
38
  var sDragSessionKey = "networkGraphDragSession";
28
39
  var oUtilityFunctions = {
29
40
  diff: function (a, b) {
30
41
  return Math.abs(a - b);
42
+ },
43
+ clampPosition: function (x, y) {
44
+ /**
45
+ * Clamps position coordinates to minimum thresholds.
46
+ * Prevents nodes from being positioned where action buttons would be off-screen.
47
+ */
48
+ return {
49
+ x: Math.max(POSITION_CLAMP_OFFSET.LEFT, x),
50
+ y: Math.max(POSITION_CLAMP_OFFSET.TOP, y)
51
+ };
31
52
  }
32
53
  };
33
54
 
@@ -276,45 +297,6 @@ sap.ui.define([
276
297
  oControl.isA("sap.suite.ui.commons.networkgraph.Node");
277
298
  }
278
299
 
279
- /**
280
- * Retains the scroll position of the graph after node drop.
281
- * This method ensures that the viewport remains stable after drag and drop operations.
282
- *
283
- * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The graph control
284
- * @param {number} scrollLeft - The horizontal scroll position to maintain
285
- * @param {number} scrollTop - The vertical scroll position to maintain
286
- * @private
287
- */
288
- DragDropManager.prototype._retainScrollPosition = function (oGraph, scrollLeft, scrollTop) {
289
- if (!oGraph || !oGraph.$scroller || !oGraph.$scroller[0]) {
290
- Log.warning("DragDropManager: Invalid graph or scroller element for scroll position retention.");
291
- return;
292
- }
293
-
294
- const scrollerElement = oGraph.$scroller[0];
295
-
296
- // Use requestAnimationFrame for better performance and timing
297
- this._iRequestAnimationFrameId = requestAnimationFrame(() => {
298
- try {
299
- scrollerElement.scrollLeft = scrollLeft;
300
- scrollerElement.scrollTop = scrollTop;
301
-
302
- // Fallback verification - ensure the scroll position was actually set
303
- if (Math.abs(scrollerElement.scrollLeft - scrollLeft) > 1 ||
304
- Math.abs(scrollerElement.scrollTop - scrollTop) > 1) {
305
-
306
- // If the scroll position wasn't set correctly, try again after DOM updates
307
- setTimeout(() => {
308
- scrollerElement.scrollLeft = scrollLeft;
309
- scrollerElement.scrollTop = scrollTop;
310
- }, 10);
311
- }
312
- } catch (error) {
313
- Log.error("DragDropManager: Failed to retain scroll position", error);
314
- }
315
- });
316
- }
317
-
318
300
  /**
319
301
  * Handles the drag start event for nodes.
320
302
  *
@@ -325,6 +307,7 @@ sap.ui.define([
325
307
  let dragSession = oEvent.getParameter("dragSession");
326
308
  let browserEvent = oEvent.getParameter("browserEvent");
327
309
  let oGraph = oEvent.getParameter("target")?.getParent();
310
+ let oNode = oEvent.getParameter("target");
328
311
  let boundingRectScroller = oGraph?.$scroller?.[0]?.getBoundingClientRect() || { x: 0, y: 0 };
329
312
  let boundingRectInnerScroller = oGraph?._$innerscroller?.[0]?.getBoundingClientRect() || { x: 0, y: 0 };
330
313
 
@@ -336,6 +319,9 @@ sap.ui.define([
336
319
  // Stop any existing auto-scroll from previous drag operations
337
320
  this._stopAutoScroll();
338
321
 
322
+ // Create custom drag image that includes the border
323
+ this._oDragImageNode = Utils.createCustomDragImage(oNode, browserEvent);
324
+
339
325
  dragSession.setComplexData(sDragSessionKey, {
340
326
  // Mouse cursor position when drag starts (in viewport coordinates)
341
327
  cursorX: browserEvent.clientX,
@@ -369,6 +355,12 @@ sap.ui.define([
369
355
 
370
356
  // Stop auto-scrolling when drag ends
371
357
  this._stopAutoScroll();
358
+
359
+ // Clean up the drag image node
360
+ if (this._oDragImageNode && this._oDragImageNode.parentNode) {
361
+ this._oDragImageNode.parentNode.removeChild(this._oDragImageNode);
362
+ this._oDragImageNode = null;
363
+ }
372
364
  };
373
365
 
374
366
  /**
@@ -543,6 +535,9 @@ sap.ui.define([
543
535
  let newX = dropData.draggedControl.getX() + deltaX + (deltaSignatureX * deltaInnerScrollerX),
544
536
  newY = dropData.draggedControl.getY() + deltaY + (deltaSignatureY * deltaInnerScrollerY);
545
537
 
538
+ // Clamp position to prevent nodes from going off-screen (especially for action buttons)
539
+ var oClampedPosition = oUtilityFunctions.clampPosition(newX, newY);
540
+
546
541
  // Store current scroll position before any DOM changes
547
542
  let currentScrollLeft = oGraph?.$scroller?.[0]?.scrollLeft || 0;
548
543
  let currentScrollTop = oGraph?.$scroller?.[0]?.scrollTop || 0;
@@ -550,14 +545,11 @@ sap.ui.define([
550
545
  oGraph.fireEvent("nodeDropped", {
551
546
  ...oEvent.getParameters(),
552
547
  node: dropData.draggedControl,
553
- newX: newX,
554
- newY: newY
548
+ newX: oClampedPosition.x,
549
+ newY: oClampedPosition.y
555
550
  });
556
- // Restore the scroll position using the dedicated method
557
- // TODO: udpate promise based
558
- setTimeout(() => {
559
- this._retainScrollPosition(oGraph, currentScrollLeft, currentScrollTop);
560
- }, 0);
551
+ // Preserve scroll position after event
552
+ Utils.preserveScrollPosition(oGraph, currentScrollLeft, currentScrollTop, 0);
561
553
  };
562
554
 
563
555
  /**
@@ -574,12 +566,22 @@ sap.ui.define([
574
566
  x = dropData.clientX - boundingRect.left,
575
567
  y = dropData.clientY - boundingRect.top;
576
568
 
569
+ // Clamp position to prevent nodes from going off-screen (especially for action buttons)
570
+ var oClampedPosition = oUtilityFunctions.clampPosition(x, y);
571
+
572
+ // Store current scroll position before any DOM changes
573
+ let currentScrollLeft = oGraph?.$scroller?.[0]?.scrollLeft || 0;
574
+ let currentScrollTop = oGraph?.$scroller?.[0]?.scrollTop || 0;
575
+
577
576
  oGraph.fireEvent("nodeDropped", {
578
577
  ...oEvent.getParameters(),
579
578
  node: dropData.draggedControl,
580
- newX: x,
581
- newY: y
579
+ newX: oClampedPosition.x,
580
+ newY: oClampedPosition.y
582
581
  });
582
+
583
+ // Preserve scroll position after event
584
+ Utils.preserveScrollPosition(oGraph, currentScrollLeft, currentScrollTop, 0);
583
585
  };
584
586
 
585
587
  /**
@@ -6,8 +6,9 @@
6
6
  */
7
7
  sap.ui.define([
8
8
  "sap/ui/thirdparty/jquery",
9
- "sap/suite/ui/commons/library"
10
- ], function (jQuery, Library) {
9
+ "sap/suite/ui/commons/library",
10
+ "sap/suite/ui/commons/networkgraph/Utils"
11
+ ], function (jQuery, Library, Utils) {
11
12
  "use strict";
12
13
  /**
13
14
  * PortManager class for managing network graph ports.
@@ -485,6 +486,11 @@ sap.ui.define([
485
486
  const targetPortSide = target.dataset.portSide;
486
487
  // Check if the target node is valid
487
488
  if (targetNode) {
489
+ const oGraph = sourceNode.getParent();
490
+ // Capture current scroll position before firing event
491
+ const scrollerElement = oGraph.$scroller[0];
492
+ const currentScrollLeft = scrollerElement.scrollLeft || 0;
493
+ const currentScrollTop = scrollerElement.scrollTop || 0;
488
494
  const mParameters = {
489
495
  from: sourceNode.getKey(),
490
496
  to: targetNode.getKey(),
@@ -493,7 +499,10 @@ sap.ui.define([
493
499
  toNode: targetNode
494
500
  };
495
501
  // Fire the connectionCreated event
496
- sourceNode.getParent().fireConnectionCreated(mParameters);
502
+ oGraph.fireConnectionCreated(mParameters);
503
+
504
+ // Preserve scroll position after event
505
+ Utils.preserveScrollPosition(oGraph, currentScrollLeft, currentScrollTop, 0);
497
506
  }
498
507
  }
499
508
  // Remove inlet ports from other nodes
@@ -30,7 +30,7 @@ sap.ui.define([
30
30
  * @extends sap.suite.ui.commons.statusindicator.SimpleShape
31
31
  *
32
32
  * @author SAP SE
33
- * @version 1.145.0
33
+ * @version 1.146.0
34
34
  * @since 1.50
35
35
  *
36
36
  * @constructor
@@ -36,7 +36,7 @@ sap.ui.define([
36
36
  * @extends sap.suite.ui.commons.statusindicator.Shape
37
37
  *
38
38
  * @author SAP SE
39
- * @version 1.145.0
39
+ * @version 1.146.0
40
40
  * @since 1.50
41
41
  *
42
42
  * @constructor
@@ -21,7 +21,7 @@ sap.ui.define([
21
21
  * @extends sap.ui.core.Control
22
22
  *
23
23
  * @author SAP SE
24
- * @version 1.145.0
24
+ * @version 1.146.0
25
25
  * @since 1.50
26
26
  *
27
27
  * @constructor
@@ -23,7 +23,7 @@ sap.ui.define([
23
23
  * @extends sap.ui.core.Control
24
24
  *
25
25
  * @author SAP SE
26
- * @version 1.145.0
26
+ * @version 1.146.0
27
27
  * @since 1.50
28
28
  *
29
29
  * @constructor