Skip to content

Repository files navigation

abap2UI5 samples-embed-control

abap2UI5 apps inside any UI5 app, with the npm package @abap2ui5/embed-control (developed in abap2UI5/embed-control): the examples, ready to read, run and install. A z2ui5.embed.Container control runs an abap2UI5 app - an ABAP class implementing z2ui5_if_app - in its own backend session, wherever the host app places it:

<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns:z2ui5="z2ui5.embed">
  <z2ui5:Container app="Z2UI5_CL_UI5_APP_HI_WORLD" height="400px"/>
</mvc:View>

main has the examples as one npm workspace, with their tests and the build of the branches - Develop. The branch standard has three host apps and a card:

Path
freestyle/ a UI5 freestyle app with three containers - the package is an npm dependency like any other
fiori-elements/ a Fiori elements app for OData V4, list report and object page, with the control in a custom section of the object page - the abap2UI5 app gets the key of the object on the page
fiori-elements-v2/ a Fiori elements app for OData V2 with the control in an extension of its object page, and in abap/ the RAP service it reads and the abap2UI5 app it starts - the app gets fields of the object on the page
card/ a UI Integration Card for SAP Build Work Zone that runs any abap2UI5 app - the class is a card parameter, the backend a card destination
src/ the freestyle app as the BSP Z2UI5_HOST, with the control from npm where ui5 build puts it - to try it on a system with a plain abapGit pull
VERSION the commit of main, the version of @abap2ui5/embed-control and the abap2UI5 tools the branch is built from

The branch rap is the OData V2 app on a system - one abapGit pull for a system with RAP:

Path
src/01/ the RAP service of fiori-elements-v2/abap - CDS view, metadata extension, service definition, OData V2 binding - and the abap2UI5 app Z2UI5_CL_EMBED_COUNTRY
src/02/ fiori-elements-v2 as the BSP Z2UI5_HOST_FE, on that service and starting that app
VERSION as on standard

None of them carries a copy of the abap2UI5 frontend: the control loads it from the abap2UI5 installation it talks to, so the frontend always has the version of that backend.

Include the package in your UI5 app

Four steps - the first three are the same in every app, the fourth places the control.

1. Install it - freestyle/package.json:

npm install @abap2ui5/embed-control

2. Take it into the build - freestyle/ui5.yaml. ui5 serve serves the control anyway; ui5 build copies it into dist/thirdparty/z2ui5/embed/ only for a dependency named here:

builder:
  settings:
    includeDependency:
      - "@abap2ui5/embed-control"

3. Register its namespace - freestyle/webapp/manifest.json:

"sap.ui5": {
  "resourceRoots": { "z2ui5.embed": "./thirdparty/z2ui5/embed/" }
}

thirdparty/, not resources/: an app deployed to an ABAP system answers every <app>/resources/ path from the UI5 of the system.

4. Place the control - in a view of your own, freestyle/webapp/view/Main.view.xml:

<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns:z2ui5="z2ui5.embed">
  <z2ui5:Container app="Z2UI5_CL_UI5_APP_HI_WORLD" height="400px"/>
</mvc:View>

or, in a Fiori elements app, in a custom section - below - or in an object page extension for OData V2 - further below - or in a card - at the end.

That is all a deployed app needs, as long as the page and abap2UI5 share an origin: the app served from the same system (BSP, launchpad), or an approuter that routes /sap/bc/z2ui5 to it. ui5 serve needs a proxy for /sap to the system - freestyle/ui5.yaml shows it. ui5-middleware-simpleproxy tells the backend the dev server's host in X-Forwarded-Host, and abap2UI5's CSRF check compares the browser's Origin with it - nothing else is needed.

Properties, events, the backend the control needs and the UI5 versions it supports are in the package README.

In a Fiori elements app: a custom section

The object page of a Fiori elements app takes content of its own as a custom section - an entry in the manifest and a fragment. There the control runs an abap2UI5 app for the object on the page: fiori-elements/webapp/manifest.json, in the object page's settings:

