@sapui5/sap.fe.core 1.121.2 → 1.123.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 (241) hide show
  1. package/package.json +1 -1
  2. package/src/sap/fe/core/.library +1 -1
  3. package/src/sap/fe/core/ActionRuntime.js +2 -2
  4. package/src/sap/fe/core/ActionRuntime.ts +1 -2
  5. package/src/sap/fe/core/CommonUtils.js +14 -171
  6. package/src/sap/fe/core/CommonUtils.ts +15 -221
  7. package/src/sap/fe/core/PageController.js +13 -1
  8. package/src/sap/fe/core/PageController.ts +16 -0
  9. package/src/sap/fe/core/TemplateComponent.js +6 -1
  10. package/src/sap/fe/core/TemplateComponent.ts +8 -0
  11. package/src/sap/fe/core/UIProvider.js +23 -0
  12. package/src/sap/fe/core/UIProvider.ts +38 -0
  13. package/src/sap/fe/core/buildingBlocks/BuildingBlockBase.js +97 -43
  14. package/src/sap/fe/core/buildingBlocks/BuildingBlockBase.ts +120 -50
  15. package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockSupport.js +6 -3
  16. package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockSupport.ts +12 -18
  17. package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockTemplateProcessor.js +2 -2
  18. package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockTemplateProcessor.ts +1 -1
  19. package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockTemplatingBase.js +1 -1
  20. package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockTemplatingBase.ts +4 -3
  21. package/src/sap/fe/core/buildingBlocks/templating/RuntimeBuildingBlockFragment.js +1 -1
  22. package/src/sap/fe/core/buildingBlocks/templating/RuntimeBuildingBlockFragment.ts +1 -0
  23. package/src/sap/fe/core/controllerextensions/BaseControllerExtension.js +42 -1
  24. package/src/sap/fe/core/controllerextensions/BaseControllerExtension.ts +40 -0
  25. package/src/sap/fe/core/controllerextensions/CollaborativeDraft.js +5 -2
  26. package/src/sap/fe/core/controllerextensions/CollaborativeDraft.ts +5 -3
  27. package/src/sap/fe/core/controllerextensions/EditFlow.js +151 -60
  28. package/src/sap/fe/core/controllerextensions/EditFlow.ts +165 -68
  29. package/src/sap/fe/core/controllerextensions/HookSupport.js +32 -14
  30. package/src/sap/fe/core/controllerextensions/HookSupport.ts +35 -14
  31. package/src/sap/fe/core/controllerextensions/IntentBasedNavigation.js +5 -17
  32. package/src/sap/fe/core/controllerextensions/IntentBasedNavigation.ts +0 -12
  33. package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.js +6 -6
  34. package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.ts +15 -10
  35. package/src/sap/fe/core/controllerextensions/InternalRouting.js +108 -287
  36. package/src/sap/fe/core/controllerextensions/InternalRouting.ts +117 -309
  37. package/src/sap/fe/core/controllerextensions/KPIManagement.js +2 -2
  38. package/src/sap/fe/core/controllerextensions/KPIManagement.ts +6 -2
  39. package/src/sap/fe/core/controllerextensions/MessageHandler.js +2 -2
  40. package/src/sap/fe/core/controllerextensions/MessageHandler.ts +1 -1
  41. package/src/sap/fe/core/controllerextensions/PageReady.js +6 -6
  42. package/src/sap/fe/core/controllerextensions/PageReady.ts +5 -4
  43. package/src/sap/fe/core/controllerextensions/Paginator.js +17 -110
  44. package/src/sap/fe/core/controllerextensions/Paginator.ts +13 -130
  45. package/src/sap/fe/core/controllerextensions/Placeholder.js +3 -3
  46. package/src/sap/fe/core/controllerextensions/Placeholder.ts +1 -2
  47. package/src/sap/fe/core/controllerextensions/Recommendations.js +36 -31
  48. package/src/sap/fe/core/controllerextensions/Recommendations.ts +32 -37
  49. package/src/sap/fe/core/controllerextensions/Share.js +7 -7
  50. package/src/sap/fe/core/controllerextensions/Share.ts +6 -6
  51. package/src/sap/fe/core/controllerextensions/SideEffects.js +52 -6
  52. package/src/sap/fe/core/controllerextensions/SideEffects.ts +56 -4
  53. package/src/sap/fe/core/controllerextensions/ViewState.js +32 -46
  54. package/src/sap/fe/core/controllerextensions/ViewState.ts +24 -31
  55. package/src/sap/fe/core/controllerextensions/dialog/OperationsDialog.block.js +42 -31
  56. package/src/sap/fe/core/controllerextensions/dialog/OperationsDialog.block.tsx +6 -0
  57. package/src/sap/fe/core/controllerextensions/editFlow/TransactionHelper.js +168 -276
  58. package/src/sap/fe/core/controllerextensions/editFlow/TransactionHelper.ts +182 -310
  59. package/src/sap/fe/core/controllerextensions/editFlow/draft.js +3 -3
  60. package/src/sap/fe/core/controllerextensions/editFlow/draft.ts +2 -2
  61. package/src/sap/fe/core/controllerextensions/editFlow/draftDataLossPopup.js +4 -3
  62. package/src/sap/fe/core/controllerextensions/editFlow/draftDataLossPopup.ts +3 -2
  63. package/src/sap/fe/core/controllerextensions/editFlow/operations/facade.js +74 -52
  64. package/src/sap/fe/core/controllerextensions/editFlow/operations/facade.ts +95 -55
  65. package/src/sap/fe/core/controllerextensions/messageHandler/messageHandling.js +3 -17
  66. package/src/sap/fe/core/controllerextensions/messageHandler/messageHandling.ts +10 -23
  67. package/src/sap/fe/core/controllerextensions/recommendations/Telemetry.js +3 -3
  68. package/src/sap/fe/core/controllerextensions/recommendations/Telemetry.ts +2 -2
  69. package/src/sap/fe/core/controllerextensions/routing/ContextPathHelper.js +225 -0
  70. package/src/sap/fe/core/controllerextensions/routing/ContextPathHelper.ts +241 -0
  71. package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DraftDataLossDialog.block.js +69 -48
  72. package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DraftDataLossDialog.block.tsx +56 -33
  73. package/src/sap/fe/core/controls/FormElementWrapper.js +8 -11
  74. package/src/sap/fe/core/controls/FormElementWrapper.ts +9 -0
  75. package/src/sap/fe/core/controls/Recommendations/ConfirmRecommendationDialog.block.js +6 -14
  76. package/src/sap/fe/core/controls/Recommendations/ConfirmRecommendationDialog.block.tsx +12 -23
  77. package/src/sap/fe/core/converters/ConverterContext.js +17 -9
  78. package/src/sap/fe/core/converters/ConverterContext.ts +55 -41
  79. package/src/sap/fe/core/converters/ManifestSettings.js +1 -1
  80. package/src/sap/fe/core/converters/ManifestSettings.ts +19 -5
  81. package/src/sap/fe/core/converters/ManifestWrapper.js +14 -4
  82. package/src/sap/fe/core/converters/ManifestWrapper.ts +21 -10
  83. package/src/sap/fe/core/converters/MetaModelConverter.js +402 -383
  84. package/src/sap/fe/core/converters/MetaModelConverter.ts +538 -338
  85. package/src/sap/fe/core/converters/TemplateConverter.js +4 -2
  86. package/src/sap/fe/core/converters/TemplateConverter.ts +18 -13
  87. package/src/sap/fe/core/converters/annotations/DataField.js +30 -28
  88. package/src/sap/fe/core/converters/annotations/DataField.ts +58 -35
  89. package/src/sap/fe/core/converters/common/AnnotationConverter.js +24 -23
  90. package/src/sap/fe/core/converters/controls/Common/Action.js +5 -4
  91. package/src/sap/fe/core/converters/controls/Common/Action.ts +34 -28
  92. package/src/sap/fe/core/converters/controls/Common/Chart.js +37 -33
  93. package/src/sap/fe/core/converters/controls/Common/Chart.ts +64 -46
  94. package/src/sap/fe/core/converters/controls/Common/DataVisualization.js +15 -4
  95. package/src/sap/fe/core/converters/controls/Common/DataVisualization.ts +31 -15
  96. package/src/sap/fe/core/converters/controls/Common/Form.js +6 -4
  97. package/src/sap/fe/core/converters/controls/Common/Form.ts +23 -11
  98. package/src/sap/fe/core/converters/controls/Common/KPI.js +5 -3
  99. package/src/sap/fe/core/converters/controls/Common/KPI.ts +17 -11
  100. package/src/sap/fe/core/converters/controls/Common/Table.js +197 -101
  101. package/src/sap/fe/core/converters/controls/Common/Table.ts +393 -182
  102. package/src/sap/fe/core/converters/controls/Common/table/StandardActions.js +4 -5
  103. package/src/sap/fe/core/converters/controls/Common/table/StandardActions.ts +38 -27
  104. package/src/sap/fe/core/converters/controls/ListReport/FilterBar.js +41 -11
  105. package/src/sap/fe/core/converters/controls/ListReport/FilterBar.ts +112 -45
  106. package/src/sap/fe/core/converters/controls/ListReport/VisualFilters.js +7 -7
  107. package/src/sap/fe/core/converters/controls/ListReport/VisualFilters.ts +18 -12
  108. package/src/sap/fe/core/converters/controls/ObjectPage/Avatar.js +1 -1
  109. package/src/sap/fe/core/converters/controls/ObjectPage/Avatar.ts +5 -4
  110. package/src/sap/fe/core/converters/controls/ObjectPage/HeaderFacet.js +1 -1
  111. package/src/sap/fe/core/converters/controls/ObjectPage/HeaderFacet.ts +19 -9
  112. package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.js +64 -63
  113. package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.ts +109 -100
  114. package/src/sap/fe/core/converters/helpers/Aggregation.js +12 -11
  115. package/src/sap/fe/core/converters/helpers/Aggregation.ts +35 -30
  116. package/src/sap/fe/core/converters/helpers/ConfigurableObject.js +4 -1
  117. package/src/sap/fe/core/converters/helpers/ConfigurableObject.ts +12 -9
  118. package/src/sap/fe/core/converters/helpers/DataFieldHelper.js +1 -1
  119. package/src/sap/fe/core/converters/helpers/DataFieldHelper.ts +1 -1
  120. package/src/sap/fe/core/converters/helpers/ID.js +1 -1
  121. package/src/sap/fe/core/converters/helpers/ID.ts +6 -6
  122. package/src/sap/fe/core/converters/helpers/InsightsHelpers.js +3 -3
  123. package/src/sap/fe/core/converters/helpers/InsightsHelpers.ts +11 -6
  124. package/src/sap/fe/core/converters/helpers/Key.js +2 -2
  125. package/src/sap/fe/core/converters/helpers/Key.ts +4 -4
  126. package/src/sap/fe/core/converters/helpers/SelectionVariantHelper.js +1 -1
  127. package/src/sap/fe/core/converters/helpers/SelectionVariantHelper.ts +2 -2
  128. package/src/sap/fe/core/converters/objectPage/FormMenuActions.js +21 -19
  129. package/src/sap/fe/core/converters/objectPage/FormMenuActions.ts +43 -31
  130. package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.js +1 -1
  131. package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.ts +16 -12
  132. package/src/sap/fe/core/converters/templates/ListReportConverter.js +8 -3
  133. package/src/sap/fe/core/converters/templates/ListReportConverter.ts +41 -21
  134. package/src/sap/fe/core/converters/templates/ObjectPageConverter.js +5 -3
  135. package/src/sap/fe/core/converters/templates/ObjectPageConverter.ts +24 -19
  136. package/src/sap/fe/core/designtime/AppComponent.designtime.js +3 -2
  137. package/src/sap/fe/core/designtime/AppComponent.designtime.ts +2 -1
  138. package/src/sap/fe/core/filter/DraftEditState.fragment.xml +1 -1
  139. package/src/sap/fe/core/formatters/CollaborationFormatter.js +4 -6
  140. package/src/sap/fe/core/formatters/CollaborationFormatter.ts +5 -4
  141. package/src/sap/fe/core/formatters/FPMFormatter.js +5 -13
  142. package/src/sap/fe/core/formatters/FPMFormatter.ts +11 -10
  143. package/src/sap/fe/core/formatters/FiscalFormat.js +1 -1
  144. package/src/sap/fe/core/formatters/FiscalFormat.ts +1 -1
  145. package/src/sap/fe/core/formatters/KPIFormatter.js +4 -7
  146. package/src/sap/fe/core/formatters/KPIFormatter.ts +3 -3
  147. package/src/sap/fe/core/formatters/StandardFormatter.js +4 -7
  148. package/src/sap/fe/core/formatters/StandardFormatter.ts +3 -3
  149. package/src/sap/fe/core/formatters/ValueFormatter.js +35 -6
  150. package/src/sap/fe/core/formatters/ValueFormatter.ts +31 -3
  151. package/src/sap/fe/core/fpm/manifest.json +1 -1
  152. package/src/sap/fe/core/helpers/AppStartupHelper.js +54 -33
  153. package/src/sap/fe/core/helpers/AppStartupHelper.ts +62 -41
  154. package/src/sap/fe/core/helpers/BindingToolkit.js +17 -3
  155. package/src/sap/fe/core/helpers/BindingToolkit.ts +28 -6
  156. package/src/sap/fe/core/helpers/ClassSupport.js +32 -13
  157. package/src/sap/fe/core/helpers/ClassSupport.ts +35 -15
  158. package/src/sap/fe/core/helpers/DeleteHelper.js +71 -61
  159. package/src/sap/fe/core/helpers/DeleteHelper.ts +125 -103
  160. package/src/sap/fe/core/helpers/DraftEditState.js +5 -3
  161. package/src/sap/fe/core/helpers/DraftEditState.ts +3 -1
  162. package/src/sap/fe/core/helpers/FPMHelper.js +43 -46
  163. package/src/sap/fe/core/helpers/FPMHelper.ts +50 -56
  164. package/src/sap/fe/core/helpers/MetaModelFunction.js +77 -53
  165. package/src/sap/fe/core/helpers/MetaModelFunction.ts +78 -57
  166. package/src/sap/fe/core/helpers/ModelHelper.js +10 -4
  167. package/src/sap/fe/core/helpers/ModelHelper.ts +12 -6
  168. package/src/sap/fe/core/helpers/PasteHelper.js +194 -7
  169. package/src/sap/fe/core/helpers/PasteHelper.ts +265 -13
  170. package/src/sap/fe/core/helpers/PromiseKeeper.js +66 -0
  171. package/src/sap/fe/core/helpers/PromiseKeeper.ts +56 -0
  172. package/src/sap/fe/core/helpers/SemanticKeyHelper.js +30 -19
  173. package/src/sap/fe/core/helpers/SemanticKeyHelper.ts +34 -22
  174. package/src/sap/fe/core/helpers/StableIdHelper.js +1 -1
  175. package/src/sap/fe/core/helpers/StableIdHelper.ts +7 -2
  176. package/src/sap/fe/core/helpers/StandardRecommendationHelper.js +26 -52
  177. package/src/sap/fe/core/helpers/StandardRecommendationHelper.ts +37 -63
  178. package/src/sap/fe/core/helpers/TitleHelper.js +1 -1
  179. package/src/sap/fe/core/helpers/TitleHelper.ts +17 -14
  180. package/src/sap/fe/core/helpers/TypeGuards.js +27 -3
  181. package/src/sap/fe/core/helpers/TypeGuards.ts +37 -7
  182. package/src/sap/fe/core/jsx-runtime/jsx-xml.js +48 -8
  183. package/src/sap/fe/core/jsx-runtime/jsx-xml.ts +40 -9
  184. package/src/sap/fe/core/library.js +1 -1
  185. package/src/sap/fe/core/messagebundle.properties +5 -2
  186. package/src/sap/fe/core/messagebundle_da.properties +1 -1
  187. package/src/sap/fe/core/messagebundle_en.properties +267 -2
  188. package/src/sap/fe/core/messagebundle_sl.properties +1 -1
  189. package/src/sap/fe/core/operationsHelper.js +2 -1
  190. package/src/sap/fe/core/operationsHelper.ts +1 -0
  191. package/src/sap/fe/core/services/EnvironmentServiceFactory.js +3 -3
  192. package/src/sap/fe/core/services/EnvironmentServiceFactory.ts +2 -2
  193. package/src/sap/fe/core/services/NavigationServiceFactory.js +2 -2
  194. package/src/sap/fe/core/services/NavigationServiceFactory.ts +3 -2
  195. package/src/sap/fe/core/services/RoutingServiceFactory.js +27 -14
  196. package/src/sap/fe/core/services/RoutingServiceFactory.ts +27 -14
  197. package/src/sap/fe/core/services/ShellServicesFactory.js +49 -12
  198. package/src/sap/fe/core/services/ShellServicesFactory.ts +62 -13
  199. package/src/sap/fe/core/services/SideEffectsServiceFactory.js +156 -82
  200. package/src/sap/fe/core/services/SideEffectsServiceFactory.ts +218 -100
  201. package/src/sap/fe/core/services/TelemetryServiceFactory.js +3 -3
  202. package/src/sap/fe/core/services/TelemetryServiceFactory.ts +6 -6
  203. package/src/sap/fe/core/services/ValueHelpHistoryServiceFactory.js +3 -2
  204. package/src/sap/fe/core/services/ValueHelpHistoryServiceFactory.ts +1 -1
  205. package/src/sap/fe/core/services/collaborativeDraftServiceFactory.js +1 -1
  206. package/src/sap/fe/core/services/collaborativeDraftServiceFactory.ts +2 -2
  207. package/src/sap/fe/core/services/view/TemplatingErrorPage.view.xml +1 -1
  208. package/src/sap/fe/core/templating/CommonFormatters.js +6 -3
  209. package/src/sap/fe/core/templating/CommonFormatters.ts +13 -12
  210. package/src/sap/fe/core/templating/CriticalityFormatters.js +2 -2
  211. package/src/sap/fe/core/templating/CriticalityFormatters.ts +37 -14
  212. package/src/sap/fe/core/templating/DataFieldFormatters.js +12 -11
  213. package/src/sap/fe/core/templating/DataFieldFormatters.ts +35 -24
  214. package/src/sap/fe/core/templating/DataModelPathHelper.js +22 -18
  215. package/src/sap/fe/core/templating/DataModelPathHelper.ts +61 -51
  216. package/src/sap/fe/core/templating/DisplayModeFormatter.js +1 -1
  217. package/src/sap/fe/core/templating/DisplayModeFormatter.ts +8 -3
  218. package/src/sap/fe/core/templating/EntityTypeHelper.js +1 -1
  219. package/src/sap/fe/core/templating/EntityTypeHelper.ts +1 -1
  220. package/src/sap/fe/core/templating/FieldControlHelper.js +3 -3
  221. package/src/sap/fe/core/templating/FieldControlHelper.ts +27 -8
  222. package/src/sap/fe/core/templating/FilterHelper.js +13 -10
  223. package/src/sap/fe/core/templating/FilterHelper.ts +80 -46
  224. package/src/sap/fe/core/templating/FilterTemplating.js +1 -1
  225. package/src/sap/fe/core/templating/FilterTemplating.ts +2 -2
  226. package/src/sap/fe/core/templating/PropertyFormatters.js +6 -8
  227. package/src/sap/fe/core/templating/PropertyFormatters.ts +11 -11
  228. package/src/sap/fe/core/templating/PropertyHelper.js +3 -3
  229. package/src/sap/fe/core/templating/PropertyHelper.ts +4 -4
  230. package/src/sap/fe/core/templating/SemanticObjectHelper.js +157 -13
  231. package/src/sap/fe/core/templating/SemanticObjectHelper.ts +182 -16
  232. package/src/sap/fe/core/templating/UIFormatters.js +23 -22
  233. package/src/sap/fe/core/templating/UIFormatters.ts +94 -66
  234. package/src/sap/fe/core/type/DateTimeWithTimezone.js +1 -1
  235. package/src/sap/fe/core/type/DateTimeWithTimezone.ts +2 -2
  236. package/src/sap/fe/core/type/EDM.js +1 -1
  237. package/src/sap/fe/core/type/EDM.ts +2 -2
  238. package/src/sap/fe/core/type/Email.js +1 -1
  239. package/src/sap/fe/core/type/Email.ts +1 -1
  240. package/src/sap/fe/core/type/FiscalDate.js +2 -2
  241. package/src/sap/fe/core/type/FiscalDate.ts +2 -2
