Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preview support for UI5 2.x #2192

Merged
merged 22 commits into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/preview-2.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@sap-ux-private/preview-middleware-client": patch
"@sap-ux/preview-middleware": patch
"@sap-ux/ui5-proxy-middleware": patch
---

Preview support for UI5 2.x
35 changes: 35 additions & 0 deletions packages/preview-middleware-client/src/flp/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Calculates the script content for accessing the right sap/ushell/bootstrap sandbox.
*/
interface Window {
'sap-ui-config': {
[key: string]: (fnCallback: () => void) => void;
};
}

(window as unknown as Window)['sap-ui-config'] = {
'xx-bootTask': ushellBootstrap
};

export function ushellBootstrap(fnCallback: () => void): void {
fetch('/resources/sap-ui-version.json')
heimwege marked this conversation as resolved.
Show resolved Hide resolved
.then((resp) => resp.json())
.then((json) => {
const version = json?.version;
const major = version ? parseInt(version.split('.')[0], 10) : 2;
const src =
major >= 2
? '/resources/sap/ushell/bootstrap/sandbox2.js'
: '/test-resources/sap/ushell/bootstrap/sandbox.js';
const shellBootstrap = document.getElementById('sap-ushell-bootstrap');
if (shellBootstrap) {
shellBootstrap.onload = () => {
(window as unknown as Window)['sap-ui-config']['xx-bootTask'](fnCallback);
};
shellBootstrap.setAttribute('src', src);
}
})
.catch((error) => {
throw error;
});
}
26 changes: 21 additions & 5 deletions packages/preview-middleware-client/src/flp/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ 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';
import { getError } from '../cpe/error-utils';
import initConnectors from './initConnectors';
tobiasqueck marked this conversation as resolved.
Show resolved Hide resolved

/**
* SAPUI5 delivered namespaces from https://ui5.sap.com/#/api/sap
Expand Down Expand Up @@ -46,6 +49,10 @@ interface Manifest {
};
}

type InternalContainer = typeof sap.ushell.Container & {
createRendererInternal: typeof sap.ushell.Container.createRenderer;
};

type AppIndexData = Record<
string,
{
Expand Down Expand Up @@ -264,16 +271,16 @@ export async function init({
customInit?: string | null;
}): Promise<void> {
const urlParams = new URLSearchParams(window.location.search);
const container = sap?.ushell?.Container ?? (sap.ui.require('sap/ushell/Container') as typeof sap.ushell.Container);
const container = sap?.ushell?.Container ?? (sap.ui.require('sap/ushell/Container') as InternalContainer);
let scenario: string = '';
const { version } = (await VersionInfo.load()) as { version: string };
// Register RTA if configured
if (flex) {
const flexSettings = JSON.parse(flex) as FlexSettings;
scenario = flexSettings.scenario;
container.attachRendererCreatedEvent(async function () {
const lifecycleService = await container.getServiceAsync<AppLifeCycle>('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;
Expand Down Expand Up @@ -317,6 +324,9 @@ export async function init({
await registerComponentDependencyPaths(JSON.parse(appUrls), urlParams);
}

// Load rta connector
Klaus-Keller marked this conversation as resolved.
Show resolved Hide resolved
await initConnectors();

// Load custom initialization module
if (customInit) {
sap.ui.require([customInit]);
Expand All @@ -326,15 +336,21 @@ 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 InternalContainer).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.'));
}).catch((e) => {
const error = getError(e);
Log.error('Sandbox initialization failed: ' + error.message);
});
}
15 changes: 8 additions & 7 deletions packages/preview-middleware-client/src/flp/initConnectors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import VersionInfo from 'sap/ui/VersionInfo';

/**
* Initializes UI5 connectors based on the current UI5 version.
*
Expand All @@ -7,13 +9,14 @@
*
* @example
* intiConnectors(); // Simply call the function without any arguments.
* @returns {void}
*/
export function initConnectors(): void {
const version = sap.ui.version;
const minor = parseInt(version.split('.')[1], 10);
export default async function initConnectors(): Promise<void> {
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();
});
Expand All @@ -26,5 +29,3 @@ export function initConnectors(): void {
);
}
}

initConnectors();
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { documentMock } from 'mock/window';
import { ushellBootstrap } from '../../../src/flp/bootstrap';

