Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
251f40f
Bring controls newer than UI5 1.71 into the porting scope
claude Oct 20, 2026
5d1bf4e
Scaffold the 48 post-1.71 control samples (apps 624-671)
claude Oct 20, 2026
5059ca6
WIP: ports of the post-1.71 control samples in progress
claude Oct 20, 2026
ec4d0fe
WIP: ports of the post-1.71 control samples in progress
claude Oct 20, 2026
4739fc7
WIP: ports of the post-1.71 control samples in progress
claude Oct 20, 2026
6f24e95
WIP: ports of the post-1.71 control samples in progress
claude Oct 20, 2026
7254ee4
WIP: ports of the post-1.71 control samples in progress
claude Oct 20, 2026
ce01391
Port the 48 samples of controls newer than UI5 1.71 (apps 624-671)
claude Oct 20, 2026
dd8fe12
Settle the gates and records after the post-1.71 control ports
claude Oct 20, 2026
c37bd33
e2e: boot app 662 with the theme CSS instead of failing unthemed
claude Oct 20, 2026
c4f5fd2
e2e: app 600 waits for the probes' round trips, not for the busy indi…
claude Oct 20, 2026
2b3f947
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
8b6e82b
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
5818536
Regenerate STATUS, catalogue and overview after closing LIVE_TESTs
claude Oct 20, 2026
3a185a4
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
92e6a86
WIP: e2e interaction modules; LIVE_TESTs of apps 657-661 closed
claude Oct 20, 2026
c94cbe6
Fix the DynamicDateRange filter args and silence the 638 countdown tick
claude Oct 20, 2026
38e6759
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
6ef625f
App 638: pass the no-busy flag as the literal `X`
claude Oct 20, 2026
735bb4b
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
b9326e5
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
28fe579
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
e890d5f
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
56ac2c0
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
b09ca8f
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
2db16ca
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
798f1f1
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
06a4949
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
6fb0f47
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
9147596
WIP: e2e interaction modules for the post-1.71 control ports
claude Oct 20, 2026
39de556
Regenerate STATUS, catalogue and overview after closing LIVE_TESTs 65…
claude Oct 20, 2026
e188f42
e2e interaction modules for p13n and VariantManagement; LIVE_TESTs of…
claude Oct 20, 2026
bf4d695
Fix the p13n and VariantManagement ports the e2e interactions caught
claude Oct 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
31 changes: 31 additions & 0 deletions .claude/skills/e2e-debugging/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,37 @@ verdicts below turned out to be harness effects.
property through the UI5 API — that bypasses the binding the test exists to
prove. Same family: assert the *effect* (a bound property, a rendered
class), not the pixels (apps 207/130).
- **An interaction module never names the port** — `r.url().includes(':3000')`
matched nothing under `--port 3110`, and apps 351/353/demo_004 failed a
full run that was perfectly healthy (2026-10-20). Compare origins:
`new URL(r.url()).origin === new URL(page.url()).origin`.
- **Lessons the post-1.71 control ports paid for (2026-10-20)** — each a port
defect that only a running app showed:
- an XML event-handler expression knows `$controller`/`$event` and nothing
else: `JSON.stringify(…)` in a `t_arg` throws *Unsupported global
identifier 'JSON'* and the event never leaves the browser (app 650). Pass
the array/object itself; it arrives as JSON - with its keys **sorted
alphabetically** by the framework;
- `DynamicDateRange.toDates( )` returns `UniversalDate`s, which serialize as
`{oDate, sCalendarType}`: send `.getJSDate()` (apps 639/640/642);
- a `sap.m.p13n.Popup` declared in a view **leaks its panels** when it is
never opened (its `exit` destroys only the Dialog `open()` creates), and
the next-but-one re-render dies on a duplicate panel id - build it as a
`popup_display` fragment and `popup_destroy` it on close (apps 645/648/649);
- `sap.m.VariantManagement` with a **bound** `items` template filters its
own favourites list to nothing on 1.152 (it applies the template's paths to
its internal `$mVariants` model) - emit static `VariantItem`s (app 651);
- `translate( )` with a `]` in FROM breaks on the transpiled runtime (the set
becomes an unescaped regex class) - use `replace( … occ = 0 )` (app 651).
- **A control that sizes itself from its own CSS can loop unthemed** —
`sap.f.AvatarGroup` measures its unstyled avatars, re-renders with fewer,
measures again and dies on *"Rendering has been re-started too many times"*
(app 662). That is the harness, not the port: declare
`"e2e_smoke": { "theme": true, "reason": "…" }` in the sidecar and the port
boots with the theme CSS from sdk.openui5.org. It is no skip — the port runs
the full gate and its interaction themed — and it is re-verified like one:
the port is booted unthemed as well, and a declaration whose port passes
that way too FAILS as stale.
- **OverflowToolbar controls ARE drivable headless — open the overflow
popover first.** In the harness' 1280 px viewport a toolbar folds almost
everything into its `Additional Options` button, so a direct
Expand Down
10 changes: 6 additions & 4 deletions .claude/skills/port-a-sample/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -517,10 +517,12 @@ the two is passed, never both and never neither.