@@ -8,13 +8,13 @@ import BusyLocker from "sap/fe/core/controllerextensions/BusyLocker";
8
8
  import { type NavigationToErrorPageResult } from "sap/fe/core/controllerextensions/MessageHandler";
9
9
  import type { BindContextParameters } from "sap/fe/core/controllerextensions/editFlow/draft";
10
10
  import draft from "sap/fe/core/controllerextensions/editFlow/draft";
11
+ import { getDraftOrActiveContext, isPathOnDraftRoot, resolvePath } from "sap/fe/core/controllerextensions/routing/ContextPathHelper";
11
12
  import NavigationReason from "sap/fe/core/controllerextensions/routing/NavigationReason";
12
13
  import type RouterProxy from "sap/fe/core/controllerextensions/routing/RouterProxy";
13
14
  import type { EnhanceWithUI5 } from "sap/fe/core/helpers/ClassSupport";
14
15
  import { defineUI5Class, extensible, finalExtension, methodOverride, publicExtension } from "sap/fe/core/helpers/ClassSupport";
15
16
  import EditState from "sap/fe/core/helpers/EditState";
16
17
  import ModelHelper from "sap/fe/core/helpers/ModelHelper";
17
- import SemanticKeyHelper from "sap/fe/core/helpers/SemanticKeyHelper";
18
18
  import type FclController from "sap/fe/core/rootView/Fcl.controller";