describe('flp/ushellBootstrap', () => {
afterEach(() => {
jest.restoreAllMocks();
});

function dummyCallback(): void {}

test('ushell src when ui5 version is 1.x', async () => {
const fetchSpy = jest
.spyOn(global, 'fetch')
.mockImplementation(
jest.fn(() => Promise.resolve({ json: () => Promise.resolve({ version: '1.126.0' }) })) as jest.Mock
);
const htmlElement = {
onload: jest.fn(),
setAttribute: jest.fn()
};
documentMock.getElementById.mockReturnValue(htmlElement);

await ushellBootstrap(dummyCallback);

expect(fetchSpy).toHaveBeenCalled();
});
});
21 changes: 16 additions & 5 deletions packages/preview-middleware-client/test/unit/flp/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -196,6 +197,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);
Expand All @@ -207,7 +209,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);
Expand Down Expand Up @@ -245,7 +247,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);
Expand Down Expand Up @@ -275,17 +277,26 @@ describe('flp/init', () => {
const initRtaMock = jest.fn();
const plugnScriptMock = jest.fn();
await requireCb(initRtaMock, plugnScriptMock);
expect(initRtaMock).toBeCalledWith(expect.anything(), plugnScriptMock);
expect(initRtaMock).toBeCalled();
});

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]);
});
});
});
Original file line number Diff line number Diff line change
@@ -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'],
Expand All @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions packages/preview-middleware-client/types/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
declare module 'sap/open/ux/preview/global' {
heimwege marked this conversation as resolved.
Show resolved Hide resolved
interface Window {
'sap-ui-config': {
[key: string]: (fnCallback: () => void) => void;
};
}
}
7 changes: 2 additions & 5 deletions packages/preview-middleware/templates/flp/sandbox.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
};
</script>

<script src="<%- basePath %>/test-resources/sap/ushell/bootstrap/sandbox.js" id="sap-ushell-bootstrap"></script>
<script src="/preview/client/flp/bootstrap.js" id="preview-bootstrap"></script>
<script id="sap-ushell-bootstrap"></script>
<!-- Bootstrap the UI5 core library. 'data-sap-ui-frameOptions="allow"'' is a NON-SECURE setting for test environments -->
<script id="sap-ui-bootstrap"
src="<%- basePath %>/resources/sap-ui-core.js"
Expand All @@ -61,10 +62,6 @@
data-open-ux-preview-libs-manifests='<%- JSON.stringify(Object.values(apps).map(app => app.url)) %>'<% } %>>
</script>

<script type="text/javascript">
(() => sap.ui.require(['open/ux/preview/client/flp/initConnectors']))()
</script>

<% if (locals.flex && flex?.developerMode) { %>
<!-- Hides Rta native toolbar -->
<style>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ exports[`config generatePreviewFiles minimum settings 1`] = `
};
</script>

<script src=\\"../test-resources/sap/ushell/bootstrap/sandbox.js\\" id=\\"sap-ushell-bootstrap\\"></script>
<script src=\\"/preview/client/flp/bootstrap.js\\" id=\\"preview-bootstrap\\"></script>
<script id=\\"sap-ushell-bootstrap\\"></script>
<!-- Bootstrap the UI5 core library. 'data-sap-ui-frameOptions=\\"allow\\"'' is a NON-SECURE setting for test environments -->
<script id=\\"sap-ui-bootstrap\\"
src=\\"../resources/sap-ui-core.js\\"
Expand All @@ -97,10 +98,6 @@ exports[`config generatePreviewFiles minimum settings 1`] = `
data-sap-ui-oninit=\\"module:open/ux/preview/client/flp/init\\">
</script>

<script type=\\"text/javascript\\">
(() => sap.ui.require(['open/ux/preview/client/flp/initConnectors']))()
</script>


</head>

Expand Down Expand Up @@ -156,7 +153,8 @@ Object {
};
</script>

<script src=\\"../test-resources/sap/ushell/bootstrap/sandbox.js\\" id=\\"sap-ushell-bootstrap\\"></script>
<script src=\\"/preview/client/flp/bootstrap.js\\" id=\\"preview-bootstrap\\"></script>
<script id=\\"sap-ushell-bootstrap\\"></script>
<!-- Bootstrap the UI5 core library. 'data-sap-ui-frameOptions=\\"allow\\"'' is a NON-SECURE setting for test environments -->
<script id=\\"sap-ui-bootstrap\\"
src=\\"../resources/sap-ui-core.js\\"
Expand All @@ -174,10 +172,6 @@ Object {
data-sap-ui-oninit=\\"module:open/ux/preview/client/flp/init\\">
</script>

<script type=\\"text/javascript\\">
(() => sap.ui.require(['open/ux/preview/client/flp/initConnectors']))()
</script>


</head>

Expand Down Expand Up @@ -236,7 +230,8 @@ Object {
};
</script>

<script src=\\"../test-resources/sap/ushell/bootstrap/sandbox.js\\" id=\\"sap-ushell-bootstrap\\"></script>
<script src=\\"/preview/client/flp/bootstrap.js\\" id=\\"preview-bootstrap\\"></script>
<script id=\\"sap-ushell-bootstrap\\"></script>
<!-- Bootstrap the UI5 core library. 'data-sap-ui-frameOptions=\\"allow\\"'' is a NON-SECURE setting for test environments -->
<script id=\\"sap-ui-bootstrap\\"
src=\\"../resources/sap-ui-core.js\\"
Expand All @@ -254,10 +249,6 @@ Object {
data-sap-ui-oninit=\\"module:open/ux/preview/client/flp/init\\">
</script>

<script type=\\"text/javascript\\">
(() => sap.ui.require(['open/ux/preview/client/flp/initConnectors']))()
</script>


</head>

Expand Down
Loading
Loading