@sapui5/sap.fe.templates 1.148.3 → 1.150.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.
- package/package.json +1 -1
- package/src/sap/fe/templates/.library +1 -1
- package/src/sap/fe/templates/AnalyticalListPage/manifest.json +1 -1
- package/src/sap/fe/templates/ListComponent.js +2 -5
- package/src/sap/fe/templates/ListReport/Component.js +2 -5
- package/src/sap/fe/templates/ListReport/ExtensionAPI.js +84 -14
- package/src/sap/fe/templates/ListReport/ExtensionAPI.ts +88 -13
- package/src/sap/fe/templates/ListReport/LRMessageStrip.js +41 -1
- package/src/sap/fe/templates/ListReport/LRMessageStrip.ts +43 -0
- package/src/sap/fe/templates/ListReport/ListReportController.controller.js +87 -11
- package/src/sap/fe/templates/ListReport/ListReportController.controller.ts +74 -2
- package/src/sap/fe/templates/ListReport/controls/MultipleModeControl.js +4 -7
- package/src/sap/fe/templates/ListReport/manifest.json +1 -1
- package/src/sap/fe/templates/ListReport/overrides/IntentBasedNavigation.js +12 -6
- package/src/sap/fe/templates/ListReport/overrides/IntentBasedNavigation.ts +14 -6
- package/src/sap/fe/templates/ListReport/overrides/ViewState.js +7 -1
- package/src/sap/fe/templates/ListReport/overrides/ViewState.ts +5 -0
- package/src/sap/fe/templates/ListReport/view/fragments/Table.fragment.xml +1 -0
- package/src/sap/fe/templates/ListReport/view/fragments/VariantManagement.fragment.xml +1 -0
- package/src/sap/fe/templates/ObjectPage/Component.js +12 -15
- package/src/sap/fe/templates/ObjectPage/ExtensionAPI.js +3 -7
- package/src/sap/fe/templates/ObjectPage/ObjectPage.view.xml +3 -2
- package/src/sap/fe/templates/ObjectPage/ObjectPageController.controller.js +105 -83
- package/src/sap/fe/templates/ObjectPage/ObjectPageController.controller.ts +88 -80
- package/src/sap/fe/templates/ObjectPage/ObjectPageTemplating.js +5 -18
- package/src/sap/fe/templates/ObjectPage/ObjectPageTemplating.ts +2 -15
- package/src/sap/fe/templates/ObjectPage/components/CollaborationDraft.js +28 -3
- package/src/sap/fe/templates/ObjectPage/components/CollaborationDraft.tsx +29 -1
- package/src/sap/fe/templates/ObjectPage/controls/StashableHBox.js +2 -5
- package/src/sap/fe/templates/ObjectPage/controls/StashableVBox.js +2 -5
- package/src/sap/fe/templates/ObjectPage/controls/SubSectionBlock.js +3 -6
- package/src/sap/fe/templates/ObjectPage/manifest.json +1 -1
- package/src/sap/fe/templates/ObjectPage/view/fragments/ObjectPageHeaderForm.fragment.xml +1 -0
- package/src/sap/fe/templates/ObjectPage/view/fragments/SectionContent.fragment.xml +0 -4
- package/src/sap/fe/templates/ObjectPage/view/fragments/SectionFormContent.fragment.xml +0 -1
- package/src/sap/fe/templates/ObjectPage/view/fragments/SectionMoreFormContent.fragment.xml +0 -1
- package/src/sap/fe/templates/ObjectPage/view/fragments/Table.fragment.xml +1 -0
- package/src/sap/fe/templates/library.js +1 -1
|
@@ -30,15 +30,17 @@ import type { InternalModelContext } from "sap/fe/core/helpers/ModelHelper";
|
|
|
30
30
|
import ModelHelper from "sap/fe/core/helpers/ModelHelper";
|
|
31
31
|
import FELibrary from "sap/fe/core/library";
|
|
32
32
|
import { type WrappedCard } from "sap/fe/core/services/CollaborationManagerServiceFactory";
|
|
33
|
+
import type { TelemetryVariantEvent } from "sap/fe/core/services/TelemetryServiceFactory";
|
|
33
34
|
import type ChartBlock from "sap/fe/macros/Chart";
|
|
34
35
|
import CommonHelper from "sap/fe/macros/CommonHelper";
|
|
36
|
+
import type FormBlock from "sap/fe/macros/Form";
|
|
35
37
|
import type MacroAPI from "sap/fe/macros/MacroAPI";
|
|
36
38
|
import type MultiValueFieldBlock from "sap/fe/macros/MultiValueField";
|
|
37
39
|
import type TableAPI from "sap/fe/macros/Table";
|
|
40
|
+
import VariantManagementBB from "sap/fe/macros/VariantManagement";
|
|
38
41
|
import type EasyFillButton from "sap/fe/macros/ai/EasyFillButton";
|
|
39
42
|
import type SummarizationButton from "sap/fe/macros/ai/SummarizationButton";
|
|
40
43
|
import type SubSection from "sap/fe/macros/controls/section/SubSection";
|
|
41
|
-
import type FormAPI from "sap/fe/macros/form/FormAPI";
|
|
42
44
|
import type MessageButton from "sap/fe/macros/messages/MessageButton";
|
|
43
45
|
import type ShareAPI from "sap/fe/macros/share/ShareAPI";
|
|
44
46
|
import type TableCreationOptions from "sap/fe/macros/table/TableCreationOptions";
|
|
@@ -100,7 +102,7 @@ import MessageHandlerOverride from "./overrides/MessageHandler";
|
|
|
100
102
|
import PaginatorOverride from "./overrides/Paginator";
|
|
101
103
|
import ShareOverrides from "./overrides/Share";
|
|
102
104
|
import ViewStateOverrides from "./overrides/ViewState";
|
|
103
|
-
|
|
105
|
+
const { VariantType } = VariantManagementBB;
|
|
104
106
|
export type BindingParams = {
|
|
105
107
|
redirectedToNonDraft?: string | undefined;
|
|
106
108
|
reason?: NavigationReason;
|
|
@@ -656,6 +658,10 @@ class ObjectPageController extends PageController {
|
|
|
656
658
|
// SubSection's contents binding is disabled.
|
|
657
659
|
blocks.forEach((block) => {
|
|
658
660
|
if (block.isA<SubSectionBlock>("sap.fe.templates.ObjectPage.controls.SubSectionBlock")) {
|
|
661
|
+
// Set binding context to null on both the block and its content
|
|
662
|
+
// to support both: subsections with UI.Hidden annotation (content needs to be cleared)
|
|
663
|
+
// and customer controller extensions that set binding context on the block level
|
|
664
|
+
block.setBindingContext(undefined);
|
|
659
665
|
block.content.setBindingContext?.(null);
|
|
660
666
|
} else {
|
|
661
667
|
block.setBindingContext(null);
|
|
@@ -671,7 +677,7 @@ class ObjectPageController extends PageController {
|
|
|
671
677
|
_getFirstEmptyMandatoryFieldFromSubSection(aSubSections: ObjectPageSubSection[]): InputBase | undefined {
|
|
672
678
|
if (aSubSections.length === 0) return undefined;
|
|
673
679
|
for (const subSection of aSubSections) {
|
|
674
|
-
const aBlocks = subSection.getBlocks() as (Form |
|
|
680
|
+
const aBlocks = subSection.getBlocks() as (Form | FormBlock)[];
|
|
675
681
|
|
|
676
682
|
if (aBlocks) {
|
|
677
683
|
for (const blockControl of aBlocks) {
|
|
@@ -682,8 +688,8 @@ class ObjectPageController extends PageController {
|
|
|
682
688
|
aFormContainers = blockControl.getFormContainers();
|
|
683
689
|
} else if (blockControl.getContent && blockControl.getContent()?.isA<Form>("sap.ui.layout.form.Form")) {
|
|
684
690
|
aFormContainers = (blockControl.getContent() as Form).getFormContainers();
|
|
685
|
-
} else if (blockControl?.getContent?.()?.isA<
|
|
686
|
-
aFormContainers = ((blockControl.getContent() as
|
|
691
|
+
} else if (blockControl?.getContent?.()?.isA<FormBlock>("sap.fe.macros.Form")) {
|
|
692
|
+
aFormContainers = ((blockControl.getContent() as FormBlock).getContent() as Form).getFormContainers();
|
|
687
693
|
}
|
|
688
694
|
if (aFormContainers) {
|
|
689
695
|
for (const formContainer of aFormContainers) {
|
|
@@ -822,6 +828,10 @@ class ObjectPageController extends PageController {
|
|
|
822
828
|
const blocks = oSubSection.getBlocks();
|
|
823
829
|
blocks.forEach((block) => {
|
|
824
830
|
if (block.isA<SubSectionBlock>("sap.fe.templates.ObjectPage.controls.SubSectionBlock")) {
|
|
831
|
+
// Set binding context to undefined on both the block and its content
|
|
832
|
+
// to support both: subsections with UI.Hidden annotation (content needs to be cleared)
|
|
833
|
+
// and customer controller extensions that set binding context on the block level
|
|
834
|
+
block.setBindingContext(undefined);
|
|
825
835
|
block.content.setBindingContext?.(undefined);
|
|
826
836
|
} else {
|
|
827
837
|
block.setBindingContext(undefined);
|
|
@@ -831,59 +841,6 @@ class ObjectPageController extends PageController {
|
|
|
831
841
|
oSubSection.getActions().forEach((actions) => actions.setBindingContext(undefined));
|
|
832
842
|
}
|
|
833
843
|
|
|
834
|
-
_onBackNavigationInDraft(oContext: ODataV4Context): void {
|
|
835
|
-
this.messageHandler.removeTransitionMessages();
|
|
836
|
-
|
|
837
|
-
// Function to navigate back, or display the launchpad if we're on the first page of the history
|
|
838
|
-
const navBack = (): void => {
|
|
839
|
-
// Use the new Navigation API if it's available in the browser, to check if we can go back in history.
|
|
840
|
-
const canGoBack = (window as { navigation?: { canGoBack?: boolean } }).navigation?.canGoBack;
|
|
841
|
-
if (canGoBack === true) {
|
|
842
|
-
history.back();
|
|
843
|
-
} else if (canGoBack === false) {
|
|
844
|
-
this._routing.navigateBackFromContext(oContext);
|
|
845
|
-
} else {
|
|
846
|
-
// Fallback in case the browser doesn't support the Navigation API
|
|
847
|
-
const currentURL = document.URL;
|
|
848
|
-
history.back();
|
|
849
|
-
// In case there is no previous page in the history, history.back does nothing.
|
|
850
|
-
// In this case, we need to use navigateBackFromContext, that will display the home page
|
|
851
|
-
setTimeout(() => {
|
|
852
|
-
if (document.URL === currentURL) {
|
|
853
|
-
this._routing.navigateBackFromContext(oContext);
|
|
854
|
-
}
|
|
855
|
-
}, 500);
|
|
856
|
-
}
|
|
857
|
-
};
|
|
858
|
-
|
|
859
|
-
if (this.getAppComponent().getRouterProxy().checkIfBackHasSameContext()) {
|
|
860
|
-
// Back nav will keep the same context --> no need to display the dialog
|
|
861
|
-
history.back();
|
|
862
|
-
} else if (!this.getView().getBindingContext()) {
|
|
863
|
-
// This object page doesn't have a binding context, but still handles the shell back navigation --> pform the nav back and remove the navback handler as it makes no sense any longer
|
|
864
|
-
this.getAppComponent()
|
|
865
|
-
.getShellServices()
|
|
866
|
-
.setBackNavigation(undefined)
|
|
867
|
-
.then(navBack)
|
|
868
|
-
.catch((e) => {
|
|
869
|
-
Log.warning("Error while setting back navigation", e);
|
|
870
|
-
});
|
|
871
|
-
} else {
|
|
872
|
-
const hiddenDraftEnabled = (this.getAppComponent()?.getEnvironmentCapabilities()?.getCapabilities()?.HiddenDraft as HiddenDraft)
|
|
873
|
-
?.enabled;
|
|
874
|
-
draft.processDataLossOrDraftDiscardConfirmation(
|
|
875
|
-
navBack,
|
|
876
|
-
Function.prototype,
|
|
877
|
-
oContext,
|
|
878
|
-
this,
|
|
879
|
-
true,
|
|
880
|
-
draft.NavigationType.BackNavigation,
|
|
881
|
-
undefined,
|
|
882
|
-
hiddenDraftEnabled ? true : undefined
|
|
883
|
-
);
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
|
|
887
844
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
888
845
|
_onAfterBinding(inputBindingContext: ODataV4Context | undefined, mParameters: BindingParams | undefined): void {
|
|
889
846
|
const view = this.getView();
|
|
@@ -1081,6 +1038,13 @@ class ObjectPageController extends PageController {
|
|
|
1081
1038
|
if (!targetControlId) {
|
|
1082
1039
|
return;
|
|
1083
1040
|
}
|
|
1041
|
+
// Reset stale flag so ViewState.apply() is not blocked when the OP is re-activated
|
|
1042
|
+
// via shell keep-alive (cross-app re-entry) without _onBeforeBinding firing.
|
|
1043
|
+
// Intentional ordering: reset to false here before pollForSectionStability (below) sets it back
|
|
1044
|
+
// to true, so any concurrent ViewState.apply() triggered on re-entry is unblocked immediately.
|
|
1045
|
+
if (xAppStateTargetControlId) {
|
|
1046
|
+
this.skipViewStateSectionRestore = false;
|
|
1047
|
+
}
|
|
1084
1048
|
|
|
1085
1049
|
// Wait for visibility bindings (needed for lazy loading scenarios)
|
|
1086
1050
|
try {
|
|
@@ -1130,22 +1094,22 @@ class ObjectPageController extends PageController {
|
|
|
1130
1094
|
return;
|
|
1131
1095
|
}
|
|
1132
1096
|
|
|
1133
|
-
// Poll to detect UX rules reset
|
|
1134
|
-
// _adjustSelectedSectionByUXRules()
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1097
|
+
// Poll to detect UX rules reset. The guard on isNewBindingContext was removed because
|
|
1098
|
+
// _adjustSelectedSectionByUXRules() can also reset the section on cross-app re-entry to
|
|
1099
|
+
// the same entity (shell keep-alive). Polling is lightweight (max 10 × 50 ms) and safe to
|
|
1100
|
+
// run unconditionally whenever we need to hold a target section.
|
|
1101
|
+
pollForSectionStability({
|
|
1102
|
+
getSelectedSection: () => oObjectPage.getSelectedSection(),
|
|
1103
|
+
targetSectionId,
|
|
1104
|
+
onResetDetected: navigateToTarget
|
|
1105
|
+
})
|
|
1106
|
+
.then(() => {
|
|
1107
|
+
this.skipViewStateSectionRestore = true;
|
|
1108
|
+
return; // Required by linter rule promise/always-return
|
|
1140
1109
|
})
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
})
|
|
1145
|
-
.catch(() => {
|
|
1146
|
-
// Required by linter rule promise/catch-or-return - polling failures are non-critical
|
|
1147
|
-
});
|
|
1148
|
-
}
|
|
1110
|
+
.catch(() => {
|
|
1111
|
+
// Required by linter rule promise/catch-or-return - polling failures are non-critical
|
|
1112
|
+
});
|
|
1149
1113
|
}
|
|
1150
1114
|
|
|
1151
1115
|
/**
|
|
@@ -1163,9 +1127,48 @@ class ObjectPageController extends PageController {
|
|
|
1163
1127
|
}
|
|
1164
1128
|
|
|
1165
1129
|
/**
|
|
1166
|
-
*
|
|
1167
|
-
* @param
|
|
1130
|
+
* Tracks telemetry when a new variant is saved.
|
|
1131
|
+
* @param event The save event.
|
|
1132
|
+
*/
|
|
1133
|
+
private async trackVariantSavedTelemetry(event: UI5Event<Record<string, unknown>>): Promise<void> {
|
|
1134
|
+
if (event.getParameter("overwrite")) {
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
if (!event.getSource().isA("sap.fe.macros.Table")) {
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
if (!(await this.getAppComponent()?.getTelemetryService()?.isEnabled())) {
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
const tableAPI = event.getSource() as unknown as TableAPI;
|
|
1144
|
+
this.fireTelemetry(tableAPI?.getContent?.()?.getVariant?.()?.getVariants?.()?.length ?? 0, VariantType.OBJECT_PAGE_TABLE);
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
/**
|
|
1148
|
+
* Tracks telemetry when variants are managed (e.g. deleted).
|
|
1149
|
+
* @param event The manage event.
|
|
1168
1150
|
*/
|
|
1151
|
+
private async trackVariantManagedTelemetry(event: UI5Event<Record<string, unknown>>): Promise<void> {
|
|
1152
|
+
const deletedCount: number = ((event.getParameter("deleted") as string[] | undefined) ?? []).length;
|
|
1153
|
+
if (deletedCount === 0) {
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
if (!(await this.getAppComponent()?.getTelemetryService()?.isEnabled())) {
|
|
1157
|
+
return;
|
|
1158
|
+
}
|
|
1159
|
+
this.fireTelemetry(deletedCount, VariantType.OBJECT_PAGE_TABLE);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* Stores a FE.Variant telemetry event.
|
|
1164
|
+
* @param countVariants Number of variants affected by the action.
|
|
1165
|
+
* @param variantType The variant type discriminator.
|
|
1166
|
+
*/
|
|
1167
|
+
private fireTelemetry(countVariants: number, variantType: TelemetryVariantEvent["parameters"]["variantType"]): void {
|
|
1168
|
+
const telemetryEvent: TelemetryVariantEvent = { type: "FE.Variant", parameters: { countVariants, variantType } };
|
|
1169
|
+
this.getAppComponent()?.getTelemetryService()?.storeAction(telemetryEvent);
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1169
1172
|
private navigateWithConfirmation(targetControlId: string): void {
|
|
1170
1173
|
// Set targetSubSection BEFORE navigation for app state saving.
|
|
1171
1174
|
// scrollToSection() doesn't fire the navigate event, so onNavigateChange won't be called.
|
|
@@ -1321,12 +1324,13 @@ class ObjectPageController extends PageController {
|
|
|
1321
1324
|
const oView = this.getView();
|
|
1322
1325
|
const oInternalModelContext = oView.getBindingContext("internal") as InternalModelContext;
|
|
1323
1326
|
const oBindingContext = oView.getBindingContext();
|
|
1324
|
-
//Show popup while navigating back from object page in case of draft
|
|
1327
|
+
// Show popup while navigating back from object page in case of draft (incl. hidden draft).
|
|
1328
|
+
// Sticky's shell back is registered centrally from EditFlow.registerEditLifecycleCallbacks.
|
|
1325
1329
|
if (oBindingContext) {
|
|
1326
|
-
const
|
|
1327
|
-
if (
|
|
1330
|
+
const isDraftSupported = ModelHelper.isDraftSupported(oBindingContext.getModel().getMetaModel(), oBindingContext.getPath());
|
|
1331
|
+
if (isDraftSupported) {
|
|
1328
1332
|
const oAppComponent = CommonUtils.getAppComponent(oView);
|
|
1329
|
-
await oAppComponent.getShellServices().setBackNavigation(() => this.
|
|
1333
|
+
await oAppComponent.getShellServices().setBackNavigation(() => this.editFlow.onBackNavigationInDraft(oBindingContext));
|
|
1330
1334
|
}
|
|
1331
1335
|
}
|
|
1332
1336
|
// do not request recommendations action if we are in Display mode
|
|
@@ -2445,11 +2449,15 @@ class ObjectPageController extends PageController {
|
|
|
2445
2449
|
onVariantSelected: function (this: ObjectPageController): void {
|
|
2446
2450
|
this.getExtensionAPI().updateAppState();
|
|
2447
2451
|
},
|
|
2448
|
-
onVariantSaved: function (this: ObjectPageController): void {
|
|
2452
|
+
onVariantSaved: function (this: ObjectPageController, event: UI5Event<Record<string, unknown>>): void {
|
|
2449
2453
|
//TODO: Should remove this setTimeOut once Variant Management provides an api to fetch the current variant key on save
|
|
2450
2454
|
setTimeout(() => {
|
|
2451
2455
|
this.getExtensionAPI().updateAppState();
|
|
2452
2456
|
}, 2000);
|
|
2457
|
+
this.trackVariantSavedTelemetry(event);
|
|
2458
|
+
},
|
|
2459
|
+
onVariantManaged: function (this: ObjectPageController, event: UI5Event<Record<string, unknown>>): void {
|
|
2460
|
+
this.trackVariantManagedTelemetry(event);
|
|
2453
2461
|
},
|
|
2454
2462
|
navigateToSubSection: function (oController: ObjectPageController, vDetailConfig: string | object): void {
|
|
2455
2463
|
const oDetailConfig = typeof vDetailConfig === "string" ? JSON.parse(vDetailConfig) : vDetailConfig;
|