#### The 1.71 rule in practice

The **control** must exist since UI5 1.71 and not be deprecated — otherwise
the sample is out of scope and is never ported (pre-check with
`node scripts/scope-of.mjs <entity>`); never silently substitute a different
control. **Members** (properties/aggregations/associations/events) newer than
The **control** must not be deprecated — otherwise the sample is out of scope
and is never ported (pre-check with `node scripts/scope-of.mjs <entity>`);
never silently substitute a different control. A **control** newer than 1.71
is in scope since 2026-10-20: it is kept 1:1 and declared as a `POST_171`
deviation naming the control (the scaffolder writes it), which files the port
under `src/02` (AGENTS §1, §3). **Members** (properties/aggregations/associations/events) newer than
1.71 ARE kept when the original uses them — 1:1 fidelity wins (AGENTS §5) —
and each one is declared as a `POST_171` deviation naming the member (app 040
keeps `showClearIcon` @1.94 that way; the app then needs a UI5 release ≥ that
Expand Down
6 changes: 4 additions & 2 deletions .claude/skills/scaffold-a-port/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,12 @@ that is the actual porting work):
`meta/` sidecar. Since 2026-08-04 it **enforces the two pre-checks
that used to be manual**: a HOLDOUT sample (`ui5/holdout.json`) and an
out-of-scope sample (same verdict as `generate-coverage.mjs` `scopeOf`:
1.71 floor, deprecation, non-app family — facts from the universe enriched
deprecation, non-app family — facts from the universe enriched
with `ui5/properties.json`) are refused with the facts printed;
`ui5/scope-exceptions.json` entries pass with a note, `--force` overrides
as a recorded maintainer decision. The stub is a TODO placeholder view: it passes
as a recorded maintainer decision. A control newer than 1.71 is in scope
(AGENTS §1): the scaffolder writes its `POST_171` deviation into the sidecar
and files the port under `src/02/<lib>/` straight away. The stub is a TODO placeholder view: it passes
abaplint / pattern-lint / view-gates immediately, and
`structural_diff` (correctly) fails until you rebuild the view 1:1. Needs an
OpenUI5 checkout (`OPENUI5_SRC`, default `../fork-openui5`). `--dry-run` to
Expand Down
38 changes: 23 additions & 15 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,16 @@ rebuild it as an abap2UI5 sample**. Doing that systematically reveals the gaps
between what UI5 ships and what abap2UI5 can already express — and those gaps
become the backlog to close.

