@sap-ux/preview-middleware 0.20.2 → 0.20.4

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/README.md CHANGED
@@ -31,7 +31,9 @@ When this middleware is used together with the `reload-middleware`, then the ord
31
31
  | `editors` | `array` | optional | `undefined` | List of configurations allowing to add mount points for additional editors |
32
32
  | `editors.rta` | `array` | optional | `undefined` | Configuration allowing to add mount points for runtime adaptation |
33
33
  | `editors.rta.layer` | `string` | optional | `(calculated)` | Property for defining the runtime adaptation layer for changes (default is `CUSTOMER_BASE` or read from the project for adaptation projects) |
34
- | `editors.rta.endpoints` | `array` | optional | `undefined` | List of mount points for editing |
34
+ | `editors.rta.endpoints` | `array` | optional | `undefined` | List of mount points for editing
35
+ | `editors.cardGenerator` | --- | optional | `undefined` | Configuration object to enable card generation for an application.
36
+ | `editors.cardGenerator.path` | `string` | optional | `test/flpGeneratorSandbox.html` | The mount point of the local SAP Fiori launchpad which will be considered for card generation.
35
37
  | `test` | `array` | optional | `undefined` | List of configurations for automated testing. |
36
38
  | `debug` | `boolean` | optional | `false` | Enables the debug output |
37
39
 
@@ -57,6 +57,7 @@ export interface TemplateConfig {
57
57
  }[];
58
58
  locateReuseLibsScript?: boolean;
59
59
  enhancedHomePage?: boolean;
60
+ enableCardGenerator?: boolean;
60
61
  }
61
62
  /**
62
63
  * Static settings
@@ -70,6 +71,11 @@ export declare const PREVIEW_URL: {
70
71
  };
71
72
  readonly api: "/preview/api";
72
73
  };
74
+ export declare const CARD_GENERATOR_DEFAULT: {
75
+ readonly previewGeneratorSandbox: "/test/flpCardGeneratorSandbox.html";
76
+ readonly cardsStore: "/cards/store";
77
+ readonly i18nStore: "/editor/i18n";
78
+ };
73
79
  /**
74
80
  * Default theme
75
81
  */
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DEFAULT_INTENT = exports.DEFAULT_PATH = exports.DEFAULT_THEME = exports.PREVIEW_URL = void 0;
3
+ exports.DEFAULT_INTENT = exports.DEFAULT_PATH = exports.DEFAULT_THEME = exports.CARD_GENERATOR_DEFAULT = exports.PREVIEW_URL = void 0;
4
4
  exports.getFlpConfigWithDefaults = getFlpConfigWithDefaults;
5
5
  exports.sanitizeConfig = sanitizeConfig;
6
6
  exports.sanitizeRtaConfig = sanitizeRtaConfig;
@@ -30,6 +30,11 @@ exports.PREVIEW_URL = {
30
30
  },
31
31
  api: '/preview/api'
32
32
  };
33
+ exports.CARD_GENERATOR_DEFAULT = {
34
+ previewGeneratorSandbox: '/test/flpCardGeneratorSandbox.html',
35
+ cardsStore: '/cards/store',
36
+ i18nStore: '/editor/i18n'
37
+ };
33
38
  /**
34
39
  * Default theme
35
40
  */
@@ -270,7 +275,8 @@ function createFlpTemplateConfig(config, manifest, resources = {}) {
270
275
  bootstrapOptions: ''
271
276
  },
272
277
  locateReuseLibsScript: config.libs,
273
- enhancedHomePage: config.enhancedHomePage
278
+ enhancedHomePage: config.enhancedHomePage,
279
+ enableCardGenerator: false
274
280
  };
275
281
  }
276
282
  /**
@@ -38,6 +38,7 @@ export declare class FlpSandbox {
38
38
  private readonly logger;
39
39
  private readonly utils;
40
40
  private readonly project;
41
+ private readonly cardGenerator?;
41
42
  /**
42
43
  * Constructor setting defaults and keeping reference to workspace resources.
43
44
  *
@@ -132,6 +133,15 @@ export declare class FlpSandbox {
132
133
  * Add routes for html and scripts required for a local FLP.
133
134
  */
134
135
  private addStandardRoutes;
136
+ /**
137
+ * Adds a middleware route for the Card Generator in the FLP sandbox.
138
+ *
139
+ * This route dynamically updates the `templateConfig` with the Card Generator application details
140
+ * and serves the FLP sandbox HTML using the `flpGetHandler`.
141
+ *
142
+ * @private
143
+ */
144
+ private addCardGeneratorMiddlewareRoute;
135
145
  /**
136
146
  * Read the UI5 version.
137
147
  * In case of an error, the default UI5 version '1.121.0' is returned.
@@ -263,6 +273,36 @@ export declare class FlpSandbox {
263
273
  * @param id application id from manifest
264
274
  */
265
275
  private addTestRoutes;
