@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
|
@@ -2,8 +2,9 @@ sap.ui.define([
|
|
|
2
2
|
"sap/ui/model/json/JSONModel",
|
|
3
3
|
"sap/m/MessageToast",
|
|
4
4
|
"sap/suite/ui/generic/template/genericUtilities/FeLogger",
|
|
5
|
-
"sap/suite/ui/generic/template/genericUtilities/FeError"
|
|
6
|
-
|
|
5
|
+
"sap/suite/ui/generic/template/genericUtilities/FeError",
|
|
6
|
+
"sap/ui/core/ResizeHandler"
|
|
7
|
+
], function(JSONModel, MessageToast, FeLogger, FeError, ResizeHandler) {
|
|
7
8
|
"use strict";
|
|
8
9
|
|
|
9
10
|
var sClassName = "lib.ai.EasyFill.EasyFillDialogController";
|
|
@@ -58,12 +59,15 @@ sap.ui.define([
|
|
|
58
59
|
feedbackPressedDown: false,
|
|
59
60
|
isEasyFillButtonEnabled: false,
|
|
60
61
|
llmData: {},
|
|
62
|
+
updatableFields: {},
|
|
63
|
+
nonUpdatableFields: {},
|
|
64
|
+
hasNonUpdatableFields: false,
|
|
61
65
|
easyFillMode: oEasyFillLayoutMode.CondensedMode,
|
|
62
66
|
sections: [],
|
|
63
67
|
isFullScreen: true,
|
|
64
68
|
hasTableUpdates: false,
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
attemptedMultipleNewRows: false,
|
|
70
|
+
isSplitterPageMode: false
|
|
67
71
|
};
|
|
68
72
|
|
|
69
73
|
oController.getView().setModel(new JSONModel(oData), "easyFillDialogModel");
|
|
@@ -94,6 +98,34 @@ sap.ui.define([
|
|
|
94
98
|
true // use view as parent
|
|
95
99
|
).then(function(oDialog) {
|
|
96
100
|
oDialog.open();
|
|
101
|
+
|
|
102
|
+
// Register a ResizeHandler on the ResponsiveSplitter
|
|
103
|
+
// The dialog is kept alive across opens so we must not register more than once.
|
|
104
|
+
if (!oDialog._easyFillResizeHandlerId) {
|
|
105
|
+
oDialog.attachEventOnce("afterOpen", function() {
|
|
106
|
+
// Locate the splitter by its stable fragment ID
|
|
107
|
+
var oSplitter = oController.byId("EasyFillMainFlex") &&
|
|
108
|
+
oController.byId("EasyFillMainFlex").findAggregatedObjects(true, function(o) {
|
|
109
|
+
return o.isA("sap.ui.layout.ResponsiveSplitter");
|
|
110
|
+
})[0];
|
|
111
|
+
|
|
112
|
+
if (oSplitter) {
|
|
113
|
+
var oDialogModel = oController.getView().getModel("easyFillDialogModel");
|
|
114
|
+
// sapUiRSVisiblePaginator is added/removed by the splitter itself on resize
|
|
115
|
+
oDialog._easyFillResizeHandlerId = ResizeHandler.register(oSplitter, function() {
|
|
116
|
+
var bInPageMode = oSplitter.$().hasClass("sapUiRSVisiblePaginator");
|
|
117
|
+
oDialogModel.setProperty("/isSplitterPageMode", bInPageMode);
|
|
118
|
+
if (bInPageMode && !oDialogModel.getProperty("/isFullScreen")) {
|
|
119
|
+
// Reset fullscreen state so pane sizes are correct when dialog is widened again
|
|
120
|
+
oDialogModel.setProperty("/isFullScreen", true);
|
|
121
|
+
oController.byId("inputAreaSplitPane").getLayoutData().setSize("40%");
|
|
122
|
+
oController.byId("reviewAreaSplitPane").getLayoutData().setSize("60%");
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
97
129
|
oLogger.debug("openDialog: EasyFillDialog opened");
|
|
98
130
|
});
|
|
99
131
|
},
|
|
@@ -107,6 +139,8 @@ sap.ui.define([
|
|
|
107
139
|
var oDialog = oController.byId("EasyFillDialog");
|
|
108
140
|
if (oDialog && oDialog.isOpen()) {
|
|
109
141
|
oDialog.close();
|
|
142
|
+
// Reset page-mode flag so the button is visible on the next open
|
|
143
|
+
oController.getView().getModel("easyFillDialogModel").setProperty("/isSplitterPageMode", false);
|
|
110
144
|
oLogger.debug("closeDialog: EasyFillDialog closed");
|
|
111
145
|
}
|
|
112
146
|
},
|
|
@@ -131,10 +165,19 @@ sap.ui.define([
|
|
|
131
165
|
oController.getOwnerComponent().getEntitySet()
|
|
132
166
|
);
|
|
133
167
|
oDialogModel.setProperty("/easyFillMode", sSelectedKey);
|
|
134
|
-
var oLLMResult = oDialogModel.getProperty("/llmData");
|
|
168
|
+
var oLLMResult = oDialogModel.getProperty("/llmData") || {};
|
|
169
|
+
// Use stored updatable subset when available; fall back to full LLM result
|
|
170
|
+
// only when it is absent (e.g. before the first AI submit).
|
|
171
|
+
// Important: an empty map is a valid state (all fields are non-updatable)
|
|
172
|
+
// and must not trigger fallback, otherwise non-updatable fields appear as filled.
|
|
173
|
+
var oStoredUpdatable = oDialogModel.getProperty("/updatableFields");
|
|
174
|
+
var oUpdatableFields = (oStoredUpdatable !== undefined && oStoredUpdatable !== null)
|
|
175
|
+
? oStoredUpdatable
|
|
176
|
+
: oLLMResult;
|
|
177
|
+
var oNonUpdatableFields = oDialogModel.getProperty("/nonUpdatableFields") || {};
|
|
135
178
|
var aData = (sSelectedKey === oEasyFillLayoutMode.CondensedMode)
|
|
136
|
-
? oFieldCollector.getSectionsForCondensedView(oLLMResult)
|
|
137
|
-
: oFieldCollector.getSectionsForObjectPageView(oEntityType, oLLMResult, oRb);
|
|
179
|
+
? oFieldCollector.getSectionsForCondensedView(oLLMResult, oUpdatableFields, oNonUpdatableFields)
|
|
180
|
+
: oFieldCollector.getSectionsForObjectPageView(oEntityType, oLLMResult, oRb, oNonUpdatableFields);
|
|
138
181
|
oDialogModel.setProperty("/sections", aData);
|
|
139
182
|
},
|
|
140
183
|
|
|
@@ -253,10 +296,14 @@ sap.ui.define([
|
|
|
253
296
|
*/
|
|
254
297
|
formatSectionTitle: function(sTitle, oController) {
|
|
255
298
|
if (!sTitle) { return ""; }
|
|
299
|
+
|
|
300
|
+
var oResourceBundle = oController.getView().getModel("i18n").getResourceBundle();
|
|
301
|
+
|
|
302
|
+
// Handle i18n pattern in title
|
|
256
303
|
var oMatch = sTitle.match(/\{@?i18n>([^}]+)\}/);
|
|
257
304
|
if (oMatch) {
|
|
258
305
|
var sKey = oMatch[1];
|
|
259
|
-
return
|
|
306
|
+
return oResourceBundle.getText(sKey);
|
|
260
307
|
}
|
|
261
308
|
return sTitle;
|
|
262
309
|
},
|
|
@@ -60,7 +60,7 @@ sap.ui.define([
|
|
|
60
60
|
* @param {object} oObjectPage - the ObjectPage control (used to find SmartTables)
|
|
61
61
|
* @param {object} oObjectPageModel - the OData model of the ObjectPage
|
|
62
62
|
* @param {object} oTemplateUtils - FE template utilities (used for PresentationControlHandler)
|
|
63
|
-
* @param {object} mCollectionState - mutable collection state: { mCollectionRowContexts, mCollectionRowContextsByPath, mCollectionProperties, mCollectionEntityTypes }
|
|
63
|
+
* @param {object} mCollectionState - mutable collection state: { mCollectionRowContexts, mCollectionRowContextsByPath, mCollectionProperties, mCollectionEntityTypes, mCollectionEntitySets }
|
|
64
64
|
* @param {function} fnGetLabel - function(oProperty) → string label
|
|
65
65
|
*/
|
|
66
66
|
appendCollectionMap: function(mPropertyMap, oObjectPage, oObjectPageModel, oTemplateUtils, mCollectionState, fnGetLabel) {
|
|
@@ -69,6 +69,8 @@ sap.ui.define([
|
|
|
69
69
|
mCollectionState.mCollectionRowContextsByPath = Object.create(null);
|
|
70
70
|
mCollectionState.mCollectionProperties = Object.create(null);
|
|
71
71
|
mCollectionState.mCollectionEntityTypes = Object.create(null);
|
|
72
|
+
mCollectionState.mCollectionEntitySets = Object.create(null);
|
|
73
|
+
mCollectionState.mCollectionAllowsCreation = Object.create(null);
|
|
72
74
|
|
|
73
75
|
var aSmartTables = this.getObjectPageSmartTables(oObjectPage);
|
|
74
76
|
if (!aSmartTables.length) {
|
|
@@ -154,6 +156,8 @@ sap.ui.define([
|
|
|
154
156
|
mCollectionState.mCollectionRowContextsByPath[sNavProperty] = mRowsByPath;
|
|
155
157
|
mCollectionState.mCollectionProperties[sNavProperty] = mPropertyByName;
|
|
156
158
|
mCollectionState.mCollectionEntityTypes[sNavProperty] = oEntityType;
|
|
159
|
+
mCollectionState.mCollectionEntitySets[sNavProperty] = oEntitySet;
|
|
160
|
+
mCollectionState.mCollectionAllowsCreation[sNavProperty] = this.resolveTableAllowsCreation(oSmartTable);
|
|
157
161
|
|
|
158
162
|
// Add collection entry to the LLM field mapping
|
|
159
163
|
mPropertyMap[sNavProperty] = {
|
|
@@ -177,9 +181,10 @@ sap.ui.define([
|
|
|
177
181
|
* @param {object} oAiCallResult - flat map of { fieldName: aiValue } from the LLM
|
|
178
182
|
* @param {object} oEntityType - OData entity type metadata
|
|
179
183
|
* @param {object} oObjectPageContext - current ObjectPage binding context
|
|
184
|
+
* @param {object} oEntitySet - OData entity set metadata (for entity-set-level sap:updatable checks)
|
|
180
185
|
* @returns {{ updatableFields: object, nonUpdatableFields: object }}
|
|
181
186
|
*/
|
|
182
|
-
getUpdatableAndNonUpdatableFields: function(oAiCallResult, oEntityType, oObjectPageContext) {
|
|
187
|
+
getUpdatableAndNonUpdatableFields: function(oAiCallResult, oEntityType, oObjectPageContext, oEntitySet) {
|
|
183
188
|
var updatableFields = {};
|
|
184
189
|
var nonUpdatableFields = {};
|
|
185
190
|
|
|
@@ -195,7 +200,7 @@ sap.ui.define([
|
|
|
195
200
|
nonUpdatableFields[sKey] = oAiCallResult[sKey];
|
|
196
201
|
return;
|
|
197
202
|
}
|
|
198
|
-
if (this.isEditable(oProperty, oObjectPageContext)) {
|
|
203
|
+
if (this.isEditable(oProperty, oObjectPageContext, oEntitySet)) {
|
|
199
204
|
updatableFields[sKey] = oAiCallResult[sKey];
|
|
200
205
|
} else {
|
|
201
206
|
nonUpdatableFields[sKey] = oAiCallResult[sKey];
|
|
@@ -250,18 +255,19 @@ sap.ui.define([
|
|
|
250
255
|
* Checks whether a property is editable based on OData annotations.
|
|
251
256
|
* Uses the current ObjectPage context object for dynamic field-control checks.
|
|
252
257
|
*
|
|
253
|
-
* Priority: sap:updatable → FieldControl (EnumMember) → sap:field-control (dynamic value)
|
|
258
|
+
* Priority: entity-set-level sap:updatable → property sap:updatable → FieldControl (EnumMember) → sap:field-control (dynamic value)
|
|
254
259
|
*
|
|
255
260
|
* Field control values:
|
|
256
261
|
* 0 = Hidden, 1 = ReadOnly, 3 = Editable, 7 = Mandatory (editable)
|
|
257
262
|
*
|
|
258
263
|
* @param {object} oProperty - OData property metadata
|
|
259
264
|
* @param {object} oObjectPageContext - current ObjectPage binding context
|
|
265
|
+
* @param {object} oEntitySet - optional OData entity set metadata (for entity-set-level checks)
|
|
260
266
|
* @returns {boolean}
|
|
261
267
|
*/
|
|
262
|
-
isEditable: function(oProperty, oObjectPageContext) {
|
|
268
|
+
isEditable: function(oProperty, oObjectPageContext, oEntitySet) {
|
|
263
269
|
var oContextObject = oObjectPageContext && oObjectPageContext.getObject && oObjectPageContext.getObject();
|
|
264
|
-
return this.isEditableByContextObject(oProperty, oContextObject);
|
|
270
|
+
return this.isEditableByContextObject(oProperty, oContextObject, oEntitySet);
|
|
265
271
|
},
|
|
266
272
|
|
|
267
273
|
/**
|
|
@@ -270,14 +276,31 @@ sap.ui.define([
|
|
|
270
276
|
*
|
|
271
277
|
* @param {object} oProperty - OData property metadata
|
|
272
278
|
* @param {object} oContextObject - plain JS object of the current row/entity data
|
|
279
|
+
* @param {object} oEntitySet - optional OData entity set metadata (for entity-set-level checks)
|
|
273
280
|
* @returns {boolean}
|
|
274
281
|
*/
|
|
275
|
-
isEditableByContextObject: function(oProperty, oContextObject) {
|
|
282
|
+
isEditableByContextObject: function(oProperty, oContextObject, oEntitySet) {
|
|
276
283
|
if (!oProperty) {
|
|
277
284
|
return false;
|
|
278
285
|
}
|
|
279
286
|
|
|
280
|
-
// Check sap:updatable
|
|
287
|
+
// Check entity-set-level sap:updatable (entire entity set is read-only)
|
|
288
|
+
if (oEntitySet) {
|
|
289
|
+
var sEntitySetUpdatable = oEntitySet["sap:updatable"];
|
|
290
|
+
if (sEntitySetUpdatable === "false") {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
// sap:updatable-path: resolved against the context object (boolean property)
|
|
294
|
+
var sEntitySetUpdatablePath = oEntitySet["sap:updatable-path"];
|
|
295
|
+
if (sEntitySetUpdatablePath && oContextObject) {
|
|
296
|
+
var bUpdatableFromPath = oContextObject[sEntitySetUpdatablePath];
|
|
297
|
+
if (bUpdatableFromPath === false || bUpdatableFromPath === "false") {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Check sap:updatable — static annotation on the property
|
|
281
304
|
var sUpdatable = oProperty["sap:updatable"];
|
|
282
305
|
if (sUpdatable) {
|
|
283
306
|
return sUpdatable !== "false";
|
|
@@ -304,32 +327,101 @@ sap.ui.define([
|
|
|
304
327
|
|
|
305
328
|
/**
|
|
306
329
|
* Builds a flat section tree for the Condensed view mode.
|
|
307
|
-
*
|
|
330
|
+
* Creates two sections: "Filled Fields" (updatable) and "Unfilled Fields" (non-updatable).
|
|
308
331
|
*
|
|
309
332
|
* @param {object} oLLMResult - flat map of { fieldName: value } from the LLM
|
|
333
|
+
* @param {object} oUpdatableFields - flat map of updatable fields only
|
|
334
|
+
* @param {object} oNonUpdatableFields - flat map of non-updatable fields only
|
|
310
335
|
* @returns {Array} section tree array
|
|
311
336
|
*/
|
|
312
|
-
getSectionsForCondensedView: function(oLLMResult) {
|
|
313
|
-
|
|
337
|
+
getSectionsForCondensedView: function(oLLMResult, oUpdatableFields, oNonUpdatableFields) {
|
|
338
|
+
var aUpdatableKeys = Object.keys(oUpdatableFields || {});
|
|
339
|
+
var aNonUpdatableKeys = Object.keys(oNonUpdatableFields || {});
|
|
340
|
+
var aSections = [];
|
|
341
|
+
// Section 1: Filled Fields (updatable)
|
|
342
|
+
if (aUpdatableKeys.length > 0) {
|
|
343
|
+
aSections.push({
|
|
344
|
+
title: "{@i18n>EASY_FILL_FILLED_FIELDS}",
|
|
345
|
+
fields: [],
|
|
346
|
+
children: [{
|
|
347
|
+
title: "",
|
|
348
|
+
fields: aUpdatableKeys,
|
|
349
|
+
id: this._generateId("filledFields", aUpdatableKeys)
|
|
350
|
+
}]
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Section 2: Unfilled Fields (non-updatable/read-only)
|
|
355
|
+
if (aNonUpdatableKeys.length > 0) {
|
|
356
|
+
aSections.push({
|
|
357
|
+
title: "{@i18n>EASY_FILL_UNFILLED_FIELDS}",
|
|
358
|
+
fields: [],
|
|
359
|
+
children: [{
|
|
360
|
+
title: "",
|
|
361
|
+
fields: aNonUpdatableKeys,
|
|
362
|
+
id: this._generateId("unfilledFields", aNonUpdatableKeys)
|
|
363
|
+
}]
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Fallback: if no split provided, use old behavior
|
|
368
|
+
if (aSections.length === 0) {
|
|
369
|
+
return this._transformToTreeExpanded(oLLMResult);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return aSections;
|
|
314
373
|
},
|
|
315
374
|
|
|
316
375
|
/**
|
|
317
376
|
* Builds a structured section tree for the ObjectPage view mode.
|
|
318
377
|
* Mirrors the ObjectPage section/facet structure and filters to only include
|
|
319
|
-
* fields returned by the LLM.
|
|
378
|
+
* updatable fields returned by the LLM. Non-updatable (read-only) fields are
|
|
379
|
+
* excluded from the annotation sections and shown exclusively in the
|
|
380
|
+
* "Unfilled Fields" section appended at the end.
|
|
320
381
|
*
|
|
321
382
|
* @param {object} oEntityType - OData entity type metadata
|
|
322
383
|
* @param {object} oLLMResult - flat map of { fieldName: value } from the LLM
|
|
323
384
|
* @param {object} oRb - i18n resource bundle
|
|
385
|
+
* @param {object} oNonUpdatableFields - flat map of non-updatable fields only (optional)
|
|
324
386
|
* @returns {Array} filtered section tree array
|
|
325
387
|
*/
|
|
326
|
-
getSectionsForObjectPageView: function(oEntityType, oLLMResult, oRb) {
|
|
388
|
+
getSectionsForObjectPageView: function(oEntityType, oLLMResult, oRb, oNonUpdatableFields) {
|
|
327
389
|
var aSections = [];
|
|
328
390
|
aSections = aSections
|
|
329
391
|
.concat(this._getSectionsForHeader(oEntityType, oRb))
|
|
330
392
|
.concat(this._getSectionsForObjectPageFacets(oEntityType));
|
|
331
393
|
var aTree = this._transformToTree(aSections);
|
|
332
|
-
|
|
394
|
+
|
|
395
|
+
// Annotation sections must only show updatable fields.
|
|
396
|
+
// Derive the updatable-only subset by removing non-updatable keys from oLLMResult
|
|
397
|
+
// so non-updatable fields do not appear in both annotation sections AND Unfilled Fields.
|
|
398
|
+
var aNonUpdatableSet = Object.keys(oNonUpdatableFields || {});
|
|
399
|
+
var oUpdatableResult = Object.keys(oLLMResult).reduce(function(oAcc, sKey) {
|
|
400
|
+
if (aNonUpdatableSet.indexOf(sKey) === -1) {
|
|
401
|
+
oAcc[sKey] = oLLMResult[sKey];
|
|
402
|
+
}
|
|
403
|
+
return oAcc;
|
|
404
|
+
}, {});
|
|
405
|
+
var aFilteredTree = this._filterTreeByLLMResult(aTree, oUpdatableResult);
|
|
406
|
+
aFilteredTree = this._flattenTreeForObjectPageDialog(aFilteredTree);
|
|
407
|
+
|
|
408
|
+
// "Unfilled Fields" contains only non-updatable (read-only) fields.
|
|
409
|
+
// Editable fields that have no annotation section are silently dropped here —
|
|
410
|
+
// they already appear in their respective annotation-matched sections above.
|
|
411
|
+
var aNonUpdatableKeys = Object.keys(oNonUpdatableFields || {});
|
|
412
|
+
if (aNonUpdatableKeys.length > 0) {
|
|
413
|
+
aFilteredTree.push({
|
|
414
|
+
title: "{@i18n>EASY_FILL_UNFILLED_FIELDS}",
|
|
415
|
+
fields: [],
|
|
416
|
+
children: [{
|
|
417
|
+
title: "",
|
|
418
|
+
fields: aNonUpdatableKeys,
|
|
419
|
+
id: this._generateId("unfilledFields", aNonUpdatableKeys)
|
|
420
|
+
}]
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return aFilteredTree;
|
|
333
425
|
},
|
|
334
426
|
|
|
335
427
|
// ─── SmartTable Utilities ─────────────────────────────────────────────────
|
|
@@ -375,6 +467,49 @@ sap.ui.define([
|
|
|
375
467
|
};
|
|
376
468
|
},
|
|
377
469
|
|
|
470
|
+
/**
|
|
471
|
+
* Determines whether a SmartTable supports creation of new rows via inline mode.
|
|
472
|
+
* Supports "inline" createMode (with an enabled Create toolbar button) and
|
|
473
|
+
* "creationRows" / "creationRowsHiddenInEditMode" createMode (InlineCreationRows).
|
|
474
|
+
*
|
|
475
|
+
* @param {object} oSmartTable - sap.ui.comp.smarttable.SmartTable control
|
|
476
|
+
* @returns {boolean} true if new rows can be created for this table
|
|
477
|
+
*/
|
|
478
|
+
resolveTableAllowsCreation: function(oSmartTable) {
|
|
479
|
+
var sCreateMode = oSmartTable.data("creationMode");
|
|
480
|
+
var bIsInlineCreationRows = sCreateMode === "creationRows" || sCreateMode === "creationRowsHiddenInEditMode";
|
|
481
|
+
var bIsInline = sCreateMode === "inline";
|
|
482
|
+
|
|
483
|
+
if (bIsInlineCreationRows) {
|
|
484
|
+
return true;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (bIsInline) {
|
|
488
|
+
// Inline create requires the Create toolbar button to be enabled
|
|
489
|
+
var oTable = oSmartTable.getTable && oSmartTable.getTable();
|
|
490
|
+
if (!oTable) {
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
var oToolbar = oSmartTable.getCustomToolbar && oSmartTable.getCustomToolbar();
|
|
494
|
+
if (!oToolbar) {
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
var aButtons = oToolbar.getContent && oToolbar.getContent();
|
|
498
|
+
if (!Array.isArray(aButtons)) {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
var oCreateButton = aButtons.find(function(oControl) {
|
|
502
|
+
return oControl.isA && oControl.isA("sap.m.Button") &&
|
|
503
|
+
typeof oControl.getId === "function" &&
|
|
504
|
+
oControl.getId().indexOf("add") >= 0 &&
|
|
505
|
+
oControl.getEnabled && oControl.getEnabled();
|
|
506
|
+
});
|
|
507
|
+
return !!oCreateButton;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
return false;
|
|
511
|
+
},
|
|
512
|
+
|
|
378
513
|
// ─── Private Helpers ─────────────────────────────────────────────────────
|
|
379
514
|
|
|
380
515
|
/**
|
|
@@ -482,23 +617,23 @@ sap.ui.define([
|
|
|
482
617
|
|
|
483
618
|
/**
|
|
484
619
|
* Filters a section tree to only include nodes that contain at least one LLM-returned field.
|
|
485
|
-
* Fields
|
|
620
|
+
* Fields with no matching annotation section are silently dropped; the caller is responsible
|
|
621
|
+
* for surfacing them elsewhere (e.g. the "unfilledFields" section for non-updatable fields).
|
|
622
|
+
*
|
|
623
|
+
* @param {Array} aTree - section tree
|
|
624
|
+
* @param {object} oLLMResult - flat map of all LLM fields
|
|
625
|
+
* @returns {Array} filtered tree
|
|
486
626
|
* @private
|
|
487
627
|
*/
|
|
488
628
|
_filterTreeByLLMResult: function(aTree, oLLMResult) {
|
|
489
629
|
var aRequestedKeys = Object.keys(oLLMResult);
|
|
490
|
-
var aMatchedKeys = new Set();
|
|
491
630
|
var that = this;
|
|
492
631
|
|
|
493
632
|
function filterNode(oNode, sParentPath) {
|
|
494
633
|
var sTitlePath = sParentPath ? (sParentPath + "_" + oNode.title) : oNode.title;
|
|
495
634
|
|
|
496
635
|
var aFilteredFields = oNode.fields.filter(function(sField) {
|
|
497
|
-
|
|
498
|
-
aMatchedKeys.add(sField);
|
|
499
|
-
return true;
|
|
500
|
-
}
|
|
501
|
-
return false;
|
|
636
|
+
return aRequestedKeys.includes(sField);
|
|
502
637
|
});
|
|
503
638
|
|
|
504
639
|
var aFilteredChildren = oNode.children
|
|
@@ -513,22 +648,58 @@ sap.ui.define([
|
|
|
513
648
|
};
|
|
514
649
|
}
|
|
515
650
|
|
|
516
|
-
|
|
651
|
+
return aTree
|
|
517
652
|
.map(function(oNode) { return filterNode(oNode, ""); })
|
|
518
653
|
.filter(function(oNode) { return oNode.fields.length > 0 || oNode.children.length > 0; });
|
|
654
|
+
},
|
|
519
655
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
656
|
+
/**
|
|
657
|
+
* Flattens nested ObjectPage section trees to one group level expected by the dialog fragment.
|
|
658
|
+
*
|
|
659
|
+
* EasyFill dialog binds SmartForm groups only to section.children (one level deep).
|
|
660
|
+
* If annotation facets produce deeper nesting, section titles can render while fields remain
|
|
661
|
+
* invisible because grandchildren are never bound as groups.
|
|
662
|
+
*
|
|
663
|
+
* @param {Array} aTree - filtered section tree
|
|
664
|
+
* @returns {Array} dialog-compatible tree with one-level children per section
|
|
665
|
+
* @private
|
|
666
|
+
*/
|
|
667
|
+
_flattenTreeForObjectPageDialog: function(aTree) {
|
|
668
|
+
var that = this;
|
|
669
|
+
|
|
670
|
+
function collectRenderableGroups(oNode, sParentPath) {
|
|
671
|
+
var sTitlePath = sParentPath ? (sParentPath + "_" + oNode.title) : oNode.title;
|
|
672
|
+
var aGroups = [];
|
|
673
|
+
|
|
674
|
+
if (Array.isArray(oNode.fields) && oNode.fields.length > 0) {
|
|
675
|
+
aGroups.push({
|
|
676
|
+
title: oNode.title,
|
|
677
|
+
id: that._generateId(sTitlePath, oNode.fields),
|
|
678
|
+
fields: oNode.fields,
|
|
679
|
+
children: []
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
if (Array.isArray(oNode.children) && oNode.children.length > 0) {
|
|
684
|
+
oNode.children.forEach(function(oChild) {
|
|
685
|
+
aGroups = aGroups.concat(collectRenderableGroups(oChild, sTitlePath));
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return aGroups;
|
|
529
690
|
}
|
|
530
691
|
|
|
531
|
-
return
|
|
692
|
+
return (aTree || []).map(function(oSection) {
|
|
693
|
+
var sSectionPath = oSection.title || "";
|
|
694
|
+
return {
|
|
695
|
+
title: oSection.title,
|
|
696
|
+
id: oSection.id,
|
|
697
|
+
fields: [],
|
|
698
|
+
children: collectRenderableGroups(oSection, sSectionPath)
|
|
699
|
+
};
|
|
700
|
+
}).filter(function(oSection) {
|
|
701
|
+
return Array.isArray(oSection.children) && oSection.children.length > 0;
|
|
702
|
+
});
|
|
532
703
|
},
|
|
533
704
|
|
|
534
705
|
/**
|
|
@@ -638,12 +809,14 @@ sap.ui.define([
|
|
|
638
809
|
// FieldGroup / Form — iterate Data array
|
|
639
810
|
oAnnotation.Data.forEach(function(oData) {
|
|
640
811
|
if (!this._isSupportedRecordType(oData.RecordType)) { return; }
|
|
812
|
+
if (!oData.Value || !oData.Value.Path) { return; }
|
|
641
813
|
aRes.push({ title: aTempText, property: oData.Value.Path });
|
|
642
814
|
}.bind(this));
|
|
643
815
|
} else if (Array.isArray(oAnnotation)) {
|
|
644
816
|
// LineItem — iterate annotation array directly
|
|
645
817
|
oAnnotation.forEach(function(oAnno) {
|
|
646
818
|
if (!this._isSupportedRecordType(oAnno.RecordType)) { return; }
|
|
819
|
+
if (!oAnno.Value || !oAnno.Value.Path) { return; }
|
|
647
820
|
aRes.push({ title: aTempText, property: oAnno.Value.Path });
|
|
648
821
|
}.bind(this));
|
|
649
822
|
} else if (oAnnotation.Value && oAnnotation.Value.Path) {
|
|
@@ -658,12 +831,18 @@ sap.ui.define([
|
|
|
658
831
|
/**
|
|
659
832
|
* Returns false for record types that EasyFill does not support rendering.
|
|
660
833
|
* Currently excludes: IntentBasedNavigation, ForAnnotation, ForAction.
|
|
834
|
+
* Handles both fully-qualified names (com.sap.vocabularies.UI.v1.*) and
|
|
835
|
+
* alias form (UI.*) that OData metadata can return depending on the service.
|
|
661
836
|
* @private
|
|
662
837
|
*/
|
|
663
838
|
_isSupportedRecordType: function(sRecordType) {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
839
|
+
if (!sRecordType) { return false; }
|
|
840
|
+
var sNormalized = sRecordType.replace("com.sap.vocabularies.UI.v1.", "UI.");
|
|
841
|
+
return sNormalized !== "UI.DataFieldForIntentBasedNavigation" &&
|
|
842
|
+
sNormalized !== "UI.DataFieldForAnnotation" &&
|
|
843
|
+
sNormalized !== "UI.DataFieldForAction" &&
|
|
844
|
+
sNormalized !== "UI.DataFieldWithNavigationPath" &&
|
|
845
|
+
sNormalized !== "UI.DataFieldWithIntentBasedNavigation";
|
|
667
846
|
}
|
|
668
847
|
};
|
|
669
848
|
});
|