@sapui5/sap.suite.ui.generic.template 1.147.1 → 1.148.0

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 (43) 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_id.properties +2 -2
  7. package/src/sap/suite/ui/generic/template/AnalyticalListPage/manifest.json +1 -1
  8. package/src/sap/suite/ui/generic/template/Canvas/manifest.json +1 -1
  9. package/src/sap/suite/ui/generic/template/ListReport/controller/ControllerImplementation.js +32 -3
  10. package/src/sap/suite/ui/generic/template/ListReport/i18n/i18n_id.properties +1 -1
  11. package/src/sap/suite/ui/generic/template/ListReport/i18n/i18n_uk.properties +1 -1
  12. package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
  13. package/src/sap/suite/ui/generic/template/ObjectPage/Component.js +4 -0
  14. package/src/sap/suite/ui/generic/template/ObjectPage/controller/ControllerImplementation.js +57 -25
  15. package/src/sap/suite/ui/generic/template/ObjectPage/i18n/i18n.properties +6 -0
  16. package/src/sap/suite/ui/generic/template/ObjectPage/i18n/i18n_en_US_saprigi.properties +4 -0
  17. package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +6 -1
  18. package/src/sap/suite/ui/generic/template/ObjectPage/templateSpecificPreparationHelper.js +35 -19
  19. package/src/sap/suite/ui/generic/template/ObjectPage/view/fragments/Footer.fragment.xml +103 -42
  20. package/src/sap/suite/ui/generic/template/QuickCreate/manifest.json +1 -1
  21. package/src/sap/suite/ui/generic/template/QuickView/manifest.json +1 -1
  22. package/src/sap/suite/ui/generic/template/fragments/EasyFilter.fragment.xml +3 -0
  23. package/src/sap/suite/ui/generic/template/genericUtilities/controlHelper.js +30 -29
  24. package/src/sap/suite/ui/generic/template/genericUtilities/controlStateWrapperFactory/SmartFilterBarWrapper.js +15 -0
  25. package/src/sap/suite/ui/generic/template/lib/AppComponent.js +1 -1
  26. package/src/sap/suite/ui/generic/template/lib/CRUDHelper.js +93 -55
  27. package/src/sap/suite/ui/generic/template/lib/CRUDManager.js +7 -0
  28. package/src/sap/suite/ui/generic/template/lib/CommonEventHandlers.js +19 -13
  29. package/src/sap/suite/ui/generic/template/lib/CommonUtils.js +4 -1
  30. package/src/sap/suite/ui/generic/template/lib/ComponentUtils.js +17 -7
  31. package/src/sap/suite/ui/generic/template/lib/StableIdDefinition.js +35 -34
  32. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillHandler.js +853 -130
  33. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/ObjectPageSectionHandler.js +282 -0
  34. package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillDialog.fragment.xml +138 -72
  35. package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterBarHandler.js +409 -22
  36. package/src/sap/suite/ui/generic/template/lib/i18n/i18n.properties +21 -0
  37. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ja.properties +6 -6
  38. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_uk.properties +3 -3
  39. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_CN.properties +6 -6
  40. package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_TW.properties +6 -6
  41. package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +1 -1
  42. package/src/sap/suite/ui/generic/template/library.js +25 -2
  43. package/src/sap/suite/ui/generic/template/themes/base/ObjectPage.less +14 -0