276
+ /**
277
+ * Stores the card manifest files in the webapp folder of the project and updates the application manifest.
278
+ *
279
+ * @param {Request} req - The HTTP request object containing the card manifest data in the body.
280
+ * @param {Response} res - The HTTP response object used to send the response back to the client.
281
+ * @returns {Promise<void>} A promise that resolves when the operation is complete.
282
+ */
283
+ private storeCardManifestHandler;
284
+ /**
285
+ * Adds a route to store card manifest files, the files are stored in the webapp folder of the project.
286
+ * The application manifest.json file is updated with the new card manifests information within the sap.cards.ap.embeds.
287
+ *
288
+ * @returns {Promise<void>} A promise that resolves when the route is added.
289
+ */
290
+ addStoreCardManifestRoute(): Promise<void>;
291
+ /**
292
+ * Handles the storage of i18n keys in the i18n file.
293
+ *
294
+ * @param {Request} req - The HTTP request object containing the i18n key-value pairs in the body.
295
+ * @param {Response} res - The HTTP response object used to send the response back to the client.
296
+ * @returns {Promise<void>} A promise that resolves when the operation is complete.
297
+ */
298
+ private storeI18nKeysHandler;
299
+ /**
300
+ * Adds a route to store i18n properties in the i18n file.
301
+ * This function updates the i18n file with new properties provided in the request body.
302
+ *
303
+ * @returns {Promise<void>} A promise that resolves when the route is added.
304
+ */
305
+ addStoreI18nKeysRoute(): Promise<void>;
266
306
  }
