@sap-ux/odata-service-inquirer 2.5.21 → 2.5.23

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.
@@ -22,7 +22,7 @@ const prompt_helpers_1 = require("../../../prompt-helpers");
22
22
  const validators_1 = require("../../../validators");
23
23
  const service_helpers_1 = require("../../service-helpers/service-helpers");
24
24
  // Service ids continaining these paths should not be offered as UI compatible services
25
- const nonUIServicePaths = ['/IWBEP/COMMON/'];
25
+ const nonUIServicePaths = ['/IWBEP/COMMON'];
26
26
  // Telemetry event name for successful service validation on BAS, note: legacy event names should not be changed
27
27
  exports.telemEventBASServiceSuccess = 'SERVICE_INQUIRER_BAS_SUCCESS';
28
28
  /**
@@ -41,7 +41,7 @@ const createServiceChoices = (serviceInfos) => {
41
41
  }
42
42
  serviceInfos
43
43
  // Exclude non-UI compatible services
44
- ?.filter((service) => !nonUIServicePaths.some((path) => service.path.includes(path)))
44
+ ?.filter((service) => !nonUIServicePaths.some((path) => service.id.includes(path)))
45
45
  .forEach((service) => {
46
46
  let serviceName = service.name;
47
47
  const servicePath = service.path;
@@ -60,6 +60,7 @@ const createServiceChoices = (serviceInfos) => {
60
60
  }
61
61
  });
62
62
  });
63
+ logger_helper_1.default.logger.debug(`Number of unique service choices: ${choices.length}`);
63
64
  return choices.sort((a, b) => (a.name ? a.name.localeCompare(b.name ?? '') : 0));
64
65
  };
65
66
  /**
@@ -87,9 +88,22 @@ function logServiceCatalogErrorsForHelp(requestErrors, numOfRequests) {
87
88
  */
