@sapui5/sap.suite.ui.generic.template 1.139.0 → 1.139.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.
Files changed (20) hide show
  1. package/package.json +1 -1
  2. package/src/sap/suite/ui/generic/template/.library +1 -1
  3. package/src/sap/suite/ui/generic/template/AnalyticalListPage/manifest.json +1 -1
  4. package/src/sap/suite/ui/generic/template/Canvas/manifest.json +1 -1
  5. package/src/sap/suite/ui/generic/template/ListReport/manifest.json +1 -1
  6. package/src/sap/suite/ui/generic/template/ObjectPage/controller/ControllerImplementation.js +1 -0
  7. package/src/sap/suite/ui/generic/template/ObjectPage/controller/RelatedAppsHandler.js +2 -0
  8. package/src/sap/suite/ui/generic/template/ObjectPage/controller/SectionTitleHandler.js +17 -13
  9. package/src/sap/suite/ui/generic/template/ObjectPage/controllerFrameworkExtensions.js +285 -270
  10. package/src/sap/suite/ui/generic/template/ObjectPage/manifest.json +1 -1
  11. package/src/sap/suite/ui/generic/template/ObjectPage/view/fragments/SmartForm.fragment.xml +2 -1
  12. package/src/sap/suite/ui/generic/template/QuickCreate/manifest.json +1 -1
  13. package/src/sap/suite/ui/generic/template/QuickView/manifest.json +1 -1
  14. package/src/sap/suite/ui/generic/template/js/AnnotationHelper.js +81 -0
  15. package/src/sap/suite/ui/generic/template/lib/AppComponent.js +16 -2
  16. package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterBarHandler.js +44 -198
  17. package/src/sap/suite/ui/generic/template/lib/ai/EasyFilterDataFetcherHelper.js +334 -0
  18. package/src/sap/suite/ui/generic/template/lib/navigation/NavigationController.js +6 -1
  19. package/src/sap/suite/ui/generic/template/lib/presentationControl/SmartTableHandler.js +1 -1
  20. package/src/sap/suite/ui/generic/template/library.js +1 -1