@@ -1,15 +1,30 @@
1
1
  sap.ui.define([
2
2
  "sap/ui/base/Object",
3
3
  "sap/base/util/extend",
4
- "sap/ui/comp/smartform/Group",
5
4
  "sap/ui/comp/smartform/GroupElement",
6
5
  "sap/ui/comp/smartfield/SmartField",
7
- "sap/ui/comp/smartfield/SmartLabel",
8
6
  "sap/m/MessageToast",
9
7
  "sap/ui/model/json/JSONModel",
10
- "sap/ui/model/odata/AnnotationHelper"
11
- ], function(BaseObject, extend, Group, GroupElement, SmartField, SmartLabel,MessageToast,JSONModel,AnnotationHelperModel) {
8
+ "sap/ui/model/odata/AnnotationHelper",
9
+ "sap/suite/ui/generic/template/lib/ai/EasyFill/ObjectPageSectionHandler",
10
+ "sap/m/VBox",
11
+ "sap/m/Text",
12
+ "sap/suite/ui/generic/template/library",
13
+ "sap/m/HBox",
14
+ "sap/ui/layout/form/ColumnElementData",
15
+ "sap/suite/ui/generic/template/js/AnnotationHelper",
16
+ "sap/suite/ui/generic/template/genericUtilities/controlHelper",
17
+ "sap/ui/model/Filter",
18
+ "sap/ui/model/FilterOperator",
19
+ "sap/m/Title",
20
+ "sap/m/SegmentedButton",
21
+ "sap/m/SegmentedButtonItem",
22
+ "sap/m/Table",
23
+ "sap/m/Column",
24
+ "sap/m/ColumnListItem"
25
+ ], function(BaseObject, extend, GroupElement, SmartField,MessageToast,JSONModel,AnnotationHelperModel,ObjectPageSectionHandler,VBox,Text,Library,HBox,ColumnElementData,GenericAnnotationHelper,controlHelper,Filter,FilterOperator,Title,SegmentedButton,SegmentedButtonItem,Table,Column,ColumnListItem) {
12
26
  'use strict';
27
+ const EasyFillLayoutMode = Library.EasyFillLayoutMode;
13
28
  /*
14
29
  * This is a handler class for EasyFill.
15
30
  * It gets initialized when the Fiori AI EasyFill is enabled
@@ -26,6 +41,13 @@ sap.ui.define([
26
41
  let oRb;
27
42
  let oAIPopover;
28
43
  let aEditableFields = [];
44
+ let mCollectionUpdates = Object.create(null);
45
+ let mCollectionRowContexts = Object.create(null);
46
+ let mCollectionRowContextsByPath = Object.create(null);
47
+ let mCollectionProperties = Object.create(null);
48
+ let mCollectionEntityTypes = Object.create(null);
49
+ let mStagedRowValues = Object.create(null);
50
+ const MAX_TABLE_PREVIEW_ROWS = 20;
29
51
 
30
52
  async function openEasyFillDialog(oEvent,oContext) {
31
53
  let oEasyFillDialog;
@@ -42,15 +64,21 @@ sap.ui.define([
42
64
 
43
65
  const oData = {
44
66
  isBusy: false,
45
- isUpdatableVisible: false,
46
- isNonUpdatableVisible: false,
67
+ isFormVisible: false,
47
68
  isIllustrationVisible: true,
48
69
  isSaveEnabled: false,
49
70
  stateType: "Initial",
50
71
  feedbackEnabled: true,
51
72
  feedbackPressedUp: false,
52
73
  feedbackPressedDown: false,
53
- isEasyFillButtonEnabled: false
74
+ isEasyFillButtonEnabled: false,
75
+ llmData: {},
76
+ easyFillMode: EasyFillLayoutMode.CondensedMode,
77
+ sections:[],
78
+ isFullScreen: true,
79
+ hasTableUpdates: false,
80
+ hasTableValidationErrors: false,
81
+ tableValidationMessage: ""
54
82
  };
55
83
 
56
84
  let oModel = new JSONModel(oData);
@@ -62,11 +90,32 @@ sap.ui.define([
62
90
  // cannot use OP path to create a list binding as it is a individual entry
63
91
  var sFragmentname = "sap.suite.ui.generic.template.lib.ai.EasyFill.fragments.EasyFillDialog";
64
92
  oTemplateUtils.oCommonUtils.getDialogFragmentAsync(sFragmentname, {
93
+ onSelectionChange: function(oEvent) {
94
+ const sSelectedKey = oEvent.getSource().getSelectedKey();
95
+ const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
96
+ const oEntityType = oTemplateUtils.oCommonUtils.getMetaModelEntityType(oController.getOwnerComponent().getEntitySet());
97
+ easyFillDialogModel.setProperty("/easyFillMode",sSelectedKey);
98
+ const oLLMResult = easyFillDialogModel.getProperty("/llmData");
99
+ const aData = (sSelectedKey === EasyFillLayoutMode.CondensedMode) ? ObjectPageSectionHandler.getSectionsForCondensedView(oLLMResult) : ObjectPageSectionHandler.getSectionsForObjectPageView(oEntityType,oLLMResult,oRb);
100
+ easyFillDialogModel.setProperty("/sections",aData);
101
+ },
65
102
  onFeedbackPress: function() {
66
103
  const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
67
104
  easyFillDialogModel.setProperty("/feedbackEnabled",false);
68
105
  MessageToast.show(oRb.getText("EASYFILL_RESULT_FEEDBACK"));
69
106
  },
107
+ formatSectionTitle: function(sTitle) {
108
+ if (!sTitle) {return "";}
109
+ // Matches {@i18n>SomeKey} or {i18n>SomeKey}
110
+ const oMatch = sTitle.match(/\{@?i18n>([^}]+)\}/);
111
+ if (oMatch) {
112
+ const sKey = oMatch[1];
113
+ const oResourceBundle = oController.getView().getModel("i18n").getResourceBundle();
114
+ return oResourceBundle.getText(sKey);
115
+ }
116
+ // No i18n pattern → return as-is
117
+ return sTitle;
118
+ },
70
119
  formatIllustrationType: function (sState) {
71
120
  switch (sState) {
72
121
  case "Initial":
@@ -110,7 +159,11 @@ sap.ui.define([
110
159
  oObjectPageContext.setProperty(oProp, oTransientObject[oProp]);
111
160
  }
112
161
  }
113
- activateSideEffects();
162
+ // Collection row values are already staged onto OData contexts via the editable New table;
163
+ // clear staged tracking without reverting, then activate side effects.
164
+ mStagedRowValues = Object.create(null);
165
+ //Temporarily deactivating, Yet to be added again
166
+ // activateSideEffects();
114
167
  resetEasyFill(true);
115
168
  oEasyFillDialog?.close();
116
169
  },
@@ -122,51 +175,185 @@ sap.ui.define([
122
175
  resetEasyFill(true);
123
176
  oEasyFillDialog.close();
124
177
  },
125
- onEasyFillSubmitInputToAI : async function (oEvent) {
178
+ formatFieldValue: function(sFieldName,oData) {
179
+ return `{${sFieldName}}`;
180
+ },
181
+ onEasyFillSubmitInputToAI : async function (oEvent) {
126
182
  const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
127
183
  easyFillDialogModel.setProperty("/isBusy",true);
128
184
  let mFieldMapping = getEntitySetMapForLLM();
129
185
  let aiCallResult = await oTemplateUtils.oServices.oFioriAIHandler.fioriaiLib.EasyFill.extractFieldValuesFromText(oController.byId("EasyFillInputTextArea").getValue(), mFieldMapping);
130
- resetEasyFill();
131
186
  aEditableFields = [];
132
187
  easyFillDialogModel.setProperty("/isBusy",false);
133
- formatDateValues(aiCallResult,mFieldMapping);
188
+ formatDateValues(aiCallResult,mFieldMapping);
189
+ const oEntityType = oTemplateUtils.oCommonUtils.getMetaModelEntityType(oController.getOwnerComponent().getEntitySet());
190
+ const sSelectedKey = easyFillDialogModel.getProperty("/easyFillMode") || EasyFillLayoutMode.CondensedMode;
191
+ easyFillDialogModel.setProperty("/easyFillMode",sSelectedKey);
134
192
  if (aiCallResult.success) {
135
- const {updatableFields,nonUpdatableFields} = getUpdatableAndNonUpdatableFields(aiCallResult.data);
193
+ const {simpleFields,collectionFields} = splitAIResultByCollection(aiCallResult.data, mFieldMapping);
194
+ const {updatableFields,nonUpdatableFields} = getUpdatableAndNonUpdatableFields(simpleFields);
136
195
  mUpdatableLookupMap = updatableFields;
137
- if (Object.keys(updatableFields).length + Object.keys(nonUpdatableFields).length === 0) {
196
+ //Setting up Sections for both condensed view and Object page view
197
+ const aData = (sSelectedKey === EasyFillLayoutMode.CondensedMode) ? ObjectPageSectionHandler.getSectionsForCondensedView(simpleFields) : ObjectPageSectionHandler.getSectionsForObjectPageView(oEntityType,simpleFields,oRb);
198
+ resetEasyFill();
199
+ makeTransientContext();
200
+ easyFillDialogModel.setProperty("/sections",aData);
201
+ easyFillDialogModel.setProperty("/llmData",simpleFields);
202
+ //Setting and rendering of SmartTables
203
+ mCollectionUpdates = collectionFields;
204
+ const bHasTableUpdates = Object.keys(mCollectionUpdates).length > 0;
205
+ easyFillDialogModel.setProperty("/hasTableUpdates", bHasTableUpdates);
206
+ const aTableValidationErrors = await validateCollectionUpdatesAgainstValueHelp(mFieldMapping);
207
+ applyTableValidationState(aTableValidationErrors);
208
+ renderCollectionPreviews(mFieldMapping, aTableValidationErrors);
209
+
210
+ if (Object.keys(updatableFields).length + Object.keys(nonUpdatableFields).length === 0 && !bHasTableUpdates) {
138
211
  easyFillDialogModel.setProperty("/stateType","NoEntries");
139
212
  return;
140
213
  }
141
214
  easyFillDialogModel.setProperty("/isIllustrationVisible",false);
142
215
  //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);
216
+ easyFillDialogModel.setProperty("/isFormVisible",Object.keys(updatableFields).length + Object.keys(nonUpdatableFields).length > 0);
217
+
218
+ if (bHasTableUpdates) {
219
+ easyFillDialogModel.setProperty("/isSaveEnabled", aTableValidationErrors.length === 0);
162
220
  }
163
221
  } else {
222
+ applyTableValidationState([]);
164
223
  easyFillDialogModel.setProperty("/stateType","Error");
165
224
  }
166
225
  },
226
+
167
227
  onEasyFillClearAll: function() {
168
228
  resetEasyFill(true);
169
229
  },
230
+
231
+ populateSmartFields: function(sId, aFields, sEasyFillMode) {
232
+ const oObjectPageLayout = oController.byId("EasyFillObjectPageLayout");
233
+ if (!oObjectPageLayout || !Array.isArray(aFields) || aFields.length === 0) {
234
+ return true;
235
+ }
236
+
237
+ const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
238
+
239
+ setTimeout(() => {
240
+ const oLLMData = easyFillDialogModel.getProperty("/llmData");
241
+ let oTargetGroup = null;
242
+
243
+ // sections -> ObjectPageSection
244
+ oObjectPageLayout.getSections().forEach((oSection) => {
245
+ // subSections -> ObjectPageSubSection
246
+ oSection.getSubSections().forEach((oSubSection) => {
247
+ // blocks -> SmartForm
248
+ oSubSection.getBlocks().forEach((oBlock) => {
249
+ if (oBlock.isA("sap.ui.comp.smartform.SmartForm")) {
250
+ // ✅ Search inside Groups, not SmartForm
251
+ oBlock.getGroups().forEach((oGroup) => {
252
+ const oMatchedCustomData = oGroup.getCustomData().find(
253
+ (oData) => oData.getKey() === "id" && oData.getValue() === sId
254
+ );
255
+ if (oMatchedCustomData) {
256
+ oTargetGroup = oGroup;
257
+ }
258
+ });
259
+ }
260
+ });
261
+ });
262
+ });
263
+
264
+ if (!oTargetGroup) {
265
+ return;
266
+ }
267
+
268
+ // Destroy old GroupElements before adding new
269
+ oTargetGroup.destroyGroupElements();
270
+
271
+ aFields.forEach((sKey) => {
272
+ // const bFieldEditable = true;
273
+ const oGroupElement = new GroupElement({
274
+ useHorizontalLayout: false
275
+ });
276
+
277
+ const isEditable = mUpdatableLookupMap && !!mUpdatableLookupMap[sKey];
278
+
279
+ const oSmartField = new SmartField({
280
+ value: "{" + sKey + "}",
281
+ editable: isEditable,
282
+ enabled: isEditable,
283
+ contextEditable: isEditable,
284
+ //Yet to be added, Temporarily disabled
285
+ // change: onSmartFieldChange.bind(this),
286
+ layoutData: new ColumnElementData({
287
+ cellsSmall: 12,
288
+ cellsLarge: 12
289
+ }),
290
+ editableChanged: (oEvent) => {
291
+ if (oEvent.getParameter("editable") !== isEditable) {
292
+ oEvent.getSource().setEditable(isEditable);
293
+ }
294
+ }
295
+ });
296
+
297
+ const oSmartFieldPrev = new SmartField({
298
+ value: "{" + sKey + "}",
299
+ editable: false,
300
+ enabled: false,
301
+ contextEditable: false,
302
+ showLabel: false,
303
+ visible: isEditable,
304
+ layoutData: new ColumnElementData({
305
+ cellsSmall: 9,
306
+ cellsLarge: 10
307
+ }),
308
+ editableChanged: (oEvent) => {
309
+ if (oEvent.getParameter("editable") !== false) {
310
+ oEvent.getSource().setEditable(false);
311
+ }
312
+ }
313
+ });
314
+
315
+
316
+ if (isEditable) {
317
+ oSmartField.setBindingContext(oTransientContextForEasyFill);
318
+ oSmartFieldPrev.setBindingContext(oObjectPageContext);
319
+ // aEditableFields.push(oSmartField);
320
+ oTransientContextForEasyFill.setProperty(sKey, oLLMData[sKey]);
321
+ } else {
322
+ oSmartField.setBindingContext(oObjectPageContext);
323
+ }
324
+ oGroupElement.addElement(oSmartField); // label source
325
+ oGroupElement.addElement( new Text({
326
+ text: "Previously:",
327
+ visible: isEditable,
328
+ layoutData: new ColumnElementData({
329
+ cellsSmall: 3,
330
+ cellsLarge: 2
331
+ })
332
+ }));
333
+ oGroupElement.addElement(oSmartFieldPrev);
334
+ oTargetGroup.addGroupElement(oGroupElement);
335
+ });
336
+
337
+ }, 0);
338
+
339
+ return true;
340
+ },
341
+
342
+ onToggleFullScreen: function() {
343
+ const oEasyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
344
+ const bIsFullScreen = oEasyFillDialogModel.getProperty("/isFullScreen");
345
+ // ✅ Toggle fullscreen state
346
+ oEasyFillDialogModel.setProperty("/isFullScreen", !bIsFullScreen);
347
+ if (bIsFullScreen) {
348
+ oController.byId("inputAreaSplitPane").getLayoutData().setSize("0%");
349
+ oController.byId("reviewAreaSplitPane").getLayoutData().setSize("100%");
350
+ } else {
351
+ oController.byId("inputAreaSplitPane").getLayoutData().setSize("40%");
352
+ oController.byId("reviewAreaSplitPane").getLayoutData().setSize("60%");
353
+ }
354
+ },
355
+
356
+
170
357
  onLinkPress: async function(oEvent) {
171
358
  if (!oAIPopover) {
172
359
  oAIPopover = await getAIPopover();
@@ -179,51 +366,52 @@ sap.ui.define([
179
366
  });
180
367
  }
181
368
 
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
- });
369
+ //Yet to implement, temporarily disabled
370
+ // function activateSideEffects() {
371
+ // //Making a set so that , duplicate field group ids are not passed
372
+ // const aFieldGroupIdSet = new Set();
373
+ // aEditableFields.forEach((oSmartField)=>{
374
+ // //SideEffect would be invoked only for the editable controls inside the SmartField
375
+ // const aEditableInnerFields = oSmartField.getInnerControls().filter((oControl)=>oControl.getEditable());
376
+ // aEditableInnerFields.forEach((oControl)=>{
377
+ // const aControlFieldGroupId = oControl.getFieldGroupIds();
378
+ // if (aControlFieldGroupId.length > 0) {
379
+ // aControlFieldGroupId.forEach((sFieldGroupId)=>{
380
+ // aFieldGroupIdSet.add(sFieldGroupId);
381
+ // });
382
+ // }
383
+ // });
196
384
 
197
- });
385
+ // });
198
386
 
199
- const oView = oController.getView();
200
-
201
- aFieldGroupIdSet.forEach((sFieldGroupId)=>{
202
- const oID = oView.data(sFieldGroupId);
203
-
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
- */
213
-
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
- });
387
+ // const oView = oController.getView();
223
388
 
389
+ // aFieldGroupIdSet.forEach((sFieldGroupId)=>{
390
+ // const oID = oView.data(sFieldGroupId);
391
+
392
+ // /**
393
+ // * Currently, the SmartFields are created using the TransientContext, which means both
394
+ // * "context" and "contextObject" refer to the TransientContext instance.
395
+ // *
396
+ // * However, we need to use the original OP context so that side effects are triggered
397
+ // * on the original OP context when the user saves data from the EasyFill dialog back to OP.
398
+ // *
399
+ // * Therefore, we update the "context" and "contextObject" to reference the original OP context.
400
+ // */
401
+
402
+ // if (oID) {
403
+ // oID["context"] = oObjectPageContext.getPath();
404
+ // oID["contextObject"] = oObjectPageContext;
405
+ // oView.data(sFieldGroupId,oID);
406
+ // }
407
+ // //To make sure that all the fields sideeffect would be triggered
408
+ // const sSideEffectQualifier = oTemplateUtils.oServices.oApplicationController._getSideEffectsQualifier(oID.name);
409
+ // oTemplateUtils.oServices.oApplicationController.registerGroupChange(sSideEffectQualifier);
410
+ // });
224
411
 
225
- oView.triggerValidateFieldGroup([...aFieldGroupIdSet]);
226
- }
412
+
413
+ // oView.triggerValidateFieldGroup([...aFieldGroupIdSet]);
414
+ // }
227
415
 
