@sapui5/sap.suite.ui.generic.template 1.148.0 → 1.148.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 (77) 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/i18n/i18n_fr.properties +1 -1
  7. package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
  8. package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +1 -1
  9. package/src/sap/suite/ui/generic/template/ObjectPage/view/fragments/Actions.fragment.xml +13 -13
  10. package/src/sap/suite/ui/generic/template/QuickCreate/manifest.json +1 -1
  11. package/src/sap/suite/ui/generic/template/QuickView/manifest.json +1 -1
  12. package/src/sap/suite/ui/generic/template/lib/AppComponent.js +1 -1
  13. package/src/sap/suite/ui/generic/template/lib/CommonEventHandlers.js +57 -6
  14. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillAIOrchestrator.js +185 -0
  15. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillApplyHandler.js +476 -0
  16. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillDialogController.js +311 -0
  17. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFieldCollector.js +669 -0
  18. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFormRenderer.js +217 -0
  19. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillHandler.js +323 -1120
  20. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillTableRenderer.js +491 -0
  21. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillDialog.fragment.xml +14 -10
  22. package/src/sap/suite/ui/generic/template/lib/i18n/i18n.properties +11 -8
  23. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ar.properties +14 -0
  24. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_bg.properties +14 -0
  25. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ca.properties +14 -0
  26. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cnr.properties +14 -0
  27. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cs.properties +14 -0
  28. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cy.properties +14 -0
  29. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_da.properties +14 -0
  30. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_de.properties +14 -0
  31. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_el.properties +14 -0
  32. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en.properties +14 -0
  33. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_GB.properties +14 -0
  34. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_US_saprigi.properties +14 -0
  35. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es.properties +14 -0
  36. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es_MX.properties +14 -0
  37. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_et.properties +14 -0
  38. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fi.properties +14 -0
  39. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr.properties +15 -1
  40. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr_CA.properties +15 -1
  41. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hi.properties +14 -0
  42. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hr.properties +15 -1
  43. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hu.properties +14 -0
  44. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_id.properties +14 -0
  45. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_it.properties +14 -0
  46. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_iw.properties +14 -0
  47. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ja.properties +14 -0
  48. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_kk.properties +14 -0
  49. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ko.properties +14 -0
  50. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lt.properties +14 -0
  51. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lv.properties +14 -0
  52. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_mk.properties +14 -0
  53. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ms.properties +14 -0
  54. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_nl.properties +15 -1
  55. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_no.properties +14 -0
  56. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pl.properties +14 -0
  57. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt.properties +14 -0
  58. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt_PT.properties +14 -0
  59. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ro.properties +14 -0
  60. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ru.properties +14 -0
  61. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sh.properties +14 -0
  62. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sk.properties +14 -0
  63. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sl.properties +14 -0
  64. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sr.properties +14 -0
  65. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sv.properties +14 -0
  66. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_th.properties +14 -0
  67. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_tr.properties +14 -0
  68. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_uk.properties +14 -0
  69. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_vi.properties +14 -0
  70. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_CN.properties +14 -0
  71. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_TW.properties +14 -0
  72. package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +1 -1
  73. package/src/sap/suite/ui/generic/template/library.js +1 -1
  74. package/src/sap/suite/ui/generic/template/themes/base/ObjectPage.less +8 -3
  75. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/ObjectPageSectionHandler.js +0 -282
  76. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillNonUpdatableSmartForm.fragment.xml +0 -18
  77. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillUpdatebleSmartForm.fragment.xml +0 -15