267
307
  /**
268
308
  * Initialize the preview for an adaptation project.
package/dist/base/flp.js CHANGED
@@ -1,13 +1,45 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.FlpSandbox = void 0;
4
37
  exports.initAdp = initAdp;
5
38
  const mem_fs_1 = require("mem-fs");
6
39
  const mem_fs_editor_1 = require("mem-fs-editor");
7
- const fs_1 = require("fs");
8
40
  const ejs_1 = require("ejs");
9
41
  const express_1 = require("express");
10
- const path_1 = require("path");
42
+ const path_1 = __importStar(require("path"));
11
43
  const project_access_1 = require("@sap-ux/project-access");
12
44
  const adp_tooling_1 = require("@sap-ux/adp-tooling");
13
45
  const btp_utils_1 = require("@sap-ux/btp-utils");
@@ -16,6 +48,9 @@ const flex_1 = require("./flex");
16
48
  const test_1 = require("./test");
17
49
  const config_1 = require("./config");
18
50
  const cdm_1 = require("./cdm");
51
+ const fs_1 = require("fs");
52
+ const cards_1 = require("./utils/cards");
53
+ const i18n_1 = require("@sap-ux/i18n");
19
54
  const DEFAULT_LIVERELOAD_PORT = 35729;
20
55
  /**
21
56
  * Class handling preview of a sandbox FLP.
@@ -33,6 +68,7 @@ class FlpSandbox {
33
68
  logger;
34
69
  utils;
35
70
  project;
71
+ cardGenerator;
36
72
  /**
37
73
  * Constructor setting defaults and keeping reference to workspace resources.
38
74
  *
@@ -50,6 +86,7 @@ class FlpSandbox {
50
86
  this.rta = config.editors?.rta ?? (0, config_1.sanitizeRtaConfig)(config.rta, logger); //NOSONAR
51
87
  logger.debug(`Config: ${JSON.stringify({ flp: this.flpConfig, rta: this.rta, test: this.test })}`);
52
88
  this.router = (0, express_1.Router)();
89
+ this.cardGenerator = config.editors?.cardGenerator;
53
90
  }
54
91
  /**
55
92
  * Registers a handler function to be called when a change request occurs.
@@ -81,6 +118,15 @@ class FlpSandbox {
81
118
  intent: this.flpConfig.intent
82
119
  }, this.logger);
83
120
  this.addStandardRoutes();
121
+ const cardGeneratorPath = this.cardGenerator?.path;
122
+ if (cardGeneratorPath) {
123
+ if (!cardGeneratorPath.startsWith('/')) {
124
+ this.cardGenerator.path = `/${cardGeneratorPath}`;
125
+ }
126
+ await this.addCardGeneratorMiddlewareRoute();
127
+ await this.addStoreCardManifestRoute();
128
+ await this.addStoreI18nKeysRoute();
129
+ }
84
130
  if (this.rta) {
85
131
  this.rta.options ??= {};
86
132
  this.rta.options.baseId = componentId ?? id;
@@ -285,9 +331,7 @@ class FlpSandbox {
285
331
  async flpGetHandler(req, res, next) {
286
332
  // connect API (karma test runner) has no request query property
287
333
  if ('query' in req && 'redirect' in res && !req.query['sap-ui-xx-viewCache']) {
288
- const url = 'ui5-patched-router' in req
289
- ? (0, path_1.join)(req['ui5-patched-router']?.baseUrl ?? '', this.flpConfig.path)
290
- : this.flpConfig.path;
334
+ const url = 'ui5-patched-router' in req ? (0, path_1.join)(req['ui5-patched-router']?.baseUrl ?? '', req.path) : req.path;
291
335
  // Redirect to the same URL but add the necessary parameter
292
336
  const params = structuredClone(req.query);
293
337
  params['sap-ui-xx-viewCache'] = 'false';
@@ -323,6 +367,22 @@ class FlpSandbox {
323
367
  await this.flpGetHandler(req, res, next);
324
368
  });
325
369
  }
370
+ /**
371
+ * Adds a middleware route for the Card Generator in the FLP sandbox.
372
+ *
373
+ * This route dynamically updates the `templateConfig` with the Card Generator application details
374
+ * and serves the FLP sandbox HTML using the `flpGetHandler`.
375
+ *
376
+ * @private
377
+ */
378
+ async addCardGeneratorMiddlewareRoute() {
379
+ const previewGeneratorPath = this.cardGenerator?.path ?? config_1.CARD_GENERATOR_DEFAULT.previewGeneratorSandbox;
380
+ this.logger.debug(`Add route for ${previewGeneratorPath}`);
381
+ this.router.get(previewGeneratorPath, async (req, res, next) => {
382
+ this.templateConfig.enableCardGenerator = !!this.cardGenerator?.path;
383
+ await this.flpGetHandler(req, res, next);
384
+ });
385
+ }
326
386
  /**
327
387
  * Read the UI5 version.
328
388
  * In case of an error, the default UI5 version '1.121.0' is returned.
@@ -691,6 +751,97 @@ class FlpSandbox {
691
751
  });
692
752
  }
693
753
  }
754
+ /**
755
+ * Stores the card manifest files in the webapp folder of the project and updates the application manifest.
756
+ *
757
+ * @param {Request} req - The HTTP request object containing the card manifest data in the body.
758
+ * @param {Response} res - The HTTP response object used to send the response back to the client.
759
+ * @returns {Promise<void>} A promise that resolves when the operation is complete.
760
+ */
761
+ async storeCardManifestHandler(req, res) {
762
+ try {
763
+ const { floorplan, localPath, fileName = project_access_1.FileName.Manifest, manifests } = req.body;
764
+ this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
765
+ const webappPath = await (0, project_access_1.getWebappPath)(path_1.default.resolve(), this.fs);
766
+ const fullPath = (0, path_1.join)(webappPath, localPath);
767
+ const filePath = fileName.endsWith('.json') ? (0, path_1.join)(fullPath, fileName) : `${(0, path_1.join)(fullPath, fileName)}.json`;
768
+ const integrationCard = (0, cards_1.getIntegrationCard)(manifests);
769
+ this.fs.write(filePath, JSON.stringify(integrationCard.manifest, null, 2));
770
+ const entitySet = integrationCard.entitySet;
771
+ const sapCardsAp = (this.manifest['sap.cards.ap'] ??= {});
772
+ sapCardsAp.embeds ??= {};
773
+ sapCardsAp.embeds[floorplan] = {
774
+ default: entitySet,
775
+ manifests: {
776
+ [entitySet]: [
777
+ {
778
+ localUri: localPath
779
+ }
780
+ ]
781
+ }
782
+ };
783
+ const appAccess = await (0, project_access_1.createApplicationAccess)(path_1.default.resolve(), this.fs);
784
+ await appAccess.updateManifestJSON(this.manifest, this.fs);
785
+ this.fs.commit(() => this.sendResponse(res, 'text/plain', 201, `Files were updated/created`));
786
+ }
787
+ catch (error) {
788
+ this.logger.error(`Files could not be created/updated. Error: ${error}`);
789
+ this.sendResponse(res, 'text/plain', 500, 'Files could not be created/updated.');
790
+ }
791
+ }
792
+ /**
793
+ * Adds a route to store card manifest files, the files are stored in the webapp folder of the project.
794
+ * The application manifest.json file is updated with the new card manifests information within the sap.cards.ap.embeds.
795
+ *
796
+ * @returns {Promise<void>} A promise that resolves when the route is added.
797
+ */
798
+ async addStoreCardManifestRoute() {
799
+ this.router.use(config_1.CARD_GENERATOR_DEFAULT.cardsStore, (0, express_1.json)());
800
+ this.logger.debug(`Add route for ${config_1.CARD_GENERATOR_DEFAULT.cardsStore}`);
801
+ this.router.post(config_1.CARD_GENERATOR_DEFAULT.cardsStore, async (req, res) => {
802
+ await this.storeCardManifestHandler(req, res);
803
+ });
804
+ }
805
+ /**
806
+ * Handles the storage of i18n keys in the i18n file.
807
+ *
808
+ * @param {Request} req - The HTTP request object containing the i18n key-value pairs in the body.
809
+ * @param {Response} res - The HTTP response object used to send the response back to the client.
810
+ * @returns {Promise<void>} A promise that resolves when the operation is complete.
811
+ */
812
+ async storeI18nKeysHandler(req, res) {
813
+ try {
814
+ this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
815
+ const webappPath = await (0, project_access_1.getWebappPath)(path_1.default.resolve(), this.fs);
816
+ const i18nPath = this.manifest['sap.app'].i18n;
817
+ const filePath = i18nPath ? (0, path_1.join)(webappPath, i18nPath) : (0, path_1.join)(webappPath, 'i18n', 'i18n.properties');
818
+ const entries = req.body || [];
819
+ entries.forEach((entry) => {
820
+ if (entry.comment) {
821
+ entry.annotation = entry.comment;
822
+ }
823
+ });
824
+ await (0, i18n_1.createPropertiesI18nEntries)(filePath, entries);
825
+ this.fs.commit(() => this.sendResponse(res, 'text/plain', 201, `i18n file updated.`));
826
+ }
827
+ catch (error) {
828
+ this.logger.error(`File could not be updated. Error: ${error}`);
829
+ this.sendResponse(res, 'text/plain', 500, 'File could not be updated.');
830
+ }
831
+ }
832
+ /**
833
+ * Adds a route to store i18n properties in the i18n file.
834
+ * This function updates the i18n file with new properties provided in the request body.
835
+ *
836
+ * @returns {Promise<void>} A promise that resolves when the route is added.
837
+ */
838
+ async addStoreI18nKeysRoute() {
839
+ this.router.use(config_1.CARD_GENERATOR_DEFAULT.i18nStore, (0, express_1.json)());
840
+ this.logger.debug(`Add route for ${config_1.CARD_GENERATOR_DEFAULT.i18nStore}`);
841
+ this.router.post(config_1.CARD_GENERATOR_DEFAULT.i18nStore, async (req, res) => {
842
+ await this.storeI18nKeysHandler(req, res);
843
+ });
844
+ }
694
845
  }