"content": {
  "body": {
    "sections": {
      "abap2UI5": {
        "template": "demo.fe.ext.Abap2UI5Section",
        "title": "abap2UI5",
        "position": { "placement": "After", "anchor": "General" }
      }
    }
  }
}

fiori-elements/webapp/ext/Abap2UI5Section.fragment.xml, bound to the object - ID is the key of the customer on the page, and ext/Abap2UI5Section.js turns it into the class to run and its parameters:

<z2ui5:Container
    core:require="{ Section: 'demo/fe/ext/Abap2UI5Section' }"
    app="{ path: 'ID', formatter: 'Section.app' }"
    params="{ path: 'ID', targetType: 'any', formatter: 'Section.params' }"
    height="420px"/>

The ABAP class reads the key with client->get( )-t_comp_params - a snippet, and why targetType: 'any' is there, are in fiori-elements/README.md. Another customer ends the running abap2UI5 session and starts a new one with its key.

A Fiori elements app routes by the URL hash, so the abap2UI5 behind it has to leave the hash to the page it is embedded in: abap2UI5 1.146.0 or later does. An older one clears the hash after every roundtrip, and the object page goes back to the list.

In a Fiori elements app for OData V2: an object page extension

The templates for OData V2 take content of their own as a view extension of the object page - again an entry in the manifest and a fragment, here a section after the facet General: fiori-elements-v2/webapp/manifest.json:

"sap.ui.viewExtensions": {
  "sap.suite.ui.generic.template.ObjectPage.view.Details": {
    "AfterFacet|Countries|General": {
      "type": "XML",
      "className": "sap.ui.core.Fragment",
      "fragmentName": "demo.fev2.ext.Abap2UI5Section",
      "sap.ui.generic.app": { "title": "abap2UI5" }
    }
  }
}

fiori-elements-v2/webapp/ext/Abap2UI5Section.fragment.xml hands three fields of the country on the page to the app:

<z2ui5:Container
    core:require="{ Section: 'demo/fev2/ext/Abap2UI5Section' }"
    app="{ parts: [ 'Country', 'Language', 'Nationality' ], formatter: 'Section.app' }"
    params="{ parts: [ 'Country', 'Language', 'Nationality' ], formatter: 'Section.params' }"
    height="420px"/>

The service is a RAP service, and it is part of the example: fiori-elements-v2/abap/ has the CDS view, its metadata extension with the facet, the service definition, the OData V2 binding and the abap2UI5 app Z2UI5_CL_EMBED_COUNTRY, which reads the fields by name and the country again from the view. The dev server answers the service from a mock under the binding's own paths; the branch rap has it all for a system - below. It is the successor of abap2UI5-addons/fiori-elements-integration, without its controller extension and its launchpad target mapping - fiori-elements-v2/README.md compares the two.

In SAP Build Work Zone: a UI Integration Card

The cards of SAP Build Work Zone are UI Integration Cards, and one of type Component runs a UI5 component of its own - here one with the control in its view. The card is generic: the class it runs is a card parameter, so an administrator places it on a page as often as needed and configures each one, the way an FLP tile names its class with ?app_start=. card/webapp/manifest.json names a destination instead of a URL, and the class as a parameter:

"sap.card": {
  "type": "Component",
  "configuration": {
    "destinations": { "abap2UI5": { "name": "ABAP2UI5" } },
    "parameters": { "app": { "value": "Z2UI5_CL_UI5_APP_HI_WORLD" } }
  }
}

card/webapp/Component.js resolves the destination in onCardReady - Work Zone answers with a path of its own origin that it proxies to the system behind the BTP destination - and hands the class, the endpoint and every further parameter to the control in card/webapp/view/Card.view.xml:

<z2ui5:Container app="{embed>/app}" endpoint="{embed>/endpoint}" params="{embed>/params}" height="{embed>/height}"/>

The further parameters reach the ABAP class as startup parameters, client->get( )-t_comp_params - one class, configured per card. Work Zone routes by the URL hash as well, so the card needs the same abap2UI5 as the Fiori elements app: 1.146.0 or later. card/README.md lists the parameters and the way into Work Zone, and what to check on the first card.

Run the examples