@@ -0,0 +1,491 @@
1
+ sap.ui.define([
2
+ "sap/ui/comp/smartfield/SmartField",
3
+ "sap/m/Text",
4
+ "sap/m/Title",
5
+ "sap/m/Table",
6
+ "sap/m/Column",
7
+ "sap/m/ColumnListItem",
8
+ "sap/m/VBox",
9
+ "sap/m/HBox",
10
+ "sap/m/SegmentedButton",
11
+ "sap/m/SegmentedButtonItem",
12
+ "sap/suite/ui/generic/template/genericUtilities/FeLogger",
13
+ "sap/suite/ui/generic/template/genericUtilities/FeError"
14
+ ], function(SmartField, Text, Title, Table, Column, ColumnListItem, VBox, HBox, SegmentedButton, SegmentedButtonItem, FeLogger, FeError) {
15
+ "use strict";
16
+
17
+ var sClassName = "lib.ai.EasyFill.EasyFillTableRenderer";
18
+ var oLogger = new FeLogger(sClassName).getLogger();
19
+ var iMaxPreviewRows = 20;
20
+
21
+ /**
22
+ * EasyFillTableRenderer
23
+ *
24
+ * Responsible for rendering the SmartTable collection preview in the EasyFill dialog.
25
+ * For each collection (navigation property) with LLM-suggested row updates, this module:
26
+ *
27
+ * 1. Creates transient OData row contexts for preview rendering.
28
+ * 2. Creates a "Previous Values" read-only table and a "New Values" editable SmartField table.
29
+ * 3. Renders a SegmentedButton toggle between the two views.
30
+ * 4. Provides reset logic to discard staged values if the user cancels.
31
+ *
32
+ * The table preview container (VBox#EasyFillTablePreviewContainer) in the dialog XML is populated
33
+ * programmatically — no table rows are declared in the fragment XML.
34
+ */
35
+ return {
36
+
37
+ /**
38
+ * Renders collection (SmartTable) previews into the EasyFillTablePreviewContainer VBox.
39
+ * For each collection with AI-suggested updates:
40
+ * - Creates transient staging contexts for the preview rows
41
+ * - Creates a Previous/New table pair with a toggle SegmentedButton
42
+ * - Appends the section to the container
43
+ *
44
+ * @param {object} mCollectionUpdates - map of { navProperty: [ rowUpdate ] } from AI response
45
+ * @param {object} mFieldMapping - full LLM field mapping (used to get item properties and descriptions)
46
+ * @param {Array} aTableValidationErrors - validation errors from value-help checks
47
+ * @param {object} oController - MVC controller (used to byId the container)
48
+ * @param {object} oRb - i18n resource bundle
49
+ * @param {object} mCollectionState - collection tracking state { mCollectionRowContexts, mCollectionRowContextsByPath, mCollectionProperties }
50
+ * @param {object} oTableStagingState - mutable table staging state { mStagedRows }
51
+ * @param {object} oObjectPageModel - the OData model used to create transient staging contexts
52
+ * @param {function} fnOnTableFieldChange - callback invoked when a preview table cell changes
53
+ */
54
+ renderCollectionPreviews: function(mCollectionUpdates, mFieldMapping, aTableValidationErrors, oController, oRb, mCollectionState, oTableStagingState, oObjectPageModel, fnOnTableFieldChange) {
55
+ var oTablePreviewContainer = oController.byId("EasyFillTablePreviewContainer");
56
+ if (!oTablePreviewContainer) {
57
+ oLogger.warning("renderCollectionPreviews: EasyFillTablePreviewContainer not found");
58
+ return;
59
+ }
60
+
61
+ // Remove all previously rendered table sections
62
+ oTablePreviewContainer.destroyItems();
63
+
64
+ this._initializeStagedCollectionRows(
65
+ mCollectionUpdates,
66
+ mFieldMapping,
67
+ mCollectionState,
68
+ oTableStagingState,
69
+ oObjectPageModel
70
+ );
71
+
72
+ var that = this;
73
+ Object.keys(mCollectionUpdates).forEach(function(sCollectionName) {
74
+ var oCollectionMeta = mFieldMapping[sCollectionName];
75
+ if (!oCollectionMeta || !oCollectionMeta.itemProperties) {
76
+ return;
77
+ }
78
+
79
+ var aPropertyNames = Object.keys(oCollectionMeta.itemProperties || {});
80
+ if (!aPropertyNames.length) {
81
+ return;
82
+ }
83
+ var aPreviewRows = (oTableStagingState.mStagedRows[sCollectionName] || []).filter(function(oStagedRow) {
84
+ return oStagedRow.isPreviewVisible;
85
+ });
86
+
87
+ if (!aPreviewRows.length) {
88
+ return;
89
+ }
90
+
91
+ // Previous values table (read-only, initially hidden)
92
+ var aPreviousRows = aPreviewRows.map(function(oPreviewRow) {
93
+ return that._buildCollectionPreviewRowFromContext(aPropertyNames, oPreviewRow.realContext);
94
+ });
95
+ var oPreviousTable = that._createPreviewTable(aPropertyNames, oCollectionMeta.itemProperties, aPreviousRows);
96
+ oPreviousTable.setVisible(false);
97
+
98
+ // New values table (editable SmartFields, initially visible)
99
+ var oNewTable = that._createEditableNewTable(
100
+ aPropertyNames,
101
+ oCollectionMeta.itemProperties,
102
+ aPreviewRows,
103
+ sCollectionName,
104
+ mCollectionState,
105
+ fnOnTableFieldChange
106
+ );
107
+
108
+ // Section title showing collection label and row count
109
+ var oSectionTitle = new Title({
110
+ level: "H5",
111
+ text: (oCollectionMeta.description || sCollectionName) + " (" + aPreviewRows.length + ")"
112
+ });
113
+
114
+ // Toggle button between "Previous" and "New" views
115
+ var oSegmentedButton = new SegmentedButton({
116
+ selectedKey: "new",
117
+ width: "auto",
118
+ items: [
119
+ new SegmentedButtonItem({ key: "previous", text: oRb.getText("EASY_FILL_TABLE_VIEW_PREVIOUS"), width: "auto" }),
120
+ new SegmentedButtonItem({ key: "new", text: oRb.getText("EASY_FILL_TABLE_VIEW_NEW"), width: "auto" })
121
+ ],
122
+ selectionChange: function() {
123
+ var sKey = oSegmentedButton.getSelectedKey();
124
+ oPreviousTable.setVisible(sKey === "previous");
125
+ oNewTable.setVisible(sKey === "new");
126
+ }
127
+ });
128
+
129
+ var oHeader = new HBox({
130
+ justifyContent: "SpaceBetween",
131
+ items: [oSectionTitle, oSegmentedButton]
132
+ }).addStyleClass("sapUiSmallMarginTop");
133
+
134
+ var oSection = new VBox({
135
+ items: [oHeader, oPreviousTable, oNewTable]
136
+ }).addStyleClass("sapSmartTemplatesObjectPageEasyFillTableSection");
137
+
138
+ oTablePreviewContainer.addItem(oSection);
139
+ oLogger.debug("renderCollectionPreviews: rendered collection '" + sCollectionName + "' with " + aPreviewRows.length + " rows");
140
+ });
141
+ },
142
+
143
+ /**
144
+ * Resets and clears all transient collection contexts created for table preview staging.
145
+ *
146
+ * @param {object} oTableStagingState - table staging state { mStagedRows }
147
+ * @param {object} oObjectPageModel - the OData model
148
+ */
149
+ resetStagedCollectionContexts: function(oTableStagingState, oObjectPageModel) {
150
+ var aTransientPaths = [];
151
+
152
+ Object.keys((oTableStagingState && oTableStagingState.mStagedRows) || {}).forEach(function(sCollectionName) {
153
+ (oTableStagingState.mStagedRows[sCollectionName] || []).forEach(function(oStagedRow) {
154
+ var oTransientContext = oStagedRow.transientContext;
155
+ var sTransientPath = oTransientContext && oTransientContext.getPath && oTransientContext.getPath();
156
+ if (sTransientPath) {
157
+ aTransientPaths.push(sTransientPath);
158
+ }
159
+ });
160
+ });
161
+
162
+ if (aTransientPaths.length && oObjectPageModel) {
163
+ oObjectPageModel.resetChanges(aTransientPaths, false, true);
164
+ }
165
+
166
+ this._clearStagedCollectionState(oTableStagingState);
167
+ oLogger.debug("resetStagedCollectionContexts: transient table contexts reset");
168
+ },
169
+
170
+ // ─── Private Helpers ─────────────────────────────────────────────────────
171
+
172
+ _initializeStagedCollectionRows: function(mCollectionUpdates, mFieldMapping, mCollectionState, oTableStagingState, oObjectPageModel) {
173
+ var that = this;
174
+ this._clearStagedCollectionState(oTableStagingState);
175
+
176
+ Object.keys(mCollectionUpdates || {}).forEach(function(sCollectionName) {
177
+ var oCollectionMeta = mFieldMapping[sCollectionName];
178
+ var aRowUpdates = mCollectionUpdates[sCollectionName] || [];
179
+ var aCollectionRowContexts = mCollectionState.mCollectionRowContexts[sCollectionName] || [];
180
+ var mCollectionPropertyMap = mCollectionState.mCollectionProperties[sCollectionName] || Object.create(null);
181
+ var aPropertyNames = Object.keys((oCollectionMeta && oCollectionMeta.itemProperties) || {});
182
+
183
+ if (!oCollectionMeta || !oCollectionMeta.entitySet || !aPropertyNames.length) {
184
+ return;
185
+ }
186
+
187
+ var mUpdatesByIdentity = Object.create(null);
188
+ aRowUpdates.forEach(function(oRowUpdate, iUpdateIndex) {
189
+ var oResolvedUpdate = that._resolveCollectionRowContext(sCollectionName, oRowUpdate, mCollectionState);
190
+ mUpdatesByIdentity[that._getCollectionRowIdentity(oResolvedUpdate, oRowUpdate, iUpdateIndex)] = oRowUpdate;
191
+ });
192
+
193
+ oTableStagingState.mStagedRows[sCollectionName] = [];
194
+
195
+ aCollectionRowContexts.forEach(function(oRealContext, iRowIndex) {
196
+ var oResolvedRow = { context: oRealContext, rowIndex: iRowIndex };
197
+ var sIdentity = that._getCollectionRowIdentity(oResolvedRow, null, iRowIndex);
198
+ var oRowUpdate = mUpdatesByIdentity[sIdentity];
199
+ var bIsPreviewVisible = iRowIndex < iMaxPreviewRows;
200
+
201
+ if (!bIsPreviewVisible && !oRowUpdate) {
202
+ return;
203
+ }
204
+
205
+ var oTransientContext = that._createTransientCollectionContext(oCollectionMeta.entitySet, oObjectPageModel);
206
+ if (!oTransientContext) {
207
+ return;
208
+ }
209
+
210
+ var oRealRowObject = oRealContext.getObject && oRealContext.getObject();
211
+ that._seedTransientContextFromRowObject(oTransientContext, oRealRowObject);
212
+ that._applyRowUpdateToTransientContext(oTransientContext, oRowUpdate, mCollectionPropertyMap, oRealRowObject);
213
+
214
+ oTableStagingState.mStagedRows[sCollectionName].push({
215
+ realContext: oRealContext,
216
+ transientContext: oTransientContext,
217
+ rowIndex: iRowIndex,
218
+ propertyNames: aPropertyNames,
219
+ isPreviewVisible: bIsPreviewVisible
220
+ });
221
+ });
222
+ });
223
+ },
224
+
225
+ /**
226
+ * Creates a read-only sap.m.Table for displaying table row data (used for "Previous Values" view).
227
+ * All cells are rendered as plain Text controls.
228
+ *
229
+ * @param {Array<string>} aPropertyNames - ordered list of property names to show as columns
230
+ * @param {object} oItemProperties - map of { propName: { description, dataType } }
231
+ * @param {Array<object>} aRows - array of plain row value objects
232
+ * @param {function} [fnCellFormatter] - optional custom cell formatter (oRow, sPropName, sRawValue) → string
233
+ * @returns {sap.m.Table}
234
+ */
235
+ _createPreviewTable: function(aPropertyNames, oItemProperties, aRows, fnCellFormatter) {
236
+ var aColumns = aPropertyNames.map(function(sPropertyName) {
237
+ return new Column({
238
+ header: new Text({
239
+ text: (oItemProperties[sPropertyName] && oItemProperties[sPropertyName].description) || sPropertyName
240
+ })
241
+ });
242
+ });
243
+
244
+ var aItems = aRows.map(function(oRow) {
245
+ return new ColumnListItem({
246
+ cells: aPropertyNames.map(function(sPropertyName) {
247
+ var sText = fnCellFormatter
248
+ ? fnCellFormatter(oRow, sPropertyName, this._stringifyCellValue(oRow[sPropertyName]))
249
+ : this._stringifyCellValue(oRow[sPropertyName]);
250
+ return new Text({ text: sText });
251
+ }.bind(this))
252
+ });
253
+ }.bind(this));
254
+
255
+ return new Table({
256
+ columns: aColumns,
257
+ items: aItems,
258
+ fixedLayout: false,
259
+ autoPopinMode: true
260
+ }).addStyleClass("sapSmartTemplatesObjectPageEasyFillTablePreview");
261
+ },
262
+
263
+ /**
264
+ * Creates an editable sap.m.Table for displaying AI-suggested row updates.
265
+ * Editable cells are rendered as SmartField controls bound to the OData row context.
266
+ * Non-editable cells are rendered as plain Text controls.
267
+ *
268
+ * @param {Array<string>} aPropertyNames - ordered list of property names to show as columns
269
+ * @param {object} oItemProperties - map of { propName: { description, dataType } }
270
+ * @param {Array<object>} aPreviewRows - enriched row objects with context, newValues, etc.
271
+ * @param {string} sCollectionName - navigation property name (used to look up property metadata)
272
+ * @param {object} mCollectionState - collection tracking state (used to get property metadata)
273
+ * @returns {sap.m.Table}
274
+ */
275
+ _createEditableNewTable: function(aPropertyNames, oItemProperties, aPreviewRows, sCollectionName, mCollectionState, fnOnTableFieldChange) {
276
+ var aColumns = aPropertyNames.map(function(sPropName) {
277
+ return new Column({
278
+ header: new Text({
279
+ text: (oItemProperties[sPropName] && oItemProperties[sPropName].description) || sPropName
280
+ })
281
+ });
282
+ });
283
+
284
+ var mCollectionPropertyMap = mCollectionState.mCollectionProperties[sCollectionName] || Object.create(null);
285
+ var that = this;
286
+
287
+ var aItems = aPreviewRows.map(function(oPreviewRow) {
288
+ var oContext = oPreviewRow.transientContext;
289
+ var oRowObject = oPreviewRow.realContext && oPreviewRow.realContext.getObject && oPreviewRow.realContext.getObject();
290
+
291
+ var aCells = aPropertyNames.map(function(sPropName) {
292
+ if (!oContext) {
293
+ return new Text({ text: "" });
294
+ }
295
+
296
+ var oPropertyMeta = mCollectionPropertyMap[sPropName];
297
+ var bEditable = that._isEditableProperty(oPropertyMeta, oRowObject);
298
+
299
+ // Use a SmartField so value-help and type-specific rendering are supported
300
+ var oSmartField = new SmartField({
301
+ value: "{" + sPropName + "}",
302
+ editable: bEditable,
303
+ enabled: bEditable,
304
+ contextEditable: bEditable,
305
+ change: function() {
306
+ if (typeof fnOnTableFieldChange === "function") {
307
+ fnOnTableFieldChange();
308
+ }
309
+ },
310
+ editableChanged: function(oEvent) {
311
+ // Keep table SmartField editability deterministic during preview
312
+ if (oEvent.getParameter("editable") !== bEditable) {
313
+ oEvent.getSource().setEditable(bEditable);
314
+ }
315
+ }
316
+ });
317
+
318
+ return oSmartField;
319
+ });
320
+
321
+ var oItem = new ColumnListItem({ cells: aCells });
322
+ if (oContext) {
323
+ oItem.setBindingContext(oContext);
324
+ }
325
+ return oItem;
326
+ });
327
+
328
+ return new Table({
329
+ columns: aColumns,
330
+ items: aItems,
331
+ fixedLayout: false,
332
+ autoPopinMode: true
333
+ }).addStyleClass("sapSmartTemplatesObjectPageEasyFillTablePreview");
334
+ },
335
+
336
+ /**
337
+ * Builds a plain preview row object from a given OData context.
338
+ *
339
+ * @param {Array<string>} aPropertyNames - property names to include
340
+ * @param {object} oContext - OData context providing the property values
341
+ * @returns {object} plain row data object
342
+ */
343
+ _buildCollectionPreviewRowFromContext: function(aPropertyNames, oContext) {
344
+ var oPreviewRow = {};
345
+
346
+ aPropertyNames.forEach(function(sPropertyName) {
347
+ oPreviewRow[sPropertyName] = oContext ? oContext.getProperty(sPropertyName) : "";
348
+ });
349
+
350
+ return oPreviewRow;
351
+ },
352
+
353
+ _createTransientCollectionContext: function(sEntitySetName, oObjectPageModel) {
354
+ if (!sEntitySetName || !oObjectPageModel) {
355
+ return null;
356
+ }
357
+
358
+ return oObjectPageModel.createEntry("/" + sEntitySetName, {
359
+ groupId: "EasyFillFETransientChanges",
360
+ changeSetId: "EasyFillFETransientChanges"
361
+ });
362
+ },
363
+
364
+ _seedTransientContextFromRowObject: function(oTransientContext, oRowObject) {
365
+ Object.keys(oRowObject || {}).forEach(function(sPropertyName) {
366
+ var vValue = oRowObject[sPropertyName];
367
+ if (vValue === null || vValue === undefined || typeof vValue !== "object" || vValue instanceof Date) {
368
+ oTransientContext.setProperty(sPropertyName, vValue);
369
+ }
370
+ });
371
+ },
372
+
373
+ _applyRowUpdateToTransientContext: function(oTransientContext, oRowUpdate, mCollectionPropertyMap, oRealRowObject) {
374
+ var that = this;
375
+ Object.keys(oRowUpdate || {}).forEach(function(sPropertyName) {
376
+ if (sPropertyName === "_rowIndex" || sPropertyName === "_contextPath") {
377
+ return;
378
+ }
379
+
380
+ var oPropertyMeta = mCollectionPropertyMap[sPropertyName];
381
+ if (!that._isEditableProperty(oPropertyMeta, oRealRowObject)) {
382
+ return;
383
+ }
384
+
385
+ oTransientContext.setProperty(sPropertyName, oRowUpdate[sPropertyName]);
386
+ });
387
+ },
388
+
389
+ _clearStagedCollectionState: function(oTableStagingState) {
390
+ Object.keys((oTableStagingState && oTableStagingState.mStagedRows) || {}).forEach(function(sCollectionName) {
391
+ delete oTableStagingState.mStagedRows[sCollectionName];
392
+ });
393
+ },
394
+
395
+ /**
396
+ * Resolves an OData row context for a given collection row update.
397
+ * Prefers context path lookup; falls back to row index.
398
+ *
399
+ * @param {string} sCollectionName - navigation property name
400
+ * @param {object} oRowUpdate - the AI row update object ({ _contextPath?, _rowIndex? })
401
+ * @param {object} mCollectionState - collection tracking state
402
+ * @returns {{ context, rowIndex }|null}
403
+ */
404
+ _resolveCollectionRowContext: function(sCollectionName, oRowUpdate, mCollectionState) {
405
+ var mByPath = mCollectionState.mCollectionRowContextsByPath[sCollectionName] || Object.create(null);
406
+ var sContextPath = oRowUpdate && oRowUpdate._contextPath;
407
+
408
+ // Prefer context path (more stable across refreshes)
409
+ if (typeof sContextPath === "string" && mByPath[sContextPath]) {
410
+ return mByPath[sContextPath];
411
+ }
412
+
413
+ // Fallback to row index
414
+ var iRowIndex = oRowUpdate && oRowUpdate._rowIndex;
415
+ var aRowContexts = mCollectionState.mCollectionRowContexts[sCollectionName] || [];
416
+ if (typeof iRowIndex === "number" && aRowContexts[iRowIndex]) {
417
+ return { context: aRowContexts[iRowIndex], rowIndex: iRowIndex };
418
+ }
419
+
420
+ return null;
421
+ },
422
+
423
+ /**
424
+ * Returns a stable string identity for a collection row, used as a map key.
425
+ * Priority: context path → _contextPath from update → _rowIndex → fallback index string.
426
+ *
427
+ * @param {object} oResolvedRow - { context, rowIndex } or null
428
+ * @param {object} oRowUpdate - the AI row update object
429
+ * @param {number} iFallbackIndex - fallback numeric index
430
+ * @returns {string}
431
+ */
432
+ _getCollectionRowIdentity: function(oResolvedRow, oRowUpdate, iFallbackIndex) {
433
+ if (oResolvedRow && oResolvedRow.context && oResolvedRow.context.getPath) {
434
+ return oResolvedRow.context.getPath();
435
+ }
436
+ if (oRowUpdate && typeof oRowUpdate._contextPath === "string") {
437
+ return oRowUpdate._contextPath;
438
+ }
439
+ if (oRowUpdate && typeof oRowUpdate._rowIndex === "number") {
440
+ return "index:" + String(oRowUpdate._rowIndex);
441
+ }
442
+ return "row:" + String(iFallbackIndex);
443
+ },
444
+
445
+ /**
446
+ * Converts a raw cell value to a display string for read-only table cells.
447
+ * Handles null/undefined, Date objects, and primitives.
448
+ *
449
+ * @param {*} vValue
450
+ * @returns {string}
451
+ */
452
+ _stringifyCellValue: function(vValue) {
453
+ if (vValue === null || vValue === undefined) {
454
+ return "";
455
+ }
456
+ if (vValue instanceof Date) {
457
+ return vValue.toISOString();
458
+ }
459
+ return String(vValue);
460
+ },
461
+
462
+ /**
463
+ * Checks whether a collection property is editable given the current row data object.
464
+ * Delegates to the same annotation checks used in EasyFillFieldCollector.isEditableByContextObject.
465
+ * Duplicated here to keep TableRenderer self-contained (no circular dependency).
466
+ *
467
+ * @param {object} oPropertyMeta - OData property metadata
468
+ * @param {object} oRowObject - plain row data object
469
+ * @returns {boolean}
470
+ */
471
+ _isEditableProperty: function(oPropertyMeta, oRowObject) {
472
+ if (!oPropertyMeta) {
473
+ return false;
474
+ }
475
+ var sUpdatable = oPropertyMeta["sap:updatable"];
476
+ if (sUpdatable) {
477
+ return sUpdatable !== "false";
478
+ }
479
+ var oAnnotation = oPropertyMeta["com.sap.vocabularies.Common.v1.FieldControl"];
480
+ if (oAnnotation && oAnnotation["EnumMember"]) {
481
+ return oAnnotation["EnumMember"] !== "com.sap.vocabularies.Common.v1.FieldControlType/ReadOnly";
482
+ }
483
+ var sFieldControl = oPropertyMeta["sap:field-control"];
484
+ if (sFieldControl) {
485
+ var iFieldControlValue = oRowObject && oRowObject[sFieldControl];
486
+ return iFieldControlValue !== 1;
487
+ }
488
+ return true;
489
+ }
490
+ };
491
+ });
@@ -50,6 +50,7 @@ xmlns:fesr="http://schemas.sap.com/sapui5/extension/sap.ui.core.FESR/1">
50
50
  type="Transparent"
