@sapui5/sap.suite.ui.generic.template 1.148.1 → 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 (74) hide show
  1. package/package.json +1 -1
  2. package/src/sap/suite/ui/generic/template/.library +1 -1
  3. package/src/sap/suite/ui/generic/template/AnalyticalListPage/manifest.json +1 -1
  4. package/src/sap/suite/ui/generic/template/Canvas/manifest.json +1 -1
  5. package/src/sap/suite/ui/generic/template/ListReport/controller/ControllerImplementation.js +6 -3
  6. package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
  7. package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +1 -1
  8. package/src/sap/suite/ui/generic/template/QuickCreate/manifest.json +1 -1
  9. package/src/sap/suite/ui/generic/template/QuickView/manifest.json +1 -1
  10. package/src/sap/suite/ui/generic/template/genericUtilities/controlStateWrapperFactory/SmartFilterBarWrapper.js +20 -1
  11. package/src/sap/suite/ui/generic/template/lib/AppComponent.js +1 -1
  12. package/src/sap/suite/ui/generic/template/lib/CRUDManager.js +0 -7
  13. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillAIOrchestrator.js +43 -12
  14. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillApplyHandler.js +67 -218
  15. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillDialogController.js +55 -8
  16. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFieldCollector.js +214 -35
  17. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFormRenderer.js +93 -18
  18. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillHandler.js +426 -48
  19. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillTableRenderer.js +512 -63
  20. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillDialog.fragment.xml +33 -22
  21. package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterBarHandler.js +90 -73
  22. package/src/sap/suite/ui/generic/template/lib/i18n/i18n.properties +24 -0
  23. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ar.properties +15 -7
  24. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_bg.properties +15 -7
  25. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ca.properties +15 -7
  26. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cnr.properties +15 -7
  27. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cs.properties +15 -7
  28. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cy.properties +15 -7
  29. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_da.properties +15 -7
  30. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_de.properties +19 -11
  31. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_el.properties +15 -7
  32. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en.properties +15 -7
  33. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_GB.properties +15 -7
  34. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_US_saprigi.properties +15 -7
  35. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es.properties +15 -7
  36. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es_MX.properties +15 -7
  37. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_et.properties +15 -7
  38. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fi.properties +15 -7
  39. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr.properties +16 -8
  40. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr_CA.properties +16 -8
  41. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hi.properties +15 -7
  42. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hr.properties +16 -8
  43. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hu.properties +15 -7
  44. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_id.properties +15 -7
  45. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_it.properties +15 -7
  46. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_iw.properties +15 -7
  47. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ja.properties +15 -7
  48. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_kk.properties +15 -7
  49. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ko.properties +15 -7
  50. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lt.properties +15 -7
  51. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lv.properties +15 -7
  52. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_mk.properties +15 -7
  53. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ms.properties +15 -7
  54. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_nl.properties +15 -7
  55. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_no.properties +15 -7
  56. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pl.properties +15 -7
  57. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt.properties +15 -7
  58. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt_PT.properties +15 -7
  59. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ro.properties +15 -7
  60. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ru.properties +15 -7
  61. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sh.properties +15 -7
  62. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sk.properties +15 -7
  63. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sl.properties +15 -7
  64. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sr.properties +15 -7
  65. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sv.properties +15 -7
  66. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_th.properties +15 -7
  67. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_tr.properties +15 -7
  68. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_uk.properties +15 -7
  69. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_vi.properties +15 -7
  70. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_CN.properties +15 -7
  71. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_TW.properties +15 -7
  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 +22 -1