git clone --branch standard https://github.com/abap2UI5/samples-embed-control.git
cd samples-embed-control/freestyle      # or fiori-elements, fiori-elements-v2, card
npm install

Against an SAP system - npm start: set the system's URL as baseUri in ui5.yaml, copy .env.example to .env and put user and password there.

Without an SAP system - npm run start-local: the proxy goes to http://localhost:3000 (ui5-local.yaml), abap2UI5 transpiled to JavaScript and run in Node: the npm package @abap2ui5/node-runtime, in a folder of its own, with Node 22 or later:

mkdir abap2ui5-backend && cd abap2ui5-backend
npm install @abap2ui5/node-runtime express
node --input-type=module -e 'import { serve } from "@abap2ui5/node-runtime"; await serve({ port: 3000 });'

Either way, ui5 serve serves only the libraries framework.libraries in the example's ui5.yaml names: the ones the ABAP views of the embedded apps use, and sap.ui.codeeditor for abap2UI5's developer tools (Ctrl+F12). A library missing there fails in the browser console with a script load error; an app deployed to a system has every library of that system.

The Fiori elements apps and the card need abap2UI5 1.146.0 or later. The READMEs of freestyle/, fiori-elements/, fiori-elements-v2/ and card/ have both ways. The Fiori elements apps answer their own OData services from mock data, and take SAPUI5 from npm - Fiori elements is not part of OpenUI5. The card opens on a preview page: three cards and a stand-in for Work Zone. npm run build writes an app - or the card - to deploy into dist/.

Install the BSP

  1. abap2UI5 1.145.0 or later, with its HTTP service /sap/bc/z2ui5 active - the node the standard branch of abap2UI5/frontend brings, for example.
  2. Pull the branch standard of this repository with abapGit into a new package. It creates the BSP Z2UI5_HOST with the ICF nodes /sap/bc/ui5_ui5/sap/z2ui5_host and /sap/bc/bsp/sap/z2ui5_host - nothing else, and nothing shared with the Z2UI5 BSP of abap2UI5/frontend. abapGit reads src/ only; freestyle/, fiori-elements/, fiori-elements-v2/ and card/ stay out of the system.
  3. Activate the two ICF nodes in SICF.
  4. Open /sap/bc/ui5_ui5/sap/z2ui5_host/index.html.

What to look for: three hello world apps. In the browser's network tab, thirdparty/z2ui5/embed/Container.js and .css of the BSP, one GET /sap/bc/z2ui5?z2ui5-bundle and no other file of the frontend; every POST goes to /sap/bc/z2ui5. An abap2UI5 older than 1.145.0 answers the bundle request with its page - the control then says so ("abap2UI5 could not start") instead of starting.

BSP Z2UI5_HOST                             the host app
  ├─ thirdparty/z2ui5/embed/               the control, from npm
  └─ z2ui5.embed.Container
       ├─ GET  /sap/bc/z2ui5?z2ui5-bundle   the frontend as a script, once per page
       └─ POST /sap/bc/z2ui5                the roundtrips, one session per control

The Fiori elements app for OData V4 has no BSP: it needs its OData service, which the example mocks and a system does not have - an app of your own brings its RAP service. The one for OData V2 brings its RAP service, and has its BSP on the branch rap. The card has none: a card is deployed to its host.

Install the branch rap

The Fiori elements app for OData V2 with its RAP service, on a system with RAP view entities and OData V2 bindings - SAP S/4HANA 2020 (ABAP 7.55) or later, standard ABAP (the view reads T005T, which ABAP Cloud does not release).

  1. abap2UI5 1.146.0 or later, with its HTTP service /sap/bc/z2ui5 active.
  2. Pull the branch rap of this repository with abapGit into a new package. It creates the RAP service and Z2UI5_CL_EMBED_COUNTRY (src/01) and the BSP Z2UI5_HOST_FE with the ICF nodes /sap/bc/ui5_ui5/sap/z2ui5_host_fe and /sap/bc/bsp/sap/z2ui5_host_fe (src/02) - nothing shared with the branch standard, which installs next to it.
  3. Publish the service binding Z2UI5_UI_EMBED_COUNTRY_O2 (ADT: open it, Publish) if the pull did not, and activate the two ICF nodes in SICF.
  4. Open /sap/bc/ui5_ui5/sap/z2ui5_host_fe/index.html.

