@sapui5/sap.fe.core 1.136.10 → 1.136.11

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 (35) hide show
  1. package/package.json +1 -1
  2. package/src/sap/fe/core/.library +1 -1
  3. package/src/sap/fe/core/PageController.controller.js +10 -0
  4. package/src/sap/fe/core/PageController.controller.ts +3 -0
  5. package/src/sap/fe/core/controllerextensions/InternalRouting.js +23 -13
  6. package/src/sap/fe/core/controllerextensions/InternalRouting.ts +34 -13
  7. package/src/sap/fe/core/controllerextensions/routing/RouterProxy.js +7 -6
  8. package/src/sap/fe/core/controllerextensions/routing/RouterProxy.ts +8 -5
  9. package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DraftDataLossDialog.js +2 -1
  10. package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DraftDataLossDialog.tsx +1 -0
  11. package/src/sap/fe/core/converters/controls/Common/Action.js +15 -1
  12. package/src/sap/fe/core/converters/controls/Common/Action.ts +21 -1
  13. package/src/sap/fe/core/converters/controls/Common/Table.js +54 -46
  14. package/src/sap/fe/core/converters/controls/Common/Table.ts +65 -45
  15. package/src/sap/fe/core/converters/controls/Common/table/Columns.js +26 -6
  16. package/src/sap/fe/core/converters/controls/Common/table/Columns.ts +32 -10
  17. package/src/sap/fe/core/converters/controls/Common/table/StandardActions.js +12 -18
  18. package/src/sap/fe/core/converters/controls/Common/table/StandardActions.ts +13 -27
  19. package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.js +5 -2
  20. package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.ts +7 -1
  21. package/src/sap/fe/core/designtime/AnnotationBasedChanges.js +8 -3
  22. package/src/sap/fe/core/designtime/AnnotationBasedChanges.ts +7 -2
  23. package/src/sap/fe/core/fpm/manifest.json +1 -1
  24. package/src/sap/fe/core/helpers/AppStartupHelper.js +75 -18
  25. package/src/sap/fe/core/helpers/AppStartupHelper.ts +79 -25
  26. package/src/sap/fe/core/helpers/MetaModelFunction.js +10 -3
  27. package/src/sap/fe/core/helpers/MetaModelFunction.ts +9 -3
  28. package/src/sap/fe/core/library.js +1 -1
  29. package/src/sap/fe/core/messagebundle_es.properties +1 -1
  30. package/src/sap/fe/core/messagebundle_fr.properties +1 -1
  31. package/src/sap/fe/core/messagebundle_ko.properties +1 -1
  32. package/src/sap/fe/core/messagebundle_no.properties +2 -2
  33. package/src/sap/fe/core/services/RoutingServiceFactory.js +4 -2
  34. package/src/sap/fe/core/services/RoutingServiceFactory.ts +5 -2
  35. package/ui5.yaml +1 -0