51
51
  press=".onEasyFillClearAll"
52
52
  fesr:press="fe2:ef:clearAll"
53
+ enabled="{easyFillDialogModel>/isEasyFillButtonEnabled}"
53
54
  text="{i18n>EASYFILL_CLEAR_ALL}"/>
54
55
  </FlexBox>
55
56
  </FlexBox>
@@ -67,31 +68,34 @@ xmlns:fesr="http://schemas.sap.com/sapui5/extension/sap.ui.core.FESR/1">
67
68
  title="{path: 'easyFillDialogModel>/stateType', formatter: '.formatIllustrationTitle'}"
68
69
  description="{path: 'easyFillDialogModel>/stateType', formatter: '.formatIllustrationDescription'}"/>
69
70
  <!-- <ScrollContainer height="100%" horizontal = "true"> -->
70
- <uxap:ObjectPageLayout visible="{easyFillDialogModel>/isFormVisible}" id="EasyFillObjectPageLayout" sections="{path: 'easyFillDialogModel>/sections', templateShareable: false}">
71
+ <uxap:ObjectPageLayout visible="{easyFillDialogModel>/isFormVisible}" id="EasyFillObjectPageLayout" sections="{path: 'easyFillDialogModel>/sections', templateShareable: false}" alwaysShowContentHeader="true" upperCaseAnchorBar="false">
71
72
  <uxap:headerTitle>