228
416
  function getAIPopover() {
229
417
  return new Promise(async(resolve,reject) => {
@@ -237,7 +425,7 @@ sap.ui.define([
237
425
  });
238
426
  }
239
427
 
240
- function getEntitySetMapForLLM() {
428
+ function getEntitySetMapForLLM(oLLMResult) {
241
429
  const mPropertyMap = {};
242
430
  const oEntityType = oTemplateUtils.oCommonUtils.getMetaModelEntityType(oController.getOwnerComponent().getEntitySet());
243
431
  oEntityType.property.forEach((oProperty)=>{
@@ -248,6 +436,7 @@ sap.ui.define([
248
436
  };
249
437
  }
250
438
  });
439
+ appendCollectionMapForLLM(mPropertyMap);
251
440
  return mPropertyMap;
252
441
  }
253
442
 
@@ -266,38 +455,66 @@ sap.ui.define([
266
455
  }
267
456
  }
268
457
 
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);
278
- }
279
- }, 0);
458
+ //Yet to be implemented, temporarily disabled
459
+ // function validateSmartForm() {
460
+ // setTimeout(async() => {
461
+ // const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
462
+ // try {
463
+ // const oAIResponseReviewRegionSmartFormForUpdatableFields = oController.byId("EasyFillUpdatebleForm");
464
+ // const aIds = await oAIResponseReviewRegionSmartFormForUpdatableFields.check();
465
+ // const bHasTableValidationErrors = !!easyFillDialogModel.getProperty("/hasTableValidationErrors");
466
+ // easyFillDialogModel.setProperty("/isSaveEnabled",aIds.length === 0 && !bHasTableValidationErrors);
467
+ // } catch (error) {
468
+ // easyFillDialogModel.setProperty("/isSaveEnabled",false);
469
+ // }
470
+ // }, 0);
471
+ // }
472
+
473
+ function applyTableValidationState(aValidationErrors) {
474
+ const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
475
+ if (!aValidationErrors || aValidationErrors.length === 0) {
476
+ easyFillDialogModel.setProperty("/hasTableValidationErrors", false);
477
+ easyFillDialogModel.setProperty("/tableValidationMessage", "");
478
+ return;
479
+ }
480
+ const sSummary = aValidationErrors.slice(0, 3).map(function(oError) {
481
+ return oError.collectionLabel + " / " + oError.rowLabel + " / " + oError.propertyLabel;
482
+ }).join(", ");
483
+ easyFillDialogModel.setProperty("/hasTableValidationErrors", true);
484
+ easyFillDialogModel.setProperty(
485
+ "/tableValidationMessage",
486
+ oRb.getText("EASY_FILL_TABLE_VALIDATION_MESSAGE", [sSummary])
487
+ );
280
488
  }
281
489
 
282
490
  function resetEasyFill(bRemoveTextAreaValue) {
283
491
  const easyFillDialogModel = oController.getView().getModel("easyFillDialogModel");
284
- const oAIResponseReviewRegionSmartFormForNonUpdatableFields = oController.byId("EasyFillNonUpdatebleForm");
285
- const oAIResponseReviewRegionSmartFormForUpdatableFields = oController.byId("EasyFillUpdatebleForm");
286
- oAIResponseReviewRegionSmartFormForUpdatableFields.destroyGroups();
287
- oAIResponseReviewRegionSmartFormForNonUpdatableFields.destroyGroups();
492
+ const oTablePreviewContainer = oController.byId("EasyFillTablePreviewContainer");
493
+ if (oTablePreviewContainer) {
494
+ oTablePreviewContainer.destroyItems();
495
+ }
496
+ revertStagedCollectionUpdates();
288
497
  resetTransientContext();
289
- easyFillDialogModel.setProperty("/isUpdatableVisible",false);
290
- easyFillDialogModel.setProperty("/isNonUpdatableVisible",false);
498
+ easyFillDialogModel.setProperty("/isFormVisible",false);
291
499
  easyFillDialogModel.setProperty("/isIllustrationVisible",true);
292
500
  easyFillDialogModel.setProperty("/isSaveEnabled",false);
293
501
  easyFillDialogModel.setProperty("/stateType","Initial");
294
502
  easyFillDialogModel.setProperty("/feedbackEnabled",true);
295
503
  easyFillDialogModel.setProperty("/feedbackPressedUp",false);
296
504
  easyFillDialogModel.setProperty("/feedbackPressedDown",false);
505
+ easyFillDialogModel.setProperty("/isFullScreen",true);
506
+ easyFillDialogModel.setProperty("/hasTableUpdates",false);
507
+ easyFillDialogModel.setProperty("/hasTableValidationErrors",false);
508
+ easyFillDialogModel.setProperty("/tableValidationMessage","");
509
+ easyFillDialogModel.setProperty("/easyFillMode",EasyFillLayoutMode.CondensedMode);
510
+ mCollectionUpdates = Object.create(null);
297
511
  if (bRemoveTextAreaValue) {
298
512
  oController.byId("EasyFillInputTextArea").setValue("");
299
513
  easyFillDialogModel.setProperty("/isEasyFillButtonEnabled",false);
300
514
  }
515
+ easyFillDialogModel.setProperty("/llmData",{});
516
+ easyFillDialogModel.setProperty("/sections",[]);
517
+
301
518
  }
302
519
 