19
19
  import type { RoutingNavigationInfo, RoutingNavigationParameters, RoutingService } from "sap/fe/core/services/RoutingServiceFactory";
20
20
  import type Event from "sap/ui/base/Event";
@@ -25,13 +25,10 @@ import ControllerExtension from "sap/ui/core/mvc/ControllerExtension";
25
25
  import OverrideExecution from "sap/ui/core/mvc/OverrideExecution";
26
26
  import type Router from "sap/ui/core/routing/Router";
27
27
  import type Binding from "sap/ui/model/Binding";
28
- import Filter from "sap/ui/model/Filter";
29
- import FilterOperator from "sap/ui/model/FilterOperator";
30
28
  import type JSONModel from "sap/ui/model/json/JSONModel";
31
29
  import type Context from "sap/ui/model/odata/v4/Context";
32
30
  import type ODataContextBinding from "sap/ui/model/odata/v4/ODataContextBinding";
33
31
  import type ODataListBinding from "sap/ui/model/odata/v4/ODataListBinding";
34
- import type ODataMetaModel from "sap/ui/model/odata/v4/ODataMetaModel";
35
32
  import type ODataModel from "sap/ui/model/odata/v4/ODataModel";
36
33
  import type ODataPropertyBinding from "sap/ui/model/odata/v4/ODataPropertyBinding";