72
- <uxap:ObjectPageHeader objectTitle="{i18n>EASY_FILL_FILLED_FIELDS}">
73
+ <uxap:ObjectPageDynamicHeaderTitle>
74
+ <uxap:heading>
75
+ <Title text="{i18n>EASY_FILL_FILLED_FIELDS}" wrapping="true" level="H2"/>
76
+ </uxap:heading>
73
77
  <uxap:actions>
74
- <SegmentedButton selectedKey="{easyFillDialogModel>/easyFillMode}" selectionChange=".onSelectionChange" class="sapUiSmallMarginBottom">
78
+ <SegmentedButton selectedKey="{easyFillDialogModel>/easyFillMode}" selectionChange=".onSelectionChange">
75
79
  <items>
76
- <SegmentedButtonItem icon="sap-icon://increase-line-height" key="CondensedMode"/>
77
- <SegmentedButtonItem icon="sap-icon://decrease-line-height" key="ObjectPageMode"/>
80
+ <SegmentedButtonItem icon="sap-icon://increase-line-height" key="CondensedMode" tooltip="{i18n>EASY_FILL_CONDENSED_VIEW_TOOLTIP}"/>
81
+ <SegmentedButtonItem icon="sap-icon://decrease-line-height" key="ObjectPageMode" tooltip="{i18n>EASY_FILL_DETAILED_VIEW_TOOLTIP}"/>
78
82
  </items>