303
520
  function getUpdatableAndNonUpdatableFields(oAiCallResult) {
@@ -307,6 +524,10 @@ sap.ui.define([
307
524
 
308
525
  Object.keys(oAiCallResult).forEach((sKey)=>{
309
526
  const oProperty = oEntityType.property.find((oProperty)=>oProperty.name === sKey);
527
+ if (!oProperty) {
528
+ nonUpdatableFields[sKey] = oAiCallResult[sKey];
529
+ return;
530
+ }
310
531
  if (isEditable(oProperty)) {
311
532
  updatableFields[sKey] = oAiCallResult[sKey];
312
533
  } else {
@@ -337,6 +558,13 @@ sap.ui.define([
337
558
  //Since "com.sap.vocabularies.Common.v1.FieldControl" is an V4 annotation, it would be given the first priority
338
559
 
339
560
  function isEditable(oProperty) {
561
+ return isEditableByContextObject(oProperty, oObjectPageContext && oObjectPageContext.getObject && oObjectPageContext.getObject());
562
+ }
563
+
564
+ function isEditableByContextObject(oProperty, oContextObject) {
565
+ if (!oProperty) {
566
+ return false;
567
+ }
340
568
 
341
569
  //Check for sap:updatable
342
570
  const sUpdatable = oProperty["sap:updatable"];
@@ -357,7 +585,7 @@ sap.ui.define([
357
585
  const sFieldControl = oProperty["sap:field-control"];
358
586
 
359
587
  if (sFieldControl) {
360
- const iFieldControlValue = oObjectPageContext.getObject()[sFieldControl];
588
+ const iFieldControlValue = oContextObject && oContextObject[sFieldControl];
361
589
  return iFieldControlValue === 1 ? false : true;
362
590
  }
363
591
 
@@ -365,6 +593,535 @@ sap.ui.define([
365
593
  return true;
366
594
  }
367
595
 
596
+ function splitAIResultByCollection(oAiData, mFieldMapping) {
597
+ var oSplitResult = {
598
+ simpleFields: {},
599
+ collectionFields: {}
600
+ };
601
+ Object.keys(oAiData || {}).forEach(function(sFieldName) {
602
+ var oFieldMeta = mFieldMapping[sFieldName];
603
+ var vFieldValue = oAiData[sFieldName];
604
+ var aCollectionRows = null;
605
+ if (Array.isArray(vFieldValue)) {
606
+ aCollectionRows = vFieldValue;
607
+ } else if (vFieldValue && Array.isArray(vFieldValue.rows)) {
608
+ aCollectionRows = vFieldValue.rows;
609
+ }
610
+ if (oFieldMeta && oFieldMeta.isCollection === true && aCollectionRows) {
611
+ var aRowUpdates = aCollectionRows.filter(function(oRow) {
612
+ return oRow && typeof oRow === "object" && (typeof oRow._contextPath === "string" || typeof oRow._rowIndex === "number");
613
+ });
614
+
615
+ // For current development, we are only supporting one SmartTable
616
+ // in future if we support multiple SmartTable in the same OP, then we can change the structure of collectionFields to support multiple tables
617
+ const {isValid} = isValidSmartTable(oFieldMeta.entitySet);
618
+ if (aRowUpdates.length > 0 && Object.keys(oSplitResult.collectionFields).length === 0 && isValid) {
619
+ oSplitResult.collectionFields[sFieldName] = aRowUpdates;
620
+ }
621
+ } else {
622
+ oSplitResult.simpleFields[sFieldName] = vFieldValue;
623
+ }
624
+ });
625
+ return oSplitResult;
626
+ }
627
+
628
+ function isValidSmartTable(sEntitySet) {
629
+ var aSmartTables = getObjectPageSmartTables();
630
+ const oSmartTable = aSmartTables.find(function(oSmartTable) {
631
+ return oSmartTable.getEntitySet() === sEntitySet;
632
+ });
633
+ return {
634
+ isValid: !!oSmartTable,
635
+ smartTable: oSmartTable
636
+ };
637
+ }
638
+
639
+ function getObjectPageSmartTables() {
640
+ if (!oObjectPage || !oObjectPage.findAggregatedObjects) {
641
+ return [];
642
+ }
643
+ //Currently we are looping all the tables in the ObjectPage, but it might contain custom smarttables
644
+ //In future we have to read the table data from annotations/manifest so that we dont confuse with custom smart tables
645
+ return oObjectPage.findAggregatedObjects(true, function(oControl) {
646
+ const isSmartTable = controlHelper.isSmartTable(oControl);
647
+ //Currently restricting it to Responsive Table and UITable, in future we have to extend it for other table types as well
648
+ return isSmartTable && (oControl.getTable().isA("sap.m.Table") || oControl.getTable().isA("sap.ui.table.Table"));
649
+ }) || [];
650
+ }
651
+
652
+ function appendCollectionMapForLLM(mPropertyMap) {
653
+ mCollectionRowContexts = Object.create(null);
654
+ mCollectionRowContextsByPath = Object.create(null);
655
+ mCollectionProperties = Object.create(null);
656
+ mCollectionEntityTypes = Object.create(null);
657
+ var aSmartTables = getObjectPageSmartTables();
658
+ if (!aSmartTables.length) {
659
+ return;
660
+ }
661
+ var oMetaModel = oObjectPageModel && oObjectPageModel.getMetaModel();
662
+ aSmartTables.forEach(function(oSmartTable) {
663
+ var oHandler = oTemplateUtils.oServices.oPresentationControlHandlerFactory.getPresentationControlHandler(oSmartTable);
664
+ if (!oHandler) {
665
+ return;
666
+ }
667
+ var sNavProperty = extractNavigationPropertyName(oHandler.getBindingPath());
668
+ if (!sNavProperty) {
669
+ return;
670
+ }
671
+ var aVisibleProps = (oHandler.findVisibleColumnProperties && oHandler.findVisibleColumnProperties()) || [];
672
+ if (!aVisibleProps.length) {
673
+ return;
674
+ }
675
+ var aRowContexts = (oHandler.getCurrentContexts && oHandler.getCurrentContexts()) || [];
676
+ var sEntitySetName = oSmartTable.getEntitySet();
677
+ var oEntitySet = oMetaModel.getODataEntitySet(oSmartTable.getEntitySet());
678
+ var oEntityType = oEntitySet && oMetaModel.getODataEntityType(oEntitySet.entityType);
679
+ if (!oEntityType || !oEntityType.property) {
680
+ return;
681
+ }
682
+ var mPropertyByName = Object.create(null);
683
+ oEntityType.property.forEach(function(oProperty) {
684
+ mPropertyByName[oProperty.name] = oProperty;
685
+ });
686
+
687
+ var oItemProperties = {};
688
+ aVisibleProps.forEach(function(sPropName) {
689
+ var oProperty = mPropertyByName[sPropName];
690
+ if (!oProperty) {
691
+ return;
692
+ }
693
+ oItemProperties[sPropName] = {
694
+ description: getLabel(oProperty) || sPropName,
695
+ dataType: oProperty.type
696
+ };
697
+ });
698
+
699
+ if (!Object.keys(oItemProperties).length) {
700
+ return;
701
+ }
702
+
703
+ var aCurrentItems = [];
704
+ var mRowsByPath = Object.create(null);
705
+ aRowContexts.forEach(function(oContext, iIndex) {
706
+ if (!oContext || !oContext.getObject) {
707
+ return;
708
+ }
709
+ var sContextPath = oContext.getPath && oContext.getPath();
710
+ var oRowData = {_rowIndex: iIndex};
711
+ if (typeof sContextPath === "string") {
712
+ oRowData._contextPath = sContextPath;
713
+ mRowsByPath[sContextPath] = {
714
+ context: oContext,
715
+ rowIndex: iIndex
716
+ };
717
+ }
718
+ Object.keys(oItemProperties).forEach(function(sPropName) {
719
+ var vValue = oContext.getProperty(sPropName);
720
+ if (typeof vValue !== "object") {
721
+ oRowData[sPropName] = vValue;
722
+ }
723
+ });
724
+ aCurrentItems.push(oRowData);
725
+ });
726
+
727
+ mCollectionRowContexts[sNavProperty] = aRowContexts;
728
+ mCollectionRowContextsByPath[sNavProperty] = mRowsByPath;
729
+ mCollectionProperties[sNavProperty] = mPropertyByName;
730
+ mCollectionEntityTypes[sNavProperty] = oEntityType;
731
+ mPropertyMap[sNavProperty] = {
732
+ description: typeof oSmartTable.getHeader() === "string" ? oSmartTable.getHeader() : sNavProperty,
733
+ dataType: "Collection",
734
+ isCollection: true,
735
+ itemProperties: oItemProperties,
736
+ currentItems: aCurrentItems,
737
+ entitySet: sEntitySetName,
738
+ section: typeof oSmartTable.getHeader() === "string" ? oSmartTable.getHeader() : sNavProperty
739
+ };
740
+ });
741
+ }
742
+
743
+ function extractNavigationPropertyName(sBindingPath) {
744
+ if (!sBindingPath || typeof sBindingPath !== "string") {
745
+ return null;
746
+ }
747
+ var aParts = sBindingPath.split("/").filter(Boolean);
748
+ return aParts.length ? aParts[aParts.length - 1] : null;
749
+ }
750
+
751
+ function resolveCollectionRowContext(sCollectionName, oRowUpdate) {
752
+ var mByPath = mCollectionRowContextsByPath[sCollectionName] || Object.create(null);
753
+ var sContextPath = oRowUpdate && oRowUpdate._contextPath;
754
+ if (typeof sContextPath === "string" && mByPath[sContextPath]) {
755
+ return mByPath[sContextPath];
756
+ }
757
+ var iRowIndex = oRowUpdate && oRowUpdate._rowIndex;
758
+ var aRowContexts = mCollectionRowContexts[sCollectionName] || [];
759
+ if (typeof iRowIndex === "number" && aRowContexts[iRowIndex]) {
760
+ return {
761
+ context: aRowContexts[iRowIndex],
762
+ rowIndex: iRowIndex
763
+ };
764
+ }
765
+ return null;
766
+ }
767
+
768
+ function readValueListByEquality(sCollectionPath, sValueListProperty, vValue) {
769
+ return new Promise(function(resolve) {
770
+ oObjectPageModel.read("/" + sCollectionPath, {
771
+ filters: [
772
+ new Filter({
773
+ path: sValueListProperty,
774
+ operator: FilterOperator.EQ,
775
+ value1: vValue
776
+ })
777
+ ],
778
+ success: function(oResponse) {
779
+ resolve(!!(oResponse && Array.isArray(oResponse.results) && oResponse.results.length > 0));
780
+ },
781
+ error: function() {
782
+ resolve(true);
783
+ }
784
+ });
785
+ });
786
+ }
787
+
788
+ async function validateCollectionUpdatesAgainstValueHelp(mFieldMapping) {
789
+ const oMetaModel = oObjectPageModel && oObjectPageModel.getMetaModel();
790
+ if (!oMetaModel) {
791
+ return [];
792
+ }
793
+ const aValidationErrors = [];
794
+ const aCollectionNames = Object.keys(mCollectionUpdates || {});
795
+ for (const sCollectionName of aCollectionNames) {
796
+ const aRowUpdates = mCollectionUpdates[sCollectionName] || [];
797
+ const mCollectionPropertyMap = mCollectionProperties[sCollectionName] || Object.create(null);
798
+ const oCollectionEntityType = mCollectionEntityTypes[sCollectionName];
799
+ const sCollectionLabel = (mFieldMapping[sCollectionName] && mFieldMapping[sCollectionName].description) || sCollectionName;
800
+ if (!oCollectionEntityType) {
801
+ continue;
802
+ }
803
+ for (const oRowUpdate of aRowUpdates) {
804
+ const oResolvedRow = resolveCollectionRowContext(sCollectionName, oRowUpdate);
805
+ if (!oResolvedRow || !oResolvedRow.context) {
806
+ continue;
807
+ }
808
+ const oRowContext = oResolvedRow.context;
809
+ const oRowObject = oRowContext.getObject && oRowContext.getObject();
810
+ const sRowLabel = oRb.getText("EASY_FILL_TABLE_ROW_LABEL", [String((oResolvedRow.rowIndex || 0) + 1)]);
811
+ for (const sPropertyName of Object.keys(oRowUpdate)) {
812
+ if (sPropertyName === "_rowIndex" || sPropertyName === "_contextPath") {
813
+ continue;
814
+ }
815
+ const oPropertyMeta = mCollectionPropertyMap[sPropertyName];
816
+ if (!oPropertyMeta || !isEditableByContextObject(oPropertyMeta, oRowObject)) {
817
+ continue;
818
+ }
819
+ if (!GenericAnnotationHelper.isValueHelpTableAvailable(oPropertyMeta)) {
820
+ continue;
821
+ }
822
+ const vUpdatedValue = oRowUpdate[sPropertyName];
823
+ if (vUpdatedValue === null || vUpdatedValue === undefined || typeof vUpdatedValue === "object") {
824
+ continue;
825
+ }
826
+ try {
827
+ const sPropertyPath = oMetaModel.getODataProperty(oCollectionEntityType, sPropertyName, true);
828
+ if (!sPropertyPath) {
829
+ continue;
830
+ }
831
+ const oPropertyContext = oMetaModel.createBindingContext(sPropertyPath);
832
+ const oValueLists = await oMetaModel.getODataValueLists(oPropertyContext);
833
+ const oDefaultValueList = oValueLists && oValueLists[""];
834
+ if (!oDefaultValueList || !oDefaultValueList.CollectionPath || !oDefaultValueList.CollectionPath.String) {
835
+ continue;
836
+ }
837
+ let sValueListProperty = sPropertyName;
838
+ if (Array.isArray(oDefaultValueList.Parameters)) {
839
+ const oParameter = oDefaultValueList.Parameters.find(function(oParam) {
840
+ return (
841
+ oParam.RecordType === "com.sap.vocabularies.Common.v1.ValueListParameterInOut" &&
842
+ oParam.LocalDataProperty &&
843
+ oParam.LocalDataProperty.PropertyPath === sPropertyName
844
+ );
845
+ });
846
+ if (oParameter && oParameter.ValueListProperty && oParameter.ValueListProperty.String) {
847
+ sValueListProperty = oParameter.ValueListProperty.String;
848
+ }
849
+ }
850
+ const bValueFound = await readValueListByEquality(
851
+ oDefaultValueList.CollectionPath.String,
852
+ sValueListProperty,
853
+ vUpdatedValue
854
+ );
855
+ if (!bValueFound) {
856
+ aValidationErrors.push({
857
+ collectionName: sCollectionName,
858
+ collectionLabel: sCollectionLabel,
859
+ rowLabel: sRowLabel,
860
+ rowIndex: oResolvedRow.rowIndex,
861
+ rowPath: oRowContext.getPath && oRowContext.getPath(),
862
+ propertyName: sPropertyName,
863
+ propertyLabel: getLabel(oPropertyMeta) || sPropertyName
864
+ });
865
+ }
866
+ } catch (e) {
867
+ // If metadata/value list cannot be resolved, we keep current behavior and do not block save.
868
+ }
869
+ }
870
+ }
871
+ }
872
+ return aValidationErrors;
873
+ }
874
+
875
+ function stringifyCellValue(vValue) {
876
+ if (vValue === null || vValue === undefined) {
877
+ return "";
878
+ }
879
+ if (vValue instanceof Date) {
880
+ return vValue.toISOString();
881
+ }
882
+ return String(vValue);
883
+ }
884
+
885
+ function createPreviewTable(aPropertyNames, oItemProperties, aRows, fnCellFormatter) {
886
+ var aColumns = aPropertyNames.map(function(sPropertyName) {
887
+ return new Column({
888
+ header: new Text({ text: (oItemProperties[sPropertyName] && oItemProperties[sPropertyName].description) || sPropertyName })
889
+ });
890
+ });
891
+
892
+ var aItems = aRows.map(function(oRow) {
893
+ return new ColumnListItem({
894
+ cells: aPropertyNames.map(function(sPropertyName) {
895
+ var sText = fnCellFormatter
896
+ ? fnCellFormatter(oRow, sPropertyName, stringifyCellValue(oRow[sPropertyName]))
897
+ : stringifyCellValue(oRow[sPropertyName]);
898
+ return new Text({ text: sText });
899
+ })
900
+ });
901
+ });
902
+
903
+ return new Table({
904
+ columns: aColumns,
905
+ items: aItems,
906
+ fixedLayout: false,
907
+ autoPopinMode: true
908
+ }).addStyleClass("sapSmartTemplatesObjectPageEasyFillTablePreview");
909
+ }
910
+
911
+ function stageCollectionUpdatesForPreview() {
912
+ mStagedRowValues = Object.create(null);
913
+ Object.keys(mCollectionUpdates).forEach(function(sCollectionName) {
914
+ var mCollectionPropertyMap = mCollectionProperties[sCollectionName] || Object.create(null);
915
+ var aRowUpdates = mCollectionUpdates[sCollectionName] || [];
916
+ aRowUpdates.forEach(function(oRowUpdate) {
917
+ var oResolved = resolveCollectionRowContext(sCollectionName, oRowUpdate);
918
+ if (!oResolved || !oResolved.context) { return; }
919
+ var oContext = oResolved.context;
920
+ var sPath = oContext.getPath && oContext.getPath();
921
+ if (!sPath) { return; }
922
+ if (!mStagedRowValues[sPath]) {
923
+ mStagedRowValues[sPath] = { context: oContext, originalValues: {} };
924
+ }
925
+ var oRowObject = oContext.getObject && oContext.getObject();
926
+ Object.keys(oRowUpdate).forEach(function(sPropName) {
927
+ if (sPropName === "_rowIndex" || sPropName === "_contextPath") { return; }
928
+ var oPropertyMeta = mCollectionPropertyMap[sPropName];
929
+ if (!isEditableByContextObject(oPropertyMeta, oRowObject)) { return; }
930
+ if (!Object.prototype.hasOwnProperty.call(mStagedRowValues[sPath].originalValues, sPropName)) {
931
+ mStagedRowValues[sPath].originalValues[sPropName] = oContext.getProperty(sPropName);
932
+ }
933
+ oContext.setProperty(sPropName, oRowUpdate[sPropName]);
934
+ });
935
+ });
936
+ });
937
+ }
938
+
939
+ function revertStagedCollectionUpdates() {
940
+ Object.keys(mStagedRowValues).forEach(function(sPath) {
941
+ var oEntry = mStagedRowValues[sPath];
942
+ var oContext = oEntry.context;
943
+ Object.keys(oEntry.originalValues).forEach(function(sPropName) {
944
+ oContext.setProperty(sPropName, oEntry.originalValues[sPropName]);
945
+ });
946
+ });
947
+ mStagedRowValues = Object.create(null);
948
+ }
949
+
950
+ function buildCollectionPreviewRow(aPropertyNames, oResolvedRow, oRowUpdate, bUseUpdatedValues) {
951
+ var oPreviewRow = {};
952
+ var oContext = oResolvedRow && oResolvedRow.context;
953
+ var sPath = oContext && oContext.getPath && oContext.getPath();
954
+ var oStagedEntry = sPath && mStagedRowValues[sPath];
955
+ aPropertyNames.forEach(function(sPropertyName) {
956
+ if (bUseUpdatedValues && oRowUpdate && Object.prototype.hasOwnProperty.call(oRowUpdate, sPropertyName)) {
957
+ oPreviewRow[sPropertyName] = oRowUpdate[sPropertyName];
958
+ return;
959
+ }
960
+ if (!bUseUpdatedValues && oStagedEntry && Object.prototype.hasOwnProperty.call(oStagedEntry.originalValues, sPropertyName)) {
961
+ oPreviewRow[sPropertyName] = oStagedEntry.originalValues[sPropertyName];
962
+ return;
963
+ }
964
+ oPreviewRow[sPropertyName] = oContext ? oContext.getProperty(sPropertyName) : "";
965
+ });
966
+ return oPreviewRow;
967
+ }
968
+
969
+ function getCollectionRowIdentity(oResolvedRow, oRowUpdate, iFallbackIndex) {
970
+ if (oResolvedRow && oResolvedRow.context && oResolvedRow.context.getPath) {
971
+ return oResolvedRow.context.getPath();
972
+ }
973
+ if (oRowUpdate && typeof oRowUpdate._contextPath === "string") {
974
+ return oRowUpdate._contextPath;
975
+ }
976
+ if (oRowUpdate && typeof oRowUpdate._rowIndex === "number") {
977
+ return "index:" + String(oRowUpdate._rowIndex);
978
+ }
979
+ return "row:" + String(iFallbackIndex);
980
+ }
981
+
982
+ function createEditableNewTable(aPropertyNames, oItemProperties, aPreviewRows, sCollectionName) {
983
+ var aColumns = aPropertyNames.map(function(sPropName) {
984
+ return new Column({
985
+ header: new Text({ text: (oItemProperties[sPropName] && oItemProperties[sPropName].description) || sPropName })
986
+ });
987
+ });
988
+ var mCollectionPropertyMap = mCollectionProperties[sCollectionName] || Object.create(null);
989
+ var aItems = aPreviewRows.map(function(oPreviewRow) {
990
+ var oContext = oPreviewRow.context;
991
+ var oRowObject = oContext && oContext.getObject && oContext.getObject();
992
+ var aCells = aPropertyNames.map(function(sPropName) {
993
+ if (!oContext) {
994
+ return new Text({ text: stringifyCellValue(oPreviewRow.newValues[sPropName]) });
995
+ }
996
+ var oPropertyMeta = mCollectionPropertyMap[sPropName];
997
+ var bEditable = isEditableByContextObject(oPropertyMeta, oRowObject);
998
+ var oSmartField = new SmartField({
999
+ value: "{" + sPropName + "}",
1000
+ editable: bEditable,
1001
+ enabled: bEditable,
1002
+ contextEditable: bEditable,
1003
+ // change: onSmartFieldChange.bind(this),
1004
+ editableChanged: function(oEvent) {
1005
+ // Keep table SmartField editability deterministic in preview mode.
1006
+ if (oEvent.getParameter("editable") !== bEditable) {
1007
+ oEvent.getSource().setEditable(bEditable);
1008
+ }
1009
+ }
1010
+ });
1011
+
1012
+ if (bEditable) {
1013
+ aEditableFields.push(oSmartField);
1014
+ }
1015
+ return oSmartField;
1016
+ });
1017
+ var oItem = new ColumnListItem({ cells: aCells });
1018
+ if (oContext) {
1019
+ oItem.setBindingContext(oContext);
1020
+ }
1021
+ return oItem;
1022
+ });
1023
+ return new Table({
1024
+ columns: aColumns,
1025
+ items: aItems,
1026
+ fixedLayout: false,
1027
+ autoPopinMode: true
1028
+ }).addStyleClass("sapSmartTemplatesObjectPageEasyFillTablePreview");
1029
+ }
1030
+
1031
+ function renderCollectionPreviews(mFieldMapping, aTableValidationErrors) {
1032
+ var oTablePreviewContainer = oController.byId("EasyFillTablePreviewContainer");
1033
+ if (!oTablePreviewContainer) {
1034
+ return;
1035
+ }
1036
+ oTablePreviewContainer.destroyItems();
1037
+ // Stage LLM values onto OData row contexts; saves originals for revert on cancel
1038
+ stageCollectionUpdatesForPreview();
1039
+ var mInvalidCellByPath = Object.create(null);
1040
+ (aTableValidationErrors || []).forEach(function(oError) {
1041
+ if (!oError || !oError.rowPath) {
1042
+ return;
1043
+ }
1044
+ mInvalidCellByPath[oError.rowPath + "|" + oError.propertyName] = true;
1045
+ });
1046
+
1047
+ Object.keys(mCollectionUpdates).forEach(function(sCollectionName) {
1048
+ var oCollectionMeta = mFieldMapping[sCollectionName];
1049
+ if (!oCollectionMeta || !oCollectionMeta.itemProperties) {
1050
+ return;
1051
+ }
1052
+ var aRowUpdates = mCollectionUpdates[sCollectionName] || [];
1053
+ var aPropertyNames = Object.keys(oCollectionMeta.itemProperties || {});
1054
+ if (!aPropertyNames.length) {
1055
+ return;
1056
+ }
1057
+ var mUpdatesByIdentity = Object.create(null);
1058
+ aRowUpdates.forEach(function(oRowUpdate, iUpdateIndex) {
1059
+ var oResolvedUpdate = resolveCollectionRowContext(sCollectionName, oRowUpdate);
1060
+ mUpdatesByIdentity[getCollectionRowIdentity(oResolvedUpdate, oRowUpdate, iUpdateIndex)] = oRowUpdate;
1061
+ });
1062
+ var aPreviewRows = [];
1063
+ var aCollectionRowContexts = mCollectionRowContexts[sCollectionName] || [];
1064
+ aCollectionRowContexts.forEach(function(oContext, iRowIndex) {
1065
+ var oResolved = {
1066
+ context: oContext,
1067
+ rowIndex: iRowIndex
1068
+ };
1069
+ var sIdentity = getCollectionRowIdentity(oResolved, null, iRowIndex);
1070
+ var oRowUpdate = mUpdatesByIdentity[sIdentity];
1071
+ aPreviewRows.push({
1072
+ context: oContext,
1073
+ rowIndex: iRowIndex,
1074
+ update: oRowUpdate,
1075
+ previousValues: buildCollectionPreviewRow(aPropertyNames, oResolved, oRowUpdate, false),
1076
+ newValues: buildCollectionPreviewRow(aPropertyNames, oResolved, oRowUpdate, true)
1077
+ });
1078
+ });
1079
+ aPreviewRows = aPreviewRows.slice(0, MAX_TABLE_PREVIEW_ROWS);
1080
+
1081
+ var aPreviousRows = aPreviewRows.map(function(oPreviewRow) {
1082
+ return oPreviewRow.previousValues;
1083
+ });
1084
+
1085
+ if (!aPreviewRows.length) {
1086
+ return;
1087
+ }
1088
+
1089
+ var oPreviousTable = createPreviewTable(aPropertyNames, oCollectionMeta.itemProperties, aPreviousRows);
1090
+ var oNewTable = createEditableNewTable(aPropertyNames, oCollectionMeta.itemProperties, aPreviewRows, sCollectionName);
1091
+ oPreviousTable.setVisible(false);
1092
+
1093
+ var oSectionTitle = new Title({
1094
+ level: "H5",
1095
+ text: (oCollectionMeta.description || sCollectionName) + " (" + aPreviewRows.length + ")"
1096
+ });
1097
+
1098
+ var oSegmentedButton = new SegmentedButton({
1099
+ selectedKey: "new",
1100
+ width:"auto",
1101
+ items: [
1102
+ new SegmentedButtonItem({ key: "previous", text: oRb.getText("EASY_FILL_TABLE_VIEW_PREVIOUS"), width:"auto" }),
1103
+ new SegmentedButtonItem({ key: "new", text: oRb.getText("EASY_FILL_TABLE_VIEW_NEW"), width:"auto" })
1104
+ ],
1105
+ selectionChange: function() {
1106
+ var sKey = oSegmentedButton.getSelectedKey();
1107
+ oPreviousTable.setVisible(sKey === "previous");
1108
+ oNewTable.setVisible(sKey === "new");
1109
+ }
1110
+ });
1111
+
1112
+ var oHeader = new HBox({
1113
+ justifyContent: "SpaceBetween",
1114
+ items: [oSectionTitle, oSegmentedButton]
1115
+ }).addStyleClass("sapUiSmallMarginTop");
1116
+
1117
+ var oSection = new VBox({
1118
+ items: [oHeader, oPreviousTable, oNewTable]
1119
+ }).addStyleClass("sapSmartTemplatesObjectPageEasyFillTableSection");
1120
+
1121
+ oTablePreviewContainer.addItem(oSection);
1122
+ });
1123
+ }
1124
+
368
1125
  function isVisible(oProperty) {
369
1126
 
370
1127
  //Check for "com.sap.vocabularies.Common.v1.FieldControl"
@@ -416,45 +1173,11 @@ sap.ui.define([
416
1173
  });
417
1174
  }
418
1175
 
419
- function onSmartFieldChange() {
420
- validateSmartForm();
421
- }
422
-
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
- });
1176
+ //Yet to implement, temporarily disabled
1177
+ // function onSmartFieldChange() {
1178
+ // validateSmartForm();
1179
+ // }
427
1180
 
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
- }
458
1181
 
459
1182
  return {
460
1183
  onEasyFillButtonClick: function(oEvent) {