**Porting scope**: a sample is in scope when its **control exists since UI5
1.71** and is **not deprecated** in the current release (legacy-free ready) —
computed per sample from `ui5/universe.json` by `generate-coverage.mjs`
(`scopeOf`). Out-of-scope samples stay listed in `api.md` (marked `✗`) but are
**Porting scope**: a sample is in scope when its **control is not
deprecated** in the current release (legacy-free ready) — computed per sample
from `ui5/universe.json` by `generate-coverage.mjs` (`scopeOf`). A control
**newer than UI5 1.71** is in scope too (maintainer decision 2026-10-20 — it
was out of scope before, which left 48 samples of Avatar, IllustratedMessage,
DynamicDateRange, SidePanel, p13n, UploadSetwithTable & co. unported): its
port keeps the control 1:1 and declares it as a **`POST_171` deviation naming
the control**, which files the port under `src/02` (§3). `generate-coverage.mjs`
fails a port of a post-1.71 control without that deviation, and the scaffolder
writes it for you. Out-of-scope samples stay listed in `api.md` (marked `✗`) but are
**never ported**; `node scripts/generate-coverage.mjs --backlog` prints the
in-scope, unported samples for batch planning.

Expand Down Expand Up @@ -109,7 +115,7 @@ family **before** the control has to resolve in the fork checkout
(`ControllerExtension` carries `entity: null` in the universe and would
otherwise report `UNRESOLVED`). Adding a family is a maintainer decision —
write the reason into the file; a ported sample that matches hits the same
hard scope gate as a deprecated/newer one.
hard scope gate as a deprecated one.

> **⚠️ Verify scope from source before porting.** The gate is not blind:
> `ui5/properties.json` carries each control's class-level
Expand Down Expand Up @@ -276,17 +282,18 @@ naming the folder it belongs in. A port needs a newer runtime in two ways, and
both are committed facts, so the verdict is offline and deterministic:

- it **keeps a post-1.71 member** — always a `POST_171` deviation in the sidecar;
- its **control itself is post-1.71** — which needs no deviation (the sample uses
the control as the original does) and can only exist as a maintainer-decided
entry in `ui5/scope-exceptions.json`, since the scope gate blocks every other
post-1.71 control. That entry pins the control's `@since`, which is what
`lib-packages.mjs` reads (app 141, `sap.ui.core.InvisibleMessage` @1.78, is
the case with no deviation at all).
- its **control itself is post-1.71** — also a `POST_171` deviation, naming the
control (§1; `generate-coverage.mjs` fails the port without it). Until
2026-10-20 such a port could only exist as a `ui5/scope-exceptions.json`
entry whose pinned `@since` `lib-packages.mjs` read; that path is gone with
the scope change.

So **declaring the first `POST_171` deviation on a port moves it from
`src/01/<lib>/` to `src/02/<lib>/`** (and dropping the last one moves it back);
`scaffold.mjs` starts every fresh port in the `<= 1.71` half of its flavour,
which is where a port with no deviations belongs.
which is where a port with no deviations belongs — except a port of a
post-1.71 control, which it scaffolds with that `POST_171` deviation straight
into `src/02`.