79
83
  </SegmentedButton>
80
-
81
84
  <Button
82
85
  icon="{= ${easyFillDialogModel>/isFullScreen} ? 'sap-icon://full-screen' : 'sap-icon://exit-full-screen'}"
83
86
  type="Transparent"
84
87
  press=".onToggleFullScreen"/>
85
88
  </uxap:actions>
86
- </uxap:ObjectPageHeader>
89
+ </uxap:ObjectPageDynamicHeaderTitle>
87
90
  </uxap:headerTitle>
88
91
  <uxap:headerContent>
89
- <HBox gap="0.5rem" justifyContent="End" alignItems="Center" renderType="Bare" class="sapSmartTemplatesObjectPageEasyFillReviewAreaBanner">
92
+ <HBox gap="0.5rem" justifyContent="Start" alignItems="Center" renderType="Bare" class="sapSmartTemplatesObjectPageEasyFillReviewAreaBanner">
90
93
  <Link text="{i18n>AI_LINK_NOTICE_TITLE}" press=".onLinkPress"/>
91
- <Label text="{i18n>AI_WARNING_TEXT}"/>
94
+ <ToggleButton icon = "sap-icon://thumb-up" type = "Transparent" fesr:press="fe2:ef:thumbsup" pressed="{easyFillDialogModel>/feedbackPressedUp}" enabled="{easyFillDialogModel>/feedbackEnabled}" press=".onFeedbackPress"/>
95
+ <ToggleButton icon = "sap-icon://thumb-down" type = "Transparent" fesr:press="fe2:ef:thumbsdown" pressed="{easyFillDialogModel>/feedbackPressedDown}" enabled="{easyFillDialogModel>/feedbackEnabled}" press=".onFeedbackPress"/>
92
96
  </HBox>
