@sapui5/sap.suite.ui.commons 1.144.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 (123) 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 +35 -6
  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 -3
  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/Timeline.js +9 -0
  19. package/src/sap/suite/ui/commons/TimelineNavigator.js +37 -5
  20. package/src/sap/suite/ui/commons/TimelineRenderer.js +3 -3
  21. package/src/sap/suite/ui/commons/collaboration/BaseHelperService.js +0 -1
  22. package/src/sap/suite/ui/commons/collaboration/CollaborationHelper.js +0 -3
  23. package/src/sap/suite/ui/commons/collaboration/CollaborationManagerService.js +0 -1
  24. package/src/sap/suite/ui/commons/collaboration/ContactHelper.js +12 -1
  25. package/src/sap/suite/ui/commons/collaboration/ContactPopover.fragment.xml +4 -1
  26. package/src/sap/suite/ui/commons/collaboration/MinimalContactPopover.fragment.xml +8 -5
  27. package/src/sap/suite/ui/commons/collaboration/ServiceContainer.js +12 -2
  28. package/src/sap/suite/ui/commons/collaboration/TeamsHelperService.js +0 -6
  29. package/src/sap/suite/ui/commons/collaboration/channels/MessageChannel.js +0 -2
  30. package/src/sap/suite/ui/commons/collaboration/flpplugins/msplugin/Component-preload.js +1 -1
  31. package/src/sap/suite/ui/commons/collaboration/flpplugins/msplugin/Component.js +1 -2
  32. package/src/sap/suite/ui/commons/flexibility/changeHandler/PropertyChangeMapper.js +1 -1
  33. package/src/sap/suite/ui/commons/imageeditor/CropCustomShapeHistoryItem.js +1 -1
  34. package/src/sap/suite/ui/commons/imageeditor/CropEllipseHistoryItem.js +1 -1
  35. package/src/sap/suite/ui/commons/imageeditor/CropRectangleHistoryItem.js +1 -1
  36. package/src/sap/suite/ui/commons/imageeditor/CustomSizeItem.js +1 -1
  37. package/src/sap/suite/ui/commons/imageeditor/FilterHistoryItem.js +1 -1
  38. package/src/sap/suite/ui/commons/imageeditor/FlipHistoryItem.js +1 -1
  39. package/src/sap/suite/ui/commons/imageeditor/HistoryItem.js +1 -1
  40. package/src/sap/suite/ui/commons/imageeditor/ImageEditor.js +1 -1
  41. package/src/sap/suite/ui/commons/imageeditor/ImageEditorContainer.js +1 -1
  42. package/src/sap/suite/ui/commons/imageeditor/ImageEditorResponsiveContainer.js +9 -6
  43. package/src/sap/suite/ui/commons/imageeditor/ResizeHistoryItem.js +1 -1
  44. package/src/sap/suite/ui/commons/imageeditor/RotateHistoryItem.js +1 -1
  45. package/src/sap/suite/ui/commons/library.js +25 -1
  46. package/src/sap/suite/ui/commons/messagebundle.properties +20 -9
  47. package/src/sap/suite/ui/commons/messagebundle_ar.properties +24 -3
  48. package/src/sap/suite/ui/commons/messagebundle_bg.properties +24 -3
  49. package/src/sap/suite/ui/commons/messagebundle_ca.properties +24 -3
  50. package/src/sap/suite/ui/commons/messagebundle_cnr.properties +24 -3
  51. package/src/sap/suite/ui/commons/messagebundle_cs.properties +23 -2
  52. package/src/sap/suite/ui/commons/messagebundle_cy.properties +24 -3
  53. package/src/sap/suite/ui/commons/messagebundle_da.properties +23 -2
  54. package/src/sap/suite/ui/commons/messagebundle_de.properties +36 -15
  55. package/src/sap/suite/ui/commons/messagebundle_el.properties +25 -4
  56. package/src/sap/suite/ui/commons/messagebundle_en.properties +24 -3
  57. package/src/sap/suite/ui/commons/messagebundle_en_GB.properties +24 -3
  58. package/src/sap/suite/ui/commons/messagebundle_en_US_saprigi.properties +11 -5
  59. package/src/sap/suite/ui/commons/messagebundle_es.properties +24 -3
  60. package/src/sap/suite/ui/commons/messagebundle_es_MX.properties +24 -3
  61. package/src/sap/suite/ui/commons/messagebundle_et.properties +23 -2
  62. package/src/sap/suite/ui/commons/messagebundle_fi.properties +23 -2
  63. package/src/sap/suite/ui/commons/messagebundle_fr.properties +32 -11
  64. package/src/sap/suite/ui/commons/messagebundle_fr_CA.properties +24 -3
  65. package/src/sap/suite/ui/commons/messagebundle_hi.properties +24 -3
  66. package/src/sap/suite/ui/commons/messagebundle_hr.properties +24 -3
  67. package/src/sap/suite/ui/commons/messagebundle_hu.properties +24 -3
  68. package/src/sap/suite/ui/commons/messagebundle_id.properties +25 -4
  69. package/src/sap/suite/ui/commons/messagebundle_it.properties +24 -3
  70. package/src/sap/suite/ui/commons/messagebundle_iw.properties +24 -3
  71. package/src/sap/suite/ui/commons/messagebundle_ja.properties +24 -3
  72. package/src/sap/suite/ui/commons/messagebundle_kk.properties +25 -4
  73. package/src/sap/suite/ui/commons/messagebundle_ko.properties +23 -2
  74. package/src/sap/suite/ui/commons/messagebundle_lt.properties +24 -3
  75. package/src/sap/suite/ui/commons/messagebundle_lv.properties +24 -3
  76. package/src/sap/suite/ui/commons/messagebundle_mk.properties +23 -2
  77. package/src/sap/suite/ui/commons/messagebundle_ms.properties +24 -3
  78. package/src/sap/suite/ui/commons/messagebundle_nl.properties +23 -2
  79. package/src/sap/suite/ui/commons/messagebundle_no.properties +25 -4
  80. package/src/sap/suite/ui/commons/messagebundle_pl.properties +24 -3
  81. package/src/sap/suite/ui/commons/messagebundle_pt.properties +24 -3
  82. package/src/sap/suite/ui/commons/messagebundle_pt_PT.properties +24 -3
  83. package/src/sap/suite/ui/commons/messagebundle_ro.properties +24 -3
  84. package/src/sap/suite/ui/commons/messagebundle_ru.properties +25 -4
  85. package/src/sap/suite/ui/commons/messagebundle_sh.properties +24 -3
  86. package/src/sap/suite/ui/commons/messagebundle_sk.properties +24 -3
  87. package/src/sap/suite/ui/commons/messagebundle_sl.properties +23 -2
  88. package/src/sap/suite/ui/commons/messagebundle_sr.properties +24 -3
  89. package/src/sap/suite/ui/commons/messagebundle_sv.properties +23 -2
  90. package/src/sap/suite/ui/commons/messagebundle_th.properties +25 -4
  91. package/src/sap/suite/ui/commons/messagebundle_tr.properties +24 -3
  92. package/src/sap/suite/ui/commons/messagebundle_uk.properties +27 -6
  93. package/src/sap/suite/ui/commons/messagebundle_vi.properties +26 -5
  94. package/src/sap/suite/ui/commons/messagebundle_zh_CN.properties +24 -3
  95. package/src/sap/suite/ui/commons/messagebundle_zh_TW.properties +26 -5
  96. package/src/sap/suite/ui/commons/networkgraph/Graph.js +49 -22
  97. package/src/sap/suite/ui/commons/networkgraph/KeyboardNavigator.js +45 -4
  98. package/src/sap/suite/ui/commons/networkgraph/Line.js +157 -11
  99. package/src/sap/suite/ui/commons/networkgraph/Node.js +289 -86
  100. package/src/sap/suite/ui/commons/networkgraph/Utils.js +239 -10
  101. package/src/sap/suite/ui/commons/networkgraph/layout/NoopLayout.js +55 -8
  102. package/src/sap/suite/ui/commons/networkgraph/util/DependencyLayoutHelper.js +156 -74
  103. package/src/sap/suite/ui/commons/networkgraph/util/DragDropManager.js +52 -50
  104. package/src/sap/suite/ui/commons/networkgraph/util/PortManager.js +14 -6
  105. package/src/sap/suite/ui/commons/statusindicator/Circle.js +1 -1
  106. package/src/sap/suite/ui/commons/statusindicator/CustomShape.js +1 -1
  107. package/src/sap/suite/ui/commons/statusindicator/DiscreteThreshold.js +1 -1
  108. package/src/sap/suite/ui/commons/statusindicator/FillingOption.js +1 -1
  109. package/src/sap/suite/ui/commons/statusindicator/LibraryShape.js +1 -1
  110. package/src/sap/suite/ui/commons/statusindicator/Path.js +1 -1
  111. package/src/sap/suite/ui/commons/statusindicator/PropertyThreshold.js +1 -1
  112. package/src/sap/suite/ui/commons/statusindicator/Rectangle.js +1 -1
  113. package/src/sap/suite/ui/commons/statusindicator/Shape.js +1 -1
  114. package/src/sap/suite/ui/commons/statusindicator/ShapeGroup.js +1 -1
  115. package/src/sap/suite/ui/commons/statusindicator/SimpleShape.js +1 -1
  116. package/src/sap/suite/ui/commons/statusindicator/StatusIndicator.js +1 -1
  117. package/src/sap/suite/ui/commons/taccount/TAccount.js +1 -1
  118. package/src/sap/suite/ui/commons/taccount/TAccountGroup.js +1 -1
  119. package/src/sap/suite/ui/commons/taccount/TAccountItem.js +1 -1
  120. package/src/sap/suite/ui/commons/taccount/TAccountItemProperty.js +1 -1
  121. package/src/sap/suite/ui/commons/taccount/TAccountPanel.js +1 -1
  122. package/src/sap/suite/ui/commons/themes/base/NetworkLine.less +26 -5
  123. package/src/sap/suite/ui/commons/windowmessages/CollaborationMessageConsumer.js +3 -3
