@sapui5/sap.suite.ui.generic.template 1.151.0 → 1.152.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 (41) 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/control/visualfilterbar/SmartVisualFilterBar.js +4 -3
  4. package/src/sap/suite/ui/generic/template/AnalyticalListPage/manifest.json +1 -1
  5. package/src/sap/suite/ui/generic/template/Canvas/manifest.json +1 -1
  6. package/src/sap/suite/ui/generic/template/ListReport/Component.js +4 -2
  7. package/src/sap/suite/ui/generic/template/ListReport/i18n/i18n_sv.properties +1 -1
  8. package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
  9. package/src/sap/suite/ui/generic/template/ListReport/view/fragments/FullscreenPage.fragment.xml +3 -0
  10. package/src/sap/suite/ui/generic/template/ObjectPage/controller/ControllerImplementation.js +3 -1
  11. package/src/sap/suite/ui/generic/template/ObjectPage/controller/RelatedAppsHandler.js +1 -1
  12. package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +1 -1
  13. package/src/sap/suite/ui/generic/template/QuickCreate/manifest.json +1 -1
  14. package/src/sap/suite/ui/generic/template/QuickView/manifest.json +1 -1
  15. package/src/sap/suite/ui/generic/template/genericUtilities/controlStateWrapperFactory/SmartFilterBarWrapper.js +5 -4
  16. package/src/sap/suite/ui/generic/template/genericUtilities/controlStateWrapperFactory/SmartTableChartCommon.js +10 -0
  17. package/src/sap/suite/ui/generic/template/genericUtilities/controlStateWrapperFactory/SmartVariantManagementWrapper.js +1 -8
  18. package/src/sap/suite/ui/generic/template/js/AnnotationHelper.js +21 -17
  19. package/src/sap/suite/ui/generic/template/lib/AppComponent.js +3 -1
  20. package/src/sap/suite/ui/generic/template/lib/Application.js +15 -2
  21. package/src/sap/suite/ui/generic/template/lib/CommonEventHandlers.js +30 -8
  22. package/src/sap/suite/ui/generic/template/lib/CommonUtils.js +3 -3
  23. package/src/sap/suite/ui/generic/template/lib/PageLeaveHandler.js +19 -14
  24. package/src/sap/suite/ui/generic/template/lib/ShareUtils.js +1 -1
  25. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillAIOrchestrator.js +1 -6
  26. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillApplyHandler.js +25 -44
  27. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillDialogController.js +80 -64
  28. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFieldCollector.js +442 -259
  29. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFormRenderer.js +125 -161
  30. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillHandler.js +134 -160
  31. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillTableRenderer.js +55 -189
  32. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillDialog.fragment.xml +67 -85
  33. package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterBarHandler.js +138 -17
  34. package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterDataFetcherHelper.js +1 -1
  35. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_US_saptrc.properties +6 -6
  36. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fi.properties +4 -4
  37. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sl.properties +1 -1
  38. package/src/sap/suite/ui/generic/template/lib/insights/InsightsCardHelper.js +16 -4
  39. package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +3 -2
  40. package/src/sap/suite/ui/generic/template/library.js +1 -1
  41. package/src/sap/suite/ui/generic/template/themes/base/ObjectPage.less +1 -1