93
97
  </uxap:headerContent>
94
- <uxap:ObjectPageSection title="{path: 'easyFillDialogModel>title', formatter: '.formatSectionTitle'}">
98
+ <uxap:ObjectPageSection title="{path: 'easyFillDialogModel>title', formatter: '.formatSectionTitle'}" titleUppercase="false">
95
99
  <uxap:ObjectPageSubSection>
96
100
  <smartForm:SmartForm editable="true" id="EasyFillSmartForm" groups="{path: 'easyFillDialogModel>children', templateShareable: false}">
97
101
  <smartForm:layout>
@@ -764,13 +764,13 @@ RTA_CONTEXT_MENU_CONFIG=Configuration
764
764
  EASY_FILL_TITLE = Easy Fill
765
765
 
766
766
  # XTXT: EasyFill Description 1
767
- EASY_FILL_FIRST_LABEL_TEXT = You can use the Easy Fill feature to fill multiple fields simultaneously.
767
+ EASY_FILL_FIRST_LABEL_TEXT = You can use the Easy Fill feature to fill multiple fields simultaneously using natural language.
768
768
 
769
769
  # XTXT: EasyFill Description 1
770
- EASY_FILL_SECOND_LABEL_TEXT = Use data sources like spreadsheets, notes, and emails to populate the fields, or clearly describe the information you want to fill in. Then click Easy Fill.
770
+ EASY_FILL_SECOND_LABEL_TEXT = Provide any information that helps AI fill the appropriate fields. You can also upload a file containing the relevant information.
771
771
 
