@sapui5/sap.suite.ui.generic.template 1.151.0 → 1.151.1

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 (21) hide show
  1. package/package.json +1 -1
  2. package/src/sap/suite/ui/generic/template/.library +1 -1
  3. package/src/sap/suite/ui/generic/template/AnalyticalListPage/manifest.json +1 -1
  4. package/src/sap/suite/ui/generic/template/Canvas/manifest.json +1 -1
  5. package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
  6. package/src/sap/suite/ui/generic/template/ObjectPage/controller/ControllerImplementation.js +3 -1
  7. package/src/sap/suite/ui/generic/template/ObjectPage/controller/RelatedAppsHandler.js +1 -1
  8. package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +1 -1
  9. package/src/sap/suite/ui/generic/template/QuickCreate/manifest.json +1 -1
  10. package/src/sap/suite/ui/generic/template/QuickView/manifest.json +1 -1
  11. package/src/sap/suite/ui/generic/template/genericUtilities/controlStateWrapperFactory/SmartTableChartCommon.js +10 -0
  12. package/src/sap/suite/ui/generic/template/genericUtilities/controlStateWrapperFactory/SmartVariantManagementWrapper.js +1 -8
  13. package/src/sap/suite/ui/generic/template/lib/AppComponent.js +3 -1
  14. package/src/sap/suite/ui/generic/template/lib/Application.js +28 -2
  15. package/src/sap/suite/ui/generic/template/lib/CommonEventHandlers.js +47 -10
  16. package/src/sap/suite/ui/generic/template/lib/CommonUtils.js +7 -7
  17. package/src/sap/suite/ui/generic/template/lib/PageLeaveHandler.js +19 -14
  18. package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterBarHandler.js +111 -14
  19. package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterDataFetcherHelper.js +1 -1
  20. package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +1 -1
  21. package/src/sap/suite/ui/generic/template/library.js +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sapui5/sap.suite.ui.generic.template",
3
- "version": "1.151.0",
3
+ "version": "1.151.1",
4
4
  "description": "SAPUI5 Library sap.suite.ui.generic.template",
5
5
  "keywords": [
6
6
  "sapui5",
@@ -7,7 +7,7 @@
7
7
 
8
8
  (c) Copyright 2009-2015 SAP SE. All rights reserved
9
9
  </copyright>
10
- <version>1.151.0</version>
10
+ <version>1.151.1</version>
11
11
 
12
12
  <documentation>Library with generic Suite UI templates.</documentation>
13
13
 
@@ -8,7 +8,7 @@
8
8
  "i18n": "i18n/i18n.properties",
9
9
  "applicationVersion": {
10
10
  "__comment": "applicationVersion oder componentversion??",
11
- "version": "1.151.0"
11
+ "version": "1.151.1"
12
12
  },
13
13
  "title": "{{TITLE}}",
14
14
  "description": "{{DESCRIPTION}}",
@@ -8,7 +8,7 @@
8
8
  "i18n": "i18n/i18n.properties",
9
9
  "applicationVersion": {
10
10
  "__comment": "applicationVersion oder componentversion??",
11
- "version": "1.151.0"
11
+ "version": "1.151.1"
12
12
  },
13
13
  "title": "Canvas",
14
14
  "description": "Canvas Page",
@@ -8,7 +8,7 @@
8
8
  "i18n": "i18n/i18n.properties",
9
9
  "applicationVersion": {
10
10
  "__comment": "applicationVersion oder componentversion??",
11
- "version": "1.151.0"
11
+ "version": "1.151.1"
12
12
  },
13
13
  "title": "{{TITLE}}",
14
14
  "description": "{{DESCRIPTION}}",
@@ -2804,9 +2804,11 @@ sap.ui.define([
2804
2804
  onDataFieldForIntentBasedNavigation: function (oEvent) {
2805
2805
  oEvent = merge({}, oEvent);
2806
2806
  oTemplateUtils.oServices.oApplication.performAfterSideEffectExecution(function () {
2807
+ var oCustomData = oTemplateUtils.oCommonUtils.getCustomDataFromEvent(oEvent);
2808
+ var oTarget = { semanticObject: oCustomData.SemanticObject, action: oCustomData.Action };
2807
2809
  oTemplateUtils.oCommonUtils.fnProcessDataLossOrDraftDiscardConfirmation(function () {
2808
2810
  oTemplateUtils.oCommonEventHandlers.onDataFieldForIntentBasedNavigation(oEvent, oBase.state);
2809
- }, Function.prototype, "LeaveApp");
2811
+ }, Function.prototype, "LeaveApp", false, oTarget);
2810
2812
  }, true);
2811
2813
  },
2812
2814
  onDataFieldWithIntentBasedNavigation: function (oEvent) {
@@ -25,7 +25,7 @@ sap.ui.define([
25
25
  oTemplateUtils.oCommonUtils.fnProcessDataLossOrDraftDiscardConfirmation(function () {
26
26
  var oContext = oController.getView().getBindingContext();
27
27
  oTemplateUtils.oCommonEventHandlers.onRelatedAppNavigation(oTarget, oContext);
28
- }, Function.prototype, "LeaveApp");
28
+ }, Function.prototype, "LeaveApp", false, oTarget);
29
29
  }
30
30
  }, "buttons");
