@sap-ux/preview-middleware 0.17.20 → 0.17.23
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/README.md +1 -1
- package/dist/base/config.js +5 -0
- package/dist/base/flp.d.ts +95 -1
- package/dist/base/flp.js +277 -159
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -188,7 +188,7 @@ return flp.router
|
|
|
188
188
|
|
|
189
189
|
|
|
190
190
|
## [Migration](#migration)
|
|
191
|
-
If you have no custom modifications in the local Fiori Launchpad sandbox files (
|
|
191
|
+
If you have no custom modifications in the local Fiori Launchpad sandbox files (`<webapp>/test/flpSandbox.html` or `<webapp>/test/flpSandboxMockserver.html`), the conversion is finished.
|
|
192
192
|
|
|
193
193
|
If you have custom modifications in the local Fiori Launchpad sandbox files, you need to migrate them into a custom .js or .ts file (depending on your setup) and integrate this file as a custom `init` script into the configuration options of the middleware.
|
|
194
194
|
|
package/dist/base/config.js
CHANGED
|
@@ -160,6 +160,11 @@ function getFlexSettings() {
|
|
|
160
160
|
*/
|
|
161
161
|
async function addApp(templateConfig, manifest, app, logger) {
|
|
162
162
|
const id = manifest['sap.app']?.id ?? '';
|
|
163
|
+
if (manifest['sap.app']?.type === 'component') {
|
|
164
|
+
logger.debug(`No application added for id '${id}' because its type is 'component'`);
|
|
165
|
+
templateConfig.apps = templateConfig.apps ?? {};
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
163
168
|
const appName = getAppName(manifest, app.intent);
|
|
164
169
|
templateConfig.ui5.resources[id] = app.target;
|
|
165
170
|
templateConfig.apps[appName] = {
|
package/dist/base/flp.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Editor as MemFsEditor } from 'mem-fs-editor';
|
|
|
3
3
|
import type { Router } from 'express';
|
|
4
4
|
import type { Logger, ToolsLogger } from '@sap-ux/logger';
|
|
5
5
|
import type { MiddlewareUtils } from '@ui5/server';
|
|
6
|
-
import type
|
|
6
|
+
import { type Manifest } from '@sap-ux/project-access';
|
|
7
7
|
import { AdpPreview, type AdpPreviewConfig, type CommonChangeProperties, type OperationType } from '@sap-ux/adp-tooling';
|
|
8
8
|
import type { FlpConfig, MiddlewareConfig, RtaConfig, TestConfig } from '../types';
|
|
9
9
|
import { type TemplateConfig } from './config';
|
|
@@ -29,6 +29,7 @@ export declare class FlpSandbox {
|
|
|
29
29
|
readonly rta?: RtaConfig;
|
|
30
30
|
readonly test?: TestConfig[];
|
|
31
31
|
readonly router: EnhancedRouter;
|
|
32
|
+
private fs;
|
|
32
33
|
/**
|
|
33
34
|
* Constructor setting defaults and keeping reference to workspace resources.
|
|
34
35
|
*
|
|
@@ -77,12 +78,41 @@ export declare class FlpSandbox {
|
|
|
77
78
|
* @returns Promise that resolves when the application dependencies are set
|
|
78
79
|
*/
|
|
79
80
|
private setApplicationDependencies;
|
|
81
|
+
/**
|
|
82
|
+
* Handler for the GET requests to the runtime adaptation editor in developer mode.
|
|
83
|
+
*
|
|
84
|
+
* @param res the response
|
|
85
|
+
* @param rta runtime adaptation configuration
|
|
86
|
+
* @param previewUrl the url of the preview
|
|
87
|
+
* @private
|
|
88
|
+
*/
|
|
89
|
+
private editorGetHandlerDeveloperMode;
|
|
90
|
+
/**
|
|
91
|
+
* Handler for the GET requests to the runtime adaptation editor.
|
|
92
|
+
*
|
|
93
|
+
* @param req the request
|
|
94
|
+
* @param res the response
|
|
95
|
+
* @param rta runtime adaptation configuration
|
|
96
|
+
* @param previewUrl the url of the preview
|
|
97
|
+
* @param editor editor configuration
|
|
98
|
+
* @private
|
|
99
|
+
*/
|
|
100
|
+
private editorGetHandler;
|
|
80
101
|
/**
|
|
81
102
|
* Add additional routes for configured editors.
|
|
82
103
|
*
|
|
83
104
|
* @param rta runtime authoring configuration
|
|
84
105
|
*/
|
|
85
106
|
private addEditorRoutes;
|
|
107
|
+
/**
|
|
108
|
+
* Handler for the GET requests to the FLP.
|
|
109
|
+
*
|
|
110
|
+
* @param req the request
|
|
111
|
+
* @param res the response
|
|
112
|
+
* @param next the next function
|
|
113
|
+
* @private
|
|
114
|
+
*/
|
|
115
|
+
private flpGetHandler;
|
|
86
116
|
/**
|
|
87
117
|
* Add routes for html and scripts required for a local FLP.
|
|
88
118
|
*/
|
|
@@ -120,10 +150,53 @@ export declare class FlpSandbox {
|
|
|
120
150
|
* Add additional routes for apps also to be shown in the local FLP.
|
|
121
151
|
*/
|
|
122
152
|
private addRoutesForAdditionalApps;
|
|
153
|
+
/**
|
|
154
|
+
* Handler for flex changes GET requests.
|
|
155
|
+
*
|
|
156
|
+
* @param res the response
|
|
157
|
+
* @private
|
|
158
|
+
*/
|
|
159
|
+
private flexGetHandler;
|
|
160
|
+
/**
|
|
161
|
+
* Handler for flex changes POST requests.
|
|
162
|
+
*
|
|
163
|
+
* @param req the request
|
|
164
|
+
* @param res the response
|
|
165
|
+
* @private
|
|
166
|
+
*/
|
|
167
|
+
private flexPostHandler;
|
|
168
|
+
/**
|
|
169
|
+
* Handler for flex changes DELETE requests.
|
|
170
|
+
*
|
|
171
|
+
* @param req the request
|
|
172
|
+
* @param res the response
|
|
173
|
+
* @private
|
|
174
|
+
*/
|
|
175
|
+
private flexDeleteHandler;
|
|
123
176
|
/**
|
|
124
177
|
* Create required routes for flex.
|
|
125
178
|
*/
|
|
126
179
|
private createFlexHandler;
|
|
180
|
+
/**
|
|
181
|
+
* Handler for the GET requests to the HTML of the test suite.
|
|
182
|
+
*
|
|
183
|
+
* @param res the response
|
|
184
|
+
* @param testsuite the test suite template
|
|
185
|
+
* @param config the test configuration
|
|
186
|
+
* @private
|
|
187
|
+
*/
|
|
188
|
+
private testSuiteHtmlGetHandler;
|
|
189
|
+
/**
|
|
190
|
+
* Handler for the GET requests to the JS of the test suite.
|
|
191
|
+
*
|
|
192
|
+
* @param res the response
|
|
193
|
+
* @param next the next function
|
|
194
|
+
* @param config the test configuration
|
|
195
|
+
* @param initTemplate the test runner template
|
|
196
|
+
* @param testPaths the paths to the test files
|
|
197
|
+
* @private
|
|
198
|
+
*/
|
|
199
|
+
private testSuiteJsGetHandler;
|
|
127
200
|
/**
|
|
128
201
|
* If it is part of TestConfig, create a test suite for the test configurations.
|
|
129
202
|
*
|
|
@@ -142,6 +215,27 @@ export declare class FlpSandbox {
|
|
|
142
215
|
* @private
|
|
143
216
|
*/
|
|
144
217
|
private sendResponse;
|
|
218
|
+
/**
|
|
219
|
+
* Handler for the GET requests to the HTML of the test runner.
|
|
220
|
+
*
|
|
221
|
+
* @param res the response
|
|
222
|
+
* @param next the next function
|
|
223
|
+
* @param config test configuration
|
|
224
|
+
* @param htmlTemplate the test runner template
|
|
225
|
+
* @param id application id from manifest
|
|
226
|
+
*/
|
|
227
|
+
private testRunnerHtmlGetHandler;
|
|
228
|
+
/**
|
|
229
|
+
* Handler for the GET requests to the JS of the test runner.
|
|
230
|
+
*
|
|
231
|
+
* @param res the response
|
|
232
|
+
* @param next the next function
|
|
233
|
+
* @param config test configuration
|
|
234
|
+
* @param initTemplate the test runner template
|
|
235
|
+
* @param ns namespace for the test files
|
|
236
|
+
* @private
|
|
237
|
+
*/
|
|
238
|
+
private testRunnerJsGetHandler;
|
|
145
239
|
/**
|
|
146
240
|
* Add routes for html and scripts required for a local test FLP.
|
|
147
241
|
*
|
package/dist/base/flp.js
CHANGED
|
@@ -4,10 +4,11 @@ exports.FlpSandbox = void 0;
|
|
|
4
4
|
exports.initAdp = initAdp;
|
|
5
5
|
const mem_fs_1 = require("mem-fs");
|
|
6
6
|
const mem_fs_editor_1 = require("mem-fs-editor");
|
|
7
|
-
const ejs_1 = require("ejs");
|
|
8
7
|
const fs_1 = require("fs");
|
|
9
|
-
const
|
|
8
|
+
const ejs_1 = require("ejs");
|
|
10
9
|
const express_1 = require("express");
|
|
10
|
+
const path_1 = require("path");
|
|
11
|
+
const project_access_1 = require("@sap-ux/project-access");
|
|
11
12
|
const adp_tooling_1 = require("@sap-ux/adp-tooling");
|
|
12
13
|
const btp_utils_1 = require("@sap-ux/btp-utils");
|
|
13
14
|
const feature_toggle_1 = require("@sap-ux/feature-toggle");
|
|
@@ -30,6 +31,7 @@ class FlpSandbox {
|
|
|
30
31
|
rta;
|
|
31
32
|
test;
|
|
32
33
|
router;
|
|
34
|
+
fs;
|
|
33
35
|
/**
|
|
34
36
|
* Constructor setting defaults and keeping reference to workspace resources.
|
|
35
37
|
*
|
|
@@ -173,6 +175,61 @@ class FlpSandbox {
|
|
|
173
175
|
this.templateConfig.apps[appName].applicationDependencies = this.adp.descriptor;
|
|
174
176
|
}
|
|
175
177
|
}
|
|
178
|
+
/**
|
|
179
|
+
* Handler for the GET requests to the runtime adaptation editor in developer mode.
|
|
180
|
+
*
|
|
181
|
+
* @param res the response
|
|
182
|
+
* @param rta runtime adaptation configuration
|
|
183
|
+
* @param previewUrl the url of the preview
|
|
184
|
+
* @private
|
|
185
|
+
*/
|
|
186
|
+
async editorGetHandlerDeveloperMode(res, rta, previewUrl) {
|
|
187
|
+
const scenario = rta.options?.scenario;
|
|
188
|
+
let templatePreviewUrl = `${previewUrl}?sap-ui-xx-viewCache=false&fiori-tools-rta-mode=forAdaptation&sap-ui-rta-skip-flex-validation=true&sap-ui-xx-condense-changes=true#${this.config.intent.object}-${this.config.intent.action}`;
|
|
189
|
+
if (scenario === 'ADAPTATION_PROJECT') {
|
|
190
|
+
templatePreviewUrl = templatePreviewUrl.replace('?', `?sap-ui-layer=${rta.layer}&`);
|
|
191
|
+
}
|
|
192
|
+
const template = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/flp/editor.html'), 'utf-8');
|
|
193
|
+
const features = feature_toggle_1.FeatureToggleAccess.getAllFeatureToggles();
|
|
194
|
+
const envPort = process.env.FIORI_TOOLS_LIVERELOAD_PORT;
|
|
195
|
+
let livereloadPort = envPort ? parseInt(envPort, 10) : DEFAULT_LIVERELOAD_PORT;
|
|
196
|
+
livereloadPort = isNaN(livereloadPort) ? DEFAULT_LIVERELOAD_PORT : livereloadPort;
|
|
197
|
+
const envLivereloadUrl = (0, btp_utils_1.isAppStudio)() ? await (0, btp_utils_1.exposePort)(livereloadPort) : undefined;
|
|
198
|
+
const html = (0, ejs_1.render)(template, {
|
|
199
|
+
previewUrl: templatePreviewUrl,
|
|
200
|
+
telemetry: rta.options?.telemetry ?? false,
|
|
201
|
+
appName: rta.options?.appName,
|
|
202
|
+
scenario,
|
|
203
|
+
livereloadPort,
|
|
204
|
+
livereloadUrl: envLivereloadUrl,
|
|
205
|
+
features: JSON.stringify(features)
|
|
206
|
+
});
|
|
207
|
+
this.sendResponse(res, 'text/html', 200, html);
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Handler for the GET requests to the runtime adaptation editor.
|
|
211
|
+
*
|
|
212
|
+
* @param req the request
|
|
213
|
+
* @param res the response
|
|
214
|
+
* @param rta runtime adaptation configuration
|
|
215
|
+
* @param previewUrl the url of the preview
|
|
216
|
+
* @param editor editor configuration
|
|
217
|
+
* @private
|
|
218
|
+
*/
|
|
219
|
+
async editorGetHandler(req, res, rta, previewUrl, editor) {
|
|
220
|
+
if (!req.query['fiori-tools-rta-mode']) {
|
|
221
|
+
// Redirect to the same URL but add the necessary parameter
|
|
222
|
+
const params = structuredClone(req.query);
|
|
223
|
+
params['sap-ui-xx-viewCache'] = 'false';
|
|
224
|
+
params['fiori-tools-rta-mode'] = 'true';
|
|
225
|
+
params['sap-ui-rta-skip-flex-validation'] = 'true';
|
|
226
|
+
params['sap-ui-xx-condense-changes'] = 'true';
|
|
227
|
+
res.redirect(302, `${previewUrl}?${new URLSearchParams(params)}`);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const html = (await this.generateSandboxForEditor(req, rta, editor)).replace('</body>', `</body>\n<!-- livereload disabled for editor </body>-->`);
|
|
231
|
+
this.sendResponse(res, 'text/html', 200, html);
|
|
232
|
+
}
|
|
176
233
|
/**
|
|
177
234
|
* Add additional routes for configured editors.
|
|
178
235
|
*
|
|
@@ -186,27 +243,7 @@ class FlpSandbox {
|
|
|
186
243
|
previewUrl = `${previewUrl}.inner.html`;
|
|
187
244
|
editor.pluginScript ??= 'open/ux/preview/client/cpe/init';
|
|
188
245
|
this.router.get(editor.path, async (_req, res) => {
|
|
189
|
-
|
|
190
|
-
let templatePreviewUrl = `${previewUrl}?sap-ui-xx-viewCache=false&fiori-tools-rta-mode=forAdaptation&sap-ui-rta-skip-flex-validation=true&sap-ui-xx-condense-changes=true#${this.config.intent.object}-${this.config.intent.action}`;
|
|
191
|
-
if (scenario === 'ADAPTATION_PROJECT') {
|
|
192
|
-
templatePreviewUrl = templatePreviewUrl.replace('?', `?sap-ui-layer=${rta.layer}&`);
|
|
193
|
-
}
|
|
194
|
-
const template = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/flp/editor.html'), 'utf-8');
|
|
195
|
-
const features = feature_toggle_1.FeatureToggleAccess.getAllFeatureToggles();
|
|
196
|
-
const envPort = process.env.FIORI_TOOLS_LIVERELOAD_PORT;
|
|
197
|
-
let livereloadPort = envPort ? parseInt(envPort, 10) : DEFAULT_LIVERELOAD_PORT;
|
|
198
|
-
livereloadPort = isNaN(livereloadPort) ? DEFAULT_LIVERELOAD_PORT : livereloadPort;
|
|
199
|
-
const envLivereloadUrl = (0, btp_utils_1.isAppStudio)() ? await (0, btp_utils_1.exposePort)(livereloadPort) : undefined;
|
|
200
|
-
const html = (0, ejs_1.render)(template, {
|
|
201
|
-
previewUrl: templatePreviewUrl,
|
|
202
|
-
telemetry: rta.options?.telemetry ?? false,
|
|
203
|
-
appName: rta.options?.appName,
|
|
204
|
-
scenario,
|
|
205
|
-
livereloadPort,
|
|
206
|
-
livereloadUrl: envLivereloadUrl,
|
|
207
|
-
features: JSON.stringify(features)
|
|
208
|
-
});
|
|
209
|
-
this.sendResponse(res, 'text/html', 200, html);
|
|
246
|
+
await this.editorGetHandlerDeveloperMode(res, rta, previewUrl);
|
|
210
247
|
});
|
|
211
248
|
let path = (0, path_1.dirname)(editor.path);
|
|
212
249
|
if (!path.endsWith('/')) {
|
|
@@ -215,21 +252,45 @@ class FlpSandbox {
|
|
|
215
252
|
this.router.use(`${path}editor`, (0, express_1.static)(cpe));
|
|
216
253
|
}
|
|
217
254
|
this.router.get(previewUrl, async (req, res) => {
|
|
218
|
-
|
|
219
|
-
// Redirect to the same URL but add the necessary parameter
|
|
220
|
-
const params = structuredClone(req.query);
|
|
221
|
-
params['sap-ui-xx-viewCache'] = 'false';
|
|
222
|
-
params['fiori-tools-rta-mode'] = 'true';
|
|
223
|
-
params['sap-ui-rta-skip-flex-validation'] = 'true';
|
|
224
|
-
params['sap-ui-xx-condense-changes'] = 'true';
|
|
225
|
-
res.redirect(302, `${previewUrl}?${new URLSearchParams(params)}`);
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
const html = (await this.generateSandboxForEditor(req, rta, editor)).replace('</body>', `</body>\n<!-- livereload disabled for editor </body>-->`);
|
|
229
|
-
this.sendResponse(res, 'text/html', 200, html);
|
|
255
|
+
await this.editorGetHandler(req, res, rta, previewUrl, editor);
|
|
230
256
|
});
|
|
231
257
|
}
|
|
232
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Handler for the GET requests to the FLP.
|
|
261
|
+
*
|
|
262
|
+
* @param req the request
|
|
263
|
+
* @param res the response
|
|
264
|
+
* @param next the next function
|
|
265
|
+
* @private
|
|
266
|
+
*/
|
|
267
|
+
async flpGetHandler(req, res, next) {
|
|
268
|
+
// connect API (karma test runner) has no request query property
|
|
269
|
+
if ('query' in req && 'redirect' in res && !req.query['sap-ui-xx-viewCache']) {
|
|
270
|
+
// Redirect to the same URL but add the necessary parameter
|
|
271
|
+
const params = structuredClone(req.query);
|
|
272
|
+
params['sap-ui-xx-viewCache'] = 'false';
|
|
273
|
+
res.redirect(302, `${this.config.path}?${new URLSearchParams(params)}`);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
await this.setApplicationDependencies();
|
|
277
|
+
// inform the user if a html file exists on the filesystem
|
|
278
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
279
|
+
const file = await this.project.byPath(this.config.path);
|
|
280
|
+
if (file) {
|
|
281
|
+
this.logger.info(`HTML file returned at ${this.config.path} is loaded from the file system.`);
|
|
282
|
+
next();
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
const ui5Version = await this.getUi5Version(
|
|
286
|
+
//use protocol from request header referer as fallback for connect API (karma test runner)
|
|
287
|
+
'protocol' in req
|
|
288
|
+
? req.protocol
|
|
289
|
+
: req.headers.referer?.substring(0, req.headers.referer.indexOf(':')) ?? 'http', req.headers.host, 'ui5-patched-router' in req ? req['ui5-patched-router']?.baseUrl : undefined);
|
|
290
|
+
const html = (0, ejs_1.render)(this.getSandboxTemplate(ui5Version.major), this.templateConfig);
|
|
291
|
+
this.sendResponse(res, 'text/html', 200, html);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
233
294
|
/**
|
|
234
295
|
* Add routes for html and scripts required for a local FLP.
|
|
235
296
|
*/
|
|
@@ -237,33 +298,9 @@ class FlpSandbox {
|
|
|
237
298
|
// register static client sources
|
|
238
299
|
this.router.use(config_1.PREVIEW_URL.client.path, (0, express_1.static)(config_1.PREVIEW_URL.client.local));
|
|
239
300
|
// add route for the sandbox html
|
|
240
|
-
this.router.get(this.config.path,
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
// Redirect to the same URL but add the necessary parameter
|
|
244
|
-
const params = structuredClone(req.query);
|
|
245
|
-
params['sap-ui-xx-viewCache'] = 'false';
|
|
246
|
-
res.redirect(302, `${this.config.path}?${new URLSearchParams(params)}`);
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
await this.setApplicationDependencies();
|
|
250
|
-
// inform the user if a html file exists on the filesystem
|
|
251
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
252
|
-
const file = await this.project.byPath(this.config.path);
|
|
253
|
-
if (file) {
|
|
254
|
-
this.logger.info(`HTML file returned at ${this.config.path} is loaded from the file system.`);
|
|
255
|
-
next();
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
const ui5Version = await this.getUi5Version(
|
|
259
|
-
//use protocol from request header referer as fallback for connect API (karma test runner)
|
|
260
|
-
'protocol' in req
|
|
261
|
-
? req.protocol
|
|
262
|
-
: req.headers.referer?.substring(0, req.headers.referer.indexOf(':')) ?? 'http', req.headers.host, 'ui5-patched-router' in req ? req['ui5-patched-router']?.baseUrl : undefined);
|
|
263
|
-
const html = (0, ejs_1.render)(this.getSandboxTemplate(ui5Version.major), this.templateConfig);
|
|
264
|
-
this.sendResponse(res, 'text/html', 200, html);
|
|
265
|
-
}
|
|
266
|
-
}));
|
|
301
|
+
this.router.get(this.config.path, async (req, res, next) => {
|
|
302
|
+
await this.flpGetHandler(req, res, next);
|
|
303
|
+
});
|
|
267
304
|
}
|
|
268
305
|
/**
|
|
269
306
|
* Read the UI5 version.
|
|
@@ -338,8 +375,10 @@ class FlpSandbox {
|
|
|
338
375
|
for (const app of this.config.apps) {
|
|
339
376
|
let manifest;
|
|
340
377
|
if (app.local) {
|
|
341
|
-
|
|
342
|
-
|
|
378
|
+
this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
|
|
379
|
+
const webappPath = await (0, project_access_1.getWebappPath)(app.local, this.fs);
|
|
380
|
+
manifest = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(webappPath, 'manifest.json'), 'utf-8'));
|
|
381
|
+
this.router.use(app.target, (0, express_1.static)(webappPath));
|
|
343
382
|
this.logger.info(`Serving additional application at ${app.target} from ${app.local}`);
|
|
344
383
|
}
|
|
345
384
|
else if (app.componentId) {
|
|
@@ -360,53 +399,125 @@ class FlpSandbox {
|
|
|
360
399
|
}
|
|
361
400
|
}
|
|
362
401
|
/**
|
|
363
|
-
*
|
|
402
|
+
* Handler for flex changes GET requests.
|
|
403
|
+
*
|
|
404
|
+
* @param res the response
|
|
405
|
+
* @private
|
|
364
406
|
*/
|
|
365
|
-
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
407
|
+
async flexGetHandler(res) {
|
|
408
|
+
const changes = await (0, flex_1.readChanges)(this.project, this.logger);
|
|
409
|
+
if (this.onChangeRequest) {
|
|
410
|
+
this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
|
|
411
|
+
for (const change of Object.values(changes)) {
|
|
412
|
+
await this.onChangeRequest('read', change, this.fs, this.logger);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
this.sendResponse(res, 'application/json', 200, JSON.stringify(changes));
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Handler for flex changes POST requests.
|
|
419
|
+
*
|
|
420
|
+
* @param req the request
|
|
421
|
+
* @param res the response
|
|
422
|
+
* @private
|
|
423
|
+
*/
|
|
424
|
+
async flexPostHandler(req, res) {
|
|
425
|
+
this.fs = this.fs ?? (0, mem_fs_editor_1.create)((0, mem_fs_1.create)());
|
|
426
|
+
try {
|
|
427
|
+
const change = req.body;
|
|
371
428
|
if (this.onChangeRequest) {
|
|
372
|
-
|
|
373
|
-
await this.onChangeRequest('read', change, fs, this.logger);
|
|
374
|
-
}
|
|
429
|
+
await this.onChangeRequest('write', change, this.fs, this.logger);
|
|
375
430
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
try {
|
|
380
|
-
const change = req.body;
|
|
381
|
-
if (this.onChangeRequest) {
|
|
382
|
-
await this.onChangeRequest('write', change, fs, this.logger);
|
|
383
|
-
}
|
|
384
|
-
const { success, message } = (0, flex_1.writeChange)(change, this.utils.getProject().getSourcePath(), fs, this.logger);
|
|
385
|
-
if (success) {
|
|
386
|
-
fs.commit(() => this.sendResponse(res, 'text/plain', 200, message ?? ''));
|
|
387
|
-
}
|
|
388
|
-
else {
|
|
389
|
-
this.sendResponse(res, 'text/plain', 400, 'INVALID_DATA');
|
|
390
|
-
}
|
|
431
|
+
const { success, message } = (0, flex_1.writeChange)(change, this.utils.getProject().getSourcePath(), this.fs, this.logger);
|
|
432
|
+
if (success) {
|
|
433
|
+
this.fs.commit(() => this.sendResponse(res, 'text/plain', 200, message ?? ''));
|
|
391
434
|
}
|
|
392
|
-
|
|
393
|
-
this.sendResponse(res, 'text/plain',
|
|
435
|
+
else {
|
|
436
|
+
this.sendResponse(res, 'text/plain', 400, 'INVALID_DATA');
|
|
394
437
|
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
438
|
+
}
|
|
439
|
+
catch (error) {
|
|
440
|
+
this.sendResponse(res, 'text/plain', 500, error.message);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Handler for flex changes DELETE requests.
|
|
445
|
+
*
|
|
446
|
+
* @param req the request
|
|
447
|
+
* @param res the response
|
|
448
|
+
* @private
|
|
449
|
+
*/
|
|
450
|
+
async flexDeleteHandler(req, res) {
|
|
451
|
+
try {
|
|
452
|
+
const { success, message } = (0, flex_1.deleteChange)(req.body, this.utils.getProject().getSourcePath(), this.logger);
|
|
453
|
+
if (success) {
|
|
454
|
+
this.sendResponse(res, 'text/plain', 200, message ?? '');
|
|
405
455
|
}
|
|
406
|
-
|
|
407
|
-
this.sendResponse(res, 'text/plain',
|
|
456
|
+
else {
|
|
457
|
+
this.sendResponse(res, 'text/plain', 400, 'INVALID_DATA');
|
|
408
458
|
}
|
|
409
|
-
}
|
|
459
|
+
}
|
|
460
|
+
catch (error) {
|
|
461
|
+
this.sendResponse(res, 'text/plain', 500, error.message);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Create required routes for flex.
|
|
466
|
+
*/
|
|
467
|
+
createFlexHandler() {
|
|
468
|
+
const api = `${config_1.PREVIEW_URL.api}/changes`;
|
|
469
|
+
this.router.use(api, (0, express_1.json)());
|
|
470
|
+
this.router.get(api, async (_req, res) => {
|
|
471
|
+
await this.flexGetHandler(res);
|
|
472
|
+
});
|
|
473
|
+
this.router.post(api, async (req, res) => {
|
|
474
|
+
await this.flexPostHandler(req, res);
|
|
475
|
+
});
|
|
476
|
+
this.router.delete(api, async (req, res) => {
|
|
477
|
+
await this.flexDeleteHandler(req, res);
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Handler for the GET requests to the HTML of the test suite.
|
|
482
|
+
*
|
|
483
|
+
* @param res the response
|
|
484
|
+
* @param testsuite the test suite template
|
|
485
|
+
* @param config the test configuration
|
|
486
|
+
* @private
|
|
487
|
+
*/
|
|
488
|
+
async testSuiteHtmlGetHandler(res, testsuite, config) {
|
|
489
|
+
this.logger.debug(`Serving test route: ${config.path}`);
|
|
490
|
+
const templateConfig = {
|
|
491
|
+
basePath: this.templateConfig.basePath,
|
|
492
|
+
initPath: config.init
|
|
493
|
+
};
|
|
494
|
+
const html = (0, ejs_1.render)(testsuite, templateConfig);
|
|
495
|
+
this.sendResponse(res, 'text/html', 200, html);
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Handler for the GET requests to the JS of the test suite.
|
|
499
|
+
*
|
|
500
|
+
* @param res the response
|
|
501
|
+
* @param next the next function
|
|
502
|
+
* @param config the test configuration
|
|
503
|
+
* @param initTemplate the test runner template
|
|
504
|
+
* @param testPaths the paths to the test files
|
|
505
|
+
* @private
|
|
506
|
+
*/
|
|
507
|
+
async testSuiteJsGetHandler(res, next, config, initTemplate, testPaths) {
|
|
508
|
+
const files = await this.project.byGlob(config.init.replace('.js', '.[jt]s'));
|
|
509
|
+
if (files?.length > 0) {
|
|
510
|
+
this.logger.warn(`Script returned at ${config.path} is loaded from the file system.`);
|
|
511
|
+
next();
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
this.logger.debug(`Serving test route: ${config.init}`);
|
|
515
|
+
const templateConfig = {
|
|
516
|
+
testPaths: testPaths
|
|
517
|
+
};
|
|
518
|
+
const js = (0, ejs_1.render)(initTemplate, templateConfig);
|
|
519
|
+
this.sendResponse(res, 'application/javascript', 200, js);
|
|
520
|
+
}
|
|
410
521
|
}
|
|
411
522
|
/**
|
|
412
523
|
* If it is part of TestConfig, create a test suite for the test configurations.
|
|
@@ -425,18 +536,11 @@ class FlpSandbox {
|
|
|
425
536
|
return;
|
|
426
537
|
}
|
|
427
538
|
const testsuite = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/testsuite.qunit.html'), 'utf-8');
|
|
428
|
-
const initTemplate = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/testsuite.qunit.js'), 'utf-8');
|
|
429
539
|
const config = (0, test_1.mergeTestConfigDefaults)(testsuiteConfig);
|
|
430
540
|
this.logger.debug(`Add route for ${config.path}`);
|
|
431
|
-
this.router.get(config.path,
|
|
432
|
-
this.
|
|
433
|
-
|
|
434
|
-
basePath: this.templateConfig.basePath,
|
|
435
|
-
initPath: config.init
|
|
436
|
-
};
|
|
437
|
-
const html = (0, ejs_1.render)(testsuite, templateConfig);
|
|
438
|
-
this.sendResponse(res, 'text/html', 200, html);
|
|
439
|
-
}));
|
|
541
|
+
this.router.get(config.path, async (_req, res) => {
|
|
542
|
+
await this.testSuiteHtmlGetHandler(res, testsuite, config);
|
|
543
|
+
});
|
|
440
544
|
if (testsuiteConfig.init !== undefined) {
|
|
441
545
|
this.logger.debug(`Skip serving testsuite init script in favor of provided script: ${testsuiteConfig.init}`);
|
|
442
546
|
return;
|
|
@@ -449,22 +553,11 @@ class FlpSandbox {
|
|
|
449
553
|
const mergedConfig = (0, test_1.mergeTestConfigDefaults)(testConfig);
|
|
450
554
|
testPaths.push(path_1.posix.relative(path_1.posix.dirname(config.path), mergedConfig.path));
|
|
451
555
|
}
|
|
556
|
+
const initTemplate = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/testsuite.qunit.js'), 'utf-8');
|
|
452
557
|
this.logger.debug(`Add route for ${config.init}`);
|
|
453
|
-
this.router.get(config.init,
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
this.logger.warn(`Script returned at ${config.path} is loaded from the file system.`);
|
|
457
|
-
next();
|
|
458
|
-
}
|
|
459
|
-
else {
|
|
460
|
-
this.logger.debug(`Serving test route: ${config.init}`);
|
|
461
|
-
const templateConfig = {
|
|
462
|
-
testPaths: testPaths
|
|
463
|
-
};
|
|
464
|
-
const js = (0, ejs_1.render)(initTemplate, templateConfig);
|
|
465
|
-
this.sendResponse(res, 'application/javascript', 200, js);
|
|
466
|
-
}
|
|
467
|
-
}));
|
|
558
|
+
this.router.get(config.init, async (_req, res, next) => {
|
|
559
|
+
await this.testSuiteJsGetHandler(res, next, config, initTemplate, testPaths);
|
|
560
|
+
});
|
|
468
561
|
}
|
|
469
562
|
/**
|
|
470
563
|
* Send a response with the given content type, status and body.
|
|
@@ -483,6 +576,53 @@ class FlpSandbox {
|
|
|
483
576
|
res.write(body);
|
|
484
577
|
res.end();
|
|
485
578
|
}
|
|
579
|
+
/**
|
|
580
|
+
* Handler for the GET requests to the HTML of the test runner.
|
|
581
|
+
*
|
|
582
|
+
* @param res the response
|
|
583
|
+
* @param next the next function
|
|
584
|
+
* @param config test configuration
|
|
585
|
+
* @param htmlTemplate the test runner template
|
|
586
|
+
* @param id application id from manifest
|
|
587
|
+
*/
|
|
588
|
+
async testRunnerHtmlGetHandler(res, next, config, htmlTemplate, id) {
|
|
589
|
+
this.logger.debug(`Serving test route: ${config.path}`);
|
|
590
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
591
|
+
const file = await this.project.byPath(config.path);
|
|
592
|
+
if (file) {
|
|
593
|
+
this.logger.warn(`HTML file returned at ${config.path} is loaded from the file system.`);
|
|
594
|
+
next();
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
const templateConfig = (0, config_1.createTestTemplateConfig)(config, id, this.templateConfig.ui5.theme);
|
|
598
|
+
const html = (0, ejs_1.render)(htmlTemplate, templateConfig);
|
|
599
|
+
this.sendResponse(res, 'text/html', 200, html);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Handler for the GET requests to the JS of the test runner.
|
|
604
|
+
*
|
|
605
|
+
* @param res the response
|
|
606
|
+
* @param next the next function
|
|
607
|
+
* @param config test configuration
|
|
608
|
+
* @param initTemplate the test runner template
|
|
609
|
+
* @param ns namespace for the test files
|
|
610
|
+
* @private
|
|
611
|
+
*/
|
|
612
|
+
async testRunnerJsGetHandler(res, next, config, initTemplate, ns) {
|
|
613
|
+
this.logger.debug(`Serving test init script: ${config.init}`);
|
|
614
|
+
const files = await this.project.byGlob(config.init.replace('.js', '.[jt]s'));
|
|
615
|
+
if (files?.length > 0) {
|
|
616
|
+
this.logger.warn(`Script returned at ${config.path} is loaded from the file system.`);
|
|
617
|
+
next();
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
const testFiles = await this.project.byGlob(config.pattern);
|
|
621
|
+
const templateConfig = { tests: (0, test_1.generateImportList)(ns, testFiles) };
|
|
622
|
+
const js = (0, ejs_1.render)(initTemplate, templateConfig);
|
|
623
|
+
this.sendResponse(res, 'application/javascript', 200, js);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
486
626
|
/**
|
|
487
627
|
* Add routes for html and scripts required for a local test FLP.
|
|
488
628
|
*
|
|
@@ -492,45 +632,23 @@ class FlpSandbox {
|
|
|
492
632
|
addTestRoutes(configs, id) {
|
|
493
633
|
const ns = id.replace(/\./g, '/');
|
|
494
634
|
const htmlTemplate = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/qunit.html'), 'utf-8');
|
|
495
|
-
const initTemplate = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/qunit.js'), 'utf-8');
|
|
496
635
|
for (const testConfig of configs) {
|
|
497
636
|
const config = (0, test_1.mergeTestConfigDefaults)(testConfig);
|
|
498
637
|
this.logger.debug(`Add route for ${config.path}`);
|
|
499
638
|
// add route for the *.qunit.html
|
|
500
|
-
this.router.get(config.path,
|
|
501
|
-
this.
|
|
502
|
-
|
|
503
|
-
const file = await this.project.byPath(config.path);
|
|
504
|
-
if (file) {
|
|
505
|
-
this.logger.warn(`HTML file returned at ${config.path} is loaded from the file system.`);
|
|
506
|
-
next();
|
|
507
|
-
}
|
|
508
|
-
else {
|
|
509
|
-
const templateConfig = (0, config_1.createTestTemplateConfig)(config, id, this.templateConfig.ui5.theme);
|
|
510
|
-
const html = (0, ejs_1.render)(htmlTemplate, templateConfig);
|
|
511
|
-
this.sendResponse(res, 'text/html', 200, html);
|
|
512
|
-
}
|
|
513
|
-
}));
|
|
639
|
+
this.router.get(config.path, async (_req, res, next) => {
|
|
640
|
+
await this.testRunnerHtmlGetHandler(res, next, config, htmlTemplate, id);
|
|
641
|
+
});
|
|
514
642
|
if (testConfig.init !== undefined) {
|
|
515
643
|
this.logger.debug(`Skip serving test init script in favor of provided script: ${testConfig.init}`);
|
|
516
644
|
continue;
|
|
517
645
|
}
|
|
518
646
|
// add route for the init file
|
|
647
|
+
const initTemplate = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../../templates/test/qunit.js'), 'utf-8');
|
|
519
648
|
this.logger.debug(`Add route for ${config.init}`);
|
|
520
|
-
this.router.get(config.init,
|
|
521
|
-
this.
|
|
522
|
-
|
|
523
|
-
if (files?.length > 0) {
|
|
524
|
-
this.logger.warn(`Script returned at ${config.path} is loaded from the file system.`);
|
|
525
|
-
next();
|
|
526
|
-
}
|
|
527
|
-
else {
|
|
528
|
-
const testFiles = await this.project.byGlob(config.pattern);
|
|
529
|
-
const templateConfig = { tests: (0, test_1.generateImportList)(ns, testFiles) };
|
|
530
|
-
const js = (0, ejs_1.render)(initTemplate, templateConfig);
|
|
531
|
-
this.sendResponse(res, 'application/javascript', 200, js);
|
|
532
|
-
}
|
|
533
|
-
}));
|
|
649
|
+
this.router.get(config.init, async (_req, res, next) => {
|
|
650
|
+
await this.testRunnerJsGetHandler(res, next, config, initTemplate, ns);
|
|
651
|
+
});
|
|
534
652
|
}
|
|
535
653
|
}
|
|
536
654
|
}
|
|
@@ -539,7 +657,7 @@ exports.FlpSandbox = FlpSandbox;
|
|
|
539
657
|
* Creates an attribute string that can be added to an HTML element.
|
|
540
658
|
*
|
|
541
659
|
* @param attributes map with attributes and their values
|
|
542
|
-
* @param indent indentation
|
|
660
|
+
* @param indent indentation that's inserted before each attribute
|
|
543
661
|
* @param prefix value that should be added at the start of to all attribute names
|
|
544
662
|
* @returns attribute string
|
|
545
663
|
*/
|
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.17.
|
|
12
|
+
"version": "0.17.23",
|
|
13
13
|
"license": "Apache-2.0",
|
|
14
14
|
"author": "@SAP/ux-tools-team",
|
|
15
15
|
"main": "dist/index.js",
|
|
@@ -26,11 +26,11 @@
|
|
|
26
26
|
"mem-fs": "2.1.0",
|
|
27
27
|
"mem-fs-editor": "9.4.0",
|
|
28
28
|
"@sap-ux/logger": "0.6.0",
|
|
29
|
-
"@sap-ux/feature-toggle": "0.2.3",
|
|
30
29
|
"@sap-ux/btp-utils": "1.0.1",
|
|
31
|
-
"@sap-ux/adp-tooling": "0.12.
|
|
30
|
+
"@sap-ux/adp-tooling": "0.12.125",
|
|
31
|
+
"@sap-ux/feature-toggle": "0.2.3",
|
|
32
32
|
"@sap-ux/control-property-editor-sources": "npm:@sap-ux/control-property-editor@0.5.35",
|
|
33
|
-
"@sap-ux/project-access": "1.29.
|
|
33
|
+
"@sap-ux/project-access": "1.29.5"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"connect": "^3.7.0",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@sap-ux/axios-extension": "1.18.5",
|
|
53
53
|
"@sap-ux/store": "1.0.0",
|
|
54
54
|
"@sap-ux/ui5-info": "0.8.3",
|
|
55
|
-
"@sap-ux/i18n": "0.2.
|
|
55
|
+
"@sap-ux/i18n": "0.2.1"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"express": "4"
|