772
772
  # XTXT: EasyFill TextArea placeholder
773
- EASY_FILL_TEXTAREA_PLACEHOLDER = Provide the required information using data sources or by typing
773
+ EASY_FILL_TEXTAREA_PLACEHOLDER = Provide any information that helps AI fill the appropriate fields. Note that AI can only assist with visible fields and rows.
774
774
 
775
775
  # XTIT: EasyFill initial Illustration title
776
776
  EASY_FILL_ILLUSTRATION_TITLE_INITIAL = Let\u2019s fill in some fields
@@ -794,10 +794,7 @@ EASY_FILL_ILLUSTRATION_DESCRIPTION_ERROR =It looks like an error occurred. Try a
794
794
  EASY_FILL_CONFIRM = Confirm
795
795
 
796
796
  # XTXT: EasyFill AI Notice link
797
- AI_LINK_NOTICE_TITLE = Created with AI.
798
-
799
- # XTXT: EasyFill AI Notice warning
800
- AI_WARNING_TEXT = Verify results before use.
797
+ AI_LINK_NOTICE_TITLE = Created with AI. Verify results before use.
801
798
 
802
799
  # XTIT: EasyFill fillable fields title
803
800
  EASY_FILL_FILLED_FIELDS = Filled Fields
@@ -815,7 +812,7 @@ EASY_FILL_PROPOSED_VALUES = Proposed Values
815
812
  EASY_FILL_PREVIOUS_VALUES = Previous Values
816
813
 
817
814
  # XTXT: EasyFill AINotice link popover text
818
- EASY_FILL_POPOVER_AI_TEXT_1=The content was partially or fully generated by artificial intelligence(AI) technologies.
815
+ EASY_FILL_POPOVER_AI_TEXT_1=The content was partially or fully generated by AI.
819
816
 
820
817
  # XTXT: EasyFill AINotice link popover text
821
818
  EASY_FILL_POPOVER_AI_TEXT_2=The AI-generated content may contain inaccuracies due to using multiple information sources. Verify results before use.
@@ -849,3 +846,9 @@ EASY_FILL_TABLE_INVALID_CELL_SUFFIX = (invalid)
849
846
 
850
847
  # XTIT: EasyFill Section Title
851
848
  EASY_FILL_SECTION_HEADER = Header
849
+
850
+ # XTOL: EasyFill condensed view mode tooltip
851
+ EASY_FILL_CONDENSED_VIEW_TOOLTIP=Switch to condensed layout
852
+
853
+ # XTOL: EasyFill detailed view mode tooltip
854
+ EASY_FILL_DETAILED_VIEW_TOOLTIP=Switch to object page layout
@@ -543,3 +543,17 @@ EASY_FILL_POPOVER_AI_TITLE=\u062A\u0645 \u0627\u0644\u0625\u0646\u0634\u0627\u06
543
543
  EASYFILL_RESULT_FEEDBACK=\u062A\u0645 \u0625\u0631\u0633\u0627\u0644 \u0627\u0644\u0645\u0644\u0627\u062D\u0638\u0627\u062A
544
544
 
545
545
  EASYFILL_CLEAR_ALL=\u062D\u0630\u0641 \u0627\u0644\u0627\u0633\u062A\u0639\u0644\u0627\u0645
