@sap-ux/fe-fpm-writer 0.42.20 → 0.43.0

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.
@@ -82,7 +82,7 @@ async function generateBuildingBlock(basePath, config, fs) {
82
82
  const { path: manifestPath, content: manifest } = await (0, utils_1.getManifest)(basePath, fs);
83
83
  // Read the view xml and template files and update contents of the view xml file
84
84
  const xmlDocument = getUI5XmlDocument(basePath, viewOrFragmentPath, fs);
85
- const { updatedAggregationPath, processedBuildingBlockData, hasAggregation, aggregationNamespace } = (0, processor_1.processBuildingBlock)(buildingBlockData, xmlDocument, manifestPath, manifest, aggregationPath, fs);
85
+ const { updatedAggregationPath, processedBuildingBlockData, hasAggregation, aggregationNamespace } = (0, processor_1.processBuildingBlock)({ ...buildingBlockData, generateId: fnGenerateId }, xmlDocument, manifestPath, manifest, aggregationPath, fs);
86
86
  const templateConfig = {
87
87
  hasAggregation,
88
88
  aggregationNamespace
@@ -1,10 +1,14 @@
1
1
  import type { Editor } from 'mem-fs-editor';
2
- import { BuildingBlockType, type BuildingBlock, type EmbededFragment } from './types';
2
+ import { BuildingBlockType, type BuildingBlock, type EmbededFragment, type EmbeddedAction } from './types';
3
3
  import type { Manifest, InternalCustomElement } from '../common/types';
4
4
  /**
5
5
  * Type for embedded fragment data used in building block processing.
6
6
  */
7
7
  type EmbeddedFragmentData = InternalCustomElement & EmbededFragment;
8
+ /**
9
+ * Type for embedded action data used in building block processing for custom actions.
10
+ */
11
+ type EmbeddedActionData = InternalCustomElement & EmbeddedAction;
8
12
  /**
9
13
  * Namespace for XML elements.
10
14
  */
@@ -22,6 +26,7 @@ interface ProcessingContext {
22
26
  embeddedFragment?: EmbeddedFragmentData;
23
27
  updatedAggregationPath?: string;
24
28
  hasAggregation?: boolean;
29
+ embeddedAction?: EmbeddedActionData;
25
30
  }
26
31
  /**
27
32
  * Configuration for building block templates.
@@ -78,6 +78,11 @@ exports.BUILDING_BLOCK_CONFIG = {
78
78
  aggregationConfig: { aggregationName: 'buttonGroups', elementName: 'ButtonGroup' },
79
79
  namespace: { uri: 'sap.fe.macros', prefix: 'macros' },
80
80
  processor: processRichTextEditorButtonGroups
81
+ },
82
+ [types_1.BuildingBlockType.Action]: {
83
+ aggregationConfig: { aggregationName: 'actions', elementName: 'Action' },
84
+ namespace: { uri: 'sap.fe.macros.table', prefix: 'macrosTable' },
85
+ processor: processAction
81
86
  }
82
87
  };
83
88
  /**
@@ -95,13 +100,14 @@ function getBuildingBlockConfig(buildingBlockType) {
95
100
  return config;
96
101
  }
97
102
  /**
98
- * Type guard to check if the building block data is a custom column.
103
+ * Checks if the building block data matches a specific type.
99
104
  *
100
105
  * @param {BuildingBlock} data - The building block data to check
101
- * @returns {boolean} True if the data is a custom column
106
+ * @param {BuildingBlockType} type - The building block type to check against
107
+ * @returns {boolean} True if the data matches the specified type
102
108
  */
103
- function isCustomColumn(data) {
104
- return data.buildingBlockType === types_1.BuildingBlockType.CustomColumn;
109
+ function isBuildingBlockType(data, type) {
110
+ return data.buildingBlockType === type;
105
111
  }
106
112
  /**
107
113
  * Processes custom column building block.
@@ -111,7 +117,7 @@ function isCustomColumn(data) {
111
117
  */
112
118
  function processCustomColumn(buildingBlockData, context) {
113
119
  const { fs, viewPath } = context;
114
- if (!isCustomColumn(buildingBlockData)) {
120
+ if (!isBuildingBlockType(buildingBlockData, types_1.BuildingBlockType.CustomColumn)) {
115
121
  throw new Error('Expected CustomColumn building block data');
116
122
  }
117
123
  const config = getBuildingBlockConfig(types_1.BuildingBlockType.CustomColumn);
@@ -130,15 +136,6 @@ function processCustomColumn(buildingBlockData, context) {
130
136
  fs.copyTpl((0, templates_1.getTemplatePath)(config.templateFile), viewPath, columnConfig);
131
137
  }
132
138
  }
133
- /**
134
- * Type guard to check if the building block data is a custom filter field.
135
- *
136
- * @param {BuildingBlock} data - The building block data to check
137
- * @returns {boolean} True if the data is a custom filter field
138
- */
139
- function isCustomFilterField(data) {
140
- return data.buildingBlockType === types_1.BuildingBlockType.CustomFilterField;
141
- }
142
139
  /**
143
140
  * Processes custom filter field building block.
144
141
  *
@@ -147,7 +144,7 @@ function isCustomFilterField(data) {
147
144
  */
148
145
  function processCustomFilterField(buildingBlockData, context) {
149
146
  const { fs, viewPath, embeddedFragment } = context;
150
- if (!isCustomFilterField(buildingBlockData)) {
147
+ if (!isBuildingBlockType(buildingBlockData, types_1.BuildingBlockType.CustomFilterField)) {
151
148
  throw new Error('Expected CustomFilterField building block data');
152
149
  }
153
150
  if (!embeddedFragment) {
@@ -173,9 +170,9 @@ function processCustomFilterField(buildingBlockData, context) {
173
170
  });
174
171
  }
175
172
  const configKey = config.templateFile;
176
- const additionnalDataConfig = file_1.CONFIG[configKey];
177
- if (additionnalDataConfig?.getData) {
178
- const additionalContext = additionnalDataConfig.getData(buildingBlockData.generateId, buildingBlockData);
173
+ const additionalDataConfig = file_1.CONFIG[configKey];
174
+ if (additionalDataConfig?.getData) {
175
+ const additionalContext = additionalDataConfig.getData(buildingBlockData.generateId);
179
176
  filterConfig = { ...filterConfig, ...additionalContext };
180
177
  }
181
178
  if (viewPath && !fs.exists(viewPath)) {
@@ -281,22 +278,6 @@ function mergeButtonGroups(existingButtonGroupsMap, rteButtonGroups) {
281
278
  };
282
279
  });
283
280
  }
284
- /**
285
- * Type guard to check if the building block data is a rich text editor button groups.
286
- *
287
- * @param {BuildingBlock} data - The building block data to check
288
- * @returns {boolean} True if the data is a rich text editor button groups
289
- */
290
- function isRichTextEditorButtonGroups(data) {
291
- return data.buildingBlockType === types_1.BuildingBlockType.RichTextEditorButtonGroups;
292
- }
293
- /**
294
- *
295
- * @param data
296
- */
297
- function isRichTextEditor(data) {
298
- return data.buildingBlockType === types_1.BuildingBlockType.RichTextEditor;
299
- }
300
281
  /**
301
282
  * Processes rich text editor button groups building block.
302
283
  *
@@ -305,7 +286,8 @@ function isRichTextEditor(data) {
305
286
  */
306
287
  function processRichTextEditorButtonGroups(buildingBlockData, context) {
307
288
  const { xmlDocument, updatedAggregationPath, hasAggregation } = context;
308
- if (!isRichTextEditorButtonGroups(buildingBlockData) && !isRichTextEditor(buildingBlockData)) {
289
+ if (!isBuildingBlockType(buildingBlockData, types_1.BuildingBlockType.RichTextEditorButtonGroups) &&
290
+ !isBuildingBlockType(buildingBlockData, types_1.BuildingBlockType.RichTextEditor)) {
309
291
  throw new Error('Expected RichTextEditorButtonGroups or RichTextEditor building block data');
310
292
  }
311
293
  const existingButtonGroupsMap = new Map();
@@ -369,6 +351,44 @@ function updateAggregationPath(xmlDocument, aggregationPath, config, namespace)
369
351
  }
370
352
  return { updatedAggregationPath: aggregationPath, hasElement: false };
371
353
  }
354
+ /**
355
+ * Processes custom action building blocks.
356
+ *
357
+ * @param buildingBlockData - The building block data
358
+ * @param context - Processing context
359
+ */
360
+ function processAction(buildingBlockData, context) {
361
+ const { fs } = context;
362
+ if (!isBuildingBlockType(buildingBlockData, types_1.BuildingBlockType.Action)) {
363
+ throw new Error('Expected Action building block data');
364
+ }
365
+ const actionConfig = buildingBlockData.embeddedAction;
366
+ if (typeof actionConfig.eventHandler === 'object') {
367
+ const processedEventHandler = (0, event_handler_1.applyEventHandlerConfiguration)(fs, actionConfig, actionConfig.eventHandler, {
368
+ typescript: actionConfig.typescript
369
+ });
370
+ const fnName = actionConfig.eventHandler ? actionConfig.eventHandler.fnName : processedEventHandler;
371
+ // Check if file name includes .controller
372
+ if (actionConfig.eventHandler.fileName?.includes('.controller')) {
373
+ // Controller method: use fnName as is, no core:require needed
374
+ actionConfig.eventHandler = {
375
+ fnName: `.${fnName}`
376
+ };
377
+ }
378
+ else {
379
+ // Custom handler file: use handler alias with core:require
380
+ let handlerPath;
381
+ if (actionConfig.eventHandler.fileName) {
382
+ const path = context.embeddedAction?.ns?.split('.').join('/');
383
+ handlerPath = node_path_1.posix.join(path ?? '', actionConfig.eventHandler.fileName);
384
+ }
385
+ actionConfig.eventHandler = {
386
+ fnName: `handler.${fnName}`,
387
+ fileName: handlerPath
388
+ };
389
+ }
390
+ }
391
+ }
372
392
  /**
373
393
  * Processes building block configuration.
374
394
  *
@@ -397,7 +417,8 @@ function processBuildingBlock(buildingBlockData, xmlDocument, manifestPath, mani
397
417
  aggregationNamespace
398
418
  };
399
419
  }
400
- if (isRichTextEditorButtonGroups(buildingBlockData) || isRichTextEditor(buildingBlockData)) {
420
+ if (isBuildingBlockType(buildingBlockData, types_1.BuildingBlockType.RichTextEditorButtonGroups) ||
421
+ isBuildingBlockType(buildingBlockData, types_1.BuildingBlockType.RichTextEditor)) {
401
422
  const result = updateAggregationPath(xmlDocument, aggregationPath, {
402
423
  aggregationName: config.aggregationConfig.aggregationName,
403
424
  elementName: config.aggregationConfig.elementName
@@ -415,7 +436,8 @@ function processBuildingBlock(buildingBlockData, xmlDocument, manifestPath, mani
415
436
  aggregationNamespace = (0, xml_1.getOrAddNamespace)(xmlDocument, config.namespace.uri, config.namespace.prefix);
416
437
  }
417
438
  // Process embedded fragment for types that support it
418
- if ((isCustomColumn(buildingBlockData) || isCustomFilterField(buildingBlockData)) &&
439
+ if ((isBuildingBlockType(buildingBlockData, types_1.BuildingBlockType.CustomColumn) ||
440
+ isBuildingBlockType(buildingBlockData, types_1.BuildingBlockType.CustomFilterField)) &&
419
441
  buildingBlockData.embededFragment) {
420
442
  embeddedFragment = (0, defaults_1.setCommonDefaults)(buildingBlockData.embededFragment, manifestPath, manifest);
421
443
  viewPath = (0, node_path_1.join)(embeddedFragment.path, `${embeddedFragment.fragmentFile ?? embeddedFragment.name}.fragment.xml`);
@@ -434,6 +456,23 @@ function processBuildingBlock(buildingBlockData, xmlDocument, manifestPath, mani
434
456
  hasAggregation = result.hasElement;
435
457
  aggregationNamespace = (0, xml_1.getOrAddNamespace)(xmlDocument, config.namespace.uri, config.namespace.prefix);
436
458
  }
459
+ if (isBuildingBlockType(buildingBlockData, types_1.BuildingBlockType.Action) && buildingBlockData.embeddedAction) {
460
+ const result = updateAggregationPath(xmlDocument, aggregationPath, {
461
+ aggregationName: config.aggregationConfig.aggregationName,
462
+ elementName: config.aggregationConfig.elementName
463
+ });
464
+ const context = {
465
+ fs,
466
+ xmlDocument,
467
+ updatedAggregationPath: result.updatedAggregationPath,
468
+ hasAggregation: result.hasElement,
469
+ embeddedAction: (0, defaults_1.setCommonDefaults)(buildingBlockData.embeddedAction, manifestPath, manifest)
470
+ };
471
+ config.processor(buildingBlockData, context);
472
+ updatedAggregationPath = result.updatedAggregationPath;
473
+ hasAggregation = result.hasElement;
474
+ (0, xml_1.getOrAddNamespace)(xmlDocument, config.namespace.uri, config.namespace.prefix);
475
+ }
437
476
  return {
438
477
  updatedAggregationPath,
439
478
  processedBuildingBlockData: buildingBlockData,
@@ -20,6 +20,7 @@ const xml_1 = require("./xml");
20
20
  const i18n_1 = require("../../../i18n");
21
21
  const prompt_helpers_1 = require("./prompt-helpers");
22
22
  const file_1 = require("../../../common/file");
23
+ const utils_1 = require("../../../common/utils");
23
24
  /* eslint-disable @typescript-eslint/no-floating-promises */
24
25
  (0, i18n_1.initI18n)();
25
26
  const t = (0, i18n_1.translate)(i18n_1.i18nNamespaces.buildingBlock, 'prompts.common.');
@@ -374,7 +375,7 @@ function getBuildingBlockIdPrompt(context, validationErrorMessage, properties =
374
375
  }
375
376
  else {
376
377
  return answers?.viewOrFragmentPath &&
377
- !(0, xml_1.isElementIdAvailable)(fs, (0, node_path_1.join)(appPath, answers.viewOrFragmentPath), value)
378
+ !(0, utils_1.isElementIdAvailable)(fs, (0, node_path_1.join)(appPath, answers.viewOrFragmentPath), value)
378
379
  ? t('id.existingIdValidation')
379
380
  : true;
380
381
  }
@@ -1,13 +1,4 @@
1
1
  import type { Editor } from 'mem-fs-editor';
2
- /**
3
- * Method validates if passed id is available.
4
- *
5
- * @param fs - the file system object for reading files
6
- * @param viewOrFragmentPath - path to fragment or view file
7
- * @param id - id to check/validate
8
- * @returns true if passed id is available.
9
- */
10
- export declare function isElementIdAvailable(fs: Editor, viewOrFragmentPath: string, id: string): boolean;
11
2
  /**
12
3
  * Converts the provided xpath string from `/mvc:View/Page/content` to
13
4
  * `/mvc:View/*[local-name()='Page']/*[local-name()='content']`.
@@ -34,26 +34,12 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.augmentXpathWithLocalNames = void 0;
37
- exports.isElementIdAvailable = isElementIdAvailable;
38
37
  exports.getXPathStringsForXmlFile = getXPathStringsForXmlFile;
39
38
  exports.getFilterBarIdsInFile = getFilterBarIdsInFile;
40
39
  exports.getExistingButtonGroups = getExistingButtonGroups;
41
40
  exports.getOrAddNamespace = getOrAddNamespace;
42
41
  const xmldom_1 = require("@xmldom/xmldom");
43
42
  const xpath = __importStar(require("xpath"));
44
- /**
45
- * Method validates if passed id is available.
46
- *
47
- * @param fs - the file system object for reading files
48
- * @param viewOrFragmentPath - path to fragment or view file
49
- * @param id - id to check/validate
50
- * @returns true if passed id is available.
51
- */
52
- function isElementIdAvailable(fs, viewOrFragmentPath, id) {
53
- const xmlContent = fs.read(viewOrFragmentPath).toString();
54
- const xmlDocument = new xmldom_1.DOMParser({ errorHandler: () => { } }).parseFromString(xmlContent);
55
- return xmlDocument.documentElement ? !xmlDocument.getElementById(id) : true;
56
- }
57
43
  /**
58
44
  * Converts the provided xpath string from `/mvc:View/Page/content` to
59
45
  * `/mvc:View/*[local-name()='Page']/*[local-name()='content']`.
@@ -15,7 +15,8 @@ export declare enum BuildingBlockType {
15
15
  Table = "table",
16
16
  CustomColumn = "custom-column",
17
17
  RichTextEditor = "rich-text-editor",
18
- RichTextEditorButtonGroups = "rich-text-editor-button-groups"
18
+ RichTextEditorButtonGroups = "rich-text-editor-button-groups",
19
+ Action = "action"
19
20
  }
20
21
  /**
21
22
  * Binding context type.
@@ -425,6 +426,56 @@ export interface CustomColumn extends BuildingBlock {
425
426
  position?: Position;
426
427
  embededFragment?: EmbededFragment;
427
428
  }
429
+ /**
430
+ * Building block for adding custom actions to tables.
431
+ * Custom actions can be added to table toolbars and can trigger controller methods or fragments.
432
+ *
433
+ * @see https://sapui5.hana.ondemand.com/#/api/sap.fe.macros.table.Action
434
+ * @example
435
+ * // Simple action with event handler
436
+ * <macros:Table id="MyTable" metaPath="@com.sap.vocabularies.UI.v1.LineItem">
437
+ * <macros:actions>
438
+ * <macrosTable:Action
439
+ * key="approveAction"
440
+ * text="Approve"
441
+ * press=".onApprove"
442
+ * requiresSelection="true"
443
+ * placement="After"
444
+ * />
445
+ * </macros:actions>
446
+ * </macros:Table>
447
+ * @extends {BuildingBlock}
448
+ */
449
+ export interface Action extends BuildingBlock {
450
+ /**
451
+ * Unique identifier of the action.
452
+ */
453
+ actionKey: string;
454
+ /**
455
+ * The text that will be displayed for this action.
456
+ */
457
+ text: string;
458
+ /**
459
+ * Reference to the key of another action already displayed in the toolbar to properly place this one.
460
+ */
461
+ anchor?: string;
462
+ /**
463
+ * Defines where this action should be placed relative to the defined anchor.
464
+ * Allowed values are 'Before' and 'After'.
465
+ */
466
+ placement?: 'Before' | 'After';
467
+ /**
468
+ * Defines if the action requires a selection.
469
+ *
470
+ * @default false
471
+ */
472
+ requiresSelection?: boolean;
473
+ /**
474
+ * This allows you to define event handlers, or custom XML elements for the action.
475
+ */
476
+ embeddedAction: EmbeddedAction;
477
+ }
478
+ export type EmbeddedAction = EventHandler & CustomFragment & CustomElement;
428
479
  export type EmbededFragment = EventHandler & CustomFragment & CustomElement & FragmentContentData;
429
480
  /**
430
481
  * Building block used to create a rich text editor based on the metadata provided by OData V4.
@@ -18,6 +18,7 @@ var BuildingBlockType;
18
18
  BuildingBlockType["CustomColumn"] = "custom-column";
19
19
  BuildingBlockType["RichTextEditor"] = "rich-text-editor";
20
20
  BuildingBlockType["RichTextEditorButtonGroups"] = "rich-text-editor-button-groups";
21
+ BuildingBlockType["Action"] = "action";
21
22
  })(BuildingBlockType || (exports.BuildingBlockType = BuildingBlockType = {}));
22
23
  exports.bindingContextAbsolute = 'absolute';
23
24
  exports.bindingContextRelative = 'relative';
@@ -1,16 +1,10 @@
1
1
  import type { CopyOptions, Editor } from 'mem-fs-editor';
2
2
  import type { TabInfo } from '../common/types';
3
3
  interface ButtonGroup {
4
- name: string;
5
- buttons: string[];
6
- visible?: boolean;
7
- priority?: number;
8
- customToolbarPriority?: number;
9
- row?: number;
10
4
  id?: string;
11
5
  }
12
6
  export type IdGeneratorFunction = (baseId: string, validatedIds?: string[]) => string;
13
- interface TemplateContext {
7
+ export interface TemplateContext {
14
8
  buttonGroups?: ButtonGroup[];
15
9
  name?: string;
16
10
  data?: {
@@ -49,7 +43,7 @@ export declare const CONFIG: {
49
43
  };
50
44
  };
51
45
  "building-block/rich-text-editor-button-groups/View.xml": {
52
- getData: (generateId: IdGeneratorFunction, context?: TemplateContext) => {
46
+ getData: (generateId: IdGeneratorFunction, context?: Partial<TemplateContext>) => {
53
47
  ids: Record<string, string>;
54
48
  };
55
49
  };
@@ -10,7 +10,7 @@ exports.copyTpl = copyTpl;
10
10
  exports.getRelativeTemplateComponentPath = getRelativeTemplateComponentPath;
11
11
  const node_path_1 = require("node:path");
12
12
  const file_1 = require("@sap-ux/project-access/dist/file");
13
- const utils_1 = require("../building-block/prompts/utils");
13
+ const utils_1 = require("./utils");
14
14
  const CHAR_SPACE = ' ';
15
15
  const CHAR_TAB = '\t';
16
16
  exports.CONFIG = {
@@ -82,7 +82,7 @@ exports.CONFIG = {
82
82
  const ids = {};
83
83
  const validatedIds = [];
84
84
  buttonGroups.forEach((group, index) => {
85
- const id = generateId(`${'ButtonGroup'}`, validatedIds);
85
+ const id = generateId('ButtonGroup', validatedIds);
86
86
  ids[index] = group.id ?? id;
87
87
  if (!group.id) {
88
88
  validatedIds.push(id);
@@ -48,4 +48,13 @@ export declare function getManifestPath(basePath: string, fs: Editor): Promise<s
48
48
  * @returns {Manifest | undefined} The content and path of the manifest
49
49
  */
50
50
  export declare function getManifest(basePath: string, fs: Editor, validate?: boolean): Promise<ManifestData>;
51
+ /**
52
+ * Method validates if passed id is available.
53
+ *
54
+ * @param fs - the file system object for reading files
55
+ * @param viewOrFragmentPath - path to fragment or view file
56
+ * @param id - id to check/validate
57
+ * @returns true if passed id is available.
58
+ */
59
+ export declare function isElementIdAvailable(fs: Editor, viewOrFragmentPath: string, id: string): boolean;
51
60
  //# sourceMappingURL=utils.d.ts.map
@@ -8,12 +8,14 @@ exports.insertTextAtPosition = insertTextAtPosition;
8
8
  exports.addExtensionTypes = addExtensionTypes;
9
9
  exports.getManifestPath = getManifestPath;
10
10
  exports.getManifest = getManifest;
11
+ exports.isElementIdAvailable = isElementIdAvailable;
11
12
  const node_os_1 = __importDefault(require("node:os"));
12
13
  const node_path_1 = require("node:path");
13
14
  const semver_1 = require("semver");
14
15
  const project_access_1 = require("@sap-ux/project-access");
15
16
  const templates_1 = require("../templates");
16
17
  const file_1 = require("./file");
18
+ const xmldom_1 = require("@xmldom/xmldom");
17
19
  /**
18
20
  * Method inserts passed text into content by char index position.
19
21
  * In case if position is out of range, then whitespaces would be created.
@@ -103,4 +105,17 @@ async function getManifest(basePath, fs, validate = true) {
103
105
  content: fs.readJSON(path)
104
106
  };
105
107
  }
108
+ /**
109
+ * Method validates if passed id is available.
110
+ *
111
+ * @param fs - the file system object for reading files
112
+ * @param viewOrFragmentPath - path to fragment or view file
113
+ * @param id - id to check/validate
114
+ * @returns true if passed id is available.
115
+ */
116
+ function isElementIdAvailable(fs, viewOrFragmentPath, id) {
117
+ const xmlContent = fs.read(viewOrFragmentPath).toString();
118
+ const xmlDocument = new xmldom_1.DOMParser({ errorHandler: () => { } }).parseFromString(xmlContent);
119
+ return xmlDocument.documentElement ? !xmlDocument.getElementById(id) : true;
120
+ }
106
121
  //# sourceMappingURL=utils.js.map
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@ export { CustomView } from './view/types';
14
14
  export { generateCustomView } from './view';
15
15
  export { enableFPM, FPMConfig } from './app';
16
16
  export { validateBasePath, validateVersion } from './common/validate';
17
- export { BuildingBlockType, FilterBar, Form, Chart, Field, FieldFormatOptions, Table, BuildingBlockConfig, Page, CustomColumn, CustomFilterField, RichTextEditor, ButtonGroupConfig } from './building-block/types';
17
+ export { BuildingBlockType, FilterBar, Form, Chart, Field, FieldFormatOptions, Table, BuildingBlockConfig, Page, CustomColumn, CustomFilterField, RichTextEditor, ButtonGroupConfig, Action } from './building-block/types';
18
18
  export { generateBuildingBlock, getSerializedFileContent } from './building-block';
19
19
  export { ChartPromptsAnswer, FilterBarPromptsAnswer, FormPromptsAnswer, TablePromptsAnswer, PagePromptsAnswer, RichTextEditorPromptsAnswer, RichTextEditorButtonGroupsPromptsAnswer, BuildingBlockTypePromptsAnswer } from './building-block/prompts/questions';
20
20
  export { PromptsType, SupportedGeneratorAnswers, PromptsAPI, PromptsGroup, Prompts, ValidationResults, Answers, Subset, CodeSnippet } from './prompts';
@@ -91,7 +91,7 @@ async function handlePageBuildingBlock(basePath, data, viewPath, fs, generateId,
91
91
  log?.warn(t('minUi5VersionRequirement', { minUI5Version: data.minUI5Version }));
92
92
  return;
93
93
  }
94
- const pageId = await generateId('Page');
94
+ const pageId = generateId('Page');
95
95
  await (0, building_block_1.generateBuildingBlock)(basePath, {
96
96
  viewOrFragmentPath: (0, node_path_1.relative)(basePath, viewPath),
97
97
  aggregationPath: (0, utils_2.augmentXpathWithLocalNames)(`/mvc:View/Page`),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sap-ux/fe-fpm-writer",
3
3
  "description": "SAP Fiori elements flexible programming model writer",
4
- "version": "0.42.20",
4
+ "version": "0.43.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -30,7 +30,7 @@
30
30
  "semver": "7.7.4",
31
31
  "xml-formatter": "2.6.1",
32
32
  "xpath": "0.0.33",
33
- "@sap-ux/fiori-annotation-api": "0.9.24",
33
+ "@sap-ux/fiori-annotation-api": "0.9.25",
34
34
  "@sap-ux/project-access": "1.35.10",
35
35
  "@sap-ux/logger": "0.8.1"
36
36
  },
@@ -0,0 +1,30 @@
1
+ <%_ if (!config?.hasAggregation) { _%>
2
+ <<%- macrosNamespace %>:actions>
3
+ <%_ } _%>
4
+ <<%- config?.aggregationNamespace %>:Action
5
+ <%_ if (data.embeddedAction?.eventHandler?.fileName) { _%>
6
+ core:require="{ handler: '<%- data.embeddedAction.eventHandler.fileName %>' }"
7
+ <%_ } _%>
8
+ <%_ if (data.id) { _%>
9
+ id="<%- data.id %>"
10
+ <%_ } _%>
11
+ <%_ if (data.actionKey) { _%>
12
+ key="<%- data.actionKey %>"
13
+ <%_ } _%>
14
+ text="<%- data.text %>"
15
+ <%_ if (data.embeddedAction?.eventHandler?.fnName) { _%>
16
+ press="<%- data.embeddedAction.eventHandler.fnName %>"
17
+ <%_ } _%>
18
+ <%_ if (data.anchor) { _%>
19
+ anchor="<%- data.anchor %>"
20
+ <%_ } _%>
21
+ <%_ if (data.placement) { _%>
22
+ placement="<%- data.placement %>"
23
+ <%_ } _%>
24
+ <%_ if (data.requiresSelection !== undefined) { _%>
25
+ requiresSelection="<%- data.requiresSelection %>"
26
+ <%_ } _%>
27
+ />
28
+ <%_ if (!config?.hasAggregation) { _%>
29
+ </<%- macrosNamespace %>:actions>
30
+ <%_ } _%>