@sap-ux/preview-middleware 0.23.99 → 0.23.101

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.
@@ -29,6 +29,7 @@ export type PreviewUrls = {
29
29
  */
30
30
  export interface TemplateConfig {
31
31
  basePath: string;
32
+ baseUrl: string;
32
33
  apps: Record<string, {
33
34
  title: string;
34
35
  description: string;
@@ -281,6 +281,7 @@ function createFlpTemplateConfig(config, manifest, resources = {}) {
281
281
  }
282
282
  return {
283
283
  basePath: basePath,
284
+ baseUrl: '',
284
285
  apps: {},
285
286
  init: initPath,
286
287
  ui5: {
@@ -385,9 +386,7 @@ async function generatePreviewFiles(basePath, config, fs, logger = new logger_1.
385
386
  // remove incorrect configurations
386
387
  sanitizeConfig(config, logger);
387
388
  // create file system if not provided
388
- if (!fs) {
389
- fs = (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
390
- }
389
+ fs ??= (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
391
390
  // generate FLP configuration
392
391
  const flpTemplate = (0, node_fs_1.readFileSync)((0, node_path_1.join)(TEMPLATE_PATH, 'flp/sandbox.ejs'), 'utf-8');
393
392
  const flpConfig = getFlpConfigWithDefaults(config.flp);
@@ -34,7 +34,7 @@ export declare class FlpSandbox {
34
34
  readonly rta?: RtaConfig;
35
35
  readonly test?: TestConfig[];
36
36
  readonly router: EnhancedRouter;
37
- private fs;
37
+ private readonly fs;
38
38
  private readonly logger;
39
39
  private readonly utils;
40
40
  private readonly project;
@@ -103,6 +103,7 @@ export declare class FlpSandbox {
103
103
  /**
104
104
  * Handler for the GET requests to the runtime adaptation editor in developer mode.
105
105
  *
106
+ * @param req the request
106
107
  * @param res the response
107
108
  * @param rta runtime adaptation configuration
108
109
  * @param previewUrl the url of the preview
package/dist/base/flp.js CHANGED
@@ -78,6 +78,7 @@ class FlpSandbox {
78
78
  * @param logger logger instance
79
79
  */
80
80
  constructor(config, project, utils, logger) {
81
+ this.fs = (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
81
82
  this.logger = logger;
82
83
  this.project = project;
83
84
  this.utils = utils;
@@ -220,12 +221,19 @@ class FlpSandbox {
220
221
  ? '@sap-ux/control-property-editor'
221
222
  : '@sap-ux/preview-middleware';
222
223
  await this.setApplicationDependencies();
223
- const config = { ...this.templateConfig };
224
- /* sap.ui.rta needs to be added to the list of preload libs for variants management and adaptation projects */
224
+ this.templateConfig.baseUrl = req['ui5-patched-router']?.baseUrl ?? '';
225
+ const ui5Version = await this.getUi5Version(req.protocol, req.headers.host, this.templateConfig.baseUrl);
226
+ this.checkDeleteConnectors(ui5Version.major, ui5Version.minor, ui5Version.isCdn);
227
+ if (ui5Version.major === 1 && ui5Version.minor <= 71) {
228
+ this.removeAsyncHintsRequests();
229
+ }
230
+ const config = structuredClone(this.templateConfig);
225
231
  if (!config.ui5.libs.includes('sap.ui.rta')) {
226
- const libs = config.ui5.libs.split(',');
227
- libs.push('sap.ui.rta');
228
- config.ui5.libs = libs.join(',');
232
+ // sap.ui.rta needs to be added to the list of preload libs for variants management and adaptation projects
233
+ config.ui5.libs += ',sap.ui.rta';
234
+ }
235
+ if (editor.developerMode) {
236
+ config.ui5.bootstrapOptions = serializeUi5Configuration(this.getDeveloperModeConfig(ui5Version.major));
229
237
  }
230
238
  config.flexSettings = {
231
239
  layer: rta.layer ?? 'CUSTOMER_BASE',
@@ -235,14 +243,6 @@ class FlpSandbox {
235
243
  pluginScript: editor.pluginScript
236
244
  };
237
245
  config.features = feature_toggle_1.FeatureToggleAccess.getAllFeatureToggles();
238
- const ui5Version = await this.getUi5Version(req.protocol, req.headers.host, req['ui5-patched-router']?.baseUrl);
239
- this.checkDeleteConnectors(ui5Version.major, ui5Version.minor, ui5Version.isCdn);
240
- if (editor.developerMode === true) {
241
- config.ui5.bootstrapOptions = serializeUi5Configuration(this.getDeveloperModeConfig(ui5Version.major));
242
- }
243
- if (ui5Version.major === 1 && ui5Version.minor <= 71) {
244
- this.removeAsyncHintsRequests();
245
- }
246
246
  return (0, ejs_1.render)(this.getSandboxTemplate(ui5Version), config);
247
247
  }
248
248
  /**
@@ -261,12 +261,13 @@ class FlpSandbox {
261
261
  /**
262
262
  * Handler for the GET requests to the runtime adaptation editor in developer mode.
263
263
  *
264
+ * @param req the request
264
265
  * @param res the response
265
266
  * @param rta runtime adaptation configuration
266
267
  * @param previewUrl the url of the preview
267
268
  * @private
268
269
  */
269
- async editorGetHandlerDeveloperMode(res, rta, previewUrl) {
270
+ async editorGetHandlerDeveloperMode(req, res, rta, previewUrl) {
270
271
  const scenario = rta.options?.scenario;
271
272
  let templatePreviewUrl = `${previewUrl}?sap-ui-xx-viewCache=false&fiori-tools-rta-mode=forAdaptation&sap-ui-rta-skip-flex-validation=true&sap-ui-xx-condense-changes=true#${this.flpConfig.intent.object}-${this.flpConfig.intent.action}`;
272
273
  if (scenario === 'ADAPTATION_PROJECT') {
@@ -280,12 +281,13 @@ class FlpSandbox {
280
281
  const envLivereloadUrl = (0, btp_utils_1.isAppStudio)() ? await (0, btp_utils_1.exposePort)(livereloadPort) : undefined;
281
282
  const html = (0, ejs_1.render)(template, {
282
283
  previewUrl: templatePreviewUrl,
283
- telemetry: rta.options?.telemetry ?? false,
284
+ telemetry: !!rta.options?.telemetry,
284
285
  appName: rta.options?.appName,
285
286
  scenario,
286
287
  livereloadPort,
287
288
  livereloadUrl: envLivereloadUrl,
288
- features: JSON.stringify(features)
289
+ features: JSON.stringify(features),
290
+ baseUrl: req['ui5-patched-router']?.baseUrl ?? ''
289
291
  });
290
292
  this.sendResponse(res, 'text/html', 200, html);
291
293
  }
@@ -302,7 +304,9 @@ class FlpSandbox {
302
304
  async editorGetHandler(req, res, rta, previewUrl, editor) {
303
305
  if (!req.query['fiori-tools-rta-mode']) {
304
306
  this.logger.debug(`Adjusting URL parameters for runtime adaptation mode. Redirecting to correct URL.`);
305
- const url = 'ui5-patched-router' in req ? (0, node_path_1.join)(req['ui5-patched-router']?.baseUrl ?? '', previewUrl) : previewUrl;
307
+ const url = 'ui5-patched-router' in req
308
+ ? node_path_1.posix.join(req['ui5-patched-router']?.baseUrl ?? '', previewUrl)
309
+ : previewUrl;
306
310
  const params = structuredClone(req.query);
307
311
  params['sap-ui-xx-viewCache'] = 'false';
308
312
  params['fiori-tools-rta-mode'] = 'true';
@@ -326,8 +330,8 @@ class FlpSandbox {
326
330
  if (editor.developerMode) {
327
331
  previewUrl = `${previewUrl}.inner.html`;
328
332
  editor.pluginScript ??= 'open/ux/preview/client/cpe/init';
329
- this.router.get(editor.path, async (_req, res) => {
330
- await this.editorGetHandlerDeveloperMode(res, rta, previewUrl);
333
+ this.router.get(editor.path, async (req, res) => {
334
+ await this.editorGetHandlerDeveloperMode(req, res, rta, previewUrl);
331
335
  });
332
336
  let path = (0, node_path_1.dirname)(editor.path);
333
337
  if (!path.endsWith('/')) {
@@ -352,7 +356,7 @@ class FlpSandbox {
352
356
  // connect API (karma test runner) has no request query property
353
357
  if ('query' in req && 'redirect' in res && !req.query['sap-ui-xx-viewCache']) {
354
358
  this.logger.debug(`Adjusting URL parameters for preview. Redirecting to correct URL.`);
355
- const url = 'ui5-patched-router' in req ? (0, node_path_1.join)(req['ui5-patched-router']?.baseUrl ?? '', req.path) : req.path;
359
+ const url = 'ui5-patched-router' in req ? node_path_1.posix.join(req['ui5-patched-router']?.baseUrl ?? '', req.path) : req.path;
356
360
  const params = structuredClone(req.query);
357
361
  params['sap-ui-xx-viewCache'] = 'false';
358
362
  res.redirect(302, `${url}?${new URLSearchParams(params)}`);
@@ -368,12 +372,15 @@ class FlpSandbox {
368
372
  next();
369
373
  }
370
374
  else {
375
+ // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
376
+ this.templateConfig.baseUrl = ('ui5-patched-router' in req && req['ui5-patched-router']?.baseUrl) || '';
371
377
  const ui5Version = await this.getUi5Version(
372
378
  //use protocol from request header referer as fallback for connect API (karma test runner)
373
379
  'protocol' in req
374
380
  ? req.protocol
375
- : (req.headers.referer?.substring(0, req.headers.referer.indexOf(':')) ?? 'http'), req.headers.host, 'ui5-patched-router' in req ? req['ui5-patched-router']?.baseUrl : undefined);
381
+ : (req.headers.referer?.substring(0, req.headers.referer.indexOf(':')) ?? 'http'), req.headers.host, this.templateConfig.baseUrl);
376
382
  this.checkDeleteConnectors(ui5Version.major, ui5Version.minor, ui5Version.isCdn);
383
+ //for consistency reasons, we also add the baseUrl to the HTML here, although it is only used in editor mode
377
384
  const html = (0, ejs_1.render)(this.getSandboxTemplate(ui5Version), this.templateConfig);
378
385
  this.sendResponse(res, 'text/html', 200, html);
379
386
  }
@@ -492,7 +499,6 @@ class FlpSandbox {
492
499
  for (const app of this.flpConfig.apps) {
493
500
  let manifest;
494
501
  if (app.local) {
495
- this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
496
502
  const webappPath = await (0, project_access_1.getWebappPath)(app.local, this.fs);
497
503
  manifest = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(webappPath, 'manifest.json'), 'utf-8'));
498
504
  this.router.use(app.target, (0, express_1.static)(webappPath));
@@ -534,7 +540,6 @@ class FlpSandbox {
534
540
  async flexGetHandler(res) {
535
541
  const changes = await (0, flex_1.readChanges)(this.project, this.logger);
536
542
  if (this.onChangeRequest) {
537
- this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
538
543
  for (const change of Object.values(changes)) {
539
544
  await this.onChangeRequest('read', change, this.fs, this.logger);
540
545
  }
@@ -549,7 +554,6 @@ class FlpSandbox {
549
554
  * @private
550
555
  */
551
556
  async flexPostHandler(req, res) {
552
- this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
553
557
  try {
554
558
  const body = req.body;
555
559
  if (this.onChangeRequest) {
@@ -788,7 +792,6 @@ class FlpSandbox {
788
792
  async storeCardManifestHandler(req, res) {
789
793
  try {
790
794
  const { floorplan, localPath, fileName = project_access_1.FileName.Manifest, manifests } = req.body;
791
- this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
792
795
  const webappPath = await (0, project_access_1.getWebappPath)(node_path_1.default.resolve(), this.fs);
793
796
  const fullPath = (0, node_path_1.join)(webappPath, localPath);
794
797
  const filePath = fileName.endsWith('.json') ? (0, node_path_1.join)(fullPath, fileName) : `${(0, node_path_1.join)(fullPath, fileName)}.json`;
@@ -838,7 +841,6 @@ class FlpSandbox {
838
841
  */
839
842
  async storeI18nKeysHandler(req, res) {
840
843
  try {
841
- this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
842
844
  const webappPath = await (0, project_access_1.getWebappPath)(node_path_1.default.resolve(), this.fs);
843
845
  const i18nConfig = this.manifest['sap.app'].i18n;
844
846
  let i18nPath = 'i18n/i18n.properties';
@@ -853,7 +855,7 @@ class FlpSandbox {
853
855
  supportedLocales = locales;
854
856
  fallbackLocale = fallback;
855
857
  }
856
- const requestedLocale = req.query.locale || fallbackLocale || '';
858
+ const requestedLocale = req.query.locale ?? fallbackLocale ?? '';
857
859
  const baseFilePath = (0, node_path_1.join)(webappPath, i18nPath);
858
860
  const filePath = requestedLocale
859
861
  ? baseFilePath.replace('.properties', `_${requestedLocale}.properties`)
@@ -38,7 +38,8 @@ sap.ui.define(["../utils/error"], function (___utils_error) {
38
38
  }
39
39
  };
40
40
  try {
41
- const response = await fetch(endpoint, config);
41
+ const baseUrl = document.getElementById('root')?.dataset.openUxPreviewBaseUrl ?? '';
42
+ const response = await fetch(`${baseUrl}${endpoint}`, config);
42
43
  if (!response.ok) {
43
44
  const errorData = await response.json();
44
45
  const message = errorData?.message ? ` Server message: ${errorData.message}.` : '';
@@ -83,7 +83,8 @@ export async function request<T>(endpoint: ApiEndpoints, method: RequestMethod,
83
83
  };
84
84
 
85
85
  try {
86
- const response: Response = await fetch(endpoint, config);
86
+ const baseUrl = document.getElementById('root')?.dataset.openUxPreviewBaseUrl ?? '';
87
+ const response: Response = await fetch(`${baseUrl}${endpoint}`, config);
87
88
 
88
89
  if (!response.ok) {
89
90
  const errorData = (await response.json()) as ResponseMessage;
@@ -38,14 +38,6 @@ sap.ui.define(["./BaseDialog.controller", "sap/ui/model/json/JSONModel", "../../
38
38
  };
39
39
  }
40
40
 
41
- // Check for spaces
42
- if (actionId.includes(' ')) {
43
- return {
44
- isValid: false,
45
- errorMessage: resource.getText('ACTION_ID_CANNOT_CONTAIN_SPACES')
46
- };
47
- }
48
-
49
41
  // Check starts and only allowed characters
50
42
  if (!/(^([A-Za-z_][-A-Za-z0-9_.:]*)$)/.test(actionId)) {
51
43
  return {
@@ -186,7 +178,13 @@ sap.ui.define(["./BaseDialog.controller", "sap/ui/model/json/JSONModel", "../../
186
178
  press: this.options.controllerReference,
187
179
  visible: true,
188
180
  enabled: true,
189
- text: actionLabel
181
+ text: actionLabel,
182
+ ...(this.options.actionType === 'tableAction' ? {
183
+ requiresSelection: false
184
+ } : {}),
185
+ ...(this.options.position && {
186
+ position: this.options.position
187
+ })
190
188
  }
191
189
  }
192
190
  }
@@ -29,10 +29,15 @@ type AddActionFragmentsModel = JSONModel & {
29
29
  export interface AddActionOptions {
30
30
  name: string;
31
31
  propertyPath: string;
32
+ actionType: 'pageAction' | 'tableAction';
32
33
  title: string;
33
34
  controllerReference: string;
34
35
  appDescriptor?: PageDescriptorV4;
35
36
  validateActionId?: (actionId: string) => boolean;
37
+ position?: {
38
+ placement: 'Before' | 'After';
39
+ anchor: string;
40
+ };
36
41
  }
37
42
 
38
43
  /**
@@ -58,11 +63,6 @@ function validateActionId(
58
63
  return { isValid: false, errorMessage: resource.getText('ACTION_WITH_GIVEN_ID_ALREADY_EXISTS', [actionId]) };
59
64
  }
60
65
 
61
- // Check for spaces
62
- if (actionId.includes(' ')) {
63
- return { isValid: false, errorMessage: resource.getText('ACTION_ID_CANNOT_CONTAIN_SPACES') };
64
- }
65
-
66
66
  // Check starts and only allowed characters
67
67
  if (!/(^([A-Za-z_][-A-Za-z0-9_.:]*)$)/.test(actionId)) {
68
68
  return { isValid: false, errorMessage: resource.getText('ACTION_ID_INVALID_FORMAT') };
@@ -213,7 +213,9 @@ export default class AddActionFragment extends BaseDialog<AddActionFragmentsMode
213
213
  press: this.options.controllerReference,
214
214
  visible: true,
215
215
  enabled: true,
216
- text: actionLabel
216
+ text: actionLabel,
217
+ ...(this.options.actionType === 'tableAction' ? { requiresSelection: false } : {}),
218
+ ...(this.options.position && { position: this.options.position })
217
219
  }
218
220
  }
219
221
  }
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+
3
+ sap.ui.define(["sap/ui/dt/OverlayRegistry", "../../dialog-factory", "../../../utils/version", "../dialog-enablement-validator", "../../api-handler", "../../utils", "../../../utils/fe-v4", "../table-quick-action-base", "../control-types", "../../../utils/core", "./utils"], function (OverlayRegistry, ____dialog_factory, _____utils_version, ___dialog_enablement_validator, ____api_handler, ____utils, _____utils_fe_v4, ___table_quick_action_base, ___control_types, _____utils_core, ___utils) {
4
+ "use strict";
5
+
6
+ const DialogFactory = ____dialog_factory["DialogFactory"];
7
+ const DialogNames = ____dialog_factory["DialogNames"];
8
+ const getUi5Version = _____utils_version["getUi5Version"];
9
+ const isLowerThanMinimalUi5Version = _____utils_version["isLowerThanMinimalUi5Version"];
10
+ const DIALOG_ENABLEMENT_VALIDATOR = ___dialog_enablement_validator["DIALOG_ENABLEMENT_VALIDATOR"];
11
+ const getExistingController = ____api_handler["getExistingController"];
12
+ const getControllerInfoForControl = ____utils["getControllerInfoForControl"];
13
+ const getV4AppComponent = _____utils_fe_v4["getV4AppComponent"];
14
+ const TableQuickActionDefinitionBase = ___table_quick_action_base["TableQuickActionDefinitionBase"];
15
+ const MDC_TABLE_TYPE = ___control_types["MDC_TABLE_TYPE"];
16
+ const isA = _____utils_core["isA"];
17
+ const getActionsPropertyPath = ___utils["getActionsPropertyPath"];
18
+ const CREATE_TABLE_ACTION = 'create-table-action';
19
+ const regexForAnnotationPath = /controlConfiguration\/(?:[^@]+\/)?@com\.sap\.vocabularies\.UI\.v1\.LineItem(?:#[^/]+)?\/actions\//;
20
+
21
+ /**
22
+ * Quick Action for adding a custom page action.
23
+ */
24
+ class AddTableActionQuickAction extends TableQuickActionDefinitionBase {
25
+ constructor(context) {
26
+ super(CREATE_TABLE_ACTION, [MDC_TABLE_TYPE], 'QUICK_ACTION_ADD_CUSTOM_TABLE_ACTION', context, undefined, [DIALOG_ENABLEMENT_VALIDATOR]);
27
+ }
28
+ async initialize() {
29
+ this.pageId = this.context.view.getViewData()?.stableId.split('::').pop();
30
+ const version = await getUi5Version();
31
+ if (isLowerThanMinimalUi5Version(version, {
32
+ major: 1,
33
+ minor: 120
34
+ })) {
35
+ return;
36
+ }
37
+ await super.initialize();
38
+ }
39
+ async execute(path) {
40
+ const {
41
+ table
42
+ } = this.tableMap[path];
43
+ const propertyPath = `${getActionsPropertyPath(table)}`;
44
+ if (!table || !propertyPath) {
45
+ return [];
46
+ }
47
+ if (table) {
48
+ const overlay = OverlayRegistry.getOverlay(table) || [];
49
+ const controlInfo = getControllerInfoForControl(table);
50
+ const data = await getExistingController(controlInfo.controllerName);
51
+ const controllerPath = data.controllerPathFromRoot.replaceAll('/', '.').replace(/\.[^.]+$/, '');
52
+ await DialogFactory.createDialog(overlay, this.context.rta, DialogNames.ADD_ACTION, undefined, {
53
+ title: 'QUICK_ACTION_ADD_CUSTOM_TABLE_ACTION',
54
+ controllerReference: controllerPath ? `.extension.${controllerPath}.<methodName>` : '.extension.<ApplicationId.FolderName.ScriptFilename.methodName>',
55
+ actionType: 'tableAction',
56
+ appDescriptor: {
57
+ appComponent: getV4AppComponent(this.context.view),
58
+ appType: 'fe-v4',
59
+ pageId: this.pageId,
60
+ projectId: this.context.flexSettings.projectId
61
+ },
62
+ validateActionId: actionId => {
63
+ const actionPaths = [...this.context.changeService.getAllPendingConfigPropertyPath()].filter(path => regexForAnnotationPath.test(path));
64
+ const idInPendingChanges = actionPaths.includes(`${propertyPath}${actionId}`);
65
+ if (idInPendingChanges) {
66
+ return false;
67
+ }
68
+ if (isA(MDC_TABLE_TYPE, table) && table.getActions().every(action => !action.getAction().getId().endsWith(`CustomAction::${actionId}`))) {
69
+ return true;
70
+ }
71
+ return false;
72
+ },
73
+ position: calculatePosition(table, this.context.view),
74
+ propertyPath
75
+ }, {
76
+ actionName: this.type,
77
+ telemetryEventIdentifier: this.getTelemetryIdentifier()
78
+ });
79
+ }
80
+ return [];
81
+ }
82
+ }
83
+ function calculatePosition(table, view) {
84
+ const actions = table.getActions();
85
+ if (!actions.length) {
86
+ return undefined;
87
+ }
88
+ const annotationAction = actions.findIndex(action => action.getAction().getId().includes('::DataFieldForAction::'));
89
+ const customAction = actions.findIndex(action => action.getAction().getId().includes('::CustomAction::'));
90
+ if (annotationAction === -1 && customAction === -1) {
91
+ return undefined;
92
+ }
93
+ // determine the least index of either annotation or custom action
94
+ let actionIndex;
95
+ if (annotationAction === -1) {
96
+ actionIndex = customAction;
97
+ } else if (customAction === -1) {
98
+ actionIndex = annotationAction;
99
+ } else {
100
+ actionIndex = Math.min(annotationAction, customAction);
101
+ }
102
+ const actionToolBarAction = actions[actionIndex];
103
+ let anchor;
104
+ let action = actionToolBarAction?.getAction();
105
+ if (action) {
106
+ const localId = view.getLocalId(action.getId()) ?? '';
107
+ if (localId.includes('CustomAction::')) {
108
+ const str = localId.substring(Math.max(0, localId.lastIndexOf('CustomAction::')));
109
+ anchor = str.split('::').pop();
110
+ } else {
111
+ anchor = localId.substring(localId.lastIndexOf('DataFieldForAction::'));
112
+ }
113
+ }
114
+ if (!anchor) {
115
+ return undefined;
116
+ }
117
+ return {
118
+ placement: 'Before',
119
+ anchor
120
+ };
121
+ }
122
+ var __exports = {
123
+ __esModule: true
124
+ };
125
+ __exports.CREATE_TABLE_ACTION = CREATE_TABLE_ACTION;
126
+ __exports.AddTableActionQuickAction = AddTableActionQuickAction;
127
+ return __exports;
128
+ });
129
+ //# sourceMappingURL=create-table-action-config-change.js.map
@@ -0,0 +1,151 @@
1
+ import OverlayRegistry from 'sap/ui/dt/OverlayRegistry';
2
+ import FlexCommand from 'sap/ui/rta/command/FlexCommand';
3
+
4
+ import { DialogFactory, DialogNames } from '../../dialog-factory';
5
+ import { NestedQuickActionDefinition, QuickActionContext } from '../../../cpe/quick-actions/quick-action-definition';
6
+ import { getUi5Version, isLowerThanMinimalUi5Version } from '../../../utils/version';
7
+ import { DIALOG_ENABLEMENT_VALIDATOR } from '../dialog-enablement-validator';
8
+ import { getExistingController } from '../../api-handler';
9
+ import { getControllerInfoForControl } from '../../utils';
10
+ import { getV4AppComponent } from '../../../utils/fe-v4';
11
+ import { TableQuickActionDefinitionBase } from '../table-quick-action-base';
12
+ import { MDC_TABLE_TYPE } from '../control-types';
13
+ import { isA } from '../../../utils/core';
14
+ import Table from 'sap/ui/mdc/Table';
15
+ import XMLView from 'sap/ui/core/mvc/XMLView';
16
+ import ActionToolbarAction from 'sap/ui/mdc/actiontoolbar/ActionToolbarAction';
17
+ import { getActionsPropertyPath } from './utils';
18
+
19
+ export const CREATE_TABLE_ACTION = 'create-table-action';
20
+
21
+ interface ViewDataType {
22
+ stableId: string;
23
+ }
24
+ const regexForAnnotationPath =
25
+ /controlConfiguration\/(?:[^@]+\/)?@com\.sap\.vocabularies\.UI\.v1\.LineItem(?:#[^/]+)?\/actions\//;
26
+
27
+ /**
28
+ * Quick Action for adding a custom page action.
29
+ */
30
+ export class AddTableActionQuickAction extends TableQuickActionDefinitionBase implements NestedQuickActionDefinition {
31
+ protected pageId: string | undefined;
32
+ constructor(context: QuickActionContext) {
33
+ super(CREATE_TABLE_ACTION, [MDC_TABLE_TYPE], 'QUICK_ACTION_ADD_CUSTOM_TABLE_ACTION', context, undefined, [
34
+ DIALOG_ENABLEMENT_VALIDATOR
35
+ ]);
36
+ }
37
+
38
+ async initialize(): Promise<void> {
39
+ this.pageId = (this.context.view.getViewData() as ViewDataType)?.stableId.split('::').pop() as string;
40
+ const version = await getUi5Version();
41
+ if (isLowerThanMinimalUi5Version(version, { major: 1, minor: 120 })) {
42
+ return;
43
+ }
44
+ await super.initialize();
45
+ }
46
+
47
+ async execute(path: string): Promise<FlexCommand[]> {
48
+ const { table } = this.tableMap[path];
49
+ const propertyPath = `${getActionsPropertyPath(table)}`;
50
+ if (!table || !propertyPath) {
51
+ return [];
52
+ }
53
+ if (table) {
54
+ const overlay = OverlayRegistry.getOverlay(table) || [];
55
+ const controlInfo = getControllerInfoForControl(table);
56
+ const data = await getExistingController(controlInfo.controllerName);
57
+ const controllerPath = data.controllerPathFromRoot.replaceAll('/', '.').replace(/\.[^.]+$/, '');
58
+ await DialogFactory.createDialog(
59
+ overlay,
60
+ this.context.rta,
61
+ DialogNames.ADD_ACTION,
62
+ undefined,
63
+ {
64
+ title: 'QUICK_ACTION_ADD_CUSTOM_TABLE_ACTION',
65
+ controllerReference: controllerPath
66
+ ? `.extension.${controllerPath}.<methodName>`
67
+ : '.extension.<ApplicationId.FolderName.ScriptFilename.methodName>',
68
+ actionType: 'tableAction',
69
+ appDescriptor: {
70
+ appComponent: getV4AppComponent(this.context.view)!,
71
+ appType: 'fe-v4',
72
+ pageId: this.pageId!,
73
+ projectId: this.context.flexSettings.projectId
74
+ },
75
+ validateActionId: (actionId) => {
76
+ const actionPaths = [...this.context.changeService.getAllPendingConfigPropertyPath()].filter(
77
+ (path) => regexForAnnotationPath.test(path)
78
+ );
79
+ const idInPendingChanges = actionPaths.includes(`${propertyPath}${actionId}`);
80
+ if (idInPendingChanges) {
81
+ return false;
82
+ }
83
+ if (
84
+ isA(MDC_TABLE_TYPE, table) &&
85
+ (table as Table)
86
+ .getActions()
87
+ .every(
88
+ (action) =>
89
+ !(action as ActionToolbarAction)
90
+ .getAction()
91
+ .getId()
92
+ .endsWith(`CustomAction::${actionId}`)
93
+ )
94
+ ) {
95
+ return true;
96
+ }
97
+ return false;
98
+ },
99
+ position: calculatePosition(table as Table, this.context.view),
100
+ propertyPath
101
+ },
102
+ { actionName: this.type, telemetryEventIdentifier: this.getTelemetryIdentifier() }
103
+ );
104
+ }
105
+ return [];
106
+ }
107
+ }
108
+
109
+ function calculatePosition(table: Table, view: XMLView): { placement: 'Before' | 'After'; anchor: string } | undefined {
110
+ const actions = table.getActions() as ActionToolbarAction[];
111
+ if (!actions.length) {
112
+ return undefined;
113
+ }
114
+ const annotationAction = actions.findIndex((action) =>
115
+ action.getAction().getId().includes('::DataFieldForAction::')
116
+ );
117
+ const customAction = actions.findIndex((action) => action.getAction().getId().includes('::CustomAction::'));
118
+ if (annotationAction === -1 && customAction === -1) {
119
+ return undefined;
120
+ }
121
+ // determine the least index of either annotation or custom action
122
+ let actionIndex: number;
123
+ if (annotationAction === -1) {
124
+ actionIndex = customAction;
125
+ } else if (customAction === -1) {
126
+ actionIndex = annotationAction;
127
+ } else {
128
+ actionIndex = Math.min(annotationAction, customAction);
129
+ }
130
+ const actionToolBarAction = actions[actionIndex];
131
+ let anchor;
132
+ let action = actionToolBarAction?.getAction();
133
+
134
+ if (action) {
135
+ const localId = view.getLocalId(action.getId()) ?? '';
136
+ if (localId.includes('CustomAction::')) {
137
+ const str = localId.substring(Math.max(0, localId.lastIndexOf('CustomAction::')));
138
+ anchor = str.split('::').pop();
139
+ } else {
140
+ anchor = localId.substring(localId.lastIndexOf('DataFieldForAction::'));
141
+ }
142
+ }
143
+ if (!anchor) {
144
+ return undefined;
145
+ }
146
+
147
+ return {
148
+ placement: 'Before',
149
+ anchor
150
+ };
151
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- sap.ui.define(["../../../cpe/quick-actions/registry", "../common/add-controller-to-page", "./lr-toggle-clear-filter-bar", "./change-table-columns", "../common/op-add-header-field", "./op-add-custom-section", "./create-table-custom-column", "./create-page-action", "./create-table-action", "./lr-enable-table-filtering", "./lr-enable-semantic-date-range-filter-bar", "./op-enable-empty-row-mode", "../common/add-new-annotation-file", "./enable-variant-management", "../fe-v4/add-new-subpage", "../fe-v4/change-table-actions"], function (_____cpe_quick_actions_registry, ___common_add_controller_to_page, ___lr_toggle_clear_filter_bar, ___change_table_columns, ___common_op_add_header_field, ___op_add_custom_section, ___create_table_custom_column, ___create_page_action, ___create_table_action, ___lr_enable_table_filtering, ___lr_enable_semantic_date_range_filter_bar, ___op_enable_empty_row_mode, ___common_add_new_annotation_file, ___enable_variant_management, ___fe_v4_add_new_subpage, ___fe_v4_change_table_actions) {
3
+ sap.ui.define(["../../../cpe/quick-actions/registry", "../common/add-controller-to-page", "./lr-toggle-clear-filter-bar", "./change-table-columns", "../common/op-add-header-field", "./op-add-custom-section", "./create-table-custom-column", "./create-page-action", "./lr-enable-table-filtering", "./lr-enable-semantic-date-range-filter-bar", "./op-enable-empty-row-mode", "../common/add-new-annotation-file", "./enable-variant-management", "../fe-v4/add-new-subpage", "../fe-v4/change-table-actions", "./create-table-action-config-change"], function (_____cpe_quick_actions_registry, ___common_add_controller_to_page, ___lr_toggle_clear_filter_bar, ___change_table_columns, ___common_op_add_header_field, ___op_add_custom_section, ___create_table_custom_column, ___create_page_action, ___lr_enable_table_filtering, ___lr_enable_semantic_date_range_filter_bar, ___op_enable_empty_row_mode, ___common_add_new_annotation_file, ___enable_variant_management, ___fe_v4_add_new_subpage, ___fe_v4_change_table_actions, ___create_table_action_config_change) {
4
4
  "use strict";
5
5
 
6
6
  const QuickActionDefinitionRegistry = _____cpe_quick_actions_registry["QuickActionDefinitionRegistry"];
@@ -11,7 +11,6 @@ sap.ui.define(["../../../cpe/quick-actions/registry", "../common/add-controller-
11
11
  const AddCustomSectionQuickAction = ___op_add_custom_section["AddCustomSectionQuickAction"];
12
12
  const AddTableCustomColumnQuickAction = ___create_table_custom_column["AddTableCustomColumnQuickAction"];
13
13
  const AddPageActionQuickAction = ___create_page_action["AddPageActionQuickAction"];
14
- const AddTableActionQuickAction = ___create_table_action["AddTableActionQuickAction"];
15
14
  const EnableTableFilteringQuickAction = ___lr_enable_table_filtering["EnableTableFilteringQuickAction"];
16
15
  const ToggleSemanticDateRangeFilterBar = ___lr_enable_semantic_date_range_filter_bar["ToggleSemanticDateRangeFilterBar"];
17
16
  const EnableTableEmptyRowModeQuickAction = ___op_enable_empty_row_mode["EnableTableEmptyRowModeQuickAction"];
@@ -19,6 +18,7 @@ sap.ui.define(["../../../cpe/quick-actions/registry", "../common/add-controller-
19
18
  const EnableVariantManagementQuickAction = ___enable_variant_management["EnableVariantManagementQuickAction"];
20
19
  const AddNewSubpage = ___fe_v4_add_new_subpage["AddNewSubpage"];
21
20
  const ChangeTableActionsQuickAction = ___fe_v4_change_table_actions["ChangeTableActionsQuickAction"];
21
+ const AddTableActionQuickAction = ___create_table_action_config_change["AddTableActionQuickAction"];
22
22
  const LIST_REPORT_TYPE = 'sap.fe.templates.ListReport.ListReport';
23
23
  const OBJECT_PAGE_TYPE = 'sap.fe.templates.ObjectPage.ObjectPage';
24
24
 
@@ -11,7 +11,6 @@ import { AddHeaderFieldQuickAction } from '../common/op-add-header-field';
11
11
  import { AddCustomSectionQuickAction } from './op-add-custom-section';
12
12
  import { AddTableCustomColumnQuickAction } from './create-table-custom-column';
13
13
  import { AddPageActionQuickAction } from './create-page-action';
14
- import { AddTableActionQuickAction } from './create-table-action';
15
14
  import { EnableTableFilteringQuickAction } from './lr-enable-table-filtering';
16
15
  import { ToggleSemanticDateRangeFilterBar } from './lr-enable-semantic-date-range-filter-bar';
17
16
  import { EnableTableEmptyRowModeQuickAction } from './op-enable-empty-row-mode';
@@ -19,6 +18,7 @@ import { AddNewAnnotationFile } from '../common/add-new-annotation-file';
19
18
  import { EnableVariantManagementQuickAction } from './enable-variant-management';
20
19
  import { AddNewSubpage } from '../fe-v4/add-new-subpage';
21
20
  import { ChangeTableActionsQuickAction } from '../fe-v4/change-table-actions';
21
+ import { AddTableActionQuickAction } from './create-table-action-config-change';
22
22
 
23
23
  type PageName = 'listReport' | 'objectPage';
24
24
 
@@ -4,6 +4,7 @@ sap.ui.define(["../../../utils/core", "sap/ui/rta/command/CommandFactory", "../.
4
4
  "use strict";
5
5
 
6
6
  const getControlById = _____utils_core["getControlById"];
7
+ const isA = _____utils_core["isA"];
7
8
  const getV4AppComponent = _____utils_fe_v4["getV4AppComponent"];
8
9
  const getPageName = _____utils_fe_v4["getPageName"];
9
10
  const getReference = _____utils_fe_v4["getReference"];
@@ -64,11 +65,89 @@ sap.ui.define(["../../../utils/core", "sap/ui/rta/command/CommandFactory", "../.
64
65
  parts.push(PATTERN_SUFFIX);
65
66
  return parts.join('');
66
67
  }
68
+ /**
69
+ * Get LineItem annotation - tries to use design-time helper if available, falls back to local implementation.
70
+ *
71
+ * @param table - table control
72
+ * @returns LineItem annotation string
73
+ */
74
+ function getLineItemAnnotation(table) {
75
+ try {
76
+ const helper = sap.ui.require('sap/fe/macros/table/designtime/Table.designtime.helper');
77
+ if (helper && typeof helper.getLineItemAnnotation === 'function') {
78
+ return helper.getLineItemAnnotation(table);
79
+ }
80
+ } catch {
81
+ // Module not available or error occurred
82
+ }
83
+ return getLineItemAnnotationForTable(table);
84
+ }
85
+
86
+ /**
87
+ * Get property path for table action.
88
+ *
89
+ * @param table - table control
90
+ * @returns string
91
+ */
92
+ function getActionsPropertyPath(table) {
93
+ const macroTable = table.getParent();
94
+ const configPath = '';
95
+ if (macroTable && isA('sap.fe.macros.table.TableAPI', macroTable)) {
96
+ const lineItemAnnotation = getLineItemAnnotation(macroTable);
97
+ const navigationPath = macroTable.metaPath.split(macroTable.getProperty('contextPath'))[1];
98
+ if (!lineItemAnnotation) {
99
+ throw new Error('Line item annotation could not be determined for the table.');
100
+ }
101
+ if (navigationPath) {
102
+ return configPath.concat('controlConfiguration/', navigationPath.split('@')[0], lineItemAnnotation, '/actions/');
103
+ } else {
104
+ let contextString = macroTable.metaPath;
105
+ const firstSlash = contextString.indexOf('/');
106
+ if (firstSlash >= 0) {
107
+ contextString = contextString.substring(firstSlash + 1);
108
+ }
109
+ const secondSlash = contextString.indexOf('/');
110
+ if (secondSlash >= 0) {
111
+ contextString = contextString.substring(0, secondSlash);
112
+ }
113
+ return configPath.concat('controlConfiguration/', '/', contextString, '/', lineItemAnnotation, '/actions/');
114
+ }
115
+ }
116
+ return undefined;
117
+ }
118
+
119
+ /**
120
+ * Return the line item annotation that defines the table.
121
+ * This may come from a Presentation Variant, a Selection Presentation Variant or the default.
122
+ * @param table - The table control
123
+ * @returns The line item annotation used to define the table
124
+ */
125
+ function getLineItemAnnotationForTable(table) {
126
+ const presentation = table.getModel()?.getMetaModel()?.getObject(table.metaPath);
127
+ let lineItemAnnotation = '';
128
+ // default line item annotation
129
+ if (!presentation.Visualizations && !presentation.PresentationVariant) {
130
+ lineItemAnnotation = table.metaPath.split('/').pop();
131
+ } else if (presentation.Visualizations) {
132
+ lineItemAnnotation = presentation.Visualizations[0].$AnnotationPath;
133
+ } else if (presentation.PresentationVariant) {
134
+ if (presentation.PresentationVariant.Visualizations) {
135
+ lineItemAnnotation = presentation.PresentationVariant.Visualizations[0].$AnnotationPath;
136
+ } else {
137
+ const contextPath = table.metaPath.startsWith('/') ? table.metaPath.split('@')[0] : table.contextPath;
138
+ const pathForLineItems = contextPath + presentation.PresentationVariant.$Path;
139
+ const presentationVariantType = table.getModel()?.getMetaModel()?.getObject(pathForLineItems);
140
+ lineItemAnnotation = presentationVariantType.Visualizations[0].$AnnotationPath;
141
+ }
142
+ }
143
+ return lineItemAnnotation;
144
+ }
67
145
  var __exports = {
68
146
  __esModule: true
69
147
  };
70
148
  __exports.executeToggleAction = executeToggleAction;
71
149
  __exports.generateRoutePattern = generateRoutePattern;
150
+ __exports.getActionsPropertyPath = getActionsPropertyPath;
72
151
  return __exports;
73
152
  });
74
153
  //# sourceMappingURL=utils.js.map
@@ -1,8 +1,10 @@
1
- import { getControlById } from '../../../utils/core';
1
+ import { getControlById, isA } from '../../../utils/core';
2
2
  import type FlexCommand from 'sap/ui/rta/command/FlexCommand';
3
3
  import type { QuickActionContext } from '../../../cpe/quick-actions/quick-action-definition';
4
4
  import CommandFactory from 'sap/ui/rta/command/CommandFactory';
5
5
  import { getV4AppComponent, getPageName, getReference } from '../../../utils/fe-v4';
6
+ import TableAPI from 'sap/fe/macros/table/TableAPI';
7
+ import UI5Element from 'sap/ui/core/Element';
6
8
 
7
9
  export async function executeToggleAction(
8
10
  context: QuickActionContext,
@@ -62,11 +64,7 @@ const PATTERN_SUFFIX = ':?query:';
62
64
  * @param targetEntitySet navigation target entity set
63
65
  * @returns the generated pattern as string
64
66
  */
65
- export function generateRoutePattern(
66
- sourceRoutePattern: string,
67
- navProperty: string,
68
- targetEntitySet: string
69
- ): string {
67
+ export function generateRoutePattern(sourceRoutePattern: string, navProperty: string, targetEntitySet: string): string {
70
68
  const parts: string[] = [];
71
69
  const basePattern = sourceRoutePattern.replace(PATTERN_SUFFIX, '');
72
70
  if (basePattern) {
@@ -80,3 +78,93 @@ export function generateRoutePattern(
80
78
  parts.push(PATTERN_SUFFIX);
81
79
  return parts.join('');
82
80
  }
81
+
82
+ export type MacroTable = TableAPI & {
83
+ metaPath: string;
84
+ contextPath: string;
85
+ };
86
+
87
+ /**
88
+ * Get LineItem annotation - tries to use design-time helper if available, falls back to local implementation.
89
+ *
90
+ * @param table - table control
91
+ * @returns LineItem annotation string
92
+ */
93
+ function getLineItemAnnotation(table: MacroTable): string | undefined {
94
+ try {
95
+ const helper = sap.ui.require('sap/fe/macros/table/designtime/Table.designtime.helper');
96
+ if (helper && typeof helper.getLineItemAnnotation === 'function') {
97
+ return helper.getLineItemAnnotation(table);
98
+ }
99
+ } catch {
100
+ // Module not available or error occurred
101
+ }
102
+ return getLineItemAnnotationForTable(table);
103
+ }
104
+
105
+ /**
106
+ * Get property path for table action.
107
+ *
108
+ * @param table - table control
109
+ * @returns string
110
+ */
111
+ export function getActionsPropertyPath(table: UI5Element): string | undefined {
112
+ const macroTable = table.getParent();
113
+ const configPath = '';
114
+ if (macroTable && isA<MacroTable>('sap.fe.macros.table.TableAPI', macroTable)) {
115
+ const lineItemAnnotation = getLineItemAnnotation(macroTable);
116
+
117
+ const navigationPath = macroTable.metaPath.split(macroTable.getProperty('contextPath'))[1];
118
+ if (!lineItemAnnotation) {
119
+ throw new Error('Line item annotation could not be determined for the table.');
120
+ }
121
+ if (navigationPath) {
122
+ return configPath.concat(
123
+ 'controlConfiguration/',
124
+ navigationPath.split('@')[0],
125
+ lineItemAnnotation,
126
+ '/actions/'
127
+ );
128
+ } else {
129
+ let contextString = macroTable.metaPath;
130
+ const firstSlash = contextString.indexOf('/');
131
+ if (firstSlash >= 0) {
132
+ contextString = contextString.substring(firstSlash + 1);
133
+ }
134
+ const secondSlash = contextString.indexOf('/');
135
+ if (secondSlash >= 0) {
136
+ contextString = contextString.substring(0, secondSlash);
137
+ }
138
+ return configPath.concat('controlConfiguration/', '/', contextString, '/', lineItemAnnotation, '/actions/');
139
+ }
140
+ }
141
+ return undefined;
142
+ }
143
+
144
+ /**
145
+ * Return the line item annotation that defines the table.
146
+ * This may come from a Presentation Variant, a Selection Presentation Variant or the default.
147
+ * @param table - The table control
148
+ * @returns The line item annotation used to define the table
149
+ */
150
+ function getLineItemAnnotationForTable(table: MacroTable): string | undefined {
151
+ const presentation = table.getModel()?.getMetaModel()?.getObject(table.metaPath);
152
+
153
+ let lineItemAnnotation: string | undefined = '';
154
+ // default line item annotation
155
+ if (!presentation.Visualizations && !presentation.PresentationVariant) {
156
+ lineItemAnnotation = table.metaPath.split('/').pop();
157
+ } else if (presentation.Visualizations) {
158
+ lineItemAnnotation = presentation.Visualizations[0].$AnnotationPath;
159
+ } else if (presentation.PresentationVariant) {
160
+ if (presentation.PresentationVariant.Visualizations) {
161
+ lineItemAnnotation = presentation.PresentationVariant.Visualizations[0].$AnnotationPath;
162
+ } else {
163
+ const contextPath = table.metaPath.startsWith('/') ? table.metaPath.split('@')[0] : table.contextPath;
164
+ const pathForLineItems = contextPath + presentation.PresentationVariant.$Path;
165
+ const presentationVariantType = table.getModel()?.getMetaModel()?.getObject(pathForLineItems);
166
+ lineItemAnnotation = presentationVariantType.Visualizations[0].$AnnotationPath;
167
+ }
168
+ }
169
+ return lineItemAnnotation;
170
+ }
@@ -3,11 +3,13 @@
3
3
  sap.ui.define(["sap/base/util/merge", "sap/ui/fl/write/api/connectors/ObjectStorageConnector", "sap/ui/fl/Layer", "./common", "../utils/version", "../utils/additional-change-info"], function (merge, ObjectStorageConnector, Layer, ___common, ___utils_version, ___utils_additional_change_info) {
4
4
  "use strict";
5
5
 
6
- const CHANGES_API_PATH = ___common["CHANGES_API_PATH"];
6
+ const CHANGES_API_PATH_STATIC = ___common["CHANGES_API_PATH"];
7
7
  const getFlexSettings = ___common["getFlexSettings"];
8
8
  const getUi5Version = ___utils_version["getUi5Version"];
9
9
  const isLowerThanMinimalUi5Version = ___utils_version["isLowerThanMinimalUi5Version"];
10
10
  const getAdditionalChangeInfo = ___utils_additional_change_info["getAdditionalChangeInfo"];
11
+ const baseUrl = document.getElementById('sap-ui-bootstrap')?.dataset.openUxPreviewBaseUrl ?? '';
12
+ const changesApiPath = `${baseUrl}${CHANGES_API_PATH_STATIC}`;
11
13
  const connector = merge({}, ObjectStorageConnector, {
12
14
  layers: [Layer.VENDOR, Layer.CUSTOMER_BASE],
13
15
  storage: {
@@ -31,7 +33,7 @@ sap.ui.define(["sap/base/util/merge", "sap/ui/fl/write/api/connectors/ObjectStor
31
33
  change,
32
34
  additionalChangeInfo
33
35
  };
34
- return fetch(CHANGES_API_PATH, {
36
+ return fetch(changesApiPath, {
35
37
  method: 'POST',
36
38
  body: JSON.stringify(body, null, 2),
37
39
  headers: {
@@ -47,7 +49,7 @@ sap.ui.define(["sap/base/util/merge", "sap/ui/fl/write/api/connectors/ObjectStor
47
49
  // exceptions in the listener call are ignored
48
50
  }
49
51
  }
50
- return fetch(CHANGES_API_PATH, {
52
+ return fetch(changesApiPath, {
51
53
  method: 'DELETE',
52
54
  body: JSON.stringify({
53
55
  fileName: key
@@ -64,7 +66,7 @@ sap.ui.define(["sap/base/util/merge", "sap/ui/fl/write/api/connectors/ObjectStor
64
66
  // not implemented
65
67
  },
66
68
  getItems: async function () {
67
- const response = await fetch(CHANGES_API_PATH, {
69
+ const response = await fetch(changesApiPath, {
68
70
  method: 'GET',
69
71
  headers: {
70
72
  'content-type': 'application/json'
@@ -2,10 +2,13 @@ import merge from 'sap/base/util/merge';
2
2
  import ObjectStorageConnector from 'sap/ui/fl/write/api/connectors/ObjectStorageConnector';
3
3
  import Layer from 'sap/ui/fl/Layer';
4
4
  import type { FlexChange } from './common';
5
- import { CHANGES_API_PATH, getFlexSettings } from './common';
5
+ import { CHANGES_API_PATH as CHANGES_API_PATH_STATIC, getFlexSettings } from './common';
6
6
  import { getUi5Version, isLowerThanMinimalUi5Version } from '../utils/version';
7
7
  import { getAdditionalChangeInfo } from '../utils/additional-change-info';
8
8
 
9
+ const baseUrl = document.getElementById('sap-ui-bootstrap')?.dataset.openUxPreviewBaseUrl ??'';
10
+ const changesApiPath = `${baseUrl}${CHANGES_API_PATH_STATIC}`;
11
+
9
12
  const connector = merge({}, ObjectStorageConnector, {
10
13
  layers: [Layer.VENDOR, Layer.CUSTOMER_BASE],
11
14
  storage: {
@@ -33,7 +36,7 @@ const connector = merge({}, ObjectStorageConnector, {
33
36
  additionalChangeInfo
34
37
  };
35
38
 
36
- return fetch(CHANGES_API_PATH, {
39
+ return fetch(changesApiPath, {
37
40
  method: 'POST',
38
41
  body: JSON.stringify(body, null, 2),
39
42
  headers: {
@@ -50,7 +53,7 @@ const connector = merge({}, ObjectStorageConnector, {
50
53
  }
51
54
  }
52
55
 
53
- return fetch(CHANGES_API_PATH, {
56
+ return fetch(changesApiPath, {
54
57
  method: 'DELETE',
55
58
  body: JSON.stringify({ fileName: key }),
56
59
  headers: {
@@ -65,7 +68,7 @@ const connector = merge({}, ObjectStorageConnector, {
65
68
  // not implemented
66
69
  },
67
70
  getItems: async function () {
68
- const response = await fetch(CHANGES_API_PATH, {
71
+ const response = await fetch(changesApiPath, {
69
72
  method: 'GET',
70
73
  headers: {
71
74
  'content-type': 'application/json'
@@ -4,8 +4,11 @@ sap.ui.define(["sap/ui/fl/LrepConnector", "sap/ui/fl/FakeLrepConnector", "../uti
4
4
  "use strict";
5
5
 
6
6
  const getAdditionalChangeInfo = ___utils_additional_change_info["getAdditionalChangeInfo"];
7
- const CHANGES_API_PATH = ___common["CHANGES_API_PATH"];
7
+ const CHANGES_API_PATH_STATIC = ___common["CHANGES_API_PATH"];
8
8
  const getFlexSettings = ___common["getFlexSettings"];
9
+ const baseUrl = document.getElementById('sap-ui-bootstrap')?.dataset.openUxPreviewBaseUrl ?? '';
10
+ const changesApiPath = `${baseUrl}${CHANGES_API_PATH_STATIC}`;
11
+
9
12
  /**
10
13
  * Processes an array of FlexChange objects.
11
14
  * It updates each change object with settings and sends them to a API endpoint.
@@ -32,7 +35,7 @@ sap.ui.define(["sap/ui/fl/LrepConnector", "sap/ui/fl/FakeLrepConnector", "../uti
32
35
  change,
33
36
  additionalChangeInfo
34
37
  };
35
- return fetch(CHANGES_API_PATH, {
38
+ return fetch(changesApiPath, {
36
39
  method: 'POST',
37
40
  body: JSON.stringify(body, null, 2),
38
41
  headers: {
@@ -50,7 +53,7 @@ sap.ui.define(["sap/ui/fl/LrepConnector", "sap/ui/fl/FakeLrepConnector", "../uti
50
53
  */
51
54
  async function loadChanges(...args) {
52
55
  const lrep = new LrepConnector();
53
- const response = await fetch(CHANGES_API_PATH, {
56
+ const response = await fetch(changesApiPath, {
54
57
  method: 'GET',
55
58
  headers: {
56
59
  'content-type': 'application/json'
@@ -3,7 +3,7 @@ import FakeLrepConnector from 'sap/ui/fl/FakeLrepConnector';
3
3
  import { getAdditionalChangeInfo } from '../utils/additional-change-info';
4
4
 
5
5
  import type { FlexChange } from './common';
6
- import { CHANGES_API_PATH, getFlexSettings } from './common';
6
+ import { CHANGES_API_PATH as CHANGES_API_PATH_STATIC, getFlexSettings } from './common';
7
7
 
8
8
  interface FetchedChanges {
9
9
  [key: string]: FlexChange;
@@ -23,6 +23,9 @@ interface LoadChangesResult {
23
23
  messagebundle: string | undefined;
24
24
  }
25
25
 
26
+ const baseUrl = document.getElementById('sap-ui-bootstrap')?.dataset.openUxPreviewBaseUrl ?? '';
27
+ const changesApiPath = `${baseUrl}${CHANGES_API_PATH_STATIC}`;
28
+
26
29
  /**
27
30
  * Processes an array of FlexChange objects.
28
31
  * It updates each change object with settings and sends them to a API endpoint.
@@ -55,7 +58,7 @@ export async function create(changes: FlexChange | FlexChange[]): Promise<void>
55
58
  };
56
59
 
57
60
 
58
- return fetch(CHANGES_API_PATH, {
61
+ return fetch(changesApiPath, {
59
62
  method: 'POST',
60
63
  body: JSON.stringify(body, null, 2),
61
64
  headers: {
@@ -75,7 +78,7 @@ export async function create(changes: FlexChange | FlexChange[]): Promise<void>
75
78
  export async function loadChanges(...args: []): Promise<LoadChangesResult> {
76
79
  const lrep = new LrepConnector();
77
80
 
78
- const response = await fetch(CHANGES_API_PATH, {
81
+ const response = await fetch(changesApiPath, {
79
82
  method: 'GET',
80
83
  headers: {
81
84
  'content-type': 'application/json'
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.23.99",
12
+ "version": "0.23.101",
13
13
  "license": "Apache-2.0",
14
14
  "author": "@SAP/ux-tools-team",
15
15
  "main": "dist/index.js",
@@ -30,11 +30,11 @@
30
30
  "@sap-ux/adp-tooling": "0.18.45",
31
31
  "@sap-ux/btp-utils": "1.1.6",
32
32
  "@sap-ux/control-property-editor-sources": "npm:@sap-ux/control-property-editor@0.7.9",
33
- "@sap-ux/feature-toggle": "0.3.5",
34
33
  "@sap-ux/logger": "0.8.0",
35
34
  "@sap-ux/project-access": "1.34.2",
36
35
  "@sap-ux/system-access": "0.6.43",
37
- "@sap-ux/i18n": "0.3.7"
36
+ "@sap-ux/i18n": "0.3.7",
37
+ "@sap-ux/feature-toggle": "0.3.5"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@sap-ux-private/playwright": "0.2.5",
@@ -53,7 +53,7 @@
53
53
  "nock": "13.4.0",
54
54
  "npm-run-all2": "6.2.0",
55
55
  "supertest": "7.1.4",
56
- "@private/preview-middleware-client": "npm:@sap-ux-private/preview-middleware-client@0.18.11",
56
+ "@private/preview-middleware-client": "npm:@sap-ux-private/preview-middleware-client@0.18.13",
57
57
  "@sap-ux/axios-extension": "1.25.7",
58
58
  "@sap-ux/store": "1.5.1",
59
59
  "@sap-ux/ui5-info": "0.13.8"
@@ -24,10 +24,6 @@
24
24
  for productive scenarios.
25
25
  -->
26
26
 
27
- <script type="text/javascript">
28
- window["data-open-ux-preview-basePath"] = "<%- basePath %>";
29
- </script>
30
-
31
27
  <!-- Bootstrap the UI5 core library. 'data-sap-ui-frameOptions="allow"' is a NON-SECURE setting for test environments -->
32
28
  <script id="sap-ui-bootstrap"
33
29
  src="<%- basePath %>/resources/sap-ui-core.js"
@@ -49,6 +45,7 @@
49
45
  data-open-ux-preview-features='<%- JSON.stringify(features) %>'
50
46
  data-open-ux-preview-flex-settings='<%- JSON.stringify(flexSettings) %>'<% } if (locals.locateReuseLibsScript) { %>
51
47
  data-open-ux-preview-libs-manifests='<%- JSON.stringify(Object.values(apps).map(app => app.url)) %>'<% } %>
48
+ data-open-ux-preview-base-url='<%- baseUrl %>'
52
49
  data-open-ux-preview-enhanced-homepage='true'>
53
50
  </script>
54
51
 
@@ -10,7 +10,7 @@
10
10
  </head>
11
11
  <body>
12
12
  <noscript>You need to enable JavaScript to run this app.</noscript>
13
- <div id="root"></div>
13
+ <div id="root" data-open-ux-preview-base-url="<%- baseUrl %>"></div>
14
14
  <script type="module">
15
15
  import { start } from './editor/app.js';
16
16
  start({
@@ -40,10 +40,6 @@
40
40
  };
41
41
  </script>
42
42
 
43
- <script type="text/javascript">
44
- window["data-open-ux-preview-basePath"] = "<%- basePath %>";
45
- </script>
46
-
47
43
  <script src="<%- basePath %>/test-resources/sap/ushell/bootstrap/sandbox.js" id="sap-ushell-bootstrap"></script>
48
44
  <!-- Bootstrap the UI5 core library. 'data-sap-ui-frameOptions="allow"' is a NON-SECURE setting for test environments -->
49
45
  <script id="sap-ui-bootstrap"
@@ -65,7 +61,8 @@
65
61
  data-open-ux-preview-custom-init='<%- init %>'<% } if (locals.flexSettings) { %>
66
62
  data-open-ux-preview-features='<%- JSON.stringify(features) %>'
67
63
  data-open-ux-preview-flex-settings='<%- JSON.stringify(flexSettings) %>'<% } if (locals.locateReuseLibsScript) { %>
68
- data-open-ux-preview-libs-manifests='<%- JSON.stringify(Object.values(apps).map(app => app.url)) %>'<% } %>>
64
+ data-open-ux-preview-libs-manifests='<%- JSON.stringify(Object.values(apps).map(app => app.url)) %>'<% } %>
65
+ data-open-ux-preview-base-url='<%- baseUrl %>'>
69
66
  </script>
70
67
 
71
68
  <% if (locals.flexSettings && flexSettings?.developerMode) { %>
@@ -40,10 +40,6 @@
40
40
  };
41
41
  </script>
42
42
 
43
- <script type="text/javascript">
44
- window["data-open-ux-preview-basePath"] = "<%- basePath %>";
45
- </script>
46
-
47
43
  <script src="<%- basePath %>/resources/sap/ushell/bootstrap/sandbox2.js" id="sap-ushell-bootstrap"></script>
48
44
  <!-- Bootstrap the UI5 core library. 'data-sap-ui-frameOptions="allow"' is a NON-SECURE setting for test environments -->
49
45
  <script id="sap-ui-bootstrap"
@@ -63,7 +59,8 @@
63
59
  data-open-ux-preview-custom-init='<%- init %>'<% } if (locals.flexSettings) { %>
64
60
  data-open-ux-preview-features='<%- JSON.stringify(features) %>'
65
61
  data-open-ux-preview-flex-settings='<%- JSON.stringify(flexSettings) %>'<% } if (locals.locateReuseLibsScript) { %>
66
- data-open-ux-preview-libs-manifests='<%- JSON.stringify(Object.values(apps).map(app => app.url)) %>'<% } %>>
62
+ data-open-ux-preview-libs-manifests='<%- JSON.stringify(Object.values(apps).map(app => app.url)) %>'<% } %>
63
+ data-open-ux-preview-base-url='<%- baseUrl %>'>
67
64
  </script>
68
65
 
69
66
  <% if (locals.flexSettings && flexSettings?.developerMode) { %>
@@ -1,55 +0,0 @@
1
- "use strict";
2
-
3
- sap.ui.define(["sap/ui/dt/OverlayUtil", "../../../utils/core", "../../dialog-factory", "../dialog-enablement-validator", "../table-quick-action-base", "../control-types", "../fe-v2/create-table-custom-column"], function (OverlayUtil, _____utils_core, ____dialog_factory, ___dialog_enablement_validator, ___table_quick_action_base, ___control_types, ___fe_v2_create_table_custom_column) {
4
- "use strict";
5
-
6
- const getControlById = _____utils_core["getControlById"];
7
- const DialogFactory = ____dialog_factory["DialogFactory"];
8
- const DialogNames = ____dialog_factory["DialogNames"];
9
- const DIALOG_ENABLEMENT_VALIDATOR = ___dialog_enablement_validator["DIALOG_ENABLEMENT_VALIDATOR"];
10
- const TableQuickActionDefinitionBase = ___table_quick_action_base["TableQuickActionDefinitionBase"];
11
- const MDC_TABLE_TYPE = ___control_types["MDC_TABLE_TYPE"];
12
- const preprocessActionExecution = ___fe_v2_create_table_custom_column["preprocessActionExecution"];
13
- const CREATE_TABLE_ACTION = 'create-table-action';
14
-
15
- /**
16
- * Quick Action for creating table action.
17
- */
18
- class AddTableActionQuickAction extends TableQuickActionDefinitionBase {
19
- constructor(context) {
20
- super(CREATE_TABLE_ACTION, [MDC_TABLE_TYPE], 'QUICK_ACTION_ADD_CUSTOM_TABLE_ACTION', context, undefined, [DIALOG_ENABLEMENT_VALIDATOR]);
21
- }
22
- async execute(path) {
23
- const {
24
- table,
25
- sectionInfo,
26
- iconTabBarFilterKey
27
- } = this.tableMap[path];
28
- if (!table) {
29
- return [];
30
- }
31
- preprocessActionExecution(table, sectionInfo, this.iconTabBar, iconTabBarFilterKey);
32
- const tableControl = getControlById(table.getId());
33
- const controlOverlay = OverlayUtil.getClosestOverlayFor(tableControl);
34
- if (controlOverlay) {
35
- controlOverlay.setSelected(true);
36
- await DialogFactory.createDialog(controlOverlay, this.context.rta, DialogNames.ADD_FRAGMENT, undefined, {
37
- aggregation: 'actions',
38
- defaultAggregationArrayIndex: 0,
39
- title: 'QUICK_ACTION_ADD_CUSTOM_TABLE_ACTION'
40
- }, {
41
- actionName: this.type,
42
- telemetryEventIdentifier: this.getTelemetryIdentifier()
43
- });
44
- }
45
- return [];
46
- }
47
- }
48
- var __exports = {
49
- __esModule: true
50
- };
51
- __exports.CREATE_TABLE_ACTION = CREATE_TABLE_ACTION;
52
- __exports.AddTableActionQuickAction = AddTableActionQuickAction;
53
- return __exports;
54
- });
55
- //# sourceMappingURL=create-table-action.js.map
@@ -1,55 +0,0 @@
1
- import OverlayUtil from 'sap/ui/dt/OverlayUtil';
2
- import type FlexCommand from 'sap/ui/rta/command/FlexCommand';
3
-
4
- import {
5
- QuickActionContext,
6
- NestedQuickActionDefinition
7
- } from '../../../cpe/quick-actions/quick-action-definition';
8
- import { getControlById } from '../../../utils/core';
9
- import { DialogFactory, DialogNames } from '../../dialog-factory';
10
- import { DIALOG_ENABLEMENT_VALIDATOR } from '../dialog-enablement-validator';
11
- import { TableQuickActionDefinitionBase } from '../table-quick-action-base';
12
- import { MDC_TABLE_TYPE } from '../control-types';
13
- import { preprocessActionExecution } from '../fe-v2/create-table-custom-column';
14
-
15
- export const CREATE_TABLE_ACTION = 'create-table-action';
16
-
17
- /**
18
- * Quick Action for creating table action.
19
- */
20
- export class AddTableActionQuickAction extends TableQuickActionDefinitionBase implements NestedQuickActionDefinition {
21
- constructor(context: QuickActionContext) {
22
- super(CREATE_TABLE_ACTION, [MDC_TABLE_TYPE], 'QUICK_ACTION_ADD_CUSTOM_TABLE_ACTION', context, undefined, [
23
- DIALOG_ENABLEMENT_VALIDATOR
24
- ]);
25
- }
26
-
27
- async execute(path: string): Promise<FlexCommand[]> {
28
- const { table, sectionInfo, iconTabBarFilterKey } = this.tableMap[path];
29
- if (!table) {
30
- return [];
31
- }
32
-
33
- preprocessActionExecution(table, sectionInfo, this.iconTabBar, iconTabBarFilterKey);
34
- const tableControl = getControlById(table.getId());
35
- const controlOverlay = OverlayUtil.getClosestOverlayFor(tableControl);
36
- if (controlOverlay) {
37
- controlOverlay.setSelected(true);
38
-
39
- await DialogFactory.createDialog(
40
- controlOverlay,
41
- this.context.rta,
42
- DialogNames.ADD_FRAGMENT,
43
- undefined,
44
- {
45
- aggregation: 'actions',
46
- defaultAggregationArrayIndex: 0,
47
- title: 'QUICK_ACTION_ADD_CUSTOM_TABLE_ACTION'
48
- },
49
- { actionName: this.type, telemetryEventIdentifier: this.getTelemetryIdentifier() }
50
- );
51
- }
52
-
53
- return [];
54
- }
55
- }