37
34
  import { getInvolvedDataModelObjects } from "../converters/MetaModelConverter";
@@ -124,20 +121,27 @@ class InternalRouting extends ControllerExtension {
124
121
 
125
122
  @publicExtension()
126
123
  @extensible(OverrideExecution.After)
127
- onBeforeBinding(oBindingContext: Context | null, _mParameters?: unknown): void {
124
+ onBeforeBinding(_bindingContext: Context | null, _mParameters?: unknown): void {}
125
+
126
+ beforeSetBindingContext(bindingContext: Context | null, _mParameters?: unknown): void {
127
+ this.onBeforeBinding(bindingContext, _mParameters);
128
128
  const oRouting = this.base.getView().getController().routing;
129
129
  if (oRouting && oRouting.onBeforeBinding) {
130
- oRouting.onBeforeBinding(oBindingContext);
130
+ oRouting.onBeforeBinding(bindingContext);
131
131
  }
132
132
  }
133
133
 
134
134
  @publicExtension()
135
135
  @extensible(OverrideExecution.After)
136
- onAfterBinding(oBindingContext: Context | null, _mParameters?: unknown): void {
137
- this._oAppComponent.getRootViewController().onContextBoundToView(oBindingContext);
136
+ onAfterBinding(bindingContext: Context | null, _mParameters?: unknown): void {
137
+ this._oAppComponent.getRootViewController().onContextBoundToView(bindingContext);
138
+ }
139
+
140
+ afterSetBindingContext(bindingContext: Context | null, _mParameters?: unknown): void {
141
+ this.onAfterBinding(bindingContext, _mParameters);
138
142
  const oRouting = this.base.getView().getController().routing;
139
143
  if (oRouting && oRouting.onAfterBinding) {
140
- oRouting.onAfterBinding(oBindingContext);
144
+ oRouting.onAfterBinding(bindingContext);
141
145
  }
142
146
  }
143
147
 
@@ -241,9 +245,103 @@ class InternalRouting extends ControllerExtension {
241
245
 
242
246
  parameters.FCLLevel = this._getFCLLevel();
243
247
 
248
+ // In case we're navigating from a table in a ListReport with draft, there's special handling for collaboration and tree table.
249
+ // We may not navigate to the context the user clicked on.
250
+ if (parameters.reason === NavigationReason.RowPress && context.isA<Context>("sap.ui.model.odata.v4.Context")) {
251
+ const model = context.getModel();
252
+ const metaModel = model.getMetaModel();
253
+
254
+ if (isPathOnDraftRoot(context.getPath(), metaModel)) {
255
+ const contextForNavigation =
256
+ (await this.getContextForNavigationWithCollaboration(context, parameters)) ??
257
+ (await this.getContextForNavigationFromTreeTable(context));
258
+
259
+ // Use another instance for navigation
260
+ if (contextForNavigation) {
261
+ context = contextForNavigation;
262
+ }
263
+ }
264
+ }
265
+
244
266
  return this._oRoutingService.navigateToContext(context, parameters, this._oView.getViewData(), this._oTargetInformation);
245
267
  }
246
268
 
269
+ /**
270
+ * Retrieves the context to use for navigation in case we're navigating to a draft instance from the LR and we're in a collaboration application.
271
+ *
272
+ * @param originalContext
273
+ * @param parameters
274
+ * @returns The context to use for navigation if it's different from the original context, null otherwise
275
+ */
276
+ private async getContextForNavigationWithCollaboration(
277
+ originalContext: Context,
278
+ parameters: RoutingNavigationParameters
279
+ ): Promise<Context | null> {
280
+ const model = originalContext.getModel();
281
+ const metaModel = model.getMetaModel();
282
+ if (ModelHelper.isCollaborationDraftSupported(metaModel) && originalContext.getProperty("IsActiveEntity") === false) {
283
+ // If we're in a collaboration application, and we're navigating to a draft instance from the LR,
284
+ // We want to check if the draft instance exists first. Otherwise we navigate to the original (draft) version.
285
+ const draftOrActiveContext = await getDraftOrActiveContext(originalContext);
286
+
287
+ if (draftOrActiveContext !== null && originalContext.getPath() !== draftOrActiveContext.getPath()) {
288
+ // Notify the user that we have navigated to the saved instance
289
+ const objectPath = getInvolvedDataModelObjects(metaModel.getMetaContext(originalContext.getPath()));
290
+ parameters.redirectedToNonDraft =
291
+ (objectPath.targetEntityType.annotations.UI?.HeaderInfo?.TypeName as unknown as string) ??
292
+ objectPath.targetEntityType.name;
293
+
294
+ if (this._oAppComponent.getRootViewController().isFclEnabled()) {
295
+ // FCL: replace the context in the list binding
296
+ const contextToReplaceWith = model.getKeepAliveContext(draftOrActiveContext.getPath());
297
+ originalContext.replaceWith(contextToReplaceWith);
298
+ } else {
299
+ // Fullscreen: trigger a refresh of the list binding
300
+ EditState.setEditStateDirty();
301
+ }
302
+
303
+ // Use the saved instance for navigation
304
+ return draftOrActiveContext;
305
+ }
306
+ }
307
+
308
+ // Use the original context
309
+ return null;
310
+ }
311
+
312
+ /**
313
+ * Retrieves the context to use for navigation in case we're navigating to an active instance from the LR and we're in a Tree table.
314
+ *
315
+ * @param originalContext
316
+ * @returns The context to use for navigation if it's different from the original context, null otherwise
317
+ */
318
+ private async getContextForNavigationFromTreeTable(originalContext: Context): Promise<Context | null> {
319
+ const parentBinding = originalContext.getBinding();
320
+ if (!parentBinding.isA<ODataListBinding>("sap.ui.model.odata.v4.ODataListBinding")) {
321
+ // The context doesn't belong to a list binding
322
+ return null;
323
+ }
324
+ const aggregation = parentBinding.getAggregation() as { hierarchyQualifier?: string } | undefined;
325
+ if (!aggregation?.hierarchyQualifier) {
326
+ // The context doesn't belong to a hierarchical list binding
327
+ return null;
328
+ }
329
+
330
+ if (originalContext.getProperty("IsActiveEntity") === true && originalContext.getProperty("HasDraftEntity") === true) {
331
+ // If we're in a TreeTable, and we're navigating to an active instance instance that has a draft,
332
+ // --> We try to navigate to the draft instance (if it still exists)
333
+ const draftOrActiveContext = await getDraftOrActiveContext(originalContext);
334
+
335
+ if (draftOrActiveContext !== null && originalContext.getPath() !== draftOrActiveContext.getPath()) {
336
+ // Use the draft instance for navigation
337
+ return draftOrActiveContext;
338
+ }
339
+ }
340
+
341
+ // Use the original context
342
+ return null;
343
+ }
344
+
247
345
  /**
248
346
  * Navigates backwards from a context.
249
347
  *
@@ -449,7 +547,7 @@ class InternalRouting extends ControllerExtension {
449
547
  * @returns A promise
450
548
  */
451
549
  async _bindDeferred(targetPath: string, navigationParameters: RoutingNavigationInfo): Promise<void> {
452
- this.onBeforeBinding(null, { editable: navigationParameters.bTargetEditable });
550
+ this.beforeSetBindingContext(null, { editable: navigationParameters.bTargetEditable });
453
551
 
454
552
  if (!navigationParameters.createOnNavigateParameters || navigationParameters.createOnNavigateParameters.mode === "Deferred") {
455
553
  // either the context shall be created in the target page (deferred Context) or it shall
@@ -477,7 +575,7 @@ class InternalRouting extends ControllerExtension {
477
575
  // remove the context to avoid showing old data
478
576
  this._setBindingContext(null);
479
577
 
480
- this.onAfterBinding(null);
578
+ this.afterSetBindingContext(null);
481
579
 
482
580
  return Promise.resolve();
483
581
  }
@@ -494,7 +592,7 @@ class InternalRouting extends ControllerExtension {
494
592
  */
495
593
  async _bindPageForEdit(targetPath: string, model: ODataModel, navigationParameters: RoutingNavigationInfo): Promise<void | Context> {
496
594
  try {
497
- const technicalPath: string = await this.resolvePath(targetPath, model, navigationParameters);
595
+ const technicalPath: string = await resolvePath(targetPath, model, this._oRoutingService, this._oRouter);
498
596
  if (technicalPath.includes("IsActiveEntity=true")) {
499
597
  // create context
500
598
  const activeContext = this._createContext(technicalPath, model);
@@ -529,7 +627,7 @@ class InternalRouting extends ControllerExtension {
529
627
  return Promise.resolve(this._bindPageToContext(null, model, navigationParameters));
530
628
  }
531
629
 
532
- return this.resolvePath(targetPath, model, navigationParameters)
630
+ return resolvePath(targetPath, model, this._oRoutingService, this._oRouter)
533
631
  .then((technicalPath: string): void => {
534
632
  return this._bindPageToPath(technicalPath, model, navigationParameters);
535
633
  })
@@ -544,296 +642,6 @@ class InternalRouting extends ControllerExtension {
544
642
  });
545
643
  }
546
644
 
547
- /**
548
- * Creates the filter to retrieve a context corresponding to a semantic path.
549
- *
550
- * @param semanticPath The semantic or technical path
551
- * @param semanticKeys The semantic or technical keys for the path
552
- * @param metaModel The instance of the metamodel
553
- * @returns The filter
554
- */
555
- createFilterFromPath(semanticPath: string, semanticKeys: string[], metaModel: ODataMetaModel): Filter | null {
556
- const unquoteAndDecode = function (value: string): string {
557
- if (value.indexOf("'") === 0 && value.lastIndexOf("'") === value.length - 1) {
558
- // Remove the quotes from the value and decode special chars
559
- value = decodeURIComponent(value.substring(1, value.length - 1));
560
- }
561
- return value;
562
- };
563
- const keyValues = semanticPath.substring(semanticPath.indexOf("(") + 1, semanticPath.length - 1).split(",");
564
-
565
- let finalKeys = semanticKeys;
566
- let finalKeyValues = keyValues;
567
- // If we have technical keys, IsActiveEntity will be present. We need to remove it as we're already adding them at the end.
568
- if (semanticKeys.includes("IsActiveEntity")) {
569
- finalKeys = semanticKeys.filter((singleKey) => !singleKey.includes("IsActiveEntity"));
570
- finalKeyValues = keyValues.filter((element) => !element.startsWith("IsActiveEntity"));
571
- }
572
-
573
- if (finalKeys.length != finalKeyValues.length) {
574
- return null;
575
- }
576
-
577
- const filteringCaseSensitive = ModelHelper.isFilteringCaseSensitive(metaModel);
578
- let filters: Filter[];
579
- if (finalKeys.length === 1) {
580
- // If this is a technical key, the equal is present because there's at least 2 parameters, a technical key and IsActiveEntity
581
- if (finalKeyValues[0].indexOf("=") > 0) {
582
- const keyPart = finalKeyValues[0].split("=");
583
- finalKeyValues[0] = keyPart[1];
584
- }
585
- // Take the first key value
586
- const keyValue = unquoteAndDecode(finalKeyValues[0]);
587
- filters = [
588
- new Filter({
589
- path: finalKeys[0],
590
- operator: FilterOperator.EQ,
591
- value1: keyValue,
592
- caseSensitive: filteringCaseSensitive
593
- })
594
- ];
595
- } else {
596
- const mKeyValues: Record<string, unknown> = {};
597
- // Create a map of all key values
598
- finalKeyValues.forEach(function (sKeyAssignment: string) {
599
- const aParts = sKeyAssignment.split("="),
600
- keyValue = unquoteAndDecode(aParts[1]);
601
-
602
- mKeyValues[aParts[0]] = keyValue;
603
- });
604
-
605
- let failed = false;
606
- filters = finalKeys.map(function (semanticKey) {
607
- const key = semanticKey,
608
- value = mKeyValues[key];
609
-
610
- if (value !== undefined) {
611
- return new Filter({
612
- path: key,
613
- operator: FilterOperator.EQ,
614
- value1: value,
615
- caseSensitive: filteringCaseSensitive
616
- });
617
- } else {
618
- failed = true;
619
- return new Filter({
620
- path: "XX"
621
- }); // will be ignored anyway since we return after
622
- }
623
- });
624
-
625
- if (failed) {
626
- return null;
627
- }
628
- }
629
-
630
- // Add a draft filter to make sure we take the draft entity if there is one
631
- // Or the active entity otherwise
632
- const draftFilter = new Filter({
633
- filters: [new Filter("IsActiveEntity", "EQ", false), new Filter("SiblingEntity/IsActiveEntity", "EQ", null)],
634
- and: false
635
- });
636
- filters.push(draftFilter);
637
-
638
- return new Filter(filters, true);
639
- }
640
-
641
- /**
642
- * Converts a path with semantic keys to a path with technical keys.
643
- *
644
- * @param pathWithParameters The path with semantic keys
645
- * @param model The model for the path
646
- * @param keys The semantic or technical keys for the path
647
- * @returns A Promise containing the path with technical keys if pathWithParameters could be interpreted as a technical path, null otherwise
648
- */
649
- async getTechnicalPathFromPath(pathWithParameters: string, model: ODataModel, keys: string[]): Promise<string | null> {
650
- const metaModel = model.getMetaModel();
651
- if (!keys || keys.length === 0) {
652
- // No semantic/technical keys
653
- return null;
654
- }
655
-
656
- // Create a set of filters corresponding to all keys
657
-
658
- const filter = this.createFilterFromPath(pathWithParameters, keys, metaModel);
659
- if (filter === null) {
660
- // Couldn't interpret the path as a semantic one
661
- return null;
662
- }
663
-
664
- // Retrieve the entity keys to add them in the $select query parameter
665
- const absolutePath = pathWithParameters.startsWith("/") ? pathWithParameters : `/${pathWithParameters}`;
666
- const metaContext = metaModel.getMetaContext(absolutePath);
667
- const objectPath = getInvolvedDataModelObjects(metaContext);
668
- const technicalKeys = objectPath.targetEntityType.keys.map((property) => property.name);
669
-
670
- // Load the corresponding object
671
- const listBinding = model.bindList(metaContext.getPath(), undefined, undefined, filter, {
672
- $select: technicalKeys.join(","),
673
- $$groupId: "$auto.Heroes"
674
- });
675
-
676
- const contexts = await listBinding.requestContexts(0, 2);
677
- if (contexts.length) {
678
- return contexts[0].getPath();
679
- } else {
680
- // No data could be loaded
681
- return null;
682
- }
683
- }
684
-
685
- /**
686
- * Refreshes a context.
687
- *
688
- * @param model The OData model
689
- * @param pathToReplaceWith The path to the new context
690
- * @param contextToRemove The initial context that is going to be replaced
691
- */
692
- refreshContext(model: ODataModel, pathToReplaceWith: string, contextToRemove: Context): void {
693
- const rootViewController = this._oAppComponent.getRootViewController();
694
- if (rootViewController.isFclEnabled()) {
695
- const contextToReplaceWith = model.getKeepAliveContext(pathToReplaceWith);
696
- contextToRemove.replaceWith(contextToReplaceWith);
697
- } else {
698
- EditState.setEditStateDirty();
699
- }
700
- }
701
-
702
- /**
703
- * Checks if a path is a root draft.
704
- *
705
- * @param path The path to test
706
- * @param metaModel The associated metadata model
707
- * @returns `true` if the path is a root path
708
- */
709
- checkDraftAvailability(path: string, metaModel: ODataMetaModel): boolean {
710
- const matches = /^[/]?(\w+)\([^/]+\)$/.exec(path);
711
- if (!matches) {
712
- return false;
713
- }
714
- // Get the entitySet name
715
- const entitySetPath = `/${matches[1]}`;
716
- // Check the entity set supports draft
717
- const draftRoot = metaModel.getObject(`${entitySetPath}@com.sap.vocabularies.Common.v1.DraftRoot`);
718
- return draftRoot ? true : false;
719
- }
720
-
721
- /**
722
- * Builds a path to navigate to from a path with SemanticKeys or technical keys.
723
- *
724
- * @param pathToResolve The path to be transformed
725
- * @param model The OData model
726
- * @param navigationParameter The parameter of the navigation
727
- * @returns String promise for the new path. If pathToResolve couldn't be interpreted as a semantic path, it is returned as is.
728
- */
729
- async resolvePath(pathToResolve: string, model: ODataModel, navigationParameter: RoutingNavigationInfo): Promise<string> {
730
- const metaModel = model.getMetaModel();
731
- const lastSemanticMapping = this._oRoutingService.getLastSemanticMapping();
732
- let currentHashNoParams = this._oRouter.getHashChanger().getHash().split("?")[0];
733
-
734
- if (currentHashNoParams?.lastIndexOf("/") === currentHashNoParams?.length - 1) {
735
- // Remove trailing '/'
736
- currentHashNoParams = currentHashNoParams.substring(0, currentHashNoParams.length - 1);
737
- }
738
-
739
- let rootEntityName = currentHashNoParams?.substring(0, currentHashNoParams.indexOf("("));
740
- if (rootEntityName.indexOf("/") === 0) {
741
- rootEntityName = rootEntityName.substring(1);
742
- }
743
- const isRootDraft = this.checkDraftAvailability(currentHashNoParams, metaModel),
744
- semanticKeys = isRootDraft
745
- ? (SemanticKeyHelper.getSemanticKeys(metaModel, rootEntityName) as { $PropertyPath: string }[])
746
- : undefined,
747
- isCollaborationEnabled = ModelHelper.isCollaborationDraftSupported(metaModel);
748
-
749
- /**
750
- * If the entity is draft enabled, we're in a collaboration application, and we're navigating to a draft from a list, we're treating it as a new path.
751
- * We want to check if the draft exists first, then we navigate on it if it does exist, otherwise we navigate to the saved version.
752
- */
753
- if (isRootDraft && isCollaborationEnabled && navigationParameter.reason === NavigationReason.RowPress) {
754
- const isActiveEntity = navigationParameter.useContext?.getProperty("IsActiveEntity") ?? true;
755
- if (!isActiveEntity) {
756
- return this.resolveCollaborationPath(pathToResolve, model, navigationParameter, semanticKeys, rootEntityName);
757
- }
758
- }
759
- /**
760
- * This is the 'normal' process.
761
- * If we don't have semantic keys, the path we have is technical and can be used as is.
762
- * If the path to resolve is the same as the semantic path, then we know is has been resolved previously and we can return the technical path
763
- * Otherwise, we need to evaluate the technical path, to set up the semantic mapping (if it's been resolved).
764
- */
765
- if (semanticKeys === undefined) {
766
- return pathToResolve;
767
- }
768
- if (lastSemanticMapping?.semanticPath === pathToResolve) {
769
- // This semantic path has been resolved previously
770
- return lastSemanticMapping.technicalPath;
771
- }
772
- const formattedSemanticKeys = semanticKeys.map((singleKey) => singleKey.$PropertyPath);
773
-
774
- // We need resolve the semantic path to get the technical keys
775
- const technicalPath = await this.getTechnicalPathFromPath(currentHashNoParams, model, formattedSemanticKeys);
776
-
777
- if (technicalPath && technicalPath !== pathToResolve) {
778
- // The semantic path was resolved (otherwise keep the original value for target)
779
- this._oRoutingService.setLastSemanticMapping({
780
- technicalPath: technicalPath,
781
- semanticPath: pathToResolve
782
- });
783
- return technicalPath;
784
- }
785
- return pathToResolve;
786
- }
787
-
788
- /**
789
- * Evaluate the path to navigate when we're in a collaboration application and navigating to a draft.
790
- * If the draft has been discarded, we change the path to the sibling element associated, otherwise we keep the same path.
791
- * We're not doing it outside of collaboration as it's adding a request during navigation!
792
- *
793
- * @param pathToResolve The path we're checking. If the draft exists, we return it as is, otherwise we return the sibling element associated
794
- * @param model The oData model
795
- * @param navigationParameter The parameter of the navigation
796
- * @param semanticKeys The semantic keys if we have semantic navigation, otherwise false
797
- * @param rootEntityName Name of the root entity
798
- * @returns The path to navigate to
799
- */
800
- async resolveCollaborationPath(
801
- pathToResolve: string,
802
- model: ODataModel,
803
- navigationParameter: RoutingNavigationInfo,
804
- semanticKeys: { $PropertyPath: string }[] | undefined,
805
- rootEntityName: string
806
- ): Promise<string> {
807
- const lastSemanticMapping = this._oRoutingService.getLastSemanticMapping();
808
- const metaModel = model.getMetaModel();
809
- const currentHashNoParams = this._oRouter.getHashChanger().getHash().split("?")[0];
810
- let formattedKeys: string[];
811
- const comparativePath = lastSemanticMapping?.technicalPath ?? pathToResolve;
812
- if (semanticKeys) {
813
- formattedKeys = semanticKeys.map((singleKey) => singleKey.$PropertyPath);
814
- } else {
815
- formattedKeys = metaModel.getObject(`/${rootEntityName}/$Type/$Key`);
816
- }
817
-
818
- const technicalPath = await this.getTechnicalPathFromPath(currentHashNoParams, model, formattedKeys);
819
- if (technicalPath === null) {
820
- return pathToResolve;
821
- }
822
- // Comparing path that was returned from the server with the one we have. If they are different, it means the draft doesn't exist.
823
- if (technicalPath !== comparativePath && navigationParameter.useContext) {
824
- if (lastSemanticMapping) {
825
- this._oRoutingService.setLastSemanticMapping({
826
- technicalPath: technicalPath,
827
- semanticPath: pathToResolve
828
- });
829
- }
830
- navigationParameter.redirectedToNonDraft =
831
- metaModel.getObject(`/${rootEntityName}/@com.sap.vocabularies.UI.v1.HeaderInfo`)?.TypeName ?? rootEntityName;
832
- this.refreshContext(model, technicalPath, navigationParameter.useContext);
833
- }
834
- return technicalPath;
835
- }
836
-
837
645
  /**
838
646
  * Sets the binding context for the page from a path.
839
647
  *
@@ -886,14 +694,14 @@ class InternalRouting extends ControllerExtension {
886
694
  } else if (oNavigationParameters.reason === NavigationReason.EditFlowAction) {
887
695
  // We have the same context but an editflow action happened (e.g. CancelDocument in sticky mode)
888
696
  // --> We need to call onBefore/AfterBinding to refresh the object page properly
889
- this.onBeforeBinding(oUseContext, {
697
+ this.beforeSetBindingContext(oUseContext, {
890
698
  editable: oNavigationParameters.bTargetEditable,
891
699
  listBinding: oUseContext.getBinding(),
892
700
  bPersistOPScroll: oNavigationParameters.bPersistOPScroll,
893
701
  reason: oNavigationParameters.reason,
894
702
  showPlaceholder: oNavigationParameters.bShowPlaceholder
895
703
  });
896
- this.onAfterBinding(oUseContext, { redirectedToNonDraft: oNavigationParameters?.redirectedToNonDraft });
704
+ this.afterSetBindingContext(oUseContext, { redirectedToNonDraft: oNavigationParameters?.redirectedToNonDraft });
897
705
  }
898
706
  } else if (sCurrentPath !== sTargetPath || oNavigationParameters.reason === NavigationReason.EditFlowAction) {
899
707
  // We need to create a new context for its path
@@ -918,8 +726,8 @@ class InternalRouting extends ControllerExtension {
918
726
  */
919
727
  _bindPageToContext(oContext: Context | null, oModel: ODataModel, oNavigationParameters: RoutingNavigationInfo): void {
920
728
  if (!oContext) {
921
- this.onBeforeBinding(null);
922
- this.onAfterBinding(null);
729
+ this.beforeSetBindingContext(null);
730
+ this.afterSetBindingContext(null);
923
731
  return;
924
732
  }
925
733
 
@@ -955,7 +763,7 @@ class InternalRouting extends ControllerExtension {
955
763
  }
956
764
 
957
765
  // Set the binding context with the proper before/after callbacks
958
- this.onBeforeBinding(oContext, {
766
+ this.beforeSetBindingContext(oContext, {
959
767
  editable: oNavigationParameters.bTargetEditable,
960
768
  listBinding: oParentListBinding,
961
769
  bPersistOPScroll: oNavigationParameters.bPersistOPScroll,
@@ -964,7 +772,7 @@ class InternalRouting extends ControllerExtension {
964
772
  });
965
773
 
966
774
  this._setBindingContext(oContext);
967
- this.onAfterBinding(oContext, { redirectedToNonDraft: oNavigationParameters?.redirectedToNonDraft });
775
+ this.afterSetBindingContext(oContext, { redirectedToNonDraft: oNavigationParameters?.redirectedToNonDraft });
968
776
  }
969
777
 
970
778
  /**