@sapui5/sap.fe.core 1.136.1 → 1.138.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 (154) 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 +76 -28
  4. package/src/sap/fe/core/ActionRuntime.ts +106 -30
  5. package/src/sap/fe/core/AppComponent.js +11 -1
  6. package/src/sap/fe/core/AppComponent.ts +10 -0
  7. package/src/sap/fe/core/AppStateHandler.js +9 -2
  8. package/src/sap/fe/core/AppStateHandler.ts +8 -2
  9. package/src/sap/fe/core/CommonUtils.js +15 -3
  10. package/src/sap/fe/core/CommonUtils.ts +13 -2
  11. package/src/sap/fe/core/PageController.controller.js +10 -0
  12. package/src/sap/fe/core/PageController.controller.ts +3 -0
  13. package/src/sap/fe/core/buildingBlocks/TraceInfo.js +3 -4
  14. package/src/sap/fe/core/buildingBlocks/TraceInfo.ts +2 -2
  15. package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockTemplateProcessor.js +3 -3
  16. package/src/sap/fe/core/buildingBlocks/templating/BuildingBlockTemplateProcessor.ts +2 -2
  17. package/src/sap/fe/core/controllerextensions/EditFlow.js +25 -12
  18. package/src/sap/fe/core/controllerextensions/EditFlow.ts +27 -16
  19. package/src/sap/fe/core/controllerextensions/InlineEditFlow.js +27 -41
  20. package/src/sap/fe/core/controllerextensions/InlineEditFlow.ts +27 -41
  21. package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.js +2 -1
  22. package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.ts +2 -1
  23. package/src/sap/fe/core/controllerextensions/InternalRouting.js +2 -1
  24. package/src/sap/fe/core/controllerextensions/InternalRouting.ts +1 -0
  25. package/src/sap/fe/core/controllerextensions/MessageHandler.js +4 -4
  26. package/src/sap/fe/core/controllerextensions/MessageHandler.ts +22 -15
  27. package/src/sap/fe/core/controllerextensions/Paginator.js +20 -5
  28. package/src/sap/fe/core/controllerextensions/Paginator.ts +19 -0
  29. package/src/sap/fe/core/controllerextensions/SideEffects.js +3 -2
  30. package/src/sap/fe/core/controllerextensions/SideEffects.ts +2 -2
  31. package/src/sap/fe/core/controllerextensions/collaboration/CollaborationCommon.js +2 -1
  32. package/src/sap/fe/core/controllerextensions/collaboration/CollaborationCommon.ts +1 -0
  33. package/src/sap/fe/core/controllerextensions/dialog/ODataStrictDialog.js +9 -5
  34. package/src/sap/fe/core/controllerextensions/dialog/ODataStrictDialog.tsx +8 -3
  35. package/src/sap/fe/core/controllerextensions/editFlow/NotApplicableContextDialog.js +4 -2
  36. package/src/sap/fe/core/controllerextensions/editFlow/NotApplicableContextDialog.tsx +7 -2
  37. package/src/sap/fe/core/controllerextensions/editFlow/TransactionHelper.js +178 -125
  38. package/src/sap/fe/core/controllerextensions/editFlow/TransactionHelper.ts +222 -174
  39. package/src/sap/fe/core/controllerextensions/editFlow/draft.js +5 -3
  40. package/src/sap/fe/core/controllerextensions/editFlow/draft.ts +2 -3
  41. package/src/sap/fe/core/controllerextensions/editFlow/operations/ODataOperation.js +39 -5
  42. package/src/sap/fe/core/controllerextensions/editFlow/operations/ODataOperation.ts +51 -11
  43. package/src/sap/fe/core/controllerextensions/editFlow/operations/ODataStrictHandling.js +16 -1
  44. package/src/sap/fe/core/controllerextensions/editFlow/operations/ODataStrictHandling.ts +17 -2
  45. package/src/sap/fe/core/controllerextensions/editFlow/operations/Operation.js +88 -1
  46. package/src/sap/fe/core/controllerextensions/editFlow/operations/Operation.ts +106 -7
  47. package/src/sap/fe/core/controllerextensions/editFlow/operations/OperationMessage.js +16 -1
  48. package/src/sap/fe/core/controllerextensions/editFlow/operations/OperationMessage.ts +15 -0
  49. package/src/sap/fe/core/controllerextensions/editFlow/operations/OperationParameters.js +25 -1
  50. package/src/sap/fe/core/controllerextensions/editFlow/operations/OperationParameters.ts +24 -0
  51. package/src/sap/fe/core/controllerextensions/messageHandler/messageHandling.js +11 -8
  52. package/src/sap/fe/core/controllerextensions/messageHandler/messageHandling.ts +13 -10
  53. package/src/sap/fe/core/controllerextensions/routing/RouterProxy.js +7 -4
  54. package/src/sap/fe/core/controllerextensions/routing/RouterProxy.ts +7 -3
  55. package/src/sap/fe/core/controls/DataWatcher.js +2 -2
  56. package/src/sap/fe/core/controls/DataWatcher.tsx +1 -1
  57. package/src/sap/fe/core/controls/Recommendations/ConfirmRecommendationDialog.js +11 -6
  58. package/src/sap/fe/core/controls/Recommendations/ConfirmRecommendationDialog.tsx +13 -9
  59. package/src/sap/fe/core/controls/inlineEditFlow/InlineEditExitDialog.js +144 -0
  60. package/src/sap/fe/core/controls/inlineEditFlow/{BeforeNavigationDialog.tsx → InlineEditExitDialog.tsx} +1 -1
  61. package/src/sap/fe/core/converters/ManifestSettings.js +1 -1
  62. package/src/sap/fe/core/converters/ManifestSettings.ts +4 -0
  63. package/src/sap/fe/core/converters/MetaModelConverter.js +3 -2
  64. package/src/sap/fe/core/converters/MetaModelConverter.ts +12 -4
  65. package/src/sap/fe/core/converters/controls/Common/Action.js +42 -5
  66. package/src/sap/fe/core/converters/controls/Common/Action.ts +42 -5
  67. package/src/sap/fe/core/converters/controls/Common/Chart.js +4 -1
  68. package/src/sap/fe/core/converters/controls/Common/Chart.ts +2 -1
  69. package/src/sap/fe/core/converters/controls/Common/Table.js +46 -13
  70. package/src/sap/fe/core/converters/controls/Common/Table.ts +50 -11
  71. package/src/sap/fe/core/converters/controls/Common/table/Columns.js +11 -10
  72. package/src/sap/fe/core/converters/controls/Common/table/Columns.ts +13 -1
  73. package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.js +2 -2
  74. package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.ts +2 -1
  75. package/src/sap/fe/core/fpm/manifest.json +1 -1
  76. package/src/sap/fe/core/helpers/DeleteHelper.js +9 -9
  77. package/src/sap/fe/core/helpers/DeleteHelper.ts +8 -9
  78. package/src/sap/fe/core/helpers/FPMHelper.js +2 -2
  79. package/src/sap/fe/core/helpers/FPMHelper.ts +1 -1
  80. package/src/sap/fe/core/helpers/ModelHelper.js +4 -4
  81. package/src/sap/fe/core/helpers/ModelHelper.ts +8 -4
  82. package/src/sap/fe/core/helpers/PasteHelper.js +2 -2
  83. package/src/sap/fe/core/helpers/PasteHelper.ts +1 -1
  84. package/src/sap/fe/core/library.js +33 -4
  85. package/src/sap/fe/core/library.ts +33 -2
  86. package/src/sap/fe/core/messagebundle.properties +18 -2
  87. package/src/sap/fe/core/messagebundle_ar.properties +3 -2
  88. package/src/sap/fe/core/messagebundle_bg.properties +2 -1
  89. package/src/sap/fe/core/messagebundle_ca.properties +2 -1
  90. package/src/sap/fe/core/messagebundle_cnr.properties +2 -1
  91. package/src/sap/fe/core/messagebundle_cs.properties +4 -3
  92. package/src/sap/fe/core/messagebundle_cy.properties +2 -1
  93. package/src/sap/fe/core/messagebundle_da.properties +2 -1
  94. package/src/sap/fe/core/messagebundle_de.properties +8 -7
  95. package/src/sap/fe/core/messagebundle_el.properties +2 -1
  96. package/src/sap/fe/core/messagebundle_en.properties +2 -1
  97. package/src/sap/fe/core/messagebundle_en_GB.properties +2 -1
  98. package/src/sap/fe/core/messagebundle_en_US_saprigi.properties +2 -1
  99. package/src/sap/fe/core/messagebundle_es.properties +5 -4
  100. package/src/sap/fe/core/messagebundle_es_MX.properties +2 -1
  101. package/src/sap/fe/core/messagebundle_et.properties +2 -1
  102. package/src/sap/fe/core/messagebundle_fi.properties +2 -1
  103. package/src/sap/fe/core/messagebundle_fr.properties +2 -1
  104. package/src/sap/fe/core/messagebundle_fr_CA.properties +2 -1
  105. package/src/sap/fe/core/messagebundle_hi.properties +2 -1
  106. package/src/sap/fe/core/messagebundle_hr.properties +2 -1
  107. package/src/sap/fe/core/messagebundle_hu.properties +2 -1
  108. package/src/sap/fe/core/messagebundle_id.properties +2 -1
  109. package/src/sap/fe/core/messagebundle_it.properties +2 -1
  110. package/src/sap/fe/core/messagebundle_iw.properties +2 -1
  111. package/src/sap/fe/core/messagebundle_ja.properties +3 -2
  112. package/src/sap/fe/core/messagebundle_kk.properties +2 -1
  113. package/src/sap/fe/core/messagebundle_ko.properties +2 -1
  114. package/src/sap/fe/core/messagebundle_lt.properties +2 -1
  115. package/src/sap/fe/core/messagebundle_lv.properties +2 -1
  116. package/src/sap/fe/core/messagebundle_mk.properties +2 -1
  117. package/src/sap/fe/core/messagebundle_ms.properties +2 -1
  118. package/src/sap/fe/core/messagebundle_nl.properties +2 -1
  119. package/src/sap/fe/core/messagebundle_no.properties +3 -2
  120. package/src/sap/fe/core/messagebundle_pl.properties +2 -1
  121. package/src/sap/fe/core/messagebundle_pt.properties +2 -1
  122. package/src/sap/fe/core/messagebundle_pt_PT.properties +2 -1
  123. package/src/sap/fe/core/messagebundle_ro.properties +2 -1
  124. package/src/sap/fe/core/messagebundle_ru.properties +2 -1
  125. package/src/sap/fe/core/messagebundle_sh.properties +2 -1
  126. package/src/sap/fe/core/messagebundle_sk.properties +2 -1
  127. package/src/sap/fe/core/messagebundle_sl.properties +2 -1
  128. package/src/sap/fe/core/messagebundle_sr.properties +2 -1
  129. package/src/sap/fe/core/messagebundle_sv.properties +2 -1
  130. package/src/sap/fe/core/messagebundle_th.properties +2 -1
  131. package/src/sap/fe/core/messagebundle_tr.properties +2 -1
  132. package/src/sap/fe/core/messagebundle_uk.properties +2 -1
  133. package/src/sap/fe/core/messagebundle_vi.properties +2 -1
  134. package/src/sap/fe/core/messagebundle_zh_CN.properties +2 -1
  135. package/src/sap/fe/core/messagebundle_zh_TW.properties +2 -1
  136. package/src/sap/fe/core/rootView/RootViewBaseController.js +6 -6
  137. package/src/sap/fe/core/rootView/RootViewBaseController.ts +5 -5
  138. package/src/sap/fe/core/services/RoutingServiceFactory.js +3 -3
  139. package/src/sap/fe/core/services/RoutingServiceFactory.ts +2 -2
  140. package/src/sap/fe/core/services/SideEffectsServiceFactory.js +4 -1
  141. package/src/sap/fe/core/services/SideEffectsServiceFactory.ts +3 -0
  142. package/src/sap/fe/core/services/collaborativeDraftServiceFactory.js +8 -2
  143. package/src/sap/fe/core/services/collaborativeDraftServiceFactory.ts +7 -1
  144. package/src/sap/fe/core/templating/EntitySetHelper.js +75 -90
  145. package/src/sap/fe/core/templating/EntitySetHelper.ts +92 -118
  146. package/src/sap/fe/core/templating/UIFormatters.js +3 -3
  147. package/src/sap/fe/core/templating/UIFormatters.ts +1 -2
  148. package/src/sap/fe/core/controllerextensions/editFlow/operations/facade.js +0 -81
  149. package/src/sap/fe/core/controllerextensions/editFlow/operations/facade.ts +0 -126
  150. package/src/sap/fe/core/controllerextensions/editFlow/operations.js +0 -10
  151. package/src/sap/fe/core/controllerextensions/editFlow/operations.ts +0 -2
  152. package/src/sap/fe/core/controls/inlineEditFlow/BeforeActionDialog.js +0 -68
  153. package/src/sap/fe/core/controls/inlineEditFlow/BeforeActionDialog.tsx +0 -52
  154. package/src/sap/fe/core/controls/inlineEditFlow/BeforeNavigationDialog.js +0 -144
@@ -1,4 +1,4 @@
1
- import type { Action, Action as EdmAction, EntitySet, NavigationProperty } from "@sap-ux/vocabularies-types";
1
+ import type { Action as EdmAction, EntitySet, NavigationProperty } from "@sap-ux/vocabularies-types";
2
2
  import type { LineItem } from "@sap-ux/vocabularies-types/vocabularies/UI";
3
3
  import Log from "sap/base/Log";
4
4
  import type AppComponent from "sap/fe/core/AppComponent";
@@ -12,11 +12,9 @@ import type MessageHandler from "sap/fe/core/controllerextensions/MessageHandler
12
12
  import type { BindContextParameters } from "sap/fe/core/controllerextensions/editFlow/draft";
13
13
  import draft from "sap/fe/core/controllerextensions/editFlow/draft";
14
14
  import UiModelConstants from "sap/fe/core/controllerextensions/editFlow/editFlowConstants";
15
- import operations from "sap/fe/core/controllerextensions/editFlow/operations";
16
15
  import sticky from "sap/fe/core/controllerextensions/editFlow/sticky";
17
16
  import messageHandling from "sap/fe/core/controllerextensions/messageHandler/messageHandling";
18
17
  import * as MetaModelConverter from "sap/fe/core/converters/MetaModelConverter";
19
- import { convertTypes } from "sap/fe/core/converters/MetaModelConverter";
20
18
  import { isDataFieldForAction } from "sap/fe/core/converters/annotations/DataField";
21
19
  import type { DeleteOption, DeleteParameters } from "sap/fe/core/helpers/DeleteHelper";
22
20
  import deleteHelper from "sap/fe/core/helpers/DeleteHelper";
@@ -26,7 +24,7 @@ import type { InternalModelContext } from "sap/fe/core/helpers/ModelHelper";
26
24
  import ModelHelper from "sap/fe/core/helpers/ModelHelper";
27
25
  import PromiseKeeper from "sap/fe/core/helpers/PromiseKeeper";
28
26
  import toES6Promise from "sap/fe/core/helpers/ToES6Promise";
29
- import { isNavigationProperty } from "sap/fe/core/helpers/TypeGuards";
27
+ import { isAction, isFulfilled, isNavigationProperty } from "sap/fe/core/helpers/TypeGuards";
30
28
  import FELibrary from "sap/fe/core/library";
31
29
  import Button from "sap/m/Button";
32
30
  import Dialog from "sap/m/Dialog";
@@ -54,6 +52,7 @@ import type ODataMetaModel from "sap/ui/model/odata/v4/ODataMetaModel";
54
52
  import type ODataModel from "sap/ui/model/odata/v4/ODataModel";
55
53
  import ActionRuntime from "../../ActionRuntime";
