@sapui5/sap.suite.ui.generic.template 1.151.1 → 1.152.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 (35) 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/manifest.json +1 -1
  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 +5 -4
  14. package/src/sap/suite/ui/generic/template/js/AnnotationHelper.js +21 -17
  15. package/src/sap/suite/ui/generic/template/lib/AppComponent.js +1 -1
  16. package/src/sap/suite/ui/generic/template/lib/Application.js +0 -13
  17. package/src/sap/suite/ui/generic/template/lib/CommonEventHandlers.js +4 -19
  18. package/src/sap/suite/ui/generic/template/lib/CommonUtils.js +4 -4
  19. package/src/sap/suite/ui/generic/template/lib/ShareUtils.js +1 -1
  20. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillAIOrchestrator.js +1 -6
  21. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillApplyHandler.js +25 -44
  22. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillDialogController.js +80 -64
  23. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFieldCollector.js +442 -259
  24. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFormRenderer.js +125 -161
  25. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillHandler.js +134 -160
  26. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillTableRenderer.js +55 -189
  27. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillDialog.fragment.xml +67 -85
  28. package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterBarHandler.js +27 -3
  29. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_US_saptrc.properties +6 -6
  30. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fi.properties +4 -4
  31. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sl.properties +1 -1
  32. package/src/sap/suite/ui/generic/template/lib/insights/InsightsCardHelper.js +16 -4
  33. package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +3 -2
  34. package/src/sap/suite/ui/generic/template/library.js +1 -1
  35. package/src/sap/suite/ui/generic/template/themes/base/ObjectPage.less +1 -1