@@ -1,7 +1,8 @@
1
1
  sap.ui.define([
2
2
  "sap/suite/ui/generic/template/genericUtilities/FeLogger",
3
- "sap/suite/ui/generic/template/genericUtilities/FeError"
4
- ], function(FeLogger, FeError) {
3
+ "sap/suite/ui/generic/template/genericUtilities/FeError",
4
+ "sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFieldCollector"
5
+ ], function(FeLogger, FeError, EasyFillFieldCollector) {
5
6
  "use strict";
6
7
 
7
8
  var sClassName = "lib.ai.EasyFill.EasyFillApplyHandler";
@@ -45,7 +46,8 @@ sap.ui.define([
45
46
 
46
47
  // Copy each AI-suggested property value from the transient context to the live OP context
47
48
  for (var sProp in oTransientObject) {
48
- if (sProp !== "__metadata" && mUpdatableLookupMap[sProp]) {
49
+ if (!Object.prototype.hasOwnProperty.call(oTransientObject, sProp)) { continue; }
50
+ if (sProp !== "__metadata" && Object.prototype.hasOwnProperty.call(mUpdatableLookupMap, sProp)) {
49
51
  oObjectPageContext.setProperty(sProp, oTransientObject[sProp]);
50
52
  iApplied++;
51
53
  }
@@ -84,7 +86,7 @@ sap.ui.define([
84
86
  *
85
87
  * @param {object} oTableStagingState - table staging state { mPendingNewRowContexts }
86
88
  * @param {object} mCollectionState - collection tracking state (mCollectionProperties)
87
- * @returns {object} map of { navProperty: plainValuesObject }
89
+ * @returns {object} map of { navProperty: plainValuesObject[] }
88
90
  */
89
91
  extractPendingNewRowValues: function(oTableStagingState, mCollectionState) {
90
92
  var mNewRowValues = Object.create(null);
@@ -96,18 +98,20 @@ sap.ui.define([
96
98
  var mCollectionPropertyMap = (mCollectionState && mCollectionState.mCollectionProperties &&
97
99
  mCollectionState.mCollectionProperties[sCollectionName]) || Object.create(null);
98
100
 
99
- // Extract scalar values set by the user during the preview (first new row only — cap is 1)
100
- var oNewContext = aNewContexts[0];
101
- var oValues = Object.create(null);
102
- Object.keys(mCollectionPropertyMap).forEach(function(sPropName) {
103
- var vValue = oNewContext.getProperty && oNewContext.getProperty(sPropName);
104
- if (vValue !== undefined && vValue !== null && typeof vValue !== "object") {
105
- oValues[sPropName] = vValue;
106
- }
101
+ // Extract scalar values for ALL new row contexts — multiple row creation is supported
102
+ var aRowValues = aNewContexts.map(function(oNewContext) {
103
+ var oValues = Object.create(null);
104
+ Object.keys(mCollectionPropertyMap).forEach(function(sPropName) {
105
+ var vValue = oNewContext.getProperty && oNewContext.getProperty(sPropName);
106
+ if (vValue !== undefined && vValue !== null && typeof vValue !== "object") {
107
+ oValues[sPropName] = vValue;
108
+ }
109
+ });
110
+ return oValues;
107
111
  });
108
- mNewRowValues[sCollectionName] = oValues;
109
- oLogger.debug("extractPendingNewRowValues: extracted " + Object.keys(oValues).length +
110
- " value(s) for new row in '" + sCollectionName + "'");
112
+ mNewRowValues[sCollectionName] = aRowValues;
113
+ oLogger.debug("extractPendingNewRowValues: extracted " + aRowValues.length +
114
+ " new row(s) for '" + sCollectionName + "'");
111
115
  });
112
116
  return mNewRowValues;
113
117
  },
@@ -208,7 +212,6 @@ sap.ui.define([
208
212
  * @param {function} fnResetTransientContext - EasyFillFormRenderer.resetTransientContext
209
213
  */
210
214
  resetEasyFill: function(bRemoveTextAreaValue, oDialogModel, oController, mCollectionUpdates, oEasyFillLayoutMode, fnRevertStagedUpdates, fnResetTransientContext) {
211
- // Remove dynamically-added table ObjectPageSections from the shared OPL
212
215
  var sTableSectionMarker = "easyfillTableSection";
213
216
  var oObjectPageLayout = oController.byId("EasyFillObjectPageLayout");
214
217
  if (oObjectPageLayout) {
@@ -222,13 +225,9 @@ sap.ui.define([
222
225
  });
223
226
  }
224
227
 
225
- // Revert any staged table row values back to original
226
228
  fnRevertStagedUpdates();
227
-
228
- // Reset the transient context (discard all staged scalar AI values)
229
229
  fnResetTransientContext();
230
230
 
231
- // Reset all dialog model properties to their initial state
232
231
  oDialogModel.setProperty("/isFormVisible", false);
233
232
  oDialogModel.setProperty("/isIllustrationVisible", true);
234
233
  oDialogModel.setProperty("/isSaveEnabled", false);
@@ -246,16 +245,13 @@ sap.ui.define([
246
245
  oDialogModel.setProperty("/nonUpdatableFields", {});
247
246
  oDialogModel.setProperty("/hasNonUpdatableFields", false);
248
247
 
249
- // Clear the mutable collection updates map in place
250
248
  Object.keys(mCollectionUpdates).forEach(function(sKey) {
251
249
  delete mCollectionUpdates[sKey];
252
250
  });
253
251
 
254
252
  if (bRemoveTextAreaValue) {
255
253
  var oTextArea = oController.byId("EasyFillInputTextArea");
256
- if (oTextArea) {
257
- oTextArea.setValue("");
258
- }
254
+ if (oTextArea) { oTextArea.setValue(""); }
259
255
  oDialogModel.setProperty("/isEasyFillButtonEnabled", false);
260
256
  }
261
257
 
@@ -289,30 +285,15 @@ sap.ui.define([
289
285
  },
290
286
 
291
287
  _isEditableProperty: function(oPropertyMeta, oRowObject) {
292
- if (!oPropertyMeta) {
293
- return false;
294
- }
295
- var sUpdatable = oPropertyMeta["sap:updatable"];
296
- if (sUpdatable) {
297
- return sUpdatable !== "false";
298
- }
299
- var oAnnotation = oPropertyMeta["com.sap.vocabularies.Common.v1.FieldControl"];
300
- if (oAnnotation && oAnnotation["EnumMember"]) {
301
- return oAnnotation["EnumMember"] !== "com.sap.vocabularies.Common.v1.FieldControlType/ReadOnly";
302
- }
303
- var sFieldControl = oPropertyMeta["sap:field-control"];
304
- if (sFieldControl) {
305
- var iFieldControlValue = oRowObject && oRowObject[sFieldControl];
306
- return iFieldControlValue !== 1;
307
- }
308
- return true;
288
+ return EasyFillFieldCollector.isEditableByContextObject(oPropertyMeta, oRowObject, undefined);
309
289
  },
310
290
 
311
291
  _isSupportedStagedValue: function(vValue) {
312
- return vValue === null ||
313
- vValue === undefined ||
292
+ return vValue !== undefined && (
293
+ vValue === null ||
314
294
  typeof vValue !== "object" ||
315
- vValue instanceof Date;
295
+ vValue instanceof Date
296
+ );
316
297
  },
317
298
 
318
299
  _areValuesEqual: function(vLeft, vRight) {
@@ -2,9 +2,8 @@ sap.ui.define([
2
2
  "sap/ui/model/json/JSONModel",
3
3
  "sap/m/MessageToast",
4
4
  "sap/suite/ui/generic/template/genericUtilities/FeLogger",
5
- "sap/suite/ui/generic/template/genericUtilities/FeError",
6
5
  "sap/ui/core/ResizeHandler"
7
- ], function(JSONModel, MessageToast, FeLogger, FeError, ResizeHandler) {
6
+ ], function(JSONModel, MessageToast, FeLogger, ResizeHandler) {
8
7
  "use strict";
9
8
 
10
9
  var sClassName = "lib.ai.EasyFill.EasyFillDialogController";
@@ -76,57 +75,74 @@ sap.ui.define([
76
75
 
77
76
  /**
78
77
  * Loads the EasyFillDialog fragment (if not already loaded) and opens it.
79
- * Registers all event handlers and formatters on the fragment controller object.
78
+ * Uses getDialogFragmentAsync with keepAlive=true so the fragment is cached
79
+ * across opens — the OPL and SmartForm controls persist between invocations.
80
+ * A concurrent-open guard prevents the duplicate-ID error when the button is
81
+ * pressed before the first load completes.
80
82
  *
81
- * The dialog is kept alive after first open (not destroyed on close) so that the
82
- * ObjectPageLayout and SmartForm structures are preserved between invocations.
83
- *
84
- * @param {object} oController - MVC controller
85
- * @param {object} oTemplateUtils - FE template utilities (used for getDialogFragmentAsync)
86
- * @param {object} oHandlers - map of event handler and formatter functions to bind to the fragment
87
- * @returns {Promise<void>}
83
+ * @param {object} oController - MVC controller
84
+ * @param {object} oTemplateUtils - FE template utilities
85
+ * @param {object} oHandlers - event handler / formatter map
88
86
  */
89
- openDialog: function(oController, oTemplateUtils, oHandlers) {
87
+ openDialog: async function(oController, oTemplateUtils, oHandlers) {
90
88
  var sFragmentName = "sap.suite.ui.generic.template.lib.ai.EasyFill.fragments.EasyFillDialog";
89
+ var oView = oController.getView();
91
90
 
92
- return oTemplateUtils.oCommonUtils.getDialogFragmentAsync(
93
- sFragmentName,
94
- oHandlers,
95
- "easyFillPopup",
96
- undefined,
97
- true, // keep alive — do not destroy on close
98
- true // use view as parent
99
- ).then(function(oDialog) {
100
- oDialog.open();
101
-
102
- // Register a ResizeHandler on the ResponsiveSplitter
103
- // The dialog is kept alive across opens so we must not register more than once.
104
- if (!oDialog._easyFillResizeHandlerId) {
105
- oDialog.attachEventOnce("afterOpen", function() {
106
- // Locate the splitter by its stable fragment ID
107
- var oSplitter = oController.byId("EasyFillMainFlex") &&
108
- oController.byId("EasyFillMainFlex").findAggregatedObjects(true, function(o) {
109
- return o.isA("sap.ui.layout.ResponsiveSplitter");
110
- })[0];
111
-
112
- if (oSplitter) {
113
- var oDialogModel = oController.getView().getModel("easyFillDialogModel");
114
- // sapUiRSVisiblePaginator is added/removed by the splitter itself on resize
115
- oDialog._easyFillResizeHandlerId = ResizeHandler.register(oSplitter, function() {
116
- var bInPageMode = oSplitter.$().hasClass("sapUiRSVisiblePaginator");
117
- oDialogModel.setProperty("/isSplitterPageMode", bInPageMode);
118
- if (bInPageMode && !oDialogModel.getProperty("/isFullScreen")) {
119
- // Reset fullscreen state so pane sizes are correct when dialog is widened again
120
- oDialogModel.setProperty("/isFullScreen", true);
121
- oController.byId("inputAreaSplitPane").getLayoutData().setSize("40%");
122
- oController.byId("reviewAreaSplitPane").getLayoutData().setSize("60%");
123
- }
124
- });
125
- }
126
- });
91
+ // Guard: if a load is already in flight (concurrent button press) wait for it
92
+ if (oView._mEasyFillFragmentPromise) {
93
+ var oDialogPending;
94
+ try {
95
+ oDialogPending = await oView._mEasyFillFragmentPromise;
96
+ } catch (e) {
97
+ oLogger.error("openDialog: concurrent fragment load failed: " + e);
98
+ return;
127
99
  }
100
+ if (oDialogPending) { oDialogPending.open(); }
101
+ return;
102
+ }
103
+
104
+ // Store the in-flight promise before the first await so re-entrant calls
105
+ // hit the guard above instead of starting a second Fragment.load().
106
+ oView._mEasyFillFragmentPromise = oTemplateUtils.oCommonUtils.getDialogFragmentAsync(
107
+ sFragmentName, oHandlers, "easyFillPopup", undefined,
108
+ true, // keepAlive — do not destroy on close
109
+ true // use view as parent
110
+ );
111
+
112
+ var oDialog;
113
+ try {
114
+ oDialog = await oView._mEasyFillFragmentPromise;
115
+ } finally {
116
+ oView._mEasyFillFragmentPromise = null; // always clear in-flight marker
117
+ }
128
118
 
129
- oLogger.debug("openDialog: EasyFillDialog opened");
119
+ if (!oDialog) { return; } // guard: load rejected, nothing to open
120
+
121
+ oDialog.open();
122
+
123
+ if (!oDialog._easyFillResizeHandlerId) {
124
+ this._registerResizeHandler(oController, oDialog);
125
+ }
126
+ oLogger.debug("openDialog: EasyFillDialog opened");
127
+ },
128
+
129
+ _registerResizeHandler: function(oController, oDialog) {
130
+ oDialog.attachEventOnce("afterOpen", function() {
131
+ var oSplitter = oController.byId("EasyFillMainFlex") &&
132
+ oController.byId("EasyFillMainFlex").findAggregatedObjects(true, function(o) {
133
+ return o.isA("sap.ui.layout.ResponsiveSplitter");
134
+ })[0];
135
+ if (!oSplitter) { return; }
136
+ var oDialogModel = oController.getView().getModel("easyFillDialogModel");
137
+ oDialog._easyFillResizeHandlerId = ResizeHandler.register(oSplitter, function() {
138
+ var bInPageMode = oSplitter.$().hasClass("sapUiRSVisiblePaginator");
139
+ oDialogModel.setProperty("/isSplitterPageMode", bInPageMode);
140
+ if (bInPageMode && !oDialogModel.getProperty("/isFullScreen")) {
141
+ oDialogModel.setProperty("/isFullScreen", true);
142
+ oController.byId("inputAreaSplitPane").getLayoutData().setSize("40%");
143
+ oController.byId("reviewAreaSplitPane").getLayoutData().setSize("60%");
144
+ }
145
+ });
130
146
  });
131
147
  },
132
148
 
@@ -158,27 +174,27 @@ sap.ui.define([
158
174
  * @param {object} oFieldCollector - EasyFillFieldCollector
159
175
  * @param {object} oEasyFillLayoutMode - EasyFillLayoutMode enum
160
176
  */
161
- onSelectionChange: function(oEvent, oController, oTemplateUtils, oRb, oFieldCollector, oEasyFillLayoutMode) {
177
+ onSelectionChange: function(oEvent, oController, oFieldCollector, oEasyFillLayoutMode, oOPStructureMap) {
162
178
  var sSelectedKey = oEvent.getSource().getSelectedKey();
163
179
  var oDialogModel = oController.getView().getModel("easyFillDialogModel");
164
- var oEntityType = oTemplateUtils.oCommonUtils.getMetaModelEntityType(
165
- oController.getOwnerComponent().getEntitySet()
166
- );
167
180
  oDialogModel.setProperty("/easyFillMode", sSelectedKey);
168
- var oLLMResult = oDialogModel.getProperty("/llmData") || {};
169
- // Use stored updatable subset when available; fall back to full LLM result
170
- // only when it is absent (e.g. before the first AI submit).
171
- // Important: an empty map is a valid state (all fields are non-updatable)
172
- // and must not trigger fallback, otherwise non-updatable fields appear as filled.
173
- var oStoredUpdatable = oDialogModel.getProperty("/updatableFields");
174
- var oUpdatableFields = (oStoredUpdatable !== undefined && oStoredUpdatable !== null)
175
- ? oStoredUpdatable
176
- : oLLMResult;
181
+
182
+ var oStoredUpdatable = oDialogModel.getProperty("/updatableFields") || {};
177
183
  var oNonUpdatableFields = oDialogModel.getProperty("/nonUpdatableFields") || {};
178
- var aData = (sSelectedKey === oEasyFillLayoutMode.CondensedMode)
179
- ? oFieldCollector.getSectionsForCondensedView(oLLMResult, oUpdatableFields, oNonUpdatableFields)
180
- : oFieldCollector.getSectionsForObjectPageView(oEntityType, oLLMResult, oRb, oNonUpdatableFields);
181
- oDialogModel.setProperty("/sections", aData);
184
+
185
+ var aSections;
186
+ if (sSelectedKey === oEasyFillLayoutMode.CondensedMode) {
187
+ aSections = oFieldCollector.getSectionInfoForCondensedMode(oStoredUpdatable, oNonUpdatableFields);
188
+ } else if (oOPStructureMap) {
189
+ aSections = oFieldCollector.applyLLMResultToStructureMap(
190
+ oOPStructureMap.fieldMap, oOPStructureMap.sections,
191
+ oStoredUpdatable, oNonUpdatableFields
192
+ );
193
+ } else {
194
+ aSections = oFieldCollector.getSectionInfoForCondensedMode(oStoredUpdatable, oNonUpdatableFields);
195
+ oLogger.warning("onSelectionChange: oOPStructureMap not available");
196
+ }
197
+ oDialogModel.setProperty("/sections", aSections);
182
198
  },
183
199
 
184
200
  /**