88
89
  async function getServiceChoices(catalogs, serviceFilter) {
89
90
  const requestErrors = {};
90
- const listServicesRequests = catalogs.map(async (catalog) => {
91
+ // Performance tracking for the requests
92
+ const requestTimes = {}; // [v2, v4] request times in ms
93
+ const listServicesRequests = [];
94
+ for (const catalog of catalogs) {
95
+ const catalogVer = catalog instanceof axios_extension_1.V2CatalogService ? axios_extension_1.ODataVersion.v2 : axios_extension_1.ODataVersion.v4;
91
96
  try {
92
- return await catalog.listServices();
97
+ const startTime = Date.now();
98
+ const res = await catalog.listServices();
99
+ const endTime = Date.now();
100
+ const duration = endTime - startTime === 0 ? '<1 ms' : `${endTime - startTime}ms`;
101
+ requestTimes[`v${catalogVer}`] = {
102
+ serviceCount: res.length,
103
+ duration
104
+ };
105
+ logger_helper_1.default.logger.debug(`Number of service${catalogVer === axios_extension_1.ODataVersion.v4 ? ' groups' : 's'}: ${res.length} returned in: ${duration}}`);
106
+ listServicesRequests.push(res);
93
107
  }
94
108
  catch (error) {
95
109
  logger_helper_1.default.logger.error((0, i18n_1.t)('errors.serviceCatalogRequest', {
@@ -99,13 +113,15 @@ async function getServiceChoices(catalogs, serviceFilter) {
99
113
  }));
100
114
  // Save any errors for processing later as we may show more useful message to the user
101
115
  Object.assign(requestErrors, {
102
- [catalog instanceof axios_extension_1.V2CatalogService ? axios_extension_1.ODataVersion.v2 : axios_extension_1.ODataVersion.v4]: error
116
+ [catalogVer]: error
103
117
  });
104
- return [];
118
+ listServicesRequests.push([]);
105
119
  }
106
- });
107
- const serviceInfos = await Promise.all(listServicesRequests);
108
- let flatServices = serviceInfos?.flat() ?? [];
120
+ }
121
+ // Log the request times for debugging purposes
122
+ logger_helper_1.default.logger.debug(`Service catalog request times: ${JSON.stringify(requestTimes, undefined, ' ')}`);
123
+ // Flatten the array of arrays
124
+ let flatServices = listServicesRequests?.flat() ?? [];
109
125
  logger_helper_1.default.logger.debug(`Number of services available: ${flatServices.length}`);
110
126
  if (flatServices.length === 0) {
111
127
  logServiceCatalogErrorsForHelp(requestErrors, catalogs.length);
@@ -49,6 +49,14 @@ export declare function getEntityChoices(edmx: string, { entitySetFilter, defaul
49
49
  * @returns the navigation entity choices
50
50
  */
51
51
  export declare function getNavigationEntityChoices(metadata: ConvertedMetadata, odataVersion: OdataVersion, mainEntityName: string): ListChoiceOptions<NavigationEntityAnswer>[];
52
+ /**
53
+ * Returns only entity sets that have the `Aggregation.ApplySupported` annotation term with the `Transformations` property.
54
+ * This can be found within the entity set annotations or the entity type annotations.
55
+ *
56
+ * @param entitySets the entity sets to filter
57
+ * @returns the filtered entity sets
58
+ */
59
+ export declare function filterAggregateTransformations(entitySets: EntitySet[]): EntitySet[];
52
60
  /**
53
61
  * Returns only entities that have a type property of 'HasDraftEnabled'.
54
62
  *
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getEntityChoices = getEntityChoices;
7
7
  exports.getNavigationEntityChoices = getNavigationEntityChoices;
8
+ exports.filterAggregateTransformations = filterAggregateTransformations;
8
9
  exports.filterDraftEnabledEntities = filterDraftEnabledEntities;
9
10
  const annotation_converter_1 = require("@sap-ux/annotation-converter");
10
11
  const edmx_parser_1 = require("@sap-ux/edmx-parser");
@@ -131,7 +131,7 @@ function getEntitySelectionQuestions(metadata, templateType, isCapService = fals
131
131
  }
132
132
  entityQuestions.push(...getAddAnnotationQuestions(metadata, templateType, odataVersion, isCapService));
133
133
  if (!promptOptions?.hideTableLayoutPrompts) {
134
- entityQuestions.push(...getTableLayoutQuestions(templateType, odataVersion, isCapService));
134
+ entityQuestions.push(...getTableLayoutQuestions(templateType, odataVersion, isCapService, convertedMetadata));
135
135
  }
136
136
  if (templateType === 'alp') {
137
137
  entityQuestions.push(...(0, alp_questions_1.getAnalyticListPageQuestions)(odataVersion, annotations, promptOptions?.hideTableLayoutPrompts));
@@ -144,9 +144,10 @@ function getEntitySelectionQuestions(metadata, templateType, isCapService = fals
144
144
  * @param templateType used to determine if the tree table option should be included
145
145
  * @param odataVersion used to determine if the hierarchy qualifier is required when the selected table type is TreeTable
146
146
  * @param isCapService used to determine if the tree table option should be included
147
+ * @param metadata the metadata (edmx) string of the service
147
148
  * @returns the table layout questions
148
149
  */
149
- function getTableLayoutQuestions(templateType, odataVersion, isCapService) {
150
+ function getTableLayoutQuestions(templateType, odataVersion, isCapService, metadata) {
150
151
  const tableTypeChoices = [
151
152
  { name: (0, i18n_1.t)('prompts.tableType.choiceAnalytical'), value: 'AnalyticalTable' },
152
153
  { name: (0, i18n_1.t)('prompts.tableType.choiceGrid'), value: 'GridTable' },
@@ -157,7 +158,7 @@ function getTableLayoutQuestions(templateType, odataVersion, isCapService) {
157
158
  }
158
159
  const tableLayoutQuestions = [];
159
160
  if (templateType === 'lrop' || templateType === 'worklist' || templateType === 'alp') {
160
- const tableTypeDefault = templateType === 'alp' ? 'AnalyticalTable' : 'ResponsiveTable';
161
+ let setAnalyticalTableDefault = false;
161
162
  tableLayoutQuestions.push({
162
163
  when: (prevAnswers) => !!prevAnswers.mainEntity,
163
164
  type: 'list',
@@ -165,10 +166,23 @@ function getTableLayoutQuestions(templateType, odataVersion, isCapService) {
165
166
  message: (0, i18n_1.t)('prompts.tableType.message'),
166
167
  guiOptions: {
167
168
  hint: (0, i18n_1.t)('prompts.tableType.hint'),
168
- breadcrumb: true
169
+ breadcrumb: true,
170
+ applyDefaultWhenDirty: true // set table type on entity selection change
169
171
  },
170
172
  choices: tableTypeChoices,
171
- default: tableTypeDefault
173
+ default: (prevAnswers) => {
174
+ const tableTypeDefault = getDefaultTableType(templateType, metadata, odataVersion, prevAnswers?.mainEntity?.entitySetName, prevAnswers?.tableType);
175
+ setAnalyticalTableDefault = tableTypeDefault.setAnalyticalTableDefault;
176
+ return tableTypeDefault.tableType;
177
+ },
178
+ additionalMessages: (tableType) => {
179
+ if (tableType === 'AnalyticalTable' && setAnalyticalTableDefault) {
180
+ return {
181
+ message: (0, i18n_1.t)('prompts.tableType.analyticalTableDefault'),
182
+ severity: yeoman_ui_types_1.Severity.information
183
+ };
184
+ }
185
+ }
172
186
  });
173
187
  tableLayoutQuestions.push({
174
188
  when: (prevAnswers) => prevAnswers?.tableType === 'TreeTable' && odataVersion === odata_service_writer_1.OdataVersion.v4,
@@ -204,6 +218,56 @@ function getEdmxSizeInKb(edmx) {
204
218
  }
205
219
  return 0;
206
220
  }
221
+ /**
222
+ * Get the default table type based on the template type and previous answers.
223
+ *
224
+ * @param templateType the template type of the application to be generated from the prompt answers
225
+ * @param metadata the metadata (edmx) string of the service
226
+ * @param odataVersion the OData version of the service
227
+ * @param mainEntitySetName the name of the main entity set
228
+ * @param currentTableType the current table type selected by the user
229
+ * @returns the default table type and a boolean indicating if AnalyticalTable should be set as default
230
+ */
231
+ function getDefaultTableType(templateType, metadata, odataVersion, mainEntitySetName, currentTableType) {
232
+ let tableType;
233
+ let setAnalyticalTableDefault = false;
234
+ if ((templateType === 'lrop' || templateType === 'worklist') &&
235
+ odataVersion === odata_service_writer_1.OdataVersion.v4 &&
236
+ hasAggregateTransformationsForEntity(metadata, mainEntitySetName)) {
237
+ // For V4, if the selected entity has aggregate transformations, use AnalyticalTable as default
238
+ tableType = 'AnalyticalTable';
239
+ setAnalyticalTableDefault = true;
240
+ }
241
+ else if (templateType === 'alp') {
242
+ // For ALP, use AnalyticalTable as default
243
+ tableType = 'AnalyticalTable';
244
+ }
245
+ else if (currentTableType) {
246
+ // If the user has already selected a table type use it
247
+ tableType = currentTableType;
248
+ }
249
+ else {
250
+ // Default to ResponsiveTable for other cases
251
+ tableType = 'ResponsiveTable';
252
+ }
253
+ return {
254
+ tableType,
255
+ setAnalyticalTableDefault
256
+ };
257
+ }
258
+ /**
259
+ * Checks if the given entity set name has aggregate transformations in the metadata.
260
+ *
261
+ * @param metadata The metadata (edmx) string of the service.
262
+ * @param entitySetName The entity set name to check for aggregate transformations.
263
+ * @returns true if the entity set has aggregate transformations, false otherwise.
264
+ */
265
+ function hasAggregateTransformationsForEntity(metadata, entitySetName) {
266
+ if (!entitySetName) {
267
+ return false;
268
+ }
269
+ return (0, entity_helper_1.filterAggregateTransformations)(metadata.entitySets).some((entitySet) => entitySet.name === entitySetName);
270
+ }
207
271
  /**
208
272
  * Get the questions that may be used to prompt for adding annotations. Only a subset of the questions will be returned based on the template type and OData version.
209
273
  *
@@ -151,7 +151,8 @@
151
151
  "choiceGrid": "Grid",
152
152
  "choiceAnalytical": "Analytical",
153
153
  "choiceResponsive": "Responsive",
154
- "choiceTree": "Tree"
154
+ "choiceTree": "Tree",
155
+ "analyticalTableDefault": "The 'Analytical' table type is chosen by default because the selected entity supports it."
155
156
  },
156
157
  "hierarchyQualifier": {
157
158
  "message": "Hierarchy Qualifier",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sap-ux/odata-service-inquirer",
3
3
  "description": "Prompts module that can prompt users for inputs required for odata service writing",
4
- "version": "2.5.21",
4
+ "version": "2.5.23",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -28,7 +28,7 @@
28
28
  "i18next": "25.3.0",
29
29
  "inquirer-autocomplete-prompt": "2.0.1",
30
30
  "os-name": "4.0.1",
31
- "@sap-ux/axios-extension": "1.22.3",
31
+ "@sap-ux/axios-extension": "1.22.4",
32
32
  "@sap-ux/btp-utils": "1.1.0",
33
33
  "@sap-ux/fiori-generator-shared": "0.13.3",
34
34
  "@sap-ux/guided-answers-helper": "0.3.1",
@@ -43,13 +43,13 @@
43
43
  "devDependencies": {
44
44
  "@sap-ux/vocabularies-types": "0.13.0",
45
45
  "@sap-devx/yeoman-ui-types": "1.14.4",
46
- "@types/inquirer-autocomplete-prompt": "2.0.1",
46
+ "@types/inquirer-autocomplete-prompt": "2.0.2",
47
47
  "@types/inquirer": "8.2.6",
48
48
  "@types/lodash": "4.14.202",
49
- "jest-extended": "3.2.4",
49
+ "jest-extended": "6.0.0",
50
50
  "@sap-ux/fiori-generator-shared": "0.13.3",
51
- "@sap-ux/fiori-elements-writer": "2.5.14",
52
- "@sap-ux/fiori-freestyle-writer": "2.4.25",
51
+ "@sap-ux/fiori-elements-writer": "2.5.15",
52
+ "@sap-ux/fiori-freestyle-writer": "2.4.26",
53
53
  "@sap-ux/feature-toggle": "0.3.0",
54
54
  "@sap-ux/odata-service-writer": "0.27.12",
55
55
  "@sap-ux/cap-config-writer": "0.10.21"
@@ -63,7 +63,7 @@
63
63
  "watch": "tsc --watch",
64
64
  "lint": "eslint . --ext .ts",
65
65
  "lint:fix": "eslint . --ext .ts --fix",
66
- "test": "jest --ci --forceExit --detectOpenHandles --colors --passWithNoTests",
66
+ "test": "jest --ci --forceExit --detectOpenHandles --colors",
67
67
  "test-u": "jest --ci --forceExit --detectOpenHandles --colors -u",
68
68
  "link": "pnpm link --global",
69
69
  "unlink": "pnpm unlink --global"