@@ -7,7 +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;
10
+ const oConnectionType = library.networkgraph.ConnectionType,
11
+ oComponentArrangement = library.networkgraph.ComponentArrangement;
11
12
  const DEFAULT_HORIZONTAL_SPACING = 240;
12
13
  const DEFAULT_VERTICAL_SPACING = 100;
13
14
 
@@ -21,15 +22,24 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
21
22
  * @since 1.144
22
23
  */
23
24
  const DependencyLayoutHelper = {
25
+ /**
26
+ * WeakMap to store last calculated positions and origin flag for automatic drag detection.
27
+ * Structure: {x: number, y: number, bIsUserPositioned: boolean}
28
+ */
29
+ _lastCalculated: new WeakMap(),
30
+
24
31
  /**
25
32
  * Calculates and sets positions for nodes without coordinates based on their dependency relationships.
26
33
  * Uses topological sorting (Kahn's algorithm) and DFS-based cycle detection to arrange nodes
27
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.
28
36
  *
29
- * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
37
+ * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The graph instance
30
38
  * @param {object} [mConfig] - Configuration object
31
39
  * @param {number} [mConfig.horizontalSpacing=240] - Horizontal spacing between layers
32
40
  * @param {number} [mConfig.verticalSpacing=100] - Vertical spacing between nodes
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
33
43
  * @public
34
44
  */
35
45
  calculatePositions: function (oGraph, mConfig) {
@@ -41,17 +51,26 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
41
51
  {
42
52
  horizontalSpacing: DEFAULT_HORIZONTAL_SPACING,
43
53
  verticalSpacing: DEFAULT_VERTICAL_SPACING,
54
+ componentArrangement: oComponentArrangement.Horizontal,
55
+ clearCache: false
44
56
  },
45
57
  mConfig || {}
46
58
  );
47
59
 
60
+ // Clear cache if requested (e.g., when changing arrangement)
61
+ if (config.clearCache) {
62
+ this._lastCalculated = new WeakMap();
63
+ }
64
+
48
65
  try {
66
+ this._detectUserChanges(oGraph);
49
67
  this._buildDependencyGraph(oGraph);
50
68
  const aComponents = this._identifyComponents(oGraph);
51
- this._processComponents(aComponents);
69
+ this._processComponents(aComponents, config);
52
70
  this._calculateCoordinates(oGraph, config);
53
71
  this._adjustHorizontalSpacingForNodeWidths(oGraph, config);
54
72
  this._adjustVerticalSpacingForNodeHeights(oGraph, config);
73
+ this._storeFinalPositions(oGraph);
55
74
  } catch (e) {
56
75
  Log.error("DependencyLayoutHelper error: " + e.message, e);
57
76
  throw new Error("DependencyLayoutHelper error: " + e.message);
@@ -64,8 +83,8 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
64
83
  },
65
84
 
66
85
  /**
67
- * Builds the internal dependency graph structure for layout calculation.
68
- * Initializes layout data for each node and categorizes connections by type.
86
+ * Builds the dependency graph structure by analyzing node relationships.
87
+ * Initializes layout data for each node and categorizes connections.
69
88
  *
70
89
  * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
71
90
  * @private
@@ -79,9 +98,9 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
79
98
  mNodeMap.set(oNode.getKey(), oNode);
80
99
  const fX = oNode.getX();
81
100
  const fY = oNode.getY();
82
- // Constraint: Nodes with coordinates (0,0) are treated as unpositioned and will be
83
- // auto-positioned based on dependency relationships. For origin positioning, use (0.1, 0.1) or (1, 1).
84
- const bHasCoordinates = fX !== undefined && fY !== undefined && (fX !== 0 || fY !== 0);
101
+ const oLastPos = this._lastCalculated.get(oNode);
102
+ // Only preserve coordinates if they were original or user-dragged
103
+ const bShouldPreserve = oLastPos?.bIsUserPositioned;
85
104
 
86
105
  oNode._layoutData = {
87
106
  layer: -1,
@@ -91,9 +110,10 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
91
110
  parallelNodes: [],
92
111
  backwardEdges: [],
93
112
  backwardEdgeLines: [],
94
- hasCoordinates: bHasCoordinates,
113
+ isBackwardSource: false,
114
+ bShouldPreserve,
95
115
  userX: fX,
96
- userY: fY,
116
+ userY: fY
97
117
  };
98
118
  });
99
119
 
@@ -118,13 +138,13 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
118
138
  this._lineMap.get(sFromKey).set(sToKey, oLine);
119
139
 
120
140
  switch (sConnectionType) {
121
- case ConnectionType.RightToRight:
122
- case ConnectionType.LeftToLeft:
141
+ case oConnectionType.RightToRight:
142
+ case oConnectionType.LeftToLeft:
123
143
  oFromNode._layoutData.parallelNodes.push(oToNode);
124
144
  oToNode._layoutData.parallelNodes.push(oFromNode);
125
145
  break;
126
- case ConnectionType.RightToLeft:
127
- case ConnectionType.LeftToRight:
146
+ case oConnectionType.RightToLeft:
147
+ case oConnectionType.LeftToRight:
128
148
  default:
129
149
  oFromNode._layoutData.outgoing.push(oToNode);
130
150
  oToNode._layoutData.incoming.push(oFromNode);
@@ -164,12 +184,9 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
164
184
  oNode._layoutData.isBackwardSource = true;
165
185
  oNode._layoutData.backwardEdges.push(oTargetNode);
166
186
 
167
- const oFromMap = this._lineMap.get(sKey);
168
- if (oFromMap) {
169
- const oLine = oFromMap.get(sTargetKey);
170
- if (oLine) {
171
- oNode._layoutData.backwardEdgeLines.push(oLine);
172
- }
187
+ const oLine = this._lineMap.get(sKey)?.get(sTargetKey);
188
+ if (oLine) {
189
+ oNode._layoutData.backwardEdgeLines.push(oLine);
173
190
  }
174
191
 
175
192
  const idx = oTargetNode._layoutData.incoming.indexOf(oNode);
@@ -251,9 +268,10 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
251
268
  * Processes all components: separates isolated nodes and arranges connected components.
252
269
  *
253
270
  * @param {Array<sap.suite.ui.commons.networkgraph.Node[]>} aComponents - Array of components (groups of connected nodes)
271
+ * @param {object} config - Configuration object
254
272
  * @private
255
273
  */
256
- _processComponents: function (aComponents) {
274
+ _processComponents: function (aComponents, { componentArrangement }) {
257
275
  const aIsolatedNodes = [];
258
276
  const aConnectedComponents = [];
259
277
 
@@ -261,7 +279,8 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
261
279
  const bIsIsolated =
262
280
  aComponentNodes.length === 1 &&
263
281
  aComponentNodes[0]._layoutData.incoming.length === 0 &&
264
- aComponentNodes[0]._layoutData.outgoing.length === 0;
282
+ aComponentNodes[0]._layoutData.outgoing.length === 0 &&
283
+ !aComponentNodes[0]._layoutData.bShouldPreserve;
265
284
 
266
285
  if (bIsIsolated) {
267
286
  aIsolatedNodes.push(aComponentNodes[0]);
@@ -269,7 +288,7 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
269
288
  aConnectedComponents.push(aComponentNodes);
270
289
  }
271
290
  });
272
-
291
+ const bSideBySide = componentArrangement !== oComponentArrangement.Vertical;
273
292
  let iMaxVerticalPosition = 0;
274
293
  let iMaxLayerAcrossAll = 0;
275
294
 
@@ -278,35 +297,56 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
278
297
  this._adjustParallelLayersForComponent(aComponentNodes);
279
298
  this._assignVerticalPositionsForComponent(aComponentNodes);
280
299
 
281
- aComponentNodes.forEach((oNode) => {
282
- oNode._layoutData.position += iMaxVerticalPosition;
283
- oNode._layoutData.componentOffset = 0;
284
- });
300
+ if (bSideBySide) {
301
+ aComponentNodes.forEach((oNode) => {
302
+ oNode._layoutData.layer += iMaxLayerAcrossAll;
303
+ oNode._layoutData.componentOffset = 0;
304
+ });
285
305
 
286
- let iComponentMaxPosition = -1;
287
- aComponentNodes.forEach((n) => {
288
- if (n._layoutData.position > iComponentMaxPosition) {
289
- iComponentMaxPosition = n._layoutData.position;
290
- }
291
- });
292
- iMaxVerticalPosition = iComponentMaxPosition + 1;
306
+ let iComponentMaxLayer = -1;
307
+ aComponentNodes.forEach((n) => {
308
+ if (n._layoutData.layer > iComponentMaxLayer) {
309
+ iComponentMaxLayer = n._layoutData.layer;
310
+ }
311
+ });
312
+ iMaxLayerAcrossAll = iComponentMaxLayer + 1;
313
+ } else {
314
+ aComponentNodes.forEach((oNode) => {
315
+ oNode._layoutData.position += iMaxVerticalPosition;
316
+ oNode._layoutData.componentOffset = 0;
317
+ });
293
318
 
294
- let iComponentMaxLayer = -1;
295
- aComponentNodes.forEach((n) => {
296
- if (n._layoutData.layer > iComponentMaxLayer) {
297
- iComponentMaxLayer = n._layoutData.layer;
298
- }
299
- });
300
- iMaxLayerAcrossAll = Math.max(iMaxLayerAcrossAll, iComponentMaxLayer);
319
+ let iComponentMaxPosition = -1;
320
+ aComponentNodes.forEach((n) => {
321
+ if (n._layoutData.position > iComponentMaxPosition) {
322
+ iComponentMaxPosition = n._layoutData.position;
323
+ }
324
+ });
325
+ iMaxVerticalPosition = iComponentMaxPosition + 1;
326
+
327
+ let iComponentMaxLayer = -1;
328
+ aComponentNodes.forEach((n) => {
329
+ if (n._layoutData.layer > iComponentMaxLayer) {
330
+ iComponentMaxLayer = n._layoutData.layer;
331
+ }
332
+ });
333
+ iMaxLayerAcrossAll = Math.max(iMaxLayerAcrossAll, iComponentMaxLayer);
334
+ }
301
335
  });
