@sap-ux/preview-middleware 0.20.1 → 0.20.2

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 (26) hide show
  1. package/dist/client/adp/command-executor.js +2 -2
  2. package/dist/client/adp/command-executor.ts +4 -4
  3. package/dist/client/adp/controllers/AddFragment.controller.js +1 -1
  4. package/dist/client/adp/controllers/AddFragment.controller.ts +2 -2
  5. package/dist/client/adp/controllers/AddTableColumnFragments.controller.js +1 -1
  6. package/dist/client/adp/controllers/AddTableColumnFragments.controller.ts +2 -2
  7. package/dist/client/adp/controllers/BaseDialog.controller.js +2 -13
  8. package/dist/client/adp/controllers/BaseDialog.controller.ts +7 -25
  9. package/dist/client/adp/controllers/ControllerExtension.controller.js +73 -15
  10. package/dist/client/adp/controllers/ControllerExtension.controller.ts +110 -22
  11. package/dist/client/adp/dialog-factory.js +1 -1
  12. package/dist/client/adp/dialog-factory.ts +3 -1
  13. package/dist/client/adp/extend-controller.js +48 -0
  14. package/dist/client/adp/extend-controller.ts +49 -0
  15. package/dist/client/adp/init-dialogs.js +15 -35
  16. package/dist/client/adp/init-dialogs.ts +42 -20
  17. package/dist/client/adp/init.js +9 -1
  18. package/dist/client/adp/init.ts +6 -1
  19. package/dist/client/adp/quick-actions/common/add-controller-to-page.js +16 -2
  20. package/dist/client/adp/quick-actions/common/add-controller-to-page.ts +25 -3
  21. package/dist/client/adp/ui/ControllerExtension.fragment.xml +14 -3
  22. package/dist/client/adp/utils.js +49 -8
  23. package/dist/client/adp/utils.ts +55 -7
  24. package/dist/client/cpe/connector-service.ts +1 -0
  25. package/dist/client/messagebundle.properties +5 -0
  26. package/package.json +5 -5
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ sap.ui.define(["sap/ui/rta/command/CommandFactory", "./utils", "./dialog-factory", "sap/ui/rta/plugin/ExtendControllerPlugin"], function (CommandFactory, ___utils, ___dialog_factory, ExtendController) {
4
+ "use strict";
5
+
6
+ const createDeferred = ___utils["createDeferred"];
7
+ const DialogFactory = ___dialog_factory["DialogFactory"];
8
+ const DialogNames = ___dialog_factory["DialogNames"];
9
+ /**
10
+ * Initializes the ExtendControllerPlugin and includes it in the Runtime Authoring (RTA) plugins.
11
+ *
12
+ * @param rta Runtime Authoring instance
13
+ */
14
+ function initExtendControllerPlugin(rta) {
15
+ const flexSettings = rta.getFlexSettings();
16
+ const commandFactory = new CommandFactory({
17
+ flexSettings
18
+ });
19
+ const plugin = new ExtendController({
20
+ commandFactory,
21
+ handlerFunction: async overlay => await handlerFunction(rta, overlay)
22
+ });
23
+ const plugins = rta.getPlugins();
24
+ plugins.extendControllerPlugin = plugin;
25
+ rta.setPlugins(plugins);
26
+ }
27
+
28
+ /**
29
+ * Handles the creation of a controller extension by opening a dialog and resolving the deferred data.
30
+ *
31
+ * @param rta Runtime Authoring instance
32
+ * @param overlay UI5 Element overlay
33
+ * @returns A promise that resolves with DeferredXmlFragmentData
34
+ */
35
+ async function handlerFunction(rta, overlay) {
36
+ const deferred = createDeferred();
37
+ await DialogFactory.createDialog(overlay, rta, DialogNames.CONTROLLER_EXTENSION, {
38
+ deferred
39
+ });
40
+ return deferred.promise;
41
+ }
42
+ var __exports = {
43
+ __esModule: true
44
+ };
45
+ __exports.initExtendControllerPlugin = initExtendControllerPlugin;
46
+ return __exports;
47
+ });
48
+ //# sourceMappingURL=extend-controller.js.map
@@ -0,0 +1,49 @@
1
+ import type RuntimeAuthoring from 'sap/ui/rta/RuntimeAuthoring';
2
+ import type UI5Element from 'sap/ui/core/Element';
3
+ import CommandFactory from 'sap/ui/rta/command/CommandFactory';
4
+ import { Deferred, createDeferred } from './utils';
5
+ import { DialogFactory, DialogNames } from './dialog-factory';
6
+ import ExtendController from 'sap/ui/rta/plugin/ExtendControllerPlugin';
7
+
8
+ export interface ExtendControllerData {
9
+ deferred: Deferred<DeferredExtendControllerData>;
10
+ }
11
+
12
+ export type DeferredExtendControllerData = {
13
+ codeRef: string;
14
+ viewId: string;
15
+ };
16
+
17
+ /**
18
+ * Initializes the ExtendControllerPlugin and includes it in the Runtime Authoring (RTA) plugins.
19
+ *
20
+ * @param rta Runtime Authoring instance
21
+ */
22
+ export function initExtendControllerPlugin(rta: RuntimeAuthoring): void {
23
+ const flexSettings = rta.getFlexSettings();
24
+ const commandFactory = new CommandFactory({ flexSettings });
25
+
26
+ const plugin = new ExtendController({
27
+ commandFactory,
28
+ handlerFunction: async (overlay: UI5Element) => await handlerFunction(rta, overlay)
29
+ });
30
+
31
+ const plugins = rta.getPlugins();
32
+ plugins.extendControllerPlugin = plugin;
33
+ rta.setPlugins(plugins);
34
+ }
35
+
36
+ /**
37
+ * Handles the creation of a controller extension by opening a dialog and resolving the deferred data.
38
+ *
39
+ * @param rta Runtime Authoring instance
40
+ * @param overlay UI5 Element overlay
41
+ * @returns A promise that resolves with DeferredXmlFragmentData
42
+ */
43
+ async function handlerFunction(rta: RuntimeAuthoring, overlay: UI5Element): Promise<DeferredExtendControllerData> {
44
+ const deferred = createDeferred<DeferredExtendControllerData>();
45
+
46
+ await DialogFactory.createDialog(overlay, rta, DialogNames.CONTROLLER_EXTENSION, { deferred });
47
+
48
+ return deferred.promise;
49
+ }
@@ -1,30 +1,12 @@
1
1
  "use strict";