@@ -2,8 +2,9 @@ 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
- ], function(JSONModel, MessageToast, FeLogger, FeError) {
5
+ "sap/suite/ui/generic/template/genericUtilities/FeError",
6
+ "sap/ui/core/ResizeHandler"
7
+ ], function(JSONModel, MessageToast, FeLogger, FeError, ResizeHandler) {
7
8
  "use strict";
8
9
 
9
10
  var sClassName = "lib.ai.EasyFill.EasyFillDialogController";
@@ -58,12 +59,15 @@ sap.ui.define([
58
59
  feedbackPressedDown: false,
59
60
  isEasyFillButtonEnabled: false,
60
61
  llmData: {},
62
+ updatableFields: {},
63
+ nonUpdatableFields: {},
64
+ hasNonUpdatableFields: false,
61
65
  easyFillMode: oEasyFillLayoutMode.CondensedMode,
62
66
  sections: [],
63
67
  isFullScreen: true,
64
68
  hasTableUpdates: false,
65
- hasTableValidationErrors: false,
66
- tableValidationMessage: ""
69
+ attemptedMultipleNewRows: false,
70
+ isSplitterPageMode: false
67
71
  };
68
72
 
69
73
  oController.getView().setModel(new JSONModel(oData), "easyFillDialogModel");
@@ -94,6 +98,34 @@ sap.ui.define([
94
98
  true // use view as parent
95
99
  ).then(function(oDialog) {
96
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
+ });
127
+ }
128
+
97
129
  oLogger.debug("openDialog: EasyFillDialog opened");
98
130
  });
99
131
  },
@@ -107,6 +139,8 @@ sap.ui.define([
107
139
  var oDialog = oController.byId("EasyFillDialog");
108
140
  if (oDialog && oDialog.isOpen()) {
109
141
  oDialog.close();
142
+ // Reset page-mode flag so the button is visible on the next open
143
+ oController.getView().getModel("easyFillDialogModel").setProperty("/isSplitterPageMode", false);
110
144
  oLogger.debug("closeDialog: EasyFillDialog closed");
111
145
  }
112
146
  },
@@ -131,10 +165,19 @@ sap.ui.define([
131
165
  oController.getOwnerComponent().getEntitySet()
132
166
  );
133
167
  oDialogModel.setProperty("/easyFillMode", sSelectedKey);
134
- var oLLMResult = oDialogModel.getProperty("/llmData");
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;
177
+ var oNonUpdatableFields = oDialogModel.getProperty("/nonUpdatableFields") || {};
135
178
  var aData = (sSelectedKey === oEasyFillLayoutMode.CondensedMode)
136
- ? oFieldCollector.getSectionsForCondensedView(oLLMResult)
137
- : oFieldCollector.getSectionsForObjectPageView(oEntityType, oLLMResult, oRb);
179
+ ? oFieldCollector.getSectionsForCondensedView(oLLMResult, oUpdatableFields, oNonUpdatableFields)
180
+ : oFieldCollector.getSectionsForObjectPageView(oEntityType, oLLMResult, oRb, oNonUpdatableFields);
138
181
  oDialogModel.setProperty("/sections", aData);
139
182
  },
140
183
 
@@ -253,10 +296,14 @@ sap.ui.define([
253
296
  */
254
297
  formatSectionTitle: function(sTitle, oController) {
255
298
  if (!sTitle) { return ""; }
299
+
300
+ var oResourceBundle = oController.getView().getModel("i18n").getResourceBundle();
301
+
302
+ // Handle i18n pattern in title
256
303
  var oMatch = sTitle.match(/\{@?i18n>([^}]+)\}/);
257
304
  if (oMatch) {
258
305
  var sKey = oMatch[1];
259
- return oController.getView().getModel("i18n").getResourceBundle().getText(sKey);
306
+ return oResourceBundle.getText(sKey);
260
307
  }
261
308
  return sTitle;
262
309
  },
@@ -60,7 +60,7 @@ sap.ui.define([
60
60
  * @param {object} oObjectPage - the ObjectPage control (used to find SmartTables)
61
61
  * @param {object} oObjectPageModel - the OData model of the ObjectPage
62
62
  * @param {object} oTemplateUtils - FE template utilities (used for PresentationControlHandler)
63
- * @param {object} mCollectionState - mutable collection state: { mCollectionRowContexts, mCollectionRowContextsByPath, mCollectionProperties, mCollectionEntityTypes }
63
+ * @param {object} mCollectionState - mutable collection state: { mCollectionRowContexts, mCollectionRowContextsByPath, mCollectionProperties, mCollectionEntityTypes, mCollectionEntitySets }
64
64
  * @param {function} fnGetLabel - function(oProperty) → string label
65
65
  */
66
66
  appendCollectionMap: function(mPropertyMap, oObjectPage, oObjectPageModel, oTemplateUtils, mCollectionState, fnGetLabel) {
@@ -69,6 +69,8 @@ sap.ui.define([
69
69
  mCollectionState.mCollectionRowContextsByPath = Object.create(null);
70
70
  mCollectionState.mCollectionProperties = Object.create(null);
71
71
  mCollectionState.mCollectionEntityTypes = Object.create(null);
72
+ mCollectionState.mCollectionEntitySets = Object.create(null);
73
+ mCollectionState.mCollectionAllowsCreation = Object.create(null);
72
74
 
73
75
  var aSmartTables = this.getObjectPageSmartTables(oObjectPage);
74
76
  if (!aSmartTables.length) {
@@ -154,6 +156,8 @@ sap.ui.define([
154
156
  mCollectionState.mCollectionRowContextsByPath[sNavProperty] = mRowsByPath;
155
157
  mCollectionState.mCollectionProperties[sNavProperty] = mPropertyByName;
156
158
  mCollectionState.mCollectionEntityTypes[sNavProperty] = oEntityType;
159
+ mCollectionState.mCollectionEntitySets[sNavProperty] = oEntitySet;
160
+ mCollectionState.mCollectionAllowsCreation[sNavProperty] = this.resolveTableAllowsCreation(oSmartTable);
157
161
 
158
162
  // Add collection entry to the LLM field mapping
159
163
  mPropertyMap[sNavProperty] = {
@@ -177,9 +181,10 @@ sap.ui.define([
177
181
  * @param {object} oAiCallResult - flat map of { fieldName: aiValue } from the LLM
178
182
  * @param {object} oEntityType - OData entity type metadata
179
183
  * @param {object} oObjectPageContext - current ObjectPage binding context
184
+ * @param {object} oEntitySet - OData entity set metadata (for entity-set-level sap:updatable checks)
180
185
  * @returns {{ updatableFields: object, nonUpdatableFields: object }}
181
186
  */
182
- getUpdatableAndNonUpdatableFields: function(oAiCallResult, oEntityType, oObjectPageContext) {
187
+ getUpdatableAndNonUpdatableFields: function(oAiCallResult, oEntityType, oObjectPageContext, oEntitySet) {
183
188
  var updatableFields = {};
184
189
  var nonUpdatableFields = {};
185
190
 
@@ -195,7 +200,7 @@ sap.ui.define([
195
200
  nonUpdatableFields[sKey] = oAiCallResult[sKey];
196
201
  return;
197
202
  }
198
- if (this.isEditable(oProperty, oObjectPageContext)) {
203
+ if (this.isEditable(oProperty, oObjectPageContext, oEntitySet)) {
199
204
  updatableFields[sKey] = oAiCallResult[sKey];
200
205
  } else {
201
206
  nonUpdatableFields[sKey] = oAiCallResult[sKey];
@@ -250,18 +255,19 @@ sap.ui.define([
250
255
  * Checks whether a property is editable based on OData annotations.
251
256
  * Uses the current ObjectPage context object for dynamic field-control checks.
252
257
  *
253
- * Priority: sap:updatable → FieldControl (EnumMember) → sap:field-control (dynamic value)
258
+ * Priority: entity-set-level sap:updatable → property sap:updatable → FieldControl (EnumMember) → sap:field-control (dynamic value)
254
259
  *
255
260
  * Field control values:
256
261
  * 0 = Hidden, 1 = ReadOnly, 3 = Editable, 7 = Mandatory (editable)
257
262
  *
258
263
  * @param {object} oProperty - OData property metadata
259
264
  * @param {object} oObjectPageContext - current ObjectPage binding context
265
+ * @param {object} oEntitySet - optional OData entity set metadata (for entity-set-level checks)
260
266
  * @returns {boolean}
261
267
  */
262
- isEditable: function(oProperty, oObjectPageContext) {
268
+ isEditable: function(oProperty, oObjectPageContext, oEntitySet) {
263
269
  var oContextObject = oObjectPageContext && oObjectPageContext.getObject && oObjectPageContext.getObject();
264
- return this.isEditableByContextObject(oProperty, oContextObject);
270
+ return this.isEditableByContextObject(oProperty, oContextObject, oEntitySet);
265
271
  },
266
272
 
267
273
  /**
@@ -270,14 +276,31 @@ sap.ui.define([
270
276
  *
271
277
  * @param {object} oProperty - OData property metadata
272
278
  * @param {object} oContextObject - plain JS object of the current row/entity data
279
+ * @param {object} oEntitySet - optional OData entity set metadata (for entity-set-level checks)
273
280
  * @returns {boolean}
274
281
  */
275
- isEditableByContextObject: function(oProperty, oContextObject) {
282
+ isEditableByContextObject: function(oProperty, oContextObject, oEntitySet) {
276
283
  if (!oProperty) {
277
284
  return false;
278
285
  }
279
286
 
280
- // Check sap:updatable static annotation, highest priority
287
+ // Check entity-set-level sap:updatable (entire entity set is read-only)
288
+ if (oEntitySet) {
289
+ var sEntitySetUpdatable = oEntitySet["sap:updatable"];
290
+ if (sEntitySetUpdatable === "false") {
291
+ return false;
292
+ }
293
+ // sap:updatable-path: resolved against the context object (boolean property)
294
+ var sEntitySetUpdatablePath = oEntitySet["sap:updatable-path"];
295
+ if (sEntitySetUpdatablePath && oContextObject) {
296
+ var bUpdatableFromPath = oContextObject[sEntitySetUpdatablePath];
297
+ if (bUpdatableFromPath === false || bUpdatableFromPath === "false") {
298
+ return false;
299
+ }
300
+ }
301
+ }
302
+
303
+ // Check sap:updatable — static annotation on the property
281
304
  var sUpdatable = oProperty["sap:updatable"];
282
305
  if (sUpdatable) {
283
306
  return sUpdatable !== "false";
@@ -304,32 +327,101 @@ sap.ui.define([
304
327
 
305
328
  /**
306
329
  * Builds a flat section tree for the Condensed view mode.
307
- * All LLM result fields are grouped into a single unnamed section.
330
+ * Creates two sections: "Filled Fields" (updatable) and "Unfilled Fields" (non-updatable).
308
331
  *
309
332
  * @param {object} oLLMResult - flat map of { fieldName: value } from the LLM
333
+ * @param {object} oUpdatableFields - flat map of updatable fields only
334
+ * @param {object} oNonUpdatableFields - flat map of non-updatable fields only
310
335
  * @returns {Array} section tree array
311
336
  */
312
- getSectionsForCondensedView: function(oLLMResult) {
313
- return this._transformToTreeExpanded(oLLMResult);
337
+ getSectionsForCondensedView: function(oLLMResult, oUpdatableFields, oNonUpdatableFields) {
338
+ var aUpdatableKeys = Object.keys(oUpdatableFields || {});
339
+ var aNonUpdatableKeys = Object.keys(oNonUpdatableFields || {});
340
+ var aSections = [];
341
+ // Section 1: Filled Fields (updatable)
342
+ if (aUpdatableKeys.length > 0) {
343
+ aSections.push({
344
+ title: "{@i18n>EASY_FILL_FILLED_FIELDS}",
345
+ fields: [],
346
+ children: [{
347
+ title: "",
348
+ fields: aUpdatableKeys,
349
+ id: this._generateId("filledFields", aUpdatableKeys)
350
+ }]
351
+ });
352
+ }
353
+
354
+ // Section 2: Unfilled Fields (non-updatable/read-only)
355
+ if (aNonUpdatableKeys.length > 0) {
356
+ aSections.push({
357
+ title: "{@i18n>EASY_FILL_UNFILLED_FIELDS}",
358
+ fields: [],
359
+ children: [{
360
+ title: "",
361
+ fields: aNonUpdatableKeys,
362
+ id: this._generateId("unfilledFields", aNonUpdatableKeys)
363
+ }]
364
+ });
365
+ }
366
+
367
+ // Fallback: if no split provided, use old behavior
368
+ if (aSections.length === 0) {
369
+ return this._transformToTreeExpanded(oLLMResult);
370
+ }
371
+
372
+ return aSections;
314
373
  },
315
374
 
316
375
  /**
317
376
  * Builds a structured section tree for the ObjectPage view mode.
318
377
  * Mirrors the ObjectPage section/facet structure and filters to only include
319
- * fields returned by the LLM.
378
+ * updatable fields returned by the LLM. Non-updatable (read-only) fields are
379
+ * excluded from the annotation sections and shown exclusively in the
380
+ * "Unfilled Fields" section appended at the end.
320
381
  *
321
382
  * @param {object} oEntityType - OData entity type metadata
322
383
  * @param {object} oLLMResult - flat map of { fieldName: value } from the LLM
323
384
  * @param {object} oRb - i18n resource bundle
385
+ * @param {object} oNonUpdatableFields - flat map of non-updatable fields only (optional)
324
386
  * @returns {Array} filtered section tree array
325
387
  */
326
- getSectionsForObjectPageView: function(oEntityType, oLLMResult, oRb) {
388
+ getSectionsForObjectPageView: function(oEntityType, oLLMResult, oRb, oNonUpdatableFields) {
327
389
  var aSections = [];
328
390
  aSections = aSections
329
391
  .concat(this._getSectionsForHeader(oEntityType, oRb))
330
392
  .concat(this._getSectionsForObjectPageFacets(oEntityType));
331
393
  var aTree = this._transformToTree(aSections);
332
- return this._filterTreeByLLMResult(aTree, oLLMResult);
394
+
395
+ // Annotation sections must only show updatable fields.
396
+ // Derive the updatable-only subset by removing non-updatable keys from oLLMResult
397
+ // so non-updatable fields do not appear in both annotation sections AND Unfilled Fields.
398
+ var aNonUpdatableSet = Object.keys(oNonUpdatableFields || {});
399
+ var oUpdatableResult = Object.keys(oLLMResult).reduce(function(oAcc, sKey) {
400
+ if (aNonUpdatableSet.indexOf(sKey) === -1) {
401
+ oAcc[sKey] = oLLMResult[sKey];
402
+ }
403
+ return oAcc;
404
+ }, {});
405
+ var aFilteredTree = this._filterTreeByLLMResult(aTree, oUpdatableResult);
406
+ aFilteredTree = this._flattenTreeForObjectPageDialog(aFilteredTree);
407
+
408
+ // "Unfilled Fields" contains only non-updatable (read-only) fields.
409
+ // Editable fields that have no annotation section are silently dropped here —
410
+ // they already appear in their respective annotation-matched sections above.
411
+ var aNonUpdatableKeys = Object.keys(oNonUpdatableFields || {});
412
+ if (aNonUpdatableKeys.length > 0) {
413
+ aFilteredTree.push({
414
+ title: "{@i18n>EASY_FILL_UNFILLED_FIELDS}",
415
+ fields: [],
416
+ children: [{
417
+ title: "",
418
+ fields: aNonUpdatableKeys,
419
+ id: this._generateId("unfilledFields", aNonUpdatableKeys)
420
+ }]
421
+ });
422
+ }
423
+
424
+ return aFilteredTree;
333
425
  },
334
426
 
335
427
  // ─── SmartTable Utilities ─────────────────────────────────────────────────
@@ -375,6 +467,49 @@ sap.ui.define([
375
467
  };
376
468
  },
377
469
 
470
+ /**
471
+ * Determines whether a SmartTable supports creation of new rows via inline mode.
472
+ * Supports "inline" createMode (with an enabled Create toolbar button) and
473
+ * "creationRows" / "creationRowsHiddenInEditMode" createMode (InlineCreationRows).
474
+ *
475
+ * @param {object} oSmartTable - sap.ui.comp.smarttable.SmartTable control
476
+ * @returns {boolean} true if new rows can be created for this table
477
+ */
478
+ resolveTableAllowsCreation: function(oSmartTable) {
479
+ var sCreateMode = oSmartTable.data("creationMode");
480
+ var bIsInlineCreationRows = sCreateMode === "creationRows" || sCreateMode === "creationRowsHiddenInEditMode";
481
+ var bIsInline = sCreateMode === "inline";
482
+
483
+ if (bIsInlineCreationRows) {
484
+ return true;
485
+ }
486
+
487
+ if (bIsInline) {
488
+ // Inline create requires the Create toolbar button to be enabled
489
+ var oTable = oSmartTable.getTable && oSmartTable.getTable();
490
+ if (!oTable) {
491
+ return false;
492
+ }
493
+ var oToolbar = oSmartTable.getCustomToolbar && oSmartTable.getCustomToolbar();
494
+ if (!oToolbar) {
495
+ return false;
496
+ }
497
+ var aButtons = oToolbar.getContent && oToolbar.getContent();
498
+ if (!Array.isArray(aButtons)) {
499
+ return false;
500
+ }
501
+ var oCreateButton = aButtons.find(function(oControl) {
502
+ return oControl.isA && oControl.isA("sap.m.Button") &&
503
+ typeof oControl.getId === "function" &&
504
+ oControl.getId().indexOf("add") >= 0 &&
505
+ oControl.getEnabled && oControl.getEnabled();
506
+ });
507
+ return !!oCreateButton;
508
+ }
509
+
510
+ return false;
511
+ },
512
+
378
513
  // ─── Private Helpers ─────────────────────────────────────────────────────
379
514
 
380
515
  /**
@@ -482,23 +617,23 @@ sap.ui.define([
482
617
 
483
618
  /**
484
619
  * Filters a section tree to only include nodes that contain at least one LLM-returned field.
485
- * Fields not matched to any section are grouped into an "unableToFill" catch-all node.
620
+ * Fields with no matching annotation section are silently dropped; the caller is responsible
621
+ * for surfacing them elsewhere (e.g. the "unfilledFields" section for non-updatable fields).
622
+ *
623
+ * @param {Array} aTree - section tree
624
+ * @param {object} oLLMResult - flat map of all LLM fields
625
+ * @returns {Array} filtered tree
486
626
  * @private
487
627
  */
488
628
  _filterTreeByLLMResult: function(aTree, oLLMResult) {
489
629
  var aRequestedKeys = Object.keys(oLLMResult);
490
- var aMatchedKeys = new Set();
491
630
  var that = this;
492
631
 
493
632
  function filterNode(oNode, sParentPath) {
494
633
  var sTitlePath = sParentPath ? (sParentPath + "_" + oNode.title) : oNode.title;
495
634
 
496
635
  var aFilteredFields = oNode.fields.filter(function(sField) {
497
- if (aRequestedKeys.includes(sField)) {
498
- aMatchedKeys.add(sField);
499
- return true;
500
- }
501
- return false;
636
+ return aRequestedKeys.includes(sField);
502
637
  });
503
638
 
504
639
  var aFilteredChildren = oNode.children
@@ -513,22 +648,58 @@ sap.ui.define([
513
648
  };
514
649
  }
515
650
 
516
- var aFilteredTree = aTree
651
+ return aTree
517
652
  .map(function(oNode) { return filterNode(oNode, ""); })
518
653
  .filter(function(oNode) { return oNode.fields.length > 0 || oNode.children.length > 0; });
654
+ },
519
655
 
520
- // Any LLM fields that didn't map to a known section go into a special "unableToFill" node
521
- var aUnmatchedKeys = aRequestedKeys.filter(function(sKey) { return !aMatchedKeys.has(sKey); });
522
- if (aUnmatchedKeys.length > 0) {
523
- aFilteredTree.push({
524
- title: "unableToFill",
525
- id: this._generateId("unableToFill", aUnmatchedKeys),
526
- fields: aUnmatchedKeys,
527
- children: []
528
- });
656
+ /**
657
+ * Flattens nested ObjectPage section trees to one group level expected by the dialog fragment.
658
+ *
659
+ * EasyFill dialog binds SmartForm groups only to section.children (one level deep).
660
+ * If annotation facets produce deeper nesting, section titles can render while fields remain
661
+ * invisible because grandchildren are never bound as groups.
662
+ *
663
+ * @param {Array} aTree - filtered section tree
664
+ * @returns {Array} dialog-compatible tree with one-level children per section
665
+ * @private
666
+ */
667
+ _flattenTreeForObjectPageDialog: function(aTree) {
668
+ var that = this;
669
+
670
+ function collectRenderableGroups(oNode, sParentPath) {
671
+ var sTitlePath = sParentPath ? (sParentPath + "_" + oNode.title) : oNode.title;
672
+ var aGroups = [];
673
+
674
+ if (Array.isArray(oNode.fields) && oNode.fields.length > 0) {
675
+ aGroups.push({
676
+ title: oNode.title,
677
+ id: that._generateId(sTitlePath, oNode.fields),
678
+ fields: oNode.fields,
679
+ children: []
680
+ });
681
+ }
682
+
683
+ if (Array.isArray(oNode.children) && oNode.children.length > 0) {
684
+ oNode.children.forEach(function(oChild) {
685
+ aGroups = aGroups.concat(collectRenderableGroups(oChild, sTitlePath));
686
+ });
687
+ }
688
+
689
+ return aGroups;
529
690
  }
530
691
 
531
- return aFilteredTree;
692
+ return (aTree || []).map(function(oSection) {
693
+ var sSectionPath = oSection.title || "";
694
+ return {
695
+ title: oSection.title,
696
+ id: oSection.id,
697
+ fields: [],
698
+ children: collectRenderableGroups(oSection, sSectionPath)
699
+ };
700
+ }).filter(function(oSection) {
701
+ return Array.isArray(oSection.children) && oSection.children.length > 0;
702
+ });
532
703
  },
533
704
 
534
705
  /**
@@ -638,12 +809,14 @@ sap.ui.define([
638
809
  // FieldGroup / Form — iterate Data array
639
810
  oAnnotation.Data.forEach(function(oData) {
640
811
  if (!this._isSupportedRecordType(oData.RecordType)) { return; }
812
+ if (!oData.Value || !oData.Value.Path) { return; }
641
813
  aRes.push({ title: aTempText, property: oData.Value.Path });
642
814
  }.bind(this));
643
815
  } else if (Array.isArray(oAnnotation)) {
644
816
  // LineItem — iterate annotation array directly
645
817
  oAnnotation.forEach(function(oAnno) {
646
818
  if (!this._isSupportedRecordType(oAnno.RecordType)) { return; }
819
+ if (!oAnno.Value || !oAnno.Value.Path) { return; }
647
820
  aRes.push({ title: aTempText, property: oAnno.Value.Path });
648
821
  }.bind(this));
649
822
  } else if (oAnnotation.Value && oAnnotation.Value.Path) {
@@ -658,12 +831,18 @@ sap.ui.define([
658
831
  /**
659
832
  * Returns false for record types that EasyFill does not support rendering.
660
833
  * Currently excludes: IntentBasedNavigation, ForAnnotation, ForAction.
834
+ * Handles both fully-qualified names (com.sap.vocabularies.UI.v1.*) and
835
+ * alias form (UI.*) that OData metadata can return depending on the service.
661
836
  * @private
662
837
  */
663
838
  _isSupportedRecordType: function(sRecordType) {
664
- return sRecordType !== "com.sap.vocabularies.UI.v1.DataFieldForIntentBasedNavigation" &&
665
- sRecordType !== "com.sap.vocabularies.UI.v1.DataFieldForAnnotation" &&
666
- sRecordType !== "com.sap.vocabularies.UI.v1.DataFieldForAction";
839
+ if (!sRecordType) { return false; }
840
+ var sNormalized = sRecordType.replace("com.sap.vocabularies.UI.v1.", "UI.");
841
+ return sNormalized !== "UI.DataFieldForIntentBasedNavigation" &&
842
+ sNormalized !== "UI.DataFieldForAnnotation" &&
843
+ sNormalized !== "UI.DataFieldForAction" &&
844
+ sNormalized !== "UI.DataFieldWithNavigationPath" &&
845
+ sNormalized !== "UI.DataFieldWithIntentBasedNavigation";
667
846
  }
668
847
  };
669
848
  });