@sap-ux/preview-middleware 0.25.37 → 0.25.38
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.
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
sap.ui.define(["sap/base/Log", "open/ux/preview/client/thirdparty/@sap-ux-private/control-property-editor-common", "../utils/info-center-message"], function (log, ___sap_ux_private_control_property_editor_common, ___utils_info_center_message) {
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
const MessageBarType = ___sap_ux_private_control_property_editor_common["MessageBarType"];
|
|
7
|
+
const sendInfoCenterMessage = ___utils_info_center_message["sendInfoCenterMessage"];
|
|
8
|
+
const CHANGE_TYPE = {
|
|
9
|
+
addXML: 'addXML',
|
|
10
|
+
codeExt: 'codeExt'
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Type guard for changes that reference a fragment or controller extension file.
|
|
14
|
+
*
|
|
15
|
+
* @param change flex change object
|
|
16
|
+
* @returns true if the change is an addXML with fragmentPath or a codeExt with codeRef
|
|
17
|
+
*/
|
|
18
|
+
function isFragmentOrCodeExtChange(change) {
|
|
19
|
+
return !!change.reference && (change.changeType === CHANGE_TYPE.addXML && !!change.content?.fragmentPath || change.changeType === CHANGE_TYPE.codeExt && !!change.content?.codeRef);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Builds a lookup map from module name patterns to change metadata
|
|
24
|
+
* for addXML and codeExt changes.
|
|
25
|
+
*
|
|
26
|
+
* @param changes record of change objects keyed by flex key
|
|
27
|
+
* @returns map from module name substring to orphaned change entry
|
|
28
|
+
*/
|
|
29
|
+
function buildModuleNameMap(changes) {
|
|
30
|
+
const map = new Map();
|
|
31
|
+
for (const change of Object.values(changes)) {
|
|
32
|
+
if (!isFragmentOrCodeExtChange(change)) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const prefix = change.reference.replaceAll('.', '/');
|
|
36
|
+
const path = change.changeType === CHANGE_TYPE.addXML ? change.content?.fragmentPath ?? '' : change.content?.codeRef ?? '';
|
|
37
|
+
const changeFileName = `${change.fileName}.${change.fileType ?? 'change'}`;
|
|
38
|
+
const key = change.moduleName ?? `${prefix}/changes/${path}`;
|
|
39
|
+
map.set(key, {
|
|
40
|
+
changeFileName,
|
|
41
|
+
filePath: path,
|
|
42
|
+
changeType: change.changeType
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return map;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Creates an error handler that matches error messages against known module names
|
|
50
|
+
* and sends InfoCenter errors for orphaned change files.
|
|
51
|
+
*
|
|
52
|
+
* @param moduleNameMap map from module name substring to orphaned change entry
|
|
53
|
+
* @returns error handler function
|
|
54
|
+
*/
|
|
55
|
+
function createErrorHandler(moduleNameMap, restoreConsole) {
|
|
56
|
+
return message => {
|
|
57
|
+
for (const [moduleName, entry] of moduleNameMap) {
|
|
58
|
+
if (message.includes(moduleName)) {
|
|
59
|
+
sendInfoCenterMessage({
|
|
60
|
+
title: {
|
|
61
|
+
key: 'ADP_ORPHANED_CHANGE_ERROR_TITLE'
|
|
62
|
+
},
|
|
63
|
+
description: {
|
|
64
|
+
key: 'ADP_ORPHANED_FILE_DESCRIPTION',
|
|
65
|
+
params: [entry.filePath, entry.changeFileName]
|
|
66
|
+
},
|
|
67
|
+
type: MessageBarType.error
|
|
68
|
+
}).catch(error => {
|
|
69
|
+
log.error('Failed to send orphaned change InfoCenter message', error);
|
|
70
|
+
});
|
|
71
|
+
moduleNameMap.delete(moduleName);
|
|
72
|
+
if (moduleNameMap.size === 0) {
|
|
73
|
+
restoreConsole();
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Initializes orphaned change file detection.
|
|
83
|
+
*
|
|
84
|
+
* Fetches loaded flex changes, builds a lookup map of module names for addXML and codeExt changes,
|
|
85
|
+
* and wraps console.error to intercept UI5 flex change application errors. When UI5 fails to load
|
|
86
|
+
* a fragment or controller extension referenced by a change file, the error is intercepted and an
|
|
87
|
+
* actionable message is shown in the InfoCenter advising the user to delete the orphaned change file.
|
|
88
|
+
*/
|
|
89
|
+
async function initOrphanedChangeDetection() {
|
|
90
|
+
const baseUrl = document.getElementById('sap-ui-bootstrap')?.dataset.openUxPreviewBaseUrl ?? '';
|
|
91
|
+
const response = await fetch(`${baseUrl}/preview/api/changes`, {
|
|
92
|
+
method: 'GET',
|
|
93
|
+
headers: {
|
|
94
|
+
'content-type': 'application/json'
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
if (!response.ok) {
|
|
98
|
+
log.error(`Failed to fetch changes for orphaned change detection: ${response.status}`);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const changes = await response.json();
|
|
102
|
+
const moduleNameMap = buildModuleNameMap(changes);
|
|
103
|
+
if (moduleNameMap.size === 0) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const consoleRef = globalThis.console;
|
|
107
|
+
const originalConsoleError = consoleRef.error;
|
|
108
|
+
const restore = () => {
|
|
109
|
+
consoleRef.error = originalConsoleError;
|
|
110
|
+
};
|
|
111
|
+
const handler = createErrorHandler(moduleNameMap, restore);
|
|
112
|
+
const safetyTimeout = setTimeout(restore, 60_000);
|
|
113
|
+
consoleRef.error = (...args) => {
|
|
114
|
+
originalConsoleError.apply(consoleRef, args);
|
|
115
|
+
const message = args.filter(arg => typeof arg === 'string').join('');
|
|
116
|
+
handler(message);
|
|
117
|
+
if (moduleNameMap.size === 0) {
|
|
118
|
+
clearTimeout(safetyTimeout);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
var __exports = {
|
|
123
|
+
__esModule: true
|
|
124
|
+
};
|
|
125
|
+
__exports.initOrphanedChangeDetection = initOrphanedChangeDetection;
|
|
126
|
+
return __exports;
|
|
127
|
+
});
|
|
128
|
+
//# sourceMappingURL=change-file-validator.js.map
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import log from 'sap/base/Log';
|
|
2
|
+
import { MessageBarType } from '@sap-ux-private/control-property-editor-common';
|
|
3
|
+
|
|
4
|
+
import { sendInfoCenterMessage } from '../utils/info-center-message';
|
|
5
|
+
|
|
6
|
+
const CHANGE_TYPE = {
|
|
7
|
+
addXML: 'addXML',
|
|
8
|
+
codeExt: 'codeExt'
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
type FlexChangeType = (typeof CHANGE_TYPE)[keyof typeof CHANGE_TYPE];
|
|
12
|
+
|
|
13
|
+
interface ChangeContent {
|
|
14
|
+
fragmentPath?: string;
|
|
15
|
+
codeRef?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Change {
|
|
19
|
+
changeType: string;
|
|
20
|
+
fileName: string;
|
|
21
|
+
fileType?: string;
|
|
22
|
+
reference: string;
|
|
23
|
+
moduleName?: string;
|
|
24
|
+
content?: ChangeContent;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface OrphanedChangeEntry {
|
|
28
|
+
changeFileName: string;
|
|
29
|
+
filePath: string;
|
|
30
|
+
changeType: FlexChangeType;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface RelevantChange extends Change {
|
|
34
|
+
changeType: FlexChangeType;
|
|
35
|
+
reference: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Type guard for changes that reference a fragment or controller extension file.
|
|
40
|
+
*
|
|
41
|
+
* @param change flex change object
|
|
42
|
+
* @returns true if the change is an addXML with fragmentPath or a codeExt with codeRef
|
|
43
|
+
*/
|
|
44
|
+
function isFragmentOrCodeExtChange(change: Change): change is RelevantChange {
|
|
45
|
+
return (
|
|
46
|
+
!!change.reference &&
|
|
47
|
+
((change.changeType === CHANGE_TYPE.addXML && !!change.content?.fragmentPath) ||
|
|
48
|
+
(change.changeType === CHANGE_TYPE.codeExt && !!change.content?.codeRef))
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Builds a lookup map from module name patterns to change metadata
|
|
54
|
+
* for addXML and codeExt changes.
|
|
55
|
+
*
|
|
56
|
+
* @param changes record of change objects keyed by flex key
|
|
57
|
+
* @returns map from module name substring to orphaned change entry
|
|
58
|
+
*/
|
|
59
|
+
function buildModuleNameMap(changes: Record<string, Change>): Map<string, OrphanedChangeEntry> {
|
|
60
|
+
const map = new Map<string, OrphanedChangeEntry>();
|
|
61
|
+
|
|
62
|
+
for (const change of Object.values(changes)) {
|
|
63
|
+
if (!isFragmentOrCodeExtChange(change)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const prefix = change.reference.replaceAll('.', '/');
|
|
68
|
+
const path = change.changeType === CHANGE_TYPE.addXML ? change.content?.fragmentPath ?? '' : change.content?.codeRef ?? '';
|
|
69
|
+
const changeFileName = `${change.fileName}.${change.fileType ?? 'change'}`;
|
|
70
|
+
const key = change.moduleName ?? `${prefix}/changes/${path}`;
|
|
71
|
+
|
|
72
|
+
map.set(key, { changeFileName, filePath: path, changeType: change.changeType });
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return map;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Creates an error handler that matches error messages against known module names
|
|
80
|
+
* and sends InfoCenter errors for orphaned change files.
|
|
81
|
+
*
|
|
82
|
+
* @param moduleNameMap map from module name substring to orphaned change entry
|
|
83
|
+
* @returns error handler function
|
|
84
|
+
*/
|
|
85
|
+
function createErrorHandler(
|
|
86
|
+
moduleNameMap: Map<string, OrphanedChangeEntry>,
|
|
87
|
+
restoreConsole: () => void
|
|
88
|
+
): (message: string) => void {
|
|
89
|
+
return (message: string) => {
|
|
90
|
+
for (const [moduleName, entry] of moduleNameMap) {
|
|
91
|
+
if (message.includes(moduleName)) {
|
|
92
|
+
sendInfoCenterMessage({
|
|
93
|
+
title: { key: 'ADP_ORPHANED_CHANGE_ERROR_TITLE' },
|
|
94
|
+
description: {
|
|
95
|
+
key: 'ADP_ORPHANED_FILE_DESCRIPTION',
|
|
96
|
+
params: [entry.filePath, entry.changeFileName]
|
|
97
|
+
},
|
|
98
|
+
type: MessageBarType.error
|
|
99
|
+
}).catch((error) => {
|
|
100
|
+
log.error('Failed to send orphaned change InfoCenter message', error);
|
|
101
|
+
});
|
|
102
|
+
moduleNameMap.delete(moduleName);
|
|
103
|
+
if (moduleNameMap.size === 0) {
|
|
104
|
+
restoreConsole();
|
|
105
|
+
}
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Initializes orphaned change file detection.
|
|
114
|
+
*
|
|
115
|
+
* Fetches loaded flex changes, builds a lookup map of module names for addXML and codeExt changes,
|
|
116
|
+
* and wraps console.error to intercept UI5 flex change application errors. When UI5 fails to load
|
|
117
|
+
* a fragment or controller extension referenced by a change file, the error is intercepted and an
|
|
118
|
+
* actionable message is shown in the InfoCenter advising the user to delete the orphaned change file.
|
|
119
|
+
*/
|
|
120
|
+
export async function initOrphanedChangeDetection(): Promise<void> {
|
|
121
|
+
const baseUrl = document.getElementById('sap-ui-bootstrap')?.dataset.openUxPreviewBaseUrl ?? '';
|
|
122
|
+
const response = await fetch(`${baseUrl}/preview/api/changes`, {
|
|
123
|
+
method: 'GET',
|
|
124
|
+
headers: { 'content-type': 'application/json' }
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
if (!response.ok) {
|
|
128
|
+
log.error(`Failed to fetch changes for orphaned change detection: ${response.status}`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const changes = (await response.json()) as Record<string, Change>;
|
|
133
|
+
const moduleNameMap = buildModuleNameMap(changes);
|
|
134
|
+
|
|
135
|
+
if (moduleNameMap.size === 0) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const consoleRef = globalThis.console;
|
|
140
|
+
const originalConsoleError = consoleRef.error;
|
|
141
|
+
|
|
142
|
+
const restore = (): void => {
|
|
143
|
+
consoleRef.error = originalConsoleError;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
const handler = createErrorHandler(moduleNameMap, restore);
|
|
147
|
+
|
|
148
|
+
const safetyTimeout = setTimeout(restore, 60_000);
|
|
149
|
+
|
|
150
|
+
consoleRef.error = (...args: unknown[]) => {
|
|
151
|
+
originalConsoleError.apply(consoleRef, args);
|
|
152
|
+
const message = args.filter((arg): arg is string => typeof arg === 'string').join('');
|
|
153
|
+
handler(message);
|
|
154
|
+
if (moduleNameMap.size === 0) {
|
|
155
|
+
clearTimeout(safetyTimeout);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
package/dist/client/adp/init.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
sap.ui.define(["sap/base/Log", "open/ux/preview/client/thirdparty/@sap-ux-private/control-property-editor-common", "../utils/version", "../cpe/init", "./sync-views-utils", "../utils/application", "./quick-actions/load", "./init-dialogs", "../utils/info-center-message", "../cpe/communication-service"], function (log, ___sap_ux_private_control_property_editor_common, ___utils_version, __init, ___sync_views_utils, ___utils_application, ___quick_actions_load, ___init_dialogs, ___utils_info_center_message, ___cpe_communication_service) {
|
|
3
|
+
sap.ui.define(["sap/base/Log", "open/ux/preview/client/thirdparty/@sap-ux-private/control-property-editor-common", "../utils/version", "../cpe/init", "./sync-views-utils", "../utils/application", "./quick-actions/load", "./init-dialogs", "../utils/info-center-message", "../cpe/communication-service", "./change-file-validator"], function (log, ___sap_ux_private_control_property_editor_common, ___utils_version, __init, ___sync_views_utils, ___utils_application, ___quick_actions_load, ___init_dialogs, ___utils_info_center_message, ___cpe_communication_service, ___change_file_validator) {
|
|
4
4
|
"use strict";
|
|
5
5
|
|
|
6
6
|
function _interopRequireDefault(obj) {
|
|
@@ -38,6 +38,7 @@ sap.ui.define(["sap/base/Log", "open/ux/preview/client/thirdparty/@sap-ux-privat
|
|
|
38
38
|
const initDialogs = ___init_dialogs["initDialogs"];
|
|
39
39
|
const sendInfoCenterMessage = ___utils_info_center_message["sendInfoCenterMessage"];
|
|
40
40
|
const CommunicationService = ___cpe_communication_service["CommunicationService"];
|
|
41
|
+
const initOrphanedChangeDetection = ___change_file_validator["initOrphanedChangeDetection"];
|
|
41
42
|
var __exports = async function (rta) {
|
|
42
43
|
const flexSettings = rta.getFlexSettings();
|
|
43
44
|
if (flexSettings.telemetry === true) {
|
|
@@ -104,6 +105,9 @@ sap.ui.define(["sap/base/Log", "open/ux/preview/client/thirdparty/@sap-ux-privat
|
|
|
104
105
|
CommunicationService.sendAction(toggleAppPreviewVisibility(false));
|
|
105
106
|
return;
|
|
106
107
|
}
|
|
108
|
+
initOrphanedChangeDetection().catch(error => {
|
|
109
|
+
log.error('Failed to run orphaned change detection', error);
|
|
110
|
+
});
|
|
107
111
|
log.debug('ADP init executed.');
|
|
108
112
|
};
|
|
109
113
|
return __exports;
|
package/dist/client/adp/init.ts
CHANGED
|
@@ -23,6 +23,7 @@ import { loadDefinitions } from './quick-actions/load';
|
|
|
23
23
|
import { initDialogs } from './init-dialogs';
|
|
24
24
|
import { sendInfoCenterMessage } from '../utils/info-center-message';
|
|
25
25
|
import { CommunicationService } from '../cpe/communication-service';
|
|
26
|
+
import { initOrphanedChangeDetection } from './change-file-validator';
|
|
26
27
|
|
|
27
28
|
export default async function (rta: RuntimeAuthoring) {
|
|
28
29
|
const flexSettings = rta.getFlexSettings();
|
|
@@ -88,5 +89,9 @@ export default async function (rta: RuntimeAuthoring) {
|
|
|
88
89
|
return;
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
initOrphanedChangeDetection().catch((error) => {
|
|
93
|
+
log.error('Failed to run orphaned change detection', error);
|
|
94
|
+
});
|
|
95
|
+
|
|
91
96
|
log.debug('ADP init executed.');
|
|
92
97
|
}
|
|
@@ -67,6 +67,8 @@ ADP_CREATE_CONTROLLER_EXTENSION_TITLE = Create Controller Extension
|
|
|
67
67
|
ADP_CREATE_CONTROLLER_EXTENSION_DESCRIPTION = Controller extension with name ''{0}'' was created.
|
|
68
68
|
ADP_ODATA_HEALTH_CHECK_TITLE = OData Service Health Check
|
|
69
69
|
ADP_ODATA_SERVICE_DOWN_DESCRIPTION = The OData service with the {0} endpoint is down. Error: {1}.
|
|
70
|
+
ADP_ORPHANED_CHANGE_ERROR_TITLE = Missing File Detected
|
|
71
|
+
ADP_ORPHANED_FILE_DESCRIPTION = The "{0}" file referenced by the "{1}" change was not found. To resolve this error, delete the change file.
|
|
70
72
|
ADP_ADD_ACTION_DIALOG_ACTION_ID_LABEL = Action ID
|
|
71
73
|
ADP_ADD_ACTION_DIALOG_BUTTON_TEXT_LABEL = Button Text
|
|
72
74
|
ADP_ADD_ACTION_DIALOG_HANDLER_METHOD_LABEL = Handler Method
|
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.25.
|
|
12
|
+
"version": "0.25.38",
|
|
13
13
|
"license": "Apache-2.0",
|
|
14
14
|
"author": "@SAP/ux-tools-team",
|
|
15
15
|
"main": "dist/index.js",
|
|
@@ -27,13 +27,13 @@
|
|
|
27
27
|
"mem-fs-editor": "9.4.0",
|
|
28
28
|
"qrcode": "1.5.4",
|
|
29
29
|
"@sap/bas-sdk": "3.13.6",
|
|
30
|
+
"@sap-ux/btp-utils": "1.1.14",
|
|
30
31
|
"@sap-ux/adp-tooling": "0.18.128",
|
|
32
|
+
"@sap-ux/control-property-editor-sources": "npm:@sap-ux/control-property-editor@0.7.24",
|
|
31
33
|
"@sap-ux/feature-toggle": "0.3.8",
|
|
32
|
-
"@sap-ux/btp-utils": "1.1.14",
|
|
33
34
|
"@sap-ux/logger": "0.8.5",
|
|
34
|
-
"@sap-ux/control-property-editor-sources": "npm:@sap-ux/control-property-editor@0.7.24",
|
|
35
|
-
"@sap-ux/project-access": "1.36.2",
|
|
36
35
|
"@sap-ux/system-access": "0.7.10",
|
|
36
|
+
"@sap-ux/project-access": "1.36.2",
|
|
37
37
|
"@sap-ux/i18n": "0.3.11"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"nock": "14.0.11",
|
|
54
54
|
"npm-run-all2": "8.0.4",
|
|
55
55
|
"supertest": "7.2.2",
|
|
56
|
-
"@private/preview-middleware-client": "npm:@sap-ux-private/preview-middleware-client@0.25.
|
|
57
|
-
"@sap-ux/
|
|
56
|
+
"@private/preview-middleware-client": "npm:@sap-ux-private/preview-middleware-client@0.25.38",
|
|
57
|
+
"@sap-ux/store": "1.5.13",
|
|
58
58
|
"@sap-ux/ui5-info": "0.13.20",
|
|
59
|
-
"@sap-ux/
|
|
59
|
+
"@sap-ux/axios-extension": "1.25.34"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"express": "4"
|