@sapui5/sap.suite.ui.generic.template 1.147.2 → 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 (98) 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/controller/ControllerImplementation.js +5 -3
  4. package/src/sap/suite/ui/generic/template/AnalyticalListPage/i18n/i18n_bg.properties +3 -3
  5. package/src/sap/suite/ui/generic/template/AnalyticalListPage/i18n/i18n_da.properties +3 -3
  6. package/src/sap/suite/ui/generic/template/AnalyticalListPage/i18n/i18n_fr_CA.properties +2 -2
  7. package/src/sap/suite/ui/generic/template/AnalyticalListPage/i18n/i18n_id.properties +2 -2
  8. package/src/sap/suite/ui/generic/template/AnalyticalListPage/manifest.json +1 -1
  9. package/src/sap/suite/ui/generic/template/Canvas/manifest.json +1 -1
  10. package/src/sap/suite/ui/generic/template/ListReport/controller/ControllerImplementation.js +32 -3
  11. package/src/sap/suite/ui/generic/template/ListReport/i18n/i18n_fr.properties +1 -1
  12. package/src/sap/suite/ui/generic/template/ListReport/i18n/i18n_id.properties +1 -1
  13. package/src/sap/suite/ui/generic/template/ListReport/i18n/i18n_uk.properties +1 -1
  14. package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
  15. package/src/sap/suite/ui/generic/template/ObjectPage/Component.js +4 -0
  16. package/src/sap/suite/ui/generic/template/ObjectPage/controller/ControllerImplementation.js +57 -25
  17. package/src/sap/suite/ui/generic/template/ObjectPage/i18n/i18n.properties +6 -0
  18. package/src/sap/suite/ui/generic/template/ObjectPage/i18n/i18n_en_US_saprigi.properties +4 -0
  19. package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +6 -1
  20. package/src/sap/suite/ui/generic/template/ObjectPage/templateSpecificPreparationHelper.js +35 -19
  21. package/src/sap/suite/ui/generic/template/ObjectPage/view/fragments/Actions.fragment.xml +13 -13
  22. package/src/sap/suite/ui/generic/template/ObjectPage/view/fragments/Footer.fragment.xml +103 -42
  23. package/src/sap/suite/ui/generic/template/QuickCreate/manifest.json +1 -1
  24. package/src/sap/suite/ui/generic/template/QuickView/manifest.json +1 -1
  25. package/src/sap/suite/ui/generic/template/fragments/EasyFilter.fragment.xml +3 -0
  26. package/src/sap/suite/ui/generic/template/genericUtilities/controlHelper.js +30 -29
  27. package/src/sap/suite/ui/generic/template/genericUtilities/controlStateWrapperFactory/SmartFilterBarWrapper.js +15 -0
  28. package/src/sap/suite/ui/generic/template/lib/AppComponent.js +1 -1
  29. package/src/sap/suite/ui/generic/template/lib/CRUDHelper.js +93 -55
  30. package/src/sap/suite/ui/generic/template/lib/CRUDManager.js +7 -0
  31. package/src/sap/suite/ui/generic/template/lib/CommonEventHandlers.js +76 -19
  32. package/src/sap/suite/ui/generic/template/lib/CommonUtils.js +4 -1
  33. package/src/sap/suite/ui/generic/template/lib/ComponentUtils.js +17 -7
  34. package/src/sap/suite/ui/generic/template/lib/StableIdDefinition.js +35 -34
  35. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillAIOrchestrator.js +185 -0
  36. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillApplyHandler.js +476 -0
  37. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillDialogController.js +311 -0
  38. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFieldCollector.js +669 -0
  39. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFormRenderer.js +217 -0
  40. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillHandler.js +348 -422
  41. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillTableRenderer.js +491 -0
  42. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillDialog.fragment.xml +142 -72
  43. package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterBarHandler.js +409 -22
  44. package/src/sap/suite/ui/generic/template/lib/i18n/i18n.properties +32 -8
  45. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ar.properties +14 -0
  46. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_bg.properties +14 -0
  47. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ca.properties +14 -0
  48. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cnr.properties +14 -0
  49. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cs.properties +14 -0
  50. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cy.properties +14 -0
  51. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_da.properties +14 -0
  52. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_de.properties +14 -0
  53. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_el.properties +14 -0
  54. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en.properties +14 -0
  55. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_GB.properties +14 -0
  56. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_US_saprigi.properties +14 -0
  57. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es.properties +14 -0
  58. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es_MX.properties +14 -0
  59. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_et.properties +14 -0
  60. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fi.properties +14 -0
  61. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr.properties +15 -1
  62. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr_CA.properties +15 -1
  63. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hi.properties +14 -0
  64. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hr.properties +15 -1
  65. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hu.properties +14 -0
  66. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_id.properties +14 -0
  67. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_it.properties +14 -0
  68. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_iw.properties +14 -0
  69. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ja.properties +20 -6
  70. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_kk.properties +14 -0
  71. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ko.properties +14 -0
  72. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lt.properties +14 -0
  73. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lv.properties +14 -0
  74. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_mk.properties +14 -0
  75. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ms.properties +14 -0
  76. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_nl.properties +15 -1
  77. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_no.properties +14 -0
  78. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pl.properties +14 -0
  79. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt.properties +14 -0
  80. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt_PT.properties +14 -0
  81. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ro.properties +14 -0
  82. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ru.properties +14 -0
  83. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sh.properties +14 -0
  84. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sk.properties +14 -0
  85. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sl.properties +14 -0
  86. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sr.properties +14 -0
  87. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sv.properties +14 -0
  88. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_th.properties +14 -0
  89. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_tr.properties +14 -0
  90. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_uk.properties +17 -3
  91. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_vi.properties +14 -0
  92. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_CN.properties +20 -6
  93. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_TW.properties +20 -6
  94. package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +1 -1
  95. package/src/sap/suite/ui/generic/template/library.js +25 -2
  96. package/src/sap/suite/ui/generic/template/themes/base/ObjectPage.less +22 -3
  97. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillNonUpdatableSmartForm.fragment.xml +0 -18
  98. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillUpdatebleSmartForm.fragment.xml +0 -15
