@sap-ux/preview-middleware 0.10.7 → 0.11.1
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.
- package/dist/client/adp/api-handler.js +15 -1
- package/dist/client/adp/api-handler.ts +20 -1
- package/dist/client/adp/controllers/ControllerExtension.controller.js +62 -7
- package/dist/client/adp/controllers/ControllerExtension.controller.ts +107 -17
- package/dist/client/adp/ui/ControllerExtension.view.xml +11 -0
- package/dist/client/cpe/changes/flex-change.js +11 -4
- package/dist/client/cpe/changes/flex-change.ts +10 -4
- package/dist/client/cpe/changes/validator.js +37 -0
- package/dist/client/cpe/changes/validator.ts +31 -0
- package/package.json +4 -4
|
@@ -7,6 +7,7 @@ sap.ui.define([], function () {
|
|
|
7
7
|
ApiEndpoints["CHANGES"] = "/preview/api/changes";
|
|
8
8
|
ApiEndpoints["FRAGMENT"] = "/adp/api/fragment";
|
|
9
9
|
ApiEndpoints["CONTROLLER"] = "/adp/api/controller";
|
|
10
|
+
ApiEndpoints["CODE_EXT"] = "/adp/api/code_ext";
|
|
10
11
|
ApiEndpoints["MANIFEST_APP_DESCRIPTOR"] = "/manifest.appdescr_variant";
|
|
11
12
|
return ApiEndpoints;
|
|
12
13
|
}(ApiEndpoints || {});
|
|
@@ -37,7 +38,9 @@ sap.ui.define([], function () {
|
|
|
37
38
|
try {
|
|
38
39
|
const response = await fetch(endpoint, config);
|
|
39
40
|
if (!response.ok) {
|
|
40
|
-
|
|
41
|
+
const errorData = await response.json();
|
|
42
|
+
const message = errorData?.message ?? '';
|
|
43
|
+
throw new Error(`Request failed, status: ${response.status}. ${message}`.trim());
|
|
41
44
|
}
|
|
42
45
|
switch (method) {
|
|
43
46
|
case RequestMethod.GET:
|
|
@@ -103,6 +106,16 @@ sap.ui.define([], function () {
|
|
|
103
106
|
return request(ApiEndpoints.CONTROLLER, RequestMethod.POST, data);
|
|
104
107
|
}
|
|
105
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Checks for existing controller in the project's workspace
|
|
111
|
+
*
|
|
112
|
+
* @param controllerName Name of the controller
|
|
113
|
+
* @returns {CodeExtResponse} Returns path to existing controller if found
|
|
114
|
+
*/
|
|
115
|
+
async function getExistingController(controllerName) {
|
|
116
|
+
return request(`${ApiEndpoints.CODE_EXT}/${controllerName}`, RequestMethod.GET);
|
|
117
|
+
}
|
|
118
|
+
|
|
106
119
|
/**
|
|
107
120
|
* Writes a change object to the project's workspace
|
|
108
121
|
*
|
|
@@ -123,6 +136,7 @@ sap.ui.define([], function () {
|
|
|
123
136
|
__exports.getManifestAppdescr = getManifestAppdescr;
|
|
124
137
|
__exports.readControllers = readControllers;
|
|
125
138
|
__exports.writeController = writeController;
|
|
139
|
+
__exports.getExistingController = getExistingController;
|
|
126
140
|
__exports.writeChange = writeChange;
|
|
127
141
|
return __exports;
|
|
128
142
|
});
|
|
@@ -4,6 +4,7 @@ export const enum ApiEndpoints {
|
|
|
4
4
|
CHANGES = '/preview/api/changes',
|
|
5
5
|
FRAGMENT = '/adp/api/fragment',
|
|
6
6
|
CONTROLLER = '/adp/api/controller',
|
|
7
|
+
CODE_EXT = '/adp/api/code_ext',
|
|
7
8
|
MANIFEST_APP_DESCRIPTOR = '/manifest.appdescr_variant'
|
|
8
9
|
}
|
|
9
10
|
|
|
@@ -23,6 +24,12 @@ export interface FragmentsResponse {
|
|
|
23
24
|
message: string;
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
export interface CodeExtResponse {
|
|
28
|
+
controllerExists: boolean;
|
|
29
|
+
controllerPath: string;
|
|
30
|
+
controllerPathFromRoot: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
export interface ControllersResponse {
|
|
27
34
|
controllers: Controllers;
|
|
28
35
|
message: string;
|
|
@@ -60,7 +67,9 @@ export async function request<T>(endpoint: ApiEndpoints, method: RequestMethod,
|
|
|
60
67
|
const response: Response = await fetch(endpoint, config);
|
|
61
68
|
|
|
62
69
|
if (!response.ok) {
|
|
63
|
-
|
|
70
|
+
const errorData = await response.json();
|
|
71
|
+
const message = errorData?.message ?? '';
|
|
72
|
+
throw new Error(`Request failed, status: ${response.status}. ${message}`.trim());
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
switch (method) {
|
|
@@ -127,6 +136,16 @@ export async function writeController<T>(data: T): Promise<T> {
|
|
|
127
136
|
return request<T>(ApiEndpoints.CONTROLLER, RequestMethod.POST, data);
|
|
128
137
|
}
|
|
129
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Checks for existing controller in the project's workspace
|
|
141
|
+
*
|
|
142
|
+
* @param controllerName Name of the controller
|
|
143
|
+
* @returns {CodeExtResponse} Returns path to existing controller if found
|
|
144
|
+
*/
|
|
145
|
+
export async function getExistingController(controllerName: string): Promise<CodeExtResponse> {
|
|
146
|
+
return request<CodeExtResponse>(`${ApiEndpoints.CODE_EXT}/${controllerName}` as ApiEndpoints, RequestMethod.GET);
|
|
147
|
+
}
|
|
148
|
+
|
|
130
149
|
/**
|
|
131
150
|
* Writes a change object to the project's workspace
|
|
132
151
|
*
|
|
@@ -9,6 +9,7 @@ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/library", "sap/ui/model/json/J
|
|
|
9
9
|
/** sap.ui.core */
|
|
10
10
|
const ValueState = sap_ui_core_library["ValueState"];
|
|
11
11
|
/** sap.ui.base */
|
|
12
|
+
const getExistingController = ___api_handler["getExistingController"];
|
|
12
13
|
const getManifestAppdescr = ___api_handler["getManifestAppdescr"];
|
|
13
14
|
const readControllers = ___api_handler["readControllers"];
|
|
14
15
|
const writeChange = ___api_handler["writeChange"];
|
|
@@ -65,19 +66,71 @@ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/library", "sap/ui/model/json/J
|
|
|
65
66
|
},
|
|
66
67
|
onCreateBtnPress: async function _onCreateBtnPress(event) {
|
|
67
68
|
const source = event.getSource();
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
const controllerExists = this.model.getProperty('/controllerExists');
|
|
70
|
+
if (!controllerExists) {
|
|
71
|
+
source.setEnabled(false);
|
|
72
|
+
const controllerName = this.model.getProperty('/newControllerName');
|
|
73
|
+
const viewId = this.model.getProperty('/viewId');
|
|
74
|
+
await this.createNewController(controllerName, viewId);
|
|
75
|
+
} else {
|
|
76
|
+
const controllerPath = this.model.getProperty('/controllerPath');
|
|
77
|
+
window.open(`vscode://file${controllerPath}`);
|
|
78
|
+
}
|
|
72
79
|
this.handleDialogClose();
|
|
73
80
|
},
|
|
74
81
|
buildDialogData: async function _buildDialogData() {
|
|
75
82
|
const selectorId = this.overlays.getId();
|
|
76
83
|
const overlayControl = sap.ui.getCore().byId(selectorId);
|
|
84
|
+
const {
|
|
85
|
+
controllerName,
|
|
86
|
+
viewId
|
|
87
|
+
} = this.getControllerInfo(overlayControl);
|
|
88
|
+
const {
|
|
89
|
+
controllerExists,
|
|
90
|
+
controllerPath,
|
|
91
|
+
controllerPathFromRoot
|
|
92
|
+
} = await this.getExistingController(controllerName);
|
|
93
|
+
if (controllerExists) {
|
|
94
|
+
this.updateModelForExistingController(controllerExists, controllerPath, controllerPathFromRoot);
|
|
95
|
+
} else {
|
|
96
|
+
this.updateModelForNewController(viewId);
|
|
97
|
+
await this.getControllers();
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
getControllerInfo: function _getControllerInfo(overlayControl) {
|
|
77
101
|
const control = overlayControl.getElement();
|
|
78
|
-
const
|
|
102
|
+
const view = Utils.getViewForControl(control);
|
|
103
|
+
const controllerName = view.getController().getMetadata().getName();
|
|
104
|
+
const viewId = view.getId();
|
|
105
|
+
return {
|
|
106
|
+
controllerName,
|
|
107
|
+
viewId
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
updateModelForExistingController: function _updateModelForExistingController(controllerExists, controllerPath, controllerPathFromRoot) {
|
|
111
|
+
this.model.setProperty('/controllerExists', controllerExists);
|
|
112
|
+
this.model.setProperty('/controllerPath', controllerPath);
|
|
113
|
+
this.model.setProperty('/controllerPathFromRoot', controllerPathFromRoot);
|
|
114
|
+
const form = this.byId('controllerExtensionDialog_Form');
|
|
115
|
+
form.setVisible(false);
|
|
116
|
+
const messageForm = this.byId('controllerExtensionDialog_Form--existingController');
|
|
117
|
+
messageForm.setVisible(true);
|
|
118
|
+
this.dialog.getBeginButton().setText('Open in VS Code').setEnabled(true);
|
|
119
|
+
this.dialog.getEndButton().setText('Close');
|
|
120
|
+
},
|
|
121
|
+
updateModelForNewController: function _updateModelForNewController(viewId) {
|
|
79
122
|
this.model.setProperty('/viewId', viewId);
|
|
80
|
-
|
|
123
|
+
},
|
|
124
|
+
getExistingController: async function _getExistingController(controllerName) {
|
|
125
|
+
try {
|
|
126
|
+
const data = await getExistingController(controllerName);
|
|
127
|
+
return data;
|
|
128
|
+
} catch (e) {
|
|
129
|
+
MessageToast.show(e.message, {
|
|
130
|
+
duration: 5000
|
|
131
|
+
});
|
|
132
|
+
throw new Error(e.message);
|
|
133
|
+
}
|
|
81
134
|
},
|
|
82
135
|
getControllers: async function _getControllers() {
|
|
83
136
|
try {
|
|
@@ -86,7 +139,9 @@ sap.ui.define(["sap/m/MessageToast", "sap/ui/core/library", "sap/ui/model/json/J
|
|
|
86
139
|
} = await readControllers();
|
|
87
140
|
this.model.setProperty('/controllersList', controllers);
|
|
88
141
|
} catch (e) {
|
|
89
|
-
MessageToast.show(e.message
|
|
142
|
+
MessageToast.show(e.message, {
|
|
143
|
+
duration: 5000
|
|
144
|
+
});
|
|
90
145
|
throw new Error(e.message);
|
|
91
146
|
}
|
|
92
147
|
},
|
|
@@ -20,17 +20,31 @@ import type RuntimeAuthoring from 'sap/ui/rta/RuntimeAuthoring';
|
|
|
20
20
|
/** sap.ui.fl */
|
|
21
21
|
import Utils from 'sap/ui/fl/Utils';
|
|
22
22
|
|
|
23
|
+
/** sap.ui.layout */
|
|
24
|
+
import type SimpleForm from 'sap/ui/layout/form/SimpleForm';
|
|
25
|
+
|
|
23
26
|
/** sap.ui.dt */
|
|
24
27
|
import type ElementOverlay from 'sap/ui/dt/ElementOverlay';
|
|
25
28
|
|
|
26
|
-
import type { ControllersResponse } from '../api-handler';
|
|
27
|
-
import {
|
|
29
|
+
import type { CodeExtResponse, ControllersResponse } from '../api-handler';
|
|
30
|
+
import {
|
|
31
|
+
getExistingController,
|
|
32
|
+
getManifestAppdescr,
|
|
33
|
+
readControllers,
|
|
34
|
+
writeChange,
|
|
35
|
+
writeController
|
|
36
|
+
} from '../api-handler';
|
|
28
37
|
import BaseDialog from './BaseDialog.controller';
|
|
29
38
|
|
|
30
39
|
interface ControllerExtensionService {
|
|
31
40
|
add: (codeRef: string, viewId: string) => Promise<unknown>;
|
|
32
41
|
}
|
|
33
42
|
|
|
43
|
+
interface ControllerInfo {
|
|
44
|
+
controllerName: string;
|
|
45
|
+
viewId: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
34
48
|
/**
|
|
35
49
|
* @namespace open.ux.preview.client.adp.controllers
|
|
36
50
|
*/
|
|
@@ -100,19 +114,15 @@ export default class ControllerExtension extends BaseDialog {
|
|
|
100
114
|
return;
|
|
101
115
|
}
|
|
102
116
|
|
|
103
|
-
|
|
104
|
-
updateDialogState(
|
|
105
|
-
ValueState.Error,
|
|
106
|
-
'A controller file name cannot contain more than 64 characters.'
|
|
107
|
-
);
|
|
117
|
+
if (controllerName.length > 64) {
|
|
118
|
+
updateDialogState(ValueState.Error, 'A controller file name cannot contain more than 64 characters.');
|
|
108
119
|
return;
|
|
109
120
|
}
|
|
110
|
-
|
|
121
|
+
|
|
111
122
|
updateDialogState(ValueState.Success);
|
|
112
123
|
this.model.setProperty('/newControllerName', controllerName);
|
|
113
124
|
}
|
|
114
125
|
|
|
115
|
-
|
|
116
126
|
/**
|
|
117
127
|
* Handles create button press
|
|
118
128
|
*
|
|
@@ -120,28 +130,108 @@ export default class ControllerExtension extends BaseDialog {
|
|
|
120
130
|
*/
|
|
121
131
|
async onCreateBtnPress(event: Event) {
|
|
122
132
|
const source = event.getSource<Button>();
|
|
123
|
-
|
|
133
|
+
const controllerExists = this.model.getProperty('/controllerExists');
|
|
124
134
|
|
|
125
|
-
|
|
126
|
-
|
|
135
|
+
if (!controllerExists) {
|
|
136
|
+
source.setEnabled(false);
|
|
127
137
|
|
|
128
|
-
|
|
138
|
+
const controllerName = this.model.getProperty('/newControllerName');
|
|
139
|
+
const viewId = this.model.getProperty('/viewId');
|
|
140
|
+
|
|
141
|
+
await this.createNewController(controllerName, viewId);
|
|
142
|
+
} else {
|
|
143
|
+
const controllerPath = this.model.getProperty('/controllerPath');
|
|
144
|
+
window.open(`vscode://file${controllerPath}`);
|
|
145
|
+
}
|
|
129
146
|
|
|
130
147
|
this.handleDialogClose();
|
|
131
148
|
}
|
|
132
149
|
|
|
133
150
|
/**
|
|
134
|
-
* Builds data that is used in the dialog
|
|
151
|
+
* Builds data that is used in the dialog.
|
|
135
152
|
*/
|
|
136
153
|
async buildDialogData(): Promise<void> {
|
|
137
154
|
const selectorId = this.overlays.getId();
|
|
138
155
|
const overlayControl = sap.ui.getCore().byId(selectorId) as unknown as ElementOverlay;
|
|
156
|
+
|
|
157
|
+
const { controllerName, viewId } = this.getControllerInfo(overlayControl);
|
|
158
|
+
|
|
159
|
+
const { controllerExists, controllerPath, controllerPathFromRoot } = await this.getExistingController(
|
|
160
|
+
controllerName
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
if (controllerExists) {
|
|
164
|
+
this.updateModelForExistingController(controllerExists, controllerPath, controllerPathFromRoot);
|
|
165
|
+
} else {
|
|
166
|
+
this.updateModelForNewController(viewId);
|
|
167
|
+
|
|
168
|
+
await this.getControllers();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Gets controller name and view ID for the given overlay control.
|
|
174
|
+
*
|
|
175
|
+
* @param overlayControl The overlay control.
|
|
176
|
+
* @returns The controller name and view ID.
|
|
177
|
+
*/
|
|
178
|
+
private getControllerInfo(overlayControl: ElementOverlay): ControllerInfo {
|
|
139
179
|
const control = overlayControl.getElement();
|
|
140
|
-
const
|
|
180
|
+
const view = Utils.getViewForControl(control);
|
|
181
|
+
const controllerName = view.getController().getMetadata().getName();
|
|
182
|
+
const viewId = view.getId();
|
|
183
|
+
return { controllerName, viewId };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Updates the model properties for an existing controller.
|
|
188
|
+
*
|
|
189
|
+
* @param controllerExists Whether the controller exists
|
|
190
|
+
* @param controllerPath The controller path
|
|
191
|
+
* @param controllerPathFromRoot The controller path from the project root
|
|
192
|
+
*/
|
|
193
|
+
private updateModelForExistingController(
|
|
194
|
+
controllerExists: boolean,
|
|
195
|
+
controllerPath: string,
|
|
196
|
+
controllerPathFromRoot: string
|
|
197
|
+
): void {
|
|
198
|
+
this.model.setProperty('/controllerExists', controllerExists);
|
|
199
|
+
this.model.setProperty('/controllerPath', controllerPath);
|
|
200
|
+
this.model.setProperty('/controllerPathFromRoot', controllerPathFromRoot);
|
|
201
|
+
|
|
202
|
+
const form = this.byId('controllerExtensionDialog_Form') as SimpleForm;
|
|
203
|
+
form.setVisible(false);
|
|
204
|
+
|
|
205
|
+
const messageForm = this.byId('controllerExtensionDialog_Form--existingController') as SimpleForm;
|
|
206
|
+
messageForm.setVisible(true);
|
|
207
|
+
|
|
208
|
+
this.dialog.getBeginButton().setText('Open in VS Code').setEnabled(true);
|
|
209
|
+
this.dialog.getEndButton().setText('Close');
|
|
210
|
+
}
|
|
141
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Updates the model property for a new controller.
|
|
214
|
+
*
|
|
215
|
+
* @param viewId The view ID
|
|
216
|
+
*/
|
|
217
|
+
private updateModelForNewController(viewId: string): void {
|
|
142
218
|
this.model.setProperty('/viewId', viewId);
|
|
219
|
+
}
|
|
143
220
|
|
|
144
|
-
|
|
221
|
+
/**
|
|
222
|
+
* Retrieves existing controller data if found in the project's workspace.
|
|
223
|
+
*
|
|
224
|
+
* @param controllerName Controller name that exists in the view
|
|
225
|
+
* @returns Returnsexisting controller data
|
|
226
|
+
*/
|
|
227
|
+
private async getExistingController(controllerName: string): Promise<CodeExtResponse> {
|
|
228
|
+
try {
|
|
229
|
+
const data = await getExistingController(controllerName);
|
|
230
|
+
return data;
|
|
231
|
+
} catch (e) {
|
|
232
|
+
MessageToast.show(e.message, { duration: 5000 });
|
|
233
|
+
throw new Error(e.message);
|
|
234
|
+
}
|
|
145
235
|
}
|
|
146
236
|
|
|
147
237
|
/**
|
|
@@ -152,7 +242,7 @@ export default class ControllerExtension extends BaseDialog {
|
|
|
152
242
|
const { controllers } = await readControllers<ControllersResponse>();
|
|
153
243
|
this.model.setProperty('/controllersList', controllers);
|
|
154
244
|
} catch (e) {
|
|
155
|
-
MessageToast.show(e.message);
|
|
245
|
+
MessageToast.show(e.message, { duration: 5000 });
|
|
156
246
|
throw new Error(e.message);
|
|
157
247
|
}
|
|
158
248
|
}
|
|
@@ -18,6 +18,17 @@
|
|
|
18
18
|
</Input>
|
|
19
19
|
</f:content>
|
|
20
20
|
</f:SimpleForm>
|
|
21
|
+
<f:SimpleForm id="controllerExtensionDialog_Form--existingController"
|
|
22
|
+
editable="true"
|
|
23
|
+
layout="ResponsiveGridLayout"
|
|
24
|
+
labelSpanS="12"
|
|
25
|
+
visible="false"
|
|
26
|
+
singleContainerFullSize="false">
|
|
27
|
+
<f:content>
|
|
28
|
+
<Label text="An existing controller extension has been found. Please use the previously created extension controller" />
|
|
29
|
+
<Text text="{/controllerPathFromRoot}" />
|
|
30
|
+
</f:content>
|
|
31
|
+
</f:SimpleForm>
|
|
21
32
|
</content>
|
|
22
33
|
<beginButton>
|
|
23
34
|
<Button
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
sap.ui.define(["sap/ui/rta/command/CommandFactory"], function (CommandFactory) {
|
|
3
|
+
sap.ui.define(["sap/ui/rta/command/CommandFactory", "./validator"], function (CommandFactory, ___validator) {
|
|
4
4
|
"use strict";
|
|
5
5
|
|
|
6
|
+
const validateBindingModel = ___validator["validateBindingModel"];
|
|
6
7
|
/**
|
|
7
8
|
* Function to check a give value is a binding expression.
|
|
8
9
|
*
|
|
@@ -10,7 +11,7 @@ sap.ui.define(["sap/ui/rta/command/CommandFactory"], function (CommandFactory) {
|
|
|
10
11
|
* @returns boolean
|
|
11
12
|
*/
|
|
12
13
|
function isBindingExpression(value) {
|
|
13
|
-
return value.includes('{') && value.includes('}');
|
|
14
|
+
return value.includes('{') && value.includes('}') && value.indexOf('{') < value.indexOf('}');
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -26,9 +27,15 @@ sap.ui.define(["sap/ui/rta/command/CommandFactory"], function (CommandFactory) {
|
|
|
26
27
|
if (!modifiedControl) {
|
|
27
28
|
return;
|
|
28
29
|
}
|
|
30
|
+
const isBindingString = typeof change.value === 'string' && isBindingExpression(change.value);
|
|
31
|
+
const modifiedControlModifiedProperties = modifiedControl.getMetadata().getAllProperties()[change.propertyName];
|
|
32
|
+
const isBindingModel = isBindingString && modifiedControlModifiedProperties?.type === 'string';
|
|
29
33
|
const flexSettings = rta.getFlexSettings();
|
|
30
|
-
const changeType =
|
|
31
|
-
|
|
34
|
+
const changeType = isBindingString ? 'BindProperty' : 'Property';
|
|
35
|
+
if (isBindingModel) {
|
|
36
|
+
validateBindingModel(change.value);
|
|
37
|
+
}
|
|
38
|
+
const property = isBindingString ? 'newBinding' : 'newValue';
|
|
32
39
|
const modifiedValue = {
|
|
33
40
|
generator: flexSettings.generator,
|
|
34
41
|
propertyName: change.propertyName,
|
|
@@ -2,6 +2,7 @@ import type FlexCommand from 'sap/ui/rta/command/FlexCommand';
|
|
|
2
2
|
import CommandFactory from 'sap/ui/rta/command/CommandFactory';
|
|
3
3
|
import type { PropertyChange } from '@sap-ux-private/control-property-editor-common';
|
|
4
4
|
import type { UI5AdaptationOptions } from '../types';
|
|
5
|
+
import { validateBindingModel } from './validator';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Function to check a give value is a binding expression.
|
|
@@ -10,7 +11,7 @@ import type { UI5AdaptationOptions } from '../types';
|
|
|
10
11
|
* @returns boolean
|
|
11
12
|
*/
|
|
12
13
|
function isBindingExpression(value: string): boolean {
|
|
13
|
-
return value.includes('{') && value.includes('}');
|
|
14
|
+
return value.includes('{') && value.includes('}') && value.indexOf('{') < value.indexOf('}');
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -25,12 +26,17 @@ export async function applyChange(options: UI5AdaptationOptions, change: Propert
|
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
const isBindingString = typeof change.value === 'string' && isBindingExpression(change.value);
|
|
30
|
+
const modifiedControlModifiedProperties = modifiedControl.getMetadata().getAllProperties()[change.propertyName];
|
|
31
|
+
const isBindingModel = isBindingString && modifiedControlModifiedProperties?.type === 'string';
|
|
28
32
|
const flexSettings = rta.getFlexSettings();
|
|
33
|
+
const changeType = isBindingString ? 'BindProperty' : 'Property';
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
if (isBindingModel) {
|
|
36
|
+
validateBindingModel(change.value as string);
|
|
37
|
+
}
|
|
32
38
|
|
|
33
|
-
const property =
|
|
39
|
+
const property = isBindingString ? 'newBinding' : 'newValue';
|
|
34
40
|
const modifiedValue = {
|
|
35
41
|
generator: flexSettings.generator,
|
|
36
42
|
propertyName: change.propertyName,
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
sap.ui.define(["sap/base/i18n/ResourceBundle"], function (ResourceBundle) {
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Function to validate if a given value is a valid binding model.
|
|
8
|
+
*
|
|
9
|
+
* @param value value to be checked.
|
|
10
|
+
*/
|
|
11
|
+
function validateBindingModel(value) {
|
|
12
|
+
const bindingValue = value.replace(/[{}]/gi, '').trim();
|
|
13
|
+
const bindingParts = bindingValue.split('>').filter(el => el != '');
|
|
14
|
+
if (!bindingParts.length) {
|
|
15
|
+
throw new SyntaxError('Invalid binding string.');
|
|
16
|
+
}
|
|
17
|
+
if (bindingParts[0].trim() === 'i18n') {
|
|
18
|
+
if (bindingParts.length === 2) {
|
|
19
|
+
const resourceBundle = ResourceBundle.create({
|
|
20
|
+
url: '../i18n/i18n.properties'
|
|
21
|
+
});
|
|
22
|
+
const resourceKey = bindingParts[1].trim();
|
|
23
|
+
if (!resourceBundle.hasText(resourceKey)) {
|
|
24
|
+
throw new SyntaxError('Invalid key in the binding string. Supported value pattern is {i18n>YOUR_KEY}. Check if the key already exists in i18n.properties. If not, add the key in the i18n.properties file and reload the editor for the new key to take effect.');
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
throw new SyntaxError('Invalid binding string. Supported value pattern is {i18n>YOUR_KEY}');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
var __exports = {
|
|
32
|
+
__esModule: true
|
|
33
|
+
};
|
|
34
|
+
__exports.validateBindingModel = validateBindingModel;
|
|
35
|
+
return __exports;
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import ResourceBundle from 'sap/base/i18n/ResourceBundle';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Function to validate if a given value is a valid binding model.
|
|
5
|
+
*
|
|
6
|
+
* @param value value to be checked.
|
|
7
|
+
*/
|
|
8
|
+
export function validateBindingModel(value: string): void {
|
|
9
|
+
const bindingValue = value.replace(/[{}]/gi, '').trim();
|
|
10
|
+
const bindingParts = bindingValue.split('>').filter((el) => el != '');
|
|
11
|
+
|
|
12
|
+
if (!bindingParts.length) {
|
|
13
|
+
throw new SyntaxError('Invalid binding string.');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (bindingParts[0].trim() === 'i18n') {
|
|
17
|
+
if (bindingParts.length === 2) {
|
|
18
|
+
const resourceBundle = ResourceBundle.create({
|
|
19
|
+
url: '../i18n/i18n.properties'
|
|
20
|
+
}) as ResourceBundle;
|
|
21
|
+
const resourceKey = bindingParts[1].trim();
|
|
22
|
+
if (!resourceBundle.hasText(resourceKey)) {
|
|
23
|
+
throw new SyntaxError(
|
|
24
|
+
'Invalid key in the binding string. Supported value pattern is {i18n>YOUR_KEY}. Check if the key already exists in i18n.properties. If not, add the key in the i18n.properties file and reload the editor for the new key to take effect.'
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
throw new SyntaxError('Invalid binding string. Supported value pattern is {i18n>YOUR_KEY}');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"bugs": {
|
|
10
10
|
"url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Apreview-middleware"
|
|
11
11
|
},
|
|
12
|
-
"version": "0.
|
|
12
|
+
"version": "0.11.1",
|
|
13
13
|
"license": "Apache-2.0",
|
|
14
14
|
"author": "@SAP/ux-tools-team",
|
|
15
15
|
"main": "dist/index.js",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"ejs": "3.1.9",
|
|
26
26
|
"@sap-ux/logger": "0.4.0",
|
|
27
|
-
"@sap-ux/adp-tooling": "0.
|
|
27
|
+
"@sap-ux/adp-tooling": "0.6.0",
|
|
28
28
|
"@sap-ux/control-property-editor-sources": "npm:@sap-ux/control-property-editor@0.4.2"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"npm-run-all": "4.1.5",
|
|
37
37
|
"nock": "13.2.1",
|
|
38
38
|
"supertest": "6.3.3",
|
|
39
|
-
"@private/preview-middleware-client": "npm:@sap-ux-private/preview-middleware-client@0.
|
|
40
|
-
"@sap-ux/project-access": "1.15.
|
|
39
|
+
"@private/preview-middleware-client": "npm:@sap-ux-private/preview-middleware-client@0.8.1",
|
|
40
|
+
"@sap-ux/project-access": "1.15.2",
|
|
41
41
|
"@sap-ux/store": "0.4.0"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|