@sap-ux/preview-middleware 0.7.3 → 0.7.5

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 (37) hide show
  1. package/dist/base/flp.js +5 -2
  2. package/dist/client/adp/api-handler.js +33 -0
  3. package/dist/client/adp/api-handler.ts +36 -0
  4. package/dist/client/adp/controllers/AddFragment.controller.js +6 -11
  5. package/dist/client/adp/controllers/AddFragment.controller.ts +3 -45
  6. package/dist/client/adp/controllers/BaseDialog.controller.js +17 -0
  7. package/dist/client/adp/controllers/BaseDialog.controller.ts +51 -0
  8. package/dist/client/adp/controllers/ControllerExtension.controller.js +114 -0
  9. package/dist/client/adp/controllers/ControllerExtension.controller.ts +172 -0
  10. package/dist/client/adp/init-dialogs.js +10 -2
  11. package/dist/client/adp/init-dialogs.ts +15 -2
  12. package/dist/client/adp/init.ts +1 -0
  13. package/dist/client/adp/ui/AddFragment.view.xml +1 -1
  14. package/dist/client/adp/ui/ControllerExtension.view.xml +38 -0
  15. package/dist/client/cpe/changes/service.js +2 -3
  16. package/dist/client/cpe/changes/service.ts +2 -3
  17. package/dist/client/cpe/control-data.js +0 -1
  18. package/dist/client/cpe/control-data.ts +0 -1
  19. package/dist/client/cpe/init.js +8 -9
  20. package/dist/client/cpe/init.ts +5 -7
  21. package/dist/client/cpe/outline/index.js +2 -2
  22. package/dist/client/cpe/outline/index.ts +2 -8
  23. package/dist/client/cpe/outline/nodes.js +6 -7
  24. package/dist/client/cpe/outline/nodes.ts +6 -8
  25. package/dist/client/cpe/outline/utils.js +6 -5
  26. package/dist/client/cpe/outline/utils.ts +4 -4
  27. package/dist/client/cpe/selection.js +12 -9
  28. package/dist/client/cpe/selection.ts +10 -7
  29. package/dist/client/cpe/types.ts +1 -12
  30. package/dist/client/cpe/ui5-utils.js +51 -0
  31. package/dist/client/cpe/ui5-utils.ts +45 -0
  32. package/dist/client/flp/WorkspaceConnector.js +17 -6
  33. package/dist/client/flp/WorkspaceConnector.ts +30 -10
  34. package/dist/types/index.d.ts +1 -1
  35. package/package.json +4 -4
  36. package/dist/client/cpe/facade.js +0 -95
  37. package/dist/client/cpe/facade.ts +0 -95
package/dist/base/flp.js CHANGED
@@ -117,7 +117,6 @@ class FlpSandbox {
117
117
  if (this.rta) {
118
118
  (_k = (_l = this.rta).options) !== null && _k !== void 0 ? _k : (_l.options = {});
119
119
  this.rta.options.baseId = componentId !== null && componentId !== void 0 ? componentId : manifest['sap.app'].id;
120
- this.rta.options.generator = 'changeUtils: SAPFioriTools-propertyEditor';
121
120
  this.addEditorRoutes(this.rta);
122
121
  }
123
122
  this.addRoutesForAdditionalApps();
@@ -153,9 +152,13 @@ class FlpSandbox {
153
152
  }
154
153
  this.router.use(`${path}editor`, (0, express_1.static)(cpe));
155
154
  }