@@ -0,0 +1,334 @@
1
+ sap.ui.define([
2
+ 'sap/ui/model/FilterOperator',
3
+ 'sap/ui/model/Filter',
4
+ 'sap/suite/ui/generic/template/js/AnnotationHelper'
5
+ ], function(FilterOperator, Filter, AnnotationHelper) {
6
+ 'use strict';
7
+
8
+ const mReverseOperator = {};
9
+ fillReverseOperator();
10
+
11
+ function fillReverseOperator() {
12
+ mReverseOperator[FilterOperator.EQ] = FilterOperator.NE;
13
+ mReverseOperator[FilterOperator.Contains] = FilterOperator.NotContains;
14
+ mReverseOperator[FilterOperator.EndsWith] = FilterOperator.NotEndsWith;
15
+ mReverseOperator[FilterOperator.StartsWith] = FilterOperator.NotStartsWith;
16
+ mReverseOperator[FilterOperator.BT] = FilterOperator.NB;
17
+
18
+ mReverseOperator[FilterOperator.NE] = FilterOperator.EQ;
19
+ mReverseOperator[FilterOperator.NotContains] = FilterOperator.Contains;
20
+ mReverseOperator[FilterOperator.NotEndsWith] = FilterOperator.EndsWith;
21
+ mReverseOperator[FilterOperator.NotStartsWith] = FilterOperator.StartsWith;
22
+ mReverseOperator[FilterOperator.NB] = FilterOperator.BT;
23
+ }
24
+
25
+ function getFiltersForDataFetching(sKey, keySpecificSelectedResult) {
26
+ const aFilters = [];
27
+
28
+ for (let i = 0; i < keySpecificSelectedResult.length; ++i) {
29
+ const result = keySpecificSelectedResult[i];
30
+ if (result.operator === FilterOperator.BT || result.operator === FilterOperator.NB) {
31
+ aFilters.push(new Filter({
32
+ path: sKey,
33
+ operator: result.operator,
34
+ value1: result.selectedValues[0],
35
+ value2: result.selectedValues[1]
36
+ }));
37
+ } else {
38
+ for (let j = 0; j < result.selectedValues.length; ++j) {
39
+ aFilters.push(new Filter({
40
+ path: sKey,
41
+ operator: result.operator,
42
+ value1: result.selectedValues[j]
43
+ }));
44
+ }
45
+ }
46
+ }
47
+ return aFilters;
48
+ }
49
+
50
+ function isComparitveOperator(sFilter) {
51
+ return sFilter === FilterOperator.BT || sFilter === FilterOperator.NB ||
52
+ sFilter === FilterOperator.GT || sFilter === FilterOperator.LT ||
53
+ sFilter === FilterOperator.GE || sFilter === FilterOperator.LE;
54
+ }
55
+
56
+ function isNegationOperator(sOperator) {
57
+ return sOperator === FilterOperator.NE || sOperator === FilterOperator.NotContains ||
58
+ sOperator === FilterOperator.NotEndsWith || sOperator === FilterOperator.NotStartsWith ||
59
+ sOperator === FilterOperator.NB;
60
+ }
61
+
62
+ function getkeySpecifiedResultFromFilters(oFilter) {
63
+ let values = [];
64
+ if (oFilter.getOperator() === FilterOperator.BT || oFilter.getOperator() === FilterOperator.NB) {
65
+ values = [{
66
+ value: oFilter.getValue1(),
67
+ description: oFilter.getValue1()
68
+ },{
69
+ value: oFilter.getValue2(),
70
+ description: oFilter.getValue2()
71
+ }];
72
+ } else {
73
+ values.push({
74
+ value: oFilter.getValue1(),
75
+ description: oFilter.getValue1()
76
+ });
77
+ }
78
+ return {
79
+ operator: oFilter.getOperator(),
80
+ selectedValues: values
81
+ };
82
+ }
83
+
84
+ async function fetchRecordsFromValueList(oValueList, oFilter, sKey, oSFBModel,oTemplateUtils) {
85
+ return new Promise((resolve, reject) => {
86
+ let oValueListDefaultBinding = oValueList[""];
87
+ let sValueListEntity = oValueListDefaultBinding.CollectionPath.String;
88
+
89
+ if (Array.isArray(oValueListDefaultBinding.Parameters)) {
90
+ let oParameter = oValueListDefaultBinding.Parameters.find(oParam => (oParam.RecordType === "com.sap.vocabularies.Common.v1.ValueListParameterInOut" && oParam.LocalDataProperty.PropertyPath === sKey));
91
+ if (oParameter) {
92
+ sKey = oParameter.ValueListProperty.String;
93
+ }
94
+ }
95
+
96
+ let bIsNotOperator = isNegationOperator(oFilter.getOperator());
97
+ if (bIsNotOperator) {
98
+ oFilter = new Filter({
99
+ path: sKey,
100
+ operator: mReverseOperator[oFilter.getOperator()],
101
+ value1: oFilter.getValue1()
102
+ });
103
+ } else {
104
+ oFilter = new Filter({
105
+ path: sKey,
106
+ operator: oFilter.getOperator(),
107
+ value1: oFilter.getValue1()
108
+ });
109
+ }
110
+
111
+ oSFBModel.read("/" + sValueListEntity, {
112
+ filters: [oFilter],
113
+ success: async function(oResponse) {
114
+ const aResults = oResponse.results;
115
+ let aResponse;
116
+ try {
117
+ if (aResults.length > 0) {
118
+ aResponse = await getDescriptionForResponse(oResponse.results, sValueListEntity, sKey, oSFBModel,oTemplateUtils,oFilter);
119
+ } else {
120
+ aResponse = await fetchRecordsFromValueListUsingFuzzySearch(sValueListEntity, oFilter, sKey, oSFBModel,oTemplateUtils);
121
+ }
122
+ resolve({
123
+ operator: (bIsNotOperator) ? mReverseOperator[oFilter.getOperator()] : oFilter.getOperator(),
124
+ selectedValues: aResponse
125
+ });
126
+ } catch (error) {
127
+ reject(error);
128
+ }
129
+ },
130
+ error: async function(oError) {
131
+ //If the error is because of some property validation, we can try to do a fuzzy search
132
+ try {
133
+ const aResponse = await fetchRecordsFromValueListUsingFuzzySearch(sValueListEntity, oFilter, sKey, oSFBModel,oTemplateUtils);
134
+ resolve({
135
+ operator: (bIsNotOperator) ? mReverseOperator[oFilter.getOperator()] : oFilter.getOperator(),
136
+ selectedValues: aResponse
137
+ });
138
+ } catch (error) {
139
+ reject(error);
140
+ }
141
+ }
142
+ });
143
+ });
144
+ }
145
+
146
+ async function fetchRecordsFromValueListUsingFuzzySearch(sValueListEntity, oFilter, sKey, oSFBModel,oTemplateUtils) {
147
+ return new Promise((resolve, reject) => {
148
+ oSFBModel.read("/" + sValueListEntity, {
149
+ urlParameters: {
150
+ search: oFilter.getValue1()
151
+ },
152
+ success: async function(oResponse) {
153
+ let aResults = oResponse.results;
154
+ if (aResults.length == 0) {
155
+ //If it dosent have any records, the return the original value
156
+ resolve([{
157
+ value: oFilter.getValue1(),
158
+ description: oFilter.getValue1()
159
+ }]);
160
+ } else {
161
+ try {
162
+ aResults = await getDescriptionForResponse(aResults, sValueListEntity, sKey, oSFBModel,oTemplateUtils,oFilter);
163
+ resolve(aResults);
164
+ } catch (oError) {
165
+ reject(oError);
166
+ }
167
+ }
168
+ },
169
+ error: function(oError) {
170
+ reject(oError);
171
+ }
172
+ });
173
+ });
174
+ }
175
+
176
+ function performClientSideSearch(aResults, oFilter,sKey,sDescriptionField) {
177
+ if (!sKey || !sDescriptionField) {
178
+ return aResults;
179
+ }
180
+ if (oFilter.getOperator() === FilterOperator.EQ || oFilter.getOperator() === FilterOperator.NE) {
181
+ const aFilteredResults = aResults.filter(result => result[sKey].toString().toLowerCase() === oFilter.getValue1().toString().toLowerCase() || result[sDescriptionField].toString().toLowerCase() === oFilter.getValue1().toString().toLowerCase());
182
+ return aFilteredResults.length > 0 ? aFilteredResults : aResults;
183
+ }
184
+ return aResults;
185
+ }
186
+
187
+ async function getDescriptionForResponse(aResults, sValueListEntity, sKey, oSFBModel, oTemplateUtils,oFilter) {
188
+ return new Promise((resolve, reject) => {
189
+ const aResultsWithTextArrangement = [];
190
+
191
+ let oSFBMetaModel = oSFBModel.getMetaModel();
192
+ let oValueHelpEntity = oTemplateUtils.oCommonUtils.getMetaModelEntityType(sValueListEntity);
193
+ let oValueHelpProperty = oSFBMetaModel.getODataProperty(oValueHelpEntity, sKey);
194
+ let sTextArrangementPath = AnnotationHelper.getTextArrangementPath(oValueHelpProperty);
195
+ let sTextArrangement = AnnotationHelper.getTextArrangementForEasyFilter(oValueHelpEntity, oValueHelpProperty);
196
+ let navigationProperty = null;
197
+ let sEntityForTextDescription = sValueListEntity;
198
+
199
+ if (sTextArrangementPath && sTextArrangementPath.split("/").length > 1) {
200
+ navigationProperty = sTextArrangementPath.split("/")[0];
201
+ sEntityForTextDescription = oSFBMetaModel.getODataAssociationSetEnd(oValueHelpEntity, navigationProperty).entitySet;
202
+ sTextArrangementPath = sTextArrangementPath.split("/")[1];
203
+ }
204
+
205
+ aResults = performClientSideSearch(aResults, oFilter,sKey,sTextArrangementPath);
206
+
207
+ if (sValueListEntity === sEntityForTextDescription) {
208
+ aResults.forEach((result) => {
209
+ aResultsWithTextArrangement.push({
210
+ value: result[sKey],
211
+ description: AnnotationHelper.getTextArrangementFinalString(result, sKey, sTextArrangementPath, sTextArrangement)
212
+ });
213
+ });
214
+ resolve(aResultsWithTextArrangement);
215
+ } else {
216
+ let aAllMatchedResults = aResults.map((result) => {
217
+ return result[sKey];
218
+ });
219
+ let aMatchedFilterResults = aAllMatchedResults.map((matchedResult) => {
220
+ return new Filter({
221
+ path: sKey,
222
+ operator: FilterOperator.EQ,
223
+ value1: matchedResult
224
+ });
225
+ });
226
+
227
+ // The below code only be executed when the textDescription and ValueList entities are different
228
+ oSFBModel.read("/" + sEntityForTextDescription, {
229
+ filters: aMatchedFilterResults,
230
+ success: function(oResponse) {
231
+ let aResults = oResponse.results;
232
+
233
+ aMatchedFilterResults.forEach((oFilter) => {
234
+ let result = aResults.find((res) => res[sKey] === oFilter.getValue1());
235
+ aResultsWithTextArrangement.push({
236
+ value: oFilter.getValue1(),
237
+ description: (result) ? AnnotationHelper.getTextArrangementFinalString(result, sKey, sTextArrangementPath, sTextArrangement) : oFilter.getValue1()
238
+ });
239
+ });
240
+ resolve(aResultsWithTextArrangement);
241
+ },
242
+ error: function(oError) {
243
+ reject(oError);
244
+ }
245
+ });
246
+ }
247
+ });
248
+ }
249
+
250
+ /**
251
+ * The primary responsibility of this function is to convert the given values into their corresponding
252
+ * IDs and Descriptions, respecting the defined TextArrangement.
253
+ *
254
+ * This process is carried out in two phases:
255
+ *
256
+ * Fetching the ID:
257
+ * 1) Make a $filter call using the provided value and operator.
258
+ * - If this returns results, we proceed to fetch the corresponding descriptions for these IDs.
259
+ * 2) If no results are returned, make a $search (fuzzy search) call instead.
260
+ *
261
+ * Fetching the Description:
262
+ * 1) The description is determined by the sap:text/com.sap.vocabularies.UI.v1.TextArrangement
263
+ * annotation of the ValueHelp entity, not from the main entity.
264
+ * 2) To fetch the description, we use a $filter call, since the IDs were already retrieved in the first step.
265
+ *
266
+ * Edge cases with negation operators:
267
+ * 1) For negation operators such as NB, NotStartsWith, etc., we make a batch call using the
268
+ * positive equivalent of these operators (e.g., BT, StartsWith).
269
+ * 2) After receiving the results, we return them with the original negation operator
270
+ * (e.g., NB, NotStartsWith).
271
+ */
272
+
273
+ function fetchDataForKey(sKey, keySpecificSelectedResult, oState, oController, oTemplateUtils) {
274
+ return new Promise(async(resolve, reject) => {
275
+ try {
276
+ const aFinalResponse = [];
277
+ const oOwnerFilterControl = oState.oSmartFilterbar;
278
+ const sEntitySet = oController.getOwnerComponent().getEntitySet();
279
+ const oEntityType = oTemplateUtils.oCommonUtils.getMetaModelEntityType(sEntitySet);
280
+ const oSFBModel = oOwnerFilterControl.getModel();
281
+ const oSFBMetaModel = oSFBModel.getMetaModel();
282
+ const aFilters = getFiltersForDataFetching(sKey, keySpecificSelectedResult);
283
+ const oProperty = oSFBMetaModel.getODataProperty(oEntityType, sKey);
284
+ const sPropertyPath = oSFBMetaModel.getODataProperty(oEntityType, sKey, true);
285
+ const isValueHelpTableAvailable = AnnotationHelper.isValueHelpTableAvailable(oProperty);
286
+
287
+ if (!isValueHelpTableAvailable) {
288
+ // When there is no valueList associate, just return the original value in CodeList type
289
+ aFilters.forEach(oFilter => aFinalResponse.push(getkeySpecifiedResultFromFilters(oFilter)));
290
+ resolve(aFinalResponse);
291
+ }
292
+
293
+ // Get value help lists from metadata
294
+ const oPropertyContext = oSFBMetaModel.createBindingContext(sPropertyPath);
295
+ const oValueList = await oSFBMetaModel.getODataValueLists(oPropertyContext);
296
+
297
+ // Process each filter in parallel
298
+ const pPromises = [];
299
+
300
+ for (const oFilter of aFilters) {
301
+ if (isComparitveOperator(oFilter.getOperator())) {
302
+ // For comparative operators, just add the original values
303
+ aFinalResponse.push(getkeySpecifiedResultFromFilters(oFilter));
304
+ } else {
305
+ // For other operators, fetch records from value list
306
+ pPromises.push(fetchRecordsFromValueList(oValueList, oFilter, sKey, oSFBModel, oTemplateUtils));
307
+ }
308
+ }
309
+
310
+ // Wait for all promises to resolve
311
+ if (pPromises.length > 0) {
312
+ const aResponses = await Promise.all(pPromises);
313
+ aResponses.forEach(aResponse => {
314
+ aFinalResponse.push(aResponse);
315
+ });
316
+ }
317
+
318
+ resolve(aFinalResponse);
319
+ } catch (error) {
320
+ reject(error); // Re-throw to allow caller to handle
321
+ }
322
+ });
323
+ }
324
+
325
+ return {
326
+ fetchDataForKey: fetchDataForKey,
327
+ getFiltersForDataFetching: getFiltersForDataFetching,
328
+ isComparitveOperator: isComparitveOperator,
329
+ isNegationOperator: isNegationOperator,
330
+ getReverseOperator: function(operator) {
331
+ return mReverseOperator[operator];
332
+ }
333
+ };
334
+ });
@@ -900,6 +900,11 @@ sap.ui.define(["sap/ui/base/Object",
900
900
  var oIntentAndAllAppStatesPromise = Promise.all(aIntentAppStatePromises);
901
901
  var fnAdjustNavigationHierarchy = function(){
902
902
  oTemplateContract.oShellServicePromise.then(function(oShellService){
903
+ // When the FE app is embedded within the Inbox app, the Inbox provides a stub implementation
904
+ // of the ShellUIService. In that case, the call to "oShellService.setHierarchy()" operates
905
+ // on this stub service (and not the actual ShellUIService).
906
+ //
907
+ // For more details, refer to AppComponent#fnGetShellUIServicePromise.
903
908
  oShellService.setHierarchy([]);
904
909
  oIntentAndAllAppStatesPromise.then(function(aIntent){
905
910
  var sCurrentIntent = aIntent[0];
@@ -3223,7 +3228,7 @@ sap.ui.define(["sap/ui/base/Object",
3223
3228
  * @param {sap.suite.ui.generic.template.lib.AppComponent} oAppComponent The AppComponent instance
3224
3229
  * @public
3225
3230
  * @extends sap.ui.base.Object
3226
- * @version 1.139.0
3231
+ * @version 1.139.2
3227
3232
  * @since 1.30.0
3228
3233
  * @alias sap.suite.ui.generic.template.lib.NavigationController
3229
3234
  */
@@ -582,7 +582,7 @@ sap.ui.define([
582
582
  const getFieldProps = function (sField) {
583
583
  return {
584
584
  "sProperty": sField,
585
- "sLabel": mPropertyByFieldName[sField]["sap:label"],
585
+ "sLabel": (mPropertyByFieldName[sField]["com.sap.vocabularies.Common.v1.Label"] || "").String || mPropertyByFieldName[sField]["sap:label"] || "",
586
586
  "sValue": oItemContext.getProperty(sField),
587
587
  "bHidden": !aVisibleColumns.has(sField)
588
588
  };
@@ -66,7 +66,7 @@ sap.ui.define([
66
66
  interfaces: [],
67
67
  controls: [],
68
68
  elements: [],
69
- version: "1.139.0",
69
+ version: "1.139.2",
70
70
  extensions: {
71
71
  //Configuration used for rule loading of Support Assistant
72
72
  "sap.ui.support": {