@sap-ux/preview-middleware 0.23.47 → 0.23.49

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.
Files changed (36) hide show
  1. package/dist/client/adp/command-executor.js +99 -66
  2. package/dist/client/adp/controllers/AddCustomFragment.controller.js +120 -102
  3. package/dist/client/adp/controllers/AddFragment.controller.js +189 -163
  4. package/dist/client/adp/controllers/AddSubpage.controller.js +146 -137
  5. package/dist/client/adp/controllers/AddTableColumnFragments.controller.js +230 -188
  6. package/dist/client/adp/controllers/BaseDialog.controller.js +187 -164
  7. package/dist/client/adp/controllers/ControllerExtension.controller.js +329 -253
  8. package/dist/client/adp/controllers/ExtensionPoint.controller.js +158 -114
  9. package/dist/client/adp/extension-point.js +81 -60
  10. package/dist/client/adp/init.js +100 -99
  11. package/dist/client/adp/quick-actions/common/add-new-annotation-file.js +165 -147
  12. package/dist/client/adp/quick-actions/enablement-validator.js +0 -4
  13. package/dist/client/adp/quick-actions/fe-v2/create-table-custom-column.js +105 -100
  14. package/dist/client/adp/quick-actions/simple-quick-action-base.js +44 -40
  15. package/dist/client/adp/quick-actions/table-quick-action-base.js +309 -266
  16. package/dist/client/adp/sync-views-utils.js +119 -83
  17. package/dist/client/cpe/changes/flex-change.js +64 -48
  18. package/dist/client/cpe/changes/service.js +492 -367
  19. package/dist/client/cpe/communication-service.js +41 -29
  20. package/dist/client/cpe/connector-service.js +87 -64
  21. package/dist/client/cpe/context-menu-service.js +87 -74
  22. package/dist/client/cpe/control-data.js +353 -263
  23. package/dist/client/cpe/documentation.js +183 -126
  24. package/dist/client/cpe/init.js +69 -75
  25. package/dist/client/cpe/outline/service.js +60 -45
  26. package/dist/client/cpe/quick-actions/quick-action-definition.js +0 -4
  27. package/dist/client/cpe/quick-actions/quick-action-service.js +154 -129
  28. package/dist/client/cpe/rta-service.js +91 -69
  29. package/dist/client/cpe/selection.js +239 -187
  30. package/dist/client/cpe/types.js +0 -4
  31. package/dist/client/flp/init.js +403 -296
  32. package/dist/client/manifest.json +7 -4
  33. package/dist/client/thirdparty/@sap-ux-private/control-property-editor-common.js +444 -370
  34. package/dist/client/utils/info-center-message.js +59 -31
  35. package/dist/client/utils/version.js +128 -72
  36. package/package.json +3 -3