What to look for: the countries of the system in the list report; on the object page a section abap2UI5 after General Information, in it the startup parameters as the page sent them and the country as the app read it from Z2UI5_C_EMBED_COUNTRY. Another country starts the app anew, and the URL stays on the object page.

BSP Z2UI5_HOST_FE                                  the Fiori elements app
  ├─ GET  /sap/opu/odata/sap/Z2UI5_UI_EMBED_COUNTRY_O2/   the RAP service
  └─ z2ui5.embed.Container                         in the object page
       ├─ GET  /sap/bc/z2ui5?z2ui5-bundle           the frontend, once
       └─ POST /sap/bc/z2ui5                        Z2UI5_CL_EMBED_COUNTRY

Known limitations

  • One frontend per page: the first control that starts decides where it comes from; every control still sends its roundtrips to its own endpoint.
  • Embedding is still page-wide in places - busy indicator, title, the sap.m.App root - until abap2UI5's embedded mode covers them (backlog item); the URL hash is the host's from abap2UI5 1.146.0 on.
  • Custom controls from Z2UI5_CCI/Z2UI5_CCC: the bundle hands over their paths like abap2UI5's own page does; not tried yet.
  • The card is tried against a stand-in for Work Zone, not yet on a Work Zone tenant: abap2UI5's Origin check behind the destination proxy is the first thing to look at ("What to check on the first card" in card/README.md).
  • The host app's own Component-preload.js does not exist in a BSP pulled with abapGit (a page name may not contain a hyphen): UI5 answers the 404 by loading the host's few files one by one. An app deployed from its ui5 build output has it.

Develop

main is the source of both branches: freestyle/, fiori-elements/, fiori-elements-v2/ and card/ are the examples, one npm workspace that installs the control from npm once, for all of them, in the version package-lock.json names.

npm ci
npm run start-local              # the freestyle example - start, start:fe, start:fe-v2, start:card for the others
Command
npm run lint / npm run format:check ESLint and Prettier
npm run abaplint the ABAP of fiori-elements-v2/abap against abap2UI5's main (abaplint.jsonc)
npm run build ui5 build of the examples - the control lands in dist/thirdparty/z2ui5/embed/
ABAP2UI5_DIR=../abap2UI5 npm run bsp the branches in out/standard/ and out/rap/ (scripts/build-bsp.mjs), built with abap2UI5's BSP tools and checked with its page invariants
npx playwright test the examples in a browser against the backend on port 3000 - the freestyle one on UI5 1.136 and 1.71, the Fiori elements ones on SAPUI5 1.136, the card on OpenUI5 1.136 (PW_CHROMIUM_PATH for an installed Chromium)

CI (ci.yaml) runs all of them on every pull request and every night, the e2e tests against abap2UI5 main and against 1.145.0, the backend floor of the control. On every push to main, deliver.yaml runs the same CI, builds the branches and writes each as one commit on top of main - never change a branch by hand. A new version of the control arrives as a pull request that bumps it in package-lock.json (dependabot, weekly, or by hand after a release).

abap2UI5/embed-control runs the branch build and the e2e tests of main in its own CI, with the control of its commit in place of the one from npm - so a change to the control is tested against these examples before it is published.

Content Where
the examples, the RAP service, the tests, the build of the branches, this README here, on main
the branches standard and rap written by deliver.yaml from main - a hand edit is gone with the next delivery
the control abap2UI5/embed-control - packages/embed-control, published to npm as @abap2ui5/embed-control
the abap2UI5 frontend and ?z2ui5-bundle, the BSP tooling abap2UI5/abap2UI5 - app/webapp, z2ui5_cl_ui5_http_handler, tools/

Issues

For bug reports or feature requests, open an issue here (the examples), in abap2UI5/embed-control (the control) or abap2UI5/abap2UI5 (the frontend, the backend).

About

Frontend of abap2UI5 with Embed Control (optional)

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages