@sapui5/sap.fe.core 1.124.0 → 1.124.2

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 (34) hide show
  1. package/package.json +1 -1
  2. package/src/sap/fe/core/.library +1 -1
  3. package/src/sap/fe/core/buildingBlocks/BuildingBlockBase.js +15 -4
  4. package/src/sap/fe/core/buildingBlocks/BuildingBlockBase.ts +10 -0
  5. package/src/sap/fe/core/controllerextensions/EditFlow.js +2 -1
  6. package/src/sap/fe/core/controllerextensions/EditFlow.ts +1 -0
  7. package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.js +2 -2
  8. package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.ts +1 -1
  9. package/src/sap/fe/core/controllerextensions/Routing.js +5 -3
  10. package/src/sap/fe/core/controllerextensions/Routing.ts +4 -2
  11. package/src/sap/fe/core/controllerextensions/SideEffects.js +1 -1
  12. package/src/sap/fe/core/controllerextensions/SideEffects.ts +5 -5
  13. package/src/sap/fe/core/controllerextensions/editFlow/draftDataLossPopup.js +54 -40
  14. package/src/sap/fe/core/controllerextensions/editFlow/draftDataLossPopup.ts +62 -38
  15. package/src/sap/fe/core/controllerextensions/editFlow/operations/facade.js +2 -2
  16. package/src/sap/fe/core/controllerextensions/editFlow/operations/facade.ts +1 -1
  17. package/src/sap/fe/core/converters/controls/ListReport/FilterBar.js +1 -1
  18. package/src/sap/fe/core/converters/controls/ListReport/FilterBar.ts +4 -0
  19. package/src/sap/fe/core/fpm/manifest.json +1 -1
  20. package/src/sap/fe/core/helpers/BindingToolkit.js +17 -5
  21. package/src/sap/fe/core/helpers/BindingToolkit.ts +8 -1
  22. package/src/sap/fe/core/helpers/ModelHelper.js +9 -1
  23. package/src/sap/fe/core/helpers/ModelHelper.ts +7 -0
  24. package/src/sap/fe/core/library.js +1 -1
  25. package/src/sap/fe/core/services/CacheHandlerServiceFactory.js +10 -6
  26. package/src/sap/fe/core/services/CacheHandlerServiceFactory.ts +20 -5
  27. package/src/sap/fe/core/services/EnvironmentServiceFactory.js +2 -2
  28. package/src/sap/fe/core/services/EnvironmentServiceFactory.ts +1 -1
  29. package/src/sap/fe/core/services/RoutingServiceFactory.js +2 -2
  30. package/src/sap/fe/core/services/RoutingServiceFactory.ts +8 -1
  31. package/src/sap/fe/core/services/TemplatedViewServiceFactory.js +3 -3
  32. package/src/sap/fe/core/services/TemplatedViewServiceFactory.ts +7 -2
  33. package/src/sap/fe/core/templating/UIFormatters.js +17 -9
  34. package/src/sap/fe/core/templating/UIFormatters.ts +26 -14
@@ -1,6 +1,7 @@
1
1
  import Log from "sap/base/Log";
2
2
  import type PageController from "sap/fe/core/PageController";
3
3
  import EditState from "sap/fe/core/helpers/EditState";
4
+ import ModelHelper from "sap/fe/core/helpers/ModelHelper";
4
5
  import type ObjectPageControllerController from "sap/fe/templates/ObjectPage/ObjectPageController.controller";
5
6
  import type ODataV4Context from "sap/ui/model/odata/v4/Context";
6
7
  import DraftDataLossDialogBlock from "../../controls/DataLossOrDraftDiscard/DraftDataLossDialog.block";
@@ -12,7 +13,7 @@ enum NavigationType {
12
13
  ForwardNavigation = "ForwardNavigation"
13
14
  }
14
15
 
15
- /* Enum types for the dataloss dialog options */
16
+ /* Enum types for the data loss dialog options */
16
17
  enum DraftDataLossOptions {
17
18
  Save = "draftDataLossOptionSave",
18
19
  Keep = "draftDataLossOptionKeep",
@@ -24,7 +25,7 @@ type DraftAdministrativeData = {
24
25
  LastChangeDateTime: Date;
25
26
  };
26
27
 
27
- /*Create the dataloss dialog*/
28
+ /*Create the data loss dialog*/
28
29
  const dataLossDialog = new DraftDataLossDialogBlock({});
29
30
 
30
31
  /**
@@ -34,20 +35,21 @@ const dataLossDialog = new DraftDataLossDialogBlock({});
34
35
  * @returns Boolean value with true or false to silently keep the draft
35
36
  */
36
37
  function silentlyKeepDraftOnForwardNavigation(pageController: PageController): boolean {
37
- let rbSilentlyKeep = false;
38
+ let rbSilentlyKeep;
38
39
  const oManifest = pageController.getAppComponent().getManifestEntry("sap.fe");
39
40
  rbSilentlyKeep = oManifest?.app?.silentlyKeepDraftOnForwardNavigation || false;
40
41
  return rbSilentlyKeep;
41
42
  }
42
43
 
43
44
  /**
44
- * Logic to process the fcl mode.
45
+ * Logic to process the FCL mode.
45
46
  *
46
47
  * @param draftAdminData Admin data
47
48
  * @param fnCancelFunction The cancel function
48
49
  * @param oController The current controller referenced
49
- * @param processFunctionForDrafts The functon to process the handler
50
+ * @param processFunctionForDrafts The function to process the handler
50
51
  * @param bSkipBindingToView The optional parameter to skip the binding to the view
52
+ * @param context The context to be used for the draft operation
51
53
  * @returns Nothing
52
54
  */
53
55
  async function processFclMode(
@@ -55,7 +57,8 @@ async function processFclMode(
55
57
  fnCancelFunction: Function,
56
58
  oController: PageController,
57
59
  processFunctionForDrafts: Function,
58
- bSkipBindingToView?: boolean
60
+ bSkipBindingToView?: boolean,
61
+ context?: ODataV4Context
59
62
  ): Promise<void> {
60
63
  // The application is running in FCL mode so in this case we fall back to
61
64
  // the old logic since the dirty state handling is not properly working
@@ -69,7 +72,8 @@ async function processFclMode(
69
72
  processFunctionForDrafts,
70
73
  fnCancelFunction,
71
74
  oController,
72
- bSkipBindingToView
75
+ bSkipBindingToView,
76
+ context
73
77
  )
74
78
  );
75
79
  } else {
@@ -83,10 +87,11 @@ async function processFclMode(
83
87
  * @param draftAdminData Admin data
84
88
  * @param fnCancelFunction The cancel function
85
89
  * @param oController The current controller referenced
86
- * @param processFunctionForDrafts The functon to process the handler
90
+ * @param processFunctionForDrafts The function to process the handler
87
91
  * @param navigationType The navigation type for which the function should be called
88
92
  * @param bSilentlyKeepDraftOnForwardNavigation The parameter to determine whether to skip the popup appearance in forward case
89
93
  * @param bSkipBindingToView The optional parameter to skip the binding to the view
94
+ * @param context The context to be used for the draft operations
90
95
  * @returns Nothing
91
96
  */
92
97
  async function processNoActiveEntityMode(
@@ -96,9 +101,10 @@ async function processNoActiveEntityMode(
96
101
  processFunctionForDrafts: Function,
97
102
  navigationType: NavigationType,
98
103
  bSilentlyKeepDraftOnForwardNavigation: boolean,
99
- bSkipBindingToView?: boolean
104
+ bSkipBindingToView?: boolean,
105
+ context?: ODataV4Context
100
106
  ): Promise<void> {
101
- // There is no active entity so we are editing either newly created data or
107
+ // There is no active entity so, we are editing either newly created data or
102
108
  // a draft which has never been saved to active version
103
109
  // Since we want to react differently in the two situations, we have to check the
104
110
  // dirty state
@@ -108,7 +114,7 @@ async function processNoActiveEntityMode(
108
114
  // navigation we can silently discard the draft again
109
115
  // eslint-disable-next-line promise/no-nesting
110
116
  try {
111
- await draftDataLossPopup.discardDraft(oController, bSkipBindingToView);
117
+ await draftDataLossPopup.discardDraft(oController, bSkipBindingToView, context);
112
118
  processFunctionForDrafts();
113
119
  } catch (error: unknown) {
114
120
  Log.error("Error while canceling the document", error as string);
@@ -119,7 +125,7 @@ async function processNoActiveEntityMode(
119
125
  processFunctionForDrafts();
120
126
  } else {
121
127
  // In this case data is being changed or a forward navigation is triggered
122
- // and we always want to show the dataloss dialog on navigation
128
+ // and, we always want to show the data loss dialog on navigation
123
129
  return dataLossDialog
124
130
  .open(oController)
125
131
  .then((selectedKey) =>
@@ -128,7 +134,8 @@ async function processNoActiveEntityMode(
128
134
  processFunctionForDrafts,
129
135
  fnCancelFunction,
130
136
  oController,
131
- bSkipBindingToView
137
+ bSkipBindingToView,
138
+ context
132
139
  )
133
140
  );
134
141
  }
@@ -145,7 +152,7 @@ async function processNoActiveEntityMode(
145
152
  *
146
153
  * @param oController The current controller referenced.
147
154
  * @param oContext The context of the current call
148
- * @param processFunctionForDrafts The functon to process the handler
155
+ * @param processFunctionForDrafts The function to process the handler
149
156
  * @param navigationType The navigation type for which the function should be called
150
157
  */
151
158
  async function processEditingDraftForExistingEntity(
@@ -158,8 +165,8 @@ async function processEditingDraftForExistingEntity(
158
165
  // The CreationDateTime and LastChangeDateTime are equal, so this draft was
159
166
  // never saved before, hence we're currently editing a newly created draft for
160
167
  // an existing active entity for the first time.
161
- // Also there have so far been no changes made to the draft and in this
162
- // case we want to silently navigate and delete the draftin case of a back
168
+ // Also, there have so far been no changes made to the draft and in this
169
+ // case we want to silently navigate and delete the draft in case of a back
163
170
  // navigation but in case of a forward navigation we want to silently keep it!
164
171
  if (navigationType === NavigationType.BackNavigation) {
165
172
  const mParameters = {
@@ -180,14 +187,15 @@ async function processEditingDraftForExistingEntity(
180
187
  }
181
188
 
182
189
  /**
183
- * Logic to process the edit state dirty.
190
+ * Logic to process the context when the edit state is in dirty mode.
184
191
  *
185
192
  * @param oController The current controller referenced.
186
193
  * @param fnCancelFunction The cancel function
187
- * @param processFunctionForDrafts The functon to process the handler
194
+ * @param processFunctionForDrafts The function to process the handler
188
195
  * @param navigationType The navigation type for which the function should be called
189
196
  * @param bSilentlyKeepDraftOnForwardNavigation The parameter to determine whether to skip the popup appearance in forward case
190
197
  * @param bSkipBindingToView The optional parameter to skip the binding to the view.
198
+ * @param context The context to be used for the draft operations
191
199
  * @returns Nothing
192
200
  */
193
201
  async function processEditStateDirty(
@@ -196,7 +204,8 @@ async function processEditStateDirty(
196
204
  processFunctionForDrafts: Function,
197
205
  navigationType: NavigationType,
198
206
  bSilentlyKeepDraftOnForwardNavigation: boolean,
199
- bSkipBindingToView?: boolean
207
+ bSkipBindingToView?: boolean,
208
+ context?: ODataV4Context
200
209
  ): Promise<void> {
201
210
  if (navigationType === NavigationType.ForwardNavigation && bSilentlyKeepDraftOnForwardNavigation) {
202
211
  // In case we have a "forward navigation" and an additional parameter set in the manifest
@@ -206,8 +215,8 @@ async function processEditStateDirty(
206
215
  // The CreationDateTime and LastChangeDateTime are NOT equal, so we are currently editing
207
216
  // an existing draft and need to distinguish depending on if any changes
208
217
  // have been made in the current editing session or not
209
- // Changes have been made in the current editing session so we want
210
- // to show the dataloss dialog and let the user decide
218
+ // Changes have been made in the current editing session, so we want
219
+ // to show the data loss dialog and let the user decide
211
220
  return dataLossDialog
212
221
  .open(oController)
213
222
  .then((selectedKey) =>
@@ -216,7 +225,8 @@ async function processEditStateDirty(
216
225
  processFunctionForDrafts,
217
226
  fnCancelFunction,
218
227
  oController,
219
- bSkipBindingToView
228
+ bSkipBindingToView,
229
+ context
220
230
  )
221
231
  );
222
232
  }
@@ -226,7 +236,7 @@ async function processEditStateDirty(
226
236
  * Logic to process the admin data.
227
237
  *
228
238
  * @param draftAdminData Admin data
229
- * @param fnProcessFunction The functon to process the handler
239
+ * @param fnProcessFunction The function to process the handler
230
240
  * @param fnCancelFunction The cancel function
231
241
  * @param oContext The context of the current call
232
242
  * @param oController The current controller referenced
@@ -255,7 +265,7 @@ async function processDraftAdminData(
255
265
 
256
266
  if (draftAdminData) {
257
267
  if (oController.getAppComponent().getRootViewController().isFclEnabled()) {
258
- await processFclMode(draftAdminData, fnCancelFunction, oController, processFunctionForDrafts, bSkipBindingToView);
268
+ await processFclMode(draftAdminData, fnCancelFunction, oController, processFunctionForDrafts, bSkipBindingToView, oContext);
259
269
  } else if (!oContext.getObject().HasActiveEntity) {
260
270
  processNoActiveEntityMode(
261
271
  draftAdminData,
@@ -280,7 +290,7 @@ async function processDraftAdminData(
280
290
  } else {
281
291
  // The user started editing the existing draft but did not make any changes
282
292
  // in the current editing session, so in this case we do not want
283
- // to show the dataloss dialog but just keep the draft
293
+ // to show the data loss dialog but just keep the draft
284
294
  processFunctionForDrafts();
285
295
  }
286
296
  } else {
@@ -314,15 +324,20 @@ async function processDataLossOrDraftDiscardConfirmation(
314
324
  const isDraftRoot = contextPath ? !!oMetaModel.getObject(`${contextPath}@com.sap.vocabularies.Common.v1.DraftRoot`) : false;
315
325
  const oUIModel = oView.getModel("ui");
316
326
  const bIsEditable = oUIModel.getProperty("/isEditable");
317
- const draftDataContext = oModel.bindContext(`${oContext.getPath()}/DraftAdministrativeData`).getBoundContext();
327
+ const originalContext = oContext;
328
+ let draftRootPath = oContext.getPath();
329
+ if (!isDraftRoot) {
330
+ draftRootPath = ModelHelper.getDraftRootPath(oContext) ?? draftRootPath;
331
+ }
332
+ oContext = oModel.bindContext(draftRootPath, undefined, { $expand: "DraftAdministrativeData" }).getBoundContext();
318
333
 
319
334
  // Shouldn't display data loss popover on shell back navigation from sub-object pages
320
335
  // or when object page is in display mode, or when the object is deleted
321
- if (oContext.isDeleted() || (!isDraftRoot && navigationType === NavigationType.BackNavigation) || !bIsEditable) {
336
+ if (originalContext.isDeleted() || (!isDraftRoot && navigationType === NavigationType.BackNavigation) || !bIsEditable) {
322
337
  fnProcessFunction();
323
338
  } else {
324
339
  try {
325
- const draftAdminData = await draftDataContext.requestObject();
340
+ const draftAdminData = await oContext.requestObject("DraftAdministrativeData");
326
341
  await processDraftAdminData(
327
342
  draftAdminData,
328
343
  fnProcessFunction,
@@ -344,11 +359,13 @@ async function processDataLossOrDraftDiscardConfirmation(
344
359
  * from EditFlow is called.
345
360
  *
346
361
  * @param controller Controller of the current view
362
+ * @param context The context to be used for the draft operations
347
363
  * @returns A promise resolved if the save was successful
348
364
  */
349
- async function saveDocument(controller: PageController): Promise<unknown> {
350
- const context = controller.getView().getBindingContext();
351
- if (controller.isA<ObjectPageControllerController>("sap.fe.templates.ObjectPage.ObjectPageController")) {
365
+ async function saveDocument(controller: PageController, context?: ODataV4Context): Promise<unknown> {
366
+ const hasInitialContext = context !== undefined;
367
+ context = context ?? controller.getView().getBindingContext();
368
+ if (!hasInitialContext && controller.isA<ObjectPageControllerController>("sap.fe.templates.ObjectPage.ObjectPageController")) {
352
369
  return controller._saveDocument();
353
370
  } else {
354
371
  return controller.editFlow.saveDocument(context, {});
@@ -360,10 +377,15 @@ async function saveDocument(controller: PageController): Promise<unknown> {
360
377
  *
361
378
  * @param controller Controller of the current view
362
379
  * @param skipBindingToView The parameter to skip the binding to the view
380
+ * @param context The context to be used for the draft operations
363
381
  * @returns A promise resolved if cancelDocument was successful
364
382
  */
365
- async function discardDraft(controller: PageController, skipBindingToView: boolean | undefined): Promise<unknown> {
366
- const context = controller.getView().getBindingContext();
383
+ async function discardDraft(
384
+ controller: PageController,
385
+ skipBindingToView: boolean | undefined,
386
+ context?: ODataV4Context
387
+ ): Promise<unknown> {
388
+ context = context ?? controller.getView().getBindingContext();
367
389
  const params = {
368
390
  skipBackNavigation: true,
369
391
  skipDiscardPopover: true,
@@ -373,25 +395,27 @@ async function discardDraft(controller: PageController, skipBindingToView: boole
373
395
  }
374
396
 
375
397
  /**
376
- * Executes the follow-up functions after an option was selected in the dataloss dialog.
398
+ * Executes the follow-up functions after an option was selected in the data loss dialog.
377
399
  *
378
- * @param selectedKey The key of the selected option from the dataloss dialog
400
+ * @param selectedKey The key of the selected option from the data loss dialog
379
401
  * @param processFunctionForDrafts The function to process the handler
380
402
  * @param fnCancelFunction The function to process the handler
381
403
  * @param controller Controller of the current view
382
404
  * @param skipBindingToView The parameter to skip the binding to the view
405
+ * @param context The context to be used for the binding
383
406
  */
384
407
  function handleDialogSelection(
385
408
  selectedKey: string,
386
409
  processFunctionForDrafts: Function,
387
410
  fnCancelFunction: Function,
388
411
  controller: PageController,
389
- skipBindingToView: boolean | undefined
412
+ skipBindingToView: boolean | undefined,
413
+ context?: ODataV4Context
390
414
  ): void {
391
415
  switch (selectedKey) {
392
416
  case DraftDataLossOptions.Save:
393
417
  draftDataLossPopup
394
- .saveDocument(controller)
418
+ .saveDocument(controller, context)
395
419
  .then((context?) => processFunctionForDrafts(context))
396
420
  .catch(function (error: string | undefined) {
397
421
  if (error === RecommendationDialogDecision.Continue) {
@@ -407,7 +431,7 @@ function handleDialogSelection(
407
431
  break;
408
432
  case DraftDataLossOptions.Discard:
409
433
  draftDataLossPopup
410
- .discardDraft(controller, skipBindingToView)
434
+ .discardDraft(controller, skipBindingToView, context)
411
435
  .then((context?) => processFunctionForDrafts(context))
412
436
  .catch(function (error: string | undefined) {
413
437
  Log.error("Error while discarding draft", error);