@sapui5/sap.suite.ui.generic.template 1.148.0 → 1.148.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 (81) 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/i18n/i18n_fr_CA.properties +2 -2
  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/controller/ControllerImplementation.js +6 -3
  7. package/src/sap/suite/ui/generic/template/ListReport/i18n/i18n_fr.properties +1 -1
  8. package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
  9. package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +1 -1
  10. package/src/sap/suite/ui/generic/template/ObjectPage/view/fragments/Actions.fragment.xml +13 -13
  11. package/src/sap/suite/ui/generic/template/QuickCreate/manifest.json +1 -1
  12. package/src/sap/suite/ui/generic/template/QuickView/manifest.json +1 -1
  13. package/src/sap/suite/ui/generic/template/genericUtilities/controlStateWrapperFactory/SmartFilterBarWrapper.js +20 -1
  14. package/src/sap/suite/ui/generic/template/lib/AppComponent.js +1 -1
  15. package/src/sap/suite/ui/generic/template/lib/CRUDManager.js +0 -7
  16. package/src/sap/suite/ui/generic/template/lib/CommonEventHandlers.js +57 -6
  17. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillAIOrchestrator.js +216 -0
  18. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillApplyHandler.js +325 -0
  19. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillDialogController.js +358 -0
  20. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFieldCollector.js +848 -0
  21. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFormRenderer.js +292 -0
  22. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillHandler.js +652 -1071
  23. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillTableRenderer.js +940 -0
  24. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillDialog.fragment.xml +41 -26
  25. package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterBarHandler.js +90 -73
  26. package/src/sap/suite/ui/generic/template/lib/i18n/i18n.properties +35 -8
  27. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ar.properties +29 -7
  28. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_bg.properties +29 -7
  29. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ca.properties +29 -7
  30. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cnr.properties +29 -7
  31. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cs.properties +29 -7
  32. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cy.properties +29 -7
  33. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_da.properties +29 -7
  34. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_de.properties +29 -7
  35. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_el.properties +29 -7
  36. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en.properties +29 -7
  37. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_GB.properties +29 -7
  38. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_US_saprigi.properties +29 -7
  39. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es.properties +29 -7
  40. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es_MX.properties +29 -7
  41. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_et.properties +29 -7
  42. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fi.properties +29 -7
  43. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr.properties +30 -8
  44. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr_CA.properties +31 -9
  45. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hi.properties +29 -7
  46. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hr.properties +30 -8
  47. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hu.properties +29 -7
  48. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_id.properties +29 -7
  49. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_it.properties +29 -7
  50. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_iw.properties +29 -7
  51. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ja.properties +29 -7
  52. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_kk.properties +29 -7
  53. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ko.properties +29 -7
  54. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lt.properties +29 -7
  55. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lv.properties +29 -7
  56. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_mk.properties +29 -7
  57. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ms.properties +29 -7
  58. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_nl.properties +30 -8
  59. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_no.properties +29 -7
  60. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pl.properties +29 -7
  61. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt.properties +29 -7
  62. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt_PT.properties +29 -7
  63. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ro.properties +29 -7
  64. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ru.properties +29 -7
  65. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sh.properties +29 -7
  66. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sk.properties +29 -7
  67. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sl.properties +29 -7
  68. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sr.properties +29 -7
  69. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sv.properties +29 -7
  70. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_th.properties +29 -7
  71. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_tr.properties +29 -7
  72. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_uk.properties +29 -7
  73. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_vi.properties +29 -7
  74. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_CN.properties +29 -7
  75. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_TW.properties +29 -7
  76. package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +1 -1
  77. package/src/sap/suite/ui/generic/template/library.js +1 -1
  78. package/src/sap/suite/ui/generic/template/themes/base/ObjectPage.less +30 -4
  79. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/ObjectPageSectionHandler.js +0 -282
  80. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillNonUpdatableSmartForm.fragment.xml +0 -18
  81. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillUpdatebleSmartForm.fragment.xml +0 -15