@@ -1,482 +1,408 @@
1
1
  sap.ui.define([
2
2
  "sap/ui/base/Object",
3
3
  "sap/base/util/extend",
4
- "sap/ui/comp/smartform/Group",
5
- "sap/ui/comp/smartform/GroupElement",
6
- "sap/ui/comp/smartfield/SmartField",
7
- "sap/ui/comp/smartfield/SmartLabel",
8
- "sap/m/MessageToast",
9
- "sap/ui/model/json/JSONModel",
10
- "sap/ui/model/odata/AnnotationHelper"
11
- ], function(BaseObject, extend, Group, GroupElement, SmartField, SmartLabel,MessageToast,JSONModel,AnnotationHelperModel) {
12
- 'use strict';
13
- /*
14
- * This is a handler class for EasyFill.
15
- * It gets initialized when the Fiori AI EasyFill is enabled
16
- * Below things are handled in this class:
17
- * 1. Prepare Field metadata
18
- * 2. Prepare EasyFill Dialog
4
+ "sap/suite/ui/generic/template/library",
5
+ "sap/suite/ui/generic/template/genericUtilities/FeError",
6
+ "sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFieldCollector",
7
+ "sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillAIOrchestrator",
8
+ "sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFormRenderer",
9
+ "sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillTableRenderer",
10
+ "sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillApplyHandler",
11
+ "sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillDialogController",
12
+ "sap/suite/ui/generic/template/js/AnnotationHelper"
13
+ ], function(
14
+ BaseObject,
15
+ extend,
16
+ Library,
17
+ FeError,
18
+ EasyFillFieldCollector,
19
+ EasyFillAIOrchestrator,
20
+ EasyFillFormRenderer,
21
+ EasyFillTableRenderer,
22
+ EasyFillApplyHandler,
23
+ EasyFillDialogController,
24
+ GenericAnnotationHelper
25
+ ) {
26
+ "use strict";
27
+
28
+ /**
29
+ * EasyFillHandler
19
30
  *
31
+ * Thin orchestrator for the EasyFill AI feature on the ObjectPage.
32
+ *
33
+ * This class wires all EasyFill sub-modules together and exposes a single public
34
+ * entry point (onEasyFillButtonClick) to the ObjectPage ControllerImplementation.
35
+ *
36
+ * Sub-module responsibilities:
37
+ * EasyFillFieldCollector — OData metadata field/section extraction
38
+ * EasyFillAIOrchestrator — AI service call and response post-processing
39
+ * EasyFillFormRenderer — SmartForm/GroupElement/SmartField population
40
+ * EasyFillTableRenderer — SmartTable collection preview rendering
41
+ * EasyFillApplyHandler — Confirm/save, validation, reset logic
42
+ * EasyFillDialogController — Dialog lifecycle, formatters, UI event handlers
43
+ *
44
+ * Shared mutable state lives here and is passed by reference into sub-modules.
45
+ * Sub-modules are stateless — they never store state themselves.
20
46
  */
21
47
  function getMethods(oState, oController, oTemplateUtils, oObjectPage) {
22
- let oTransientContextForEasyFill;
23
- let oObjectPageContext;
24
- let oObjectPageModel;
25
- let mUpdatableLookupMap;
26
- let oRb;
27
- let oAIPopover;
28
- let aEditableFields = [];
29
-
30
- async function openEasyFillDialog(oEvent,oContext) {
31
- let oEasyFillDialog;
48
+ var EasyFillLayoutMode = Library.EasyFillLayoutMode;
49
+
50
+ // ─── Shared Mutable State ────────────────────────────────────────────────
51
+ // All state is declared here and passed into sub-modules as needed.
52
+ // Sub-modules must not cache these values — always use the latest reference.
53
+
54
+ var oTransientContextForEasyFill = null; // Transient OData context for staged AI scalar values
55
+ var oObjectPageContext = null; // Live ObjectPage binding context
56
+ var oObjectPageModel = null; // OData model of the ObjectPage
57
+ var mUpdatableLookupMap = {}; // { fieldName: value } for updatable fields only
58
+ var oRb = null; // i18n resource bundle
59
+ var oAIPopoverRef = { popover: null }; // Mutable ref for lazy-loaded AINotice popover
60
+
61
+ // Collection state — tracks OData row contexts and property metadata for SmartTable collections
62
+ var mCollectionState = {
63
+ mCollectionRowContexts: Object.create(null),
64
+ mCollectionRowContextsByPath: Object.create(null),
65
+ mCollectionProperties: Object.create(null),
66
+ mCollectionEntityTypes: Object.create(null)
67
+ };
68
+
69
+ var mCollectionUpdates = Object.create(null); // { navProperty: [ rowUpdate ] } from AI response
70
+ var oTableStagingState = {
71
+ mStagedRows: Object.create(null)
72
+ };
73
+
74
+ // ─── Internal Helpers ────────────────────────────────────────────────────
75
+
76
+ /**
77
+ * Opens the EasyFill dialog for the given ObjectPage context.
78
+ * Initializes the dialog model on first open, then loads and opens the dialog fragment
79
+ * with all event handlers and formatters bound.
80
+ *
81
+ * @param {sap.ui.base.Event} oEvent - the button click event
82
+ * @param {sap.ui.model.Context} [oContext] - optional context override (used when OP just entered edit mode)
83
+ */
84
+ async function openEasyFillDialog(oEvent, oContext) {
32
85
  oRb = oController.getView().getModel("i18n").getResourceBundle();
33
- const bIsModelCreated = !!oController.getView().getModel("easyFillDialogModel");
34
86
  oObjectPageModel = oObjectPage.getModel();
35
- if (!bIsModelCreated) {
36
- const aDeferredGroups = oObjectPageModel.getDeferredGroups();
37
- //Adding a defferred group will make sure that no batch call would get triggered to backend until submitChanges() is invoked
38
- aDeferredGroups.push("EasyFillFETransientChanges");
39
- oObjectPageModel.setDeferredGroups(aDeferredGroups);
40
-
41
- //Creating a JSON model for the dialog
42
-
43
- const oData = {
44
- isBusy: false,
45
- isUpdatableVisible: false,
46
- isNonUpdatableVisible: false,
47
- isIllustrationVisible: true,
48
- isSaveEnabled: false,
49
- stateType: "Initial",
50
- feedbackEnabled: true,
51
- feedbackPressedUp: false,
52
- feedbackPressedDown: false,
53
- isEasyFillButtonEnabled: false
54
- };
55
-
56
- let oModel = new JSONModel(oData);
57
- oController.getView().setModel(oModel, "easyFillDialogModel");
58
- }
59
87
 
60
- oObjectPageContext = (oContext) ? oContext : oObjectPage.getBindingContext();
88
+ // Initialize dialog model and deferred group once per view lifetime
89
+ EasyFillDialogController.initDialogModel(oController, oObjectPageModel, EasyFillLayoutMode);
61
90
 
62
- // cannot use OP path to create a list binding as it is a individual entry
63
- var sFragmentname = "sap.suite.ui.generic.template.lib.ai.EasyFill.fragments.EasyFillDialog";
64
- oTemplateUtils.oCommonUtils.getDialogFragmentAsync(sFragmentname, {
65
- onFeedbackPress: function() {
66
- const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
67
- easyFillDialogModel.setProperty("/feedbackEnabled",false);
68
- MessageToast.show(oRb.getText("EASYFILL_RESULT_FEEDBACK"));
69
- },
70
- formatIllustrationType: function (sState) {
71
- switch (sState) {
72
- case "Initial":
73
- return "sapIllus-NoSearchResults";
74
- case "NoEntries":
75
- return "sapIllus-NoEntries";
76
- case "Error":
77
- return "sapIllus-UnableToLoad";
78
- default:
79
- return "sapIllus-NoSearchResults";
80
- }
81
- },
82
- formatIllustrationTitle: function (sState) {
83
- switch (sState) {
84
- case "Initial":
85
- return oRb.getText("EASY_FILL_ILLUSTRATION_TITLE_INITIAL");
86
- case "NoEntries":
87
- return oRb.getText("EASY_FILL_ILLUSTRATION_TITLE_NO_ENTRIES");
88
- case "Error":
89
- return oRb.getText("EASY_FILL_ILLUSTRATION_TITLE_ERROR");
90
- default:
91
- return oRb.getText("EASY_FILL_ILLUSTRATION_TITLE_INITIAL");
92
- }
93
- },
94
- formatIllustrationDescription: function (sState) {
95
- switch (sState) {
96
- case "Initial":
97
- return oRb.getText("EASY_FILL_ILLUSTRATION_DESCRIPTION_INITIAL");
98
- case "NoEntries":
99
- return oRb.getText("EASY_FILL_ILLUSTRATION_DESCRIPTION_NO_ENTRIES");
100
- case "Error":
101
- return oRb.getText("EASY_FILL_ILLUSTRATION_DESCRIPTION_ERROR");
102
- default:
103
- return oRb.getText("EASY_FILL_ILLUSTRATION_DESCRIPTION_INITIAL");
104
- }
91
+ // Use the provided context override or fall back to the current OP binding context
92
+ oObjectPageContext = oContext || oObjectPage.getBindingContext();
93
+
94
+ // Build the handler/formatter map that the dialog fragment binds to
95
+ var oHandlers = _buildDialogHandlers();
96
+
97
+ await EasyFillDialogController.openDialog(oController, oTemplateUtils, oHandlers);
98
+ }
99
+
100
+ /**
101
+ * Builds the event handler and formatter map passed to the EasyFillDialog fragment.
102
+ * Each entry corresponds to a function called from the fragment via event binding or formatter.
103
+ *
104
+ * @returns {object} handler/formatter map
105
+ */
106
+ function _buildDialogHandlers() {
107
+ return {
108
+ // ── Layout mode toggle (Condensed ↔ ObjectPage view) ──────────────
109
+ onSelectionChange: function(oEvent) {
110
+ EasyFillDialogController.onSelectionChange(
111
+ oEvent, oController, oTemplateUtils, oRb,
112
+ EasyFillFieldCollector, EasyFillLayoutMode
113
+ );
105
114
  },
106
- onSaveFromEasyFillDialog : async function (oEvent) {
107
- var oTransientObject = oTransientContextForEasyFill.getObject();
108
- for (const oProp in oTransientObject) {
109
- if (oProp !== "__metadata" && mUpdatableLookupMap[oProp]) {
110
- oObjectPageContext.setProperty(oProp, oTransientObject[oProp]);
111
- }
112
- }
113
- activateSideEffects();
114
- resetEasyFill(true);
115
- oEasyFillDialog?.close();
115
+
116
+ // ── Feedback thumbs-up/down ───────────────────────────────────────
117
+ onFeedbackPress: function() {
118
+ EasyFillDialogController.onFeedbackPress(oController, oRb);
116
119
  },
117
- onLiveChange: function(oEvent) {
118
- const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
119
- easyFillDialogModel.setProperty("/isEasyFillButtonEnabled",!!oEvent.getSource().getValue());
120
+
121
+ // ── Section title formatter (resolves i18n patterns) ──────────────
122
+ formatSectionTitle: function(sTitle) {
123
+ return EasyFillDialogController.formatSectionTitle(sTitle, oController);
120
124
  },
121
- onCancelEasyFillDialog : function () {
122
- resetEasyFill(true);
123
- oEasyFillDialog.close();
125
+
126
+ // ── IllustratedMessage state formatters ───────────────────────────
127
+ formatIllustrationType: function(sState) {
128
+ return EasyFillDialogController.formatIllustrationType(sState);
124
129
  },
125
- onEasyFillSubmitInputToAI : async function (oEvent) {
126
- const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
127
- easyFillDialogModel.setProperty("/isBusy",true);
128
- let mFieldMapping = getEntitySetMapForLLM();
129
- let aiCallResult = await oTemplateUtils.oServices.oFioriAIHandler.fioriaiLib.EasyFill.extractFieldValuesFromText(oController.byId("EasyFillInputTextArea").getValue(), mFieldMapping);
130
- resetEasyFill();
131
- aEditableFields = [];
132
- easyFillDialogModel.setProperty("/isBusy",false);
133
- formatDateValues(aiCallResult,mFieldMapping);
134
- if (aiCallResult.success) {
135
- const {updatableFields,nonUpdatableFields} = getUpdatableAndNonUpdatableFields(aiCallResult.data);
136
- mUpdatableLookupMap = updatableFields;
137
- if (Object.keys(updatableFields).length + Object.keys(nonUpdatableFields).length === 0) {
138
- easyFillDialogModel.setProperty("/stateType","NoEntries");
139
- return;
140
- }
141
- easyFillDialogModel.setProperty("/isIllustrationVisible",false);
142
- //Fillable Fields
143
- makeTransientContext();
144
- easyFillDialogModel.setProperty("/isUpdatableVisible",Object.keys(updatableFields).length > 0);
145
- if (Object.keys(updatableFields).length > 0) {
146
- const oAIResponseReviewRegionSmartFormForUpdatableFields = oController.byId("EasyFillUpdatebleForm");
147
-
148
- const oOldGroup = getGroupForSmartForm(updatableFields,false,oObjectPage.getBindingContext(),false);
149
- const oNewGroup = getGroupForSmartForm(updatableFields,true,oTransientContextForEasyFill,true);
150
- oAIResponseReviewRegionSmartFormForUpdatableFields.addGroup(oOldGroup);
151
- oAIResponseReviewRegionSmartFormForUpdatableFields.addGroup(oNewGroup);
152
- validateSmartForm();
153
- }
154
- //Non-Fillable Fields
155
- easyFillDialogModel.setProperty("/isNonUpdatableVisible",Object.keys(nonUpdatableFields).length > 0);
156
- if (Object.keys(nonUpdatableFields).length > 0) {
157
- const oAIResponseReviewRegionSmartFormForNonUpdatableFields = oController.byId("EasyFillNonUpdatebleForm");
158
- const oOldGroup = getGroupForSmartForm(nonUpdatableFields,false,oObjectPage.getBindingContext(),false);
159
- const oNewGroup = getGroupForSmartForm(nonUpdatableFields,false,oTransientContextForEasyFill,true);
160
- oAIResponseReviewRegionSmartFormForNonUpdatableFields.addGroup(oOldGroup);
161
- oAIResponseReviewRegionSmartFormForNonUpdatableFields.addGroup(oNewGroup);
162
- }
163
- } else {
164
- easyFillDialogModel.setProperty("/stateType","Error");
165
- }
130
+ formatIllustrationTitle: function(sState) {
131
+ return EasyFillDialogController.formatIllustrationTitle(sState, oRb);
166
132
  },
167
- onEasyFillClearAll: function() {
168
- resetEasyFill(true);
133
+ formatIllustrationDescription: function(sState) {
134
+ return EasyFillDialogController.formatIllustrationDescription(sState, oRb);
169
135
  },
170
- onLinkPress: async function(oEvent) {
171
- if (!oAIPopover) {
172
- oAIPopover = await getAIPopover();
173
- }
174
- oAIPopover.openBy(oEvent.getSource());
175
- }
176
- }, "easyFillPopup",undefined,true,true).then(function (oPopup) {
177
- oEasyFillDialog = oPopup;
178
- oPopup?.open();
179
- });
180
- }
181
-
182
- function activateSideEffects() {
183
- //Making a set so that , duplicate field group ids are not passed
184
- const aFieldGroupIdSet = new Set();
185
- aEditableFields.forEach((oSmartField)=>{
186
- //SideEffect would be invoked only for the editable controls inside the SmartField
187
- const aEditableInnerFields = oSmartField.getInnerControls().filter((oControl)=>oControl.getEditable());
188
- aEditableInnerFields.forEach((oControl)=>{
189
- const aControlFieldGroupId = oControl.getFieldGroupIds();
190
- if (aControlFieldGroupId.length > 0) {
191
- aControlFieldGroupId.forEach((sFieldGroupId)=>{
192
- aFieldGroupIdSet.add(sFieldGroupId);
193
- });
194
- }
195
- });
196
136
 
197
- });
137
+ // ── Confirm: apply AI values to the live OP context ───────────────
138
+ onSaveFromEasyFillDialog: async function() {
139
+ EasyFillApplyHandler.applyAndSave(
140
+ oTransientContextForEasyFill,
141
+ oObjectPageContext,
142
+ mUpdatableLookupMap,
143
+ oTableStagingState,
144
+ mCollectionState
145
+ );
146
+ _resetEasyFill(true);
147
+ EasyFillDialogController.closeDialog(oController);
148
+ },
198
149
 
199
- const oView = oController.getView();
150
+ // ── Text area live change: enable/disable submit button ───────────
151
+ onLiveChange: function(oEvent) {
152
+ EasyFillDialogController.onLiveChange(oEvent, oController);
153
+ },
200
154
 
201
- aFieldGroupIdSet.forEach((sFieldGroupId)=>{
202
- const oID = oView.data(sFieldGroupId);
155
+ // ── Cancel: revert staged values and close dialog ─────────────────
156
+ onCancelEasyFillDialog: function() {
157
+ _resetEasyFill(true);
158
+ EasyFillDialogController.closeDialog(oController);
159
+ },
203
160
 
204
- /**
205
- * Currently, the SmartFields are created using the TransientContext, which means both
206
- * "context" and "contextObject" refer to the TransientContext instance.
207
- *
208
- * However, we need to use the original OP context so that side effects are triggered
209
- * on the original OP context when the user saves data from the EasyFill dialog back to OP.
210
- *
211
- * Therefore, we update the "context" and "contextObject" to reference the original OP context.
212
- */
161
+ // ── Field value formatter (binding expression builder) ────────────
162
+ formatFieldValue: function(sFieldName) {
163
+ return "{" + sFieldName + "}";
164
+ },
213
165
 
214
- if (oID) {
215
- oID["context"] = oObjectPageContext.getPath();
216
- oID["contextObject"] = oObjectPageContext;
217
- oView.data(sFieldGroupId,oID);
218
- }
219
- //To make sure that all the fields sideeffect would be triggered
220
- const sSideEffectQualifier = oTemplateUtils.oServices.oApplicationController._getSideEffectsQualifier(oID.name);
221
- oTemplateUtils.oServices.oApplicationController.registerGroupChange(sSideEffectQualifier);
222
- });
166
+ // ── Submit user text to AI ────────────────────────────────────────
167
+ onEasyFillSubmitInputToAI: async function() {
168
+ await _handleAISubmit();
169
+ },
223
170
 
171
+ // ── Clear all (reset without closing) ────────────────────────────
172
+ onEasyFillClearAll: function() {
173
+ _resetEasyFill(true);
174
+ },
224
175
 
225
- oView.triggerValidateFieldGroup([...aFieldGroupIdSet]);
226
- }
176
+ // ── SmartForm group population formatter ──────────────────────────
177
+ populateSmartFields: function(sId, aFields, sEasyFillMode) {
178
+ return EasyFillFormRenderer.populateSmartFields(
179
+ sId, aFields, sEasyFillMode,
180
+ oController,
181
+ oTransientContextForEasyFill,
182
+ oObjectPageContext,
183
+ mUpdatableLookupMap,
184
+ oDialogModel().getProperty("/llmData")
185
+ );
186
+ },
227
187
 
228
- function getAIPopover() {
229
- return new Promise(async(resolve,reject) => {
230
- const sFragmentname = "sap.suite.ui.generic.template.fragments.AINotice";
231
- const oPopover = await oTemplateUtils.oCommonUtils.getDialogFragmentAsync(sFragmentname,{
232
- onCloseAiPopover: function() {
233
- oAIPopover.close();
234
- }
235
- },"aiPopover",undefined,true);
236
- resolve(oPopover);
237
- });
238
- }
188
+ // ── Fullscreen toggle ─────────────────────────────────────────────
189
+ onToggleFullScreen: function() {
190
+ EasyFillDialogController.onToggleFullScreen(oController);
191
+ },
239
192
 
240
- function getEntitySetMapForLLM() {
241
- const mPropertyMap = {};
242
- const oEntityType = oTemplateUtils.oCommonUtils.getMetaModelEntityType(oController.getOwnerComponent().getEntitySet());
243
- oEntityType.property.forEach((oProperty)=>{
244
- if (isVisible(oProperty)) {
245
- mPropertyMap[oProperty.name] = {
246
- description: getLabel(oProperty),
247
- dataType: oProperty.type
248
- };
193
+ // ── AI Notice popover ─────────────────────────────────────────────
194
+ onLinkPress: async function(oEvent) {
195
+ await EasyFillDialogController.onLinkPress(oEvent, oTemplateUtils, oAIPopoverRef);
249
196
  }
250
- });
251
- return mPropertyMap;
197
+ };
252
198
  }
253
199
 
254
- function getLabel(oProperty) {
255
- return oProperty["com.sap.vocabularies.Common.v1.Label"] ? AnnotationHelperModel.format(oObjectPageContext,oProperty["com.sap.vocabularies.Common.v1.Label"]) : oProperty["sap:label"];
256
- }
200
+ /**
201
+ * Handles the full AI submission flow:
202
+ * 1. Build field mapping
203
+ * 2. Call AI service
204
+ * 3. Post-process response (dates, split)
205
+ * 4. Update dialog model
206
+ * 5. Populate SmartForms and table previews
207
+ */
208
+ async function _handleAISubmit() {
209
+ var oModel = oDialogModel();
210
+ oModel.setProperty("/isBusy", true);
211
+
212
+ // Build complete LLM field mapping (entity fields + collection fields)
213
+ var mFieldMapping = EasyFillAIOrchestrator.buildFieldMapping(
214
+ oTemplateUtils, oController, oObjectPage, oObjectPageModel,
215
+ oObjectPageContext, EasyFillFieldCollector, mCollectionState
216
+ );
217
+
218
+ // Submit to AI
219
+ var aiCallResult = await EasyFillAIOrchestrator.submitToAI(
220
+ oController.byId("EasyFillInputTextArea").getValue(),
221
+ mFieldMapping,
222
+ oTemplateUtils
223
+ );
224
+
225
+ // Reset editable fields tracker for fresh population
226
+ oModel.setProperty("/isBusy", false);
227
+
228
+ // Convert date strings in AI response to JS Date objects
229
+ EasyFillAIOrchestrator.formatDateValues(aiCallResult, mFieldMapping);
230
+
231
+ var sSelectedKey = oModel.getProperty("/easyFillMode") || EasyFillLayoutMode.CondensedMode;
232
+ oModel.setProperty("/easyFillMode", sSelectedKey);
257
233
 
258
- function formatDateValues(aiCallResult,mFieldMapping) {
259
234
  if (aiCallResult.success) {
260
- for (const key of Object.keys(aiCallResult.data)) {
261
- const sDataType = mFieldMapping[key].dataType;
262
- if (sDataType === "Edm.DateTimeOffset" || sDataType === "Edm.DateTime") {
263
- aiCallResult.data[key] = new Date(aiCallResult.data[key]);
235
+ // Split AI response into simple fields (SmartForm) and collection rows (SmartTable)
236
+ var oSplitResult = EasyFillAIOrchestrator.splitAIResultByCollection(
237
+ aiCallResult.data, mFieldMapping, EasyFillFieldCollector, oObjectPage
238
+ );
239
+ var simpleFields = oSplitResult.simpleFields;
240
+ var collectionFields = oSplitResult.collectionFields;
241
+
242
+ // Separate updatable from non-updatable fields
243
+ var oEntityType = oTemplateUtils.oCommonUtils.getMetaModelEntityType(
244
+ oController.getOwnerComponent().getEntitySet()
245
+ );
246
+ var oSplit = EasyFillFieldCollector.getUpdatableAndNonUpdatableFields(
247
+ simpleFields, oEntityType, oObjectPageContext
248
+ );
249
+ mUpdatableLookupMap = oSplit.updatableFields;
250
+
251
+ // Build section tree for selected view mode
252
+ var aData = (sSelectedKey === EasyFillLayoutMode.CondensedMode)
253
+ ? EasyFillFieldCollector.getSectionsForCondensedView(simpleFields)
254
+ : EasyFillFieldCollector.getSectionsForObjectPageView(oEntityType, simpleFields, oRb);
255
+
256
+ // Reset form (destroy previous SmartForm content + revert table staging)
257
+ // then create a fresh transient context for the new AI result
258
+ _resetEasyFill();
259
+ oTransientContextForEasyFill = EasyFillFormRenderer.makeTransientContext(
260
+ null, oObjectPageModel, oController
261
+ );
262
+
263
+ // Update dialog model with section data and AI result
264
+ oModel.setProperty("/sections", aData);
265
+ oModel.setProperty("/llmData", simpleFields);
266
+
267
+ // Process collection/table updates
268
+ mCollectionUpdates = collectionFields;
269
+ var bHasTableUpdates = Object.keys(mCollectionUpdates).length > 0;
270
+ oModel.setProperty("/hasTableUpdates", bHasTableUpdates);
271
+
272
+ // Render collection previews into the table preview container
273
+ EasyFillTableRenderer.renderCollectionPreviews(
274
+ mCollectionUpdates,
275
+ mFieldMapping,
276
+ [],
277
+ oController,
278
+ oRb,
279
+ mCollectionState,
280
+ oTableStagingState,
281
+ oObjectPageModel,
282
+ function() {
283
+ _refreshTableValidationAndSaveState().catch(Function.prototype);
264
284
  }
265
- }
266
- }
267
- }
285
+ );
286
+
287
+ await _refreshTableValidationAndSaveState();
268
288
 
269
- function validateSmartForm() {
270
- setTimeout(async() => {
271
- const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
272
- try {
273
- const oAIResponseReviewRegionSmartFormForUpdatableFields = oController.byId("EasyFillUpdatebleForm");
274
- const aIds = await oAIResponseReviewRegionSmartFormForUpdatableFields.check();
275
- easyFillDialogModel.setProperty("/isSaveEnabled",aIds.length === 0);
276
- } catch (error) {
277
- easyFillDialogModel.setProperty("/isSaveEnabled",false);
289
+ var iTotalFields = Object.keys(oSplit.updatableFields).length + Object.keys(oSplit.nonUpdatableFields).length;
290
+ if (iTotalFields === 0 && !bHasTableUpdates) {
291
+ oModel.setProperty("/stateType", "NoEntries");
292
+ return;
278
293
  }
279
- }, 0);
280
- }
281
294
 
282
- function resetEasyFill(bRemoveTextAreaValue) {
283
- const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
284
- const oAIResponseReviewRegionSmartFormForNonUpdatableFields = oController.byId("EasyFillNonUpdatebleForm");
285
- const oAIResponseReviewRegionSmartFormForUpdatableFields = oController.byId("EasyFillUpdatebleForm");
286
- oAIResponseReviewRegionSmartFormForUpdatableFields.destroyGroups();
287
- oAIResponseReviewRegionSmartFormForNonUpdatableFields.destroyGroups();
288
- resetTransientContext();
289
- easyFillDialogModel.setProperty("/isUpdatableVisible",false);
290
- easyFillDialogModel.setProperty("/isNonUpdatableVisible",false);
291
- easyFillDialogModel.setProperty("/isIllustrationVisible",true);
292
- easyFillDialogModel.setProperty("/isSaveEnabled",false);
293
- easyFillDialogModel.setProperty("/stateType","Initial");
294
- easyFillDialogModel.setProperty("/feedbackEnabled",true);
295
- easyFillDialogModel.setProperty("/feedbackPressedUp",false);
296
- easyFillDialogModel.setProperty("/feedbackPressedDown",false);
297
- if (bRemoveTextAreaValue) {
298
- oController.byId("EasyFillInputTextArea").setValue("");
299
- easyFillDialogModel.setProperty("/isEasyFillButtonEnabled",false);
295
+ oModel.setProperty("/isIllustrationVisible", false);
296
+ oModel.setProperty("/isFormVisible", iTotalFields > 0);
297
+ } else {
298
+ // AI call failed — show error illustration
299
+ EasyFillApplyHandler.applyTableValidationState([], oModel, oRb);
300
+ oModel.setProperty("/stateType", "Error");
300
301
  }
301
302
  }
302
303
 
303
- function getUpdatableAndNonUpdatableFields(oAiCallResult) {
304
- const oEntityType = oTemplateUtils.oCommonUtils.getMetaModelEntityType(oController.getOwnerComponent().getEntitySet());
305
- const updatableFields = {};
306
- const nonUpdatableFields = {};
307
-
308
- Object.keys(oAiCallResult).forEach((sKey)=>{
309
- const oProperty = oEntityType.property.find((oProperty)=>oProperty.name === sKey);
310
- if (isEditable(oProperty)) {
311
- updatableFields[sKey] = oAiCallResult[sKey];
312
- } else {
313
- nonUpdatableFields[sKey] = oAiCallResult[sKey];
314
- }
315
-
316
- });
317
- return {updatableFields,nonUpdatableFields};
304
+ async function _refreshTableValidationAndSaveState() {
305
+ var oModel = oDialogModel();
306
+ var mStagedCollectionUpdates = EasyFillApplyHandler.buildStagedCollectionUpdates(
307
+ oTableStagingState,
308
+ mCollectionState
309
+ );
310
+ var aTableValidationErrors = await EasyFillApplyHandler.validateCollectionUpdatesAgainstValueHelp(
311
+ mStagedCollectionUpdates,
312
+ mCollectionState,
313
+ oObjectPageModel,
314
+ oRb,
315
+ EasyFillFieldCollector,
316
+ GenericAnnotationHelper
317
+ );
318
+ EasyFillApplyHandler.applyTableValidationState(aTableValidationErrors, oModel, oRb);
319
+
320
+ var bHasScalarChanges = Object.keys(mUpdatableLookupMap || {}).length > 0;
321
+ var bHasTableChanges = EasyFillApplyHandler.hasStagedCollectionChanges(
322
+ oTableStagingState,
323
+ mCollectionState
324
+ );
325
+
326
+ oModel.setProperty(
327
+ "/isSaveEnabled",
328
+ bHasScalarChanges || (bHasTableChanges && aTableValidationErrors.length === 0)
329
+ );
330
+
331
+ return aTableValidationErrors;
318
332
  }
319
333
 
320
- //Checks if the field is editable or not
321
-
322
- // It can be set in 2 ways using field-control, it would be present when sap:updatable attribute is not present
323
- // 1. By attaching to an existing metadata property, sap:field-control-> path for the property
324
- //Below are the values by which the editable state would be defined
325
-
326
334
  /**
327
- * Value Meaning
328
- -----------------------------------------------
329
- 0 Hidden (field not shown at all)
330
- 1 Read-only (display only)
331
- 3 Editable
332
- 7 Mandatory (Still Editable)
333
- */
334
-
335
- // 2. By Adding to an annotation "com.sap.vocabularies.Common.v1.FieldControl"
336
-
337
- //Since "com.sap.vocabularies.Common.v1.FieldControl" is an V4 annotation, it would be given the first priority
338
-
339
- function isEditable(oProperty) {
340
-
341
- //Check for sap:updatable
342
- const sUpdatable = oProperty["sap:updatable"];
343
- if (sUpdatable) {
344
- return sUpdatable === "false" ? false : true;
345
- }
346
-
347
- //Check for "com.sap.vocabularies.Common.v1.FieldControl"
348
- const oAnnotation = oProperty["com.sap.vocabularies.Common.v1.FieldControl"];
349
-
350
- if (oAnnotation && oAnnotation["EnumMember"]) {
351
- const enumNumberType = oAnnotation["EnumMember"];
352
- return enumNumberType === 'com.sap.vocabularies.Common.v1.FieldControlType/ReadOnly' ? false : true;
353
- }
354
-
355
-
356
- //Check for "sap:field-control"
357
- const sFieldControl = oProperty["sap:field-control"];
358
-
359
- if (sFieldControl) {
360
- const iFieldControlValue = oObjectPageContext.getObject()[sFieldControl];
361
- return iFieldControlValue === 1 ? false : true;
362
- }
363
-
364
- //If no restriction is present then by default all fields are editable
365
- return true;
366
- }
367
-
368
- function isVisible(oProperty) {
369
-
370
- //Check for "com.sap.vocabularies.Common.v1.FieldControl"
371
- const oAnnotation = oProperty["com.sap.vocabularies.Common.v1.FieldControl"];
372
-
373
- if (oAnnotation && oAnnotation["EnumMember"]) {
374
- const enumNumberType = oAnnotation["EnumMember"];
375
- return enumNumberType === 'com.sap.vocabularies.Common.v1.FieldControlType/Hidden' ? false : true;
376
- }
377
-
378
- //Check for Hidden annotation i.e com.sap.vocabularies.UI.v1.Hidden
379
- const oHiddenAnnotation = oProperty["com.sap.vocabularies.UI.v1.Hidden"];
380
- if (oHiddenAnnotation) {
381
- let bIsVisible = false; // <Annotation Term="UI.Hidden"/>
382
- if (oHiddenAnnotation["Bool"]) {
383
- bIsVisible = (oHiddenAnnotation["Bool"] === "true") ? false : true;
384
- } else if (oHiddenAnnotation["Path"]) {
385
- bIsVisible = !oObjectPageContext.getObject()[oHiddenAnnotation["Path"]];
335
+ * Resets the EasyFill dialog to its initial state.
336
+ * Delegates to EasyFillApplyHandler.resetEasyFill with the current state references.
337
+ *
338
+ * @param {boolean} [bRemoveTextAreaValue=false] - if true, also clears the text area input
339
+ */
340
+ function _resetEasyFill(bRemoveTextAreaValue) {
341
+ EasyFillApplyHandler.resetEasyFill(
342
+ !!bRemoveTextAreaValue,
343
+ oDialogModel(),
344
+ oController,
345
+ mCollectionUpdates,
346
+ EasyFillLayoutMode,
347
+ function() {
348
+ EasyFillTableRenderer.resetStagedCollectionContexts(oTableStagingState, oObjectPageModel);
349
+ },
350
+ function() {
351
+ EasyFillFormRenderer.resetTransientContext(oTransientContextForEasyFill, oObjectPageModel);
352
+ oTransientContextForEasyFill = null;
386
353
  }
387
- return bIsVisible;
388
- }
389
-
390
- //Check for "sap:field-control"
391
- const sFieldControl = oProperty["sap:field-control"];
392
-
393
- if (sFieldControl) {
394
- const iFieldControlValue = oObjectPageContext.getObject()[sFieldControl];
395
- return iFieldControlValue === 0 ? false : true;
396
- }
397
-
398
- //If no restriction is present then by default all fields are visible
399
- return true;
400
- }
401
-
402
- function resetTransientContext() {
403
- if (oTransientContextForEasyFill) {
404
- oObjectPageModel.resetChanges([oTransientContextForEasyFill.getPath()],false,true);
405
- oTransientContextForEasyFill = null;
406
- }
407
- }
408
-
409
- function makeTransientContext() {
410
- if (oTransientContextForEasyFill) {
411
- resetTransientContext();
412
- }
413
- oTransientContextForEasyFill = oObjectPageModel.createEntry("/" + oController.getOwnerComponent().getEntitySet(), {
414
- "groupId" : "EasyFillFETransientChanges",
415
- "changeSetId":"EasyFillFETransientChanges"
416
- });
354
+ );
417
355
  }
418
356
 
419
- function onSmartFieldChange() {
420
- validateSmartForm();
357
+ /**
358
+ * Convenience accessor for the easyFillDialogModel JSONModel.
359
+ * @returns {sap.ui.model.json.JSONModel}
360
+ */
361
+ function oDialogModel() {
362
+ return oController.getView().getModel("easyFillDialogModel");
421
363
  }
422
364
 
423
- function getGroupForSmartForm(oDataFromLLM, isEditable,oContext,isTransient) {
424
- var oGroup = new Group({
425
- title: (isTransient) ? oRb.getText("EASY_FILL_PROPOSED_VALUES") : oRb.getText("EASY_FILL_PREVIOUS_VALUES")
426
- });
427
-
428
- for (const key of Object.keys(oDataFromLLM)) {
429
- const oGroupElement = new GroupElement();
430
- const oSmartField = new SmartField({
431
- value: "{" + key + "}",
432
- editable: isEditable,
433
- enabled: isEditable,
434
- contextEditable: isEditable,
435
- change: onSmartFieldChange.bind(this),
436
- editableChanged: (oEvent)=>{
437
- //SmartField changes the editable state of inner controls based on various factors, so to make sure that the editable state remains as per our requirement we are forcing it here
438
- if (oEvent.getParameter("editable") !== isEditable) {
439
- oEvent.getSource().setEditable(isEditable);
440
- }
441
- }
442
- });
443
- if (isEditable) {
444
- aEditableFields.push(oSmartField);
445
- }
446
- const oSmartLabel = new SmartLabel();
447
- oSmartLabel.setLabelFor(oSmartField);
448
- oGroupElement.addElement(oSmartField);
449
- //Update the field only if its transient
450
- if (isTransient) {
451
- oContext.setProperty(key,oDataFromLLM[key]);
452
- }
453
- oGroup.addGroupElement(oGroupElement);
454
- }
455
- oGroup.setBindingContext(oContext);
456
- return oGroup;
457
- }
365
+ // ─── Public API ──────────────────────────────────────────────────────────
458
366
 
459
367
  return {
368
+ /**
369
+ * Entry point called by the ObjectPage ControllerImplementation when the
370
+ * EasyFill button is pressed.
371
+ *
372
+ * If the ObjectPage is already in edit mode, the dialog opens immediately.
373
+ * If not, the page is transitioned to edit mode first and the resulting
374
+ * edit context is passed into the dialog.
375
+ *
376
+ * @param {sap.ui.base.Event} oEvent - the button click event
377
+ */
460
378
  onEasyFillButtonClick: function(oEvent) {
461
- // Once you click on the easyFill button the OP should be going to editable state, if its already in editState then directly open the dialog
462
- //If its in non-editable state we should wait until the context switch, We need that context to finally save the data from the AI into the newly came editable context of the OP
463
- const isEditable = oController.getView().getModel("ui").getProperty("/editable");
464
- if (isEditable) {
379
+ var bIsEditable = oController.getView().getModel("ui").getProperty("/editable");
380
+ if (bIsEditable) {
465
381
  openEasyFillDialog(oEvent);
466
382
  } else {
467
- oController._templateEventHandlers.onEditByEasyFill().then((oContext)=>{
468
- oObjectPageContext = oContext;
469
- openEasyFillDialog(oEvent,oContext);
470
- }).catch(Function.prototype);
383
+ // Trigger the OP edit flow and wait for the new edit context before opening
384
+ oController._templateEventHandlers.onEditByEasyFill()
385
+ .then(function(oContext) {
386
+ oObjectPageContext = oContext;
387
+ openEasyFillDialog(oEvent, oContext);
388
+ })
389
+ .catch(Function.prototype);
471
390
  }
472
391
  }
473
392
  };
474
393
  }
475
394
 
476
395
  return BaseObject.extend("sap.suite.ui.generic.template.lib.ai.EasyFill.EasyFillHandler", {
477
- constructor: function (oState, oController, oTemplateUtils, oObjectPage) {
396
+ /**
397
+ * Constructor — wires all helpers and exposes the public API via getMethods.
398
+ *
399
+ * @param {object} oState - shared template state (passed from ControllerImplementation)
400
+ * @param {object} oController - MVC controller instance
401
+ * @param {object} oTemplateUtils - FE template utilities (services, common utils, etc.)
402
+ * @param {object} oObjectPage - the ObjectPage control instance
403
+ */
404
+ constructor: function(oState, oController, oTemplateUtils, oObjectPage) {
478
405
  extend(this, getMethods(oState, oController, oTemplateUtils, oObjectPage));
479
406
  }
480
407
  });
481
-
482
408
  });