155
+ const defaultGenerator = editor.developerMode
156
+ ? '@sap-ux/control-property-editor'
157
+ : '@sap-ux/preview-middleware';
156
158
  this.router.get(previewUrl, ((_req, res) => __awaiter(this, void 0, void 0, function* () {
159
+ var _d;
157
160
  const config = Object.assign({}, this.templateConfig);
158
- config.flex = Object.assign(Object.assign({ layer: rta.layer }, rta.options), { developerMode: editor.developerMode === true, pluginScript: editor.pluginScript });
161
+ config.flex = Object.assign(Object.assign({ layer: rta.layer }, rta.options), { generator: (_d = editor.generator) !== null && _d !== void 0 ? _d : defaultGenerator, developerMode: editor.developerMode === true, pluginScript: editor.pluginScript });
159
162
  if (editor.developerMode === true) {
160
163
  config.ui5.bootstrapOptions = serializeUi5Configuration(DEVELOPER_MODE_CONFIG);
161
164
  }
@@ -4,6 +4,7 @@ sap.ui.define([], function () {
4
4
  "use strict";
5
5
 
6
6
  var ApiEndpoints = /*#__PURE__*/function (ApiEndpoints) {
7
+ ApiEndpoints["CHANGES"] = "/preview/api/changes";
7
8
  ApiEndpoints["FRAGMENT"] = "/adp/api/fragment";
8
9
  ApiEndpoints["CONTROLLER"] = "/adp/api/controller";
9
10
  ApiEndpoints["MANIFEST_APP_DESCRIPTOR"] = "/manifest.appdescr_variant";
@@ -82,6 +83,35 @@ sap.ui.define([], function () {
82
83
  async function getManifestAppdescr() {
83
84
  return request(ApiEndpoints.MANIFEST_APP_DESCRIPTOR, RequestMethod.GET);
84
85
  }
86
+
87
+ /**
88
+ * Retrieves all controller extensions from the project's workspace
89
+ *
90
+ * @returns Generic Promise<T>
91
+ */
92
+ async function readControllers() {
93
+ return request(ApiEndpoints.CONTROLLER, RequestMethod.GET);
94
+ }
95
+
96
+ /**
97
+ * Writes a Controller to the project's workspace
98
+ *
99
+ * @param data Data to be send to the server
100
+ * @returns Generic Promise<T>
101
+ */
102
+ async function writeController(data) {
103
+ return request(ApiEndpoints.CONTROLLER, RequestMethod.POST, data);
104
+ }
105
+
106
+ /**
107
+ * Writes a change object to the project's workspace
108
+ *
109
+ * @param data Data to be send to the server
110
+ * @returns Generic Promise<T>
111
+ */
112
+ async function writeChange(data) {
113
+ return request(ApiEndpoints.CHANGES, RequestMethod.POST, data);
114
+ }
85
115
  var __exports = {
86
116
  __esModule: true
87
117
  };
@@ -91,6 +121,9 @@ sap.ui.define([], function () {
91
121
  __exports.getFragments = getFragments;
92
122
  __exports.writeFragment = writeFragment;
93
123
  __exports.getManifestAppdescr = getManifestAppdescr;
124
+ __exports.readControllers = readControllers;
125
+ __exports.writeController = writeController;
126
+ __exports.writeChange = writeChange;
94
127
  return __exports;
95
128
  });
96
129
  //# sourceMappingURL=api-handler.js.map
@@ -1,6 +1,7 @@
1
1
  import type { Layer } from 'sap/ui/fl';
2
2
 
3
3
  export const enum ApiEndpoints {
4
+ CHANGES = '/preview/api/changes',
4
5
  FRAGMENT = '/adp/api/fragment',
5
6
  CONTROLLER = '/adp/api/controller',
6
7
  MANIFEST_APP_DESCRIPTOR = '/manifest.appdescr_variant'
@@ -15,12 +16,18 @@ export const enum RequestMethod {
15
16
  }
16
17
 
17
18
  type Fragments = { fragmentName: string }[];
19
+ type Controllers = { controllerName: string }[];
18
20
 
19
21
  export interface FragmentsResponse {
20
22
  fragments: Fragments;
21
23
  message: string;
22
24
  }
23
25
 
26
+ export interface ControllersResponse {
27
+ controllers: Controllers;
28
+ message: string;
29
+ }
30
+
24
31
  export interface ManifestAppdescr {
25
32
  fileName: string;
26
33
  layer: Layer;
@@ -100,3 +107,32 @@ export async function writeFragment<T>(data: T): Promise<T> {
100
107
  export async function getManifestAppdescr(): Promise<ManifestAppdescr> {
101
108
  return request<ManifestAppdescr>(ApiEndpoints.MANIFEST_APP_DESCRIPTOR, RequestMethod.GET);
102
109
  }
110
+
111
+ /**
112
+ * Retrieves all controller extensions from the project's workspace
113
+ *
114
+ * @returns Generic Promise<T>
115
+ */
116
+ export async function readControllers<T>(): Promise<T> {
117
+ return request<T>(ApiEndpoints.CONTROLLER, RequestMethod.GET);
118
+ }
119
+
120
+ /**
121
+ * Writes a Controller to the project's workspace
122
+ *
123
+ * @param data Data to be send to the server
124
+ * @returns Generic Promise<T>
125
+ */
126
+ export async function writeController<T>(data: T): Promise<T> {
127
+ return request<T>(ApiEndpoints.CONTROLLER, RequestMethod.POST, data);
128
+ }
129
+
130
+ /**
131
+ * Writes a change object to the project's workspace
132
+ *
133
+ * @param data Data to be send to the server
134
+ * @returns Generic Promise<T>
135
+ */
136
+ export async function writeChange<T>(data: T): Promise<T> {
137
+ return request<T>(ApiEndpoints.CHANGES, RequestMethod.POST, data);
138
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
 
3
- sap.ui.define(["sap/m/MessageToast", "sap/ui/core/library", "sap/ui/core/mvc/Controller", "sap/ui/model/json/JSONModel", "sap/ui/dt/OverlayRegistry", "../control-utils", "../command-executor", "../api-handler"], function (MessageToast, sap_ui_core_library, Controller, JSONModel, OverlayRegistry, __ControlUtils, __CommandExecutor, ___api_handler) {
3
+ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/library", "sap/ui/model/json/JSONModel", "sap/ui/dt/OverlayRegistry", "../control-utils", "../command-executor", "../api-handler", "./BaseDialog.controller"], function (MessageToast, sap_ui_core_library, JSONModel, OverlayRegistry, __ControlUtils, __CommandExecutor, ___api_handler, __BaseDialog) {
4
4
  "use strict";
5
5
 
6
6
  function _interopRequireDefault(obj) {
@@ -8,22 +8,24 @@ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/library", "sap/ui/core/mvc/Con
8
8
  }
9
9
  /** sap.ui.core */
10
10
  const ValueState = sap_ui_core_library["ValueState"];
11
+ /** sap.ui.base */
11
12
  const ControlUtils = _interopRequireDefault(__ControlUtils);
12
13
  const CommandExecutor = _interopRequireDefault(__CommandExecutor);
13
14
  const getFragments = ___api_handler["getFragments"];
14
15
  const writeFragment = ___api_handler["writeFragment"];
16
+ const BaseDialog = _interopRequireDefault(__BaseDialog);
15
17
  /**
16
18
  * @namespace open.ux.preview.client.adp.controllers
17
19
  */
18
- const AddFragment = Controller.extend("open.ux.preview.client.adp.controllers.AddFragment", {
20
+ const AddFragment = BaseDialog.extend("open.ux.preview.client.adp.controllers.AddFragment", {
19
21
  constructor: function _constructor(name, overlays, rta) {
20
- Controller.prototype.constructor.call(this, name);
22
+ BaseDialog.prototype.constructor.call(this, name);
21
23
  this.rta = rta;
22
24
  this.overlays = overlays;
25
+ this.model = new JSONModel();
23
26
  this.commandExecutor = new CommandExecutor(this.rta);
24
27
  },
25
28
  onInit: async function _onInit() {
26
- this.model = new JSONModel();
27
29
  this.dialog = this.byId('addNewFragmentDialog');
28
30
  await this.buildDialogData();
29
31
  this.getView()?.setModel(this.model);
@@ -94,13 +96,6 @@ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/library", "sap/ui/core/mvc/Con
94
96
  await this.createNewFragment(fragmentData);
95
97
  this.handleDialogClose();
96
98
  },
97
- closeDialog: function _closeDialog() {
98
- this.handleDialogClose();
99
- },
100
- handleDialogClose: function _handleDialogClose() {
101
- this.dialog.close();
102
- this.getView()?.destroy();
103
- },
104
99
  buildDialogData: async function _buildDialogData() {
105
100
  const selectorId = this.overlays.getId();
106
101
  let controlMetadata;
@@ -8,11 +8,9 @@ import MessageToast from 'sap/m/MessageToast';
8
8
  /** sap.ui.core */
9
9
  import { ValueState } from 'sap/ui/core/library';
10
10
  import type UI5Element from 'sap/ui/core/Element';
11
- import Controller from 'sap/ui/core/mvc/Controller';
12
11
 
13
12
  /** sap.ui.base */
14
13
  import type Event from 'sap/ui/base/Event';
15
- import type ManagedObject from 'sap/ui/base/ManagedObject';
16
14
  import type ManagedObjectMetadata from 'sap/ui/base/ManagedObjectMetadata';
17
15
 
18
16
  /** sap.ui.model */
@@ -28,6 +26,7 @@ import type ElementOverlay from 'sap/ui/dt/ElementOverlay';
28
26
  import ControlUtils from '../control-utils';
29
27
  import CommandExecutor from '../command-executor';
30
28
  import { getFragments, writeFragment } from '../api-handler';
29
+ import BaseDialog from './BaseDialog.controller';
31
30
 
32
31
  interface CreateFragmentProps {
33
32
  fragmentName: string;
@@ -38,36 +37,12 @@ interface CreateFragmentProps {
38
37
  /**
39
38
  * @namespace open.ux.preview.client.adp.controllers
40
39
  */
41
- export default class AddFragment extends Controller {
42
- /**
43
- * Runtime control managed object
44
- */
45
- public runtimeControl: ManagedObject;
46
- /**
47
- * JSON Model that has the data
48
- */
49
- public model: JSONModel;
50
- /**
51
- * Dialog instance
52
- */
53
- public dialog: Dialog;
54
- /**
55
- * Runtime Authoring
56
- */
57
- private rta: RuntimeAuthoring;
58
- /**
59
- * Control Overlays
60
- */
61
- private overlays: UI5Element;
62
- /**
63
- * RTA Command Executor
64
- */
65
- private commandExecutor: CommandExecutor;
66
-
40
+ export default class AddFragment extends BaseDialog {
67
41
  constructor(name: string, overlays: UI5Element, rta: RuntimeAuthoring) {
68
42
  super(name);
69
43
  this.rta = rta;
70
44
  this.overlays = overlays;
45
+ this.model = new JSONModel();
71
46
  this.commandExecutor = new CommandExecutor(this.rta);
72
47
  }
73
48
 
@@ -75,8 +50,6 @@ export default class AddFragment extends Controller {
75
50
  * Initializes controller, fills model with data and opens the dialog
76
51
  */
77
52
  async onInit() {
78
- this.model = new JSONModel();
79
-
80
53
  this.dialog = this.byId('addNewFragmentDialog') as unknown as Dialog;
81
54
 
82
55
  await this.buildDialogData();
@@ -193,21 +166,6 @@ export default class AddFragment extends Controller {
193
166
  this.handleDialogClose();
194
167
  }
195
168
 
196
- /**
197
- * Handles the closing of the dialog
198
- */
199
- closeDialog() {
200
- this.handleDialogClose();
201
- }
202
-
203
- /**
204
- * Handles the dialog closing and destruction of it
205
- */
206
- handleDialogClose() {
207
- this.dialog.close();
208
- this.getView()?.destroy();
209
- }
210
-
211
169
  /**
212
170
  * Builds data that is used in the dialog
213
171
  */
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ sap.ui.define(["sap/ui/core/mvc/Controller"], function (Controller) {
4
+ "use strict";
5
+
6
+ /**
7
+ * @namespace open.ux.preview.client.adp.controllers
8
+ */
9
+ const BaseDialog = Controller.extend("open.ux.preview.client.adp.controllers.BaseDialog", {
10
+ handleDialogClose: function _handleDialogClose() {
11
+ this.dialog.close();
12
+ this.getView()?.destroy();
13
+ }
14
+ });
15
+ return BaseDialog;
16
+ });
17
+ //# sourceMappingURL=BaseDialog.controller.js.map
@@ -0,0 +1,51 @@
1
+ import Dialog from 'sap/m/Dialog';
2
+ import Event from 'sap/ui/base/Event';
3
+ import ManagedObject from 'sap/ui/base/ManagedObject';
4
+ import UI5Element from 'sap/ui/core/Element';
5
+ import Controller from 'sap/ui/core/mvc/Controller';
6
+ import JSONModel from 'sap/ui/model/json/JSONModel';
7
+ import RuntimeAuthoring from 'sap/ui/rta/RuntimeAuthoring';
8
+
9
+ import CommandExecutor from '../command-executor';
10
+
11
+ /**
12
+ * @namespace open.ux.preview.client.adp.controllers
13
+ */
14
+ export default abstract class BaseDialog extends Controller {
15
+ /**
16
+ * Runtime Authoring
17
+ */
18
+ protected rta: RuntimeAuthoring;
19
+ /**
20
+ * Control Overlays
21
+ */
22
+ protected overlays: UI5Element;
23
+ /**
24
+ * JSON Model that has the data
25
+ */
26
+ public model: JSONModel;
27
+ /**
28
+ * Runtime control managed object
29
+ */
30
+ protected runtimeControl: ManagedObject;
31
+ /**
32
+ * Dialog instance
33
+ */
34
+ public dialog: Dialog;
35
+ /**
36
+ * RTA Command Executor
37
+ */
38
+ protected commandExecutor: CommandExecutor;
39
+
40
+ abstract onCreateBtnPress(event: Event): Promise<void>;
41
+
42
+ abstract buildDialogData(): Promise<void>;
43
+
44
+ /**
45
+ * Handles the dialog closing and destruction of it
46
+ */
47
+ handleDialogClose() {
48
+ this.dialog.close();
49
+ this.getView()?.destroy();
50
+ }
51
+ }
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+
3
+ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/library", "sap/ui/model/json/JSONModel", "sap/ui/fl/Utils", "../api-handler", "./BaseDialog.controller"], function (MessageToast, sap_ui_core_library, JSONModel, Utils, ___api_handler, __BaseDialog) {
4
+ "use strict";
5
+
6
+ function _interopRequireDefault(obj) {
7
+ return obj && obj.__esModule && typeof obj.default !== "undefined" ? obj.default : obj;
8
+ }
9
+ /** sap.ui.core */
10
+ const ValueState = sap_ui_core_library["ValueState"];
11
+ /** sap.ui.base */
12
+ const getManifestAppdescr = ___api_handler["getManifestAppdescr"];
13
+ const readControllers = ___api_handler["readControllers"];
14
+ const writeChange = ___api_handler["writeChange"];
15
+ const writeController = ___api_handler["writeController"];
16
+ const BaseDialog = _interopRequireDefault(__BaseDialog);
17
+ /**
18
+ * @namespace open.ux.preview.client.adp.controllers
19
+ */
20
+ const ControllerExtension = BaseDialog.extend("open.ux.preview.client.adp.controllers.ControllerExtension", {
21
+ constructor: function _constructor(name, overlays, rta) {
22
+ BaseDialog.prototype.constructor.call(this, name);
23
+ this.rta = rta;
24
+ this.overlays = overlays;
25
+ this.model = new JSONModel();
26
+ },
27
+ onInit: async function _onInit() {
28
+ this.dialog = this.byId('controllerExtensionDialog');
29
+ await this.buildDialogData();
30
+ this.getView()?.setModel(this.model);
31
+ this.dialog.open();
32
+ },
33
+ onControllerNameInputChange: function _onControllerNameInputChange(event) {
34
+ const source = event.getSource();
35
+ const controllerName = source.getValue().trim();
36
+ const controllerList = this.model.getProperty('/controllersList');
37
+ if (controllerName.length <= 0) {
38
+ this.dialog.getBeginButton().setEnabled(false);
39
+ source.setValueState(ValueState.None);
40
+ this.model.setProperty('/newControllerName', null);
41
+ } else {
42
+ const fileExists = controllerList.find(f => {
43
+ return f.controllerName === `${controllerName}.js`;
44
+ });
45
+ const isValidName = /^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(controllerName);
46
+ if (fileExists) {
47
+ source.setValueState(ValueState.Error);
48
+ source.setValueStateText('Enter a different name. The controller name that you entered already exists in your project.');
49
+ this.dialog.getBeginButton().setEnabled(false);
50
+ } else if (!isValidName) {
51
+ source.setValueState(ValueState.Error);
52
+ source.setValueStateText('The controller name cannot contain white spaces or special characters.');
53
+ this.dialog.getBeginButton().setEnabled(false);
54
+ } else {
55
+ this.dialog.getBeginButton().setEnabled(true);
56
+ source.setValueState(ValueState.None);
57
+ this.model.setProperty('/newControllerName', controllerName);
58
+ }
59
+ }
60
+ },
61
+ onCreateBtnPress: async function _onCreateBtnPress(event) {
62
+ const source = event.getSource();
63
+ source.setEnabled(false);
64
+ const controllerName = this.model.getProperty('/newControllerName');
65
+ const viewId = this.model.getProperty('/viewId');
66
+ await this.createNewController(controllerName, viewId);
67
+ this.handleDialogClose();
68
+ },
69
+ buildDialogData: async function _buildDialogData() {
70
+ const selectorId = this.overlays.getId();
71
+ const overlayControl = sap.ui.getCore().byId(selectorId);
72
+ const control = overlayControl.getElement();
73
+ const viewId = Utils.getViewForControl(control).getId();
74
+ this.model.setProperty('/viewId', viewId);
75
+ await this.getControllers();
76
+ },
77
+ getControllers: async function _getControllers() {
78
+ try {
79
+ const {
80
+ controllers
81
+ } = await readControllers();
82
+ this.model.setProperty('/controllersList', controllers);
83
+ } catch (e) {
84
+ MessageToast.show(e.message);
85
+ throw new Error(e.message);
86
+ }
87
+ },
88
+ createNewController: async function _createNewController(controllerName, viewId) {
89
+ try {
90
+ const manifest = await getManifestAppdescr();
91
+ await writeController({
92
+ controllerName,
93
+ projectId: manifest.id
94
+ });
95
+ const controllerRef = {
96
+ codeRef: `coding/${controllerName}.js`,
97
+ viewId
98
+ };
99
+ const service = await this.rta.getService('controllerExtension');
100
+ const change = await service.add(controllerRef.codeRef, controllerRef.viewId);
101
+ await writeChange(change);
102
+ MessageToast.show(`Controller extension with name '${controllerName}' was created.`);
103
+ } catch (e) {
104
+ // We want to update the model incase we have already created a controller file but failed when creating a change file,
105
+ // so when the user types the same controller name again he does not get 409 from the server, instead an error is shown in the UI
106
+ await this.getControllers();
107
+ MessageToast.show(e.message);
108
+ throw new Error(e.message);
109
+ }
110
+ }
111
+ });
112
+ return ControllerExtension;
113
+ });
114
+ //# sourceMappingURL=ControllerExtension.controller.js.map
@@ -0,0 +1,172 @@
1
+ /** sap.m */
2
+ import Input from 'sap/m/Input';
3
+ import Button from 'sap/m/Button';
4
+ import type Dialog from 'sap/m/Dialog';
5
+ import MessageToast from 'sap/m/MessageToast';
6
+
7
+ /** sap.ui.core */
8
+ import { ValueState } from 'sap/ui/core/library';
9
+ import type UI5Element from 'sap/ui/core/Element';
10
+
11
+ /** sap.ui.base */
12
+ import type Event from 'sap/ui/base/Event';
13
+
14
+ /** sap.ui.model */
15
+ import JSONModel from 'sap/ui/model/json/JSONModel';
16
+
17
+ /** sap.ui.rta */
18
+ import type RuntimeAuthoring from 'sap/ui/rta/RuntimeAuthoring';
19
+
20
+ /** sap.ui.fl */
21
+ import Utils from 'sap/ui/fl/Utils';
22
+
23
+ /** sap.ui.dt */
24
+ import type ElementOverlay from 'sap/ui/dt/ElementOverlay';
25
+
26
+ import type { ControllersResponse } from '../api-handler';
27
+ import { getManifestAppdescr, readControllers, writeChange, writeController } from '../api-handler';
28
+ import BaseDialog from './BaseDialog.controller';
29
+
30
+ interface ControllerExtensionService {
31
+ add: (codeRef: string, viewId: string) => Promise<unknown>;
32
+ }
33
+
34
+ /**
35
+ * @namespace open.ux.preview.client.adp.controllers
36
+ */
37
+ export default class ControllerExtension extends BaseDialog {
38
+ constructor(name: string, overlays: UI5Element, rta: RuntimeAuthoring) {
39
+ super(name);
40
+ this.rta = rta;
41
+ this.overlays = overlays;
42
+ this.model = new JSONModel();
43
+ }
44
+
45
+ /**
46
+ * Initializes controller, fills model with data and opens the dialog
47
+ */
48
+ async onInit() {
49
+ this.dialog = this.byId('controllerExtensionDialog') as unknown as Dialog;
50
+
51
+ await this.buildDialogData();
52
+
53
+ this.getView()?.setModel(this.model);
54
+
55
+ this.dialog.open();
56
+ }
57
+
58
+ /**
59
+ * Handles fragment name input change
60
+ *
61
+ * @param event Event
62
+ */
63
+ onControllerNameInputChange(event: Event) {
64
+ const source = event.getSource<Input>();
65
+
66
+ const controllerName: string = source.getValue().trim();
67
+ const controllerList: { controllerName: string }[] = this.model.getProperty('/controllersList');
68
+
69
+ if (controllerName.length <= 0) {
70
+ this.dialog.getBeginButton().setEnabled(false);
71
+ source.setValueState(ValueState.None);
72
+ this.model.setProperty('/newControllerName', null);
73
+ } else {
74
+ const fileExists = controllerList.find((f: { controllerName: string }) => {
75
+ return f.controllerName === `${controllerName}.js`;
76
+ });
77
+
78
+ const isValidName = /^[a-zA-Z_][a-zA-Z0-9_-]*$/.test(controllerName);
79
+
80
+ if (fileExists) {
81
+ source.setValueState(ValueState.Error);
82
+ source.setValueStateText(
83
+ 'Enter a different name. The controller name that you entered already exists in your project.'
84
+ );
85
+ this.dialog.getBeginButton().setEnabled(false);
86
+ } else if (!isValidName) {
87
+ source.setValueState(ValueState.Error);
88
+ source.setValueStateText('The controller name cannot contain white spaces or special characters.');
89
+ this.dialog.getBeginButton().setEnabled(false);
90
+ } else {
91
+ this.dialog.getBeginButton().setEnabled(true);
92
+ source.setValueState(ValueState.None);
93
+ this.model.setProperty('/newControllerName', controllerName);
94
+ }
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Handles create button press
100
+ *
101
+ * @param event Event
102
+ */
103
+ async onCreateBtnPress(event: Event) {
104
+ const source = event.getSource<Button>();
105
+ source.setEnabled(false);
106
+
107
+ const controllerName = this.model.getProperty('/newControllerName');
108
+ const viewId = this.model.getProperty('/viewId');
109
+
110
+ await this.createNewController(controllerName, viewId);
111
+
112
+ this.handleDialogClose();
113
+ }
114
+
115
+ /**
116
+ * Builds data that is used in the dialog
117
+ */
118
+ async buildDialogData(): Promise<void> {
119
+ const selectorId = this.overlays.getId();
120
+ const overlayControl = sap.ui.getCore().byId(selectorId) as unknown as ElementOverlay;
121
+ const control = overlayControl.getElement();
122
+ const viewId = Utils.getViewForControl(control).getId();
123
+
124
+ this.model.setProperty('/viewId', viewId);
125
+
126
+ await this.getControllers();
127
+ }
128
+
129
+ /**
130
+ * Retrieves controller files and fills the model with data
131
+ */
132
+ async getControllers(): Promise<void> {
133
+ try {
134
+ const { controllers } = await readControllers<ControllersResponse>();
135
+ this.model.setProperty('/controllersList', controllers);
136
+ } catch (e) {
137
+ MessageToast.show(e.message);
138
+ throw new Error(e.message);
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Creates a new fragment for the specified control
144
+ *
145
+ * @param controllerName Controller Name
146
+ * @param viewId View Id
147
+ */
148
+ private async createNewController(controllerName: string, viewId: string): Promise<void> {
149
+ try {
150
+ const manifest = await getManifestAppdescr();
151
+ await writeController({ controllerName, projectId: manifest.id });
152
+
153
+ const controllerRef = {
154
+ codeRef: `coding/${controllerName}.js`,
155
+ viewId
156
+ };
157
+
158
+ const service = await this.rta.getService<ControllerExtensionService>('controllerExtension');
159
+
160
+ const change = await service.add(controllerRef.codeRef, controllerRef.viewId);
161
+
162
+ await writeChange(change);
163
+ MessageToast.show(`Controller extension with name '${controllerName}' was created.`);
164
+ } catch (e) {
165
+ // We want to update the model incase we have already created a controller file but failed when creating a change file,
166
+ // so when the user types the same controller name again he does not get 409 from the server, instead an error is shown in the UI
167
+ await this.getControllers();
168
+ MessageToast.show(e.message);
169
+ throw new Error(e.message);
170
+ }
171
+ }
172
+ }
@@ -1,14 +1,16 @@
1
1
  "use strict";
2
2
 
3
- sap.ui.define(["sap/ui/core/mvc/XMLView", "./controllers/AddFragment.controller"], function (XMLView, __AddFragment) {
3
+ sap.ui.define(["sap/ui/core/mvc/XMLView", "./controllers/AddFragment.controller", "./controllers/ControllerExtension.controller"], function (XMLView, __AddFragment, __ControllerExtension) {
4
4
  "use strict";
5
5
 
6
6
  function _interopRequireDefault(obj) {
7
7
  return obj && obj.__esModule && typeof obj.default !== "undefined" ? obj.default : obj;
8
8
  }
9
9
  const AddFragment = _interopRequireDefault(__AddFragment);
10
+ const ControllerExtension = _interopRequireDefault(__ControllerExtension);
10
11
  var DialogNames = /*#__PURE__*/function (DialogNames) {
11
12
  DialogNames["ADD_FRAGMENT"] = "AddFragment";
13
+ DialogNames["CONTROLLER_EXTENSION"] = "ControllerExtension";
12
14
  return DialogNames;
13
15
  }(DialogNames || {});
14
16
  /**
@@ -24,6 +26,12 @@ sap.ui.define(["sap/ui/core/mvc/XMLView", "./controllers/AddFragment.controller"
24
26
  handler: async overlays => await handler(overlays[0], rta, DialogNames.ADD_FRAGMENT),
25
27
  icon: 'sap-icon://attachment-html'
26
28
  });
29
+ contextMenu.addMenuItem({
30
+ id: 'EXTEND_CONTROLLER',
31
+ text: 'Extend With Controller',
32
+ handler: async overlays => await handler(overlays[0], rta, DialogNames.CONTROLLER_EXTENSION),
33
+ icon: 'sap-icon://create-form'
34
+ });
27
35
  };
28
36
 
29
37
  /**
@@ -34,7 +42,7 @@ sap.ui.define(["sap/ui/core/mvc/XMLView", "./controllers/AddFragment.controller"
34
42
  * @param dialogName Dialog name
35
43
  */
36
44
  async function handler(overlays, rta, dialogName) {
37
- const controller = new AddFragment(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta);
45
+ const controller = dialogName === DialogNames.ADD_FRAGMENT ? new AddFragment(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta) : new ControllerExtension(`open.ux.preview.client.adp.controllers.${dialogName}`, overlays, rta);
38
46
  await XMLView.create({
39
47
  viewName: `open.ux.preview.client.adp.ui.${dialogName}`,
40
48
  controller