@@ -52,9 +52,14 @@ sap.ui.define([
52
52
  var oTransientContextForEasyFill = null; // Transient OData context for staged AI scalar values
53
53
  var oObjectPageContext = null; // Live ObjectPage binding context
54
54
  var oObjectPageModel = null; // OData model of the ObjectPage
55
- var mUpdatableLookupMap = {}; // { fieldName: value } for updatable fields only
55
+ var mUpdatableLookupMap = {}; // { fieldName: aiValue } updatable only
56
56
  var oRb = null; // i18n resource bundle
57
57
  var oAIPopoverRef = { popover: null }; // Mutable ref for lazy-loaded AINotice popover
58
+ // Built fresh on every AI submit by walking the rendered ObjectPage controls.
59
+ // Re-built each time so it reflects the latest edit-mode SmartField state,
60
+ // including extension fragment fields and custom fields.
61
+ var oOPStructureMap = null;
62
+ var mLiveEditable = null;
58
63
 
59
64
  // Collection state — tracks OData row contexts and property metadata for SmartTable collections
60
65
  var mCollectionState = {
@@ -67,6 +72,7 @@ sap.ui.define([
67
72
  };
68
73
 
69
74
  var mCollectionUpdates = Object.create(null); // { navProperty: [ rowUpdate ] } from AI response
75
+ var mRejectedNewRows = {}; // { navProperty: "all"|"mixed" } — hoisted so mode-switch can access it
70
76
  var mLastFieldMapping = null; // retained so table sections can be re-rendered on mode switch
71
77
  var oTableStagingState = {
72
78
  mStagedRows: Object.create(null),
@@ -87,15 +93,11 @@ sap.ui.define([
87
93
  oRb = oController.getView().getModel("i18n").getResourceBundle();
88
94
  oObjectPageModel = oObjectPage.getModel();
89
95
 
90
- // Initialize dialog model and deferred group once per view lifetime
91
96
  EasyFillDialogController.initDialogModel(oController, oObjectPageModel, EasyFillLayoutMode);
92
97
 
93
- // Use the provided context override or fall back to the current OP binding context
94
98
  oObjectPageContext = oContext || oObjectPage.getBindingContext();
95
99
 
96
- // Build the handler/formatter map that the dialog fragment binds to
97
100
  var oHandlers = _buildDialogHandlers();
98
-
99
101
  await EasyFillDialogController.openDialog(oController, oTemplateUtils, oHandlers);
100
102
  }
101
103
 
@@ -114,37 +116,23 @@ sap.ui.define([
114
116
  // immediately on whatever SmartForms are currently in the DOM, and then
115
117
  // again via fnOnFieldChange once the new SmartFields are rendered.
116
118
  onSelectionChange: function(oEvent) {
117
- // Step 1: clean up table content injected for the CURRENT mode BEFORE the
118
- // model update. This ensures the OPL aggregation is free of manually-added
119
- // sections when the sections binding recreates controls for the new mode,
120
- // so getSections() in renderCollectionPreviews returns only bound sections.
121
119
  var oOpl = oController.byId("EasyFillObjectPageLayout");
122
120
  if (oOpl && mLastFieldMapping && Object.keys(mCollectionUpdates).length > 0) {
123
121
  EasyFillTableRenderer.removeTableSections(oOpl);
124
122
  }
125
123
 
126
- // Step 2: update model — this triggers the OPL sections binding to recreate
127
- // bound section controls for the new mode.
128
124
  EasyFillDialogController.onSelectionChange(
129
- oEvent, oController, oTemplateUtils, oRb,
130
- EasyFillFieldCollector, EasyFillLayoutMode
125
+ oEvent, oController,
126
+ EasyFillFieldCollector, EasyFillLayoutMode, oOPStructureMap
131
127
  );
128
+ _populateAllVisibleGroups();
132
129
 
133
- // Step 3: re-render table previews for the new mode.
134
- // _removeTableSections is skipped inside renderCollectionPreviews because
135
- // bReuseStaging=true, since cleanup was already done in step 1 above.
136
130
  if (mLastFieldMapping && Object.keys(mCollectionUpdates).length > 0) {
137
131
  EasyFillTableRenderer.renderCollectionPreviews(
138
- mCollectionUpdates,
139
- mLastFieldMapping,
140
- [],
141
- oController,
142
- oRb,
143
- mCollectionState,
144
- oTableStagingState,
145
- oObjectPageModel,
146
- _validateFieldsAndUpdateConfirmState,
147
- true // bReuseStaging — also skips re-cleanup (already done above)
132
+ mCollectionUpdates, mLastFieldMapping, [],
133
+ oController, oRb, mCollectionState, oTableStagingState,
134
+ oObjectPageModel, _validateFieldsAndUpdateConfirmState,
135
+ true, mRejectedNewRows
148
136
  );
149
137
  }
150
138
  _validateFieldsAndUpdateConfirmState();
@@ -213,11 +201,6 @@ sap.ui.define([
213
201
  EasyFillDialogController.closeDialog(oController);
214
202
  },
215
203
 
216
- // ── Field value formatter (binding expression builder) ────────────
217
- formatFieldValue: function(sFieldName) {
218
- return "{" + sFieldName + "}";
219
- },
220
-
221
204
  // ── Submit user text to AI ────────────────────────────────────────
222
205
  onEasyFillSubmitInputToAI: async function() {
223
206
  await _handleAISubmit();
@@ -228,41 +211,6 @@ sap.ui.define([
228
211
  _resetEasyFill(true);
229
212
  },
230
213
 
231
- // ── SmartForm group population formatter ──────────────────────────
232
- populateSmartFields: function(sId, aFields, sEasyFillMode) {
233
- return EasyFillFormRenderer.populateSmartFields(
234
- sId, aFields, sEasyFillMode,
235
- oController,
236
- oTransientContextForEasyFill,
237
- oObjectPageContext,
238
- mUpdatableLookupMap,
239
- oDialogModel().getProperty("/llmData"),
240
- _validateFieldsAndUpdateConfirmState
241
- );
242
- },
243
-
244
- // ── Section visibility: hide SmartForm sections with no fields ──────────────
245
- hasSectionFields: function(aFields, aChildren) {
246
- if (Array.isArray(aFields) && aFields.length > 0) {
247
- return true;
248
- }
249
-
250
- function hasFieldsInNode(oNode) {
251
- if (!oNode) {
252
- return false;
253
- }
254
- if (Array.isArray(oNode.fields) && oNode.fields.length > 0) {
255
- return true;
256
- }
257
- if (Array.isArray(oNode.children)) {
258
- return oNode.children.some(hasFieldsInNode);
259
- }
260
- return false;
261
- }
262
-
263
- return Array.isArray(aChildren) && aChildren.some(hasFieldsInNode);
264
- },
265
-
266
214
  // ── Fullscreen toggle ─────────────────────────────────────────────
267
215
  onToggleFullScreen: function() {
268
216
  EasyFillDialogController.onToggleFullScreen(oController);
@@ -286,8 +234,29 @@ sap.ui.define([
286
234
  async function _handleAISubmit() {
287
235
  var oModel = oDialogModel();
288
236
  oModel.setProperty("/isBusy", true);
289
-
290
- // Build complete LLM field mapping (entity fields + collection fields)
237
+ try {
238
+
239
+ var sEntitySetName = oController.getOwnerComponent().getEntitySet();
240
+ var oEntityType = oTemplateUtils.oCommonUtils.getMetaModelEntityType(sEntitySetName);
241
+
242
+ // Walk the rendered ObjectPage to build structure map + editability in one pass.
243
+ // Uses findAggregatedObjects on the real FLP ObjectPage — confirmed approach:
244
+ // OP SmartFields created via AHModel.simplePath DO expose getBindingInfo("value").path.
245
+ // Walking up the parent chain gives section/group context without reading annotations.
246
+ // Fallback: if walk produces no fields (edge case), retains previous map.
247
+ // Single walk of the rendered ObjectPage — same proven approach as buildLiveEditabilityMap.
248
+ // Called here (in edit mode, after entity context resolves) so getBindingInfo("value").path
249
+ // is available. Produces section/group/field structure AND live editability in one pass.
250
+ // Annotation fallback kicks in automatically if rendered walk finds nothing.
251
+ var oFreshMap = EasyFillFieldCollector.buildObjectPageStructureMap(oObjectPage, oEntityType, oRb);
252
+ oOPStructureMap = oFreshMap;
253
+ mLiveEditable = oFreshMap.liveEditable;
254
+
255
+ // Build complete LLM field mapping (entity fields + collection fields).
256
+ // All visible fields are sent to the LLM — including read-only ones —
257
+ // so the LLM can return suggestions for every field.
258
+ // mLiveEditable is used AFTER the LLM responds (in getUpdatableAndNonUpdatableFields)
259
+ // to classify returned fields as editable (Filled Fields) or read-only (Unfilled Fields).
291
260
  var mFieldMapping = EasyFillAIOrchestrator.buildFieldMapping(
292
261
  oTemplateUtils, oController, oObjectPage, oObjectPageModel,
293
262
  oObjectPageContext, EasyFillFieldCollector, mCollectionState
@@ -300,9 +269,6 @@ sap.ui.define([
300
269
  oTemplateUtils
301
270
  );
302
271
 
303
- // Reset editable fields tracker for fresh population
304
- oModel.setProperty("/isBusy", false);
305
-
306
272
  // Convert date strings in AI response to JS Date objects
307
273
  EasyFillAIOrchestrator.formatDateValues(aiCallResult, mFieldMapping);
308
274
 
@@ -319,68 +285,49 @@ sap.ui.define([
319
285
  var collectionFields = oSplitResult.collectionFields;
320
286
 
321
287
  // Separate updatable from non-updatable fields
322
- var sEntitySetName = oController.getOwnerComponent().getEntitySet();
323
- var oEntityType = oTemplateUtils.oCommonUtils.getMetaModelEntityType(sEntitySetName);
324
288
  var oMetaModel = oObjectPageModel.getMetaModel();
325
289
  var oEntitySet = oMetaModel.getODataEntitySet(sEntitySetName);
326
290
  var oSplit = EasyFillFieldCollector.getUpdatableAndNonUpdatableFields(
327
- simpleFields, oEntityType, oObjectPageContext, oEntitySet
291
+ simpleFields, oEntityType, oObjectPageContext, oEntitySet, mLiveEditable
328
292
  );
329
293
  mUpdatableLookupMap = oSplit.updatableFields;
330
294
  var mNonUpdatableFields = oSplit.nonUpdatableFields;
331
295
 
332
- // Build section tree for selected view mode
333
- var aData = (sSelectedKey === EasyFillLayoutMode.CondensedMode)
334
- ? EasyFillFieldCollector.getSectionsForCondensedView(simpleFields, mUpdatableLookupMap, mNonUpdatableFields)
335
- : EasyFillFieldCollector.getSectionsForObjectPageView(oEntityType, simpleFields, oRb, mNonUpdatableFields);
336
-
337
- // Reset form (destroy previous SmartForm content + revert table staging)
338
- // then create a fresh transient context for the new AI result.
339
- // Restore the user's chosen layout mode afterwards because _resetEasyFill
340
- // unconditionally resets it to CondensedMode — without this, renderCollectionPreviews
341
- // would see the wrong mode and embed table sections inside the SmartForm SubSection
342
- // instead of adding them as standalone OPL sections (OP mode) or vice-versa.
296
+ // Compute sections array for the selected view mode.
297
+ // Condensed: two flat groups from scratch.
298
+ // OP mode: O(fields) pass over the pre-built structure map — no annotation re-walk.
299
+ var aSections = (sSelectedKey === EasyFillLayoutMode.CondensedMode || !oOPStructureMap)
300
+ ? EasyFillFieldCollector.getSectionInfoForCondensedMode(mUpdatableLookupMap, mNonUpdatableFields)
301
+ : EasyFillFieldCollector.applyLLMResultToStructureMap(
302
+ oOPStructureMap.fieldMap, oOPStructureMap.sections,
303
+ mUpdatableLookupMap, mNonUpdatableFields
304
+ );
305
+
343
306
  _resetEasyFill();
344
307
  oModel.setProperty("/easyFillMode", sSelectedKey);
345
308
  oTransientContextForEasyFill = EasyFillFormRenderer.makeTransientContext(
346
309
  null, oObjectPageModel, oController
347
310
  );
348
311
 
349
- // Update dialog model with section data and AI result.
350
- // llmData must be set BEFORE sections so that when the sections binding fires
351
- // and triggers the populateSmartFields formatter synchronously, the AI-suggested
352
- // values are already available and can be written to the transient context.
353
- oModel.setProperty("/llmData", simpleFields);
354
- oModel.setProperty("/updatableFields", mUpdatableLookupMap);
355
- oModel.setProperty("/nonUpdatableFields", mNonUpdatableFields);
356
- oModel.setProperty("/sections", aData);
312
+ oModel.setProperty("/llmData", simpleFields);
313
+ oModel.setProperty("/updatableFields", mUpdatableLookupMap);
314
+ oModel.setProperty("/nonUpdatableFields", mNonUpdatableFields);
315
+ oModel.setProperty("/sections", aSections);
357
316
  oModel.setProperty("/hasNonUpdatableFields", Object.keys(mNonUpdatableFields).length > 0);
358
-
359
- // Show warning if AI attempted to add multiple new rows but only one was accepted
360
317
  oModel.setProperty("/attemptedMultipleNewRows", oSplitResult.attemptedMultipleNewRows === true);
318
+ _populateAllVisibleGroups();
361
319
 
362
- // Process collection/table updates
363
320
  mCollectionUpdates = collectionFields;
364
321
  mLastFieldMapping = mFieldMapping;
365
- var mRejectedNewRows = oSplitResult.collectionsWithRejectedNewRows || {};
366
- // hasTableUpdates is true when there are accepted updates OR rejected-only tables to show
322
+ mRejectedNewRows = oSplitResult.collectionsWithRejectedNewRows || {};
367
323
  var bHasTableUpdates = Object.keys(mCollectionUpdates).length > 0 ||
368
324
  Object.keys(mRejectedNewRows).length > 0;
369
325
  oModel.setProperty("/hasTableUpdates", bHasTableUpdates);
370
326
 
371
- // Render collection previews into the table preview container
372
327
  EasyFillTableRenderer.renderCollectionPreviews(
373
- mCollectionUpdates,
374
- mFieldMapping,
375
- [],
376
- oController,
377
- oRb,
378
- mCollectionState,
379
- oTableStagingState,
380
- oObjectPageModel,
381
- _validateFieldsAndUpdateConfirmState,
382
- false,
383
- mRejectedNewRows
328
+ mCollectionUpdates, mFieldMapping, [],
329
+ oController, oRb, mCollectionState, oTableStagingState,
330
+ oObjectPageModel, _validateFieldsAndUpdateConfirmState, false, mRejectedNewRows
384
331
  );
385
332
 
386
333
  _validateFieldsAndUpdateConfirmState();
@@ -397,6 +344,9 @@ sap.ui.define([
397
344
  // AI call failed — show error illustration
398
345
  oModel.setProperty("/stateType", "Error");
399
346
  }
347
+ } finally {
348
+ oModel.setProperty("/isBusy", false);
349
+ }
400
350
  }
401
351
 
402
352
  /**
@@ -417,41 +367,61 @@ sap.ui.define([
417
367
  return true;
418
368
  }
419
369
 
420
- // Collect one Promise<errorArray> per SmartForm found in the layout
421
- var aCheckPromises = [];
422
- oObjectPageLayout.getSections().forEach(function(oSection) {
423
- oSection.getSubSections().forEach(function(oSubSection) {
424
- oSubSection.getBlocks().forEach(function(oBlock) {
425
- var aSmartFormCandidates = [];
426
- if (oBlock.isA("sap.ui.comp.smartform.SmartForm")) {
427
- aSmartFormCandidates.push(oBlock);
428
- } else if (typeof oBlock.getItems === "function") {
429
- // In condensed mode the SmartForm is nested inside a wrapper VBox;
430
- // look one level deeper to find it (mirrors EasyFillFormRenderer).
431
- oBlock.getItems().forEach(function(oItem) {
432
- if (oItem.isA("sap.ui.comp.smartform.SmartForm")) {
433
- aSmartFormCandidates.push(oItem);
434
- }
435
- });
436
- }
437
- aSmartFormCandidates.forEach(function(oSmartForm) {
438
- // .catch(() => []) absorbs internal SmartField metadata-promise rejections
439
- // that fire when SmartFields are destroyed during a mode switch.
440
- aCheckPromises.push(
441
- Promise.resolve(oSmartForm.check()).catch(function() { return []; })
442
- );
443
- });
444
- });
445
- });
370
+ var aCheckPromises = EasyFillFormRenderer.collectSmartForms(oObjectPageLayout).map(async function(oSmartForm) {
371
+ try { return await oSmartForm.check(); } catch (e) { return []; }
446
372
  });
447
373
 
448
- // Resolve all checks in parallel; valid only when every SmartForm has no errors
449
374
  var aResults = await Promise.all(aCheckPromises);
450
375
  return aResults.every(function(aErrors) {
451
- return Array.isArray(aErrors) && aErrors.length === 0;
376
+ // SmartForm.check() with validationMode="Async" resolves with an array of
377
+ // error objects when invalid, or [] / null / true when valid.
378
+ // Array.isArray guard handles the non-array zero-error sentinel.
379
+ return Array.isArray(aErrors) ? aErrors.length === 0 : !aErrors || aErrors === true;
452
380
  });
453
381
  }
454
382
 
383
+ /**
384
+ * Walks the current easyFillDialogModel>/sections array and calls
385
+ * EasyFillFormRenderer.populateGroupFields for every visible group that has
386
+ * activeFields. Deferred by setTimeout(0) so the sections= and groups= bindings
387
+ * have finished creating their controls before we try to find them.
388
+ */
389
+ function _populateAllVisibleGroups() {
390
+ setTimeout(function() {
391
+ var aSections = oDialogModel().getProperty("/sections") || [];
392
+ var oLLMData = oDialogModel().getProperty("/llmData") || {};
393
+ aSections.forEach(function(oSection) {
394
+ if (!oSection.visible) { return; }
395
+ (oSection.children || []).forEach(function(oGroup) {
396
+ var aFields = Array.isArray(oGroup.aActiveFields) && oGroup.aActiveFields.length
397
+ ? oGroup.aActiveFields : (oGroup.fields || []);
398
+ if (!oGroup.visible || !aFields.length) { return; }
399
+ EasyFillFormRenderer.populateGroupFields(
400
+ oGroup.id, aFields,
401
+ oController,
402
+ oTransientContextForEasyFill,
403
+ oObjectPageContext,
404
+ mUpdatableLookupMap,
405
+ oLLMData,
406
+ _validateFieldsAndUpdateConfirmState
407
+ );
408
+ });
409
+ });
410
+ }, 0);
411
+ }
412
+
413
+ /**
414
+ * Destroys all GroupElements in every visible SmartForm group — called by _resetEasyFill.
415
+ */
416
+ function _destroyAllGroupElements() {
417
+ EasyFillFormRenderer.collectSmartForms(oController.byId("EasyFillObjectPageLayout"))
418
+ .forEach(function(oForm) {
419
+ oForm.getGroups().forEach(function(oGroup) {
420
+ oGroup.destroyGroupElements();
421
+ });
422
+ });
423
+ }
424
+
455
425
  /**
456
426
  * Re-computes isSaveEnabled from the combined SmartForm and table SmartField validity
457
427
  * flag. Called as the single source of truth for the Confirm button state.
@@ -551,6 +521,10 @@ sap.ui.define([
551
521
  */
552
522
  function _resetEasyFill(bRemoveTextAreaValue) {
553
523
  mLastFieldMapping = null;
524
+ mRejectedNewRows = {};
525
+ // mUpdatableLookupMap is NOT reset here — it is overwritten by the next AI submit
526
+ // and explicitly cleared by EasyFillApplyHandler.resetEasyFill on Clear All / Cancel
527
+ _destroyAllGroupElements();
554
528
  EasyFillApplyHandler.resetEasyFill(
555
529
  !!bRemoveTextAreaValue,
556
530
  oDialogModel(),
@@ -584,20 +558,14 @@ sap.ui.define([
584
558
 
585
559
  // Collect all editable SmartFields from the EasyFill dialog SmartForms
586
560
  var aEditableFields = [];
587
- oObjectPageLayout.getSections().forEach(function(oSection) {
588
- oSection.getSubSections().forEach(function(oSubSection) {
589
- oSubSection.getBlocks().forEach(function(oBlock) {
590
- if (oBlock.isA("sap.ui.comp.smartform.SmartForm")) {
591
- oBlock.getGroups().forEach(function(oGroup) {
592
- oGroup.getGroupElements().forEach(function(oGroupElement) {
593
- oGroupElement.getElements().forEach(function(oElement) {
594
- if (oElement.isA && oElement.isA("sap.ui.comp.smartfield.SmartField") && oElement.getEditable()) {
595
- aEditableFields.push(oElement);
596
- }
597
- });
598
- });
599
- });
600
- }
561
+ EasyFillFormRenderer.collectSmartForms(oObjectPageLayout).forEach(function(oSmartForm) {
562
+ oSmartForm.getGroups().forEach(function(oGroup) {
563
+ oGroup.getGroupElements().forEach(function(oGroupElement) {
564
+ oGroupElement.getElements().forEach(function(oElement) {
565
+ if (oElement.isA && oElement.isA("sap.ui.comp.smartfield.SmartField") && oElement.getEditable()) {
566
+ aEditableFields.push(oElement);
567
+ }
568
+ });
601
569
  });
602
570
  });
603
571
  });
@@ -712,8 +680,10 @@ sap.ui.define([
712
680
  * CRUDManager.addEntry directly ensures the SmartTable binding is refreshed and side
713
681
  * effects are executed after the row is created — without that refresh the ObjectPage
714
682
  * table would not show the newly created row.
683
+ * Multiple new rows per table are created sequentially to avoid race conditions on
684
+ * the draft document.
715
685
  *
716
- * @param {object} mNewRowValues - map of { navProperty: plainValuesObject }
686
+ * @param {object} mNewRowValues - map of { navProperty: plainValuesObject[] }
717
687
  * @returns {Promise<void>}
718
688
  */
719
689
  async function _createNewRows(mNewRowValues) {
@@ -729,13 +699,17 @@ sap.ui.define([
729
699
  if (!oSmartTable) {
730
700
  continue;
731
701
  }
732
- try {
733
- // bSuppressNavigation=true: stay on the OP (don't navigate to the new sub-item).
734
- // bIgnoreTableRefresh not passed (undefined/falsy): the SmartTable binding is
735
- // refreshed and side effects are executed so the new row becomes visible.
736
- await oTemplateUtils.oCommonEventHandlers.addEntry(oSmartTable, true, undefined, mNewRowValues[sNavProp]);
737
- } catch (e) {
738
- // addEntry handles its own error messaging via CommonEventHandlers/CRUDManager
702
+ var aRowValues = mNewRowValues[sNavProp];
703
+ // aRowValues is now an array — iterate and create each row sequentially
704
+ if (!Array.isArray(aRowValues)) {
705
+ aRowValues = [aRowValues];
706
+ }
707
+ for (var j = 0; j < aRowValues.length; j++) {
708
+ try {
709
+ await oTemplateUtils.oCommonEventHandlers.addEntry(oSmartTable, true, undefined, aRowValues[j]);
710
+ } catch (e) {
711
+ // addEntry handles its own error messaging via CommonEventHandlers/CRUDManager
712
+ }
739
713
  }
740
714
  }
741
715
  }