546
+
547
+ EASY_FILL_TABLE_UPDATES_INFO=\u062A\u0645 \u0627\u0643\u062A\u0634\u0627\u0641 \u062A\u062D\u062F\u064A\u062B\u0627\u062A \u0635\u0641\u0648\u0641 \u0627\u0644\u062C\u062F\u0648\u0644 \u0648\u0633\u064A\u062A\u0645 \u062A\u0637\u0628\u064A\u0642\u0647\u0627 \u0639\u0646\u062F \u0627\u0644\u062A\u0623\u0643\u064A\u062F.
548
+
549
+ EASY_FILL_TABLE_VIEW_PREVIOUS=\u0627\u0644\u0633\u0627\u0628\u0642
550
+
551
+ EASY_FILL_TABLE_VIEW_NEW=\u062C\u062F\u064A\u062F
552
+
553
+ EASY_FILL_TABLE_ROW_LABEL=\u0627\u0644\u0635\u0641 {0}
554
+
555
+ EASY_FILL_TABLE_VALIDATION_MESSAGE=\u0628\u0639\u0636 \u0642\u064A\u0645 \u0627\u0644\u062C\u062F\u0648\u0644 \u063A\u064A\u0631 \u0635\u0627\u0644\u062D\u0629 \u0644\u0645\u0633\u0627\u0639\u062F\u0629 \u0627\u0644\u0625\u062F\u062E\u0627\u0644\: {0}. \u0642\u0645 \u0628\u062A\u062D\u062F\u064A\u062B \u0637\u0644\u0628\u0643 \u0648\u062D\u0627\u0648\u0644 \u0645\u0631\u0629 \u0623\u062E\u0631\u0649.
556
+
557
+ EASY_FILL_TABLE_INVALID_CELL_SUFFIX=(\u063A\u064A\u0631 \u0635\u0627\u0644\u062D)
558
+
559
+ EASY_FILL_SECTION_HEADER=\u0627\u0644\u0645\u0642\u062F\u0645\u0629
@@ -543,3 +543,17 @@ EASY_FILL_POPOVER_AI_TITLE=\u0421\u044A\u0437\u0434\u0430\u0434\u0435\u043D\u043
543
543
  EASYFILL_RESULT_FEEDBACK=\u041E\u0431\u0440\u0430\u0442\u043D\u0430\u0442\u0430 \u0432\u0440\u044A\u0437\u043A\u0430 \u0435 \u0438\u0437\u043F\u0440\u0430\u0442\u0435\u043D\u0430
544
544
 
545
545
  EASYFILL_CLEAR_ALL=\u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043D\u0435 \u043D\u0430 \u0437\u0430\u043F\u0438\u0442\u0432\u0430\u043D\u0435\u0442\u043E
546
+
547
+ EASY_FILL_TABLE_UPDATES_INFO=\u041E\u0442\u043A\u0440\u0438\u0442\u0438 \u0441\u0430 \u0430\u043A\u0442\u0443\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u0438 \u043D\u0430 \u0440\u0435\u0434\u043E\u0432\u0435\u0442\u0435 \u043D\u0430 \u0442\u0430\u0431\u043B\u0438\u0446\u0430\u0442\u0430 \u0438 \u0449\u0435 \u0431\u044A\u0434\u0430\u0442 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438, \u043A\u043E\u0433\u0430\u0442\u043E \u043F\u043E\u0442\u0432\u044A\u0440\u0434\u0438\u0442\u0435.
548
+
549
+ EASY_FILL_TABLE_VIEW_PREVIOUS=\u041D\u0430\u0437\u0430\u0434
550
+
551
+ EASY_FILL_TABLE_VIEW_NEW=\u041D\u043E\u0432\u043E
552
+
553
+ EASY_FILL_TABLE_ROW_LABEL=\u0420\u0435\u0434 {0}
554
+
555
+ EASY_FILL_TABLE_VALIDATION_MESSAGE=\u041D\u044F\u043A\u043E\u0438 \u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\u0438 \u043E\u0442 \u0442\u0430\u0431\u043B\u0438\u0446\u0430\u0442\u0430 \u0441\u0430 \u043D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u0438 \u0437\u0430 \u043F\u043E\u043C\u043E\u0449\u0442\u0430 \u043F\u0440\u0438 \u0432\u044A\u0432\u0435\u0436\u0434\u0430\u043D\u0435 \u043D\u0430 \u0441\u0442\u043E\u0439\u043D\u043E\u0441\u0442\: {0}. \u0410\u043A\u0442\u0443\u0430\u043B\u0438\u0437\u0438\u0440\u0430\u0439\u0442\u0435 \u0437\u0430\u044F\u0432\u043A\u0430\u0442\u0430 \u0441\u0438 \u0438 \u043E\u043F\u0438\u0442\u0430\u0439\u0442\u0435 \u043E\u0442\u043D\u043E\u0432\u043E.
556
+
557
+ EASY_FILL_TABLE_INVALID_CELL_SUFFIX=(\u043D\u0435\u0432\u0430\u043B\u0438\u0434\u043D\u043E)
558
+
559
+ EASY_FILL_SECTION_HEADER=\u0417\u0430\u0433\u043B\u0430\u0432\u043A\u0430
@@ -543,3 +543,17 @@ EASY_FILL_POPOVER_AI_TITLE=S'ha creat amb IA
543
543
  EASYFILL_RESULT_FEEDBACK=Comentaris enviats
544
544
 
545
545
  EASYFILL_CLEAR_ALL=Suprimir consulta
546
+
547
+ EASY_FILL_TABLE_UPDATES_INFO=S'han detectat actualitzacions de l\u00EDnia de taula i s'aplicaran quan ho confirmeu.
548
+
549
+ EASY_FILL_TABLE_VIEW_PREVIOUS=Anterior
550
+
551
+ EASY_FILL_TABLE_VIEW_NEW=Nou
552
+
553
+ EASY_FILL_TABLE_ROW_LABEL=Fila {0}
554
+
555
+ EASY_FILL_TABLE_VALIDATION_MESSAGE=Alguns valors de taula no s\u00F3n v\u00E0lids per a l''ajuda per a entrades\: {0}. Actualitzeu la vostra sol\u00B7licitud i torneu-ho a provar.
556
+
557
+ EASY_FILL_TABLE_INVALID_CELL_SUFFIX=(no v\u00E0lid)
558
+
559
+ EASY_FILL_SECTION_HEADER=Cap\u00E7alera