@@ -0,0 +1,292 @@
1
+ sap.ui.define([
2
+ "sap/ui/comp/smartform/GroupElement",
3
+ "sap/ui/comp/smartfield/SmartField",
4
+ "sap/m/Text",
5
+ "sap/ui/layout/form/ColumnElementData",
6
+ "sap/suite/ui/generic/template/genericUtilities/FeLogger",
7
+ "sap/suite/ui/generic/template/genericUtilities/FeError"
8
+ ], function(GroupElement, SmartField, Text, ColumnElementData, FeLogger, FeError) {
9
+ "use strict";
10
+
11
+ var sClassName = "lib.ai.EasyFill.EasyFillFormRenderer";
12
+ var oLogger = new FeLogger(sClassName).getLogger();
13
+
14
+ /**
15
+ * EasyFillFormRenderer
16
+ *
17
+ * Responsible for:
18
+ * 1. Programmatically populating SmartForm groups with SmartField controls based on LLM response data.
19
+ * 2. Managing the transient OData context used to stage AI-suggested values before the user confirms.
20
+ *
21
+ * Each SmartForm group in the EasyFill dialog receives:
22
+ * - An editable SmartField bound to the transient context (shows the AI-suggested value)
23
+ * - A read-only SmartField ("Previously:") bound to the original ObjectPage context (shows current value)
24
+ *
25
+ * The SmartForm shell containers (EasyFillUpdatableSmartForm, EasyFillNonUpdatableSmartForm) are
26
+ * created in XML fragments and populated here dynamically — no fields are declared in the XML.
27
+ */
28
+ return {
29
+
30
+ /**
31
+ * Populates a target SmartForm group with GroupElements for the given list of field names.
32
+ * For each field:
33
+ * - Creates an editable SmartField bound to the transient context (if updatable)
34
+ * alongside a read-only "Previously:" SmartField bound to the original OP context.
35
+ * - Creates a display-only SmartField bound to the OP context (if non-updatable).
36
+ *
37
+ * This function is called asynchronously (via setTimeout) to allow the SmartForm DOM to render
38
+ * before GroupElements are injected.
39
+ *
40
+ * @param {string} sId - the CustomData "id" value identifying the target SmartForm group
41
+ * @param {Array<string>} aFields - array of property names to render as SmartFields
42
+ * @param {string} sEasyFillMode - current layout mode (Condensed / ObjectPage) — for future use
43
+ * @param {object} oController - MVC controller (used to byId the ObjectPageLayout)
44
+ * @param {object} oTransientContextForEasyFill - transient OData context for AI-suggested values
45
+ * @param {object} oObjectPageContext - original ObjectPage binding context (current values)
46
+ * @param {object} mUpdatableLookupMap - map of { fieldName: value } for updatable fields only
47
+ * @param {object} oLLMData - flat map of { fieldName: aiValue } from the LLM response
48
+ * @returns {boolean} always returns true (used as a formatter return value in XML)
49
+ */
50
+ populateSmartFields: function(sId, aFields, sEasyFillMode, oController, oTransientContextForEasyFill, oObjectPageContext, mUpdatableLookupMap, oLLMData, fnOnFieldChange) {
51
+ var oObjectPageLayout = oController.byId("EasyFillObjectPageLayout");
52
+ if (!oObjectPageLayout || !Array.isArray(aFields) || aFields.length === 0) {
53
+ return true;
54
+ }
55
+
56
+ var sPreviouslyLabel = oController.getView().getModel("i18n").getResourceBundle().getText("EASY_FILL_PREVIOUSLY_LABEL");
57
+
58
+ // Defer injection until after the SmartForm has rendered into the DOM
59
+ setTimeout(function() {
60
+ var oTargetGroup = null;
61
+
62
+ // Walk the ObjectPageLayout section hierarchy to find the group
63
+ // matching the given CustomData "id" value.
64
+ // In condensed mode the SmartForm may be nested inside a wrapper VBox
65
+ // (used to prevent BlockLayout from placing the table side-by-side with
66
+ // the SmartForm on resize). We therefore check one level deeper when the
67
+ // direct block is not a SmartForm.
68
+ oObjectPageLayout.getSections().forEach(function(oSection) {
69
+ oSection.getSubSections().forEach(function(oSubSection) {
70
+ oSubSection.getBlocks().forEach(function(oBlock) {
71
+ var aSmartFormCandidates = [];
72
+ if (oBlock.isA("sap.ui.comp.smartform.SmartForm")) {
73
+ aSmartFormCandidates.push(oBlock);
74
+ } else if (typeof oBlock.getItems === "function") {
75
+ // Look one level inside (e.g. condensed-mode wrapper VBox)
76
+ oBlock.getItems().forEach(function(oItem) {
77
+ if (oItem.isA("sap.ui.comp.smartform.SmartForm")) {
78
+ aSmartFormCandidates.push(oItem);
79
+ }
80
+ });
81
+ }
82
+ aSmartFormCandidates.forEach(function(oSmartForm) {
83
+ oSmartForm.getGroups().forEach(function(oGroup) {
84
+ var oMatchedCustomData = oGroup.getCustomData().find(function(oData) {
85
+ return oData.getKey() === "id" && oData.getValue() === sId;
86
+ });
87
+ if (oMatchedCustomData) {
88
+ oTargetGroup = oGroup;
89
+ }
90
+ });
91
+ });
92
+ });
93
+ });
94
+ });
95
+
96
+ if (!oTargetGroup) {
97
+ oLogger.warning("populateSmartFields: no group found with id '" + sId + "'");
98
+ return;
99
+ }
100
+
101
+ // Clear any previously rendered GroupElements before re-populating
102
+ oTargetGroup.destroyGroupElements();
103
+
104
+ aFields.forEach(function(sKey) {
105
+ var bIsEditable = Object.prototype.hasOwnProperty.call(mUpdatableLookupMap || {}, sKey);
106
+
107
+ var oGroupElement = new GroupElement({
108
+ useHorizontalLayout: false
109
+ });
110
+
111
+ /**
112
+ * Primary SmartField:
113
+ * - If editable: bound to transient context, shows AI-suggested value
114
+ * - If non-editable: bound to OP context, display-only
115
+ */
116
+ var oSmartField = new SmartField({
117
+ value: "{" + sKey + "}",
118
+ editable: bIsEditable,
119
+ enabled: bIsEditable,
120
+ contextEditable: bIsEditable,
121
+ layoutData: new ColumnElementData({
122
+ cellsSmall: 12,
123
+ cellsLarge: 12
124
+ }),
125
+ editableChanged: function(oEvent) {
126
+ // Prevent the SmartField from toggling its own editability;
127
+ // editability is controlled exclusively by EasyFill logic
128
+ if (oEvent.getParameter("editable") !== bIsEditable) {
129
+ oEvent.getSource().setEditable(bIsEditable);
130
+ }
131
+ }
132
+ });
133
+
134
+ if (!bIsEditable) {
135
+ // Keep read-only behavior, but render like an input field (v4-like visual parity)
136
+ oSmartField.addStyleClass("sapUiEasyFillReadOnlyInputLike sapMInputBaseContentWrapper");
137
+ }
138
+
139
+ // Notify on user edits so SmartForm validity can re-gate the Confirm button.
140
+ if (bIsEditable && typeof fnOnFieldChange === "function") {
141
+ oSmartField.attachChange(fnOnFieldChange);
142
+
143
+ // Validate AI-seeded values on initial load — mirrors ObjectPage behaviour.
144
+ //
145
+ // In the OP, validation triggers because when a user TYPES a value the browser
146
+ // fires a change event which causes UI5 to call setExternalValue() on the inner
147
+ // control's binding. setExternalValue() has no fast-path: it always calls
148
+ // parseValue → validateValue → OData value-list lookup. If the lookup fails the
149
+ // binding calls setInvalidValue() + checkDataState() → ManagedObject fires
150
+ // validationError → inner control gets valueState="Error" (red mark).
151
+ //
152
+ // SmartForm.check() / SmartField.checkValuesValidity() do NOT work for
153
+ // AI-seeded values because SmartField._checkErrors() contains a fast-path:
154
+ // if (!isControlDirty() && formattedModelValue === displayedValue) → skip
155
+ // AI values always satisfy this (model = display = AI value, user never typed),
156
+ // so _checkErrors() short-circuits to "valid" without the OData lookup.
157
+ //
158
+ // Fix: after innerControlsCreated, call setExternalValue() on the inner
159
+ // control's own binding with the currently displayed value. This is exactly
160
+ // the same path the OP uses when the user types. For async types (TextArrangement
161
+ // with ValueList) the call starts the OData lookup:
162
+ // valid value → resolves quietly, no red mark
163
+ // invalid value → rejects → setInvalidValue + checkDataState → red mark
164
+ // Non-async types fall through to a plain fnOnFieldChange call because
165
+ // SmartForm.check() already handles them correctly (no fast-path for sync).
166
+ oSmartField.attachInnerControlsCreated(function() {
167
+ var oInnerControl = oSmartField.getFirstInnerControl();
168
+ if (oInnerControl && typeof oInnerControl.getValue === "function") {
169
+ var oBinding = oInnerControl.getBinding("value");
170
+ var oType = oBinding && typeof oBinding.getType === "function" && oBinding.getType();
171
+ if (oType && oType.async && typeof oBinding.setExternalValue === "function") {
172
+ // setExternalValue replicates the "user typed this value" path:
173
+ // parseValue → validateValue → OData lookup → validationError/Success
174
+ Promise.resolve(oBinding.setExternalValue(oInnerControl.getValue()))
175
+ .catch(Function.prototype)
176
+ .finally(fnOnFieldChange);
177
+ return;
178
+ }
179
+ }
180
+ fnOnFieldChange();
181
+ });
182
+ }
183
+
184
+ /**
185
+ * "Previously:" SmartField (read-only):
186
+ * - Only shown for editable fields to display the current OP value for comparison
187
+ * - Bound to the original ObjectPage context
188
+ */
189
+ var oSmartFieldPrev = new SmartField({
190
+ value: "{" + sKey + "}",
191
+ editable: false,
192
+ enabled: false,
193
+ contextEditable: false,
194
+ showLabel: false,
195
+ layoutData: new ColumnElementData({
196
+ cellsSmall: 9,
197
+ cellsLarge: 9
198
+ }),
199
+ editableChanged: function(oEvent) {
200
+ // Always keep the "previously" field read-only
201
+ if (oEvent.getParameter("editable") !== false) {
202
+ oEvent.getSource().setEditable(false);
203
+ }
204
+ }
205
+ });
206
+
207
+ if (oTransientContextForEasyFill) {
208
+ // Primary field always uses transient context to show AI-proposed value.
209
+ // Field editability is controlled by bIsEditable.
210
+ oSmartField.setBindingContext(oTransientContextForEasyFill);
211
+
212
+ // Only seed the transient context with the AI-suggested value on the first
213
+ // population. On subsequent calls (e.g. mode switch), the transient context
214
+ // already holds the current value — overwriting it would discard user edits.
215
+ if (oTransientContextForEasyFill.getProperty(sKey) === undefined) {
216
+ oTransientContextForEasyFill.setProperty(sKey, oLLMData[sKey]);
217
+ }
218
+ } else {
219
+ // Fallback: without transient context, bind to original OP context.
220
+ oSmartField.setBindingContext(oObjectPageContext);
221
+ }
222
+
223
+ // Previous value is always shown from the original ObjectPage context.
224
+ oSmartFieldPrev.setBindingContext(oObjectPageContext);
225
+
226
+ // Build the GroupElement: [label+primary SmartField] [Previously: label] [preview SmartField]
227
+ oGroupElement.addElement(oSmartField); // SmartField provides the label
228
+ oGroupElement.addElement(new Text({
229
+ text: sPreviouslyLabel,
230
+ layoutData: new ColumnElementData({
231
+ cellsSmall: 3,
232
+ cellsLarge: 3
233
+ })
234
+ }).addStyleClass("sapEasyFillPreviouslyLabel"));
235
+ oGroupElement.addElement(oSmartFieldPrev);
236
+ oTargetGroup.addGroupElement(oGroupElement);
237
+ });
238
+
239
+ // Trigger initial SmartForm validation now that all SmartFields are rendered
240
+ if (typeof fnOnFieldChange === "function") {
241
+ fnOnFieldChange();
242
+ }
243
+ oLogger.debug("populateSmartFields: populated " + aFields.length + " fields for group '" + sId + "'");
244
+ }, 0);
245
+
246
+ return true;
247
+ },
248
+
249
+ /**
250
+ * Creates a new transient OData context for staging AI-suggested values.
251
+ * If a previous transient context exists, it is reset first.
252
+ *
253
+ * The transient context is created using a dedicated deferred group ("EasyFillFETransientChanges")
254
+ * so that no batch request is triggered to the backend until the user confirms via the dialog.
255
+ *
256
+ * @param {object} oTransientContextForEasyFill - current transient context (may be null)
257
+ * @param {object} oObjectPageModel - the OData model of the ObjectPage
258
+ * @param {object} oController - MVC controller (used to get the entity set name)
259
+ * @returns {object} the new transient OData context
260
+ */
261
+ makeTransientContext: function(oTransientContextForEasyFill, oObjectPageModel, oController) {
262
+ // Reset any existing transient context before creating a new one
263
+ if (oTransientContextForEasyFill) {
264
+ this.resetTransientContext(oTransientContextForEasyFill, oObjectPageModel);
265
+ }
266
+
267
+ var sEntitySet = oController.getOwnerComponent().getEntitySet();
268
+ var oNewContext = oObjectPageModel.createEntry("/" + sEntitySet, {
269
+ groupId: "EasyFillFETransientChanges",
270
+ changeSetId: "EasyFillFETransientChanges"
271
+ });
272
+
273
+ oLogger.debug("makeTransientContext: created transient context for entity set '" + sEntitySet + "'");
274
+ return oNewContext;
275
+ },
276
+
277
+ /**
278
+ * Rolls back the transient context, discarding all staged AI values without triggering a backend call.
279
+ * Called on dialog cancel or when a new AI submission replaces the previous result.
280
+ *
281
+ * @param {object} oTransientContextForEasyFill - the transient context to reset
282
+ * @param {object} oObjectPageModel - the OData model of the ObjectPage
283
+ */
284
+ resetTransientContext: function(oTransientContextForEasyFill, oObjectPageModel) {
285
+ if (oTransientContextForEasyFill) {
286
+ // Reset changes for the transient context path only, without triggering side effects
287
+ oObjectPageModel.resetChanges([oTransientContextForEasyFill.getPath()], false, true);
288
+ oLogger.debug("resetTransientContext: transient context reset");
289
+ }
290
+ }
291
+ };
292
+ });