31
31
  }
@@ -6,7 +6,7 @@
6
6
  "type": "component",
7
7
  "i18n": "i18n/i18n.properties",
8
8
  "applicationVersion": {
9
- "version": "1.151.0"
9
+ "version": "1.151.1"
10
10
  },
11
11
  "title": "{{TITLE}}",
12
12
  "description": "{{DESCRIPTION}}",
@@ -6,7 +6,7 @@
6
6
  "type": "component",
7
7
  "i18n": "i18n/i18n.properties",
8
8
  "applicationVersion": {
9
- "version": "1.151.0"
9
+ "version": "1.151.1"
10
10
  },
11
11
  "title": "{{TITLE}}",
12
12
  "description": "{{DESCRIPTION}}",
@@ -6,7 +6,7 @@
6
6
  "type": "component",
7
7
  "i18n": "i18n/i18n.properties",
8
8
  "applicationVersion": {
9
- "version": "1.151.0"
9
+ "version": "1.151.1"
10
10
  },
11
11
  "title": "{{TITLE}}",
12
12
  "description": "{{DESCRIPTION}}",
@@ -49,6 +49,12 @@ sap.ui.define([
49
49
  function getControlWrapper(oControl) {
50
50
  var bIsApplying = false; // avoid forwarding change event when caused by us applying a state
51
51
  function fnGetState() {
52
+ // getCurrentState can iterate a managed control whose view was already torn down (e.g. navigation
53
+ // while an appState write is in flight). Reading state from a destroyed control crashes in
54
+ // getUiState() because its inner aggregation is gone, so skip it.
55
+ if (oControl.isDestroyed()) {
56
+ return undefined;
57
+ }
52
58
  var oControlUiState = oControl.getUiState(); // unfortunately not serializable, but a managed object
53
59
  var oStateUiState = {
54
60
  oPresentationVariant: oControlUiState.getPresentationVariant(),
@@ -66,6 +72,10 @@ sap.ui.define([
66
72
  }
67
73
 
68
74
  function fnSetState(oState) {
75
+ // Symmetric to fnGetState: never apply state to a destroyed control.
76
+ if (oControl.isDestroyed()) {
77
+ return;
78
+ }
69
79
  if (oState) {
70
80
  if (!oState.oUiState) {
71
81
  // Legacy handling for state without additional level oUiState (created with 1.99.0 - 1.99.3). Could be relevant on LR and OP, and independent of VM
@@ -85,14 +85,7 @@ sap.ui.define([
85
85
  setManagedControlStates: function(oState){
86
86
  aWrapperInfo.forEach(function(oInfo){
87
87
  if (!oInfo.bVMConnection) {
88
- // Defer setState until the control is ready (oReadyPromise resolves after the
89
- // control fires its initialise event and its inner table/chart is created).
90
- // Without this guard, afterVariantLoad can call setState before SmartTable._oTable
91
- // exists, causing getUiState() to crash with a null-dereference on getTable().
92
- var oReady = oInfo.wrapper.oReadyPromise || Promise.resolve();
93
- oReady.then(function() {
94
- oInfo.wrapper.setState(oState[oInfo.wrapper.getLocalId()]);
95
- });
88
+ oInfo.wrapper.setState(oState[oInfo.wrapper.getLocalId()]);
96
89
  }
97
90
  });
98
91
  }
@@ -661,6 +661,7 @@ sap.ui.define([
661
661
 
662
662
  function restore(){
663
663
  oTemplateContract.oBusyHelper.setBusyReason("exiting", false);
664
+ oTemplateContract.oApplicationProxy.resetExternalNavigation();
664
665
  for (var sComponentId in oTemplateContract.componentRegistry){
665
666
  var oRegistryEntry = oTemplateContract.componentRegistry[sComponentId];
666
667
  if (oRegistryEntry.methods.onRestore) {
@@ -942,6 +943,7 @@ sap.ui.define([
942
943
  var fnNormalizePagesMapToArray = testableHelper.testable(fnNormalizePagesMapToArray, "fnNormalizePagesMapToArray");
943
944
  getConfig = testableHelper.testable(getConfig, "getConfig");
944
945
  testableHelper.testable(setLeaveAppPromise, "AppComponent_setLeaveAppPromise");
946
+ testableHelper.testable(restore, "AppComponent_restore");
945
947
  /* eslint-enable */
946
948
 
947
949
  return oMethods;
@@ -959,7 +961,7 @@ sap.ui.define([
959
961
  * @public
960
962
  * @extends sap.ui.core.UIComponent
961
963
  * @author SAP SE
962
- * @version 1.151.0
964
+ * @version 1.151.1
963
965
  * @name sap.suite.ui.generic.template.lib.AppComponent
964
966
  */
965
967
  var oAppComponent = UIComponent.extend("sap.suite.ui.generic.template.lib.AppComponent", {
@@ -82,6 +82,11 @@ sap.ui.define(["sap/ui/base/Object",
82
82
  */
83
83
  function getMethods(oTemplateContract) {
84
84
 
85
+ // Set on first fnNavigateExternal call; blocks re-entry until reset. NavigationHandler.navigate() calls fnOnError
86
+ // on all failure paths and does not call it on the success path (app is leaving). The two valid reset points are
87
+ // therefore fnOnErrorWrapper (navigation failed) and AppComponent.restore() (FLP re-activated this app).
88
+ var bExternalNavigationTriggered = false;
89
+
85
90
  var oFocusHelper = new FocusHelper(oTemplateContract);
86
91
  var oContextBookkeeping = new ContextBookkeeping(oTemplateContract);
87
92
  var mEntitySetToETagInfo = Object.create(null); // maps the name of the entity sets which have been already checked for eTag
@@ -671,8 +676,13 @@ sap.ui.define(["sap/ui/base/Object",
671
676
  if (oCurrentNavigationHandler === GHOSTNAVIGATIONHANDLER){
672
677
  return;
673
678
  }
679
+ if (bExternalNavigationTriggered){
680
+ return;
681
+ }
682
+ bExternalNavigationTriggered = true;
674
683
  oTemplateContract.oNavigationControllerProxy.leave();
675
- var fnOnErrorWrapper = function(){
684
+ var fnOnErrorWrapper = function () {
685
+ bExternalNavigationTriggered = false;
676
686
  oFocusHelper.setNextFocus(Function.prototype); // Do not change focus in case exiting the application fails
677
687
  oTemplateContract.oBusyHelper.setBusyReason("exiting", false); // in error case we are not navigating away
678
688
  if (fnOnError){
@@ -800,6 +810,18 @@ sap.ui.define(["sap/ui/base/Object",
800
810
  return oTemplateContract.oNavigationControllerProxy.preloadComponent(sRouteName);
801
811
  }
802
812
 
813
+ // Returns true when a navigation call will open in a new tab rather than replacing the current app.
814
+ // sap-ushell-navmode (manifest-level) takes priority; sap-ushell-next-navmode (FLP startup parameter,
815
+ // system-level) is the fallback — mirroring how NavigationHandler itself determines explace.
816
+ function fnIsExplaceNavigation(oOutboundParameters) {
817
+ if (oOutboundParameters && oOutboundParameters["sap-ushell-navmode"] === "explace") {
818
+ return true;
819
+ }
820
+ var oComponentData = oTemplateContract.oAppComponent.getComponentData && oTemplateContract.oAppComponent.getComponentData();
821
+ var oStartupParams = oComponentData && oComponentData.startupParameters;
822
+ return !!(oStartupParams && oStartupParams["sap-ushell-next-navmode"] && oStartupParams["sap-ushell-next-navmode"][0] === "explace");
823
+ }
824
+
803
825
  oTemplateContract.oApplicationProxy = { // inject own api for AppComponent into the Template Contract. Other classes (NavigationController, BusyHelper) will call these functions accordingly.
804
826
  createDraftSiblingPromise: oContextBookkeeping.createDraftSiblingPromise,
805
827
  getDraftSiblingPromise: oContextBookkeeping.getDraftSiblingPromise,
@@ -834,7 +856,10 @@ sap.ui.define(["sap/ui/base/Object",
834
856
  removeTransientMessages: fnRemoveTransientMessages,
835
857
  getTransientMessages: getTransientMessages,
836
858
  setNextFocus: oFocusHelper.setNextFocus,
837
- setStates: setStates
859
+ setStates: setStates,
860
+ resetExternalNavigation: function() {
861
+ bExternalNavigationTriggered = false;
862
+ }
838
863
  };
839
864
 
840
865
  return {
@@ -903,6 +928,7 @@ sap.ui.define(["sap/ui/base/Object",
903
928
  mustRequireRequestsCanonical: mustRequireRequestsCanonical,
904
929
  getNavigationHandler: getNavigationHandler,
905
930
  navigateExternal: fnNavigateExternal,
931
+ isExplaceNavigation: fnIsExplaceNavigation,
906
932
  getStatePreservationMode: getStatePreservationMode,
907
933
  setObjectInEditMode: fnSetObjectInEditMode,
908
934
  getObjectInEditMode: fnGetObjectInEditMode,
@@ -720,7 +720,16 @@ sap.ui.define(["sap/ui/base/Object",
720
720
  }
721
721
 
722
722
  // null object has to be passed as the fourth argument (i.e. for oInnerAppData) to the navigate method as an indicator that the state should not be overwritten
723
- oServices.oApplication.navigateExternal(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, oCommonUtils.handleError);
723
+ // Explace outbounds must bypass fnNavigateExternal to avoid setting the app busy and consuming the re-entry guard.
724
+ // getNavigationHandler() returns a ghost stub (no .navigate) when ghostapp=true — guard before calling.
725
+ if (oServices.oApplication.isExplaceNavigation(oOutbound.parameters)) {
726
+ var oNavHandler = oServices.oApplication.getNavigationHandler();
727
+ if (oNavHandler.navigate) {
728
+ oNavHandler.navigate(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, oCommonUtils.handleError, null, "explace");
729
+ }
730
+ } else {
731
+ oServices.oApplication.navigateExternal(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, oCommonUtils.handleError);
732
+ }
724
733
  }
725
734
 
726
735
  function fnNavigateIntentSmartLink(oOutbound, oEventSource) {
@@ -733,7 +742,15 @@ sap.ui.define(["sap/ui/base/Object",
733
742
  oCommonUtils.removePropertiesFromNavigationContext(oSelectionVariant, oEventSource);
734
743
  oController.adaptNavigationParameterExtension(oSelectionVariant, oObjectInfo);
735
744
  oCommonUtils.setComponentRefreshBehaviour(oOutbound);
736
- oServices.oApplication.navigateExternal(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, oCommonUtils.handleError);
745
+ // SmartLink outbounds have no manifest parameters so sap-ushell-navmode is never set.
746
+ // System-level sap-ushell-next-navmode can still force a new tab — bypass the re-entry guard in that case.
747
+ if (oServices.oApplication.isExplaceNavigation()) {
748
+ if (oNavigationHandler.navigate) {
749
+ oNavigationHandler.navigate(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, oCommonUtils.handleError, null, "explace");
750
+ }
751
+ } else {
752
+ oServices.oApplication.navigateExternal(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, oCommonUtils.handleError);
753
+ }
737
754
  }
738
755
 
739
756
  function fnHideTitleArea(oSmLiContent,aContactTitleArea) {
@@ -803,9 +820,10 @@ sap.ui.define(["sap/ui/base/Object",
803
820
 
804
821
  function fnOnSemanticObjectLinkNavigationPressed(oEventSource, oEventParameters){
805
822
  var oEventObject = deepExtend({}, oEventSource);
823
+ var sSemanticObject = oEventObject.data('SemanticObject');
824
+ var sAction = oEventObject.data('Action');
825
+ var oTarget = (sSemanticObject && sAction) ? { semanticObject: sSemanticObject, action: sAction } : undefined;
806
826
  oCommonUtils.fnProcessDataLossOrDraftDiscardConfirmation(function() {
807
- var sSemanticObject = oEventObject.data('SemanticObject');
808
- var sAction = oEventObject.data('Action');
809
827
  var sSemanticAttributes = oEventObject.data('SemanticAttributes');
810
828
  if (sSemanticObject && sAction){
811
829
  var oOutbound = {
@@ -818,7 +836,7 @@ sap.ui.define(["sap/ui/base/Object",
818
836
  }
819
837
  fnNavigateIntentSmartLink(oOutbound, oEventObject);
820
838
  }
821
- }, Function.prototype, "LeaveApp");
839
+ }, Function.prototype, "LeaveApp", false, oTarget);
822
840
  }
823
841
 
824
842
  function fnOnSemanticObjectLinkNavigationTargetObtained(sEntitySet, mFieldSemanticObjects, oEventParameters, oState, sTitle) {
@@ -1105,8 +1123,15 @@ sap.ui.define(["sap/ui/base/Object",
1105
1123
  // The value "sEntitySet" holds the entity set of an object page or a table.
1106
1124
  //
1107
1125
  // Sometimes, the SmartLink is located on a field group which belongs to the child entity set of object page.
1108
- // So, we have to always derive the entity type from the smart link's binding context.
1126
+ // So, we try to derive the entity type from the SmartLink's binding context.
1109
1127
  var oEntityType = ModelUtil.getEntityTypeFromContext(oControl.getBindingContext());
1128
+ // CS20260013063140: ModelUtil.getEntityTypeFromContext returns null when the SmartLink
1129
+ // is resolved via SmartLinkDelegate, because the binding context is not yet resolvable
1130
+ // to an entity type at that point.
1131
+ // Fall back to deriving the entity type from the enclosing entity set instead.
1132
+ if (!oEntityType) {
1133
+ oEntityType = oMetaModel.getODataEntityType(oEntitySet.entityType);
1134
+ }
1110
1135
  var oField = oEntityType.property.find(function (oProperty) { return oProperty.name === sSourceClickedField; });
1111
1136
  var sTextArrangement = "descriptionAndId";
1112
1137
  if (oField) { // TODO: Need to provide the correct field Object using the entityType and corresponding association (should be handled by a BLI)
@@ -1988,6 +2013,7 @@ sap.ui.define(["sap/ui/base/Object",
1988
2013
  var oContext = oEventSource.getParent().getBindingContext();
1989
2014
  var sSemanticObject = oEventSource.data("SemanticObject");
1990
2015
  var sAction = oEventSource.data("Action");
2016
+ var oTarget = { semanticObject: sSemanticObject, action: sAction };
1991
2017
 
1992
2018
  oCommonUtils.fnProcessDataLossOrDraftDiscardConfirmation(function() {
1993
2019
  var oOutbound = {
@@ -1995,7 +2021,7 @@ sap.ui.define(["sap/ui/base/Object",
1995
2021
  semanticObject: sSemanticObject
1996
2022
  };
1997
2023
  fnNavigateIntent(oOutbound, [oContext], oState.oSmartFilterbar || undefined);
1998
- }, Function.prototype, "LeaveApp");
2024
+ }, Function.prototype, "LeaveApp", false, oTarget);
1999
2025
  }
2000
2026
 
2001
2027
  /*
@@ -2025,13 +2051,15 @@ sap.ui.define(["sap/ui/base/Object",
2025
2051
  if (bRequiresContext && !aSelectedContexts.length) { // not consistent, since contexts missing
2026
2052
  fnShowMessageForInvalidNumberOfSelects(aSelectedContexts.length);
2027
2053
  } else {
2054
+ var oTarget = { semanticObject: oCustomData.SemanticObject, action: oCustomData.Action };
2028
2055
  oCommonUtils.fnProcessDataLossOrDraftDiscardConfirmation(function () {
2029
2056
  onDataFieldForIntentBasedNavigationSelectedContext(oCustomData, aSelectedContexts, oSmartFilterbar);
2030
- }, Function.prototype, "LeaveApp");
2057
+ }, Function.prototype, "LeaveApp", false, oTarget);
2031
2058
  }
2032
2059
  }
2033
2060
 
2034
2061
  function onInlineDataFieldForIntentBasedNavigation(oEventSource, oState){
2062
+ var oTarget = { semanticObject: oEventSource.data("SemanticObject"), action: oEventSource.data("Action") };
2035
2063
  oCommonUtils.fnProcessDataLossOrDraftDiscardConfirmation(function() {
2036
2064
  var oOutbound = {
2037
2065
  semanticObject: oEventSource.data("SemanticObject"),
@@ -2039,7 +2067,7 @@ sap.ui.define(["sap/ui/base/Object",
2039
2067
  };
2040
2068
  var oContext = oEventSource.getParent().getBindingContext();
2041
2069
  fnNavigateIntent(oOutbound, [oContext], oState.oSmartFilterbar);
2042
- }, Function.prototype, "LeaveApp");
2070
+ }, Function.prototype, "LeaveApp", false, oTarget);
2043
2071
  }
2044
2072
 
2045
2073
  function onInlineDataFieldForAction(oEvent) {
@@ -2709,7 +2737,16 @@ sap.ui.define(["sap/ui/base/Object",
2709
2737
  var oSelectionVariant = fnBuildSelectionVariantForNavigation(oOutbound, [], oContext);
2710
2738
  oController.adaptNavigationParameterExtension(oSelectionVariant, oOutbound);
2711
2739
  oCommonUtils.setComponentRefreshBehaviour(oOutbound);
2712
- oServices.oApplication.navigateExternal(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, oCommonUtils.handleError);
2740
+ // Explace outbounds must bypass fnNavigateExternal to avoid setting the app busy and consuming the re-entry guard.
2741
+ // getNavigationHandler() returns a ghost stub (no .navigate) when ghostapp=true — guard before calling.
2742
+ if (oServices.oApplication.isExplaceNavigation(oOutbound.parameters)) {
2743
+ var oNavHandler = oServices.oApplication.getNavigationHandler();
2744
+ if (oNavHandler.navigate) {
2745
+ oNavHandler.navigate(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, oCommonUtils.handleError, null, "explace");
2746
+ }
2747
+ } else {
2748
+ oServices.oApplication.navigateExternal(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, oCommonUtils.handleError);
2749
+ }
2713
2750
  }
2714
2751
 
2715
2752
  function onSmartFieldInitialise(oEvent,sViewId){
@@ -835,17 +835,17 @@ sap.ui.define(["sap/ui/base/Object",
835
835
 
836
836
  setComponentRefreshBehaviour(oOutbound);
837
837
 
838
- // We now ensure that the 'sap-ushell-navmode' parameter is passed to the NavigationHandler.navigate method
839
- // and skip setting the app to busy mode when opening a new tab
840
- if (oOutbound.parameters["sap-ushell-navmode"] === "explace") {
841
- oNavigationHandler.navigate(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, null, null, oOutbound.parameters["sap-ushell-navmode"]);
838
+ // We now skip setting the app to busy mode when opening a new tab and bypass the re-entry guard (fnNavigateExternal) for explace navigations:
839
+ // the source app stays alive when a new tab is opened, so without the bypass AppComponent.restore() is never called and the guard is never reset.
840
+ if (oServices.oApplication.isExplaceNavigation(oOutbound.parameters)) {
841
+ oNavigationHandler.navigate(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, null, null, "explace");
842
842
  } else {
843
843
  oServices.oApplication.navigateExternal(oOutbound.semanticObject, oOutbound.action, oSelectionVariant.toJSONString(), null, fnHandleError);
844
844
  //null object has to be passed to the NavigationHandler as an
845
845
  //indicator that the state should not be overwritten
846
846
  //if draft enabled then passing NavigateExternal else on back button passing LeavePage
847
847
  }
848
- }, Function.prototype, "LeaveApp");
848
+ }, Function.prototype, "LeaveApp", false, { semanticObject: oOutbound.semanticObject, action: oOutbound.action });
849
849
  }
850
850
 
851
851
  function fnGetNavigationKeyProperties(sTargetEntitySet) {
@@ -1369,10 +1369,10 @@ sap.ui.define(["sap/ui/base/Object",
1369
1369
  // "LeaveApp": leave the app via a forward navigation
1370
1370
  // "LeavePage": leave the page via an internal navigation or a backward navigation (which may or may not be internal)
1371
1371
  // Note: if sMode is faulty it will be considered as "LeavePage"
1372
- function fnProcessDataLossOrDraftDiscardConfirmation(fnProcessFunction, fnCancelFunction, sMode, bNoBusyCheck){
1372
+ function fnProcessDataLossOrDraftDiscardConfirmation(fnProcessFunction, fnCancelFunction, sMode, bNoBusyCheck, oTarget){
1373
1373
  sMode = sMode || "LeavePage";
1374
1374
  if (oComponentUtils.isDraftEnabled()){
1375
- return oServices.oPageLeaveHandler.performAfterDiscardOrKeepDraft(fnProcessFunction, fnCancelFunction, sMode, bNoBusyCheck, false);
1375
+ return oServices.oPageLeaveHandler.performAfterDiscardOrKeepDraft(fnProcessFunction, fnCancelFunction, sMode, bNoBusyCheck, false, oTarget);
1376
1376
  } else {
1377
1377
  return oServices.oDataLossHandler.performIfNoDataLoss(fnProcessFunction, fnCancelFunction, sMode, bNoBusyCheck, false);
1378
1378
  }
@@ -22,19 +22,24 @@ sap.ui.define(["sap/ui/base/Object",
22
22
  firstListItemOption.focus();
23
23
  }
24
24
 
25
- function checkIfNavigationIsExplace() {
25
+ function checkIfNavigationIsExplace(oTarget) {
26
26
  var UShellContainer = sap.ui.require("sap/ushell/Container");
27
27
  if (!UShellContainer) {
28
- return Promise.resolve(false); // No UShell container, assume inplace navigation
28
+ return Promise.resolve(false);
29
29
  }
30
30
 
31
- return UShellContainer.getServiceAsync("FioriElements").then(function(oFioriElementsService) {
32
- if (oFioriElementsService && typeof oFioriElementsService.isExplaceNavigation === "function") {
33
- return oFioriElementsService.isExplaceNavigation();
34
- }
35
- return false; // API not available, default to inplace behavior
36
- }).catch(function() {
37
- return false; // Service not available or error, default to inplace behavior
31
+ return new Promise(function(resolve) {
32
+ sap.ui.require(["sap/ushell/api/FioriElements"], function(FioriElements) {
33
+ FioriElements.isExplaceNavigation(oTarget ? { target: oTarget } : undefined)
34
+ .then(function(bExplace) {
35
+ resolve(bExplace);
36
+ })
37
+ .catch(function() {
38
+ resolve(false);
39
+ });
40
+ }, function() {
41
+ resolve(false);
42
+ });
38
43
  });
39
44
  }
40
45
 
@@ -147,7 +152,7 @@ sap.ui.define(["sap/ui/base/Object",
147
152
  return oDiscardPromise;
148
153
  }
149
154
 
150
- function fnPerformAfterDiscardOrKeepDraftImpl(fnPositive, fnNegative, sMode, bIsTechnical) {
155
+ function fnPerformAfterDiscardOrKeepDraftImpl(fnPositive, fnNegative, sMode, bIsTechnical, oTarget) {
151
156
  var sEnableDiscardDraftConfirmation = oTemplateContract.oNavigationControllerProxy.isDiscardDraftConfirmationNeeded();
152
157
  var bNeedsPopup = ((sEnableDiscardDraftConfirmation === "always" && sMode.startsWith("Leave")) || (sEnableDiscardDraftConfirmation === "restricted" && sMode === "LeavePage")) && isObjectEditable();
153
158
 
@@ -157,7 +162,7 @@ sap.ui.define(["sap/ui/base/Object",
157
162
  }
158
163
 
159
164
  // Check if navigation will be explace and skip popup if so
160
- checkIfNavigationIsExplace().then(function(bIsExplace) {
165
+ checkIfNavigationIsExplace(oTarget).then(function(bIsExplace) {
161
166
  if (bIsExplace) {
162
167
  fnPositive(); // Skip popup for explace navigation
163
168
  } else {
@@ -195,7 +200,7 @@ sap.ui.define(["sap/ui/base/Object",
195
200
  }
196
201
 
197
202
  // Parameter sMode has same possible values as fnProcessDataLossOrDraftDiscardConfirmation in CommonUtils
198
- function fnPerformAfterDiscardOrKeepDraft(fnProcessFunction, fnCancelFunction, sMode, bNoBusyCheck, bIsTechnical) {
203
+ function fnPerformAfterDiscardOrKeepDraft(fnProcessFunction, fnCancelFunction, sMode, bNoBusyCheck, bIsTechnical, oTarget) {
199
204
  var oRet = new Promise(function (fnResolve, fnReject) {
200
205
  var fnPositive = function () {
201
206
  var oRet = fnProcessFunction();
@@ -206,9 +211,9 @@ sap.ui.define(["sap/ui/base/Object",
206
211
  fnReject();
207
212
  };
208
213
  if (bNoBusyCheck) {
209
- fnPerformAfterDiscardOrKeepDraftImpl(fnPositive, fnNegative, sMode, bIsTechnical);
214
+ fnPerformAfterDiscardOrKeepDraftImpl(fnPositive, fnNegative, sMode, bIsTechnical, oTarget);
210
215
  } else {
211
- oTemplateContract.oApplicationProxy.performAfterSideEffectExecution(fnPerformAfterDiscardOrKeepDraftImpl.bind(null, fnPositive, fnNegative, sMode, bIsTechnical), true);
216
+ oTemplateContract.oApplicationProxy.performAfterSideEffectExecution(fnPerformAfterDiscardOrKeepDraftImpl.bind(null, fnPositive, fnNegative, sMode, bIsTechnical, oTarget), true);
212
217
  }
213
218
  });
214
219
  return oRet;
@@ -709,22 +709,119 @@ sap.ui.define([
709
709
  oSmartFilterBarWrapper.setState(oSmartFilterBarVariant);
710
710
  // currentVariantSetModified intentionally omitted — pressing Go with the same
711
711
  // query must not mark the variant as dirty.
712
- // oSmartFilterbar.getSmartVariant() && oSmartFilterbar.getSmartVariant().currentVariantSetModified(true);
713
-
714
- // Apply sorters/groupLevels bundled with tokens after SFB state is set but
715
- // before triggering search, to prevent a premature rebind with incomplete filters.
716
- var aBundledSorters = oEvent.getParameter("sorters");
717
- var aBundledGroupLevels = oEvent.getParameter("groupLevels");
718
- if (aBundledSorters !== undefined) {
719
- fnApplySortersToTable(aBundledSorters);
720
- }
721
- if (aBundledGroupLevels !== undefined) {
722
- fnApplyGroupLevelsToTable(aBundledGroupLevels);
723
- }
712
+
713
+ var aSelectOptionsNeedingInjection = fnGetCustomFieldsNeedingInjection(oSmartFilterbar, oVariantDataFromAI.aSelectOptions);
714
+ fnInjectCustomFiltersOnRebind(aSelectOptionsNeedingInjection);
715
+ fnSyncCustomFieldInputValues(aSelectOptionsNeedingInjection, oSmartFilterbar);
716
+
717
+ // Apply sorters/groupLevels bundled with tokens after SFB state is set but
718
+ // before triggering search, to prevent a premature rebind with incomplete filters.
719
+ var aBundledSorters = oEvent.getParameter("sorters");
720
+ var aBundledGroupLevels = oEvent.getParameter("groupLevels");
721
+ if (aBundledSorters !== undefined) {
722
+ fnApplySortersToTable(aBundledSorters);
723
+ }
724
+ if (aBundledGroupLevels !== undefined) {
725
+ fnApplyGroupLevelsToTable(aBundledGroupLevels);
726
+ }
724
727
 
725
728
  oSmartFilterbar.search();
726
729
  }
727
730
 
731
+ /**
732
+ * Returns the subset of aSelectOptions whose property names landed in SFB's _CUSTOM
733
+ * bucket after setState — meaning SFB could not route them through its standard filter
734
+ * pipeline (plain Input fields with no value-list annotation).
735
+ * @param {object} oSmartFilterbar - The SmartFilterBar control instance
736
+ * @param {Array} aSelectOptions - Select options built from AI tokens
737
+ * @returns {Array} Select options that require direct filter injection
738
+ */
739
+ function fnGetCustomFieldsNeedingInjection(oSmartFilterbar, aSelectOptions) {
740
+ var oFilterData = oSmartFilterbar.getFilterData();
741
+ var oCustomData = oFilterData && oFilterData._CUSTOM;
742
+ return aSelectOptions.filter(function(oSelectOption) {
743
+ return oCustomData && oCustomData.hasOwnProperty(oSelectOption.PropertyName);
744
+ });
745
+ }
746
+
747
+ /**
748
+ * Builds UI5 Filter objects for each _CUSTOM select option and registers a one-shot
749
+ * beforeRebindTable handler on the SmartTable that injects them into bindingParams.filters
750
+ * just before the OData request is built — bypassing SFB's filter pipeline entirely.
751
+ * EQ is remapped to Contains to match Classic SFB substringof behaviour on plain Input fields.
752
+ * @param {Array} aSelectOptionsNeedingInjection - Select options that require direct filter injection
753
+ * @returns {void}
754
+ */
755
+ function fnInjectCustomFiltersOnRebind(aSelectOptionsNeedingInjection) {
756
+ if (aSelectOptionsNeedingInjection.length === 0 || !oState.oPresentationControlHandler) {
757
+ return;
758
+ }
759
+ var oSmartTable = oState.oPresentationControlHandler.getControl();
760
+ if (!oSmartTable || typeof oSmartTable.attachBeforeRebindTable !== 'function') {
761
+ return;
762
+ }
763
+ var aInjectFilters = [];
764
+ aSelectOptionsNeedingInjection.forEach(function(oSelectOption) {
765
+ oSelectOption.Ranges.forEach(function(oRange) {
766
+ var sOp = oRange.Option;
767
+ var sVal = oRange.Low;
768
+ if (sOp === 'CP') {
769
+ aInjectFilters.push(new Filter(oSelectOption.PropertyName, FilterOperator.Contains, sVal.replace(/^\*|\*$/g, '')));
770
+ } else if (sOp === 'EQ') {
771
+ aInjectFilters.push(new Filter(oSelectOption.PropertyName, FilterOperator.Contains, sVal));
772
+ } else if (sOp === 'BT') {
773
+ aInjectFilters.push(new Filter(oSelectOption.PropertyName, FilterOperator.BT, oRange.Low, oRange.High));
774
+ } else if (sOp === 'NB') {
775
+ aInjectFilters.push(new Filter({path: oSelectOption.PropertyName, operator: FilterOperator.BT, value1: oRange.Low, value2: oRange.High, bExclude: true}));
776
+ } else {
777
+ var sMappedOp = FilterOperator[sOp];
778
+ if (!sMappedOp) {
779
+ oLogger.warning("EasyFilterBarHandler: unsupported select-option operator '" + sOp + "' for property '" + oSelectOption.PropertyName + "' — skipping filter injection");
780
+ return;
781
+ }
782
+ aInjectFilters.push(new Filter(oSelectOption.PropertyName, sMappedOp, sVal));
783
+ }
784
+ });
785
+ });
786
+ var fnOnBeforeRebind = function(oRebindEvent) {
787
+ oSmartTable.detachBeforeRebindTable(fnOnBeforeRebind);
788
+ var oBindingParams = oRebindEvent.getParameter('bindingParams');
789
+ oBindingParams.filters = oBindingParams.filters || [];
790
+ var aBindingFilters = oBindingParams.filters;
791
+ // Remove prior easy-filter entries for the same properties to avoid stacking.
792
+ aInjectFilters.forEach(function(oF) {
793
+ for (var i = aBindingFilters.length - 1; i >= 0; i--) {
794
+ if (aBindingFilters[i] && aBindingFilters[i].sPath === oF.sPath) {
795
+ aBindingFilters.splice(i, 1);
796
+ }
797
+ }
798
+ aBindingFilters.push(oF);
799
+ });
800
+ };
801
+ oSmartTable.attachBeforeRebindTable(fnOnBeforeRebind);
802
+ }
803
+
804
+ /**
805
+ * Sets the visible value on the SFB Input control for each _CUSTOM field so the Classic
806
+ * filter tab shows the correct value when the user switches filter modes.
807
+ * Uses setValue only — no fireChange — to avoid triggering SFB's async filter rebuild.
808
+ * @param {Array} aSelectOptionsNeedingInjection - Select options that require direct filter injection
809
+ * @param {object} oSmartFilterbar - The SmartFilterBar control instance
810
+ * @returns {void}
811
+ */
812
+ function fnSyncCustomFieldInputValues(aSelectOptionsNeedingInjection, oSmartFilterbar) {
813
+ aSelectOptionsNeedingInjection.forEach(function(oSelectOption) {
814
+ if (oSelectOption.Ranges.length > 0) {
815
+ var aItems = oSmartFilterbar.getAllFilterItems(true) || [];
816
+ var oItem = aItems.find(function(i) { return i.getName && i.getName() === oSelectOption.PropertyName; });
817
+ var oCtrl = oItem && oItem.getControl && oItem.getControl();
818
+ if (oCtrl && oCtrl.setValue) {
819
+ oCtrl.setValue(oSelectOption.Ranges[0].Low);
820
+ }
821
+ }
822
+ });
823
+ }
824
+
728
825
  /**
729
826
  * Event handler for the EasyFilterBarContainer's tokensChangedByUser event.
730
827
  * Fired when the user manually deletes or modifies a token (distinct from AI-resolved tokens).
@@ -819,8 +916,8 @@ sap.ui.define([
819
916
  /**
820
917
  * Event handler for the EasyFilter control's showValueHelp event.
821
918
  * Identifies the input field for which the value help is requested and triggers the value help opening from SFB.
822
- * @param {*} oEvent
823
- * @param {*} oState
919
+ * @param {sap.ui.base.Event} oEvent - The showValueHelp event fired by the EasyFilter control
920
+ * @param {object} oState - The current controller state object
824
921
  */
825
922
  function fnShowValueHelp(oEvent) {
826
923
  var oSmartFilterbar = oState.oSmartFilterbar;
@@ -287,7 +287,7 @@ sap.ui.define([
287
287
  if (!isValueHelpTableAvailable) {
288
288
  // When there is no valueList associate, just return the original value in CodeList type
289
289
  aFilters.forEach(oFilter => aFinalResponse.push(getkeySpecifiedResultFromFilters(oFilter)));
290
- resolve(aFinalResponse);
290
+ return resolve(aFinalResponse);
291
291
  }
292
292
 
293
293
  // Get value help lists from metadata
@@ -3222,7 +3222,7 @@ sap.ui.define(["sap/ui/base/Object",
3222
3222
  * @param {sap.suite.ui.generic.template.lib.AppComponent} oAppComponent The AppComponent instance
3223
3223
  * @public
3224
3224
  * @extends sap.ui.base.Object
3225
- * @version 1.151.0
3225
+ * @version 1.151.1
3226
3226
  * @since 1.30.0
3227
3227
  * @alias sap.suite.ui.generic.template.lib.NavigationController
3228
3228
  */
@@ -68,7 +68,7 @@ sap.ui.define([
68
68
  interfaces: [],
69
69
  controls: [],
70
70
  elements: [],
71
- version: "1.151.0",
71
+ version: "1.151.1",
72
72
  extensions: {
73
73
  //Configuration used for rule loading of Support Assistant
74
74
  "sap.ui.support": {