302
336
 
303
337
  if (aIsolatedNodes.length > 0) {
304
338
  const iRightSideOffset = iMaxLayerAcrossAll + 1;
305
339
 
306
340
  aIsolatedNodes.forEach((oNode, idx) => {
307
- oNode._layoutData.layer = idx % 2;
308
- oNode._layoutData.position = Math.floor(idx / 2);
309
- oNode._layoutData.componentOffset = iRightSideOffset;
341
+ if (bSideBySide) {
342
+ oNode._layoutData.layer = Math.floor(idx / 2);
343
+ oNode._layoutData.position = idx % 2;
344
+ oNode._layoutData.componentOffset = iMaxLayerAcrossAll;
345
+ } else {
346
+ oNode._layoutData.layer = idx % 2;
347
+ oNode._layoutData.position = Math.floor(idx / 2);
348
+ oNode._layoutData.componentOffset = iRightSideOffset;
349
+ }
310
350
  });
311
351
  }
312
352
  },
@@ -657,10 +697,10 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
657
697
  * @param {object} config - Configuration with spacing values
658
698
  * @private
659
699
  */
660
- _calculateCoordinates: function (oGraph, config) {
700
+ _calculateCoordinates: function (oGraph, { horizontalSpacing, verticalSpacing }) {
661
701
  const aNodes = oGraph.getNodes();
662
- const iHSpacing = config.horizontalSpacing;
663
- const iVSpacing = config.verticalSpacing;
702
+ const iHSpacing = horizontalSpacing;
703
+ const iVSpacing = verticalSpacing;
664
704
 
665
705
  aNodes.forEach((oNode) => {
666
706
  const iComponentOffset = oNode._layoutData.componentOffset || 0;
@@ -671,11 +711,10 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
671
711
  });
672
712
 
673
713
  aNodes.forEach((oNode) => {
674
- if (oNode._layoutData.hasCoordinates) {
675
- const fUserX = oNode._layoutData.userX;
676
- const fUserY = oNode._layoutData.userY;
677
- oNode.setX(fUserX);
678
- oNode.setY(fUserY);
714
+ if (oNode._layoutData.bShouldPreserve) {
715
+ const { userX, userY } = oNode._layoutData;
716
+ oNode.setX(userX);
717
+ oNode.setY(userY);
679
718
  }
680
719
  });
681
720
  },
@@ -684,18 +723,15 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
684
723
  * Adjusts horizontal spacing to accommodate nodes with varying widths.
685
724
  *
686
725
  * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
687
- * @param {object} config - Configuration with spacing values
688
726
  * @private
689
727
  */
690
- _adjustHorizontalSpacingForNodeWidths: function (oGraph, config) {
728
+ _adjustHorizontalSpacingForNodeWidths: function (oGraph) {
691
729
  const aNodes = oGraph.getNodes();
692
- const iDefaultSpacing = config.horizontalSpacing;
693
- const iHGap = iDefaultSpacing;
694
730
  const mLayerWidths = {};
695
731
  let iMaxLayer = -1;
696
732
 
697
733
  aNodes.forEach((oNode) => {
698
- if (!oNode._layoutData.hasCoordinates) {
734
+ if (!oNode._layoutData.bShouldPreserve) {
699
735
  const iLayer =
700
736
  oNode._layoutData.layer + (oNode._layoutData.componentOffset || 0);
701
737
  iMaxLayer = Math.max(iMaxLayer, iLayer);
@@ -716,16 +752,12 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
716
752
  mLayerOffsets[iLayer] = iCumulativeOffset;
717
753
  const iActualWidth = mLayerWidths[iLayer];
718
754
  if (iActualWidth) {
719
- if (iActualWidth > iDefaultSpacing) {
720
- iCumulativeOffset += iActualWidth - iDefaultSpacing + iHGap;
721
- } else {
722
- iCumulativeOffset += iActualWidth;
723
- }
755
+ iCumulativeOffset += iActualWidth;
724
756
  }
725
757
  }
726
758
 
727
759
  aNodes.forEach((oNode) => {
728
- if (!oNode._layoutData.hasCoordinates) {
760
+ if (!oNode._layoutData.bShouldPreserve) {
729
761
  const iLayer =
730
762
  oNode._layoutData.layer + (oNode._layoutData.componentOffset || 0);
731
763
  const iOffset = mLayerOffsets[iLayer] || 0;
@@ -738,18 +770,15 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
738
770
  * Adjusts vertical spacing to accommodate nodes with varying heights.
739
771
  *
740
772
  * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
741
- * @param {object} config - Configuration with spacing values
742
773
  * @private
743
774
  */
744
- _adjustVerticalSpacingForNodeHeights: function (oGraph, config) {
775
+ _adjustVerticalSpacingForNodeHeights: function (oGraph) {
745
776
  const aNodes = oGraph.getNodes();
746
- const iDefaultSpacing = config.verticalSpacing;
747
- const iVGap = iDefaultSpacing;
748
777
  const mPositionHeights = {};
749
778
  const mAllPositions = {};
750
779
 
751
780
  aNodes.forEach((oNode) => {
752
- if (!oNode._layoutData.hasCoordinates) {
781
+ if (!oNode._layoutData.bShouldPreserve) {
753
782
  const iPosition = oNode._layoutData.position;
754
783
  mAllPositions[iPosition] = true;
755
784
 
@@ -775,22 +804,75 @@ sap.ui.define(["sap/suite/ui/commons/library", "sap/base/Log"], function (librar
775
804
  mPositionOffsets[iPosition] = iCumulativeOffset;
776
805
  const iActualHeight = mPositionHeights[iPosition];
777
806
  if (iActualHeight) {
778
- if (iActualHeight > iDefaultSpacing) {
779
- iCumulativeOffset += iActualHeight - iDefaultSpacing + iVGap;
780
- } else {
781
- iCumulativeOffset += iActualHeight;
782
- }
807
+ iCumulativeOffset += iActualHeight;
783
808
  }
784
809
  });
785
810
 
786
811
  aNodes.forEach((oNode) => {
787
- if (!oNode._layoutData.hasCoordinates) {
812
+ if (!oNode._layoutData.bShouldPreserve) {
788
813
  const iPosition = oNode._layoutData.position;
789
814
  const iOffset = mPositionOffsets[iPosition] || 0;
790
815
  oNode.setY(oNode.getY() + iOffset);
791
816
  }
792
817
  });
793
818
  },
819
+
820
+ /**
821
+ * Stores final calculated positions for automatic drag detection on next call.
822
+ * Only stores positions for nodes that were calculated (not original/dragged).
823
+ *
824
+ * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
825
+ * @private
826
+ */
827
+ _storeFinalPositions: function (oGraph) {
828
+ const aNodes = oGraph.getNodes();
829
+
830
+ aNodes.forEach((oNode) => {
831
+ if (!oNode._layoutData.bShouldPreserve) {
832
+ this._lastCalculated.set(oNode, {
833
+ x: oNode.getX(),
834
+ y: oNode.getY(),
835
+ bIsUserPositioned: false
836
+ });
837
+ }
838
+ });
839
+ },
840
+
841
+ /**
842
+ * Detects user-made position changes by comparing current positions with last calculated positions.
843
+ * Marks nodes with original coordinates and tracks drag operations.
844
+ *
845
+ * @param {sap.suite.ui.commons.networkgraph.Graph} oGraph - The network graph instance
846
+ * @private
847
+ */
848
+ _detectUserChanges: function (oGraph) {
849
+ const aNodes = oGraph.getNodes();
850
+
851
+ aNodes.forEach((oNode) => {
852
+ const fX = oNode.getX();
853
+ const fY = oNode.getY();
854
+ // Constraint: Nodes with coordinates (0,0) or negative values are treated as unpositioned.
855
+ // For origin positioning, use (0.1, 0.1) or (1, 1).
856
+ const bHasCoordinates = fX !== undefined && fY !== undefined && (fX !== 0 || fY !== 0);
857
+ const oLastPos = this._lastCalculated.get(oNode);
858
+
859
+ if (!oLastPos && bHasCoordinates) {
860
+ // First time seeing this node with coordinates - mark as original
861
+ this._lastCalculated.set(oNode, {
862
+ x: fX,
863
+ y: fY,
864
+ bIsUserPositioned: true
865
+ });
866
+ } else if (oLastPos) {
867
+ // Check if user dragged it
868
+ if (fX !== oLastPos.x || fY !== oLastPos.y) {
869
+ oLastPos.x = fX;
870
+ oLastPos.y = fY;
871
+ oLastPos.bIsUserPositioned = true;
872
+ }
873
+ }
874
+ });
875
+ },
794
876
  };
795
877
 
796
878
  return DependencyLayoutHelper;
@@ -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.
@@ -68,8 +69,7 @@ sap.ui.define([
68
69
  * @param {boolean} bTriggerNode - Whether the node is a trigger node.
69
70
  */
70
71
  addPortsToNode(oNode, bTriggerNode) {
71
- var oGraph = oNode.getParent();
72
- var sNodePorts = oGraph.getNodePorts();
72
+ var sNodePorts = oNode._getNodePorts();
73
73
  // Remove existing ports first
74
74
  this.removePortsFromNode(oNode);
75
75
  if (sNodePorts === "None") {
@@ -200,7 +200,7 @@ sap.ui.define([
200
200
  */
201
201
  addInletPortsToOtherNodes(oNode) {
202
202
  var oGraph = oNode.getParent();
203
- var sNodePorts = oGraph.getNodePorts();
203
+ var sNodePorts = oNode._getNodePorts();
204
204
  // Don't add inlet ports if nodePorts is "None"
205
205
  if (sNodePorts === "None") {
206
206
  return;
@@ -486,6 +486,11 @@ sap.ui.define([
486
486
  const targetPortSide = target.dataset.portSide;
487
487
  // Check if the target node is valid
488
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;
489
494
  const mParameters = {
490
495
  from: sourceNode.getKey(),
491
496
  to: targetNode.getKey(),
@@ -494,7 +499,10 @@ sap.ui.define([
494
499
  toNode: targetNode
495
500
  };
496
501
  // Fire the connectionCreated event
497
- sourceNode.getParent().fireConnectionCreated(mParameters);
502
+ oGraph.fireConnectionCreated(mParameters);
503
+
504
+ // Preserve scroll position after event
505
+ Utils.preserveScrollPosition(oGraph, currentScrollLeft, currentScrollTop, 0);
498
506
  }
499
507
  }
500
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.144.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.144.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.144.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.144.0
26
+ * @version 1.146.0
27
27
  * @since 1.50
28
28
  *
29
29
  * @constructor