diff --git a/.changeset/smooth-pans-talk.md b/.changeset/smooth-pans-talk.md new file mode 100644 index 0000000000..7cdfce9400 --- /dev/null +++ b/.changeset/smooth-pans-talk.md @@ -0,0 +1,6 @@ +--- +"@sap-ux-private/preview-middleware-client": patch +"@sap-ux/preview-middleware": patch +--- + +Feature: Makes preview-middleware and preview-middleware-client ready for SAP UI5 2.0; considers the new sandbox2.js for the bootstrap. diff --git a/packages/preview-middleware-client/src/flp/bootstrap.ts b/packages/preview-middleware-client/src/flp/bootstrap.ts new file mode 100644 index 0000000000..77edd9766d --- /dev/null +++ b/packages/preview-middleware-client/src/flp/bootstrap.ts @@ -0,0 +1,23 @@ +/** + * Calculates the script content for accessing the right sap/ushell/bootstrap sandbox. + */ +export default async function bootstrap(): Promise { + var head = document.getElementsByTagName('head')[0]; + if (head) { + await fetch('/resources/sap-ui-version.json') + .then((resp) => resp.json()) + .then((json) => { + const version = json?.version; + const major = version ? parseInt(version.split('.')[0], 10) : 2; + var script = document.createElement('script'); + + script.src = + major >= 2 + ? '/resources/sap/ushell/bootstrap/sandbox2.js' + : '/test-resources/sap/ushell/bootstrap/sandbox.js'; + script.id = 'sap-ushell-bootstrap'; + script.type = 'text/javascript'; + head.appendChild(script); + }); + } +} diff --git a/packages/preview-middleware-client/src/flp/init.ts b/packages/preview-middleware-client/src/flp/init.ts index 2dd7f454b6..af1dad0380 100644 --- a/packages/preview-middleware-client/src/flp/init.ts +++ b/packages/preview-middleware-client/src/flp/init.ts @@ -7,6 +7,7 @@ import IconPool from 'sap/ui/core/IconPool'; import ResourceBundle from 'sap/base/i18n/ResourceBundle'; import AppState from 'sap/ushell/services/AppState'; import { getManifestAppdescr } from '../adp/api-handler'; +import VersionInfo from 'sap/ui/VersionInfo'; /** * SAPUI5 delivered namespaces from https://ui5.sap.com/#/api/sap @@ -244,6 +245,8 @@ export async function init({ const urlParams = new URLSearchParams(window.location.search); const container = sap?.ushell?.Container ?? (sap.ui.require('sap/ushell/Container') as typeof sap.ushell.Container); let scenario: string = ''; + const { version } = (await VersionInfo.load()) as { version: string }; + // Register RTA if configured if (flex) { const flexSettings = JSON.parse(flex) as FlexSettings; @@ -251,7 +254,6 @@ export async function init({ container.attachRendererCreatedEvent(async function () { const lifecycleService = await container.getServiceAsync('AppLifeCycle'); lifecycleService.attachAppLoaded((event) => { - const version = sap.ui.version; const minor = parseInt(version.split('.')[1], 10); const view = event.getParameter('componentInstance'); const flexSettings = JSON.parse(flex) as FlexSettings; @@ -304,15 +306,23 @@ export async function init({ const resourceBundle = await loadI18nResourceBundle(scenario as Scenario); setI18nTitle(resourceBundle); registerSAPFonts(); - const renderer = await container.createRenderer(undefined, true); + const major = version ? parseInt(version.split('.')[0], 10) : 2; + const renderer = + major < 2 + ? await container.createRenderer(undefined, true) + : await (container as any).createRendererInternal(undefined, true); renderer.placeAt('content'); } -const bootstrapConfig = document.getElementById('sap-ui-bootstrap'); -if (bootstrapConfig) { - init({ - appUrls: bootstrapConfig.getAttribute('data-open-ux-preview-libs-manifests'), - flex: bootstrapConfig.getAttribute('data-open-ux-preview-flex-settings'), - customInit: bootstrapConfig.getAttribute('data-open-ux-preview-customInit') - }).catch(() => Log.error('Sandbox initialization failed.')); +const uiBootstrap = document.getElementById('sap-ui-bootstrap'); +if (uiBootstrap) { + try { + init({ + appUrls: uiBootstrap.getAttribute('data-open-ux-preview-libs-manifests'), + flex: uiBootstrap.getAttribute('data-open-ux-preview-flex-settings'), + customInit: uiBootstrap.getAttribute('data-open-ux-preview-customInit') + }); + } catch (e) { + Log.error('Sandbox initialization failed: ' + e.message); + } } diff --git a/packages/preview-middleware-client/src/flp/initConnectors.ts b/packages/preview-middleware-client/src/flp/initConnectors.ts index 632fdb243a..a84a4ebc1a 100644 --- a/packages/preview-middleware-client/src/flp/initConnectors.ts +++ b/packages/preview-middleware-client/src/flp/initConnectors.ts @@ -1,3 +1,5 @@ +import VersionInfo from 'sap/ui/VersionInfo'; + /** * Initializes UI5 connectors based on the current UI5 version. * @@ -6,14 +8,15 @@ * This setup allows for flexibility in using different connectors based on the UI5 version. * * @example - * intiConnectors(); // Simply call the function without any arguments. - * @returns {void} + * initConnectors(); // Simply call the function without any arguments. */ -export function initConnectors(): void { - const version = sap.ui.version; - const minor = parseInt(version.split('.')[1], 10); +export default async function initConnectors(): Promise { + const { version } = (await VersionInfo.load()) as { version: string }; + const versionArray = version ? version.split('.') : ['2', '99']; + const minor = parseInt(versionArray[1], 10); + const major = parseInt(versionArray[0], 10); - if (minor < 72) { + if (major === 1 && minor < 72) { sap.ui.require(['open/ux/preview/client/flp/enableFakeConnector'], function (enableFakeConnector: () => void) { enableFakeConnector(); }); @@ -26,5 +29,3 @@ export function initConnectors(): void { ); } } - -initConnectors(); diff --git a/packages/preview-middleware-client/test/__mock__/window.ts b/packages/preview-middleware-client/test/__mock__/window.ts index eb13864754..0233bd2fc7 100644 --- a/packages/preview-middleware-client/test/__mock__/window.ts +++ b/packages/preview-middleware-client/test/__mock__/window.ts @@ -26,6 +26,7 @@ export const sapMock = { ushell: { Container: { createRenderer: jest.fn().mockReturnValue({ placeAt: jest.fn() }), + createRendererInternal: jest.fn().mockReturnValue({ placeAt: jest.fn() }), attachRendererCreatedEvent: jest.fn(), getServiceAsync: jest.fn() } diff --git a/packages/preview-middleware-client/test/unit/flp/init.test.ts b/packages/preview-middleware-client/test/unit/flp/init.test.ts index 9a9d14656e..25bcda1350 100644 --- a/packages/preview-middleware-client/test/unit/flp/init.test.ts +++ b/packages/preview-middleware-client/test/unit/flp/init.test.ts @@ -12,6 +12,7 @@ import * as apiHandler from '../../../src/adp/api-handler'; import { fetchMock, sapMock } from 'mock/window'; import type { InitRtaScript, RTAPlugin, StartAdaptation } from 'sap/ui/rta/api/startAdaptation'; import type { Scenario } from '@sap-ux-private/control-property-editor-common'; +import VersionInfo from 'mock/sap/ui/VersionInfo'; describe('flp/init', () => { test('registerSAPFonts', () => { @@ -44,7 +45,7 @@ describe('flp/init', () => { } as unknown as apiHandler.ManifestAppdescr); await loadI18nResourceBundle('other' as Scenario); expect(mockBundle.create).toBeCalledWith({ - url: 'i18n/i18n.properties', + url: 'i18n/i18n.properties' }); }); test('loadI18nResourceBundle - adaptation project', async () => { @@ -166,6 +167,7 @@ describe('flp/init', () => { }); test('nothing configured', async () => { + VersionInfo.load.mockResolvedValue({ version: '1.118.1' }); await init({}); expect(sapMock.ushell.Container.attachRendererCreatedEvent).not.toBeCalled(); expect(sapMock.ushell.Container.createRenderer).toBeCalledWith(undefined, true); @@ -177,7 +179,7 @@ describe('flp/init', () => { layer: 'CUSTOMER_BASE', pluginScript: 'my/script' }; - sapMock.ui.version = '1.84.50'; + VersionInfo.load.mockResolvedValue({ version: '1.84.50' }); await init({ flex: JSON.stringify(flexSettings) }); expect(sapMock.ushell.Container.attachRendererCreatedEvent).toBeCalled(); expect(sapMock.ushell.Container.createRenderer).toBeCalledWith(undefined, true); @@ -215,7 +217,7 @@ describe('flp/init', () => { layer: 'CUSTOMER_BASE', pluginScript: 'my/script' }; - sapMock.ui.version = '1.71.60'; + VersionInfo.load.mockResolvedValue({ version: '1.71.60' }); await init({ flex: JSON.stringify(flexSettings) }); expect(sapMock.ushell.Container.attachRendererCreatedEvent).toBeCalled(); expect(sapMock.ushell.Container.createRenderer).toBeCalledWith(undefined, true); @@ -250,12 +252,21 @@ describe('flp/init', () => { test('custom init module configured & ui5 version is 1.120.9', async () => { const customInit = 'my/app/test/integration/opaTests.qunit'; - sapMock.ui.version = '1.120.09'; + VersionInfo.load.mockResolvedValue({ version: '1.120.9' }); + await init({ customInit: customInit }); expect(sapMock.ui.require).toBeCalledWith([customInit]); - expect(sapMock.ushell.Container.createRenderer).toBeCalledWith(undefined, true); }); + + test('custom init module configured & ui5 version is 2.0.0', async () => { + const customInit = 'my/app/test/integration/opaTests.qunit'; + VersionInfo.load.mockResolvedValue({ version: '2.0.0' }); + + await init({ customInit: customInit }); + + expect(sapMock.ui.require).toBeCalledWith([customInit]); + }); }); }); diff --git a/packages/preview-middleware-client/test/unit/flp/initConnectors.test.ts b/packages/preview-middleware-client/test/unit/flp/initConnectors.test.ts index 067ed82481..ad9aeefe36 100644 --- a/packages/preview-middleware-client/test/unit/flp/initConnectors.test.ts +++ b/packages/preview-middleware-client/test/unit/flp/initConnectors.test.ts @@ -1,14 +1,16 @@ import { sapMock } from 'mock/window'; -import { initConnectors } from '../../../src/flp/initConnectors'; +import VersionInfo from 'mock/sap/ui/VersionInfo'; +import initConnectors from '../../../src/flp/initConnectors'; describe('flp/initConnectors', () => { afterEach(() => { jest.restoreAllMocks(); }); - test('enables fake lrep connector when ui5 version is 1.71', () => { + test('enables fake lrep connector when ui5 version is 1.71', async () => { sapMock.ui.version = '1.71.60'; - initConnectors(); + VersionInfo.load.mockResolvedValue({ version: '1.71.60' }); + await initConnectors(); expect(sapMock.ui.require).toBeCalledWith( ['open/ux/preview/client/flp/enableFakeConnector'], @@ -22,10 +24,11 @@ describe('flp/initConnectors', () => { expect(enableFakeConSpy).toHaveBeenCalled(); }); - test('defines a local connector for writing and applying changes and returns it', () => { + test('defines a local connector for writing and applying changes and returns it', async () => { sapMock.ui.version = '1.120.4'; + VersionInfo.load.mockResolvedValue({ version: '1.120.4' }); - initConnectors(); + await initConnectors(); const WorkspaceConnectorMock = { layers: [] }; const requireCb = sapMock.ui.define.mock.calls[0][2] as (WorkspaceConnector: unknown) => void; diff --git a/packages/preview-middleware/src/base/config.ts b/packages/preview-middleware/src/base/config.ts index 79f902743b..3371475c59 100644 --- a/packages/preview-middleware/src/base/config.ts +++ b/packages/preview-middleware/src/base/config.ts @@ -261,8 +261,9 @@ export function createFlpTemplateConfig(config: FlpConfig, manifest: Partial + } + }, + services: {}, + applications: <%- JSON.stringify(apps) %> }; - + + -<% if (locals.flex && flex?.developerMode) { %> + <% if (locals.flex && flex?.developerMode) { %> - <% } %> + <% } %> + diff --git a/packages/preview-middleware/test/unit/base/__snapshots__/config.test.ts.snap b/packages/preview-middleware/test/unit/base/__snapshots__/config.test.ts.snap index b8b2ef899e..68bc25c452 100644 --- a/packages/preview-middleware/test/unit/base/__snapshots__/config.test.ts.snap +++ b/packages/preview-middleware/test/unit/base/__snapshots__/config.test.ts.snap @@ -73,13 +73,15 @@ exports[`config generatePreviewFiles minimum settings 1`] = ` enableSearch: false } } - } - }, - applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} + } + }, + services: {}, + applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} }; - + + - + + @@ -150,13 +153,15 @@ Object { enableSearch: false } } - } - }, - applications: {\\"simpleApp-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/apps/simple-app\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/apps/other-app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} + } + }, + services: {}, + applications: {\\"simpleApp-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/apps/simple-app\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/apps/other-app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} }; - + + - + + @@ -230,13 +236,15 @@ Object { enableSearch: false } } - } - }, - applications: {\\"myapp-myaction\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} + } + }, + services: {}, + applications: {\\"myapp-myaction\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} }; - + + - + + diff --git a/packages/preview-middleware/test/unit/base/__snapshots__/flp.test.ts.snap b/packages/preview-middleware/test/unit/base/__snapshots__/flp.test.ts.snap index 657e7ff790..f5464e94df 100644 --- a/packages/preview-middleware/test/unit/base/__snapshots__/flp.test.ts.snap +++ b/packages/preview-middleware/test/unit/base/__snapshots__/flp.test.ts.snap @@ -502,13 +502,15 @@ exports[`FlpSandbox router editor with config 1`] = ` enableSearch: false } } - } - }, - applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/yet/another/app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} + } + }, + services: {}, + applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/yet/another/app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} }; - + + - + + @@ -580,13 +583,15 @@ exports[`FlpSandbox router rta 1`] = ` enableSearch: false } } - } - }, - applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/yet/another/app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} + } + }, + services: {}, + applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/yet/another/app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} }; - + + - + + @@ -688,13 +694,15 @@ exports[`FlpSandbox router rta with developerMode=true 2`] = ` enableSearch: false } } - } - }, - applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/yet/another/app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} + } + }, + services: {}, + applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/yet/another/app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} }; - + + - + - + + @@ -781,13 +791,15 @@ exports[`FlpSandbox router rta with developerMode=true and plugin 1`] = ` enableSearch: false } } - } - }, - applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/yet/another/app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} + } + }, + services: {}, + applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/yet/another/app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} }; - + + - + - + + @@ -874,13 +888,15 @@ exports[`FlpSandbox router test/flp.html 1`] = ` enableSearch: false } } - } - }, - applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/yet/another/app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} + } + }, + services: {}, + applications: {\\"app-preview\\":{\\"title\\":\\"My Simple App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.app\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"..\\",\\"applicationDependencies\\":{\\"manifest\\":true}},\\"testfev2other-preview\\":{\\"title\\":\\"My Other App\\",\\"description\\":\\"This is a very simple application.\\",\\"additionalInformation\\":\\"SAPUI5.Component=test.fe.v2.other\\",\\"applicationType\\":\\"URL\\",\\"url\\":\\"/yet/another/app\\",\\"applicationDependencies\\":{\\"manifest\\":true}}} }; - + + - + + diff --git a/packages/ui5-proxy-middleware/src/base/proxy.ts b/packages/ui5-proxy-middleware/src/base/proxy.ts index 6428d24ca2..fcaa120be7 100644 --- a/packages/ui5-proxy-middleware/src/base/proxy.ts +++ b/packages/ui5-proxy-middleware/src/base/proxy.ts @@ -1,6 +1,7 @@ import type { Filter, Options } from 'http-proxy-middleware'; import { createProxyMiddleware } from 'http-proxy-middleware'; import type { ClientRequest, IncomingMessage, ServerResponse } from 'http'; +import type { Request } from 'express'; import type { ProxyConfig } from './types'; import { proxyRequestHandler, @@ -28,7 +29,7 @@ export const ui5Proxy = (config: ProxyConfig, options?: Options, filter?: Filter }); const today = new Date(); const etag = `W/"${config.version || 'ui5-latest-' + today.getDate() + today.getMonth() + today.getFullYear()}"`; - const ui5Ver = config.version ? `/${config.version}` : ''; + const ui5Ver = config.version && !config.version.startsWith('2') ? `/${config.version}` : ''; const proxyConfig: Options = { target: config.url, changeOrigin: true, @@ -36,8 +37,8 @@ export const ui5Proxy = (config: ProxyConfig, options?: Options, filter?: Filter proxyRequestHandler(proxyReq, res, etag, logger); }, pathRewrite: { [config.path]: ui5Ver + config.path }, - onProxyRes: (proxyRes: IncomingMessage): void => { - proxyResponseHandler(proxyRes, etag); + onProxyRes: (proxyRes: IncomingMessage, req: Request): void => { + proxyResponseHandler(proxyRes, req, etag); }, onError: ( err: Error & { code?: string }, diff --git a/packages/ui5-proxy-middleware/src/base/utils.ts b/packages/ui5-proxy-middleware/src/base/utils.ts index 4fa04134c2..00c505ce00 100644 --- a/packages/ui5-proxy-middleware/src/base/utils.ts +++ b/packages/ui5-proxy-middleware/src/base/utils.ts @@ -15,11 +15,16 @@ import { t } from '../i18n'; * Sets an Etag which will be used for re-validation of the cached UI5 sources. * * @param proxyRes - proxy response object + * @param req * @param etag - ETag for the cached sources, normally the UI5 version */ -export const proxyResponseHandler = (proxyRes: IncomingMessage, etag: string): void => { +export const proxyResponseHandler = (proxyRes: IncomingMessage, req: Request, etag: string): void => { proxyRes.headers['Etag'] = etag; proxyRes.headers['cache-control'] = 'no-cache'; + if (proxyRes.statusCode === 404 && req.path.includes('/resources/sap/ushell/bootstrap/sandbox2.js')) { + proxyRes.statusCode = 302; + proxyRes.headers['location'] = '/test-resources/sap/ushell/bootstrap/sandbox.js'; + } }; /** diff --git a/packages/ui5-proxy-middleware/test/base/proxy.test.ts b/packages/ui5-proxy-middleware/test/base/proxy.test.ts index 181279e161..f8651840f5 100644 --- a/packages/ui5-proxy-middleware/test/base/proxy.test.ts +++ b/packages/ui5-proxy-middleware/test/base/proxy.test.ts @@ -132,7 +132,7 @@ describe('proxy', () => { if (typeof proxyConfig?.onProxyRes === 'function') { proxyConfig?.onProxyRes({} as any, {} as any, {} as any); expect(proxyResponseHandlerSpy).toHaveBeenCalledTimes(1); - expect(proxyResponseHandlerSpy).toHaveBeenCalledWith({}, 'W/"1.0.0"'); + expect(proxyResponseHandlerSpy).toHaveBeenCalledWith({}, {}, 'W/"1.0.0"'); } expect(createProxyMiddlewareSpy).toHaveBeenCalledWith( utils.filterCompressedHtmlFiles, diff --git a/packages/ui5-proxy-middleware/test/base/utils.test.ts b/packages/ui5-proxy-middleware/test/base/utils.test.ts index 2132d076fa..8fb8145786 100644 --- a/packages/ui5-proxy-middleware/test/base/utils.test.ts +++ b/packages/ui5-proxy-middleware/test/base/utils.test.ts @@ -36,8 +36,11 @@ describe('utils', () => { const proxyRes = { headers: {} as any }; + const proxyReq = { + headers: {} as any + }; const etag = 'W/MyEtag'; - proxyResponseHandler(proxyRes as any, etag); + proxyResponseHandler(proxyRes as any, proxyReq as any, etag); expect(proxyRes.headers['Etag']).toEqual(etag); expect(proxyRes.headers['cache-control']).toEqual('no-cache'); });