2
2
 
3
- sap.ui.define(["sap/ui/rta/util/hasStableId", "sap/ui/fl/Utils", "./dialog-factory", "../i18n", "./utils", "../utils/version"], function (hasStableId, FlUtils, ___dialog_factory, ___i18n, ___utils, ___utils_version) {
3
+ sap.ui.define(["sap/ui/rta/util/hasStableId", "sap/ui/fl/Utils", "./dialog-factory", "../i18n", "./utils"], function (hasStableId, FlUtils, ___dialog_factory, ___i18n, ___utils) {
4
4
  "use strict";
5
5
 
6
- function __ui5_require_async(path) {
7
- return new Promise(function (resolve, reject) {
8
- sap.ui.require([path], function (module) {
9
- if (!(module && module.__esModule)) {
10
- module = module === null || !(typeof module === "object" && path.endsWith("/library")) ? {
11
- default: module
12
- } : module;
13
- Object.defineProperty(module, "__esModule", {
14
- value: true
15
- });
16
- }
17
- resolve(module);
18
- }, function (err) {
19
- reject(err);
20
- });
21
- });
22
- }
23
6
  const DialogFactory = ___dialog_factory["DialogFactory"];
24
7
  const DialogNames = ___dialog_factory["DialogNames"];
25
8
  const getTextBundle = ___i18n["getTextBundle"];
26
9
  const getReuseComponentChecker = ___utils["getReuseComponentChecker"];
27
- const isLowerThanMinimalUi5Version = ___utils_version["isLowerThanMinimalUi5Version"];
28
10
  /**
29
11
  * Handler for enablement of Extend With Controller context menu entry
30
12
  *
@@ -105,12 +87,17 @@ sap.ui.define(["sap/ui/rta/util/hasStableId", "sap/ui/fl/Utils", "./dialog-facto
105
87
  * Determines the text that should be displayed for Controller Extension context menu item.
106
88
  *
107
89
  * @param {ElementOverlay} overlay - An ElementOverlay object representing the UI overlay.
90
+ * @param {string[]} syncViewsIds - Array of IDs of all application sync views.
108
91
  * @param {isReuseComponentApi} isReuseComponentChecker - Function to check if the control is a reuse component.
109
92
  * @param {boolean} isCloud - Whether the application is running in the cloud.
110
93
  * @param {TextBundle} resources - The text bundle.
111
94
  * @returns {string} The text of the Add Fragment context menu item.
112
95
  */
113
- const getExtendControllerItemText = (overlay, isReuseComponentChecker, isCloud, resources) => {
96
+ const getExtendControllerItemText = (overlay, syncViewsIds, isReuseComponentChecker, isCloud, resources) => {
97
+ const viewId = FlUtils.getViewForControl(overlay.getElement()).getId();
98
+ if (syncViewsIds.includes(viewId)) {
99
+ return resources.getText('ADP_ADD_CONTROLLER_EXTENSION_MENU_ITEM_SYNC_VIEW');
100
+ }
114
101
  if (isCloud && isReuseComponentChecker(overlay.getElement().getId())) {
115
102
  return resources.getText('ADP_ADD_CONTROLLER_EXTENSION_MENU_ITEM_REUSE_COMPONENT');
116
103
  }
@@ -129,23 +116,16 @@ sap.ui.define(["sap/ui/rta/util/hasStableId", "sap/ui/fl/Utils", "./dialog-facto
129
116
  const isCloud = rta.getFlexSettings().isCloud;
130
117
  const resources = await getTextBundle();
131
118
  const isReuseComponentChecker = await getReuseComponentChecker(ui5VersionInfo);
132
- if (isLowerThanMinimalUi5Version(ui5VersionInfo, {
133
- major: 1,
134
- minor: 136
135
- })) {
136
- contextMenu.addMenuItem({
137
- id: 'ADD_FRAGMENT',
138
- text: overlay => getAddFragmentItemText(overlay, isReuseComponentChecker, isCloud, resources),
139
- handler: async overlays => await DialogFactory.createDialog(overlays[0], rta, DialogNames.ADD_FRAGMENT),
140
- icon: 'sap-icon://attachment-html',
141
- enabled: overlays => isFragmentCommandEnabled(overlays, isReuseComponentChecker, isCloud)
142
- });
143
- } else {
144
- (await __ui5_require_async('open/ux/preview/client/adp/add-fragment')).initAddXMLPlugin(rta);
145
- }
119
+ contextMenu.addMenuItem({
120
+ id: 'ADD_FRAGMENT',
121
+ text: overlay => getAddFragmentItemText(overlay, isReuseComponentChecker, isCloud, resources),
122
+ handler: async overlays => await DialogFactory.createDialog(overlays[0], rta, DialogNames.ADD_FRAGMENT),
123
+ icon: 'sap-icon://attachment-html',
124
+ enabled: overlays => isFragmentCommandEnabled(overlays, isReuseComponentChecker, isCloud)
125
+ });
146
126
  contextMenu.addMenuItem({
147
127
  id: 'EXTEND_CONTROLLER',
148
- text: overlay => getExtendControllerItemText(overlay, isReuseComponentChecker, isCloud, resources),
128
+ text: overlay => getExtendControllerItemText(overlay, syncViewsIds, isReuseComponentChecker, isCloud, resources),
149
129
  handler: async overlays => await DialogFactory.createDialog(overlays[0], rta, DialogNames.CONTROLLER_EXTENSION),
150
130
  icon: 'sap-icon://create-form',
151
131
  enabled: overlays => isControllerExtensionEnabled(overlays, syncViewsIds, isReuseComponentChecker, isCloud)
@@ -17,7 +17,6 @@ import type { IsReuseComponentApi } from '../cpe/types';
17
17
  import { getTextBundle, type TextBundle } from '../i18n';
18
18
  import { getReuseComponentChecker } from './utils';
19
19
  import type { Ui5VersionInfo } from '../utils/version';
20
- import { isLowerThanMinimalUi5Version } from '../utils/version';
21
20
 
22
21
  /**
23
22
  * Handler for enablement of Extend With Controller context menu entry
@@ -38,7 +37,7 @@ export function isControllerExtensionEnabledForControl(
38
37
  const viewId = FlUtils.getViewForControl(control).getId();
39
38
  const isControlInSyncView = syncViewsIds.includes(viewId);
40
39
 
41
- if(isCloud) {
40
+ if (isCloud) {
42
41
  const isClickedControlReuseComponent = isReuseComponent(control.getId());
43
42
  return !isControlInSyncView && !isClickedControlReuseComponent;
44
43
  }
@@ -75,7 +74,11 @@ export const isControllerExtensionEnabled = (
75
74
  * @param {boolean} isCloud - Whether the application is running in the cloud.
76
75
  * @returns {boolean} True if the fragment command is enabled, false otherwise.
77
76
  */
78
- export const isFragmentCommandEnabled = (overlays: ElementOverlay[], isReuseComponent: IsReuseComponentApi, isCloud: boolean): boolean => {
77
+ export const isFragmentCommandEnabled = (
78
+ overlays: ElementOverlay[],
79
+ isReuseComponent: IsReuseComponentApi,
80
+ isCloud: boolean
81
+ ): boolean => {
79
82
  if (overlays.length === 0 || overlays.length > 1) {
80
83
  return false;
81
84
  }
@@ -98,7 +101,12 @@ export const isFragmentCommandEnabled = (overlays: ElementOverlay[], isReuseComp
98
101
  * @param {TextBundle} resources - The text bundle.
99
102
  * @returns {string} The text of the Add Fragment context menu item.
100
103
  */
101
- export const getAddFragmentItemText = (overlay: ElementOverlay, isReuseComponentChecker: IsReuseComponentApi, isCloud: boolean, resources: TextBundle) => {
104
+ export const getAddFragmentItemText = (
105
+ overlay: ElementOverlay,
106
+ isReuseComponentChecker: IsReuseComponentApi,
107
+ isCloud: boolean,
108
+ resources: TextBundle
109
+ ) => {
102
110
  if (isCloud && isReuseComponentChecker(overlay.getElement().getId())) {
103
111
  return resources.getText('ADP_ADD_FRAGMENT_MENU_ITEM_REUSE_COMPONENT');
104
112
  }
@@ -113,12 +121,24 @@ export const getAddFragmentItemText = (overlay: ElementOverlay, isReuseComponent
113
121
  * Determines the text that should be displayed for Controller Extension context menu item.
114
122
  *
115
123
  * @param {ElementOverlay} overlay - An ElementOverlay object representing the UI overlay.
124
+ * @param {string[]} syncViewsIds - Array of IDs of all application sync views.
116
125
  * @param {isReuseComponentApi} isReuseComponentChecker - Function to check if the control is a reuse component.
117
126
  * @param {boolean} isCloud - Whether the application is running in the cloud.
118
127
  * @param {TextBundle} resources - The text bundle.
119
128
  * @returns {string} The text of the Add Fragment context menu item.
120
129
  */
121
- export const getExtendControllerItemText = (overlay: ElementOverlay, isReuseComponentChecker: IsReuseComponentApi, isCloud: boolean, resources: TextBundle) => {
130
+ export const getExtendControllerItemText = (
131
+ overlay: ElementOverlay,
132
+ syncViewsIds: string[],
133
+ isReuseComponentChecker: IsReuseComponentApi,
134
+ isCloud: boolean,
135
+ resources: TextBundle
136
+ ) => {
137
+ const viewId = FlUtils.getViewForControl(overlay.getElement()).getId();
138
+ if (syncViewsIds.includes(viewId)) {
139
+ return resources.getText('ADP_ADD_CONTROLLER_EXTENSION_MENU_ITEM_SYNC_VIEW');
140
+ }
141
+
122
142
  if (isCloud && isReuseComponentChecker(overlay.getElement().getId())) {
123
143
  return resources.getText('ADP_ADD_CONTROLLER_EXTENSION_MENU_ITEM_REUSE_COMPONENT');
124
144
  }
@@ -133,31 +153,33 @@ export const getExtendControllerItemText = (overlay: ElementOverlay, isReuseComp
133
153
  * @param syncViewsIds Ids of all application sync views
134
154
  * @param ui5VersionInfo UI5 version information
135
155
  */
136
- export const initDialogs = async (rta: RuntimeAuthoring, syncViewsIds: string[], ui5VersionInfo: Ui5VersionInfo): Promise<void> => {
156
+ export const initDialogs = async (
157
+ rta: RuntimeAuthoring,
158
+ syncViewsIds: string[],
159
+ ui5VersionInfo: Ui5VersionInfo
160
+ ): Promise<void> => {
137
161
  const contextMenu = rta.getDefaultPlugins().contextMenu;
138
162
  const isCloud = rta.getFlexSettings().isCloud;
139
163
  const resources = await getTextBundle();
140
164
  const isReuseComponentChecker = await getReuseComponentChecker(ui5VersionInfo);
141
165
 
142
- if (isLowerThanMinimalUi5Version(ui5VersionInfo, { major: 1, minor: 136 })) {
143
- contextMenu.addMenuItem({
144
- id: 'ADD_FRAGMENT',
145
- text: (overlay: ElementOverlay) => getAddFragmentItemText(overlay, isReuseComponentChecker, isCloud, resources),
146
- handler: async (overlays: UI5Element[]) =>
147
- await DialogFactory.createDialog(overlays[0], rta, DialogNames.ADD_FRAGMENT),
148
- icon: 'sap-icon://attachment-html',
149
- enabled: (overlays: ElementOverlay[]) => isFragmentCommandEnabled(overlays, isReuseComponentChecker, isCloud)
150
- });
151
- } else {
152
- (await import('open/ux/preview/client/adp/add-fragment')).initAddXMLPlugin(rta);
153
- }
166
+ contextMenu.addMenuItem({
167
+ id: 'ADD_FRAGMENT',
168
+ text: (overlay: ElementOverlay) => getAddFragmentItemText(overlay, isReuseComponentChecker, isCloud, resources),
169
+ handler: async (overlays: UI5Element[]) =>
170
+ await DialogFactory.createDialog(overlays[0], rta, DialogNames.ADD_FRAGMENT),
171
+ icon: 'sap-icon://attachment-html',
172
+ enabled: (overlays: ElementOverlay[]) => isFragmentCommandEnabled(overlays, isReuseComponentChecker, isCloud)
173
+ });
154
174
 
155
175
  contextMenu.addMenuItem({
156
176
  id: 'EXTEND_CONTROLLER',
157
- text: (overlay: ElementOverlay) => getExtendControllerItemText(overlay, isReuseComponentChecker, isCloud, resources),
177
+ text: (overlay: ElementOverlay) =>
178
+ getExtendControllerItemText(overlay, syncViewsIds, isReuseComponentChecker, isCloud, resources),
158
179
  handler: async (overlays: UI5Element[]) =>
159
180
  await DialogFactory.createDialog(overlays[0], rta, DialogNames.CONTROLLER_EXTENSION),
160
181
  icon: 'sap-icon://create-form',
161
- enabled: (overlays: ElementOverlay[]) => isControllerExtensionEnabled(overlays, syncViewsIds, isReuseComponentChecker, isCloud)
182
+ enabled: (overlays: ElementOverlay[]) =>
183
+ isControllerExtensionEnabled(overlays, syncViewsIds, isReuseComponentChecker, isCloud)
162
184
  });
163
185
  };
@@ -49,7 +49,15 @@ sap.ui.define([
49
49
  const syncViewsIds = await getAllSyncViewsIds(ui5VersionInfo);
50
50
  const defaultPlugins = rta.getDefaultPlugins();
51
51
  rta.setPlugins(defaultPlugins);
52
- await initDialogs(rta, syncViewsIds, ui5VersionInfo);
52
+ if (isLowerThanMinimalUi5Version(ui5VersionInfo, {
53
+ major: 1,
54
+ minor: 136
55
+ })) {
56
+ await initDialogs(rta, syncViewsIds, ui5VersionInfo);
57
+ } else {
58
+ (await __ui5_require_async('open/ux/preview/client/adp/add-fragment')).initAddXMLPlugin(rta);
59
+ (await __ui5_require_async('open/ux/preview/client/adp/extend-controller')).initExtendControllerPlugin(rta);
60
+ }
53
61
  if (!isLowerThanMinimalUi5Version(ui5VersionInfo, {
54
62
  major: 1,
55
63
  minor: 78
@@ -28,7 +28,12 @@ export default async function (rta: RuntimeAuthoring) {
28
28
  const defaultPlugins = rta.getDefaultPlugins();
29
29
  rta.setPlugins(defaultPlugins);
30
30
 
31
- await initDialogs(rta, syncViewsIds, ui5VersionInfo);
31
+ if (isLowerThanMinimalUi5Version(ui5VersionInfo, { major: 1, minor: 136 })) {
32
+ await initDialogs(rta, syncViewsIds, ui5VersionInfo);
33
+ } else {
34
+ (await import('open/ux/preview/client/adp/add-fragment')).initAddXMLPlugin(rta);
35
+ (await import('open/ux/preview/client/adp/extend-controller')).initExtendControllerPlugin(rta);
36
+ }
32
37
 
33
38
  if (!isLowerThanMinimalUi5Version(ui5VersionInfo, { major: 1, minor: 78 })) {
34
39
  const ExtensionPointService = (await import('open/ux/preview/client/adp/extension-point')).default;
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
 
3
- sap.ui.define(["sap/ui/dt/OverlayRegistry", "../../../utils/version", "../../utils", "../../../cpe/quick-actions/utils", "../../dialog-factory", "../../init-dialogs", "../../api-handler", "../simple-quick-action-base", "../dialog-enablement-validator"], function (OverlayRegistry, _____utils_version, ____utils, _____cpe_quick_actions_utils, ____dialog_factory, ____init_dialogs, ____api_handler, ___simple_quick_action_base, ___dialog_enablement_validator) {
3
+ sap.ui.define(["sap/ui/dt/OverlayRegistry", "../../../utils/version", "../../utils", "../../../cpe/quick-actions/utils", "../../dialog-factory", "../../init-dialogs", "../../api-handler", "../simple-quick-action-base", "../dialog-enablement-validator", "../../../i18n"], function (OverlayRegistry, _____utils_version, ____utils, _____cpe_quick_actions_utils, ____dialog_factory, ____init_dialogs, ____api_handler, ___simple_quick_action_base, ___dialog_enablement_validator, _____i18n) {
4
4
  "use strict";
5
5
 
6
6
  const getUi5Version = _____utils_version["getUi5Version"];
7
7
  const getAllSyncViewsIds = ____utils["getAllSyncViewsIds"];
8
8
  const getControllerInfoForControl = ____utils["getControllerInfoForControl"];
9
9
  const getReuseComponentChecker = ____utils["getReuseComponentChecker"];
10
+ const checkForExistingChange = ____utils["checkForExistingChange"];
10
11
  const getRelevantControlFromActivePage = _____cpe_quick_actions_utils["getRelevantControlFromActivePage"];
11
12
  const DialogFactory = ____dialog_factory["DialogFactory"];
12
13
  const DialogNames = ____dialog_factory["DialogNames"];
@@ -14,6 +15,7 @@ sap.ui.define(["sap/ui/dt/OverlayRegistry", "../../../utils/version", "../../uti
14
15
  const getExistingController = ____api_handler["getExistingController"];
15
16
  const SimpleQuickActionDefinitionBase = ___simple_quick_action_base["SimpleQuickActionDefinitionBase"];
16
17
  const DIALOG_ENABLEMENT_VALIDATOR = ___dialog_enablement_validator["DIALOG_ENABLEMENT_VALIDATOR"];
18
+ const getTextBundle = _____i18n["getTextBundle"];
17
19
  const ADD_CONTROLLER_TO_PAGE_TYPE = 'add-controller-to-page';
18
20
  const CONTROL_TYPES = ['sap.f.DynamicPage', 'sap.uxap.ObjectPageLayout'];
19
21
 
@@ -22,9 +24,21 @@ sap.ui.define(["sap/ui/dt/OverlayRegistry", "../../../utils/version", "../../uti
22
24
  */
23
25
  class AddControllerToPageQuickAction extends SimpleQuickActionDefinitionBase {
24
26
  constructor(context) {
25
- super(ADD_CONTROLLER_TO_PAGE_TYPE, CONTROL_TYPES, '', context, [DIALOG_ENABLEMENT_VALIDATOR]);
27
+ super(ADD_CONTROLLER_TO_PAGE_TYPE, CONTROL_TYPES, '', context, [DIALOG_ENABLEMENT_VALIDATOR, {
28
+ run: async () => {
29
+ const controllerName = getControllerInfoForControl(this.context.view).controllerName;
30
+ const i18n = await getTextBundle();
31
+ if (checkForExistingChange(this.context.rta, 'codeExt', 'selector.controllerName', controllerName)) {
32
+ return {
33
+ type: 'error',
34
+ message: i18n.getText('ADP_QUICK_ACTION_CONTROLLER_PENDING_CHANGE_EXISTS')
35
+ };
36
+ }
37
+ }
38
+ }]);
26
39
  }
27
40
  controllerExists = false;
41
+ forceRefreshAfterExecution = true;
28
42
  async initialize() {
29
43
  const version = await getUi5Version();
30
44
  const isReuseComponent = await getReuseComponentChecker(version);
@@ -2,7 +2,7 @@ import OverlayRegistry from 'sap/ui/dt/OverlayRegistry';
2
2
  import FlexCommand from 'sap/ui/rta/command/FlexCommand';
3
3
 
4
4
  import { getUi5Version } from '../../../utils/version';
5
- import { getAllSyncViewsIds, getControllerInfoForControl, getReuseComponentChecker } from '../../utils';
5
+ import { getAllSyncViewsIds, getControllerInfoForControl, getReuseComponentChecker, checkForExistingChange } from '../../utils';
6
6
  import { getRelevantControlFromActivePage } from '../../../cpe/quick-actions/utils';
7
7
  import type {
8
8
  QuickActionContext,
@@ -13,6 +13,8 @@ import { isControllerExtensionEnabledForControl } from '../../init-dialogs';
13
13
  import { getExistingController } from '../../api-handler';
14
14
  import { SimpleQuickActionDefinitionBase } from '../simple-quick-action-base';
15
15
  import { DIALOG_ENABLEMENT_VALIDATOR } from '../dialog-enablement-validator';
16
+ import type { EnablementValidatorResult } from '../enablement-validator';
17
+ import { getTextBundle } from '../../../i18n';
16
18
 
17
19
  export const ADD_CONTROLLER_TO_PAGE_TYPE = 'add-controller-to-page';
18
20
  const CONTROL_TYPES = ['sap.f.DynamicPage', 'sap.uxap.ObjectPageLayout'];
@@ -25,10 +27,25 @@ export class AddControllerToPageQuickAction
25
27
  implements SimpleQuickActionDefinition
26
28
  {
27
29
  constructor(context: QuickActionContext) {
28
- super(ADD_CONTROLLER_TO_PAGE_TYPE, CONTROL_TYPES, '', context, [DIALOG_ENABLEMENT_VALIDATOR]);
30
+ super(ADD_CONTROLLER_TO_PAGE_TYPE, CONTROL_TYPES, '', context, [
31
+ DIALOG_ENABLEMENT_VALIDATOR,
32
+ {
33
+ run: async (): Promise<EnablementValidatorResult> => {
34
+ const controllerName = getControllerInfoForControl(this.context.view).controllerName;
35
+ const i18n = await getTextBundle();
36
+ if (checkForExistingChange(this.context.rta, 'codeExt', 'selector.controllerName', controllerName)) {
37
+ return {
38
+ type: 'error',
39
+ message: i18n.getText('ADP_QUICK_ACTION_CONTROLLER_PENDING_CHANGE_EXISTS')
40
+ };
41
+ }
42
+ }
43
+ }
44
+ ]);
29
45
  }
30
46
 
31
47
  private controllerExists = false;
48
+ forceRefreshAfterExecution = true;
32
49
 
33
50
  async initialize(): Promise<void> {
34
51
  const version = await getUi5Version();
@@ -43,7 +60,12 @@ export class AddControllerToPageQuickAction
43
60
  const controlInfo = getControllerInfoForControl(control);
44
61
  const data = await getExistingController(controlInfo.controllerName);
45
62
  this.controllerExists = data?.controllerExists;
46
- const isActiveAction = isControllerExtensionEnabledForControl(control, syncViewsIds, isReuseComponent, this.context.flexSettings.isCloud);
63
+ const isActiveAction = isControllerExtensionEnabledForControl(
64
+ control,
65
+ syncViewsIds,
66
+ isReuseComponent,
67
+ this.context.flexSettings.isCloud
68
+ );
47
69
  this.control = isActiveAction ? control : undefined;
48
70
  break;
49
71
  }
@@ -11,7 +11,8 @@
11
11
  editable="true"
12
12
  layout="ResponsiveGridLayout"
13
13
  labelSpanS="4"
14
- singleContainerFullSize="false">
14
+ singleContainerFullSize="false"
15
+ visible="{/inputFormVisibility}">
15
16
  <f:content>
16
17
  <Label text="Controller Name" />
17
18
  <Input
@@ -26,13 +27,23 @@
26
27
  editable="true"
27
28
  layout="ResponsiveGridLayout"
28
29
  labelSpanS="12"
29
- visible="false"
30
+ visible="{/existingControllerFormVisibility}"
30
31
  singleContainerFullSize="false">
31
32
  <f:content>
32
- <Label text="An existing controller extension has been found. Please use the previously created extension controller" />
33
+ <Label text="{i18n>ADP_CONTROLLER_EXTENSION_EXISTS}" />
33
34
  <Text text="{/controllerPathFromRoot}" />
34
35
  </f:content>
35
36
  </f:SimpleForm>
37
+ <f:SimpleForm
38
+ editable="true"
39
+ layout="ResponsiveGridLayout"
40
+ labelSpanS="12"
41
+ visible="{/pendingChangeFormVisibility}"
42
+ singleContainerFullSize="false">
43
+ <f:content>
44
+ <Text text="{i18n>ADP_CONTROLLER_PENDING_CHANGE_EXISTS}" />
45
+ </f:content>
46
+ </f:SimpleForm>
36
47
  </content>
37
48
  <beginButton>
38
49
  <Button
@@ -57,19 +57,58 @@ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/Element", "sap/base/Log", "sap
57
57
  }
58
58
 
59
59
  /**
60
- * Checks if the fragment name associated with a command matches the specified fragment name.
60
+ * Checks for the existence of a change associated with a specific fragment name in the RTA command stack.
61
+ *
62
+ * @param {RuntimeAuthoring} rta - The RuntimeAuthoring instance to check for existing changes.
63
+ * @param {string} commandName - The name of the fragment to check for existing changes.
64
+ * @param {string} propertyPath - The path to the property as string separated by dot in the change definition to check.
65
+ * @param {string} propertyValue - The value to match against the specified property.
66
+ * @returns {Promise<boolean>} A promise that resolves to `true` if a matching change is found, otherwise `false`.
67
+ */
68
+ function checkForExistingChange(rta, commandName, propertyPath, propertyValue) {
69
+ const allCommands = rta.getCommandStack().getCommands();
70
+ return allCommands.some(command => {
71
+ if (typeof command.getCommands === 'function') {
72
+ const subCommand = command.getCommands().find(c => c?.getProperty('name') === commandName);
73
+ return subCommand && matchesChangeProperty(subCommand, propertyPath, propertyValue);
74
+ } else {
75
+ return matchesChangeProperty(command, propertyPath, propertyValue);
76
+ }
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Retrieves the value of a nested property from an object based on a dot-separated path.
82
+ *
83
+ * @param obj - The object from which to retrieve the nested property.
84
+ * @param path - A dot-separated string representing the path to the desired property.
85
+ * For example, "a.b.c" will attempt to access `obj.a.b.c`.
86
+ * @returns The value of the nested property if it exists, or `undefined` if any part of the path is invalid.
87
+ */
88
+ function getNestedProperty(obj, path) {
89
+ return path.split('.').reduce((acc, key) => {
90
+ return acc?.[key];
91
+ }, obj);
92
+ }
93
+
94
+ /**
95
+ * Checks if a specific property in the command's change matches the given value.
61
96
  *
62
97
  * @param {FlexCommand} command - The command object containing the prepared change to be examined.
63
- * @param {string} fragmentName - The name of the fragment to match against the command's change.
64
- * @returns {boolean} Returns true if the command's change contains a fragment path that matches
65
- * the specified fragment name; otherwise, returns false.
98
+ * @param {string} propertyPath - The path to the property in the change definition to check.
99
+ * @param {string} propertyValue - The value to match against the specified property.
100
+ * @returns {boolean} Returns true if the command's change contains the specified property with the matching value; otherwise, returns false.
66
101
  */
67
- function matchesFragmentName(command, fragmentName) {
102
+ function matchesChangeProperty(command, propertyPath, propertyValue) {
68
103
  if (typeof command.getPreparedChange !== 'function') {
69
104
  return false;
70
105
  }
71
- const change = command.getPreparedChange().getDefinition();
72
- return change.content?.fragmentPath?.includes(`${fragmentName}.fragment.xml`) || false;
106
+ const change = command.getPreparedChange()?.getDefinition?.();
107
+ if (!change) {
108
+ return false;
109
+ }
110
+ const nestedProperty = getNestedProperty(change, propertyPath);
111
+ return typeof nestedProperty === 'string' ? nestedProperty.includes(propertyValue) : false;
73
112
  }
74
113
 
75
114
  /**
@@ -209,7 +248,9 @@ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/Element", "sap/base/Log", "sap
209
248
  };
210
249
  __exports.resetReuseComponentChecker = resetReuseComponentChecker;
211
250
  __exports.createDeferred = createDeferred;
212
- __exports.matchesFragmentName = matchesFragmentName;
251
+ __exports.checkForExistingChange = checkForExistingChange;
252
+ __exports.getNestedProperty = getNestedProperty;
253
+ __exports.matchesChangeProperty = matchesChangeProperty;
213
254
  __exports.notifyUser = notifyUser;
214
255
  __exports.getAllSyncViewsIds = getAllSyncViewsIds;
215
256
  __exports.getControllerInfoForControl = getControllerInfoForControl;
@@ -9,6 +9,7 @@ import FlexUtils from 'sap/ui/fl/Utils';
9
9
  import IsReuseComponentApi from 'sap/ui/rta/util/isReuseComponent';
10
10
  import { getControlById } from '../utils/core';
11
11
  import type { Manifest } from 'sap/ui/rta/RuntimeAuthoring';
12
+ import RuntimeAuthoring from 'sap/ui/rta/RuntimeAuthoring';
12
13
 
13
14
  import { getError } from '../utils/error';
14
15
  import { isLowerThanMinimalUi5Version, Ui5VersionInfo } from '../utils/version';
@@ -60,19 +61,66 @@ export function createDeferred<T>(): Deferred<T> {
60
61
  }
61
62
 
62
63
  /**
63
- * Checks if the fragment name associated with a command matches the specified fragment name.
64
+ * Checks for the existence of a change associated with a specific fragment name in the RTA command stack.
65
+ *
66
+ * @param {RuntimeAuthoring} rta - The RuntimeAuthoring instance to check for existing changes.
67
+ * @param {string} commandName - The name of the fragment to check for existing changes.
68
+ * @param {string} propertyPath - The path to the property as string separated by dot in the change definition to check.
69
+ * @param {string} propertyValue - The value to match against the specified property.
70
+ * @returns {Promise<boolean>} A promise that resolves to `true` if a matching change is found, otherwise `false`.
71
+ */
72
+ export function checkForExistingChange(
73
+ rta: RuntimeAuthoring,
74
+ commandName: string,
75
+ propertyPath: string,
76
+ propertyValue: string
77
+ ): boolean {
78
+ const allCommands = rta.getCommandStack().getCommands();
79
+
80
+ return allCommands.some((command: FlexCommand) => {
81
+ if (typeof command.getCommands === 'function') {
82
+ const subCommand = command.getCommands().find((c: FlexCommand) => c?.getProperty('name') === commandName);
83
+
84
+ return subCommand && matchesChangeProperty(subCommand, propertyPath, propertyValue);
85
+ } else {
86
+ return matchesChangeProperty(command, propertyPath, propertyValue);
87
+ }
88
+ });
89
+ }
90
+
91
+ /**
92
+ * Retrieves the value of a nested property from an object based on a dot-separated path.
93
+ *
94
+ * @param obj - The object from which to retrieve the nested property.
95
+ * @param path - A dot-separated string representing the path to the desired property.
96
+ * For example, "a.b.c" will attempt to access `obj.a.b.c`.
97
+ * @returns The value of the nested property if it exists, or `undefined` if any part of the path is invalid.
98
+ */
99
+ export function getNestedProperty(obj: object, path: string): unknown {
100
+ return path.split('.').reduce((acc: unknown, key) => {
101
+ return (acc as Record<string, unknown>)?.[key];
102
+ }, obj);
103
+ }
104
+
105
+ /**
106
+ * Checks if a specific property in the command's change matches the given value.
64
107
  *
65
108
  * @param {FlexCommand} command - The command object containing the prepared change to be examined.
66
- * @param {string} fragmentName - The name of the fragment to match against the command's change.
67
- * @returns {boolean} Returns true if the command's change contains a fragment path that matches
68
- * the specified fragment name; otherwise, returns false.
109
+ * @param {string} propertyPath - The path to the property in the change definition to check.
110
+ * @param {string} propertyValue - The value to match against the specified property.
111
+ * @returns {boolean} Returns true if the command's change contains the specified property with the matching value; otherwise, returns false.
69
112
  */
70
- export function matchesFragmentName(command: FlexCommand, fragmentName: string): boolean {
113
+ export function matchesChangeProperty(command: FlexCommand, propertyPath: string, propertyValue: string): boolean {
71
114
  if (typeof command.getPreparedChange !== 'function') {
72
115
  return false;
73
116
  }
74
- const change = command.getPreparedChange().getDefinition() as unknown as FragmentChange;
75
- return change.content?.fragmentPath?.includes(`${fragmentName}.fragment.xml`) || false;
117
+ const change = command.getPreparedChange()?.getDefinition?.();
118
+ if (!change) {
119
+ return false;
120
+ }
121
+
122
+ const nestedProperty = getNestedProperty(change, propertyPath);
123
+ return typeof nestedProperty === 'string' ? nestedProperty.includes(propertyValue) : false;
76
124
  }
77
125
 
78
126
  /**
@@ -45,6 +45,7 @@ export class WorkspaceConnectorService {
45
45
  changeType?: string;
46
46
  content?: {
47
47
  fragmentPath?: string;
48
+ codeRef?: string;
48
49
  };
49
50
  };
50
51
  if (