@sapui5/sap.suite.ui.generic.template 1.148.1 → 1.148.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/sap/suite/ui/generic/template/.library +1 -1
- 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 +6 -3
- package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
- package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +1 -1
- 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/genericUtilities/controlStateWrapperFactory/SmartFilterBarWrapper.js +20 -1
- package/src/sap/suite/ui/generic/template/lib/AppComponent.js +1 -1
- package/src/sap/suite/ui/generic/template/lib/CRUDManager.js +0 -7
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillAIOrchestrator.js +43 -12
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillApplyHandler.js +67 -218
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillDialogController.js +55 -8
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFieldCollector.js +214 -35
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillFormRenderer.js +93 -18
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillHandler.js +426 -48
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/EasyFillTableRenderer.js +512 -63
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFill/fragments/EasyFillDialog.fragment.xml +33 -22
- package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterBarHandler.js +90 -73
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n.properties +24 -0
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ar.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_bg.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ca.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cnr.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cs.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_cy.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_da.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_de.properties +19 -11
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_el.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_GB.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_en_US_saprigi.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_es_MX.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_et.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fi.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr.properties +16 -8
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_fr_CA.properties +16 -8
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hi.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hr.properties +16 -8
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_hu.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_id.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_it.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_iw.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ja.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_kk.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ko.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lt.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_lv.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_mk.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ms.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_nl.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_no.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pl.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_pt_PT.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ro.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_ru.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sh.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sk.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sl.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sr.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_sv.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_th.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_tr.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_uk.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_vi.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_CN.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/i18n/i18n_zh_TW.properties +15 -7
- package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +1 -1
- package/src/sap/suite/ui/generic/template/library.js +1 -1
- package/src/sap/suite/ui/generic/template/themes/base/ObjectPage.less +22 -1
package/package.json
CHANGED
|
@@ -939,9 +939,12 @@ sap.ui.define([
|
|
|
939
939
|
var oTempModel = oTemplateUtils.oComponentUtils.getTemplatePrivateModel();
|
|
940
940
|
if (oTempModel.getProperty("/listReport/filterMode") === "easyFilter") {
|
|
941
941
|
oSmartFilterbar.setVisible(false);
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
942
|
+
// Only show gray overlay when data in table is present.
|
|
943
|
+
// filters scenario where gray overlay shows up when No data Illustrated msg is rendered
|
|
944
|
+
if (oTempModel.getProperty("/generic/bDataAreShownInTable")) {
|
|
945
|
+
oTempModel.setProperty("/listReport/firstSelection", true);
|
|
946
|
+
oTempModel.setProperty("/generic/bDataAreShownInTable", false);
|
|
947
|
+
}
|
|
945
948
|
} else {
|
|
946
949
|
PXFeedback.triggerPXIntegration("toggleSwitchV2");
|
|
947
950
|
oSmartFilterbar.setVisible(true);
|
|
@@ -27,6 +27,7 @@ sap.ui.define([
|
|
|
27
27
|
var aBasicFilters = [];
|
|
28
28
|
var oSmartFilterBar = oControl;
|
|
29
29
|
var oEasyFilterCallbacks = null;
|
|
30
|
+
var oPendingEasyFilterState = null;
|
|
30
31
|
|
|
31
32
|
var oVariantManagementInitializedPromise;
|
|
32
33
|
|
|
@@ -86,6 +87,11 @@ sap.ui.define([
|
|
|
86
87
|
filterMode: oCustomData[dataPropertyNameGeneric].filterMode,
|
|
87
88
|
easyFilter: oCustomData[dataPropertyNameGeneric].easyFilter
|
|
88
89
|
});
|
|
90
|
+
} else {
|
|
91
|
+
oPendingEasyFilterState = {
|
|
92
|
+
filterMode: oCustomData[dataPropertyNameGeneric].filterMode,
|
|
93
|
+
easyFilter: oCustomData[dataPropertyNameGeneric].easyFilter
|
|
94
|
+
};
|
|
89
95
|
}
|
|
90
96
|
});
|
|
91
97
|
|
|
@@ -142,7 +148,8 @@ sap.ui.define([
|
|
|
142
148
|
.map(oFilterItem => oFilterItem.getName()),
|
|
143
149
|
...aRemovedFromStandard
|
|
144
150
|
])],
|
|
145
|
-
customFilters: mParams.oCustomFiltersWrapper.getState()
|
|
151
|
+
customFilters: mParams.oCustomFiltersWrapper.getState(),
|
|
152
|
+
easyFilterState: oEasyFilterCallbacks ? oEasyFilterCallbacks.getState() : null
|
|
146
153
|
};
|
|
147
154
|
}
|
|
148
155
|
|
|
@@ -175,6 +182,14 @@ sap.ui.define([
|
|
|
175
182
|
|
|
176
183
|
mParams.oCustomFiltersWrapper.setState(oState && oState.customFilters);
|
|
177
184
|
|
|
185
|
+
if (oState && oState.easyFilterState) {
|
|
186
|
+
if (oEasyFilterCallbacks) {
|
|
187
|
+
oEasyFilterCallbacks.setState(oState.easyFilterState);
|
|
188
|
+
} else {
|
|
189
|
+
oPendingEasyFilterState = oState.easyFilterState;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
178
193
|
// set visibility
|
|
179
194
|
// TODO:
|
|
180
195
|
// - How to deal with old states (not containing all information about visibility) -> legacy state handler?
|
|
@@ -250,6 +265,10 @@ sap.ui.define([
|
|
|
250
265
|
setSVMWrapperCallbacks: setSVMWrapperCallbacks,
|
|
251
266
|
setEasyFilterCallbacks: function(oCallbacks) {
|
|
252
267
|
oEasyFilterCallbacks = oCallbacks;
|
|
268
|
+
if (oPendingEasyFilterState) {
|
|
269
|
+
oEasyFilterCallbacks.setState(oPendingEasyFilterState);
|
|
270
|
+
oPendingEasyFilterState = null;
|
|
271
|
+
}
|
|
253
272
|
},
|
|
254
273
|
bVMConnection: oSmartFilterBar.getSmartVariant(),
|
|
255
274
|
suppressSelection: oSmartFilterBar.setSuppressSelection.bind(oSmartFilterBar), // if multiple reasons for suppressing overlap, a counter (to avoid to early resume) could be implemented here
|
|
@@ -959,7 +959,7 @@ sap.ui.define([
|
|
|
959
959
|
* @public
|
|
960
960
|
* @extends sap.ui.core.UIComponent
|
|
961
961
|
* @author SAP SE
|
|
962
|
-
* @version 1.148.
|
|
962
|
+
* @version 1.148.2
|
|
963
963
|
* @name sap.suite.ui.generic.template.lib.AppComponent
|
|
964
964
|
*/
|
|
965
965
|
var oAppComponent = UIComponent.extend("sap.suite.ui.generic.template.lib.AppComponent", {
|
|
@@ -589,13 +589,6 @@ sap.ui.define(["sap/ui/base/Object",
|
|
|
589
589
|
oServices.oTemplateCapabilities.oMessageButtonHelper.showMessagePopover();
|
|
590
590
|
}
|
|
591
591
|
}
|
|
592
|
-
// Reset pending changes to prevent infinite loop when entering edit mode again.
|
|
593
|
-
// Invalid values cause infinite loop because the pending changes (with invalid values) are resubmitted when the user clicks Edit, triggering the same error.
|
|
594
|
-
var oContext = oController.getView().getBindingContext();
|
|
595
|
-
var sContextPath = oContext && oContext.getPath();
|
|
596
|
-
if (sContextPath && oModel && oModel.hasPendingChanges()) {
|
|
597
|
-
oModel.resetChanges([sContextPath], undefined, true);
|
|
598
|
-
}
|
|
599
592
|
reject();
|
|
600
593
|
});
|
|
601
594
|
oBusyHelper.setBusy(oSubmitChange);
|
|
@@ -131,18 +131,28 @@ sap.ui.define([
|
|
|
131
131
|
* - collectionFields: row-level updates for SmartTable collections
|
|
132
132
|
*
|
|
133
133
|
* Collection fields are identified by the isCollection flag in the field mapping.
|
|
134
|
-
*
|
|
134
|
+
* For tables that allow creation (mCollectionState.mCollectionAllowsCreation), rows
|
|
135
|
+
* without _rowIndex or _contextPath are treated as new rows to be created.
|
|
136
|
+
* Only one new row per table is supported; extra new rows are flagged via multipleNewRows.
|
|
137
|
+
* Tables where the AI proposed new rows but creation is not allowed are tracked in
|
|
138
|
+
* collectionsWithRejectedNewRows so the renderer can show a per-table warning strip.
|
|
135
139
|
*
|
|
136
140
|
* @param {object} oAiData - the AI response data map { fieldName: value | rowArray }
|
|
137
141
|
* @param {object} mFieldMapping - the complete field mapping
|
|
138
142
|
* @param {object} oFieldCollector - EasyFillFieldCollector (used for SmartTable validation)
|
|
139
143
|
* @param {object} oObjectPage - the ObjectPage control (used for SmartTable validation)
|
|
140
|
-
* @
|
|
144
|
+
* @param {object} mCollectionState - collection tracking state (used for allowsCreation check)
|
|
145
|
+
* @returns {{ simpleFields: object, collectionFields: object, attemptedMultipleNewRows: boolean, collectionsWithRejectedNewRows: object }}
|
|
141
146
|
*/
|
|
142
|
-
splitAIResultByCollection: function(oAiData, mFieldMapping, oFieldCollector, oObjectPage) {
|
|
147
|
+
splitAIResultByCollection: function(oAiData, mFieldMapping, oFieldCollector, oObjectPage, mCollectionState) {
|
|
143
148
|
var oSplitResult = {
|
|
144
149
|
simpleFields: {},
|
|
145
|
-
collectionFields: {}
|
|
150
|
+
collectionFields: {},
|
|
151
|
+
attemptedMultipleNewRows: false,
|
|
152
|
+
// Map of { navProperty: "all" | "mixed" } for tables where AI proposed new rows
|
|
153
|
+
// but creation is not allowed. "all" = only new rows proposed; "mixed" = some
|
|
154
|
+
// existing updates + some rejected new rows.
|
|
155
|
+
collectionsWithRejectedNewRows: {}
|
|
146
156
|
};
|
|
147
157
|
|
|
148
158
|
Object.keys(oAiData || {}).forEach(function(sFieldName) {
|
|
@@ -158,20 +168,41 @@ sap.ui.define([
|
|
|
158
168
|
}
|
|
159
169
|
|
|
160
170
|
if (oFieldMeta && oFieldMeta.isCollection === true && aCollectionRows) {
|
|
161
|
-
|
|
162
|
-
|
|
171
|
+
var bAllowsCreation = !!(mCollectionState && mCollectionState.mCollectionAllowsCreation &&
|
|
172
|
+
mCollectionState.mCollectionAllowsCreation[sFieldName]);
|
|
173
|
+
|
|
174
|
+
// Separate existing-row updates (have _rowIndex or _contextPath) from new rows
|
|
175
|
+
var aExistingRowUpdates = aCollectionRows.filter(function(oRow) {
|
|
163
176
|
return oRow && typeof oRow === "object" &&
|
|
164
177
|
(typeof oRow._contextPath === "string" || typeof oRow._rowIndex === "number");
|
|
165
178
|
});
|
|
179
|
+
var aRawNewRows = aCollectionRows.filter(function(oRow) {
|
|
180
|
+
return oRow && typeof oRow === "object" &&
|
|
181
|
+
typeof oRow._contextPath !== "string" &&
|
|
182
|
+
typeof oRow._rowIndex !== "number";
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Track tables where AI proposed new rows that cannot be created
|
|
186
|
+
if (!bAllowsCreation && aRawNewRows.length > 0) {
|
|
187
|
+
var sRejectionType = aExistingRowUpdates.length === 0 ? "all" : "mixed";
|
|
188
|
+
oSplitResult.collectionsWithRejectedNewRows[sFieldName] = sRejectionType;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
var aNewRows = bAllowsCreation ? aRawNewRows : [];
|
|
192
|
+
|
|
193
|
+
// Cap new rows to one per table; flag if the AI proposed more
|
|
194
|
+
if (aNewRows.length > 1) {
|
|
195
|
+
oSplitResult.attemptedMultipleNewRows = true;
|
|
196
|
+
aNewRows = [aNewRows[0]];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
var aRowUpdates = aExistingRowUpdates.concat(aNewRows);
|
|
166
200
|
|
|
167
|
-
// Single-table limitation: only the first valid collection is accepted.
|
|
168
|
-
// Future work: extend collectionFields structure to support multiple tables.
|
|
169
201
|
var oValidation = oFieldCollector.isValidSmartTable(oFieldMeta.entitySet, oObjectPage);
|
|
170
|
-
if (aRowUpdates.length > 0 &&
|
|
171
|
-
Object.keys(oSplitResult.collectionFields).length === 0 &&
|
|
172
|
-
oValidation.isValid) {
|
|
202
|
+
if (aRowUpdates.length > 0 && oValidation.isValid) {
|
|
173
203
|
oSplitResult.collectionFields[sFieldName] = aRowUpdates;
|
|
174
|
-
oLogger.debug("splitAIResultByCollection: accepted collection field '" + sFieldName + "' with " +
|
|
204
|
+
oLogger.debug("splitAIResultByCollection: accepted collection field '" + sFieldName + "' with " +
|
|
205
|
+
aExistingRowUpdates.length + " updates and " + aNewRows.length + " new row(s)");
|
|
175
206
|
}
|
|
176
207
|
} else {
|
|
177
208
|
// Scalar field → goes to simpleFields
|
|
@@ -1,30 +1,12 @@
|
|
|
1
1
|
sap.ui.define([
|
|
2
2
|
"sap/suite/ui/generic/template/genericUtilities/FeLogger",
|
|
3
|
-
"sap/suite/ui/generic/template/genericUtilities/FeError"
|
|
4
|
-
|
|
5
|
-
"sap/ui/model/FilterOperator"
|
|
6
|
-
], function(FeLogger, FeError, Filter, FilterOperator) {
|
|
3
|
+
"sap/suite/ui/generic/template/genericUtilities/FeError"
|
|
4
|
+
], function(FeLogger, FeError) {
|
|
7
5
|
"use strict";
|
|
8
6
|
|
|
9
7
|
var sClassName = "lib.ai.EasyFill.EasyFillApplyHandler";
|
|
10
8
|
var oLogger = new FeLogger(sClassName).getLogger();
|
|
11
9
|
|
|
12
|
-
/**
|
|
13
|
-
* Returns the first ValueListParameterInOut parameter matching the given local property name.
|
|
14
|
-
* Extracted as a module-level helper to avoid no-loop-func ESLint violations.
|
|
15
|
-
*
|
|
16
|
-
* @param {Array} aParameters - value-list Parameters array from OData annotations
|
|
17
|
-
* @param {string} sProperty - local property name to match
|
|
18
|
-
* @returns {object|undefined}
|
|
19
|
-
*/
|
|
20
|
-
function fnFindValueListParameter(aParameters, sProperty) {
|
|
21
|
-
return aParameters.find(function(oParam) {
|
|
22
|
-
return oParam.RecordType === "com.sap.vocabularies.Common.v1.ValueListParameterInOut" &&
|
|
23
|
-
oParam.LocalDataProperty &&
|
|
24
|
-
oParam.LocalDataProperty.PropertyPath === sProperty;
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
|
|
28
10
|
/**
|
|
29
11
|
* EasyFillApplyHandler
|
|
30
12
|
*
|
|
@@ -39,15 +21,17 @@ sap.ui.define([
|
|
|
39
21
|
* Applies all AI-suggested scalar field values from the transient context to the live ObjectPage context.
|
|
40
22
|
* Called when the user clicks "Confirm" in the EasyFill dialog.
|
|
41
23
|
*
|
|
42
|
-
*
|
|
24
|
+
*
|
|
43
25
|
* Only properties present in the updatable lookup map are written back.
|
|
44
26
|
* Collection (table) row values are copied from transient staging contexts to the
|
|
45
27
|
* live row contexts only here, so the ObjectPage table updates only after confirm.
|
|
28
|
+
* New row creation is NOT done here — the caller must call createPendingNewRows separately
|
|
29
|
+
* because it requires CRUDManager access (draft-aware) that ApplyHandler does not hold.
|
|
46
30
|
*
|
|
47
31
|
* @param {object} oTransientContextForEasyFill - the transient OData context holding AI-suggested values
|
|
48
32
|
* @param {object} oObjectPageContext - the live ObjectPage binding context to write values into
|
|
49
33
|
* @param {object} mUpdatableLookupMap - map of { fieldName: value } for fields that are updatable
|
|
50
|
-
* @param {object} oTableStagingState - table staging state { mStagedRows }
|
|
34
|
+
* @param {object} oTableStagingState - table staging state { mStagedRows, mPendingNewRowContexts }
|
|
51
35
|
* @param {object} mCollectionState - collection tracking state
|
|
52
36
|
*/
|
|
53
37
|
applyAndSave: function(oTransientContextForEasyFill, oObjectPageContext, mUpdatableLookupMap, oTableStagingState, mCollectionState) {
|
|
@@ -93,6 +77,41 @@ sap.ui.define([
|
|
|
93
77
|
oLogger.debug("applyAndSave: applied " + iCollectionApplied + " staged table value(s) to ObjectPage context");
|
|
94
78
|
},
|
|
95
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Extracts user-reviewed values from the pending new-row transient contexts.
|
|
82
|
+
* Returns a map of { navProperty: predefinedValues } ready to pass to CRUDManager.addEntry.
|
|
83
|
+
* The caller is responsible for discarding the transient contexts afterwards.
|
|
84
|
+
*
|
|
85
|
+
* @param {object} oTableStagingState - table staging state { mPendingNewRowContexts }
|
|
86
|
+
* @param {object} mCollectionState - collection tracking state (mCollectionProperties)
|
|
87
|
+
* @returns {object} map of { navProperty: plainValuesObject }
|
|
88
|
+
*/
|
|
89
|
+
extractPendingNewRowValues: function(oTableStagingState, mCollectionState) {
|
|
90
|
+
var mNewRowValues = Object.create(null);
|
|
91
|
+
Object.keys((oTableStagingState && oTableStagingState.mPendingNewRowContexts) || {}).forEach(function(sCollectionName) {
|
|
92
|
+
var aNewContexts = oTableStagingState.mPendingNewRowContexts[sCollectionName] || [];
|
|
93
|
+
if (!aNewContexts.length) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
var mCollectionPropertyMap = (mCollectionState && mCollectionState.mCollectionProperties &&
|
|
97
|
+
mCollectionState.mCollectionProperties[sCollectionName]) || Object.create(null);
|
|
98
|
+
|
|
99
|
+
// Extract scalar values set by the user during the preview (first new row only — cap is 1)
|
|
100
|
+
var oNewContext = aNewContexts[0];
|
|
101
|
+
var oValues = Object.create(null);
|
|
102
|
+
Object.keys(mCollectionPropertyMap).forEach(function(sPropName) {
|
|
103
|
+
var vValue = oNewContext.getProperty && oNewContext.getProperty(sPropName);
|
|
104
|
+
if (vValue !== undefined && vValue !== null && typeof vValue !== "object") {
|
|
105
|
+
oValues[sPropName] = vValue;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
mNewRowValues[sCollectionName] = oValues;
|
|
109
|
+
oLogger.debug("extractPendingNewRowValues: extracted " + Object.keys(oValues).length +
|
|
110
|
+
" value(s) for new row in '" + sCollectionName + "'");
|
|
111
|
+
});
|
|
112
|
+
return mNewRowValues;
|
|
113
|
+
},
|
|
114
|
+
|
|
96
115
|
/**
|
|
97
116
|
* Builds a collection updates map from the staged transient row contexts.
|
|
98
117
|
* Only editable scalar properties whose staged value differs from the live row value are included.
|
|
@@ -154,157 +173,25 @@ sap.ui.define([
|
|
|
154
173
|
},
|
|
155
174
|
|
|
156
175
|
/**
|
|
157
|
-
* Returns whether any staged collection row currently differs from the live ObjectPage rows
|
|
176
|
+
* Returns whether any staged collection row currently differs from the live ObjectPage rows,
|
|
177
|
+
* or whether any new rows are pending creation.
|
|
158
178
|
*
|
|
159
|
-
* @param {object} oTableStagingState - table staging state { mStagedRows }
|
|
179
|
+
* @param {object} oTableStagingState - table staging state { mStagedRows, mPendingNewRowContexts }
|
|
160
180
|
* @param {object} mCollectionState - collection tracking state
|
|
161
181
|
* @returns {boolean}
|
|
162
182
|
*/
|
|
163
183
|
hasStagedCollectionChanges: function(oTableStagingState, mCollectionState) {
|
|
164
184
|
var mCollectionUpdates = this.buildStagedCollectionUpdates(oTableStagingState, mCollectionState);
|
|
165
|
-
|
|
185
|
+
var bHasUpdates = Object.keys(mCollectionUpdates).some(function(sCollectionName) {
|
|
166
186
|
return (mCollectionUpdates[sCollectionName] || []).length > 0;
|
|
167
187
|
});
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Validates each collection (table) row update by checking that value-help constrained
|
|
172
|
-
* properties contain values that exist in the corresponding value-help collection.
|
|
173
|
-
*
|
|
174
|
-
* Returns an array of validation error objects for any values that fail the check.
|
|
175
|
-
* If validation cannot be performed (e.g. missing metadata), the property is skipped
|
|
176
|
-
* and save is not blocked.
|
|
177
|
-
*
|
|
178
|
-
* @param {object} mCollectionUpdates - map of { navProperty: [ rowUpdate ] }
|
|
179
|
-
* @param {object} mCollectionState - collection tracking state: { mCollectionProperties, mCollectionEntityTypes, mCollectionRowContextsByPath, mCollectionRowContexts }
|
|
180
|
-
* @param {object} oObjectPageModel - the OData model (used to read value-help collections)
|
|
181
|
-
* @param {object} oRb - i18n resource bundle
|
|
182
|
-
* @param {object} oFieldCollector - EasyFillFieldCollector (used for isEditableByContextObject)
|
|
183
|
-
* @param {object} oGenericAnnotationHelper - GenericAnnotationHelper (used for isValueHelpTableAvailable)
|
|
184
|
-
* @returns {Promise<Array>} array of { collectionName, collectionLabel, rowLabel, rowIndex, rowPath, propertyName, propertyLabel }
|
|
185
|
-
*/
|
|
186
|
-
validateCollectionUpdatesAgainstValueHelp: async function(mCollectionUpdates, mCollectionState, oObjectPageModel, oRb, oFieldCollector, oGenericAnnotationHelper) {
|
|
187
|
-
var oMetaModel = oObjectPageModel && oObjectPageModel.getMetaModel();
|
|
188
|
-
if (!oMetaModel) {
|
|
189
|
-
oLogger.warning("validateCollectionUpdatesAgainstValueHelp: no MetaModel available");
|
|
190
|
-
return [];
|
|
188
|
+
if (bHasUpdates) {
|
|
189
|
+
return true;
|
|
191
190
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
for (var i = 0; i < aCollectionNames.length; i++) {
|
|
197
|
-
var sCollectionName = aCollectionNames[i];
|
|
198
|
-
var aRowUpdates = mCollectionUpdates[sCollectionName] || [];
|
|
199
|
-
var mCollectionPropertyMap = mCollectionState.mCollectionProperties[sCollectionName] || Object.create(null);
|
|
200
|
-
var oCollectionEntityType = mCollectionState.mCollectionEntityTypes[sCollectionName];
|
|
201
|
-
|
|
202
|
-
if (!oCollectionEntityType) { continue; }
|
|
203
|
-
|
|
204
|
-
// Use the field mapping description as the collection label in error messages
|
|
205
|
-
var sCollectionLabel = sCollectionName;
|
|
206
|
-
|
|
207
|
-
for (var j = 0; j < aRowUpdates.length; j++) {
|
|
208
|
-
var oRowUpdate = aRowUpdates[j];
|
|
209
|
-
var oResolvedRow = this._resolveCollectionRowContext(sCollectionName, oRowUpdate, mCollectionState);
|
|
210
|
-
if (!oResolvedRow || !oResolvedRow.context) { continue; }
|
|
211
|
-
|
|
212
|
-
var oRowContext = oResolvedRow.context;
|
|
213
|
-
var oRowObject = oRowContext.getObject && oRowContext.getObject();
|
|
214
|
-
var sRowLabel = oRb.getText("EASY_FILL_TABLE_ROW_LABEL", [String((oResolvedRow.rowIndex || 0) + 1)]);
|
|
215
|
-
|
|
216
|
-
var aPropNames = Object.keys(oRowUpdate);
|
|
217
|
-
for (var k = 0; k < aPropNames.length; k++) {
|
|
218
|
-
var sPropertyName = aPropNames[k];
|
|
219
|
-
if (sPropertyName === "_rowIndex" || sPropertyName === "_contextPath") { continue; }
|
|
220
|
-
|
|
221
|
-
var oPropertyMeta = mCollectionPropertyMap[sPropertyName];
|
|
222
|
-
// Skip non-editable properties — they cannot be written back
|
|
223
|
-
if (!oPropertyMeta || !oFieldCollector.isEditableByContextObject(oPropertyMeta, oRowObject)) { continue; }
|
|
224
|
-
|
|
225
|
-
// Only validate properties that have an associated value-help table
|
|
226
|
-
if (!oGenericAnnotationHelper.isValueHelpTableAvailable(oPropertyMeta)) { continue; }
|
|
227
|
-
|
|
228
|
-
var vUpdatedValue = oRowUpdate[sPropertyName];
|
|
229
|
-
if (vUpdatedValue === null || vUpdatedValue === undefined || typeof vUpdatedValue === "object") { continue; }
|
|
230
|
-
|
|
231
|
-
try {
|
|
232
|
-
var sPropertyPath = oMetaModel.getODataProperty(oCollectionEntityType, sPropertyName, true);
|
|
233
|
-
if (!sPropertyPath) { continue; }
|
|
234
|
-
|
|
235
|
-
var oPropertyContext = oMetaModel.createBindingContext(sPropertyPath);
|
|
236
|
-
var oValueLists = await oMetaModel.getODataValueLists(oPropertyContext);
|
|
237
|
-
var oDefaultValueList = oValueLists && oValueLists[""];
|
|
238
|
-
|
|
239
|
-
if (!oDefaultValueList || !oDefaultValueList.CollectionPath || !oDefaultValueList.CollectionPath.String) { continue; }
|
|
240
|
-
|
|
241
|
-
// Resolve which value-list property maps to this local property
|
|
242
|
-
var sValueListProperty = sPropertyName;
|
|
243
|
-
if (Array.isArray(oDefaultValueList.Parameters)) {
|
|
244
|
-
var oParameter = fnFindValueListParameter(oDefaultValueList.Parameters, sPropertyName);
|
|
245
|
-
if (oParameter && oParameter.ValueListProperty && oParameter.ValueListProperty.String) {
|
|
246
|
-
sValueListProperty = oParameter.ValueListProperty.String;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Check that the AI-provided value exists in the value-help collection
|
|
251
|
-
var bValueFound = await this._readValueListByEquality(
|
|
252
|
-
oDefaultValueList.CollectionPath.String,
|
|
253
|
-
sValueListProperty,
|
|
254
|
-
vUpdatedValue,
|
|
255
|
-
oObjectPageModel
|
|
256
|
-
);
|
|
257
|
-
|
|
258
|
-
if (!bValueFound) {
|
|
259
|
-
aValidationErrors.push({
|
|
260
|
-
collectionName: sCollectionName,
|
|
261
|
-
collectionLabel: sCollectionLabel,
|
|
262
|
-
rowLabel: sRowLabel,
|
|
263
|
-
rowIndex: oResolvedRow.rowIndex,
|
|
264
|
-
rowPath: oRowContext.getPath && oRowContext.getPath(),
|
|
265
|
-
propertyName: sPropertyName,
|
|
266
|
-
propertyLabel: this._getPropertyLabel(oPropertyMeta) || sPropertyName
|
|
267
|
-
});
|
|
268
|
-
oLogger.warning("validateCollectionUpdatesAgainstValueHelp: invalid value for '" + sPropertyName + "' in row " + oResolvedRow.rowIndex);
|
|
269
|
-
}
|
|
270
|
-
} catch (e) {
|
|
271
|
-
// If metadata or value list cannot be resolved, skip the check and do not block save
|
|
272
|
-
oLogger.warning("validateCollectionUpdatesAgainstValueHelp: could not validate '" + sPropertyName + "': " + (e && e.message));
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return aValidationErrors;
|
|
279
|
-
},
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Updates the EasyFill dialog model to reflect the current table validation state.
|
|
283
|
-
* Sets hasTableValidationErrors and a human-readable summary message (up to 3 errors shown).
|
|
284
|
-
*
|
|
285
|
-
* @param {Array} aValidationErrors - array of validation error objects
|
|
286
|
-
* @param {object} oDialogModel - the easyFillDialogModel JSONModel
|
|
287
|
-
* @param {object} oRb - i18n resource bundle
|
|
288
|
-
*/
|
|
289
|
-
applyTableValidationState: function(aValidationErrors, oDialogModel, oRb) {
|
|
290
|
-
if (!aValidationErrors || aValidationErrors.length === 0) {
|
|
291
|
-
oDialogModel.setProperty("/hasTableValidationErrors", false);
|
|
292
|
-
oDialogModel.setProperty("/tableValidationMessage", "");
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// Show up to 3 errors in the summary message to avoid overwhelming the user
|
|
297
|
-
var sSummary = aValidationErrors.slice(0, 3).map(function(oError) {
|
|
298
|
-
return oError.collectionLabel + " / " + oError.rowLabel + " / " + oError.propertyLabel;
|
|
299
|
-
}).join(", ");
|
|
300
|
-
|
|
301
|
-
oDialogModel.setProperty("/hasTableValidationErrors", true);
|
|
302
|
-
oDialogModel.setProperty(
|
|
303
|
-
"/tableValidationMessage",
|
|
304
|
-
oRb.getText("EASY_FILL_TABLE_VALIDATION_MESSAGE", [sSummary])
|
|
305
|
-
);
|
|
306
|
-
|
|
307
|
-
oLogger.warning("applyTableValidationState: " + aValidationErrors.length + " validation error(s) found");
|
|
191
|
+
// Also return true if there are pending new row contexts
|
|
192
|
+
return Object.keys((oTableStagingState && oTableStagingState.mPendingNewRowContexts) || {}).some(function(sCollectionName) {
|
|
193
|
+
return ((oTableStagingState.mPendingNewRowContexts[sCollectionName]) || []).length > 0;
|
|
194
|
+
});
|
|
308
195
|
},
|
|
309
196
|
|
|
310
197
|
/**
|
|
@@ -321,10 +208,18 @@ sap.ui.define([
|
|
|
321
208
|
* @param {function} fnResetTransientContext - EasyFillFormRenderer.resetTransientContext
|
|
322
209
|
*/
|
|
323
210
|
resetEasyFill: function(bRemoveTextAreaValue, oDialogModel, oController, mCollectionUpdates, oEasyFillLayoutMode, fnRevertStagedUpdates, fnResetTransientContext) {
|
|
324
|
-
//
|
|
325
|
-
var
|
|
326
|
-
|
|
327
|
-
|
|
211
|
+
// Remove dynamically-added table ObjectPageSections from the shared OPL
|
|
212
|
+
var sTableSectionMarker = "easyfillTableSection";
|
|
213
|
+
var oObjectPageLayout = oController.byId("EasyFillObjectPageLayout");
|
|
214
|
+
if (oObjectPageLayout) {
|
|
215
|
+
oObjectPageLayout.getSections().filter(function(oSection) {
|
|
216
|
+
return oSection.getCustomData().some(function(oData) {
|
|
217
|
+
return oData.getKey() === sTableSectionMarker;
|
|
218
|
+
});
|
|
219
|
+
}).forEach(function(oSection) {
|
|
220
|
+
oObjectPageLayout.removeSection(oSection);
|
|
221
|
+
oSection.destroy();
|
|
222
|
+
});
|
|
328
223
|
}
|
|
329
224
|
|
|
330
225
|
// Revert any staged table row values back to original
|
|
@@ -343,11 +238,13 @@ sap.ui.define([
|
|
|
343
238
|
oDialogModel.setProperty("/feedbackPressedDown", false);
|
|
344
239
|
oDialogModel.setProperty("/isFullScreen", true);
|
|
345
240
|
oDialogModel.setProperty("/hasTableUpdates", false);
|
|
346
|
-
oDialogModel.setProperty("/
|
|
347
|
-
oDialogModel.setProperty("/tableValidationMessage", "");
|
|
241
|
+
oDialogModel.setProperty("/attemptedMultipleNewRows", false);
|
|
348
242
|
oDialogModel.setProperty("/easyFillMode", oEasyFillLayoutMode.CondensedMode);
|
|
349
243
|
oDialogModel.setProperty("/llmData", {});
|
|
350
244
|
oDialogModel.setProperty("/sections", []);
|
|
245
|
+
oDialogModel.setProperty("/updatableFields", {});
|
|
246
|
+
oDialogModel.setProperty("/nonUpdatableFields", {});
|
|
247
|
+
oDialogModel.setProperty("/hasNonUpdatableFields", false);
|
|
351
248
|
|
|
352
249
|
// Clear the mutable collection updates map in place
|
|
353
250
|
Object.keys(mCollectionUpdates).forEach(function(sKey) {
|
|
@@ -391,54 +288,6 @@ sap.ui.define([
|
|
|
391
288
|
return null;
|
|
392
289
|
},
|
|
393
290
|
|
|
394
|
-
/**
|
|
395
|
-
* Checks whether a given value exists in a value-help collection via an OData $filter read.
|
|
396
|
-
* Returns true if the value is found or if the read fails (fail-open to not block save unexpectedly).
|
|
397
|
-
*
|
|
398
|
-
* @param {string} sCollectionPath - value-help entity set name
|
|
399
|
-
* @param {string} sValueListProperty - property name in the value-help to filter on
|
|
400
|
-
* @param {*} vValue - the value to look up
|
|
401
|
-
* @param {object} oObjectPageModel - the OData model
|
|
402
|
-
* @returns {Promise<boolean>}
|
|
403
|
-
*/
|
|
404
|
-
_readValueListByEquality: function(sCollectionPath, sValueListProperty, vValue, oObjectPageModel) {
|
|
405
|
-
return new Promise(function(resolve) {
|
|
406
|
-
oObjectPageModel.read("/" + sCollectionPath, {
|
|
407
|
-
filters: [
|
|
408
|
-
new Filter({
|
|
409
|
-
path: sValueListProperty,
|
|
410
|
-
operator: FilterOperator.EQ,
|
|
411
|
-
value1: vValue
|
|
412
|
-
})
|
|
413
|
-
],
|
|
414
|
-
success: function(oResponse) {
|
|
415
|
-
// Value found if the filtered result set is non-empty
|
|
416
|
-
resolve(!!(oResponse && Array.isArray(oResponse.results) && oResponse.results.length > 0));
|
|
417
|
-
},
|
|
418
|
-
error: function() {
|
|
419
|
-
// On error, resolve true to not block save (fail-open)
|
|
420
|
-
resolve(true);
|
|
421
|
-
}
|
|
422
|
-
});
|
|
423
|
-
});
|
|
424
|
-
},
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* Extracts the display label for an OData property.
|
|
428
|
-
* Prefers Common.Label annotation, falls back to sap:label.
|
|
429
|
-
*
|
|
430
|
-
* @param {object} oPropertyMeta - OData property metadata
|
|
431
|
-
* @returns {string|null}
|
|
432
|
-
*/
|
|
433
|
-
_getPropertyLabel: function(oPropertyMeta) {
|
|
434
|
-
if (!oPropertyMeta) { return null; }
|
|
435
|
-
var oLabel = oPropertyMeta["com.sap.vocabularies.Common.v1.Label"];
|
|
436
|
-
if (oLabel && oLabel.String) {
|
|
437
|
-
return oLabel.String;
|
|
438
|
-
}
|
|
439
|
-
return oPropertyMeta["sap:label"] || null;
|
|
440
|
-
},
|
|
441
|
-
|
|
442
291
|
_isEditableProperty: function(oPropertyMeta, oRowObject) {
|
|
443
292
|
if (!oPropertyMeta) {
|
|
444
293
|
return false;
|