Below the library there is **no further level**: the former batch subpackages
`src/<NN>/b<nn>/` were flattened away on 2026-08-12, when the corpus stood at
Expand Down Expand Up @@ -614,9 +621,10 @@ source of truth:
as-is; only improve the trailing text to a human phrase when you know one
(e.g. `sap.m.Switch - Some say it is only a switch...`). Do not agonize over
entity-vs-library — existing ports use both; keep the scaffolder default.
- The **control** must exist since UI5 1.71 and not be deprecated — samples
whose control is newer or deprecated are **out of scope** (§1) and never
enter a batch. **Members (properties/aggregations/associations/events)
- The **control** must not be deprecated — samples whose control is
deprecated are **out of scope** (§1) and never enter a batch. A control
newer than 1.71 is in scope and kept 1:1, declared as a `POST_171`
deviation naming the control (§1, §3). **Members (properties/aggregations/associations/events)
newer than 1.71 ARE kept when the original uses them — 1:1 fidelity wins**
(policy decision). Every such member must be declared with a `POST_171`
deviation naming it (the `property_gate` enforces this via
Expand Down
1 change: 1 addition & 0 deletions CAPABILITIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ abap2UI5.
| Composite/array properties (RangeSlider `range="[lo,hi]"`) | 🔶 | split into the scalar sibling properties the control keeps in sync (`value`/`value2`) | app 045 |
| Literal line breaks inside attribute values (`&#xA;` in the original) | ✅ | write the break as `\n` in a `\|...\|` template — `xml_escape` emits it as `&#xA;`/`&#xD;`/`&#x9;` so it survives XML attribute-value normalization | app 035 (`noDataText`); builder fix 2026-07-16 |
| Raw text / CDATA child nodes | ❌ | `z2ui5_cl_ui5_view_builder` has element+attribute nodes only; for markup/CSS use the `core:HTML` `content` attribute (row above) | app 026 NOTES |
| Registering an additional **illustration set** (`IllustrationPool.registerIllustrationSet` in `Component.js` - the `tnt` set, an app's `Custom` set) for `sap.m.IllustratedMessage` | ❌ | no frontend target reaches `sap.m.IllustrationPool` (the `CONTROL_GLOBAL` targets carry `ICON_POOL` but no illustration counterpart), and `IllustratedMessage.src` resolves `sap-illustration://` through the same registry. The view ports 1:1; the illustration area stays empty and UI5 logs the set as not registered. Default-set (`sapIllus`) illustrations render. An `ILLUSTRATION_POOL` target with `registerIllustrationSet( setFamily, setURI )`, the analogue of `ICON_POOL` / `registerFont`, would close it | apps 630, 635-638 (`IMPROVISED`; 630/635 declare a `render_smoke` skip) |
| A CSS value on a control that has **no matching property** (the sample writes it onto the DOM node) | 🔶 | `follow_up_action( control_by_id, <id> / css / <property> / <value> )` writes one whitelisted declaration (width, height, color, background-color, font-size, opacity, …) onto the control's own DOM ref — the abap2UI5 form of the samples' `byId(x).$().width(v + '%')`. **Prefer a bound property wherever the control has one** (apps 213/214); this is only for the residue, e.g. `sap.m.Page`, which has no `width`. The value may be a client expression (`${$parameters>/value} + '%'`), so a Slider drag stays roundtrip-free | apps 138/267/269 (`DynamicSideContent` width sliders); upstream `pr/control-inline-style` (2026-08-05) |

## Popups & messages
Expand Down
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,12 @@ sample and its ABAP class next to each other and compare line by line.
<br>

This repository is generated and gated by an AI coding agent: from every
official demo kit sample of the covered libraries whose control **exists
since UI5 1.71** and is **not deprecated** (legacy-free ready), it builds an
official demo kit sample of the covered libraries whose control is **not
deprecated** (legacy-free ready), it builds an
abap2UI5 app — exposing the **functional gaps** between what UI5 offers and
what abap2UI5 can already express, so they can be closed. Deprecated or newer
controls are listed as out of scope. The pipeline:
what abap2UI5 can already express, so they can be closed. Deprecated controls
are listed as out of scope; a control newer than UI5 1.71 is ported into
`src/02`. The pipeline:

1. **Read** — clone [OpenUI5](https://github.com/SAP/openui5) and scan every
demo kit sample of the covered libraries
Expand All @@ -113,7 +114,7 @@ controls are listed as out of scope. The pipeline:
4. **Report** — regenerate the [coverage](#coverage) tables and the in-system
overview app. In api.md, `—` marks an in-scope sample not yet ported (the
backlog), `⊘` one reserved as hold-out (in scope, unported on purpose) and
`✗` an out-of-scope one (deprecated / newer than UI5 1.71).
`✗` an out-of-scope one (deprecated control, or not an app view).

Nothing graduates out of here. Since 2026-08-12 this repository is the home of
the demo kit rebuilds (AGENTS.md §1) — `checked` is the top rung of the quality
Expand Down Expand Up @@ -212,25 +213,25 @@ have an abap2UI5 port.

<!-- coverage:start -->

Overall **617 / 617** portable demo kit samples ported (100.0 %).
**In scope**: samples whose control exists since **UI5 1.71** and is **not deprecated** (legacy-free ready).
Out of scope: 113 of 742 samples — 21 on deprecated controls, 52 on controls newer than 1.71, 37 that are not app views (UI5 test infrastructure, Component routing, view-templating demos — see `ui5/scope-nonapp.json`), 3 demo apps without an owning control.
Plus **5** ported samples outside that scope — maintainer-decided exceptions (`ui5/scope-exceptions.json`, listed in [STATUS.md](STATUS.md)); they are not counted as coverage of the in-scope backlog.
Overall **669 / 669** portable demo kit samples ported (100.0 %).
**In scope**: samples whose control is **not deprecated** (legacy-free ready). 52 of them use a control newer than **UI5 1.71** — their ports need a newer runtime and are filed under `src/02`.
Out of scope: 61 of 742 samples — 21 on deprecated controls, 37 that are not app views (UI5 test infrastructure, Component routing, view-templating demos — see `ui5/scope-nonapp.json`), 3 demo apps without an owning control.
Plus **1** ported samples outside that scope — maintainer-decided exceptions (`ui5/scope-exceptions.json`, listed in [STATUS.md](STATUS.md)); they are not counted as coverage of the in-scope backlog.
Control metadata from OpenUI5 **1.152.0**.

| Module | Samples | In scope | Reserved | To port | Ported | Coverage | |
|--------|--------:|---------:|---------:|--------:|-------:|---------:|---|
| `sap.f` | 46 | 34 | | 34 | 34 | 100.0 % | ██████████ |
| `sap.m` | 461 | 403 | 12 | 391 | 391 | 100.0 % | ██████████ |
| `sap.f` | 46 | 46 | | 46 | 46 | 100.0 % | ██████████ |
| `sap.m` | 461 | 442 | 12 | 430 | 430 | 100.0 % | ██████████ |
| `sap.tnt` | 17 | 17 | | 17 | 17 | 100.0 % | ██████████ |
| `sap.ui.codeeditor` | 2 | 2 | | 2 | 2 | 100.0 % | ██████████ |
| `sap.ui.core` | 63 | 20 | | 20 | 20 | 100.0 % | ██████████ |
| `sap.ui.core` | 63 | 21 | | 21 | 21 | 100.0 % | ██████████ |
| `sap.ui.integration` | 4 | 4 | | 4 | 4 | 100.0 % | ██████████ |
| `sap.ui.layout` | 61 | 61 | | 61 | 61 | 100.0 % | ██████████ |
| `sap.ui.table` | 21 | 21 | | 21 | 21 | 100.0 % | ██████████ |
| `sap.ui.unified` | 22 | 22 | | 22 | 22 | 100.0 % | ██████████ |
| `sap.uxap` | 45 | 45 | | 45 | 45 | 100.0 % | ██████████ |
| **Total** | **742** | **629** | **12** | **617** | **617** | **100.0 %** | ██████████ |
| **Total** | **742** | **681** | **12** | **669** | **669** | **100.0 %** | ██████████ |

**Reserved** — 12 in-scope samples are deliberately *not* ported. They are the hold-out set (`ui5/holdout.json`, see [TRAINING.md](TRAINING.md#measuring-progress)): never used as prompt references, kept out of batch planning, and regenerated from scratch to measure the generator itself — CI-green on the first try, structural-diff violations, review findings per app. Spending one as a measurement is what ports it, so they leave this column by being used, not by being worked off. They are excluded from the coverage denominator because they are not backlog. **The portable backlog is zero.**

Expand Down
Loading
Loading