@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.
- package/package.json +1 -1
- package/src/sap/suite/ui/generic/template/.library +1 -1
- package/src/sap/suite/ui/generic/template/AnalyticalListPage/controller/ControllerImplementation.js +5 -3
- package/src/sap/suite/ui/generic/template/AnalyticalListPage/i18n/i18n_bg.properties +3 -3
- package/src/sap/suite/ui/generic/template/AnalyticalListPage/i18n/i18n_da.properties +3 -3
- package/src/sap/suite/ui/generic/template/AnalyticalListPage/i18n/i18n_fr_CA.properties +2 -2
- package/src/sap/suite/ui/generic/template/AnalyticalListPage/i18n/i18n_id.properties +2 -2
- package/src/sap/suite/ui/generic/template/AnalyticalListPage/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/Canvas/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/ListReport/controller/ControllerImplementation.js +32 -3
- package/src/sap/suite/ui/generic/template/ListReport/i18n/i18n_fr.properties +1 -1
- package/src/sap/suite/ui/generic/template/ListReport/i18n/i18n_id.properties +1 -1
- package/src/sap/suite/ui/generic/template/ListReport/i18n/i18n_uk.properties +1 -1
- package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/ObjectPage/Component.js +4 -0
- package/src/sap/suite/ui/generic/template/ObjectPage/controller/ControllerImplementation.js +57 -25
- package/src/sap/suite/ui/generic/template/ObjectPage/i18n/i18n.properties +6 -0
- package/src/sap/suite/ui/generic/template/ObjectPage/i18n/i18n_en_US_saprigi.properties +4 -0
- package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +6 -1
- package/src/sap/suite/ui/generic/template/ObjectPage/templateSpecificPreparationHelper.js +35 -19
- package/src/sap/suite/ui/generic/template/ObjectPage/view/fragments/Actions.fragment.xml +13 -13
- package/src/sap/suite/ui/generic/template/ObjectPage/view/fragments/Footer.fragment.xml +103 -42
- package/src/sap/suite/ui/generic/template/QuickCreate/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/QuickView/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/fragments/EasyFilter.fragment.xml +3 -0
- package/src/sap/suite/ui/generic/template/genericUtilities/controlHelper.js +30 -29
- package/src/sap/suite/ui/generic/template/genericUtilities/controlStateWrapperFactory/SmartFilterBarWrapper.js +15 -0
- package/src/sap/suite/ui/generic/template/lib/AppComponent.js +1 -1
- package/src/sap/suite/ui/generic/template/lib/CRUDHelper.js +93 -55
- package/src/sap/suite/ui/generic/template/lib/CRUDManager.js +7 -0
- package/src/sap/suite/ui/generic/template/lib/CommonEventHandlers.js +76 -19
- package/src/sap/suite/ui/generic/template/lib/CommonUtils.js +4 -1
- package/src/sap/suite/ui/generic/template/lib/ComponentUtils.js +17 -7
- package/src/sap/suite/ui/generic/template/lib/StableIdDefinition.js +35 -34
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillAIOrchestrator.js +185 -0
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillApplyHandler.js +476 -0
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillDialogController.js +311 -0
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFieldCollector.js +669 -0
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFormRenderer.js +217 -0
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillHandler.js +348 -422
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillTableRenderer.js +491 -0
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillDialog.fragment.xml +142 -72
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterBarHandler.js +409 -22
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n.properties +32 -8
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ar.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_bg.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ca.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cnr.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cs.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cy.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_da.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_de.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_el.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_GB.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_US_saprigi.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es_MX.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_et.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fi.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr.properties +15 -1
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr_CA.properties +15 -1
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hi.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hr.properties +15 -1
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hu.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_id.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_it.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_iw.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ja.properties +20 -6
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_kk.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ko.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lt.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lv.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_mk.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ms.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_nl.properties +15 -1
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_no.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pl.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt_PT.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ro.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ru.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sh.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sk.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sl.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sr.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sv.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_th.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_tr.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_uk.properties +17 -3
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_vi.properties +14 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_CN.properties +20 -6
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_TW.properties +20 -6
- package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +1 -1
- package/src/sap/suite/ui/generic/template/library.js +25 -2
- package/src/sap/suite/ui/generic/template/themes/base/ObjectPage.less +22 -3
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillNonUpdatableSmartForm.fragment.xml +0 -18
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillUpdatebleSmartForm.fragment.xml +0 -15
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
sap.ui.define([
|
|
2
|
+
"sap/ui/comp/smartfield/SmartField",
|
|
3
|
+
"sap/m/Text",
|
|
4
|
+
"sap/m/Title",
|
|
5
|
+
"sap/m/Table",
|
|
6
|
+
"sap/m/Column",
|
|
7
|
+
"sap/m/ColumnListItem",
|
|
8
|
+
"sap/m/VBox",
|
|
9
|
+
"sap/m/HBox",
|
|
10
|
+
"sap/m/SegmentedButton",
|
|
11
|
+
"sap/m/SegmentedButtonItem",
|
|
12
|
+
"sap/suite/ui/generic/template/genericUtilities/FeLogger",
|
|
13
|
+
"sap/suite/ui/generic/template/genericUtilities/FeError"
|
|
14
|
+
], function(SmartField, Text, Title, Table, Column, ColumnListItem, VBox, HBox, SegmentedButton, SegmentedButtonItem, FeLogger, FeError) {
|
|
15
|
+
"use strict";
|
|
16
|
+
|
|
17
|
+
var sClassName = "lib.ai.EasyFill.EasyFillTableRenderer";
|
|
18
|
+
var oLogger = new FeLogger(sClassName).getLogger();
|
|
19
|
+
var iMaxPreviewRows = 20;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* EasyFillTableRenderer
|
|
23
|
+
*
|
|
24
|
+
* Responsible for rendering the SmartTable collection preview in the EasyFill dialog.
|
|
25
|
+
* For each collection (navigation property) with LLM-suggested row updates, this module:
|
|
26
|
+
*
|
|
27
|
+
* 1. Creates transient OData row contexts for preview rendering.
|
|
28
|
+
* 2. Creates a "Previous Values" read-only table and a "New Values" editable SmartField table.
|
|
29
|
+
* 3. Renders a SegmentedButton toggle between the two views.
|
|
30
|
+
* 4. Provides reset logic to discard staged values if the user cancels.
|
|
31
|
+
*
|
|
32
|
+
* The table preview container (VBox#EasyFillTablePreviewContainer) in the dialog XML is populated
|
|
33
|
+
* programmatically — no table rows are declared in the fragment XML.
|
|
34
|
+
*/
|
|
35
|
+
return {
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Renders collection (SmartTable) previews into the EasyFillTablePreviewContainer VBox.
|
|
39
|
+
* For each collection with AI-suggested updates:
|
|
40
|
+
* - Creates transient staging contexts for the preview rows
|
|
41
|
+
* - Creates a Previous/New table pair with a toggle SegmentedButton
|
|
42
|
+
* - Appends the section to the container
|
|
43
|
+
*
|
|
44
|
+
* @param {object} mCollectionUpdates - map of { navProperty: [ rowUpdate ] } from AI response
|
|
45
|
+
* @param {object} mFieldMapping - full LLM field mapping (used to get item properties and descriptions)
|
|
46
|
+
* @param {Array} aTableValidationErrors - validation errors from value-help checks
|
|
47
|
+
* @param {object} oController - MVC controller (used to byId the container)
|
|
48
|
+
* @param {object} oRb - i18n resource bundle
|
|
49
|
+
* @param {object} mCollectionState - collection tracking state { mCollectionRowContexts, mCollectionRowContextsByPath, mCollectionProperties }
|
|
50
|
+
* @param {object} oTableStagingState - mutable table staging state { mStagedRows }
|
|
51
|
+
* @param {object} oObjectPageModel - the OData model used to create transient staging contexts
|
|
52
|
+
* @param {function} fnOnTableFieldChange - callback invoked when a preview table cell changes
|
|
53
|
+
*/
|
|
54
|
+
renderCollectionPreviews: function(mCollectionUpdates, mFieldMapping, aTableValidationErrors, oController, oRb, mCollectionState, oTableStagingState, oObjectPageModel, fnOnTableFieldChange) {
|
|
55
|
+
var oTablePreviewContainer = oController.byId("EasyFillTablePreviewContainer");
|
|
56
|
+
if (!oTablePreviewContainer) {
|
|
57
|
+
oLogger.warning("renderCollectionPreviews: EasyFillTablePreviewContainer not found");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Remove all previously rendered table sections
|
|
62
|
+
oTablePreviewContainer.destroyItems();
|
|
63
|
+
|
|
64
|
+
this._initializeStagedCollectionRows(
|
|
65
|
+
mCollectionUpdates,
|
|
66
|
+
mFieldMapping,
|
|
67
|
+
mCollectionState,
|
|
68
|
+
oTableStagingState,
|
|
69
|
+
oObjectPageModel
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
var that = this;
|
|
73
|
+
Object.keys(mCollectionUpdates).forEach(function(sCollectionName) {
|
|
74
|
+
var oCollectionMeta = mFieldMapping[sCollectionName];
|
|
75
|
+
if (!oCollectionMeta || !oCollectionMeta.itemProperties) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
var aPropertyNames = Object.keys(oCollectionMeta.itemProperties || {});
|
|
80
|
+
if (!aPropertyNames.length) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
var aPreviewRows = (oTableStagingState.mStagedRows[sCollectionName] || []).filter(function(oStagedRow) {
|
|
84
|
+
return oStagedRow.isPreviewVisible;
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
if (!aPreviewRows.length) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Previous values table (read-only, initially hidden)
|
|
92
|
+
var aPreviousRows = aPreviewRows.map(function(oPreviewRow) {
|
|
93
|
+
return that._buildCollectionPreviewRowFromContext(aPropertyNames, oPreviewRow.realContext);
|
|
94
|
+
});
|
|
95
|
+
var oPreviousTable = that._createPreviewTable(aPropertyNames, oCollectionMeta.itemProperties, aPreviousRows);
|
|
96
|
+
oPreviousTable.setVisible(false);
|
|
97
|
+
|
|
98
|
+
// New values table (editable SmartFields, initially visible)
|
|
99
|
+
var oNewTable = that._createEditableNewTable(
|
|
100
|
+
aPropertyNames,
|
|
101
|
+
oCollectionMeta.itemProperties,
|
|
102
|
+
aPreviewRows,
|
|
103
|
+
sCollectionName,
|
|
104
|
+
mCollectionState,
|
|
105
|
+
fnOnTableFieldChange
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// Section title showing collection label and row count
|
|
109
|
+
var oSectionTitle = new Title({
|
|
110
|
+
level: "H5",
|
|
111
|
+
text: (oCollectionMeta.description || sCollectionName) + " (" + aPreviewRows.length + ")"
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Toggle button between "Previous" and "New" views
|
|
115
|
+
var oSegmentedButton = new SegmentedButton({
|
|
116
|
+
selectedKey: "new",
|
|
117
|
+
width: "auto",
|
|
118
|
+
items: [
|
|
119
|
+
new SegmentedButtonItem({ key: "previous", text: oRb.getText("EASY_FILL_TABLE_VIEW_PREVIOUS"), width: "auto" }),
|
|
120
|
+
new SegmentedButtonItem({ key: "new", text: oRb.getText("EASY_FILL_TABLE_VIEW_NEW"), width: "auto" })
|
|
121
|
+
],
|
|
122
|
+
selectionChange: function() {
|
|
123
|
+
var sKey = oSegmentedButton.getSelectedKey();
|
|
124
|
+
oPreviousTable.setVisible(sKey === "previous");
|
|
125
|
+
oNewTable.setVisible(sKey === "new");
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
var oHeader = new HBox({
|
|
130
|
+
justifyContent: "SpaceBetween",
|
|
131
|
+
items: [oSectionTitle, oSegmentedButton]
|
|
132
|
+
}).addStyleClass("sapUiSmallMarginTop");
|
|
133
|
+
|
|
134
|
+
var oSection = new VBox({
|
|
135
|
+
items: [oHeader, oPreviousTable, oNewTable]
|
|
136
|
+
}).addStyleClass("sapSmartTemplatesObjectPageEasyFillTableSection");
|
|
137
|
+
|
|
138
|
+
oTablePreviewContainer.addItem(oSection);
|
|
139
|
+
oLogger.debug("renderCollectionPreviews: rendered collection '" + sCollectionName + "' with " + aPreviewRows.length + " rows");
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Resets and clears all transient collection contexts created for table preview staging.
|
|
145
|
+
*
|
|
146
|
+
* @param {object} oTableStagingState - table staging state { mStagedRows }
|
|
147
|
+
* @param {object} oObjectPageModel - the OData model
|
|
148
|
+
*/
|
|
149
|
+
resetStagedCollectionContexts: function(oTableStagingState, oObjectPageModel) {
|
|
150
|
+
var aTransientPaths = [];
|
|
151
|
+
|
|
152
|
+
Object.keys((oTableStagingState && oTableStagingState.mStagedRows) || {}).forEach(function(sCollectionName) {
|
|
153
|
+
(oTableStagingState.mStagedRows[sCollectionName] || []).forEach(function(oStagedRow) {
|
|
154
|
+
var oTransientContext = oStagedRow.transientContext;
|
|
155
|
+
var sTransientPath = oTransientContext && oTransientContext.getPath && oTransientContext.getPath();
|
|
156
|
+
if (sTransientPath) {
|
|
157
|
+
aTransientPaths.push(sTransientPath);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
if (aTransientPaths.length && oObjectPageModel) {
|
|
163
|
+
oObjectPageModel.resetChanges(aTransientPaths, false, true);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this._clearStagedCollectionState(oTableStagingState);
|
|
167
|
+
oLogger.debug("resetStagedCollectionContexts: transient table contexts reset");
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
// ─── Private Helpers ─────────────────────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
_initializeStagedCollectionRows: function(mCollectionUpdates, mFieldMapping, mCollectionState, oTableStagingState, oObjectPageModel) {
|
|
173
|
+
var that = this;
|
|
174
|
+
this._clearStagedCollectionState(oTableStagingState);
|
|
175
|
+
|
|
176
|
+
Object.keys(mCollectionUpdates || {}).forEach(function(sCollectionName) {
|
|
177
|
+
var oCollectionMeta = mFieldMapping[sCollectionName];
|
|
178
|
+
var aRowUpdates = mCollectionUpdates[sCollectionName] || [];
|
|
179
|
+
var aCollectionRowContexts = mCollectionState.mCollectionRowContexts[sCollectionName] || [];
|
|
180
|
+
var mCollectionPropertyMap = mCollectionState.mCollectionProperties[sCollectionName] || Object.create(null);
|
|
181
|
+
var aPropertyNames = Object.keys((oCollectionMeta && oCollectionMeta.itemProperties) || {});
|
|
182
|
+
|
|
183
|
+
if (!oCollectionMeta || !oCollectionMeta.entitySet || !aPropertyNames.length) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
var mUpdatesByIdentity = Object.create(null);
|
|
188
|
+
aRowUpdates.forEach(function(oRowUpdate, iUpdateIndex) {
|
|
189
|
+
var oResolvedUpdate = that._resolveCollectionRowContext(sCollectionName, oRowUpdate, mCollectionState);
|
|
190
|
+
mUpdatesByIdentity[that._getCollectionRowIdentity(oResolvedUpdate, oRowUpdate, iUpdateIndex)] = oRowUpdate;
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
oTableStagingState.mStagedRows[sCollectionName] = [];
|
|
194
|
+
|
|
195
|
+
aCollectionRowContexts.forEach(function(oRealContext, iRowIndex) {
|
|
196
|
+
var oResolvedRow = { context: oRealContext, rowIndex: iRowIndex };
|
|
197
|
+
var sIdentity = that._getCollectionRowIdentity(oResolvedRow, null, iRowIndex);
|
|
198
|
+
var oRowUpdate = mUpdatesByIdentity[sIdentity];
|
|
199
|
+
var bIsPreviewVisible = iRowIndex < iMaxPreviewRows;
|
|
200
|
+
|
|
201
|
+
if (!bIsPreviewVisible && !oRowUpdate) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
var oTransientContext = that._createTransientCollectionContext(oCollectionMeta.entitySet, oObjectPageModel);
|
|
206
|
+
if (!oTransientContext) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
var oRealRowObject = oRealContext.getObject && oRealContext.getObject();
|
|
211
|
+
that._seedTransientContextFromRowObject(oTransientContext, oRealRowObject);
|
|
212
|
+
that._applyRowUpdateToTransientContext(oTransientContext, oRowUpdate, mCollectionPropertyMap, oRealRowObject);
|
|
213
|
+
|
|
214
|
+
oTableStagingState.mStagedRows[sCollectionName].push({
|
|
215
|
+
realContext: oRealContext,
|
|
216
|
+
transientContext: oTransientContext,
|
|
217
|
+
rowIndex: iRowIndex,
|
|
218
|
+
propertyNames: aPropertyNames,
|
|
219
|
+
isPreviewVisible: bIsPreviewVisible
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Creates a read-only sap.m.Table for displaying table row data (used for "Previous Values" view).
|
|
227
|
+
* All cells are rendered as plain Text controls.
|
|
228
|
+
*
|
|
229
|
+
* @param {Array<string>} aPropertyNames - ordered list of property names to show as columns
|
|
230
|
+
* @param {object} oItemProperties - map of { propName: { description, dataType } }
|
|
231
|
+
* @param {Array<object>} aRows - array of plain row value objects
|
|
232
|
+
* @param {function} [fnCellFormatter] - optional custom cell formatter (oRow, sPropName, sRawValue) → string
|
|
233
|
+
* @returns {sap.m.Table}
|
|
234
|
+
*/
|
|
235
|
+
_createPreviewTable: function(aPropertyNames, oItemProperties, aRows, fnCellFormatter) {
|
|
236
|
+
var aColumns = aPropertyNames.map(function(sPropertyName) {
|
|
237
|
+
return new Column({
|
|
238
|
+
header: new Text({
|
|
239
|
+
text: (oItemProperties[sPropertyName] && oItemProperties[sPropertyName].description) || sPropertyName
|
|
240
|
+
})
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
var aItems = aRows.map(function(oRow) {
|
|
245
|
+
return new ColumnListItem({
|
|
246
|
+
cells: aPropertyNames.map(function(sPropertyName) {
|
|
247
|
+
var sText = fnCellFormatter
|
|
248
|
+
? fnCellFormatter(oRow, sPropertyName, this._stringifyCellValue(oRow[sPropertyName]))
|
|
249
|
+
: this._stringifyCellValue(oRow[sPropertyName]);
|
|
250
|
+
return new Text({ text: sText });
|
|
251
|
+
}.bind(this))
|
|
252
|
+
});
|
|
253
|
+
}.bind(this));
|
|
254
|
+
|
|
255
|
+
return new Table({
|
|
256
|
+
columns: aColumns,
|
|
257
|
+
items: aItems,
|
|
258
|
+
fixedLayout: false,
|
|
259
|
+
autoPopinMode: true
|
|
260
|
+
}).addStyleClass("sapSmartTemplatesObjectPageEasyFillTablePreview");
|
|
261
|
+
},
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Creates an editable sap.m.Table for displaying AI-suggested row updates.
|
|
265
|
+
* Editable cells are rendered as SmartField controls bound to the OData row context.
|
|
266
|
+
* Non-editable cells are rendered as plain Text controls.
|
|
267
|
+
*
|
|
268
|
+
* @param {Array<string>} aPropertyNames - ordered list of property names to show as columns
|
|
269
|
+
* @param {object} oItemProperties - map of { propName: { description, dataType } }
|
|
270
|
+
* @param {Array<object>} aPreviewRows - enriched row objects with context, newValues, etc.
|
|
271
|
+
* @param {string} sCollectionName - navigation property name (used to look up property metadata)
|
|
272
|
+
* @param {object} mCollectionState - collection tracking state (used to get property metadata)
|
|
273
|
+
* @returns {sap.m.Table}
|
|
274
|
+
*/
|
|
275
|
+
_createEditableNewTable: function(aPropertyNames, oItemProperties, aPreviewRows, sCollectionName, mCollectionState, fnOnTableFieldChange) {
|
|
276
|
+
var aColumns = aPropertyNames.map(function(sPropName) {
|
|
277
|
+
return new Column({
|
|
278
|
+
header: new Text({
|
|
279
|
+
text: (oItemProperties[sPropName] && oItemProperties[sPropName].description) || sPropName
|
|
280
|
+
})
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
var mCollectionPropertyMap = mCollectionState.mCollectionProperties[sCollectionName] || Object.create(null);
|
|
285
|
+
var that = this;
|
|
286
|
+
|
|
287
|
+
var aItems = aPreviewRows.map(function(oPreviewRow) {
|
|
288
|
+
var oContext = oPreviewRow.transientContext;
|
|
289
|
+
var oRowObject = oPreviewRow.realContext && oPreviewRow.realContext.getObject && oPreviewRow.realContext.getObject();
|
|
290
|
+
|
|
291
|
+
var aCells = aPropertyNames.map(function(sPropName) {
|
|
292
|
+
if (!oContext) {
|
|
293
|
+
return new Text({ text: "" });
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
var oPropertyMeta = mCollectionPropertyMap[sPropName];
|
|
297
|
+
var bEditable = that._isEditableProperty(oPropertyMeta, oRowObject);
|
|
298
|
+
|
|
299
|
+
// Use a SmartField so value-help and type-specific rendering are supported
|
|
300
|
+
var oSmartField = new SmartField({
|
|
301
|
+
value: "{" + sPropName + "}",
|
|
302
|
+
editable: bEditable,
|
|
303
|
+
enabled: bEditable,
|
|
304
|
+
contextEditable: bEditable,
|
|
305
|
+
change: function() {
|
|
306
|
+
if (typeof fnOnTableFieldChange === "function") {
|
|
307
|
+
fnOnTableFieldChange();
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
editableChanged: function(oEvent) {
|
|
311
|
+
// Keep table SmartField editability deterministic during preview
|
|
312
|
+
if (oEvent.getParameter("editable") !== bEditable) {
|
|
313
|
+
oEvent.getSource().setEditable(bEditable);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
return oSmartField;
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
var oItem = new ColumnListItem({ cells: aCells });
|
|
322
|
+
if (oContext) {
|
|
323
|
+
oItem.setBindingContext(oContext);
|
|
324
|
+
}
|
|
325
|
+
return oItem;
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
return new Table({
|
|
329
|
+
columns: aColumns,
|
|
330
|
+
items: aItems,
|
|
331
|
+
fixedLayout: false,
|
|
332
|
+
autoPopinMode: true
|
|
333
|
+
}).addStyleClass("sapSmartTemplatesObjectPageEasyFillTablePreview");
|
|
334
|
+
},
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Builds a plain preview row object from a given OData context.
|
|
338
|
+
*
|
|
339
|
+
* @param {Array<string>} aPropertyNames - property names to include
|
|
340
|
+
* @param {object} oContext - OData context providing the property values
|
|
341
|
+
* @returns {object} plain row data object
|
|
342
|
+
*/
|
|
343
|
+
_buildCollectionPreviewRowFromContext: function(aPropertyNames, oContext) {
|
|
344
|
+
var oPreviewRow = {};
|
|
345
|
+
|
|
346
|
+
aPropertyNames.forEach(function(sPropertyName) {
|
|
347
|
+
oPreviewRow[sPropertyName] = oContext ? oContext.getProperty(sPropertyName) : "";
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
return oPreviewRow;
|
|
351
|
+
},
|
|
352
|
+
|
|
353
|
+
_createTransientCollectionContext: function(sEntitySetName, oObjectPageModel) {
|
|
354
|
+
if (!sEntitySetName || !oObjectPageModel) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return oObjectPageModel.createEntry("/" + sEntitySetName, {
|
|
359
|
+
groupId: "EasyFillFETransientChanges",
|
|
360
|
+
changeSetId: "EasyFillFETransientChanges"
|
|
361
|
+
});
|
|
362
|
+
},
|
|
363
|
+
|
|
364
|
+
_seedTransientContextFromRowObject: function(oTransientContext, oRowObject) {
|
|
365
|
+
Object.keys(oRowObject || {}).forEach(function(sPropertyName) {
|
|
366
|
+
var vValue = oRowObject[sPropertyName];
|
|
367
|
+
if (vValue === null || vValue === undefined || typeof vValue !== "object" || vValue instanceof Date) {
|
|
368
|
+
oTransientContext.setProperty(sPropertyName, vValue);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
_applyRowUpdateToTransientContext: function(oTransientContext, oRowUpdate, mCollectionPropertyMap, oRealRowObject) {
|
|
374
|
+
var that = this;
|
|
375
|
+
Object.keys(oRowUpdate || {}).forEach(function(sPropertyName) {
|
|
376
|
+
if (sPropertyName === "_rowIndex" || sPropertyName === "_contextPath") {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
var oPropertyMeta = mCollectionPropertyMap[sPropertyName];
|
|
381
|
+
if (!that._isEditableProperty(oPropertyMeta, oRealRowObject)) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
oTransientContext.setProperty(sPropertyName, oRowUpdate[sPropertyName]);
|
|
386
|
+
});
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
_clearStagedCollectionState: function(oTableStagingState) {
|
|
390
|
+
Object.keys((oTableStagingState && oTableStagingState.mStagedRows) || {}).forEach(function(sCollectionName) {
|
|
391
|
+
delete oTableStagingState.mStagedRows[sCollectionName];
|
|
392
|
+
});
|
|
393
|
+
},
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Resolves an OData row context for a given collection row update.
|
|
397
|
+
* Prefers context path lookup; falls back to row index.
|
|
398
|
+
*
|
|
399
|
+
* @param {string} sCollectionName - navigation property name
|
|
400
|
+
* @param {object} oRowUpdate - the AI row update object ({ _contextPath?, _rowIndex? })
|
|
401
|
+
* @param {object} mCollectionState - collection tracking state
|
|
402
|
+
* @returns {{ context, rowIndex }|null}
|
|
403
|
+
*/
|
|
404
|
+
_resolveCollectionRowContext: function(sCollectionName, oRowUpdate, mCollectionState) {
|
|
405
|
+
var mByPath = mCollectionState.mCollectionRowContextsByPath[sCollectionName] || Object.create(null);
|
|
406
|
+
var sContextPath = oRowUpdate && oRowUpdate._contextPath;
|
|
407
|
+
|
|
408
|
+
// Prefer context path (more stable across refreshes)
|
|
409
|
+
if (typeof sContextPath === "string" && mByPath[sContextPath]) {
|
|
410
|
+
return mByPath[sContextPath];
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Fallback to row index
|
|
414
|
+
var iRowIndex = oRowUpdate && oRowUpdate._rowIndex;
|
|
415
|
+
var aRowContexts = mCollectionState.mCollectionRowContexts[sCollectionName] || [];
|
|
416
|
+
if (typeof iRowIndex === "number" && aRowContexts[iRowIndex]) {
|
|
417
|
+
return { context: aRowContexts[iRowIndex], rowIndex: iRowIndex };
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return null;
|
|
421
|
+
},
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Returns a stable string identity for a collection row, used as a map key.
|
|
425
|
+
* Priority: context path → _contextPath from update → _rowIndex → fallback index string.
|
|
426
|
+
*
|
|
427
|
+
* @param {object} oResolvedRow - { context, rowIndex } or null
|
|
428
|
+
* @param {object} oRowUpdate - the AI row update object
|
|
429
|
+
* @param {number} iFallbackIndex - fallback numeric index
|
|
430
|
+
* @returns {string}
|
|
431
|
+
*/
|
|
432
|
+
_getCollectionRowIdentity: function(oResolvedRow, oRowUpdate, iFallbackIndex) {
|
|
433
|
+
if (oResolvedRow && oResolvedRow.context && oResolvedRow.context.getPath) {
|
|
434
|
+
return oResolvedRow.context.getPath();
|
|
435
|
+
}
|
|
436
|
+
if (oRowUpdate && typeof oRowUpdate._contextPath === "string") {
|
|
437
|
+
return oRowUpdate._contextPath;
|
|
438
|
+
}
|
|
439
|
+
if (oRowUpdate && typeof oRowUpdate._rowIndex === "number") {
|
|
440
|
+
return "index:" + String(oRowUpdate._rowIndex);
|
|
441
|
+
}
|
|
442
|
+
return "row:" + String(iFallbackIndex);
|
|
443
|
+
},
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* Converts a raw cell value to a display string for read-only table cells.
|
|
447
|
+
* Handles null/undefined, Date objects, and primitives.
|
|
448
|
+
*
|
|
449
|
+
* @param {*} vValue
|
|
450
|
+
* @returns {string}
|
|
451
|
+
*/
|
|
452
|
+
_stringifyCellValue: function(vValue) {
|
|
453
|
+
if (vValue === null || vValue === undefined) {
|
|
454
|
+
return "";
|
|
455
|
+
}
|
|
456
|
+
if (vValue instanceof Date) {
|
|
457
|
+
return vValue.toISOString();
|
|
458
|
+
}
|
|
459
|
+
return String(vValue);
|
|
460
|
+
},
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* Checks whether a collection property is editable given the current row data object.
|
|
464
|
+
* Delegates to the same annotation checks used in EasyFillFieldCollector.isEditableByContextObject.
|
|
465
|
+
* Duplicated here to keep TableRenderer self-contained (no circular dependency).
|
|
466
|
+
*
|
|
467
|
+
* @param {object} oPropertyMeta - OData property metadata
|
|
468
|
+
* @param {object} oRowObject - plain row data object
|
|
469
|
+
* @returns {boolean}
|
|
470
|
+
*/
|
|
471
|
+
_isEditableProperty: function(oPropertyMeta, oRowObject) {
|
|
472
|
+
if (!oPropertyMeta) {
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
var sUpdatable = oPropertyMeta["sap:updatable"];
|
|
476
|
+
if (sUpdatable) {
|
|
477
|
+
return sUpdatable !== "false";
|
|
478
|
+
}
|
|
479
|
+
var oAnnotation = oPropertyMeta["com.sap.vocabularies.Common.v1.FieldControl"];
|
|
480
|
+
if (oAnnotation && oAnnotation["EnumMember"]) {
|
|
481
|
+
return oAnnotation["EnumMember"] !== "com.sap.vocabularies.Common.v1.FieldControlType/ReadOnly";
|
|
482
|
+
}
|
|
483
|
+
var sFieldControl = oPropertyMeta["sap:field-control"];
|
|
484
|
+
if (sFieldControl) {
|
|
485
|
+
var iFieldControlValue = oRowObject && oRowObject[sFieldControl];
|
|
486
|
+
return iFieldControlValue !== 1;
|
|
487
|
+
}
|
|
488
|
+
return true;
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
});
|