@sap-ux/preview-middleware 0.19.40 → 0.19.42

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.
@@ -1,12 +1,12 @@
1
1
  import type {
2
2
  ExternalAction,
3
3
  PendingChange,
4
- SavedPropertyChange,
5
4
  UnknownSavedChange,
6
5
  SavedControlChange,
7
- PendingConfigurationChange,
8
- SavedConfigurationChange,
9
- ConfigurationValue
6
+ ConfigurationValue,
7
+ SavedGenericChange,
8
+ SavedChange,
9
+ PendingGenericChange
10
10
  } from '@sap-ux-private/control-property-editor-common';
11
11
  import {
12
12
  changeProperty,
@@ -17,11 +17,9 @@ import {
17
17
  reloadApplication,
18
18
  setApplicationRequiresReload,
19
19
  save,
20
- CONFIGURATION_CHANGE_KIND,
21
- PropertyType,
22
20
  PENDING_CHANGE_TYPE,
23
- PROPERTY_CHANGE_KIND,
24
- UNKNOWN_CHANGE_KIND
21
+ UNKNOWN_CHANGE_KIND,
22
+ GENERIC_CHANGE_KIND
25
23
  } from '@sap-ux-private/control-property-editor-common';
26
24
  import { applyChange } from './flex-change';
27
25
  import type { ActionSenderFunction, SubscribeFunction, UI5AdaptationOptions } from '../types';
@@ -29,108 +27,33 @@ import type Event from 'sap/ui/base/Event';
29
27
  import type FlexCommand from 'sap/ui/rta/command/FlexCommand';
30
28
  import Log from 'sap/base/Log';
31
29
  import { modeAndStackChangeHandler } from '../rta-service';
32
- import JsControlTreeModifier from 'sap/ui/core/util/reflection/JsControlTreeModifier';
33
- import FlexChange from 'sap/ui/fl/Change';
30
+ import { ChangeDefinition } from 'sap/ui/fl/Change';
34
31
  import { getError } from '../../utils/error';
35
- import { isLowerThanMinimalUi5Version, getUi5Version } from '../../utils/version';
36
32
  import MessageToast from 'sap/m/MessageToast';
37
33
  import { getTextBundle } from '../../i18n';
38
34
  import { getControlById, isA } from '../../utils/core';
39
35
  import UI5Element from 'sap/ui/core/Element';
40
- import { getConfigMapControlIdMap } from '../../utils/fe-v4';
41
36
  import { setAdditionalChangeInfo } from '../../utils/additional-change-info';
37
+ import {
38
+ ChangeHandler,
39
+ changeType,
40
+ ConfigChange,
41
+ GENERIC_CHANGE_HANDLER,
42
+ getControlIdByChange,
43
+ getFlexObject,
44
+ type GenericChange
45
+ } from './generic-change';
42
46
 
43
47
  const TITLE_MAP: { [key: string]: string } = {
44
48
  appdescr_app_addAnnotationsToOData: 'Add New Annotation File'
45
49
  };
46
50
 
47
- interface ChangeContent {
48
- property: string;
49
- newValue: string;
50
- newBinding: string;
51
- }
52
51
  export const STACK_CHANGE_EVENT = 'STACK_CHANGED';
53
52
  export interface StackChangedEventDetail {
54
53
  controls: UI5Element[];
55
54
  }
56
55
 
57
- interface ConfigurationChangeContent {
58
- page: string;
59
- entityPropertyChange: {
60
- propertyPath: string;
61
- operation: 'UPSERT' | 'DELETE' | 'INSERT' | 'UPDATE';
62
- propertyValue: string;
63
- };
64
- }
65
-
66
- interface ChangeSelector {
67
- id: string;
68
- type: string;
69
- }
70
-
71
- interface BaseChange {
72
- fileName: string;
73
- timestamp: string;
74
- creation: string;
75
- value: string;
76
- selector: ChangeSelector;
77
- }
78
-
79
- const PROPERTY_CHANGE = 'propertyChange';
80
- const PROPERTY_BINDING_CHANGE = 'propertyBindingChange';
81
- const MANIFEST_V4_CHANGE = 'appdescr_fe_changePageConfiguration';
82
-
83
- interface PropertyChange extends BaseChange {
84
- changeType: typeof PROPERTY_CHANGE | typeof PROPERTY_BINDING_CHANGE;
85
- controlId: string;
86
- propertyName: string;
87
- content: ChangeContent;
88
- }
89
- interface ConfigChange extends BaseChange {
90
- changeType: typeof MANIFEST_V4_CHANGE;
91
- propertyName: string;
92
- content: ConfigurationChangeContent;
93
- }
94
-
95
- type SavedChangesResponse = Record<string, PropertyChange | ConfigChange>;
96
-
97
- type Properties<T extends object> = { [K in keyof T]-?: K extends string ? K : never }[keyof T];
98
- /**
99
- * Assert change for its validity. Throws error if no value found in saved changes.
100
- *
101
- * @param properties array of property name
102
- * @param target object which will be checked
103
- */
104
- function assertProperties<T extends object>(properties: Properties<T>[], target: T): void {
105
- for (const property of properties) {
106
- const value = target[property];
107
- if (value === null || value === undefined) {
108
- throw new Error(`Invalid change, missing ${property} in the change file`);
109
- }
110
- }
111
- }
112
-
113
- /**
114
- * Assert change for its validity. Throws error if no value found in saved changes.
115
- *
116
- * @param change Change object
117
- */
118
- function assertChange(change: PropertyChange): void {
119
- assertProperties(['fileName', 'selector', 'content', 'creation'], change);
120
- assertProperties(['id'], change.selector);
121
- assertProperties(['property'], change.content);
122
- }
123
-
124
- /**
125
- * Assert v4 manifest change for its validity. Throws error if no value found in saved changes.
126
- *
127
- * @param change Change object
128
- */
129
- function assertManifestChange(change: ConfigChange): void {
130
- assertProperties(['fileName', 'content', 'creation'], change);
131
- assertProperties(['page', 'entityPropertyChange'], change.content);
132
- assertProperties(['propertyPath', 'operation', 'propertyValue'], change.content.entityPropertyChange);
133
- }
56
+ type SavedChangesResponse = Record<string, ConfigChange | GenericChange>;
134
57
 
135
58
  /**
136
59
  * Modify rta message.
@@ -144,34 +67,17 @@ function modifyRTAErrorMessage(errorMessage: string, id: string, type: string):
144
67
  return errorMessage.replace('Error: Applying property changes failed:', '').replace(`${type}#${id}`, '');
145
68
  }
146
69
 
147
- /**
148
- * Returns a shortened version of the given configuration path segments by removing excess segments,
149
- * leaving only the most relevant parts for display. For example, the configuration path
150
- * `controlConfiguration/com.sap.UI.v1.LineItem/tableSettings` will be shortened to
151
- * `LineItem/tableSettings`.
152
- *
153
- * @param propertyPathSeg string[]
154
- * @returns string
155
- */
156
- function getCompactV4ConfigPath(propertyPathSeg: string[]): string {
157
- return propertyPathSeg.join('/').replace(/^controlConfiguration\/(?:([^/]+\/))?@[^/]+\.v1\./, '$1');
158
- }
159
-
160
70
  /**
161
71
  * A Class of ChangeService
162
72
  */
163
73
  export class ChangeService extends EventTarget {
164
- private savedChanges:
165
- | SavedPropertyChange[]
166
- | UnknownSavedChange[]
167
- | SavedControlChange[]
168
- | SavedConfigurationChange[] = [];
74
+ private savedChanges: SavedChange[] = [];
169
75
  private changesRequiringReload = 0;
170
76
  private sendAction: (action: ExternalAction) => void;
171
77
  private pendingChanges: PendingChange[] = [];
172
78
  private changedFiles: Record<string, object> = {};
173
79
  private readonly eventStack: object[] = [];
174
- private pendingConfigChangeMap: Map<string, PendingConfigurationChange[]> = new Map();
80
+ private pendingConfigChangeMap: Map<string, PendingGenericChange[]> = new Map();
175
81
  private configPropertyControlIdMap: Map<string, string[]> = new Map();
176
82
  /**
177
83
  *
@@ -242,25 +148,17 @@ export class ChangeService extends EventTarget {
242
148
  );
243
149
  }
244
150
 
245
- private getSavedConfigurationChange(change: ConfigChange): SavedConfigurationChange {
246
- assertManifestChange(change);
247
- if ([change.content.entityPropertyChange.propertyValue].every((item) => item === undefined || item === null)) {
248
- throw new Error('Invalid change, missing property value on change file');
249
- }
250
- const propertyPathSegments = change.content.entityPropertyChange.propertyPath.split('/');
251
- const propertyName = propertyPathSegments.pop();
252
- const configMapKey = getConfigMapControlIdMap(change.content.page, propertyPathSegments);
253
- const controlIds = this.configPropertyControlIdMap?.get(configMapKey) || [];
254
- return {
255
- type: 'saved',
256
- kind: 'configuration',
257
- fileName: change.fileName,
258
- controlIds,
259
- propertyPath: getCompactV4ConfigPath(propertyPathSegments) || change.content.page,
260
- propertyName: propertyName ?? '',
261
- value: change.content.entityPropertyChange.propertyValue,
262
- timestamp: new Date(change.creation).getTime()
263
- };
151
+ private isGenericChange(change: GenericChange): change is GenericChange {
152
+ return (
153
+ change.changeType === 'appdescr_app_addAnnotationsToOData' ||
154
+ change.changeType === 'rename' ||
155
+ change.changeType === 'moveControls' ||
156
+ change.changeType === 'addXML' ||
157
+ change.changeType === 'propertyChange' ||
158
+ change.changeType === 'propertyBindingChange' ||
159
+ change.changeType === 'appdescr_fe_changePageConfiguration' ||
160
+ change.changeType === 'appdescr_ui_generic_app_changePageConfiguration'
161
+ );
264
162
  }
265
163
 
266
164
  /**
@@ -270,90 +168,80 @@ export class ChangeService extends EventTarget {
270
168
  this.changedFiles = {};
271
169
  const savedChangesResponse = await fetch(FlexChangesEndPoints.changes + `?_=${Date.now()}`);
272
170
  const savedChanges = (await savedChangesResponse.json()) as SavedChangesResponse;
171
+ const textBundle = await getTextBundle();
273
172
  const changes = (
274
- (
275
- await Promise.all(
276
- Object.keys(savedChanges ?? {}).map(
277
- async (
278
- key
279
- ): Promise<
280
- | SavedPropertyChange
281
- | UnknownSavedChange
282
- | SavedControlChange
283
- | SavedConfigurationChange
284
- | undefined
285
- > => {
286
- const change: PropertyChange | ConfigChange = savedChanges[key];
287
- let selectorId;
288
- try {
289
- if (change.changeType === MANIFEST_V4_CHANGE) {
290
- return this.getSavedConfigurationChange(change);
291
- } else {
292
- const flexObject = await this.getFlexObject(change);
293
- selectorId = await this.getControlIdByChange(flexObject);
294
- assertChange(change);
295
- if (
296
- [change.content.newValue, change.content.newBinding].every(
297
- (item) => item === undefined || item === null
298
- )
299
- ) {
300
- throw new Error('Invalid change, missing new value in the change file');
301
- }
302
- if (
303
- change.changeType !== 'propertyChange' &&
304
- change.changeType !== 'propertyBindingChange'
305
- ) {
306
- throw new Error('Unknown Change Type');
307
- }
308
- this.changedFiles[change.fileName] = change;
309
- return {
310
- type: 'saved',
311
- kind: 'property',
312
- fileName: change.fileName,
313
- controlId: selectorId,
314
- propertyName: change.content.property,
315
- value: change.content.newValue ?? change.content.newBinding,
316
- timestamp: new Date(change.creation).getTime(),
317
- controlName: change.selector.type
318
- ? (change.selector.type.split('.').pop() as string)
319
- : '',
320
- changeType: change.changeType
321
- } as SavedPropertyChange;
173
+ await Promise.all(
174
+ Object.keys(savedChanges ?? {}).map(
175
+ async (key): Promise<UnknownSavedChange | SavedControlChange | SavedGenericChange | undefined> => {
176
+ const change = savedChanges[key];
177
+ try {
178
+ const handler = GENERIC_CHANGE_HANDLER[
179
+ change.changeType
180
+ ] as unknown as ChangeHandler<GenericChange>;
181
+ if (this.isGenericChange(change)) {
182
+ const {
183
+ properties,
184
+ changeTitle,
185
+ controlId,
186
+ changeType: type,
187
+ subtitle
188
+ } = await handler(change as unknown as GenericChange, {
189
+ textBundle,
190
+ appComponent: this.options.rta.getRootControlInstance(),
191
+ configPropertyControlIdMap: this.configPropertyControlIdMap
192
+ });
193
+ this.changedFiles[change.fileName] = change;
194
+ return {
195
+ kind: GENERIC_CHANGE_KIND,
196
+ type: 'saved',
197
+ fileName: change.fileName,
198
+ ...(subtitle && { subtitle }),
199
+ changeType: type ?? change.changeType,
200
+ timestamp: new Date(change.creation).getTime(),
201
+ ...(controlId && { controlId }),
202
+ properties,
203
+ title: textBundle.getText(changeTitle)
204
+ };
205
+ }
206
+ throw new Error('Unknown change type');
207
+ } catch (error) {
208
+ // Gracefully handle change files with invalid content
209
+ const flexObject = await getFlexObject(change);
210
+ const selectorId = await getControlIdByChange(
211
+ flexObject,
212
+ this.options.rta.getRootControlInstance()
213
+ );
214
+ if (change.fileName) {
215
+ this.changedFiles[change.fileName] = change;
216
+ const unknownChange: UnknownSavedChange = {
217
+ type: 'saved',
218
+ kind: 'unknown',
219
+ changeType: change.changeType,
220
+ fileName: change.fileName,
221
+ timestamp: new Date(change.creation).getTime()
222
+ };
223
+ if (change.creation) {
224
+ unknownChange.timestamp = new Date(change.creation).getTime();
322
225
  }
323
- } catch (error) {
324
- // Gracefully handle change files with invalid content
325
- const title = TITLE_MAP[change.changeType] ?? '';
326
- if (change.fileName) {
327
- this.changedFiles[change.fileName] = change;
328
- const unknownChange: UnknownSavedChange = {
329
- type: 'saved',
330
- kind: 'unknown',
331
- changeType: change.changeType,
332
- fileName: change.fileName,
333
- timestamp: new Date(change.creation).getTime(),
334
- ...(title && { title })
226
+ if (selectorId) {
227
+ const controlChange: SavedControlChange = {
228
+ ...unknownChange,
229
+ kind: 'control',
230
+ controlId: selectorId
335
231
  };
336
- if (change.creation) {
337
- unknownChange.timestamp = new Date(change.creation).getTime();
338
- }
339
- if (selectorId) {
340
- const controlChange: SavedControlChange = {
341
- ...unknownChange,
342
- kind: 'control',
343
- controlId: selectorId
344
- };
345
-
346
- return controlChange;
347
- }
348
- return unknownChange;
232
+
233
+ return controlChange;
349
234
  }
350
- return undefined;
235
+ return unknownChange;
351
236
  }
237
+ return undefined;
352
238
  }
353
- )
239
+ }
354
240
  )
355
- ).filter((change) => !!change) as SavedPropertyChange[]
356
- ).sort((a, b) => b.timestamp - a.timestamp);
241
+ )
242
+ )
243
+ .filter((change) => !!change)
244
+ .sort((a, b) => b.timestamp - a.timestamp);
357
245
  this.savedChanges = changes;
358
246
  }
359
247
 
@@ -370,10 +258,6 @@ export class ChangeService extends EventTarget {
370
258
  return fileName === change.fileName;
371
259
  }
372
260
 
373
- if (change.kind === 'property') {
374
- return change.controlId === controlId && change.propertyName === propertyName;
375
- }
376
-
377
261
  if (change.kind === 'control') {
378
262
  return change.controlId === controlId;
379
263
  }
@@ -436,12 +320,7 @@ export class ChangeService extends EventTarget {
436
320
  if (this.eventStack.length - 1 === eventIndex) {
437
321
  this.pendingChanges = pendingChanges.filter((change): boolean => !!change);
438
322
  const changesRequiringReload = this.pendingChanges.reduce(
439
- (sum, change) =>
440
- change.kind === CONFIGURATION_CHANGE_KIND ||
441
- change.changeType === 'appdescr_ui_generic_app_changePageConfiguration' ||
442
- change.changeType === 'appdescr_app_addAnnotationsToOData'
443
- ? sum + 1
444
- : sum,
323
+ (sum, change) => (isGenericConfigChange(change) ? sum + 1 : sum),
445
324
  0
446
325
  );
447
326
  if (changesRequiringReload > this.changesRequiringReload) {
@@ -460,12 +339,12 @@ export class ChangeService extends EventTarget {
460
339
  }
461
340
 
462
341
  // Notify to update the ui for configuration changes.
463
- const configurationChanges = this.pendingChanges?.filter((item) => item.kind === 'configuration');
342
+ const configurationChanges: PendingGenericChange[] = this.pendingChanges?.filter(isGenericConfigChange);
464
343
  if (configurationChanges.length) {
465
344
  const stackChangeEvent = new CustomEvent(STACK_CHANGE_EVENT, {
466
345
  detail: {
467
346
  controls: configurationChanges.reduce((acc: UI5Element[], item) => {
468
- const controls = (item.controlIds || [])
347
+ const controls = ([...(item.controlId ?? [])] as string[])
469
348
  .map((id: string) => {
470
349
  return getControlById(id);
471
350
  })
@@ -490,7 +369,8 @@ export class ChangeService extends EventTarget {
490
369
  */
491
370
  public getConfigurationPropertyValue(controlId: string, propertyName: string): ConfigurationValue | undefined {
492
371
  const pendingChanges = this.pendingConfigChangeMap?.get(controlId);
493
- return (pendingChanges || []).find((item) => item.isActive && item.propertyName === propertyName)?.value;
372
+ return (pendingChanges || []).find((item) => item.isActive && item.properties[0].label === propertyName)
373
+ ?.properties[0].value;
494
374
  }
495
375
 
496
376
  /**
@@ -526,91 +406,14 @@ export class ChangeService extends EventTarget {
526
406
  }
527
407
  }
528
408
 
529
- private prepareV4ConfigurationChange(
530
- command: FlexCommand,
531
- value: ConfigurationValue,
532
- fileName: string,
533
- index: number,
534
- inactiveCommandCount: number
535
- ): PendingConfigurationChange {
536
- const { entityPropertyChange, page } = command.getProperty('parameters') as {
537
- entityPropertyChange: {
538
- propertyPath: string;
539
- };
540
- page: string;
541
- };
542
- const controlId = this.getCommandSelectorId(command) ?? '';
543
- const propertyPathSegments = entityPropertyChange.propertyPath.split('/');
544
- const propName = propertyPathSegments.pop() as string;
545
- const key = getConfigMapControlIdMap(page, propertyPathSegments);
546
-
547
- const isActive = index >= inactiveCommandCount;
548
- const controlIds = this.configPropertyControlIdMap?.get(key) || [controlId];
549
- const result: PendingConfigurationChange = {
550
- type: PENDING_CHANGE_TYPE,
551
- kind: CONFIGURATION_CHANGE_KIND,
552
- controlIds,
553
- propertyPath: getCompactV4ConfigPath(propertyPathSegments) || page,
554
- propertyName: propName,
555
- isActive,
556
- value,
557
- fileName
558
- };
559
- for (const id of result.controlIds) {
560
- if (!this.pendingConfigChangeMap.get(id)) {
561
- this.pendingConfigChangeMap.set(id, []);
562
- }
563
- const pendingChanges = this.pendingConfigChangeMap.get(id);
564
- pendingChanges?.push(result);
565
- }
566
-
567
- return result;
568
- }
569
-
570
- private prepareV2ConfigurationChange(
571
- command: FlexCommand,
572
- fileName: string,
573
- index: number,
574
- inactiveCommandCount: number
575
- ): PendingConfigurationChange {
576
- const { entityPropertyChange, page } = command.getProperty('parameters') as {
577
- entityPropertyChange: {
578
- propertyPath: string;
579
- propertyValue: Record<string, string>;
580
- };
581
- page: string;
582
- };
583
- const propertyPathSegments = entityPropertyChange.propertyPath.split('/');
584
- const propertyName =
585
- Object.keys(entityPropertyChange.propertyValue)?.[0] ??
586
- propertyPathSegments[propertyPathSegments.length - 1];
587
- const propertyValue = entityPropertyChange.propertyValue?.[propertyName] ?? entityPropertyChange.propertyValue;
588
- const controlId = this.getCommandSelectorId(command) ?? '';
589
-
590
- const key = getConfigMapControlIdMap(page, propertyPathSegments);
591
-
592
- const isActive = index >= inactiveCommandCount;
593
- const controlIds = this.configPropertyControlIdMap?.get(key) || [controlId];
594
-
595
- const result: PendingConfigurationChange = {
596
- type: PENDING_CHANGE_TYPE,
597
- kind: CONFIGURATION_CHANGE_KIND,
598
- controlIds,
599
- propertyPath: getCompactV4ConfigPath(propertyPathSegments) || page,
600
- propertyName,
601
- isActive,
602
- value: propertyValue,
603
- fileName
604
- };
605
- for (const id of result.controlIds) {
409
+ private trackPendingConfigChanges(result: PendingGenericChange): void {
410
+ for (const id of result?.controlId ?? []) {
606
411
  if (!this.pendingConfigChangeMap.get(id)) {
607
412
  this.pendingConfigChangeMap.set(id, []);
608
413
  }
609
414
  const pendingChanges = this.pendingConfigChangeMap.get(id);
610
415
  pendingChanges?.push(result);
611
416
  }
612
-
613
- return result;
614
417
  }
615
418
 
616
419
  /**
@@ -627,10 +430,10 @@ export class ChangeService extends EventTarget {
627
430
  index: number
628
431
  ): Promise<PendingChange | undefined> {
629
432
  const change = command?.getPreparedChange?.();
630
-
433
+ const textBundle = await getTextBundle();
631
434
  const selectorId =
632
435
  typeof change?.getSelector === 'function'
633
- ? await this.getControlIdByChange(change)
436
+ ? await getControlIdByChange(change, this.options.rta.getRootControlInstance())
634
437
  : this.getCommandSelectorId(command);
635
438
 
636
439
  const changeType = this.getCommandChangeType(command);
@@ -639,37 +442,36 @@ export class ChangeService extends EventTarget {
639
442
  return undefined;
640
443
  }
641
444
 
642
- const { fileName } = change.getDefinition ? change.getDefinition() : (change.getJson() as { fileName: string });
643
- if ((changeType === 'propertyChange' || changeType === 'propertyBindingChange') && selectorId) {
644
- let value = '';
645
- switch (changeType) {
646
- case 'propertyChange':
647
- value = command.getProperty('newValue') as string;
648
- break;
649
- case 'propertyBindingChange':
650
- value = command.getProperty('newBinding') as string;
651
- break;
652
- }
653
-
654
- return {
655
- type: PENDING_CHANGE_TYPE,
656
- kind: PROPERTY_CHANGE_KIND,
657
- changeType,
658
- controlId: selectorId,
659
- propertyType: PropertyType.ControlProperty,
660
- propertyName: command.getProperty('propertyName') as string,
445
+ const changeDefinition = change.getDefinition ? change.getDefinition() : (change.getJson() as ChangeDefinition);
446
+ const { fileName } = changeDefinition;
447
+ const handler = GENERIC_CHANGE_HANDLER[changeType as changeType] as unknown as ChangeHandler<GenericChange>;
448
+ if (handler) {
449
+ const {
450
+ properties,
451
+ changeTitle,
452
+ controlId,
453
+ changeType: type,
454
+ subtitle
455
+ } = await handler(changeDefinition as unknown as GenericChange, {
456
+ textBundle,
457
+ appComponent: this.options.rta.getRootControlInstance(),
458
+ configPropertyControlIdMap: this.configPropertyControlIdMap
459
+ });
460
+ const genericChange: PendingGenericChange = {
461
+ kind: GENERIC_CHANGE_KIND,
462
+ type: 'pending',
463
+ changeType: type ?? changeType,
464
+ ...(subtitle && { subtitle }),
661
465
  isActive: index >= inactiveCommandCount,
662
- value,
663
- controlName: command.getElement().getMetadata().getName().split('.').pop() ?? '',
664
- fileName
466
+ title: textBundle.getText(changeTitle),
467
+ fileName,
468
+ ...(controlId && { controlId }),
469
+ properties
665
470
  };
666
- } else if (changeType === 'appdescr_fe_changePageConfiguration') {
667
- const value = (
668
- command.getProperty('parameters') as { entityPropertyChange: { propertyValue: ConfigurationValue } }
669
- ).entityPropertyChange.propertyValue;
670
- return this.prepareV4ConfigurationChange(command, value, fileName, index, inactiveCommandCount);
671
- } else if (changeType === 'appdescr_ui_generic_app_changePageConfiguration') {
672
- return this.prepareV2ConfigurationChange(command, fileName, index, inactiveCommandCount);
471
+ if (changeType === 'appdescr_fe_changePageConfiguration') {
472
+ this.trackPendingConfigChanges(genericChange);
473
+ }
474
+ return genericChange;
673
475
  } else {
674
476
  const title = TITLE_MAP[changeType] ?? '';
675
477
  let result: PendingChange = {
@@ -743,59 +545,6 @@ export class ChangeService extends EventTarget {
743
545
  ]) as string | undefined;
744
546
  }
745
547
 
746
- /**
747
- * Get element id by change.
748
- *
749
- * @param change to be executed for creating change
750
- * @returns element id or empty string
751
- */
752
- private async getControlIdByChange(change: FlexChange<ChangeContent>): Promise<string | undefined> {
753
- const appComponent = this.options.rta.getRootControlInstance();
754
- const selector = typeof change.getSelector === 'function' ? change.getSelector() : undefined;
755
- const changeType = change.getChangeType();
756
- const layer = change.getLayer();
757
-
758
- if (!selector?.id) {
759
- return;
760
- }
761
-
762
- try {
763
- let control = JsControlTreeModifier.bySelector(selector, appComponent);
764
- if (!control) {
765
- return selector.id;
766
- }
767
-
768
- const changeHandlerAPI = (await import('sap/ui/fl/write/api/ChangesWriteAPI')).default;
769
-
770
- if (typeof changeHandlerAPI?.getChangeHandler !== 'function') {
771
- return selector.id;
772
- }
773
-
774
- const changeHandler = await changeHandlerAPI.getChangeHandler({
775
- changeType,
776
- element: control,
777
- modifier: JsControlTreeModifier,
778
- layer
779
- });
780
-
781
- if (changeHandler && typeof changeHandler.getChangeVisualizationInfo === 'function') {
782
- const result: { affectedControls?: [string] } = await changeHandler.getChangeVisualizationInfo(
783
- change,
784
- appComponent
785
- );
786
- return JsControlTreeModifier.getControlIdBySelector(
787
- result?.affectedControls?.[0] ?? selector,
788
- appComponent
789
- );
790
- }
791
-
792
- return JsControlTreeModifier.getControlIdBySelector(selector, appComponent);
793
- } catch (error) {
794
- Log.error('Getting element ID from change has failed:', getError(error));
795
- return selector.id;
796
- }
797
- }
798
-
799
548
  /**
800
549
  * Sync outline changes to place modification markers when outline is changed.
801
550
  *
@@ -803,9 +552,10 @@ export class ChangeService extends EventTarget {
803
552
  */
804
553
  public async syncOutlineChanges(): Promise<void> {
805
554
  for (const change of this.savedChanges) {
806
- if (change.kind !== 'unknown' && change.kind !== 'configuration') {
807
- const flexObject = await this.getFlexObject(this.changedFiles[change.fileName]);
808
- change.controlId = (await this.getControlIdByChange(flexObject)) ?? '';
555
+ if (change.kind !== 'unknown' && change.changeType !== 'configuration') {
556
+ const flexObject = await getFlexObject(this.changedFiles[change.fileName]);
557
+ change.controlId =
558
+ (await getControlIdByChange(flexObject, this.options.rta.getRootControlInstance())) ?? '';
809
559
  }
810
560
  }
811
561
  this.updateStack();
@@ -814,20 +564,8 @@ export class ChangeService extends EventTarget {
814
564
  public onStackChange(handler: (event: CustomEvent<StackChangedEventDetail>) => void | Promise<void>): void {
815
565
  this.addEventListener(STACK_CHANGE_EVENT, handler as EventListener);
816
566
  }
567
+ }
817
568
 
818
- /**
819
- * Get FlexObject from change object based on UI5 version.
820
- *
821
- * @param change change object
822
- * @returns FlexChange
823
- */
824
- private async getFlexObject(change: object): Promise<FlexChange<ChangeContent>> {
825
- if (isLowerThanMinimalUi5Version(await getUi5Version(), { major: 1, minor: 109 })) {
826
- const Change = (await import('sap/ui/fl/Change')).default;
827
- return new Change(change);
828
- }
829
-
830
- const FlexObjectFactory = (await import('sap/ui/fl/apply/_internal/flexObjects/FlexObjectFactory')).default;
831
- return FlexObjectFactory.createFromFileContent(change) as FlexChange<ChangeContent>;
832
- }
569
+ function isGenericConfigChange(change: PendingChange): change is PendingGenericChange {
570
+ return change.kind === GENERIC_CHANGE_KIND && change.changeType === 'configuration';
833
571
  }