@@ -29,6 +29,7 @@ import {
29
29
  getExpressionFromAnnotation,
30
30
  ifElse,
31
31
  isConstant,
32
+ isExpressionStaticallyResolvable,
32
33
  not,
33
34
  or,
34
35
  pathInModel,
@@ -1231,8 +1232,7 @@ export function getSelectionMode(
1231
1232
  visualizationPath: string,
1232
1233
  converterContext: ConverterContext<PageContextPathTarget>,
1233
1234
  isEntitySet: boolean,
1234
- targetCapabilities: TableCapabilityRestriction,
1235
- deleteButtonVisibilityExpression?: BindingToolkitExpression<boolean>,
1235
+ deleteButtonVisibilityExpression: BindingToolkitExpression<boolean>,
1236
1236
  massEditVisibilityExpression: BindingToolkitExpression<boolean> = constant(false),
1237
1237
  cutButtonVisibilityExpression: BindingToolkitExpression<boolean> = constant(false)
1238
1238
  ): string | undefined {
@@ -1240,25 +1240,30 @@ export function getSelectionMode(
1240
1240
  const tableType = tableManifestSettings.tableSettings?.type;
1241
1241
  let selectionMode = tableManifestSettings.tableSettings?.selectionMode;
1242
1242
 
1243
- // The collapse/Expand action of a tree table is a bound action, as a result, a tree table should always have a selection mode to "Multi" when no selectionMode has been set in the manifest
1243
+ // NEW: derive deletable from path expression instead of targetCapabilities.isDeletable
1244
+ let pathDeletableExpression = isPathDeletable(converterContext.getDataModelObjectPath());
1245
+ if (!isExpressionStaticallyResolvable(pathDeletableExpression)) {
1246
+ // dynamic (depends on path/singleton) -> treat as "potentially deletable"
1247
+ pathDeletableExpression = constant(true);
1248
+ }
1249
+ const deletableStaticFalse = isConstant(pathDeletableExpression) && pathDeletableExpression.value === false;
1250
+
1251
+ // TreeTable: default to Multi if not set
1244
1252
  if (tableType === "TreeTable" && !selectionMode) {
1245
1253
  return SelectionMode.Multi;
1246
1254
  }
1247
1255
 
1248
1256
  // If the selection mode is forced to 'None' in the manifest/macro table parameters, we keep it unless here is a delete button
1249
1257
  if (!lineItemAnnotation || selectionMode === SelectionMode.None) {
1250
- if (targetCapabilities.isDeletable && deleteButtonVisibilityExpression) {
1251
- return compileExpression(ifElse(deleteButtonVisibilityExpression, constant(SelectionMode.Multi), constant(SelectionMode.None)));
1252
- }
1253
- return SelectionMode.None;
1258
+ return compileExpression(ifElse(deleteButtonVisibilityExpression, constant(SelectionMode.Multi), constant(SelectionMode.None)));
1254
1259
  }
1255
1260
  if (selectionMode === SelectionMode.ForceMulti) {
1256
1261
  return SelectionMode.Multi;
1257
1262
  } else if (selectionMode === SelectionMode.ForceSingle) {
1258
1263
  return SelectionMode.Single;
1259
1264
  }
1260
- let aHiddenBindingExpressions: BindingToolkitExpression<boolean>[] = [],
1261
- aVisibleBindingExpressions: BindingToolkitExpression<boolean>[] = [];
1265
+ let hiddenBindingExpressions: BindingToolkitExpression<boolean>[] = [],
1266
+ visibleBindingExpressions: BindingToolkitExpression<boolean>[] = [];
1262
1267
  const manifestActions = getActionsFromManifest(
1263
1268
  converterContext.getManifestControlConfiguration<TableManifestConfiguration>(visualizationPath).actions,
1264
1269
  converterContext,
@@ -1271,11 +1276,11 @@ export function getSelectionMode(
1271
1276
  isParentDeletable = isPathDeletable(converterContext.getDataModelObjectPath());
1272
1277
  parentEntitySetDeletable = isParentDeletable ? compileExpression(isParentDeletable, true) : isParentDeletable;
1273
1278
  }
1274
- const bMassEditEnabled: boolean = !isConstant(massEditVisibilityExpression) || massEditVisibilityExpression.value !== false;
1279
+ const massEditEnabled: boolean = !isConstant(massEditVisibilityExpression) || massEditVisibilityExpression.value !== false;
1275
1280
  if (!selectionMode || selectionMode === SelectionMode.Auto) {
1276
1281
  selectionMode = SelectionMode.Multi;
1277
1282
  }
1278
- if (bMassEditEnabled) {
1283
+ if (massEditEnabled) {
1279
1284
  // Override default selection mode when mass edit is visible
1280
1285
  selectionMode = selectionMode === SelectionMode.Single ? SelectionMode.Single : SelectionMode.Multi;
1281
1286
  }
@@ -1285,25 +1290,24 @@ export function getSelectionMode(
1285
1290
  ) {
1286
1291
  return selectionMode;
1287
1292
  }
1288
- aHiddenBindingExpressions = getUIHiddenExpForActionsRequiringContext(
1293
+ hiddenBindingExpressions = getUIHiddenExpForActionsRequiringContext(
1289
1294
  lineItemAnnotation,
1290
1295
  converterContext.getEntityType(),
1291
1296
  converterContext.getDataModelObjectPath()
1292
1297
  );
1293
- aVisibleBindingExpressions = getVisibleExpForCustomActionsRequiringContext(manifestActions.actions);
1298
+ visibleBindingExpressions = getVisibleExpForCustomActionsRequiringContext(manifestActions.actions);
1294
1299
  // No action requiring a context:
1295
1300
  if (
1296
- aHiddenBindingExpressions.length === 0 &&
1297
- aVisibleBindingExpressions.length === 0 &&
1298
- (cutButtonVisibilityExpression || deleteButtonVisibilityExpression || bMassEditEnabled)
1301
+ hiddenBindingExpressions.length === 0 &&
1302
+ visibleBindingExpressions.length === 0 &&
1303
+ (cutButtonVisibilityExpression || deleteButtonVisibilityExpression || massEditEnabled)
1299
1304
  ) {
1300
1305
  if (!isEntitySet) {
1301
- // Example: OP case
1302
- if (targetCapabilities.isDeletable || parentEntitySetDeletable !== "false" || bMassEditEnabled) {
1303
- // Building expression for delete and mass edit
1306
+ // OP case:
1307
+ if (!deletableStaticFalse || parentEntitySetDeletable !== "false" || massEditEnabled) {
1304
1308
  const buttonVisibilityExpression = or(
1305
1309
  cutButtonVisibilityExpression || true,
1306
- deleteButtonVisibilityExpression || true, // default delete visibility as true
1310
+ deleteButtonVisibilityExpression,
1307
1311
  massEditVisibilityExpression
1308
1312
  );
1309
1313
  return compileExpression(
@@ -1314,23 +1318,19 @@ export function getSelectionMode(
1314
1318
  ifElse(cutButtonVisibilityExpression, constant(SelectionMode.Single), constant(SelectionMode.None))
1315
1319
  );
1316
1320
  }
1317
- // EntitySet deletable:
1318
- } else if (bMassEditEnabled) {
1319
- // example: LR scenario
1320
- return selectionMode;
1321
- } else if (targetCapabilities.isDeletable && deleteButtonVisibilityExpression) {
1322
- return compileExpression(ifElse(deleteButtonVisibilityExpression, constant(selectionMode), constant(SelectionMode.None)));
1323
- // EntitySet not deletable:
1324
1321
  } else {
1325
- return SelectionMode.None;
1322
+ // EntitySet case:
1323
+ return compileExpression(
1324
+ ifElse(or(massEditEnabled, deleteButtonVisibilityExpression), constant(selectionMode), constant(SelectionMode.None))
1325
+ );
1326
1326
  }
1327
1327
  // There are actions requiring a context:
1328
1328
  } else if (!isEntitySet) {
1329
- // Example: OP case
1330
- if (targetCapabilities.isDeletable || parentEntitySetDeletable !== "false" || bMassEditEnabled) {
1329
+ // OP case:
1330
+ if (!deletableStaticFalse || parentEntitySetDeletable !== "false" || massEditEnabled) {
1331
1331
  // Use selectionMode in edit mode if delete is enabled or mass edit is visible
1332
1332
  const editModebuttonVisibilityExpression = ifElse(
1333
- bMassEditEnabled && !targetCapabilities.isDeletable,
1333
+ massEditEnabled && deletableStaticFalse,
1334
1334
  massEditVisibilityExpression,
1335
1335
  constant(true)
1336
1336
  );
@@ -1339,7 +1339,7 @@ export function getSelectionMode(
1339
1339
  and(UI.IsEditable, editModebuttonVisibilityExpression),
1340
1340
  constant(selectionMode),
1341
1341
  ifElse(
1342
- or(...aHiddenBindingExpressions.concat(aVisibleBindingExpressions)),
1342
+ or(...hiddenBindingExpressions.concat(visibleBindingExpressions)),
1343
1343
  constant(selectionMode),
1344
1344
  constant(SelectionMode.None)
1345
1345
  )
@@ -1348,23 +1348,23 @@ export function getSelectionMode(
1348
1348
  } else {
1349
1349
  return compileExpression(
1350
1350
  ifElse(
1351
- or(...aHiddenBindingExpressions.concat(aVisibleBindingExpressions)),
1351
+ or(...hiddenBindingExpressions.concat(visibleBindingExpressions)),
1352
1352
  constant(selectionMode),
1353
1353
  constant(SelectionMode.None)
1354
1354
  )
1355
1355
  );
1356
1356
  }
1357
- //EntitySet deletable:
1358
- } else if (targetCapabilities.isDeletable || bMassEditEnabled) {
1359
- // Example: LR scenario
1360
- return selectionMode;
1361
- //EntitySet not deletable:
1357
+ // EntitySet
1362
1358
  } else {
1363
1359
  return compileExpression(
1364
1360
  ifElse(
1365
- or(...aHiddenBindingExpressions.concat(aVisibleBindingExpressions), massEditVisibilityExpression),
1361
+ or(massEditEnabled, deleteButtonVisibilityExpression),
1366
1362
  constant(selectionMode),
1367
- constant(SelectionMode.None)
1363
+ ifElse(
1364
+ or(...hiddenBindingExpressions.concat(visibleBindingExpressions), massEditVisibilityExpression),
1365
+ constant(selectionMode),
1366
+ constant(SelectionMode.None)
1367
+ )
1368
1368
  )
1369
1369
  );
1370
1370
  }
@@ -2113,14 +2113,12 @@ export function getTableAnnotationConfiguration(
2113
2113
  const hasAbsolutePath = navigationPropertyPath.length === 0;
2114
2114
  const p13nMode = getP13nMode(visualizationPath, converterContext, tableManifestConfiguration);
2115
2115
  const id = navigationPropertyPath ? getTableID(visualizationPath) : getTableID(converterContext.getContextPath(), "LineItem");
2116
- const targetCapabilities = getCapabilityRestriction(converterContext);
2117
2116
  const navigationTargetPath = getNavigationTargetPath(converterContext, navigationPropertyPath);
2118
2117
  const selectionMode = getSelectionMode(
2119
2118
  lineItemAnnotation,
2120
2119
  visualizationPath,
2121
2120
  converterContext,
2122
2121
  hasAbsolutePath,
2123
- targetCapabilities,
2124
2122
  standardActionsConfiguration.deleteButtonVisibilityExpression,
2125
2123
  standardActionsConfiguration.massEditButtonVisibilityExpression,
2126
2124
  standardActionsConfiguration.cutButtonVisibilityExpression
@@ -2397,10 +2395,12 @@ function _useEnabledExpression(dataField: DataFieldForActionTypes, sEntityType:
2397
2395
  function updateTreeTableManifestConfiguration(
2398
2396
  tableConfiguration: TableControlConfiguration,
2399
2397
  tableSettings: TableManifestSettingsConfiguration,
2400
- converterContext: ConverterContext
2398
+ converterContext: ConverterContext,
2399
+ lineItemAnnotation: LineItem | undefined
2401
2400
  ): void {
2402
2401
  const dataModelObjectPath = converterContext.getDataModelObjectPath();
2403
- tableConfiguration.hierarchyQualifier = tableSettings.hierarchyQualifier;
2402
+ const entityType = converterContext.getAnnotationEntityType(lineItemAnnotation);
2403
+ tableConfiguration.hierarchyQualifier = getHierarchyQualifier(entityType, tableSettings);
2404
2404
  const hierarchyParentNavigationPropertyPath = getHierarchyParentNavigationPropertyPath(
2405
2405
  dataModelObjectPath,
2406
2406
  tableConfiguration.hierarchyQualifier!
@@ -2478,6 +2478,26 @@ function getOptimisticBatchSettingsFromManifest(tableManifestSettings: TableMani
2478
2478
  return tableManifestSettings?.tableSettings?.disableRequestCache;
2479
2479
  }
2480
2480
 
2481
+ function getHierarchyQualifier(entityType: EntityType, tableSettings: TableManifestSettingsConfiguration): string | undefined {
2482
+ if (tableSettings.hierarchyQualifier) {
2483
+ return tableSettings.hierarchyQualifier;
2484
+ }
2485
+ const aggregationAnnotations = entityType.annotations?.Aggregation;
2486
+ const hierarchyAnnotations = entityType.annotations?.Hierarchy;
2487
+ // We only check the hierarchyQualifier from the manifest when the tree table is specifically set, otherwise we get it from the annotations
2488
+ // if both annotations have the same qualifier, use it
2489
+ // If there is no qualifier or different qualifiers, the hierarchyQualifier remains undefined
2490
+ // Note: In case of multiple hierarchies with the same qualifier, the first one found will be used
2491
+ const qualifiedName =
2492
+ hierarchyAnnotations &&
2493
+ Object.keys(hierarchyAnnotations).find(
2494
+ (key) => key.includes("RecursiveHierarchy#") && aggregationAnnotations && Object.keys(aggregationAnnotations).includes(key)
2495
+ );
2496
+ if (qualifiedName) {
2497
+ return (hierarchyAnnotations as Record<string, { qualifier?: string }>)[qualifiedName]?.qualifier;
2498
+ }
2499
+ }
2500
+
2481
2501
  /**
2482
2502
  * Gets the settings coming from the manifest related to the mass edit dialog.
2483
2503
  * @param tableSettings The table configuration
@@ -2644,7 +2664,7 @@ export function getTableManifestConfiguration(
2644
2664
  tableConfiguration.selectionChange = tableSettings.selectionChange;
2645
2665
  tableConfiguration.rowPress = tableSettings.rowPress;
2646
2666
  if (tableType === "TreeTable") {
2647
- updateTreeTableManifestConfiguration(tableConfiguration, tableSettings, converterContext);
2667
+ updateTreeTableManifestConfiguration(tableConfiguration, tableSettings, converterContext, lineItemAnnotation);
2648
2668
  }
2649
2669
 
2650
2670
  if (tableSettings.headerVisible !== undefined) {