@@ -1,386 +1,511 @@
1
- 'use strict';
2
- sap.ui.define([
3
- 'open/ux/preview/client/thirdparty/@sap-ux-private/control-property-editor-common',
4
- 'sap/base/Log',
5
- '../../i18n',
6
- '../../utils/additional-change-info',
7
- '../../utils/core',
8
- '../../utils/error',
9
- '../../utils/info-center-message',
10
- '../rta-service',
11
- './flex-change',
12
- './generic-change'
13
- ], function (___sap_ux_private_control_property_editor_common, Log, ____i18n, ____utils_additional_change_info, ____utils_core, ____utils_error, ____utils_info_center_message, ___rta_service, ___flex_change, ___generic_change) {
14
- 'use strict';
15
- const changeProperty = ___sap_ux_private_control_property_editor_common['changeProperty'];
16
- const changeStackModified = ___sap_ux_private_control_property_editor_common['changeStackModified'];
17
- const deletePropertyChanges = ___sap_ux_private_control_property_editor_common['deletePropertyChanges'];
18
- const FlexChangesEndPoints = ___sap_ux_private_control_property_editor_common['FlexChangesEndPoints'];
19
- const GENERIC_CHANGE_KIND = ___sap_ux_private_control_property_editor_common['GENERIC_CHANGE_KIND'];
20
- const MessageBarType = ___sap_ux_private_control_property_editor_common['MessageBarType'];
21
- const PENDING_CHANGE_TYPE = ___sap_ux_private_control_property_editor_common['PENDING_CHANGE_TYPE'];
22
- const propertyChangeFailed = ___sap_ux_private_control_property_editor_common['propertyChangeFailed'];
23
- const reloadApplication = ___sap_ux_private_control_property_editor_common['reloadApplication'];
24
- const save = ___sap_ux_private_control_property_editor_common['save'];
25
- const setApplicationRequiresReload = ___sap_ux_private_control_property_editor_common['setApplicationRequiresReload'];
26
- const UNKNOWN_CHANGE_KIND = ___sap_ux_private_control_property_editor_common['UNKNOWN_CHANGE_KIND'];
27
- const getTextBundle = ____i18n['getTextBundle'];
28
- const setAdditionalChangeInfo = ____utils_additional_change_info['setAdditionalChangeInfo'];
29
- const getControlById = ____utils_core['getControlById'];
30
- const isA = ____utils_core['isA'];
31
- const getError = ____utils_error['getError'];
32
- const sendInfoCenterMessage = ____utils_info_center_message['sendInfoCenterMessage'];
33
- const modeAndStackChangeHandler = ___rta_service['modeAndStackChangeHandler'];
34
- const applyChange = ___flex_change['applyChange'];
35
- const GENERIC_CHANGE_HANDLER = ___generic_change['GENERIC_CHANGE_HANDLER'];
36
- const getControlIdByChange = ___generic_change['getControlIdByChange'];
37
- const getFlexObject = ___generic_change['getFlexObject'];
38
- const TITLE_MAP = { appdescr_app_addAnnotationsToOData: 'Add New Annotation File' };
39
- const STACK_CHANGE_EVENT = 'STACK_CHANGED';
40
- function modifyRTAErrorMessage(errorMessage, id, type) {
41
- return errorMessage.replace('Error: Applying property changes failed:', '').replace(`${ type }#${ id }`, '');
1
+ "use strict";
2
+
3
+ sap.ui.define(["open/ux/preview/client/thirdparty/@sap-ux-private/control-property-editor-common", "sap/base/Log", "../../i18n", "../../utils/additional-change-info", "../../utils/core", "../../utils/error", "../../utils/info-center-message", "../rta-service", "./flex-change", "./generic-change"], function (___sap_ux_private_control_property_editor_common, Log, ____i18n, ____utils_additional_change_info, ____utils_core, ____utils_error, ____utils_info_center_message, ___rta_service, ___flex_change, ___generic_change) {
4
+ "use strict";
5
+
6
+ const changeProperty = ___sap_ux_private_control_property_editor_common["changeProperty"];
7
+ const changeStackModified = ___sap_ux_private_control_property_editor_common["changeStackModified"];
8
+ const deletePropertyChanges = ___sap_ux_private_control_property_editor_common["deletePropertyChanges"];
9
+ const FlexChangesEndPoints = ___sap_ux_private_control_property_editor_common["FlexChangesEndPoints"];
10
+ const GENERIC_CHANGE_KIND = ___sap_ux_private_control_property_editor_common["GENERIC_CHANGE_KIND"];
11
+ const MessageBarType = ___sap_ux_private_control_property_editor_common["MessageBarType"];
12
+ const PENDING_CHANGE_TYPE = ___sap_ux_private_control_property_editor_common["PENDING_CHANGE_TYPE"];
13
+ const propertyChangeFailed = ___sap_ux_private_control_property_editor_common["propertyChangeFailed"];
14
+ const reloadApplication = ___sap_ux_private_control_property_editor_common["reloadApplication"];
15
+ const save = ___sap_ux_private_control_property_editor_common["save"];
16
+ const setApplicationRequiresReload = ___sap_ux_private_control_property_editor_common["setApplicationRequiresReload"];
17
+ const UNKNOWN_CHANGE_KIND = ___sap_ux_private_control_property_editor_common["UNKNOWN_CHANGE_KIND"];
18
+ const getTextBundle = ____i18n["getTextBundle"];
19
+ const setAdditionalChangeInfo = ____utils_additional_change_info["setAdditionalChangeInfo"];
20
+ const getControlById = ____utils_core["getControlById"];
21
+ const isA = ____utils_core["isA"];
22
+ const getError = ____utils_error["getError"];
23
+ const sendInfoCenterMessage = ____utils_info_center_message["sendInfoCenterMessage"];
24
+ const modeAndStackChangeHandler = ___rta_service["modeAndStackChangeHandler"];
25
+ const applyChange = ___flex_change["applyChange"];
26
+ const GENERIC_CHANGE_HANDLER = ___generic_change["GENERIC_CHANGE_HANDLER"];
27
+ const getControlIdByChange = ___generic_change["getControlIdByChange"];
28
+ const getFlexObject = ___generic_change["getFlexObject"];
29
+ const TITLE_MAP = {
30
+ appdescr_app_addAnnotationsToOData: 'Add New Annotation File'
31
+ };
32
+ const STACK_CHANGE_EVENT = 'STACK_CHANGED';
33
+ /**
34
+ * Modify rta message.
35
+ *
36
+ * @param errorMessage error message to be replaced
37
+ * @param id - control id
38
+ * @param type - control type
39
+ * @returns string
40
+ */
41
+ function modifyRTAErrorMessage(errorMessage, id, type) {
42
+ return errorMessage.replace('Error: Applying property changes failed:', '').replace(`${type}#${id}`, '');
43
+ }
44
+
45
+ /**
46
+ * A Class of ChangeService
47
+ */
48
+ class ChangeService extends EventTarget {
49
+ savedChanges = [];
50
+ changesRequiringReload = 0;
51
+ pendingChanges = [];
52
+ changedFiles = {};
53
+ eventStack = [];
54
+ pendingConfigChangeMap = (() => new Map())();
55
+ configPropertyControlIdMap = (() => new Map())();
56
+ /**
57
+ *
58
+ * @param options ui5 adaptation options.
59
+ * @param ui5 facade for ui5 framework methods.
60
+ * @param selectionService selection service instance.
61
+ */
62
+ constructor(options) {
63
+ super();
64
+ this.options = options;
42
65
  }
43
- class ChangeService extends EventTarget {
44
- savedChanges = [];
45
- changesRequiringReload = 0;
46
- pendingChanges = [];
47
- changedFiles = {};
48
- eventStack = [];
49
- pendingConfigChangeMap = ((() => new Map())());
50
- configPropertyControlIdMap = ((() => new Map())());
51
- constructor(options) {
52
- super();
53
- this.options = options;
54
- }
55
- async init(sendAction, subscribe) {
56
- this.sendAction = sendAction;
57
- subscribe(async action => {
58
- if (changeProperty.match(action)) {
59
- try {
60
- await applyChange(this.options, action.payload);
61
- } catch (exception) {
62
- let name = '';
63
- const id = action.payload.controlId || '';
64
- const control = sap.ui.getCore().byId(id);
65
- if (control) {
66
- name = control.getMetadata().getName();
67
- }
68
- const error = getError(exception);
69
- const modifiedMessage = modifyRTAErrorMessage(error.toString(), id, name);
70
- const errorMessage = modifiedMessage || `RTA Exception applying expression "${ action.payload.value }"`;
71
- await sendInfoCenterMessage({
72
- title: { key: 'CHANGE_CREATION_FAILED_TITLE' },
73
- description: errorMessage,
74
- type: MessageBarType.error
75
- });
76
- const propertyChangeFailedAction = propertyChangeFailed({
77
- ...action.payload,
78
- errorMessage
79
- });
80
- sendAction(propertyChangeFailedAction);
81
- }
82
- } else if (deletePropertyChanges.match(action)) {
83
- await this.deleteChange(action.payload.controlId, action.payload.propertyName, action.payload.fileName);
84
- } else if (reloadApplication.match(action)) {
85
- this.sendAction(setApplicationRequiresReload(false));
86
- } else if (save.match(action)) {
87
- this.changesRequiringReload = 0;
88
- this.sendAction(setApplicationRequiresReload(false));
89
- }
66
+
67
+ /**
68
+ * Initializes change service.
69
+ *
70
+ * @param sendAction action sender function
71
+ * @param subscribe subscriber function
72
+ */
73
+ async init(sendAction, subscribe) {
74
+ this.sendAction = sendAction;
75
+ subscribe(async action => {
76
+ if (changeProperty.match(action)) {
77
+ try {
78
+ await applyChange(this.options, action.payload);
79
+ } catch (exception) {
80
+ // send error information
81
+ let name = '';
82
+ const id = action.payload.controlId || '';
83
+ const control = sap.ui.getCore().byId(id);
84
+ if (control) {
85
+ name = control.getMetadata().getName();
86
+ }
87
+ const error = getError(exception);
88
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
89
+ const modifiedMessage = modifyRTAErrorMessage(error.toString(), id, name);
90
+ const errorMessage = modifiedMessage || `RTA Exception applying expression "${action.payload.value}"`;
91
+ await sendInfoCenterMessage({
92
+ title: {
93
+ key: 'CHANGE_CREATION_FAILED_TITLE'
94
+ },
95
+ description: errorMessage,
96
+ type: MessageBarType.error
90
97
  });
91
- await this.fetchSavedChanges();
92
- this.updateStack();
93
- this.options.rta.attachUndoRedoStackModified(this.createOnStackChangeHandler());
94
- }
95
- updateStack() {
96
- this.sendAction(changeStackModified({
97
- saved: this.savedChanges ?? [],
98
- pending: this.pendingChanges ?? []
99
- }));
100
- }
101
- isGenericChange(change) {
102
- return change.changeType === 'appdescr_app_addAnnotationsToOData' || change.changeType === 'rename' || change.changeType === 'moveControls' || change.changeType === 'addXML' || change.changeType === 'propertyChange' || change.changeType === 'propertyBindingChange' || change.changeType === 'appdescr_fe_changePageConfiguration' || change.changeType === 'appdescr_ui_generic_app_changePageConfiguration';
103
- }
104
- async fetchSavedChanges() {
105
- this.changedFiles = {};
106
- const savedChangesResponse = await fetch(FlexChangesEndPoints.changes + `?_=${ Date.now() }`);
107
- const savedChanges = await savedChangesResponse.json();
108
- const textBundle = await getTextBundle();
109
- const changes = (await Promise.all(Object.keys(savedChanges ?? {}).map(async key => {
110
- const change = savedChanges[key];
111
- try {
112
- const handler = GENERIC_CHANGE_HANDLER[change.changeType];
113
- if (this.isGenericChange(change)) {
114
- const {
115
- properties,
116
- changeTitle,
117
- controlId,
118
- changeType: type,
119
- subtitle
120
- } = await handler(change, {
121
- textBundle,
122
- appComponent: this.options.rta.getRootControlInstance(),
123
- configPropertyControlIdMap: this.configPropertyControlIdMap
124
- });
125
- this.changedFiles[change.fileName] = change;
126
- return {
127
- kind: GENERIC_CHANGE_KIND,
128
- type: 'saved',
129
- fileName: change.fileName,
130
- ...subtitle && { subtitle },
131
- changeType: type ?? change.changeType,
132
- timestamp: new Date(change.creation).getTime(),
133
- ...controlId && { controlId },
134
- properties,
135
- title: textBundle.getText(changeTitle)
136
- };
137
- }
138
- throw new Error('Unknown change type');
139
- } catch (error) {
140
- const flexObject = await getFlexObject(change);
141
- const selectorId = await getControlIdByChange(flexObject, this.options.rta.getRootControlInstance());
142
- if (change.fileName) {
143
- this.changedFiles[change.fileName] = change;
144
- const unknownChange = {
145
- type: 'saved',
146
- kind: 'unknown',
147
- changeType: change.changeType,
148
- fileName: change.fileName,
149
- timestamp: new Date(change.creation).getTime()
150
- };
151
- if (change.creation) {
152
- unknownChange.timestamp = new Date(change.creation).getTime();
153
- }
154
- if (selectorId) {
155
- const controlChange = {
156
- ...unknownChange,
157
- kind: 'control',
158
- controlId: selectorId
159
- };
160
- return controlChange;
161
- }
162
- return unknownChange;
163
- }
164
- return undefined;
165
- }
166
- }))).filter(change => !!change).sort((a, b) => b.timestamp - a.timestamp);
167
- this.savedChanges = changes;
168
- }
169
- async deleteChange(controlId, propertyName, fileName) {
170
- const filesToDelete = this.savedChanges.filter(change => {
171
- if (fileName) {
172
- return fileName === change.fileName;
173
- }
174
- if (change.kind === 'control') {
175
- return change.controlId === controlId;
176
- }
177
- return false;
178
- }).map(change => fetch(FlexChangesEndPoints.changes, {
179
- method: 'DELETE',
180
- headers: { 'Content-Type': 'application/json' },
181
- body: JSON.stringify({ fileName: change.fileName })
182
- }));
183
- await Promise.all(filesToDelete).catch(error => Log.error(getError(error).message));
184
- await this.fetchSavedChanges();
185
- this.updateStack();
98
+ const propertyChangeFailedAction = propertyChangeFailed({
99
+ ...action.payload,
100
+ errorMessage
101
+ });
102
+ sendAction(propertyChangeFailedAction);
103
+ }
104
+ } else if (deletePropertyChanges.match(action)) {
105
+ await this.deleteChange(action.payload.controlId, action.payload.propertyName, action.payload.fileName);
106
+ } else if (reloadApplication.match(action)) {
107
+ this.sendAction(setApplicationRequiresReload(false));
108
+ } else if (save.match(action)) {
109
+ this.changesRequiringReload = 0;
110
+ this.sendAction(setApplicationRequiresReload(false));
186
111
  }
187
- createOnStackChangeHandler() {
188
- const handleStackChange = modeAndStackChangeHandler(this.sendAction, this.options.rta);
189
- return async event => {
190
- const pendingChanges = [];
191
- this.eventStack.push(event);
192
- const stack = this.options.rta.getCommandStack();
193
- const allCommands = stack.getCommands();
194
- const executedCommands = stack.getAllExecutedCommands();
195
- const allCommandsFlattened = allCommands.flatMap(command => typeof command.getCommands === 'function' ? command.getCommands() : [command]);
196
- const activeCommandCount = allCommandsFlattened.length - executedCommands.length;
197
- this.pendingConfigChangeMap = new Map();
198
- let i = 0;
199
- for (const command of allCommands) {
200
- try {
201
- if (typeof command.getCommands === 'function') {
202
- const subCommands = command.getCommands();
203
- for (const subCommand of subCommands) {
204
- await this.handleCommand(subCommand, activeCommandCount, i, pendingChanges);
205
- i++;
206
- }
207
- } else {
208
- await this.handleCommand(command, activeCommandCount, i, pendingChanges);
209
- i++;
210
- }
211
- } catch (error) {
212
- Log.error('CPE: Change creation Failed', getError(error));
213
- }
214
- }
215
- const eventIndex = this.eventStack.indexOf(event);
216
- if (this.eventStack.length - 1 === eventIndex) {
217
- this.pendingChanges = pendingChanges.filter(change => !!change);
218
- const changesRequiringReload = this.pendingChanges.reduce((sum, change) => isGenericConfigChange(change) ? sum + 1 : sum, 0);
219
- if (changesRequiringReload > this.changesRequiringReload) {
220
- await sendInfoCenterMessage({
221
- title: { key: 'CHANGES_VISIBLE_AFTER_SAVE_AND_RELOAD_TITLE' },
222
- description: { key: 'CHANGES_VISIBLE_AFTER_SAVE_AND_RELOAD_DESCRIPTION' },
223
- type: MessageBarType.info
224
- });
225
- this.sendAction(setApplicationRequiresReload(changesRequiringReload > 0));
226
- }
227
- this.changesRequiringReload = changesRequiringReload;
228
- }
229
- this.eventStack.splice(eventIndex, 1);
230
- if (Array.isArray(allCommands) && allCommands.length === 0) {
231
- this.pendingChanges = [];
232
- this.pendingConfigChangeMap = new Map();
233
- await this.fetchSavedChanges();
234
- }
235
- const configurationChanges = this.pendingChanges?.filter(isGenericConfigChange);
236
- if (configurationChanges.length) {
237
- const stackChangeEvent = new CustomEvent(STACK_CHANGE_EVENT, {
238
- detail: {
239
- controls: configurationChanges.reduce((acc, item) => {
240
- const controls = [...item.controlId ?? []].map(id => {
241
- return getControlById(id);
242
- }).filter(ui5Element => isA('sap.ui.core.Element', ui5Element));
243
- acc.push(...controls);
244
- return acc;
245
- }, [])
246
- }
247
- });
248
- this.dispatchEvent(stackChangeEvent);
249
- }
250
- this.updateStack();
251
- handleStackChange();
112
+ });
113
+ await this.fetchSavedChanges();
114
+ this.updateStack();
115
+ this.options.rta.attachUndoRedoStackModified(this.createOnStackChangeHandler());
116
+ }
117
+
118
+ /**
119
+ * Send update to the editor with modified stack.
120
+ *
121
+ * @param pendingChanges Changes that are waiting to be saved
122
+ */
123
+ updateStack() {
124
+ this.sendAction(changeStackModified({
125
+ saved: this.savedChanges ?? [],
126
+ pending: this.pendingChanges ?? []
127
+ }));
128
+ }
129
+ isGenericChange(change) {
130
+ return change.changeType === 'appdescr_app_addAnnotationsToOData' || change.changeType === 'rename' || change.changeType === 'moveControls' || change.changeType === 'addXML' || change.changeType === 'propertyChange' || change.changeType === 'propertyBindingChange' || change.changeType === 'appdescr_fe_changePageConfiguration' || change.changeType === 'appdescr_ui_generic_app_changePageConfiguration';
131
+ }
132
+
133
+ /**
134
+ * Fetches saved changes from the workspace and sorts them.
135
+ */
136
+ async fetchSavedChanges() {
137
+ this.changedFiles = {};
138
+ const savedChangesResponse = await fetch(FlexChangesEndPoints.changes + `?_=${Date.now()}`);
139
+ const savedChanges = await savedChangesResponse.json();
140
+ const textBundle = await getTextBundle();
141
+ const changes = (await Promise.all(Object.keys(savedChanges ?? {}).map(async key => {
142
+ const change = savedChanges[key];
143
+ try {
144
+ const handler = GENERIC_CHANGE_HANDLER[change.changeType];
145
+ if (this.isGenericChange(change)) {
146
+ const {
147
+ properties,
148
+ changeTitle,
149
+ controlId,
150
+ changeType: type,
151
+ subtitle
152
+ } = await handler(change, {
153
+ textBundle,
154
+ appComponent: this.options.rta.getRootControlInstance(),
155
+ configPropertyControlIdMap: this.configPropertyControlIdMap
156
+ });
157
+ this.changedFiles[change.fileName] = change;
158
+ return {
159
+ kind: GENERIC_CHANGE_KIND,
160
+ type: 'saved',
161
+ fileName: change.fileName,
162
+ ...(subtitle && {
163
+ subtitle
164
+ }),
165
+ changeType: type ?? change.changeType,
166
+ timestamp: new Date(change.creation).getTime(),
167
+ ...(controlId && {
168
+ controlId
169
+ }),
170
+ properties,
171
+ title: textBundle.getText(changeTitle)
252
172
  };
173
+ }
174
+ throw new Error('Unknown change type');
175
+ } catch (error) {
176
+ // Gracefully handle change files with invalid content
177
+ const flexObject = await getFlexObject(change);
178
+ const selectorId = await getControlIdByChange(flexObject, this.options.rta.getRootControlInstance());
179
+ if (change.fileName) {
180
+ this.changedFiles[change.fileName] = change;
181
+ const unknownChange = {
182
+ type: 'saved',
183
+ kind: 'unknown',
184
+ changeType: change.changeType,
185
+ fileName: change.fileName,
186
+ timestamp: new Date(change.creation).getTime()
187
+ };
188
+ if (change.creation) {
189
+ unknownChange.timestamp = new Date(change.creation).getTime();
190
+ }
191
+ if (selectorId) {
192
+ const controlChange = {
193
+ ...unknownChange,
194
+ kind: 'control',
195
+ controlId: selectorId
196
+ };
197
+ return controlChange;
198
+ }
199
+ return unknownChange;
200
+ }
201
+ return undefined;
253
202
  }
254
- getConfigurationPropertyValue(controlId, propertyName) {
255
- const pendingChanges = this.pendingConfigChangeMap?.get(controlId);
256
- return (pendingChanges || []).find(item => item.isActive && item.properties[0].label === propertyName)?.properties[0].value;
203
+ }))).filter(change => !!change).sort((a, b) => b.timestamp - a.timestamp);
204
+ this.savedChanges = changes;
205
+ }
206
+
207
+ /**
208
+ *
209
+ * @param controlId unique identifier for a control
210
+ * @param propertyName name of the property change to be deleted
211
+ * @param fileName name of the file.
212
+ */
213
+ async deleteChange(controlId, propertyName, fileName) {
214
+ const filesToDelete = this.savedChanges.filter(change => {
215
+ if (fileName) {
216
+ return fileName === change.fileName;
257
217
  }
258
- async updateConfigurationProps(configPropertyControlIdMap) {
259
- this.configPropertyControlIdMap = configPropertyControlIdMap;
260
- await this.fetchSavedChanges();
261
- this.updateStack();
218
+ if (change.kind === 'control') {
219
+ return change.controlId === controlId;
262
220
  }
263
- async handleCommand(command, inactiveCommandCount, index, pendingChanges) {
264
- setAdditionalChangeInfo(command?.getPreparedChange?.());
265
- const pendingChange = await this.prepareChangeType(command, inactiveCommandCount, index);
266
- if (pendingChange) {
267
- pendingChanges.push(pendingChange);
221
+ return false;
222
+ }).map(change => fetch(FlexChangesEndPoints.changes, {
223
+ method: 'DELETE',
224
+ headers: {
225
+ 'Content-Type': 'application/json'
226
+ },
227
+ body: JSON.stringify({
228
+ fileName: change.fileName
229
+ })
230
+ }));
231
+ await Promise.all(filesToDelete).catch(error => Log.error(getError(error).message));
232
+ await this.fetchSavedChanges();
233
+ this.updateStack();
234
+ }
235
+
236
+ /**
237
+ * Handler for undo/redo stack change.
238
+ *
239
+ * @param sendAction send action method
240
+ * @returns (event: sap.ui.base.Event) => Promise<void>
241
+ */
242
+ createOnStackChangeHandler() {
243
+ const handleStackChange = modeAndStackChangeHandler(this.sendAction, this.options.rta);
244
+ return async event => {
245
+ const pendingChanges = [];
246
+ this.eventStack.push(event);
247
+ const stack = this.options.rta.getCommandStack();
248
+ const allCommands = stack.getCommands();
249
+ const executedCommands = stack.getAllExecutedCommands();
250
+ const allCommandsFlattened = allCommands.flatMap(command => typeof command.getCommands === 'function' ? command.getCommands() : [command]);
251
+ const activeCommandCount = allCommandsFlattened.length - executedCommands.length;
252
+ this.pendingConfigChangeMap = new Map();
253
+ let i = 0;
254
+ for (const command of allCommands) {
255
+ try {
256
+ if (typeof command.getCommands === 'function') {
257
+ const subCommands = command.getCommands();
258
+ for (const subCommand of subCommands) {
259
+ await this.handleCommand(subCommand, activeCommandCount, i, pendingChanges);
260
+ i++;
261
+ }
262
+ } else {
263
+ await this.handleCommand(command, activeCommandCount, i, pendingChanges);
264
+ i++;
268
265
  }
266
+ } catch (error) {
267
+ Log.error('CPE: Change creation Failed', getError(error));
268
+ }
269
269
  }
270
- trackPendingConfigChanges(result) {
271
- for (const id of result?.controlId ?? []) {
272
- if (!this.pendingConfigChangeMap.get(id)) {
273
- this.pendingConfigChangeMap.set(id, []);
274
- }
275
- const pendingChanges = this.pendingConfigChangeMap.get(id);
276
- pendingChanges?.push(result);
277
- }
270
+ const eventIndex = this.eventStack.indexOf(event);
271
+ if (this.eventStack.length - 1 === eventIndex) {
272
+ this.pendingChanges = pendingChanges.filter(change => !!change);
273
+ const changesRequiringReload = this.pendingChanges.reduce((sum, change) => isGenericConfigChange(change) ? sum + 1 : sum, 0);
274
+ if (changesRequiringReload > this.changesRequiringReload) {
275
+ await sendInfoCenterMessage({
276
+ title: {
277
+ key: 'CHANGES_VISIBLE_AFTER_SAVE_AND_RELOAD_TITLE'
278
+ },
279
+ description: {
280
+ key: 'CHANGES_VISIBLE_AFTER_SAVE_AND_RELOAD_DESCRIPTION'
281
+ },
282
+ type: MessageBarType.info
283
+ });
284
+ this.sendAction(setApplicationRequiresReload(changesRequiringReload > 0));
285
+ }
286
+ this.changesRequiringReload = changesRequiringReload;
278
287
  }
279
- async prepareChangeType(command, inactiveCommandCount, index) {
280
- const change = command?.getPreparedChange?.();
281
- const textBundle = await getTextBundle();
282
- const selectorId = typeof change?.getSelector === 'function' ? await getControlIdByChange(change, this.options.rta.getRootControlInstance()) : this.getCommandSelectorId(command);
283
- const changeType = this.getCommandChangeType(command);
284
- if (!changeType) {
285
- return undefined;
286
- }
287
- const changeDefinition = change.getDefinition ? change.getDefinition() : change.getJson();
288
- const {fileName} = changeDefinition;
289
- const handler = GENERIC_CHANGE_HANDLER[changeType];
290
- if (handler) {
291
- const {
292
- properties,
293
- changeTitle,
294
- controlId,
295
- changeType: type,
296
- subtitle
297
- } = await handler(changeDefinition, {
298
- textBundle,
299
- appComponent: this.options.rta.getRootControlInstance(),
300
- configPropertyControlIdMap: this.configPropertyControlIdMap
301
- });
302
- const genericChange = {
303
- kind: GENERIC_CHANGE_KIND,
304
- type: 'pending',
305
- changeType: type ?? changeType,
306
- ...subtitle && { subtitle },
307
- isActive: index >= inactiveCommandCount,
308
- title: textBundle.getText(changeTitle),
309
- fileName,
310
- ...controlId && { controlId },
311
- properties
312
- };
313
- if (changeType === 'appdescr_fe_changePageConfiguration') {
314
- this.trackPendingConfigChanges(genericChange);
315
- }
316
- return genericChange;
317
- } else {
318
- const title = TITLE_MAP[changeType] ?? '';
319
- let result = {
320
- type: PENDING_CHANGE_TYPE,
321
- kind: UNKNOWN_CHANGE_KIND,
322
- ...title && { title },
323
- changeType,
324
- isActive: index >= inactiveCommandCount,
325
- fileName
326
- };
327
- if (selectorId) {
328
- result = {
329
- ...result,
330
- kind: 'control',
331
- controlId: selectorId
332
- };
333
- }
334
- return result;
335
- }
288
+ this.eventStack.splice(eventIndex, 1);
289
+ if (Array.isArray(allCommands) && allCommands.length === 0) {
290
+ this.pendingChanges = [];
291
+ this.pendingConfigChangeMap = new Map();
292
+ await this.fetchSavedChanges();
336
293
  }
337
- retryOperations(operations) {
338
- for (const operation of operations) {
339
- try {
340
- const result = operation();
341
- if (!result) {
342
- continue;
343
- }
344
- return result;
345
- } catch (error) {
346
- continue;
347
- }
294
+
295
+ // Notify to update the ui for configuration changes.
296
+ const configurationChanges = this.pendingChanges?.filter(isGenericConfigChange);
297
+ if (configurationChanges.length) {
298
+ const stackChangeEvent = new CustomEvent(STACK_CHANGE_EVENT, {
299
+ detail: {
300
+ controls: configurationChanges.reduce((acc, item) => {
301
+ const controls = [...(item.controlId ?? [])].map(id => {
302
+ return getControlById(id);
303
+ }).filter(ui5Element => isA('sap.ui.core.Element', ui5Element));
304
+ acc.push(...controls);
305
+ return acc;
306
+ }, [])
348
307
  }
349
- Log.error('All retry operations failed');
350
- return undefined;
308
+ });
309
+ this.dispatchEvent(stackChangeEvent);
310
+ }
311
+ this.updateStack();
312
+ handleStackChange();
313
+ };
314
+ }
315
+ /**
316
+ * Cached configuration commands to set reset value during stack change event.
317
+ *
318
+ * @param controlId - control id of the config property.
319
+ * @param propertyName - config property name.
320
+ * @returns Configuration property value.
321
+ */
322
+ getConfigurationPropertyValue(controlId, propertyName) {
323
+ const pendingChanges = this.pendingConfigChangeMap?.get(controlId);
324
+ return (pendingChanges || []).find(item => item.isActive && item.properties[0].label === propertyName)?.properties[0].value;
325
+ }
326
+
327
+ /**
328
+ * Update config changes with associated controls.
329
+ *
330
+ * @param {Map<string, string[]>} configPropertyControlIdMap - config property path control id map.
331
+ */
332
+ async updateConfigurationProps(configPropertyControlIdMap) {
333
+ this.configPropertyControlIdMap = configPropertyControlIdMap;
334
+ await this.fetchSavedChanges();
335
+ this.updateStack();
336
+ }
337
+
338
+ /**
339
+ * Handles a command by preparing a pending change and adding it to the list of pending changes.
340
+ *
341
+ * @param {FlexCommand} command - The command to process.
342
+ * @param {number} inactiveCommandCount - The number of inactive commands.
343
+ * @param {number} index - The index of the current command being processed.
344
+ * @param {PendingChange[]} pendingChanges - The list of pending changes to update.
345
+ * @returns {Promise<void>} A promise that resolves when the command is handled.
346
+ */
347
+ async handleCommand(command, inactiveCommandCount, index, pendingChanges) {
348
+ setAdditionalChangeInfo(command?.getPreparedChange?.());
349
+ const pendingChange = await this.prepareChangeType(command, inactiveCommandCount, index);
350
+ if (pendingChange) {
351
+ pendingChanges.push(pendingChange);
352
+ }
353
+ }
354
+ trackPendingConfigChanges(result) {
355
+ for (const id of result?.controlId ?? []) {
356
+ if (!this.pendingConfigChangeMap.get(id)) {
357
+ this.pendingConfigChangeMap.set(id, []);
351
358
  }
352
- getCommandChangeType(command) {
353
- return this.retryOperations([
354
- () => command.getChangeType(),
355
- () => command.getPreparedChange().getDefinition().changeType
356
- ]);
359
+ const pendingChanges = this.pendingConfigChangeMap.get(id);
360
+ pendingChanges?.push(result);
361
+ }
362
+ }
363
+
364
+ /**
365
+ * Prepares the type of change based on the command and other parameters.
366
+ *
367
+ * @param {FlexCommand} command - The command to process.
368
+ * @param {number} inactiveCommandCount - The number of inactive commands.
369
+ * @param {number} index - The index of the current command being processed.
370
+ * @returns {Promise<PendingChange | undefined>} - A promise that resolves to a `PendingChange` or `undefined`.
371
+ */
372
+ async prepareChangeType(command, inactiveCommandCount, index) {
373
+ const change = command?.getPreparedChange?.();
374
+ const textBundle = await getTextBundle();
375
+ const selectorId = typeof change?.getSelector === 'function' ? await getControlIdByChange(change, this.options.rta.getRootControlInstance()) : this.getCommandSelectorId(command);
376
+ const changeType = this.getCommandChangeType(command);
377
+ if (!changeType) {
378
+ return undefined;
379
+ }
380
+ const changeDefinition = change.getDefinition ? change.getDefinition() : change.getJson();
381
+ const {
382
+ fileName
383
+ } = changeDefinition;
384
+ const handler = GENERIC_CHANGE_HANDLER[changeType];
385
+ if (handler) {
386
+ const {
387
+ properties,
388
+ changeTitle,
389
+ controlId,
390
+ changeType: type,
391
+ subtitle
392
+ } = await handler(changeDefinition, {
393
+ textBundle,
394
+ appComponent: this.options.rta.getRootControlInstance(),
395
+ configPropertyControlIdMap: this.configPropertyControlIdMap
396
+ });
397
+ const genericChange = {
398
+ kind: GENERIC_CHANGE_KIND,
399
+ type: 'pending',
400
+ changeType: type ?? changeType,
401
+ ...(subtitle && {
402
+ subtitle
403
+ }),
404
+ isActive: index >= inactiveCommandCount,
405
+ title: textBundle.getText(changeTitle),
406
+ fileName,
407
+ ...(controlId && {
408
+ controlId
409
+ }),
410
+ properties
411
+ };
412
+ if (changeType === 'appdescr_fe_changePageConfiguration') {
413
+ this.trackPendingConfigChanges(genericChange);
357
414
  }
358
- getCommandSelectorId(command) {
359
- return this.retryOperations([
360
- () => command.getSelector().id,
361
- () => command.getElement().getProperty('persistencyKey'),
362
- () => command.getElement().getId(),
363
- () => command.getParent()?.getElement().getId()
364
- ]);
415
+ return genericChange;
416
+ } else {
417
+ const title = TITLE_MAP[changeType] ?? '';
418
+ let result = {
419
+ type: PENDING_CHANGE_TYPE,
420
+ kind: UNKNOWN_CHANGE_KIND,
421
+ ...(title && {
422
+ title
423
+ }),
424
+ changeType,
425
+ isActive: index >= inactiveCommandCount,
426
+ fileName
427
+ };
428
+ if (selectorId) {
429
+ result = {
430
+ ...result,
431
+ kind: 'control',
432
+ controlId: selectorId
433
+ };
365
434
  }
366
- async syncOutlineChanges() {
367
- for (const change of this.savedChanges) {
368
- if (change.kind !== 'unknown' && change.changeType !== 'configuration') {
369
- const flexObject = await getFlexObject(this.changedFiles[change.fileName]);
370
- change.controlId = await getControlIdByChange(flexObject, this.options.rta.getRootControlInstance()) ?? '';
371
- }
372
- }
373
- this.updateStack();
435
+ return result;
436
+ }
437
+ }
438
+
439
+ /**
440
+ * Retry operations.
441
+ *
442
+ * @param operations to be executed
443
+ * @returns first successfull operation result or undefined
444
+ */
445
+ retryOperations(operations) {
446
+ for (const operation of operations) {
447
+ try {
448
+ const result = operation();
449
+ if (!result) {
450
+ continue;
451
+ }
452
+ return result;
453
+ } catch (error) {
454
+ continue;
374
455
  }
375
- onStackChange(handler) {
376
- this.addEventListener(STACK_CHANGE_EVENT, handler);
456
+ }
457
+ Log.error('All retry operations failed');
458
+ return undefined;
459
+ }
460
+
461
+ /**
462
+ * Get command change type.
463
+ *
464
+ * @param command to be executed for creating change
465
+ * @returns command change type or undefined
466
+ */
467
+ getCommandChangeType(command) {
468
+ return this.retryOperations([() => command.getChangeType(), () => command.getPreparedChange().getDefinition().changeType]);
469
+ }
470
+
471
+ /**
472
+ * Get command selector id.
473
+ *
474
+ * @param command to be executed for creating change
475
+ * @returns command selector id or undefined
476
+ */
477
+ getCommandSelectorId(command) {
478
+ return this.retryOperations([() => command.getSelector().id,
479
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
480
+ () => command.getElement().getProperty('persistencyKey'), () => command.getElement().getId(), () => command.getParent()?.getElement().getId()]);
481
+ }
482
+
483
+ /**
484
+ * Sync outline changes to place modification markers when outline is changed.
485
+ *
486
+ * @returns void
487
+ */
488
+ async syncOutlineChanges() {
489
+ for (const change of this.savedChanges) {
490
+ if (change.kind !== 'unknown' && change.changeType !== 'configuration') {
491
+ const flexObject = await getFlexObject(this.changedFiles[change.fileName]);
492
+ change.controlId = (await getControlIdByChange(flexObject, this.options.rta.getRootControlInstance())) ?? '';
377
493
  }
494
+ }
495
+ this.updateStack();
378
496
  }
379
- function isGenericConfigChange(change) {
380
- return change.kind === GENERIC_CHANGE_KIND && change.changeType === 'configuration';
497
+ onStackChange(handler) {
498
+ this.addEventListener(STACK_CHANGE_EVENT, handler);
381
499
  }
382
- var __exports = { __esModule: true };
383
- __exports.STACK_CHANGE_EVENT = STACK_CHANGE_EVENT;
384
- __exports.ChangeService = ChangeService;
385
- return __exports;
386
- });
500
+ }
501
+ function isGenericConfigChange(change) {
502
+ return change.kind === GENERIC_CHANGE_KIND && change.changeType === 'configuration';
503
+ }
504
+ var __exports = {
505
+ __esModule: true
506
+ };
507
+ __exports.STACK_CHANGE_EVENT = STACK_CHANGE_EVENT;
508
+ __exports.ChangeService = ChangeService;
509
+ return __exports;
510
+ });
511
+ //# sourceMappingURL=service.js.map