695
846
  exports.FlpSandbox = FlpSandbox;
696
847
  /**
@@ -0,0 +1,9 @@
1
+ import type { MultiCardsPayload } from '../../types';
2
+ /**
3
+ * Retrieves the integration card from the provided payload and prepares it for saving.
4
+ *
5
+ * @param {MultiCardsPayload[]} multipleCard - The payload containing multiple card manifests.
6
+ * @returns {MultiCardsPayload} The integration card manifest.
7
+ */
8
+ export declare function getIntegrationCard(multipleCard: MultiCardsPayload[]): MultiCardsPayload;
9
+ //# sourceMappingURL=cards.d.ts.map
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getIntegrationCard = getIntegrationCard;
7
+ const package_json_1 = __importDefault(require("../../../package.json"));
8
+ const CARD_TYPES = {
9
+ INTEGRATION: 'integration',
10
+ ADAPTIVE: 'adaptive'
11
+ };
12
+ /**
13
+ * Prepares an integration card manifest for saving by adding the design time preview middleware i.e.`dtpMiddleware` version to the card manifest.
14
+ *
15
+ * @param {CardManifest} cardManifest - The card manifest object to be updated.
16
+ * @returns {void}
17
+ */
18
+ function prepareIntegrationCardForSaving(cardManifest) {
19
+ const version = package_json_1.default.version;
20
+ const insights = cardManifest?.['sap.insights'];
21
+ if (!insights.versions) {
22
+ insights.versions = {
23
+ dtpMiddleware: version
24
+ };
25
+ }
26
+ else {
27
+ insights.versions.dtpMiddleware = version;
28
+ }
29
+ }
30
+ /**
31
+ * Retrieves the integration card from the provided payload and prepares it for saving.
32
+ *
33
+ * @param {MultiCardsPayload[]} multipleCard - The payload containing multiple card manifests.
34
+ * @returns {MultiCardsPayload} The integration card manifest.
35
+ */
36
+ function getIntegrationCard(multipleCard) {
37
+ const integrationCard = multipleCard.find((card) => card.type === CARD_TYPES.INTEGRATION) ?? {
38
+ type: CARD_TYPES.INTEGRATION,
39
+ manifest: {
40
+ 'sap.insights': {}
41
+ },
42
+ entitySet: ''
43
+ };
44
+ prepareIntegrationCardForSaving(integrationCard.manifest);
45
+ return integrationCard;
46
+ }
47
+ //# sourceMappingURL=cards.js.map
@@ -10,7 +10,7 @@ sap.ui.define(["sap/ui/dt/OverlayUtil", "../../../utils/core", "../../dialog-fac
10
10
  const TableQuickActionDefinitionBase = ___table_quick_action_base["TableQuickActionDefinitionBase"];
11
11
  const MDC_TABLE_TYPE = ___control_types["MDC_TABLE_TYPE"];
12
12
  const preprocessActionExecution = ___fe_v2_create_table_custom_column["preprocessActionExecution"];
13
- const CREATE_TABLE_ACTION = 'create_table_action';
13
+ const CREATE_TABLE_ACTION = 'create-table-action';
14
14
 
15
15
  /**
16
16
  * Quick Action for creating table action.
@@ -12,7 +12,7 @@ import { TableQuickActionDefinitionBase } from '../table-quick-action-base';
12
12
  import { MDC_TABLE_TYPE } from '../control-types';
13
13
  import { preprocessActionExecution } from '../fe-v2/create-table-custom-column';
14
14
 
15
- export const CREATE_TABLE_ACTION = 'create_table_action';
15
+ export const CREATE_TABLE_ACTION = 'create-table-action';
16
16
 
17
17
  /**
18
18
  * Quick Action for creating table action.
@@ -5,8 +5,9 @@ sap.ui.define([
5
5
  '../i18n',
6
6
  'sap/base/Log',
7
7
  '../utils/core',
8
- '../utils/version'
9
- ], function (___sap_ux_private_control_property_editor_common, ___adp_dialog_factory, ___i18n, Log, ___utils_core, ___utils_version) {
8
+ '../utils/version',
9
+ '../utils/application'
10
+ ], function (___sap_ux_private_control_property_editor_common, ___adp_dialog_factory, ___i18n, Log, ___utils_core, ___utils_version, ___utils_application) {
10
11
  'use strict';
11
12
  const executeContextMenuAction = ___sap_ux_private_control_property_editor_common['executeContextMenuAction'];
12
13
  const reportTelemetry = ___sap_ux_private_control_property_editor_common['reportTelemetry'];
@@ -15,6 +16,7 @@ sap.ui.define([
15
16
  const getTextBundle = ___i18n['getTextBundle'];
16
17
  const getControlById = ___utils_core['getControlById'];
17
18
  const getUi5Version = ___utils_version['getUi5Version'];
19
+ const getApplicationType = ___utils_application['getApplicationType'];
18
20
  class ContextMenuService {
19
21
  sendAction = () => {
20
22
  };
@@ -36,7 +38,8 @@ sap.ui.define([
36
38
  category: 'OutlineContextMenu',
37
39
  actionName,
38
40
  controlName,
39
- ui5Version: `${ versionInfo.major }.${ versionInfo.minor }.${ versionInfo.patch }`
41
+ ui5Version: `${ versionInfo.major }.${ versionInfo.minor }.${ versionInfo.patch }`,
42
+ appType: getApplicationType(this.rta.getRootControlInstance().getManifest())
40
43
  });
41
44
  } catch (err) {
42
45
  Log.error('Error in reporting Telemetry:', err);
@@ -12,6 +12,7 @@ import { getTextBundle } from '../i18n';
12
12
  import Log from 'sap/base/Log';
13
13
  import { getControlById } from '../utils/core';
14
14
  import { getUi5Version } from '../utils/version';
15
+ import { getApplicationType } from '../utils/application';
15
16
 
16
17
  /**
17
18
  * A Class of ContextMenuService
@@ -46,7 +47,8 @@ export class ContextMenuService {
46
47
  category: 'OutlineContextMenu',
47
48
  actionName,
48
49
  controlName,
49
- ui5Version: `${versionInfo.major}.${versionInfo.minor}.${versionInfo.patch}`
50
+ ui5Version: `${versionInfo.major}.${versionInfo.minor}.${versionInfo.patch}`,
51
+ appType: getApplicationType(this.rta.getRootControlInstance().getManifest())
50
52
  });
51
53
  } catch (err) {
52
54
  Log.error('Error in reporting Telemetry:', err);
@@ -3,8 +3,10 @@ sap.ui.define([
3
3
  'sap/base/Log',
4
4
  'open/ux/preview/client/thirdparty/@sap-ux-private/control-property-editor-common',
5
5
  '../../i18n',
6
- '../../adp/dialog-factory'
7
- ], function (Log, ___sap_ux_private_control_property_editor_common, ____i18n, ____adp_dialog_factory) {
6
+ '../../adp/dialog-factory',
7
+ '../../utils/application',
8
+ '../../utils/version'
9
+ ], function (Log, ___sap_ux_private_control_property_editor_common, ____i18n, ____adp_dialog_factory, ____utils_application, ____utils_version) {
8
10
  'use strict';
9
11
  const executeQuickAction = ___sap_ux_private_control_property_editor_common['executeQuickAction'];
10
12
  const quickActionListChanged = ___sap_ux_private_control_property_editor_common['quickActionListChanged'];
@@ -15,6 +17,8 @@ sap.ui.define([
15
17
  const reportTelemetry = ___sap_ux_private_control_property_editor_common['reportTelemetry'];
16
18
  const getTextBundle = ____i18n['getTextBundle'];
17
19
  const DialogFactory = ____adp_dialog_factory['DialogFactory'];
20
+ const getApplicationType = ____utils_application['getApplicationType'];
21
+ const getUi5Version = ____utils_version['getUi5Version'];
18
22
  class QuickActionService {
19
23
  sendAction = () => {
20
24
  };
@@ -104,11 +108,14 @@ sap.ui.define([
104
108
  }
105
109
  async executeAction(actionInstance, payload) {
106
110
  try {
111
+ const versionInfo = await getUi5Version();
107
112
  await reportTelemetry({
108
113
  category: 'QuickAction',
109
114
  actionName: actionInstance.type,
110
115
  telemetryEventIdentifier: actionInstance.getTelemetryIdentifier(true),
111
- quickActionSteps: actionInstance.quickActionSteps
116
+ quickActionSteps: actionInstance.quickActionSteps,
117
+ appType: getApplicationType(this.rta.getRootControlInstance().getManifest()),
118
+ ui5Version: `${ versionInfo.major }.${ versionInfo.minor }.${ versionInfo.patch }`
112
119
  });
113
120
  } catch (error) {
114
121
  Log.error('Error in reporting Telemetry:', error);
@@ -23,6 +23,9 @@ import { OutlineService } from '../outline/service';
23
23
  import { getTextBundle, TextBundle } from '../../i18n';
24
24
  import { ChangeService } from '../changes';
25
25
  import { DialogFactory } from '../../adp/dialog-factory';
26
+ import { getApplicationType } from '../../utils/application';
27
+ import { getUi5Version } from '../../utils/version';
28
+
26
29
 
27
30
  /**
28
31
  * Service providing Quick Actions.
@@ -152,11 +155,14 @@ export class QuickActionService implements Service {
152
155
 
153
156
  private async executeAction(actionInstance: QuickActionDefinition, payload: QuickActionExecutionPayload) {
154
157
  try {
158
+ const versionInfo = await getUi5Version();
155
159
  await reportTelemetry({
156
160
  category: 'QuickAction',
157
161
  actionName: actionInstance.type,
158
162
  telemetryEventIdentifier: actionInstance.getTelemetryIdentifier(true),
159
- quickActionSteps: actionInstance.quickActionSteps
163
+ quickActionSteps: actionInstance.quickActionSteps,
164
+ appType: getApplicationType(this.rta.getRootControlInstance().getManifest()),
165
+ ui5Version: `${versionInfo.major}.${versionInfo.minor}.${versionInfo.patch}`
160
166
  });
161
167
  } catch (error) {
162
168
  Log.error('Error in reporting Telemetry:', error);
@@ -176,8 +176,25 @@ sap.ui.define([
176
176
  document.title = resourceBundle.getText(i18nKey) ?? document.title;
177
177
  }
178
178
  }
179
+ function addCardGenerationUserAction(componentInstance, container) {
180
+ sap.ui.require(['sap/cards/ap/generator/CardGenerator'], async CardGenerator => {
181
+ const extensionService = await container.getServiceAsync('Extension');
182
+ const controlProperties = {
183
+ icon: 'sap-icon://add',
184
+ id: 'generate_card',
185
+ text: 'Generate Card',
186
+ tooltip: 'Generate Card',
187
+ press: () => {
188
+ CardGenerator.initializeAsync(componentInstance);
189
+ }
190
+ };
191
+ const parameters = { controlType: 'sap.ushell.ui.launchpad.ActionItem' };
192
+ const generateCardAction = await extensionService.createUserAction(controlProperties, parameters);
193
+ generateCardAction.showForCurrentApp();
194
+ });
195
+ }
179
196
  async function init(_ref) {
180
- let {appUrls, flex, customInit, enhancedHomePage} = _ref;
197
+ let {appUrls, flex, customInit, enhancedHomePage, enableCardGenerator} = _ref;
181
198
  const urlParams = new URLSearchParams(window.location.search);
182
199
  const container = sap?.ushell?.Container ?? (await __ui5_require_async('sap/ushell/Container')).default;
183
200
  let scenario = '';
@@ -218,6 +235,20 @@ sap.ui.define([
218
235
  });
219
236
  });
220
237
  }
238
+ if (enableCardGenerator && !isLowerThanMinimalUi5Version(ui5VersionInfo, {
239
+ major: 1,
240
+ minor: 121
241
+ })) {
242
+ container.attachRendererCreatedEvent(async function () {
243
+ const lifecycleService = await container.getServiceAsync('AppLifeCycle');
244
+ lifecycleService.attachAppLoaded(event => {
245
+ const componentInstance = event.getParameter('componentInstance');
246
+ addCardGenerationUserAction(componentInstance, container);
247
+ });
248
+ });
249
+ } else {
250
+ Log.warning('Card generator is not supported for the current UI5 version.');
251
+ }
221
252
  if (urlParams.get('fiori-tools-iapp-state')?.toLocaleLowerCase() !== 'true') {
222
253
  await resetAppState(container);
223
254
  }
@@ -243,7 +274,8 @@ sap.ui.define([
243
274
  appUrls: bootstrapConfig.getAttribute('data-open-ux-preview-libs-manifests'),
244
275
  flex: bootstrapConfig.getAttribute('data-open-ux-preview-flex-settings'),
245
276
  customInit: bootstrapConfig.getAttribute('data-open-ux-preview-customInit'),
246
- enhancedHomePage: !!bootstrapConfig.getAttribute('data-open-ux-preview-enhanced-homepage')
277
+ enhancedHomePage: !!bootstrapConfig.getAttribute('data-open-ux-preview-enhanced-homepage'),
278
+ enableCardGenerator: !!bootstrapConfig.getAttribute('data-open-ux-preview-enable-card-generator')
247
279
  }).catch(e => {
248
280
  const error = getError(e);
249
281
  Log.error('Sandbox initialization failed: ' + error.message);
@@ -13,6 +13,9 @@ import initConnectors from './initConnectors';
13
13
  import { getUi5Version, isLowerThanMinimalUi5Version, Ui5VersionInfo } from '../utils/version';
14
14
  import { CommunicationService } from '../cpe/communication-service';
15
15
  import { getTextBundle } from '../i18n';
16
+ import type Component from 'sap/ui/core/Component';
17
+ import type Extension from 'sap/ushell/services/Extension';
18
+ import type { CardGeneratorType } from 'sap/cards/ap/generator';
16
19
 
17
20
  /**
18
21
  * SAPUI5 delivered namespaces from https://ui5.sap.com/#/api/sap
@@ -251,6 +254,34 @@ export function setI18nTitle(resourceBundle: ResourceBundle, i18nKey = 'appTitle
251
254
  }
252
255
  }
253
256
 
257
+ /**
258
+ * This function dynamically adds a "Generate Card" action to the SAP Fiori Launchpad for the given component instance.
259
+ *
260
+ * @param componentInstance - The instance of the component for which the card generation action is being added.
261
+ * @param container - The SAP Fiori Launchpad container instance used to access services.
262
+ */
263
+ function addCardGenerationUserAction(componentInstance : Component, container : typeof sap.ushell.Container) {
264
+ sap.ui.require([
265
+ 'sap/cards/ap/generator/CardGenerator'
266
+ ], async (CardGenerator : CardGeneratorType) => {
267
+ const extensionService = await container.getServiceAsync<Extension>('Extension');
268
+ const controlProperties = {
269
+ icon: 'sap-icon://add',
270
+ id: 'generate_card',
271
+ text: 'Generate Card',
272
+ tooltip: 'Generate Card',
273
+ press: () => {
274
+ CardGenerator.initializeAsync(componentInstance);
275
+ }
276
+ };
277
+ const parameters = {
278
+ controlType: 'sap.ushell.ui.launchpad.ActionItem'
279
+ };
280
+ const generateCardAction = await extensionService.createUserAction(controlProperties, parameters);
281
+ generateCardAction.showForCurrentApp();
282
+ });
283
+ }
284
+
254
285
  /**
255
286
  * Apply additional configuration and initialize sandbox.
256
287
  *
@@ -265,12 +296,14 @@ export async function init({
265
296
  appUrls,
266
297
  flex,
267
298
  customInit,
268
- enhancedHomePage
299
+ enhancedHomePage,
300
+ enableCardGenerator
269
301
  }: {
270
302
  appUrls?: string | null;
271
303
  flex?: string | null;
272
304
  customInit?: string | null;
273
305
  enhancedHomePage?: boolean | null;
306
+ enableCardGenerator?: boolean
274
307
  }): Promise<void> {
275
308
  const urlParams = new URLSearchParams(window.location.search);
276
309
  const container = sap?.ushell?.Container ??
@@ -320,6 +353,17 @@ export async function init({
320
353
  });
321
354
  });
322
355
  }
356
+ if (enableCardGenerator && !isLowerThanMinimalUi5Version(ui5VersionInfo, { major: 1, minor: 121 })) {
357
+ container.attachRendererCreatedEvent(async function () {
358
+ const lifecycleService = await container.getServiceAsync<AppLifeCycle>('AppLifeCycle');
359
+ lifecycleService.attachAppLoaded((event) => {
360
+ const componentInstance = event.getParameter('componentInstance');
361
+ addCardGenerationUserAction(componentInstance as unknown as Component, container);
362
+ });
363
+ });
364
+ } else {
365
+ Log.warning('Card generator is not supported for the current UI5 version.');
366
+ }
323
367
 
324
368
  // reset app state if requested
325
369
  if (urlParams.get('fiori-tools-iapp-state')?.toLocaleLowerCase() !== 'true') {
@@ -362,7 +406,8 @@ if (bootstrapConfig) {
362
406
  appUrls: bootstrapConfig.getAttribute('data-open-ux-preview-libs-manifests'),
363
407
  flex: bootstrapConfig.getAttribute('data-open-ux-preview-flex-settings'),
364
408
  customInit: bootstrapConfig.getAttribute('data-open-ux-preview-customInit'),
365
- enhancedHomePage: !!bootstrapConfig.getAttribute('data-open-ux-preview-enhanced-homepage')
409
+ enhancedHomePage: !!bootstrapConfig.getAttribute('data-open-ux-preview-enhanced-homepage'),
410
+ enableCardGenerator: !!bootstrapConfig.getAttribute('data-open-ux-preview-enable-card-generator')
366
411
  }).catch((e) => {
367
412
  const error = getError(e);
368
413
  Log.error('Sandbox initialization failed: ' + error.message);
@@ -105,6 +105,9 @@ export type TestConfigDefaults = {
105
105
  framework: 'Testsuite';
106
106
  };
107
107
  };
108
+ export type CardGeneratorConfig = {
109
+ path?: string;
110
+ };
108
111
  /**
109
112
  * Middleware configuration.
110
113
  */
@@ -117,6 +120,7 @@ export interface MiddlewareConfig {
117
120
  rta?: InternalRtaConfig;
118
121
  editors?: {
119
122
  rta?: RtaConfig;
123
+ cardGenerator?: CardGeneratorConfig;
120
124
  };
121
125
  adp?: AdpPreviewConfig;
122
126
  debug?: boolean;
@@ -229,5 +233,23 @@ export declare const FLPHomePageDefaults: {
229
233
  catalogId: string;
230
234
  sectionId: string;
231
235
  };
236
+ export interface MultiCardsPayload {
237
+ type: string;
238
+ manifest: CardManifest;
239
+ entitySet: string;
240
+ }
241
+ export interface I18nEntry {
242
+ key: string;
243
+ value: string;
244
+ comment?: string;
245
+ annotation?: string;
246
+ }
247
+ export interface CardManifest {
248
+ 'sap.insights': {
249
+ versions?: {
250
+ dtpMiddleware?: string;
251
+ };
252
+ };
253
+ }
232
254
  export {};
233
255
  //# sourceMappingURL=index.d.ts.map
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Apreview-middleware"
11
11
  },
12
- "version": "0.20.2",
12
+ "version": "0.20.4",
13
13
  "license": "Apache-2.0",
14
14
  "author": "@SAP/ux-tools-team",
15
15
  "main": "dist/index.js",
@@ -28,10 +28,10 @@
28
28
  "@sap-ux/adp-tooling": "0.14.2",
29
29
  "@sap-ux/btp-utils": "1.1.0",
30
30
  "@sap-ux/control-property-editor-sources": "npm:@sap-ux/control-property-editor@0.6.5",
31
- "@sap-ux/feature-toggle": "0.3.0",
32
31
  "@sap-ux/logger": "0.7.0",
33
32
  "@sap-ux/project-access": "1.30.1",
34
- "@sap-ux/system-access": "0.6.0"
33
+ "@sap-ux/system-access": "0.6.0",
34
+ "@sap-ux/feature-toggle": "0.3.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@sap-ux-private/playwright": "0.2.0",
@@ -49,7 +49,7 @@
49
49
  "nock": "13.4.0",
50
50
  "npm-run-all2": "6.2.0",
51
51
  "supertest": "6.3.3",
52
- "@private/preview-middleware-client": "npm:@sap-ux-private/preview-middleware-client@0.14.1",
52
+ "@private/preview-middleware-client": "npm:@sap-ux-private/preview-middleware-client@0.14.3",
53
53
  "@sap-ux/axios-extension": "1.21.0",
54
54
  "@sap-ux/i18n": "0.3.0",
55
55
  "@sap-ux/store": "1.1.0",
@@ -42,6 +42,9 @@
42
42
  data-sap-ui-resourceroots='<%- JSON.stringify(ui5.resources) %>'
43
43
  data-sap-ui-frameOptions="allow"
44
44
  data-sap-ui-xx-componentPreload="off"<%- ui5.bootstrapOptions %>
45
+ <% if (enableCardGenerator) { %>
46
+ data-open-ux-preview-enable-card-generator="<%- enableCardGenerator %>"
47
+ <% } %>
45
48
  data-sap-ui-oninit="module:open/ux/preview/client/flp/init"<% if (locals.init) { %>
46
49
  data-open-ux-preview-customInit='<%- init %>'<% } if (locals.flex) { %>
47
50
  data-open-ux-preview-features='<%- JSON.stringify(features) %>'
@@ -59,6 +59,9 @@
59
59
  data-sap-ui-resourceroots='<%- JSON.stringify(ui5.resources) %>'
60
60
  data-sap-ui-frameOptions="allow"
61
61
  data-sap-ui-xx-componentPreload="off"<%- ui5.bootstrapOptions %>
62
+ <% if (enableCardGenerator) { %>
63
+ data-open-ux-preview-enable-card-generator="<%- enableCardGenerator %>"
64
+ <% } %>
62
65
  data-sap-ui-oninit="module:open/ux/preview/client/flp/init"<% if (locals.init) { %>
63
66
  data-open-ux-preview-customInit='<%- init %>'<% } if (locals.flex) { %>
64
67
  data-open-ux-preview-features='<%- JSON.stringify(features) %>'
@@ -57,6 +57,9 @@
57
57
  data-sap-ui-resource-roots='<%- JSON.stringify(ui5.resources) %>'
58
58
  data-sap-ui-frame-options="allow"
59
59
  data-sap-ui-xx-component-preload="off"<%- ui5.bootstrapOptions %>
60
+ <% if (enableCardGenerator) { %>
61
+ data-open-ux-preview-enable-card-generator="<%- enableCardGenerator %>"
62
+ <% } %>
60
63
  data-sap-ui-on-init="module:open/ux/preview/client/flp/init"<% if (locals.init) { %>
61
64
  data-open-ux-preview-customInit='<%- init %>'<% } if (locals.flex) { %>
62
65
  data-open-ux-preview-features='<%- JSON.stringify(features) %>'