56
54
  import type { OperationResult } from "./operations/ODataOperation";
55
+ import ODataOperation from "./operations/ODataOperation";
57
56
  import Operation from "./operations/Operation";
58
57
  import actionHelper from "./operations/actionHelper";
59
58
 
@@ -94,6 +93,7 @@ export type TransactionDeleteParameters = DeleteParameters & {
94
93
  title?: string;
95
94
  noDialog?: boolean;
96
95
  };
96
+
97
97
  export type EditTransactionExecutionDetails = {
98
98
  existingDraftReused?: boolean; // true if an existing draft was returned, instead of returning a new one
99
99
  };
@@ -155,11 +155,12 @@ class TransactionHelper {
155
155
  }
156
156
 
157
157
  /**
158
- * Retrieves defatul values from the DefaultValue function.
158
+ * Retrieves default values from the DefaultValue function.
159
159
  * @param listBinding The list binding to be used for creation
160
+ * @param appComponent The app component
160
161
  * @returns A promise with an object containing the default values (or undefined if there's no default value function)
161
162
  */
162
- private async getDataFromDefaultValueFunction(listBinding: ODataListBinding): Promise<object | undefined> {
163
+ private async getDataFromDefaultValueFunction(listBinding: ODataListBinding, appComponent: AppComponent): Promise<object | undefined> {
163
164
  const model = listBinding.getModel();
164
165
  const metaModel = model.getMetaModel();
165
166
  const metaContext = metaModel.getMetaContext(listBinding.getResolvedPath() as string);
@@ -169,26 +170,64 @@ class TransactionHelper {
169
170
  ?.DefaultValuesFunction;
170
171
  const defaultFuncOnTargetEntitySet = (listBindingObjectPath.targetEntitySet as EntitySet | undefined)?.annotations.Common
171
172
  ?.DefaultValuesFunction;
172
- const defaultFunctionName = defaultFuncOnTargetObject ?? defaultFuncOnTargetEntitySet;
173
+ const defaultFunctionName = (defaultFuncOnTargetObject ?? defaultFuncOnTargetEntitySet)?.toString();
173
174
 
174
175
  if (!defaultFunctionName) {
175
176
  // No default value function
176
177
  return undefined;
177
178
  }
178
-
179
179
  const functionOnNavProp = isNavigationProperty(listBindingObjectPath.targetObject) && defaultFuncOnTargetObject !== undefined;
180
- const defaultFunctionContext = functionOnNavProp ? listBinding.getContext() : listBinding.getHeaderContext();
180
+ let defaultFunctionContext;
181
+
182
+ if (functionOnNavProp) {
183
+ // If the path is a deep navigation, derive the correct parent context
184
+ const bindingPath = listBinding.getPath();
185
+ const context = listBinding.getContext();
186
+ if (bindingPath?.startsWith("/")) {
187
+ defaultFunctionContext = context;
188
+ } else if (bindingPath && context && bindingPath.includes("/")) {
189
+ // Extract the first part of the navigation path (e.g., _ToHeader/_ToItems → _ToHeader)
190
+ const firstNav = bindingPath.split("/")[0];
191
+
192
+ // Build the full path to the correct context for the function call
193
+ const parentPath = `${context.getPath()}/${firstNav}`;
194
+
195
+ // Create a new binding context for this path
196
+ defaultFunctionContext = model.bindContext(parentPath).getBoundContext();
197
+ } else {
198
+ // Fallback to the current context if no navigation found
199
+ defaultFunctionContext = context;
200
+ }
201
+ } else {
202
+ // If not a navigation property, use the header context (root object page context)
203
+ defaultFunctionContext = listBinding.getHeaderContext();
204
+ }
205
+ //const defaultFunctionContext = functionOnNavProp ? listBinding.getContext() : listBinding.getHeaderContext();
181
206
  if (!defaultFunctionContext) {
182
207
  return undefined;
183
208
  }
184
- const defaultFunctionPath = `${metaModel.getMetaPath(defaultFunctionContext.getPath())}/${defaultFunctionName}`;
185
209
 
186
- const defaultFunctionObjectPath = MetaModelConverter.getInvolvedDataModelObjects(metaModel.getMetaContext(defaultFunctionPath));
187
- const defaultFunctionResult = (defaultFunctionObjectPath.targetObject as Action)?.isBound
188
- ? await operations.callBoundFunction(defaultFunctionName.toString(), defaultFunctionContext, model)
189
- : ((await operations.callFunctionImport(defaultFunctionName.toString(), model)) as ODataV4Context);
210
+ const operation =
211
+ Operation.getOperationFromName(defaultFunctionName, model, defaultFunctionContext) ??
212
+ Operation.getOperationFromName(defaultFunctionName, model);
213
+ if (!operation) {
214
+ return undefined;
215
+ }
190
216
 
191
- return defaultFunctionResult.getObject();
217
+ const isAnAction = isAction(operation);
218
+ const result = await new ODataOperation(
219
+ operation,
220
+ {
221
+ appComponent,
222
+ model,
223
+ contexts: isAnAction ? [defaultFunctionContext] : []
224
+ },
225
+ {
226
+ enhance$select: false,
227
+ groupId: isAnAction ? "functionGroup" : "functionImport"
228
+ }
229
+ ).execute();
230
+ return result.filter(isFulfilled)[0]?.value.boundContext.getObject();
192
231
  }
193
232
 
194
233
  /**
@@ -543,7 +582,7 @@ class TransactionHelper {
543
582
  let newDocumentContext: ODataV4Context | undefined;
544
583
  const initialData = parameters.data;
545
584
  if (!fromCopyPaste) {
546
- const defaultValueFunctionData = await this.getDataFromDefaultValueFunction(mainListBinding);
585
+ const defaultValueFunctionData = await this.getDataFromDefaultValueFunction(mainListBinding, appComponent);
547
586
  parameters.data = Object.assign({}, defaultValueFunctionData, parameters.data);
548
587
  }
549
588
  if (parameters.data) {
@@ -605,7 +644,7 @@ class TransactionHelper {
605
644
  * @param appComponent The appComponent
606
645
  * @param resourceModel The resource model to load text resources
607
646
  * @param messageHandler The message handler extension
608
- * @returns A Promise resolved once the documents are deleted
647
+ * @returns A promise resolved to true once the documents are deleted, or to false if the deletion was canceled by the user.
609
648
  */
610
649
  async deleteDocument(
611
650
  contexts: ODataV4Context | ODataV4Context[],
@@ -613,173 +652,186 @@ class TransactionHelper {
613
652
  appComponent: AppComponent,
614
653
  resourceModel: ResourceModel,
615
654
  messageHandler: MessageHandler
616
- ): Promise<void> {
655
+ ): Promise<boolean> {
617
656
  // delete document lock
618
657
  this.busyLock(appComponent);
619
658
 
620
659
  const contextsToDelete = Array.isArray(contexts) ? [...contexts] : [contexts];
621
660
  const firstContext = (mParameters.selectedContexts ?? contextsToDelete)[0];
622
661
 
623
- return new Promise<void>((resolve, reject) => {
624
- try {
625
- const draftEnabled = this._isDraftEnabled(mParameters.selectedContexts || contextsToDelete);
626
- const items: Control[] = [];
627
- let options: DeleteOption[] = [];
628
- let unSavedContext: Context | undefined;
629
- // items(texts) and options(checkBoxes and single default option) for confirm dialog.
630
- if (mParameters) {
631
- mParameters = getParameters(mParameters);
632
- mParameters.entitySetName = this.getCollectionNameFromContext(firstContext);
633
- if (!mParameters.numberOfSelectedContexts) {
634
- // non-Table
635
- if (draftEnabled) {
636
- // Check if 1 of the drafts is locked by another user
637
- const lockedContext = contextsToDelete.find((context) => {
638
- const contextData = context.getObject();
639
- return (
640
- contextData.IsActiveEntity === true &&
641
- contextData.HasDraftEntity === true &&
642
- contextData.DraftAdministrativeData &&
643
- contextData.DraftAdministrativeData.InProcessByUser &&
644
- !contextData.DraftAdministrativeData.DraftIsCreatedByMe
645
- );
662
+ try {
663
+ const draftEnabled = this._isDraftEnabled(mParameters.selectedContexts || contextsToDelete);
664
+ const items: Control[] = [];
665
+ let options: DeleteOption[] = [];
666
+ let unSavedContext: Context | undefined;
667
+ // items(texts) and options(checkBoxes and single default option) for confirm dialog.
668
+ if (mParameters) {
669
+ mParameters = getParameters(mParameters);
670
+ mParameters.entitySetName = this.getCollectionNameFromContext(firstContext);
671
+ if (!mParameters.numberOfSelectedContexts) {
672
+ // non-Table
673
+ if (draftEnabled) {
674
+ // Check if 1 of the drafts is locked by another user
675
+ const lockedContext = contextsToDelete.find((context) => {
676
+ const contextData = context.getObject();
677
+ return (
678
+ contextData.IsActiveEntity === true &&
679
+ contextData.HasDraftEntity === true &&
680
+ contextData.DraftAdministrativeData &&
681
+ contextData.DraftAdministrativeData.InProcessByUser &&
682
+ !contextData.DraftAdministrativeData.DraftIsCreatedByMe
683
+ );
684
+ });
685
+ if (lockedContext) {
686
+ // Show message box with the name of the locking user and return
687
+ await this.showDeleMessageLockedObjet(lockedContext, resourceModel);
688
+ return false; // No deletion happened
689
+ } else {
690
+ unSavedContext = contextsToDelete.find((context) => {
691
+ const { IsActiveEntity, HasDraftEntity, DraftAdministrativeData } = context.getObject() || {};
692
+ return IsActiveEntity === true && HasDraftEntity === true && !!DraftAdministrativeData?.InProcessByUser;
646
693
  });
647
- if (lockedContext) {
648
- // Show message box with the name of the locking user and return
649
- const lockingUserName = lockedContext.getObject().DraftAdministrativeData.InProcessByUser;
650
- MessageBox.show(
651
- resourceModel.getText("C_TRANSACTION_HELPER_CONFIRM_DELETE_WITH_SINGLE_OBJECT_LOCKED", [
652
- lockingUserName
653
- ]),
654
- {
655
- title: resourceModel.getText("C_COMMON_DELETE"),
656
- onClose: reject
657
- }
658
- );
659
- return;
660
- } else {
661
- unSavedContext = contextsToDelete.find((context) => {
662
- const { IsActiveEntity, HasDraftEntity, DraftAdministrativeData } = context.getObject() || {};
663
- return IsActiveEntity === true && HasDraftEntity === true && !!DraftAdministrativeData?.InProcessByUser;
664
- });
665
- }
666
694
  }
667
- let nonTableTxt = "";
668
- if (unSavedContext) {
669
- const unSavedContextUser = unSavedContext.getObject().DraftAdministrativeData.InProcessByUser;
695
+ }
696
+ let nonTableTxt = "";
697
+ if (unSavedContext) {
698
+ const unSavedContextUser = unSavedContext.getObject().DraftAdministrativeData.InProcessByUser;
699
+ nonTableTxt = resourceModel.getText(
700
+ "C_TRANSACTION_HELPER_CONFIRM_DELETE_WITH_UNSAVED_CHANGES",
701
+ [unSavedContextUser],
702
+ mParameters.entitySetName
703
+ );
704
+ } else if (mParameters.title) {
705
+ if (mParameters.description) {
670
706
  nonTableTxt = resourceModel.getText(
671
- "C_TRANSACTION_HELPER_CONFIRM_DELETE_WITH_UNSAVED_CHANGES",
672
- [unSavedContextUser],
707
+ "C_TRANSACTION_HELPER_CONFIRM_DELETE_WITH_OBJECTINFO",
708
+ [mParameters.title, mParameters.description],
673
709
  mParameters.entitySetName
674
710
  );
675
- } else if (mParameters.title) {
676
- if (mParameters.description) {
677
- nonTableTxt = resourceModel.getText(
678
- "C_TRANSACTION_HELPER_CONFIRM_DELETE_WITH_OBJECTINFO",
679
- [mParameters.title, mParameters.description],
680
- mParameters.entitySetName
681
- );
682
- } else {
683
- nonTableTxt = resourceModel.getText(
684
- "C_TRANSACTION_HELPER_CONFIRM_DELETE_WITH_OBJECTTITLE_ONLY",
685
- [mParameters.title],
686
- mParameters.entitySetName
687
- );
688
- }
689
711
  } else {
690
712
  nonTableTxt = resourceModel.getText(
691
- "C_TRANSACTION_HELPER_CONFIRM_DELETE_WITH_OBJECTTITLE_SINGULAR",
692
- undefined,
713
+ "C_TRANSACTION_HELPER_CONFIRM_DELETE_WITH_OBJECTTITLE_ONLY",
714
+ [mParameters.title],
693
715
  mParameters.entitySetName
694
716
  );
695
717
  }
696
- options.push({
697
- type: DeleteOptionTypes.deletableContexts,
698
- contexts: contextsToDelete,
699
- text: nonTableTxt,
700
- selected: true,
701
- control: DeleteDialogContentControl.TEXT
702
- });
703
718
  } else {
704
- // Table
705
- let totalDeletable = contextsToDelete.length;
706
-
707
- if (draftEnabled) {
708
- totalDeletable +=
709
- (mParameters.draftsWithNonDeletableActive?.length ?? 0) +
710
- (mParameters.draftsWithDeletableActive?.length ?? 0) +
711
- (mParameters.unSavedContexts?.length ?? 0);
712
- deleteHelper.updateDraftOptionsForDeletableTexts(
713
- mParameters,
714
- contextsToDelete,
715
- totalDeletable,
716
- resourceModel,
717
- items,
718
- options
719
- );
720
- } else {
721
- const nonDeletableText = deleteHelper.getNonDeletableText(mParameters, totalDeletable, resourceModel);
722
- if (nonDeletableText) {
723
- items.push(nonDeletableText);
724
- }
725
- }
726
-
727
- const optionsDeletableTexts = deleteHelper.getOptionsForDeletableTexts(
719
+ nonTableTxt = resourceModel.getText(
720
+ "C_TRANSACTION_HELPER_CONFIRM_DELETE_WITH_OBJECTTITLE_SINGULAR",
721
+ undefined,
722
+ mParameters.entitySetName
723
+ );
724
+ }
725
+ options.push({
726
+ type: DeleteOptionTypes.deletableContexts,
727
+ contexts: contextsToDelete,
728
+ text: nonTableTxt,
729
+ selected: true,
730
+ control: DeleteDialogContentControl.TEXT
731
+ });
732
+ } else {
733
+ // Table
734
+ let totalDeletable = contextsToDelete.length;
735
+
736
+ if (draftEnabled) {
737
+ totalDeletable +=
738
+ (mParameters.draftsWithNonDeletableActive?.length ?? 0) +
739
+ (mParameters.draftsWithDeletableActive?.length ?? 0) +
740
+ (mParameters.unSavedContexts?.length ?? 0);
741
+ deleteHelper.updateDraftOptionsForDeletableTexts(
728
742
  mParameters,
729
743
  contextsToDelete,
730
- resourceModel
744
+ totalDeletable,
745
+ resourceModel,
746
+ items,
747
+ options
731
748
  );
732
- options = [...options, ...optionsDeletableTexts];
749
+ } else {
750
+ const nonDeletableText = deleteHelper.getNonDeletableText(mParameters, totalDeletable, resourceModel);
751
+ if (nonDeletableText) {
752
+ items.push(nonDeletableText);
753
+ }
733
754
  }
755
+
756
+ const optionsDeletableTexts = deleteHelper.getOptionsForDeletableTexts(mParameters, contextsToDelete, resourceModel);
757
+ options = [...options, ...optionsDeletableTexts];
734
758
  }
759
+ }
735
760
 
736
- const commonBinding = firstContext.getBinding() as Binding;
737
- let bindingType: "Tree" | "Analytical" | undefined;
738
- if (commonBinding.isA<ODataListBinding>("sap.ui.model.odata.v4.ODataListBinding")) {
739
- if (this.isListBindingHierarchical(commonBinding)) {
740
- bindingType = "Tree";
741
- } else if (this.isListBindingAnalytical(commonBinding)) {
742
- bindingType = "Analytical";
743
- }
761
+ const commonBinding = firstContext.getBinding() as Binding;
762
+ let bindingType: "Tree" | "Analytical" | undefined;
763
+ if (commonBinding.isA<ODataListBinding>("sap.ui.model.odata.v4.ODataListBinding")) {
764
+ if (this.isListBindingHierarchical(commonBinding)) {
765
+ bindingType = "Tree";
766
+ } else if (this.isListBindingAnalytical(commonBinding)) {
767
+ bindingType = "Analytical";
744
768
  }
769
+ }
745
770
 
746
- // Content of Delete Dialog
747
- deleteHelper.updateContentForDeleteDialog(options, items);
748
- const fnConfirm = async (): Promise<void> => {
749
- messageHandling.removeBoundTransitionMessages();
750
- this.busyLock(appComponent);
771
+ // Confirm the deletion if needed
772
+ deleteHelper.updateContentForDeleteDialog(options, items);
773
+ if (mParameters.noDialog !== true && mParameters.silentMode !== true) {
774
+ const confirmed = await this.showDeleteConfirmationDialog(items, mParameters, resourceModel);
775
+ if (!confirmed) {
776
+ return false;
777
+ }
778
+ }
751
779
 
752
- try {
753
- await deleteHelper.deleteConfirmHandler(
754
- options,
755
- mParameters,
756
- messageHandler,
757
- resourceModel,
758
- appComponent,
759
- draftEnabled,
760
- bindingType
761
- );
762
- resolve();
763
- } catch (oError: unknown) {
764
- reject();
765
- } finally {
766
- this.busyUnlock(appComponent);
767
- }
768
- };
780
+ // Proceed with the deletion
781
+ messageHandling.removeBoundTransitionMessages();
782
+ await deleteHelper.deleteConfirmHandler(
783
+ options,
784
+ mParameters,
785
+ messageHandler,
786
+ resourceModel,
787
+ appComponent,
788
+ draftEnabled,
789
+ bindingType
790
+ );
769
791
 
770
- const dialog = this.createDeleteDialog(items, mParameters, resourceModel, fnConfirm, reject);
792
+ return true;
793
+ } finally {
794
+ // delete document unlock
795
+ this.busyUnlock(appComponent);
796
+ }
797
+ }
771
798
 
772
- if (mParameters.noDialog === true || mParameters.silentMode === true) {
773
- fnConfirm();
774
- } else {
775
- dialog.addStyleClass("sapUiContentPadding");
776
- dialog.open();
777
- }
778
- } finally {
779
- // delete document unlock
780
- this.busyUnlock(appComponent);
799
+ /**
800
+ * Shows an error message when trying to delee a locked object.
801
+ * @param lockedContext
802
+ * @param resourceModel
803
+ * @returns A promise that resolves when the message box is closed
804
+ */
805
+ private async showDeleMessageLockedObjet(lockedContext: ODataV4Context, resourceModel: ResourceModel): Promise<void> {
806
+ const lockingUserName = lockedContext.getObject().DraftAdministrativeData.InProcessByUser;
807
+ const promiseKeeper = new PromiseKeeper<void>();
808
+ MessageBox.show(resourceModel.getText("C_TRANSACTION_HELPER_CONFIRM_DELETE_WITH_SINGLE_OBJECT_LOCKED", [lockingUserName]), {
809
+ title: resourceModel.getText("C_COMMON_DELETE"),
810
+ onClose: () => {
811
+ promiseKeeper.resolve();
781
812
  }
782
813
  });
814
+
815
+ return promiseKeeper.promise;
816
+ }
817
+
818
+ /**
819
+ * Shows the dialog to confirm the object deletion.
820
+ * @param items
821
+ * @param parameters
822
+ * @param resourceModel
823
+ * @returns True if the user accepted the deletion, false otherwise
824
+ */
825
+ private async showDeleteConfirmationDialog(
826
+ items: Control[],
827
+ parameters: Partial<{ parentControl: Control | undefined; entitySetName: string }>,
828
+ resourceModel: ResourceModel
829
+ ): Promise<boolean> {
830
+ const promiseKeeper = new PromiseKeeper<boolean>();
831
+ const dialog = this.createDeleteDialog(items, parameters, resourceModel, promiseKeeper);
832
+ dialog.addStyleClass("sapUiContentPadding");
833
+ dialog.open();
834
+ return promiseKeeper.promise;
783
835
  }
784
836
 
785
837
  /**
@@ -789,16 +841,14 @@ class TransactionHelper {
789
841
  * @param parameters.parentControl Parent control of the delete button if any
790
842
  * @param parameters.entitySetName Name of the current entitySet
791
843
  * @param resourceModel The resource model to load text resources
792
- * @param fnConfirm Function executed upon the validation of the deletion
793
- * @param fnReject Function executed if the dialog is closed via Cancel or Escape button
844
+ * @param promiseKeeper
794
845
  * @returns The created delete confirmation dialog
795
846
  */
796
847
  createDeleteDialog(
797
848
  items: Control[],
798
849
  parameters: Partial<{ parentControl: Control | undefined; entitySetName: string }>,
799
850
  resourceModel: ResourceModel,
800
- fnConfirm: Function,
801
- fnReject: Function
851
+ promiseKeeper: PromiseKeeper<boolean>
802
852
  ): Dialog {
803
853
  let dialogConfirmed = false;
804
854
  const vBox = new VBox({ items: items });
@@ -820,7 +870,6 @@ class TransactionHelper {
820
870
  press: function (): void {
821
871
  dialogConfirmed = true;
822
872
  dialog.close();
823
- fnConfirm();
824
873
  }
825
874
  }),
826
875
  endButton: new Button({
@@ -832,9 +881,7 @@ class TransactionHelper {
832
881
  afterClose: function (): void {
833
882
  dialog.destroy();
834
883
  // if dialog is closed unconfirmed (e.g. via "Cancel" or Escape button), ensure to reject promise
835
- if (!dialogConfirmed) {
836
- fnReject();
837
- }
884
+ promiseKeeper.resolve(dialogConfirmed);
838
885
  }
839
886
  });
840
887
  return dialog;
@@ -1146,14 +1193,8 @@ class TransactionHelper {
1146
1193
  let oResult: PromiseSettledResult<OperationResult>[];
1147
1194
  if (contextToProcess && mParameters.contexts) {
1148
1195
  const contexts = Array.isArray(mParameters.contexts) ? mParameters.contexts : [mParameters.contexts]; // Ensure that contexts is an array (for static actions it's not an we need to fix it)
1149
-
1150
- const metaModel = oModel.getMetaModel(),
1151
- actionPath = `${metaModel.getMetaPath(contexts[0].getPath())}/${sActionName}`,
1152
- boundAction = metaModel.createBindingContext(`${actionPath}/@$ui5.overload/0`)!;
1153
-
1154
- const convertedTypes = convertTypes(oModel.getMetaModel());
1155
- const convertedAction = convertedTypes.resolvePath<EdmAction | undefined>(boundAction.getPath()).target;
1156
- if (!convertedAction) {
1196
+ const convertedAction = Operation.getOperationFromName(sActionName, oModel, contexts[0]);
1197
+ if (!isAction(convertedAction)) {
1157
1198
  throw new Error("Unknown bound action");
1158
1199
  }
1159
1200
  oResult = await new Operation(appComponent, oModel, convertedAction, {
@@ -1194,17 +1235,21 @@ class TransactionHelper {
1194
1235
  defaultValuesExtensionFunction: mParameters.defaultValuesExtensionFunction
1195
1236
  }).execute();
1196
1237
  } else {
1197
- oResult = await operations.callActionImport(sActionName, oModel, appComponent, {
1238
+ const convertedActionImport = Operation.getOperationFromName(sActionName, oModel);
1239
+ if (!convertedActionImport || isAction(convertedActionImport)) {
1240
+ throw new Error("Unknown action import");
1241
+ }
1242
+ oResult = await new Operation(appComponent, oModel, convertedActionImport.action, {
1198
1243
  parameterValues: mParameters.parameterValues as Record<string, string | boolean | number | MultiValueFieldItem[]>[],
1199
1244
  label: mParameters.label,
1200
1245
  skipParameterDialog: mParameters.skipParameterDialog,
1201
1246
  bindingParameters: mParameters.bindingParameters,
1202
1247
  entitySetName: mParameters.entitySetName,
1203
1248
  oDataEvents: {
1204
- onODataSubmit: () => {
1249
+ onODataSubmit: (): void => {
1205
1250
  this.busyLock(appComponent);
1206
1251
  },
1207
- onODataResponse: () => {
1252
+ onODataResponse: (): void => {
1208
1253
  this.busyUnlock(appComponent);
1209
1254
  }
1210
1255
  },
@@ -1213,7 +1258,7 @@ class TransactionHelper {
1213
1258
  },
1214
1259
  messageHandler: messageHandler,
1215
1260
  view: mParameters.view as FEView
1216
- });
1261
+ }).execute();
1217
1262
  }
1218
1263
 
1219
1264
  if (messageHandler) {
@@ -1331,6 +1376,7 @@ class TransactionHelper {
1331
1376
 
1332
1377
  // Create the content of the popover
1333
1378
  const title = new Text({
1379
+ id: "DraftDiscardMessage",
1334
1380
  text: resourceModel.getText("C_TRANSACTION_HELPER_DRAFT_DISCARD_MESSAGE")
1335
1381
  });
1336
1382
  const confirmButton = new Button({
@@ -1342,6 +1388,7 @@ class TransactionHelper {
1342
1388
  confirmationPopover.close();
1343
1389
  }
1344
1390
  });
1391
+ confirmButton.addAriaLabelledBy(title);
1345
1392
  confirmationPopover.addContent(new VBox({ items: [title, confirmButton] }));
1346
1393
 
1347
1394
  // Attach handler
@@ -1349,6 +1396,7 @@ class TransactionHelper {
1349
1396
  confirmationPopover.setInitialFocus(confirmButton);
1350
1397
  });
1351
1398
  confirmationPopover.attachAfterClose(() => {
1399
+ confirmationPopover.destroyContent();
1352
1400
  cancelButton.setEnabled(true);
1353
1401
  if (confirmationPopover.data("continueDiscard")) {
1354
1402
  resolve();