diff --git a/.claude/skills/e2e-debugging/SKILL.md b/.claude/skills/e2e-debugging/SKILL.md index b14c53d92..fe3ba0c55 100644 --- a/.claude/skills/e2e-debugging/SKILL.md +++ b/.claude/skills/e2e-debugging/SKILL.md @@ -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 diff --git a/.claude/skills/port-a-sample/SKILL.md b/.claude/skills/port-a-sample/SKILL.md index 0efea1058..559aca773 100644 --- a/.claude/skills/port-a-sample/SKILL.md +++ b/.claude/skills/port-a-sample/SKILL.md @@ -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 `); 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 `); +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 diff --git a/.claude/skills/scaffold-a-port/SKILL.md b/.claude/skills/scaffold-a-port/SKILL.md index 188684add..441e5c6f6 100644 --- a/.claude/skills/scaffold-a-port/SKILL.md +++ b/.claude/skills/scaffold-a-port/SKILL.md @@ -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//` 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 diff --git a/AGENTS.md b/AGENTS.md index 7816f3c0e..3f4572209 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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. @@ -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 @@ -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//` to `src/02//`** (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//b/` were flattened away on 2026-08-12, when the corpus stood at @@ -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 diff --git a/CAPABILITIES.md b/CAPABILITIES.md index 54155c715..4e6d83db0 100644 --- a/CAPABILITIES.md +++ b/CAPABILITIES.md @@ -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 (` ` in the original) | ✅ | write the break as `\n` in a `\|...\|` template — `xml_escape` emits it as ` `/` `/` ` 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, / css / / )` 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 diff --git a/README.md b/README.md index e52320fd6..20d8c7114 100644 --- a/README.md +++ b/README.md @@ -94,11 +94,12 @@ sample and its ABAP class next to each other and compare line by line.
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 @@ -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 @@ -212,25 +213,25 @@ have an abap2UI5 port. -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.** diff --git a/SAMPLES.md b/SAMPLES.md index 397efb7c6..727b3d18a 100644 --- a/SAMPLES.md +++ b/SAMPLES.md @@ -3,7 +3,7 @@ # The sample catalogue -Every port in this repository — 636 of them — with what it shows and a +Every port in this repository — 684 of them — with what it shows and a link to its source. This is the [overview app](src/z2ui5_cl_smpc_app_000.clas.abap) as a page you can read here, before installing anything. @@ -40,13 +40,13 @@ For what is NOT here — which demo kit samples are still unported and why — s ## The ports — by UI5 library -[sap.m](#sapm) · [sap.uxap](#sapuxap) · [sap.f](#sapf) · [sap.ui.layout.form](#sapuilayoutform) · [sap.ui.layout](#sapuilayout) · [sap.ui.unified](#sapuiunified) · [sap.ui.core](#sapuicore) · [sap.ui.table](#sapuitable) · [sap.tnt](#saptnt) · [sap.ui.layout.cssgrid](#sapuilayoutcssgrid) · [sap.ui.model.type](#sapuimodeltype) · [sap.m.semantic](#sapmsemantic) · [sap.ui.integration.widgets](#sapuiintegrationwidgets) · [sap.f.semantic](#sapfsemantic) · [sap.ui.codeeditor](#sapuicodeeditor) · [sap.ui.model](#sapuimodel) · [sap.m.upload](#sapmupload) · [sap.ui.core.hyphenation](#sapuicorehyphenation) · [sap.ui.core.theming](#sapuicoretheming) · [sap.ui.integration](#sapuiintegration) +[sap.m](#sapm) · [sap.uxap](#sapuxap) · [sap.f](#sapf) · [sap.ui.layout.form](#sapuilayoutform) · [sap.ui.layout](#sapuilayout) · [sap.ui.unified](#sapuiunified) · [sap.ui.core](#sapuicore) · [sap.ui.table](#sapuitable) · [sap.tnt](#saptnt) · [sap.m.plugins](#sapmplugins) · [sap.ui.layout.cssgrid](#sapuilayoutcssgrid) · [sap.ui.model.type](#sapuimodeltype) · [sap.m.p13n](#sapmp13n) · [sap.m.semantic](#sapmsemantic) · [sap.ui.integration.widgets](#sapuiintegrationwidgets) · [sap.f.semantic](#sapfsemantic) · [sap.ui.codeeditor](#sapuicodeeditor) · [sap.ui.model](#sapuimodel) · [sap.m.upload](#sapmupload) · [sap.ui.core.hyphenation](#sapuicorehyphenation) · [sap.ui.core.theming](#sapuicoretheming) · [sap.ui.integration](#sapuiintegration) ### sap.m -377 port(s), by control: +398 port(s), by control: -[ActionListItem](#sapmactionlistitem) · [Bar](#sapmbar) (2) · [Breadcrumbs](#sapmbreadcrumbs) (3) · [BusyDialog](#sapmbusydialog) (2) · [Button](#sapmbutton) (2) · [Carousel](#sapmcarousel) (5) · [CheckBox](#sapmcheckbox) (2) · [ColorPalette](#sapmcolorpalette) (2) · [Column](#sapmcolumn) · [ColumnListItem](#sapmcolumnlistitem) · [ComboBox](#sapmcombobox) (13) · [ComparisonPattern](#sapmcomparisonpattern) · [CookieSettingsDialogPattern](#sapmcookiesettingsdialogpattern) · [CustomListItem](#sapmcustomlistitem) · [CustomTreeItem](#sapmcustomtreeitem) · [DatePicker](#sapmdatepicker) (3) · [DateRangeSelection](#sapmdaterangeselection) (3) · [DateTimePicker](#sapmdatetimepicker) (3) · [Dialog](#sapmdialog) (5) · [DisplayListItem](#sapmdisplaylistitem) · [DraftIndicator](#sapmdraftindicator) (2) · [FacetFilter](#sapmfacetfilter) (3) · [FeedContent](#sapmfeedcontent) · [FeedInput](#sapmfeedinput) (2) · [FeedListItem](#sapmfeedlistitem) · [FlexBox](#sapmflexbox) (9) · [FormattedText](#sapmformattedtext) · [GenericTag](#sapmgenerictag) (2) · [GenericTile](#sapmgenerictile) (6) · [HeaderContainer](#sapmheadercontainer) (5) · [IconTabBar](#sapmicontabbar) (17) · [IconTabHeader](#sapmicontabheader) · [Image](#sapmimage) (3) · [ImageContent](#sapmimagecontent) · [InitialPagePattern](#sapminitialpagepattern) · [Input](#sapminput) (18) · [InputListItem](#sapminputlistitem) · [InputModelUpdate](#sapminputmodelupdate) · [Label](#sapmlabel) · [LightBox](#sapmlightbox) · [Link](#sapmlink) (3) · [List](#sapmlist) (16) · [MaskInput](#sapmmaskinput) · [Menu](#sapmmenu) (3) · [MenuButton](#sapmmenubutton) · [MessageBox](#sapmmessagebox) (3) · [MessagePopover](#sapmmessagepopover) (3) · [MessageStrip](#sapmmessagestrip) (3) · [MessageToast](#sapmmessagetoast) · [MessageView](#sapmmessageview) (5) · [MultiComboBox](#sapmmulticombobox) (10) · [MultiInput](#sapmmultiinput) (12) · [NavContainer](#sapmnavcontainer) · [NewsContent](#sapmnewscontent) · [NotificationListGroup](#sapmnotificationlistgroup) (4) · [NotificationListItem](#sapmnotificationlistitem) · [NumericContent](#sapmnumericcontent) (3) · [ObjectAttribute](#sapmobjectattribute) (4) · [ObjectHeader](#sapmobjectheader) (12) · [ObjectIdentifier](#sapmobjectidentifier) · [ObjectListItem](#sapmobjectlistitem) (2) · [ObjectMarker](#sapmobjectmarker) · [ObjectNumber](#sapmobjectnumber) · [ObjectStatus](#sapmobjectstatus) · [OverflowToolbar](#sapmoverflowtoolbar) (7) · [OverflowToolbarTokenizer](#sapmoverflowtoolbartokenizer) · [Page](#sapmpage) (3) · [Panel](#sapmpanel) (4) · [PDFViewer](#sapmpdfviewer) (3) · [PlanningCalendar](#sapmplanningcalendar) (14) · [Popover](#sapmpopover) (4) · [ProgressIndicator](#sapmprogressindicator) (2) · [PullToRefresh](#sapmpulltorefresh) (2) · [QuickView](#sapmquickview) (3) · [QuickViewCard](#sapmquickviewcard) (2) · [RadioButton](#sapmradiobutton) · [RangeSlider](#sapmrangeslider) · [ResponsivePopover](#sapmresponsivepopover) · [ScrollContainer](#sapmscrollcontainer) · [SearchField](#sapmsearchfield) (2) · [SegmentedButton](#sapmsegmentedbutton) (5) · [Select](#sapmselect) (6) · [SelectDialog](#sapmselectdialog) (2) · [SelectList](#sapmselectlist) (2) · [SinglePlanningCalendar](#sapmsingleplanningcalendar) (10) · [Slider](#sapmslider) · [SlideTile](#sapmslidetile) · [SplitApp](#sapmsplitapp) · [SplitContainer](#sapmsplitcontainer) · [StandardListItem](#sapmstandardlistitem) (9) · [StepInput](#sapmstepinput) (2) · [Switch](#sapmswitch) · [TabContainer](#sapmtabcontainer) (3) · [Table](#sapmtable) (19) · [TableSelectDialog](#sapmtableselectdialog) (2) · [Text](#sapmtext) (5) · [TextArea](#sapmtextarea) (5) · [TileContent](#sapmtilecontent) · [TimePicker](#sapmtimepicker) (2) · [TimePickerSliders](#sapmtimepickersliders) · [Title](#sapmtitle) (2) · [ToggleButton](#sapmtogglebutton) · [Tokenizer](#sapmtokenizer) (2) · [Toolbar](#sapmtoolbar) · [Tree](#sapmtree) (8) · [URLHelper](#sapmurlhelper) · [ViewSettingsDialog](#sapmviewsettingsdialog) (4) · [WhitespacePattern](#sapmwhitespacepattern) · [Wizard](#sapmwizard) (4) +[ActionListItem](#sapmactionlistitem) · [Avatar](#sapmavatar) (5) · [Bar](#sapmbar) (2) · [Breadcrumbs](#sapmbreadcrumbs) (3) · [BusyDialog](#sapmbusydialog) (2) · [Button](#sapmbutton) (2) · [Carousel](#sapmcarousel) (5) · [CheckBox](#sapmcheckbox) (2) · [ColorPalette](#sapmcolorpalette) (2) · [Column](#sapmcolumn) · [ColumnListItem](#sapmcolumnlistitem) · [ComboBox](#sapmcombobox) (13) · [ComparisonPattern](#sapmcomparisonpattern) · [CookieSettingsDialogPattern](#sapmcookiesettingsdialogpattern) · [CustomListItem](#sapmcustomlistitem) · [CustomTreeItem](#sapmcustomtreeitem) · [DatePicker](#sapmdatepicker) (3) · [DateRangeSelection](#sapmdaterangeselection) (3) · [DateTimePicker](#sapmdatetimepicker) (3) · [Dialog](#sapmdialog) (5) · [DisplayListItem](#sapmdisplaylistitem) · [DraftIndicator](#sapmdraftindicator) (2) · [DynamicDateRange](#sapmdynamicdaterange) (4) · [ExpandableText](#sapmexpandabletext) · [FacetFilter](#sapmfacetfilter) (3) · [FeedContent](#sapmfeedcontent) · [FeedInput](#sapmfeedinput) (2) · [FeedListItem](#sapmfeedlistitem) · [FlexBox](#sapmflexbox) (9) · [FormattedText](#sapmformattedtext) · [GenericTag](#sapmgenerictag) (2) · [GenericTile](#sapmgenerictile) (6) · [HeaderContainer](#sapmheadercontainer) (5) · [IconTabBar](#sapmicontabbar) (17) · [IconTabHeader](#sapmicontabheader) · [IllustratedMessage](#sapmillustratedmessage) (10) · [Image](#sapmimage) (3) · [ImageContent](#sapmimagecontent) · [InitialPagePattern](#sapminitialpagepattern) · [Input](#sapminput) (18) · [InputListItem](#sapminputlistitem) · [InputModelUpdate](#sapminputmodelupdate) · [Label](#sapmlabel) · [LightBox](#sapmlightbox) · [Link](#sapmlink) (3) · [List](#sapmlist) (16) · [MaskInput](#sapmmaskinput) · [Menu](#sapmmenu) (3) · [MenuButton](#sapmmenubutton) · [MessageBox](#sapmmessagebox) (3) · [MessagePopover](#sapmmessagepopover) (3) · [MessageStrip](#sapmmessagestrip) (3) · [MessageToast](#sapmmessagetoast) · [MessageView](#sapmmessageview) (5) · [MultiComboBox](#sapmmulticombobox) (10) · [MultiInput](#sapmmultiinput) (12) · [NavContainer](#sapmnavcontainer) · [NewsContent](#sapmnewscontent) · [NotificationListGroup](#sapmnotificationlistgroup) (4) · [NotificationListItem](#sapmnotificationlistitem) · [NumericContent](#sapmnumericcontent) (3) · [ObjectAttribute](#sapmobjectattribute) (4) · [ObjectHeader](#sapmobjectheader) (12) · [ObjectIdentifier](#sapmobjectidentifier) · [ObjectListItem](#sapmobjectlistitem) (2) · [ObjectMarker](#sapmobjectmarker) · [ObjectNumber](#sapmobjectnumber) · [ObjectStatus](#sapmobjectstatus) · [OverflowToolbar](#sapmoverflowtoolbar) (7) · [OverflowToolbarTokenizer](#sapmoverflowtoolbartokenizer) · [Page](#sapmpage) (3) · [Panel](#sapmpanel) (4) · [PDFViewer](#sapmpdfviewer) (3) · [PlanningCalendar](#sapmplanningcalendar) (14) · [Popover](#sapmpopover) (4) · [ProgressIndicator](#sapmprogressindicator) (2) · [PullToRefresh](#sapmpulltorefresh) (2) · [QuickView](#sapmquickview) (3) · [QuickViewCard](#sapmquickviewcard) (2) · [RadioButton](#sapmradiobutton) · [RangeSlider](#sapmrangeslider) · [ResponsivePopover](#sapmresponsivepopover) · [ScrollContainer](#sapmscrollcontainer) · [SearchField](#sapmsearchfield) (2) · [SegmentedButton](#sapmsegmentedbutton) (5) · [Select](#sapmselect) (6) · [SelectDialog](#sapmselectdialog) (2) · [SelectList](#sapmselectlist) (2) · [SinglePlanningCalendar](#sapmsingleplanningcalendar) (10) · [Slider](#sapmslider) · [SlideTile](#sapmslidetile) · [SplitApp](#sapmsplitapp) · [SplitContainer](#sapmsplitcontainer) · [StandardListItem](#sapmstandardlistitem) (9) · [StepInput](#sapmstepinput) (2) · [Switch](#sapmswitch) · [TabContainer](#sapmtabcontainer) (3) · [Table](#sapmtable) (19) · [TableSelectDialog](#sapmtableselectdialog) (2) · [Text](#sapmtext) (5) · [TextArea](#sapmtextarea) (5) · [TileContent](#sapmtilecontent) · [TimePicker](#sapmtimepicker) (2) · [TimePickerSliders](#sapmtimepickersliders) · [Title](#sapmtitle) (2) · [ToggleButton](#sapmtogglebutton) · [Tokenizer](#sapmtokenizer) (2) · [Toolbar](#sapmtoolbar) · [Tree](#sapmtree) (8) · [URLHelper](#sapmurlhelper) · [VariantManagement](#sapmvariantmanagement) · [ViewSettingsDialog](#sapmviewsettingsdialog) (4) · [WhitespacePattern](#sapmwhitespacepattern) · [Wizard](#sapmwizard) (4) #### sap.m.ActionListItem @@ -54,6 +54,16 @@ For what is NOT here — which demo kit samples are still unported and why — s |---|---| | **sap.m.ActionListItem**
Use the Action List Item to trigger an action directly from a list
actionlistitem action list item sap.m
✓ checked | [`Z2UI5_CL_SMPC_APP_001`](src/01/01/z2ui5_cl_smpc_app_001.clas.abap) | +#### sap.m.Avatar + +| Sample | Class | +|---|---| +| **sap.m.Avatar**
This sample demonstrates different combinations of types, shapes, and sizes of the Avatar.
avatar sap.m scrollcontainer text grid vbox
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_624`](src/02/01/z2ui5_cl_smpc_app_624.clas.abap) | +| **sap.m.Avatar** — Avatar with toggling of Active state
This sample demonstrates toggling of Avatar Active state, when a User menu is opened/closed.
avatar sap.m avataractivestate popover list standardlistitem messagestrip
○ generated · 6 deviations | [`Z2UI5_CL_SMPC_APP_625`](src/02/01/z2ui5_cl_smpc_app_625.clas.abap) | +| **sap.m.Avatar** — Avatar with Badge Icon Color
This sample demonstrates different badge icon colors of the Avatar.
avatar sap.m avatarbadgeiconcolor scrollcontainer text grid vbox
○ generated · 3 deviations | [`Z2UI5_CL_SMPC_APP_626`](src/02/01/z2ui5_cl_smpc_app_626.clas.abap) | +| **sap.m.Avatar** — Avatar with badgeValueState
This sample demonstrates different badge value states of the Avatar.
avatar sap.m avatarvaluestate scrollcontainer grid vbox text
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_627`](src/02/01/z2ui5_cl_smpc_app_627.clas.abap) | +| **sap.m.Avatar** — Avatar with Visual Affordance
This sample demonstrates different combinations of types, shapes, and sizes of the Avatar with visual affordance.
avatar sap.m avatarwithaffordance scrollcontainer text grid vbox lightbox lightboxitem
○ generated · 4 deviations | [`Z2UI5_CL_SMPC_APP_628`](src/02/01/z2ui5_cl_smpc_app_628.clas.abap) | + #### sap.m.Bar | Sample | Class | @@ -208,6 +218,21 @@ For what is NOT here — which demo kit samples are still unported and why — s | **sap.m.DraftIndicator**
The Draft Indicator shows that eighter currently a draft is saving or that it is already saved. It does not block the current UI screen so other operations could be triggered in parallel.
draftindicator draft indicator sap.m sap.m.label verticallayout button
✓ checked · 2 deviations | [`Z2UI5_CL_SMPC_APP_021`](src/01/01/z2ui5_cl_smpc_app_021.clas.abap) | | **sap.m.DraftIndicator** — Semantic Page using Draft Indicator
Integration of Draft Indicator inside Semantic Page
draftindicator draft indicator sap.m semanticpagedraftindicator fullscreenpage addaction flagaction favoriteaction messagesindicator messagepopover messageitem
○ generated · 7 deviations | [`Z2UI5_CL_SMPC_APP_448`](src/01/01/z2ui5_cl_smpc_app_448.clas.abap) | +#### sap.m.DynamicDateRange + +| Sample | Class | +|---|---| +| **sap.m.DynamicDateRange**
The dynamic date range is a control that offers a choice of absolute and relative dates, using different offset from the current date. The list of values offered must be defined by the application.
dynamicdaterange dynamic date range sap.m table overflowtoolbar title toolbarspacer label column text
○ generated · 7 deviations | [`Z2UI5_CL_SMPC_APP_639`](src/02/01/z2ui5_cl_smpc_app_639.clas.abap) | +| **sap.m.DynamicDateRange** — Dynamic Date Range with calendarWeekNumbering
This example shows the Dynamic Date Range control with Middle Eastern calendar week numbering.
dynamicdaterange dynamic date range sap.m dynamicdaterangeandcalendarweeknumbering table overflowtoolbar title toolbarspacer label column
○ generated · 9 deviations | [`Z2UI5_CL_SMPC_APP_640`](src/02/01/z2ui5_cl_smpc_app_640.clas.abap) | +| **sap.m.DynamicDateRange** — Dynamic Date Range - Open by Another Control
This example shows Dynamic Date Range which is opened by another control.
dynamicdaterange dynamic date range sap.m dynamicdaterangehidden title vbox label button link
○ generated · 6 deviations | [`Z2UI5_CL_SMPC_APP_641`](src/02/01/z2ui5_cl_smpc_app_641.clas.abap) | +| **sap.m.DynamicDateRange** — Dynamic Date Range with Custom Options
This example shows the Dynamic Date Range control with custom options for interval or date selection.
dynamicdaterange dynamic date range sap.m dynamicdaterangewithcustomoptions table overflowtoolbar title toolbarspacer label column
○ generated · 9 deviations | [`Z2UI5_CL_SMPC_APP_642`](src/02/01/z2ui5_cl_smpc_app_642.clas.abap) | + +#### sap.m.ExpandableText + +| Sample | Class | +|---|---| +| **sap.m.ExpandableText**
The ExpandableText control can be used to display a larger texts inside a table, list or form.
expandabletext expandable text sap.m table column columnlistitem
○ generated · 4 deviations | [`Z2UI5_CL_SMPC_APP_643`](src/02/01/z2ui5_cl_smpc_app_643.clas.abap) | + #### sap.m.FacetFilter | Sample | Class | @@ -311,6 +336,21 @@ For what is NOT here — which demo kit samples are still unported and why — s |---|---| | **sap.m.IconTabHeader** — Standalone Icon Tab Header
Icon Tab Header used standalone, outside of Icon Tab Bar.
icontabheader icon tab header sap.m inline mode icontabfilter
◐ reviewed | [`Z2UI5_CL_SMPC_APP_055`](src/01/01/z2ui5_cl_smpc_app_055.clas.abap) | +#### sap.m.IllustratedMessage + +| Sample | Class | +|---|---| +| **sap.m.IllustratedMessage** — Illustrated Message Enable Vertical Responsiveness
Demonstrates the IllustratedMessage's 'enableVerticalResponsiveness' property.
illustratedmessage illustrated message sap.m illustratedmessageevr responsivesplitter panecontainer splitpane splitterlayoutdata button vbox
○ generated · 2 deviations | [`Z2UI5_CL_SMPC_APP_629`](src/02/01/z2ui5_cl_smpc_app_629.clas.abap) | +| **sap.m.IllustratedMessage** — A demo application that imports a Custom Illustration Set from an npm package
Shows how to import a Custom Illustration from an npm package into a UI5 application for usage with IllustratedMessage.
illustratedmessage illustrated message sap.m illustratedmessageinappcustom simpleform label select item text button
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_630`](src/02/01/z2ui5_cl_smpc_app_630.clas.abap) | +| **sap.m.IllustratedMessage** — 'NoActivities' Illustrated Message in a Card
IllustratedMessage as content of sap.f.Card. 'NoActivities' illustration type is being used for the Illustrated Message.
illustratedmessage illustrated message sap.m illustratedmessageincardnoactivities card header button
○ generated · 1 deviation | [`Z2UI5_CL_SMPC_APP_631`](src/02/01/z2ui5_cl_smpc_app_631.clas.abap) | +| **sap.m.IllustratedMessage** — 'NoEmail' Illustrated Message in a Card
IllustratedMessage as content of sap.f.Card. 'NoEmail' illustration type is being used for the Illustrated Message.
illustratedmessage illustrated message sap.m illustratedmessageincardnoemail card header
○ generated · 1 deviation | [`Z2UI5_CL_SMPC_APP_632`](src/02/01/z2ui5_cl_smpc_app_632.clas.abap) | +| **sap.m.IllustratedMessage** — Illustrated Message in a Dialog
IllustratedMessage as content of sap.m.Dialog.
illustratedmessage illustrated message sap.m illustratedmessageindialog button dialog
○ generated · 2 deviations | [`Z2UI5_CL_SMPC_APP_633`](src/02/01/z2ui5_cl_smpc_app_633.clas.abap) | +| **sap.m.IllustratedMessage** — Default Illustration Set (sapIllus)
The available illustrations are from the default ('sapIllus') illustration set.
illustratedmessage illustrated message sap.m illustratedmessageinpage simpleform label columnelementdata switch text select item
○ generated · 6 deviations | [`Z2UI5_CL_SMPC_APP_634`](src/02/01/z2ui5_cl_smpc_app_634.clas.abap) | +| **sap.m.IllustratedMessage** — Illustrated Message in a Page with Configurable Properties (Custom Illustration Set)
The available properties of the IllustratedMessage are configurable in this sample. The available illustrations are from the 'custom' illustration set.
illustratedmessage illustrated message sap.m illustratedmessageinpagecustom simpleform label select item text button
○ generated · 4 deviations | [`Z2UI5_CL_SMPC_APP_635`](src/02/01/z2ui5_cl_smpc_app_635.clas.abap) | +| **sap.m.IllustratedMessage** — Illustrated Message in a Page with Configurable Properties (TNT Illustration Set)
The available properties of the IllustratedMessage are configurable in this sample. The available illustrations are from the 'tnt' illustration set.
illustratedmessage illustrated message sap.m illustratedmessageinpagetnt simpleform label columnelementdata select item text button
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_636`](src/02/01/z2ui5_cl_smpc_app_636.clas.abap) | +| **sap.m.IllustratedMessage** — Illustrative style illustrations using the 'src' property
The available illustrations are from the default illustration set with the use of the 'src' property.
illustratedmessage illustrated message sap.m illustratedmessageinpagewithuri simpleform label columnelementdata switch text select item
○ generated · 8 deviations | [`Z2UI5_CL_SMPC_APP_637`](src/02/01/z2ui5_cl_smpc_app_637.clas.abap) | +| **sap.m.IllustratedMessage** — Illustrated Message Session Timeout
All applications that require user sign-in should employ a mechanism for automating user sign-out. When the inactivity is about to reach that threshold, a session timeout dialog appears automatically to inform the user.
illustratedmessage illustrated message sap.m illustratedmessagesessiontimeout vbox label stepinput button dialog
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_638`](src/02/01/z2ui5_cl_smpc_app_638.clas.abap) | + #### sap.m.Image | Sample | Class | @@ -946,6 +986,12 @@ For what is NOT here — which demo kit samples are still unported and why — s |---|---| | **sap.m.URLHelper**
The URL Helper can be used to easily trigger a phone's native apps like Email, Telephone and SMS. It can be used with any UI control but typically an active Display List Item is chosen.
urlhelper sap.m tel sms email url triggers list displaylistitem
○ generated · 4 deviations | [`Z2UI5_CL_SMPC_APP_084`](src/01/01/z2ui5_cl_smpc_app_084.clas.abap) | +#### sap.m.VariantManagement + +| Sample | Class | +|---|---| +| **sap.m.VariantManagement** — VariantManagement using dedicated items
VariantManagement with dedicated items
variantmanagement variant management sap.m panel overflowtoolbar title toolbarspacer button dynamicpage dynamicpagetitle
○ generated · 4 deviations | [`Z2UI5_CL_SMPC_APP_651`](src/02/01/z2ui5_cl_smpc_app_651.clas.abap) | + #### sap.m.ViewSettingsDialog | Sample | Class | @@ -1073,45 +1119,104 @@ For what is NOT here — which demo kit samples are still unported and why — s ### sap.f -34 port(s). +44 port(s), by control: + +[AvatarGroup](#sapfavatargroup) · [Card](#sapfcard) · [DynamicPage](#sapfdynamicpage) (5) · [FlexibleColumnLayout](#sapfflexiblecolumnlayout) (8) · [GridContainer](#sapfgridcontainer) (4) · [GridList](#sapfgridlist) (9) · [HeroBanner](#sapfherobanner) (5) · [ProductSwitch](#sapfproductswitch) (2) · [ShellBar](#sapfshellbar) (5) · [SidePanel](#sapfsidepanel) (4) + +#### sap.f.AvatarGroup + +| Sample | Class | +|---|---| +| **sap.f.AvatarGroup**
This sample demonstrates the different group types and item sizes of the AvatarGroup control.
avatargroup avatar group sap.f slider verticallayout label avatargroupitem popover card hbox vbox
○ generated · 7 deviations | [`Z2UI5_CL_SMPC_APP_662`](src/02/04/z2ui5_cl_smpc_app_662.clas.abap) | + +#### sap.f.Card | Sample | Class | |---|---| -| **sap.f.GridList** — Grid List - Basic examples
A GridList with the default grid layout, resized live with a slider to show how the grid reflows.
gridlist grid list sap.f layout slider panel toolbar title gridlistitem vbox flexitemdata
◐ reviewed · 1 deviation | [`Z2UI5_CL_SMPC_APP_111`](src/01/04/z2ui5_cl_smpc_app_111.clas.abap) | | **sap.f.Card** — Card Control
This sample illustrates how to specify the predefined header and the content of the Card control.
card sap.f fiori header vbox hbox combobox item datepicker button list customlistitem
◐ reviewed · 1 deviation | [`Z2UI5_CL_SMPC_APP_117`](src/01/04/z2ui5_cl_smpc_app_117.clas.abap) | -| **sap.f.GridList** — Grid List - Different Modes With Various Item Types
This is a sample for GridList with different modes of selection.
gridlist grid list sap.f selection modes html hbox segmentedbutton segmentedbuttonitem gridbasiclayout gridlistitem
◐ reviewed · 4 deviations | [`Z2UI5_CL_SMPC_APP_133`](src/01/04/z2ui5_cl_smpc_app_133.clas.abap) | -| **sap.f.GridList** — Grid List with GridBoxLayout
This layout allows to display same height grid items with configurable width.
gridlist grid list sap.f gridboxlayout slider panel toolbar title gridlistitem vbox flexitemdata
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_144`](src/01/04/z2ui5_cl_smpc_app_144.clas.abap) | -| **sap.f.GridList** — Grid List - Drag and Drop
This sample represents GridList with enabled Drag and Drop functionality.
gridlist grid list sap.f drag drop panel toolbar title draginfo griddropinfo gridboxlayout
◐ reviewed · 4 deviations | [`Z2UI5_CL_SMPC_APP_148`](src/01/04/z2ui5_cl_smpc_app_148.clas.abap) | + +#### sap.f.DynamicPage + +| Sample | Class | +|---|---| | **sap.f.DynamicPage** — Dynamic Page Freestyle Example
Dynamic Page freestyle example with a responsive sap.m.Table in the content area, showing that each control can be placed in the title and the header content areas.
dynamicpage dynamic sap.f dynamicpagefreestyle dynamicpagetitle title breadcrumbs link label overflowtoolbar generictag objectnumber
◐ reviewed · 5 deviations | [`Z2UI5_CL_SMPC_APP_170`](src/01/04/z2ui5_cl_smpc_app_170.clas.abap) | -| **sap.f.GridList** — Grid List features - Grouping, Header, Growing
This sample illustrates subgroups with headers, custom header and lazy loading of GridList items.
gridlist grid list sap.f gridlistboxcontainergrouping slider panel toolbar title toolbarspacer searchfield gridboxlayout
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_176`](src/01/04/z2ui5_cl_smpc_app_176.clas.abap) | -| **sap.f.GridList** — Grid List - Break point examples - S, M, L, XL
This sample illustrates how to configure the responsive settings for different container sizes.
gridlist grid list sap.f gridlistbreakpoints slider panel toolbar title gridresponsivelayout gridsettings gridlistitem
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_213`](src/01/04/z2ui5_cl_smpc_app_213.clas.abap) | -| **sap.f.FlexibleColumnLayout** — Flexible Column Layout (with Event Bus)
Clicking on a link in a column opens the next column.
flexiblecolumnlayout flexible column layout sap.f master-detail table label columnlistitem text button
◐ reviewed · 4 deviations | [`Z2UI5_CL_SMPC_APP_234`](src/01/04/z2ui5_cl_smpc_app_234.clas.abap) | | **sap.f.DynamicPage** — Dynamic Page with Sticky Subheader
Dynamic Page containing an sap.m.IconTabBar in the sticky subheader content area.
dynamicpage dynamic sap.f dynamicpagewithstickysubheader dynamicpagetitle title breadcrumbs link label overflowtoolbar generictag objectnumber
◐ reviewed · 6 deviations | [`Z2UI5_CL_SMPC_APP_238`](src/01/04/z2ui5_cl_smpc_app_238.clas.abap) | -| **sap.f.GridContainer** — Grid Container - Drag and Drop
This sample represents GridContainer with enabled Drag and Drop functionality.
gridcontainer grid container sap.f gridcontainerdraganddrop scrollcontainer draginfo griddropinfo gridcontainersettings gridcontaineritemlayoutdata imagecontent header
○ generated · 6 deviations | [`Z2UI5_CL_SMPC_APP_526`](src/01/04/z2ui5_cl_smpc_app_526.clas.abap) | -| **sap.f.GridContainer** — Grid Container - Drag and Drop From List to GridContainer
This sample represents how items from a control which is not GridContainer can be dragged and dropped over a GridContainer.
gridcontainer grid container sap.f gridcontainerdraganddropfromlist scrollcontainer togglebutton hbox list draginfo dropinfo standardlistitem
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_527`](src/01/04/z2ui5_cl_smpc_app_527.clas.abap) | | **sap.f.DynamicPage** — Dynamic Page with Wizard
Dynamic Page containing a sap.m.Wizard and WizardProgressNavigator in the content area.
dynamicpage dynamic sap.f dynamicpagewithwizard navcontainer dynamicpagetitle title wizard wizardstep objectheader objectattribute list
○ generated · 10 deviations | [`Z2UI5_CL_SMPC_APP_560`](src/01/04/z2ui5_cl_smpc_app_560.clas.abap) | -| **sap.f.GridList** — Grid List - Item Designs
This is a sample for GridList item templates representing a typical tools page dashboard style.
gridlist grid list sap.f gridlistboxcontainerreal toolbar title gridboxlayout vbox flexitemdata label text
○ generated · 4 deviations | [`Z2UI5_CL_SMPC_APP_581`](src/01/04/z2ui5_cl_smpc_app_581.clas.abap) | -| **sap.f.GridList** — Navigation with keyboard arrows between multiple GridLists
This sample demonstrates the keyboard navigation between multiple grids
gridlist grid list sap.f gridlistkeyboardarrowsnavigation app slider gridresponsivelayout gridsettings gridbasiclayout gridlistitem griditemlayoutdata
○ generated · 7 deviations | [`Z2UI5_CL_SMPC_APP_582`](src/01/04/z2ui5_cl_smpc_app_582.clas.abap) | -| **sap.f.ShellBar** — Shell Bar with title mega menu
Shell Bar example showing the control title as part of a mega menu, configurable by the app developer.
shellbar shell bar sap.f application header menu menuitem avatar
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_110`](src/02/04/z2ui5_cl_smpc_app_110.clas.abap) | -| **sap.f.SidePanel** — Side Panel with single action item
Demonstrates the usage of Side Panel with single action item.
sidepanel side panel sap.f single item button vbox label switch text sidepanelitem
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_136`](src/02/04/z2ui5_cl_smpc_app_136.clas.abap) | -| **sap.f.ShellBar** — Shell Bar with menu button
Shell Bar example with a menu button and a plain title.
shellbar shell bar sap.f menu button avatar
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_152`](src/02/04/z2ui5_cl_smpc_app_152.clas.abap) | -| **sap.f.ProductSwitch** — Product Switch with Navigation
This sample demonstrates the navigation behavior of Product Switch, configurable by the app developer.
productswitch product switch sap.f productswitchnavigation verticallayout button text responsivepopover productswitchitem
◐ reviewed · 3 deviations | [`Z2UI5_CL_SMPC_APP_165`](src/02/04/z2ui5_cl_smpc_app_165.clas.abap) | -| **sap.f.GridContainer**
This sample represents the general usage of GridContainer.
gridcontainer grid container sap.f scrollcontainer togglebutton panel hbox label switch text gridcontainersettings
◐ reviewed · 5 deviations | [`Z2UI5_CL_SMPC_APP_168`](src/02/04/z2ui5_cl_smpc_app_168.clas.abap) | -| **sap.f.ShellBar** — Shell Bar with search
Shell Bar example with configured search functionality.
shellbar shell bar sap.f shellbarwithsearch menu menuitem avatar searchmanager suggestionitem
◐ reviewed · 4 deviations | [`Z2UI5_CL_SMPC_APP_218`](src/02/04/z2ui5_cl_smpc_app_218.clas.abap) | -| **sap.f.GridList** — Grid List with Responsive Column Layout
This layout displays a variable number of grid columns depending on available screen size. Grid row's height is dynamically determined by the height of the highest grid element on this row.
gridlist grid list sap.f gridlistresponsivecolumnlayout togglebutton slider panel toolbar title responsivecolumnlayout gridlistitem
◐ reviewed · 3 deviations | [`Z2UI5_CL_SMPC_APP_222`](src/02/04/z2ui5_cl_smpc_app_222.clas.abap) | | **sap.f.DynamicPage** — Dynamic Page with Responsive Avatar
Dynamic Page demonstrating the breakpointChange event to adjust Avatar sizes responsively based on breakpoints.
dynamicpage dynamic sap.f dynamicpageresponsiveavatar dynamicpagetitle breadcrumbs link hbox title objectmarker text flexbox
◐ reviewed · 4 deviations | [`Z2UI5_CL_SMPC_APP_244`](src/02/04/z2ui5_cl_smpc_app_244.clas.abap) | +| **sap.f.DynamicPage** — Dynamic Page with Analytical Table
Dynamic Page containing an Analytical Table in the content area aligned with the SAP Fiori List Report floorplan.
dynamicpage dynamic sap.f dynamicpageanalyticaltable dynamicpagetitle title label overflowtoolbar generictag objectnumber toolbarspacer button
○ generated · 9 deviations | [`Z2UI5_CL_SMPC_APP_559`](src/02/04/z2ui5_cl_smpc_app_559.clas.abap) | + +#### sap.f.FlexibleColumnLayout + +| Sample | Class | +|---|---| +| **sap.f.FlexibleColumnLayout** — Flexible Column Layout (with Event Bus)
Clicking on a link in a column opens the next column.
flexiblecolumnlayout flexible column layout sap.f master-detail table label columnlistitem text button
◐ reviewed · 4 deviations | [`Z2UI5_CL_SMPC_APP_234`](src/01/04/z2ui5_cl_smpc_app_234.clas.abap) | | **sap.f.FlexibleColumnLayout** — Flexible Column Layout Landmark Info For Columns
Flexible Column Layout where the first and the last columns have custom Landmark Info
flexiblecolumnlayout flexible column layout sap.f flexiblecolumnlayoutlandmarkinfo flexiblecolumnlayoutaccessiblelandmarkinfo button vbox
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_449`](src/02/04/z2ui5_cl_smpc_app_449.clas.abap) | | **sap.f.FlexibleColumnLayout** — Flexible Column Layout Landmark Info For Arrows
Flexible Column Layout where the all the arrows have custom Landmark Info
flexiblecolumnlayout flexible column layout sap.f flexiblecolumnlayoutlandmarkinfoarrow flexiblecolumnlayoutaccessiblelandmarkinfo button vbox
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_450`](src/02/04/z2ui5_cl_smpc_app_450.clas.abap) | -| **sap.f.GridContainer** — Grid Container - Keyboard navigation between multiple grids
This sample demonstrates the keyboard navigation between multiple grids
gridcontainer grid container sap.f gridcontainersnavigation scrollcontainer togglebutton hbox panel flexitemdata generictile gridcontaineritemlayoutdata
○ generated · 7 deviations | [`Z2UI5_CL_SMPC_APP_528`](src/02/04/z2ui5_cl_smpc_app_528.clas.abap) | -| **sap.f.DynamicPage** — Dynamic Page with Analytical Table
Dynamic Page containing an Analytical Table in the content area aligned with the SAP Fiori List Report floorplan.
dynamicpage dynamic sap.f dynamicpageanalyticaltable dynamicpagetitle title label overflowtoolbar generictag objectnumber toolbarspacer button
○ generated · 9 deviations | [`Z2UI5_CL_SMPC_APP_559`](src/02/04/z2ui5_cl_smpc_app_559.clas.abap) | | **sap.f.FlexibleColumnLayout** — Flexible Column Layout with programmatic scrolling to an item
FlexibleColumnLayout where the app programmatically scrolls to some item within the newly navigated column, once the column is fully resized
flexiblecolumnlayout flexible column layout sap.f flexiblecolumnlayoutcolumnresize objectpagelayout objectpagedynamicheadertitle title objectpagesection objectpagesubsection button
○ generated · 9 deviations | [`Z2UI5_CL_SMPC_APP_577`](src/02/04/z2ui5_cl_smpc_app_577.clas.abap) | | **sap.f.FlexibleColumnLayout** — Flexible Column Layout with Routing and first page in fullscreen only
Flexible Column Layout as an app with routing that displays different pages in the initial column. The first page is only displayed in OneColumn layout type
flexiblecolumnlayout flexible column layout sap.f flexiblecolumnlayoutwithfullscreenpage dynamicpagetitle title table text columnlistitem objectidentifier
○ generated · 15 deviations | [`Z2UI5_CL_SMPC_APP_578`](src/02/04/z2ui5_cl_smpc_app_578.clas.abap) | | **sap.f.FlexibleColumnLayout** — Flexible Column Layout with Routing and One Initial Column
Flexible Column Layout as an app with routing that starts with a single initial column.
flexiblecolumnlayout flexible column layout sap.f flexiblecolumnlayoutwithonecolumnstart flexiblecolumnlayoutdata flexiblecolumnlayoutdatafordesktop flexiblecolumnlayoutdatafortablet dynamicpage dynamicpagetitle title
○ generated · 14 deviations | [`Z2UI5_CL_SMPC_APP_579`](src/02/04/z2ui5_cl_smpc_app_579.clas.abap) | | **sap.f.FlexibleColumnLayout** — Flexible Column Layout with Routing and Two Initial Columns
Flexible Column Layout as an app with routing that starts with two initial columns.
flexiblecolumnlayout flexible column layout sap.f flexiblecolumnlayoutwithtwocolumnstart dynamicpage dynamicpagetitle title table overflowtoolbar toolbarspacer
○ generated · 14 deviations | [`Z2UI5_CL_SMPC_APP_580`](src/02/04/z2ui5_cl_smpc_app_580.clas.abap) | -| **sap.f.ShellBar** — Shell Bar with Product Switch
Shell Bar example with enabled Product Switch, configurable by the app developer. The Product Switch control is in experimental state.
shellbar shell bar sap.f shellbarproductswitch avatar responsivepopover productswitch productswitchitem
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_583`](src/02/04/z2ui5_cl_smpc_app_583.clas.abap) | | **sap.f.FlexibleColumnLayout** — Shell Bar with Flexible Column Layout
Example of Shell Bar in combination with Flexible Column Layout.
flexiblecolumnlayout flexible column layout sap.f shellbarwithflexiblecolumnlayout shellbar menu menuitem avatar dynamicpage dynamicpagetitle
○ generated · 15 deviations | [`Z2UI5_CL_SMPC_APP_584`](src/02/04/z2ui5_cl_smpc_app_584.clas.abap) | + +#### sap.f.GridContainer + +| Sample | Class | +|---|---| +| **sap.f.GridContainer** — Grid Container - Drag and Drop
This sample represents GridContainer with enabled Drag and Drop functionality.
gridcontainer grid container sap.f gridcontainerdraganddrop scrollcontainer draginfo griddropinfo gridcontainersettings gridcontaineritemlayoutdata imagecontent header
○ generated · 6 deviations | [`Z2UI5_CL_SMPC_APP_526`](src/01/04/z2ui5_cl_smpc_app_526.clas.abap) | +| **sap.f.GridContainer** — Grid Container - Drag and Drop From List to GridContainer
This sample represents how items from a control which is not GridContainer can be dragged and dropped over a GridContainer.
gridcontainer grid container sap.f gridcontainerdraganddropfromlist scrollcontainer togglebutton hbox list draginfo dropinfo standardlistitem
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_527`](src/01/04/z2ui5_cl_smpc_app_527.clas.abap) | +| **sap.f.GridContainer**
This sample represents the general usage of GridContainer.
gridcontainer grid container sap.f scrollcontainer togglebutton panel hbox label switch text gridcontainersettings
◐ reviewed · 5 deviations | [`Z2UI5_CL_SMPC_APP_168`](src/02/04/z2ui5_cl_smpc_app_168.clas.abap) | +| **sap.f.GridContainer** — Grid Container - Keyboard navigation between multiple grids
This sample demonstrates the keyboard navigation between multiple grids
gridcontainer grid container sap.f gridcontainersnavigation scrollcontainer togglebutton hbox panel flexitemdata generictile gridcontaineritemlayoutdata
○ generated · 7 deviations | [`Z2UI5_CL_SMPC_APP_528`](src/02/04/z2ui5_cl_smpc_app_528.clas.abap) | + +#### sap.f.GridList + +| Sample | Class | +|---|---| +| **sap.f.GridList** — Grid List - Basic examples
A GridList with the default grid layout, resized live with a slider to show how the grid reflows.
gridlist grid list sap.f layout slider panel toolbar title gridlistitem vbox flexitemdata
◐ reviewed · 1 deviation | [`Z2UI5_CL_SMPC_APP_111`](src/01/04/z2ui5_cl_smpc_app_111.clas.abap) | +| **sap.f.GridList** — Grid List - Different Modes With Various Item Types
This is a sample for GridList with different modes of selection.
gridlist grid list sap.f selection modes html hbox segmentedbutton segmentedbuttonitem gridbasiclayout gridlistitem
◐ reviewed · 4 deviations | [`Z2UI5_CL_SMPC_APP_133`](src/01/04/z2ui5_cl_smpc_app_133.clas.abap) | +| **sap.f.GridList** — Grid List with GridBoxLayout
This layout allows to display same height grid items with configurable width.
gridlist grid list sap.f gridboxlayout slider panel toolbar title gridlistitem vbox flexitemdata
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_144`](src/01/04/z2ui5_cl_smpc_app_144.clas.abap) | +| **sap.f.GridList** — Grid List - Drag and Drop
This sample represents GridList with enabled Drag and Drop functionality.
gridlist grid list sap.f drag drop panel toolbar title draginfo griddropinfo gridboxlayout
◐ reviewed · 4 deviations | [`Z2UI5_CL_SMPC_APP_148`](src/01/04/z2ui5_cl_smpc_app_148.clas.abap) | +| **sap.f.GridList** — Grid List features - Grouping, Header, Growing
This sample illustrates subgroups with headers, custom header and lazy loading of GridList items.
gridlist grid list sap.f gridlistboxcontainergrouping slider panel toolbar title toolbarspacer searchfield gridboxlayout
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_176`](src/01/04/z2ui5_cl_smpc_app_176.clas.abap) | +| **sap.f.GridList** — Grid List - Break point examples - S, M, L, XL
This sample illustrates how to configure the responsive settings for different container sizes.
gridlist grid list sap.f gridlistbreakpoints slider panel toolbar title gridresponsivelayout gridsettings gridlistitem
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_213`](src/01/04/z2ui5_cl_smpc_app_213.clas.abap) | +| **sap.f.GridList** — Grid List - Item Designs
This is a sample for GridList item templates representing a typical tools page dashboard style.
gridlist grid list sap.f gridlistboxcontainerreal toolbar title gridboxlayout vbox flexitemdata label text
○ generated · 4 deviations | [`Z2UI5_CL_SMPC_APP_581`](src/01/04/z2ui5_cl_smpc_app_581.clas.abap) | +| **sap.f.GridList** — Navigation with keyboard arrows between multiple GridLists
This sample demonstrates the keyboard navigation between multiple grids
gridlist grid list sap.f gridlistkeyboardarrowsnavigation app slider gridresponsivelayout gridsettings gridbasiclayout gridlistitem griditemlayoutdata
○ generated · 7 deviations | [`Z2UI5_CL_SMPC_APP_582`](src/01/04/z2ui5_cl_smpc_app_582.clas.abap) | +| **sap.f.GridList** — Grid List with Responsive Column Layout
This layout displays a variable number of grid columns depending on available screen size. Grid row's height is dynamically determined by the height of the highest grid element on this row.
gridlist grid list sap.f gridlistresponsivecolumnlayout togglebutton slider panel toolbar title responsivecolumnlayout gridlistitem
◐ reviewed · 3 deviations | [`Z2UI5_CL_SMPC_APP_222`](src/02/04/z2ui5_cl_smpc_app_222.clas.abap) | + +#### sap.f.HeroBanner + +| Sample | Class | +|---|---| +| **sap.f.HeroBanner** — Hero Banner - Basic
A basic Hero Banner with a header text and overline text.
herobanner hero banner sap.f herobannerbasic vbox
○ generated · 1 deviation | [`Z2UI5_CL_SMPC_APP_667`](src/02/04/z2ui5_cl_smpc_app_667.clas.abap) | +| **sap.f.HeroBanner** — Hero Banner - Columns Ratio
Demonstrates the three columnsRatio options: single column (no endContent), Equal, and FirstWider.
herobanner hero banner sap.f herobannercolumnsratio html title vbox button text card header
○ generated · 2 deviations | [`Z2UI5_CL_SMPC_APP_668`](src/02/04/z2ui5_cl_smpc_app_668.clas.abap) | +| **sap.f.HeroBanner** — Hero Banner - Header Block and Actions Placement
Demonstrates actionsPlacement and headerBlockPlacement properties for controlling the position of the header and actions.
herobanner hero banner sap.f herobannerheaderblockandactionsplacement vbox button card header title
○ generated · 1 deviation | [`Z2UI5_CL_SMPC_APP_669`](src/02/04/z2ui5_cl_smpc_app_669.clas.abap) | +| **sap.f.HeroBanner** — Hero Banner - Integration Card
Demonstrates the use of sap.ui.integration.widgets.Card inside both the startContent (default slot) and endContent aggregations of the Hero Banner.
herobanner hero banner sap.f herobannerintegrationcard vbox button card
○ generated · 3 deviations | [`Z2UI5_CL_SMPC_APP_670`](src/02/04/z2ui5_cl_smpc_app_670.clas.abap) | +| **sap.f.HeroBanner** — Hero Banner - Use Cases
A collection of common Hero Banner use cases: header actions only, content with actions, actions below header, and header at bottom.
herobanner hero banner sap.f herobannerusecases html title vbox button text card header
○ generated · 2 deviations | [`Z2UI5_CL_SMPC_APP_671`](src/02/04/z2ui5_cl_smpc_app_671.clas.abap) | + +#### sap.f.ProductSwitch + +| Sample | Class | +|---|---| +| **sap.f.ProductSwitch** — Product Switch with Navigation
This sample demonstrates the navigation behavior of Product Switch, configurable by the app developer.
productswitch product switch sap.f productswitchnavigation verticallayout button text responsivepopover productswitchitem
◐ reviewed · 3 deviations | [`Z2UI5_CL_SMPC_APP_165`](src/02/04/z2ui5_cl_smpc_app_165.clas.abap) | +| **sap.f.ProductSwitch** — Product Switch with imageSrc
This sample demonstrates the usage of Product Switch Item with imageSrc, configurable by the app developer.
productswitch product switch sap.f productswitchitemwithimagesrc verticallayout button text responsivepopover productswitchitem
○ generated · 4 deviations | [`Z2UI5_CL_SMPC_APP_666`](src/02/04/z2ui5_cl_smpc_app_666.clas.abap) | + +#### sap.f.ShellBar + +| Sample | Class | +|---|---| +| **sap.f.ShellBar** — Shell Bar with title mega menu
Shell Bar example showing the control title as part of a mega menu, configurable by the app developer.
shellbar shell bar sap.f application header menu menuitem avatar
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_110`](src/02/04/z2ui5_cl_smpc_app_110.clas.abap) | +| **sap.f.ShellBar** — Shell Bar with menu button
Shell Bar example with a menu button and a plain title.
shellbar shell bar sap.f menu button avatar
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_152`](src/02/04/z2ui5_cl_smpc_app_152.clas.abap) | +| **sap.f.ShellBar** — Shell Bar with search
Shell Bar example with configured search functionality.
shellbar shell bar sap.f shellbarwithsearch menu menuitem avatar searchmanager suggestionitem
◐ reviewed · 4 deviations | [`Z2UI5_CL_SMPC_APP_218`](src/02/04/z2ui5_cl_smpc_app_218.clas.abap) | +| **sap.f.ShellBar** — Shell Bar with Product Switch
Shell Bar example with enabled Product Switch, configurable by the app developer. The Product Switch control is in experimental state.
shellbar shell bar sap.f shellbarproductswitch avatar responsivepopover productswitch productswitchitem
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_583`](src/02/04/z2ui5_cl_smpc_app_583.clas.abap) | | **sap.f.ShellBar** — Shell Bar with Split App
Example of Shell Bar in combination with Split App.
shellbar shell bar sap.f shellbarwithsplitapp toolpage menu menuitem avatar searchmanager sidenavigation navcontainer
○ generated · 7 deviations | [`Z2UI5_CL_SMPC_APP_585`](src/02/04/z2ui5_cl_smpc_app_585.clas.abap) | +#### sap.f.SidePanel + +| Sample | Class | +|---|---| +| **sap.f.SidePanel** — Side Panel with single action item
Demonstrates the usage of Side Panel with single action item.
sidepanel side panel sap.f single item button vbox label switch text sidepanelitem
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_136`](src/02/04/z2ui5_cl_smpc_app_136.clas.abap) | +| **sap.f.SidePanel**
Demonstrates the basic usage of Side Panel.
sidepanel side panel sap.f button vbox label switch select listitem text sidepanelitem
○ generated · 4 deviations | [`Z2UI5_CL_SMPC_APP_663`](src/02/04/z2ui5_cl_smpc_app_663.clas.abap) | +| **sap.f.SidePanel** — Side Panel with overflow menu
Demonstrates the usage of Side Panel with overflow menu on desktop and tablet devices.
sidepanel side panel sap.f sidepaneloverflow button vbox label switch text sidepanelitem
○ generated · 3 deviations | [`Z2UI5_CL_SMPC_APP_664`](src/02/04/z2ui5_cl_smpc_app_664.clas.abap) | +| **sap.f.SidePanel** — Resizable Side Panel
Demonstrates the usage of resizable Side Panel.
sidepanel side panel sap.f sidepanelresizable button vbox label switch text sidepanelitem input
○ generated · 3 deviations | [`Z2UI5_CL_SMPC_APP_665`](src/02/04/z2ui5_cl_smpc_app_665.clas.abap) | + ### sap.ui.layout.form 28 port(s). @@ -1287,6 +1392,23 @@ For what is NOT here — which demo kit samples are still unported and why — s | **sap.tnt.ToolPage** — Tool Page with Horizontal Navigation
A tool page layout with horizontal navigation
toolpage tool sap.tnt toolpagehorizontalnavigation toolheader image title overflowtoolbarlayoutdata text toolbarspacer searchfield button
◐ reviewed · 8 deviations | [`Z2UI5_CL_SMPC_APP_303`](src/02/05/z2ui5_cl_smpc_app_303.clas.abap) | | **sap.tnt.SideNavigation** — Side Navigation with Search
SideNavigation with a search field in the filter section and filterable navigation items.
sidenavigation side navigation sap.tnt sidenavigationsearch toolpage toolheader button image title text toolbarspacer
◐ reviewed · 11 deviations | [`Z2UI5_CL_SMPC_APP_407`](src/02/05/z2ui5_cl_smpc_app_407.clas.abap) | +### sap.m.plugins + +10 port(s). + +| Sample | Class | +|---|---| +| **sap.m.plugins.UploadSetwithTable** — Plugin for Responsive Table (sap.m.Table) - File Name validation configuration
This example demonstrates the usage of fileNameValidationConfig property to configure file name validation for renaming a file.
uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.filenamevalidationsample dynamicpage vbox messagestrip text hbox checkbox
○ generated · 12 deviations | [`Z2UI5_CL_SMPC_APP_652`](src/02/01/z2ui5_cl_smpc_app_652.clas.abap) | +| **sap.m.plugins.UploadSetwithTable** — Plugin for Responsive Table (sap.m.Table) - File Preview with Custom Page Content for non supported file types
This example showcases how to display custom page content for non supported file types in the FilePreviewDialog control.
uploadsetwithtable upload setwith table sap.m.plugins filepreviewcustompagecontent dynamicpage vbox messagestrip overflowtoolbar title toolbarspacer
○ generated · 12 deviations | [`Z2UI5_CL_SMPC_APP_653`](src/02/01/z2ui5_cl_smpc_app_653.clas.abap) | +| **sap.m.plugins.UploadSetwithTable** — Plugin for Grid Table (sap.ui.table.Table)
This example demonstrates the usage of UploadSetwithTable plugin for grid table with the features of upload, download, drag & drop, remove and rename of files. It also demonstrates how the uploaded files can be displayed in a table.
uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.gridtablesimple dynamicpage overflowtoolbar title toolbarspacer actionsplaceholder button
○ generated · 9 deviations | [`Z2UI5_CL_SMPC_APP_654`](src/02/01/z2ui5_cl_smpc_app_654.clas.abap) | +| **sap.m.plugins.UploadSetwithTable** — Plugin for Responsive Table (sap.m.Table) - Multiple plugin instances with multiple tables
This example demonstrates the usage of multiple plugin instances with multiple tables. The plugin instances are created for each table and the uploaded files are displayed in their respective tables.
uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.multipleplugininstances dynamicpage vbox overflowtoolbar title toolbarspacer searchfield
○ generated · 11 deviations | [`Z2UI5_CL_SMPC_APP_655`](src/02/01/z2ui5_cl_smpc_app_655.clas.abap) | +| **sap.m.plugins.UploadSetwithTable** — Plugin for Responsive Table (sap.m.Table) - File upload with user dialogs
This example demonstrates usage of itemValidationHandler callback to leverage additional validations and configurations for the items that are to be uploaded, and also the manual trigger of the upload process.
uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.responsivetablefiledialogs dynamicpage overflowtoolbar title toolbarspacer searchfield overflowtoolbarlayoutdata
○ generated · 11 deviations | [`Z2UI5_CL_SMPC_APP_656`](src/02/01/z2ui5_cl_smpc_app_656.clas.abap) | +| **sap.m.plugins.UploadSetwithTable** — Plugin for Responsive Table (sap.m.Table) - File Preview
This example showcases how uploaded files can be previewed with FilePreviewDialog control and its related configuration. UploadSetwithTable plugin creates and uses default instance of FilePreviewDialog, if not defined.
uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.responsivetablefilepreview dynamicpage overflowtoolbar title toolbarspacer searchfield overflowtoolbarlayoutdata
○ generated · 11 deviations | [`Z2UI5_CL_SMPC_APP_657`](src/02/01/z2ui5_cl_smpc_app_657.clas.abap) | +| **sap.m.plugins.UploadSetwithTable** — Plugin for Responsive Table (sap.m.Table) - Upload Progress and Upload Termination
This example demonstrates the progress or termination of the items that are being uploaded. The upload progress is displayed for each item that is being uploaded. The users can terminate the upload process at any time.
uploadsetwithtable upload setwith table sap.m.plugins responsivetableprogressindicator dynamicpage overflowtoolbar title toolbarspacer searchfield overflowtoolbarlayoutdata
○ generated · 10 deviations | [`Z2UI5_CL_SMPC_APP_658`](src/02/01/z2ui5_cl_smpc_app_658.clas.abap) | +| **sap.m.plugins.UploadSetwithTable** — Plugin for Responsive Table (sap.m.Table)
This example demonstrates the usage of UploadSetwithTable plugin for responsive table with the features of upload, download, drag & drop, remove and rename of files. It also demonstrates how the uploaded files can be displayed in a table.
uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.responsivetablesimple dynamicpage overflowtoolbar title toolbarspacer searchfield overflowtoolbarlayoutdata
○ generated · 10 deviations | [`Z2UI5_CL_SMPC_APP_659`](src/02/01/z2ui5_cl_smpc_app_659.clas.abap) | +| **sap.m.plugins.UploadSetwithTable** — Plugin for Tree Table (sap.ui.table.TreeTable)
This example demonstrates the usage of UploadSetwithTable plugin for tree table with the features of upload, download, drag & drop, remove and rename of files. It also demonstrates how the uploaded files can be displayed in a table.
uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.treetablesimple dynamicpage treetable overflowtoolbar title toolbarspacer actionsplaceholder
○ generated · 9 deviations | [`Z2UI5_CL_SMPC_APP_660`](src/02/01/z2ui5_cl_smpc_app_660.clas.abap) | +| **sap.m.plugins.UploadSetwithTable** — Plugin for Tree Table with folder hierarchy & folder uploads
This example demonstrates the usage of UploadSetwithTable plugin with a tree table featuring folder hierarchy, folder creation, folder uploads, folder navigation with breadcrumbs and folder management
uploadsetwithtable upload setwith table sap.m.plugins treetablewithfolderhierarchy dynamicpage treetable overflowtoolbar breadcrumbs link actionsplaceholder
○ generated · 10 deviations | [`Z2UI5_CL_SMPC_APP_661`](src/02/01/z2ui5_cl_smpc_app_661.clas.abap) | + ### sap.ui.layout.cssgrid 9 port(s). @@ -1318,6 +1440,20 @@ For what is NOT here — which demo kit samples are still unported and why — s | **sap.ui.model.type.Float** — Float Format
Formats and parses both integer and decimal digits.
float sap.ui.model.type typefloat simpleform label input text
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_179`](src/02/02/z2ui5_cl_smpc_app_179.clas.abap) | | **sap.ui.model.type.FileSize** — FileSize Type
This sample explains the formatting options of the FileSize type.
filesize file size sap.ui.model.type typefilesize simpleform label input text
◐ reviewed · 2 deviations | [`Z2UI5_CL_SMPC_APP_180`](src/02/02/z2ui5_cl_smpc_app_180.clas.abap) | +### sap.m.p13n + +7 port(s). + +| Sample | Class | +|---|---| +| **sap.m.p13n.Container** — p13n.Container usage in a Dialog/Popover
Dialog & Popover with a sap.m.P13nContainer as content.
container sap.m.p13n p13n.container vbox radiobuttongroup radiobutton label button text
○ generated · 5 deviations | [`Z2UI5_CL_SMPC_APP_644`](src/02/01/z2ui5_cl_smpc_app_644.clas.abap) | +| **sap.m.p13n.Engine** — Personalization for responsive table
Responsive Table using the personalization Engine
engine sap.m.p13n p13n.engine table overflowtoolbar title toolbarseparator toolbarspacer button text columnresizer menu
○ generated · 8 deviations | [`Z2UI5_CL_SMPC_APP_645`](src/02/01/z2ui5_cl_smpc_app_645.clas.abap) | +| **sap.m.p13n.Engine** — Personalization implementing custom filter controls
Filtering using the personalization Engine
engine sap.m.p13n p13n.enginecustomfilters table overflowtoolbar title toolbarseparator toolbarspacer button columnresizer menu quicksort
○ generated · 6 deviations | [`Z2UI5_CL_SMPC_APP_646`](src/02/01/z2ui5_cl_smpc_app_646.clas.abap) | +| **sap.m.p13n.Engine** — Personalization for grid list
GridList using the personalization Engine
engine sap.m.p13n p13n.enginegridlist vbox toolbar title toolbarseparator toolbarspacer button gridlist customlistitem flexitemdata
○ generated · 4 deviations | [`Z2UI5_CL_SMPC_APP_647`](src/02/01/z2ui5_cl_smpc_app_647.clas.abap) | +| **sap.m.p13n.Engine** — Personalization for grid table
Grid Table using the personalization Engine
engine sap.m.p13n p13n.enginegridtable table overflowtoolbar title toolbarseparator toolbarspacer button menu illustratedmessage label
○ generated · 7 deviations | [`Z2UI5_CL_SMPC_APP_648`](src/02/01/z2ui5_cl_smpc_app_648.clas.abap) | +| **sap.m.p13n.Engine** — Personalization with multiple SelectionControllers
Personalization for Reponsive Table using multiple SelectionControllers
engine sap.m.p13n p13n.enginemultiplecontroller table overflowtoolbar title toolbarseparator toolbarspacer button menu actionitem dragdropinfo
○ generated · 7 deviations | [`Z2UI5_CL_SMPC_APP_649`](src/02/01/z2ui5_cl_smpc_app_649.clas.abap) | +| **sap.m.p13n.Popup** — p13n.Popup usage
Dialog with sap.m.p13n/* Panels
popup sap.m.p13n p13n.popup vbox button selectionpanel sortpanel grouppanel codeeditor
○ generated · 6 deviations | [`Z2UI5_CL_SMPC_APP_650`](src/02/01/z2ui5_cl_smpc_app_650.clas.abap) | + ### sap.m.semantic 3 port(s). diff --git a/STATUS.md b/STATUS.md index cd67004a2..3b5ae5d54 100644 --- a/STATUS.md +++ b/STATUS.md @@ -15,13 +15,13 @@ TRAINING.md; for what abap2UI5 can express see CAPABILITIES.md._ | Aspect | State | |---|---| -| Ports | **622** sidecars in `meta/` (src/01 OpenUI5 <= 1.71: 401 · src/02 OpenUI5 > 1.71: 221) | -| Per library | sap.f: 36 · sap.m: 393 · sap.tnt: 17 · sap.ui: 131 · sap.uxap: 45 | -| Status ladder | 208 `generated` · 355 `reviewed` · 59 `checked` (live-verified) | -| Deviations | 10 DROPPED_171 · 161 IMPROVISED · 1937 NOTE · 301 POST_171 | +| Ports | **670** sidecars in `meta/` (src/01 OpenUI5 <= 1.71: 401 · src/02 OpenUI5 > 1.71: 269) | +| Per library | sap.f: 46 · sap.m: 431 · sap.tnt: 17 · sap.ui: 131 · sap.uxap: 45 | +| Status ladder | 256 `generated` · 355 `reviewed` · 59 `checked` (live-verified) | +| Deviations | 10 DROPPED_171 · 214 IMPROVISED · 2068 NOTE · 396 POST_171 | | Open LIVE_TESTs | **0 ports** carry at least one `LIVE_TEST` deviation — the automated close path is the e2e interaction harness (AGENTS §6 `e2e_smoke`) | -| Declared gate skips | 2 structural-diff · 5 render-smoke · 0 data-fidelity · 1 property-gate (each re-verified per run — a stale skip FAILS) | -| Out-of-scope ported samples | `z2ui5_cl_smpc_app_121 (sap.m.sample.UploadSet — deprecated)` · `z2ui5_cl_smpc_app_136 (sap.f.sample.SidePanelSingle — control @since 1.107)` · `z2ui5_cl_smpc_app_141 (sap.ui.core.sample.InvisibleMessage — control @since 1.78)` · `z2ui5_cl_smpc_app_165 (sap.f.sample.ProductSwitchNavigation — control @since 1.72)` · `z2ui5_cl_smpc_app_203 (sap.m.sample.OverflowToolbarTokenizer — control @since 1.139)` — all decided KEEP permanently 2026-07-30 (per-app rationale in ui5/scope-exceptions.json, revertible); the source-backed scope gate stays hard for NEW undecided entries | +| Declared gate skips | 2 structural-diff · 8 render-smoke · 0 data-fidelity · 1 property-gate (each re-verified per run — a stale skip FAILS) | +| Out-of-scope ported samples | `z2ui5_cl_smpc_app_121 (sap.m.sample.UploadSet — deprecated)` — all decided KEEP permanently 2026-07-30 (per-app rationale in ui5/scope-exceptions.json, revertible); the source-backed scope gate stays hard for NEW undecided entries | | Hold-out set (generator KPI) | **24** reserved samples in `ui5/holdout.json` · **12** spent as measurements (now ordinary ports: 098, 100, 101, 103, 153, 154, 210, 212, 229, 237, 242, 243) · results: 2 probe section(s) in [docs/history.md](docs/history.md): "Hold-out probe #2 (2026-07-26) — fidelity way up, syntax is the new frontier" · "Hold-out regeneration probe #1 (2026-07-19) — baseline set" — the measurement TRAINING.md "Measuring progress" defines, and the one number that still measures the generator with the portable backlog closed | _Coverage per library (ported / in scope) is generated into the [README](README.md#coverage); one row per sample in [api.md](api.md)._ diff --git a/TRAINING.md b/TRAINING.md index 08023de83..40093ad95 100644 --- a/TRAINING.md +++ b/TRAINING.md @@ -42,7 +42,7 @@ each port's `meta/.json`. Per batch: 1. **Generate** — the agent picks ~10 related samples from the in-scope backlog (`node scripts/generate-coverage.mjs --backlog` — only controls that - exist since UI5 1.71 and are not deprecated, see AGENTS §1) and ports them + are not deprecated, see AGENTS §1) and ports them under a new `b` batch id (`npm run scaffold … --new-batch`), prompt fed with AGENTS.md, CAPABILITIES.md and the 2–3 nearest `checked` ports. Pick **breadth-first**: `NEW-CONTROL` rows diff --git a/abaplint.jsonc b/abaplint.jsonc index b2efc8368..e54da99d7 100644 --- a/abaplint.jsonc +++ b/abaplint.jsonc @@ -289,7 +289,7 @@ // d'erables) - written here the way the original writes them. "7bit_ascii": { "exclude": [ - "z2ui5_cl_smpc_app_(012|040|092|103|104|114|134|185|191|194|215|218|254|290|302|303|350|356|357|358|360|445|525|558|565|572|575|578|579|580|584|611)\\.clas\\.", + "z2ui5_cl_smpc_app_(012|040|092|103|104|114|134|185|191|194|215|218|254|290|302|303|350|356|357|358|360|445|525|558|565|572|575|578|579|580|584|611|649|668|671)\\.clas\\.", "z2ui5_cl_smpc_app_000\\.clas\\.", "z2ui5_cl_smpc_demo_\\d+\\.clas\\." ] diff --git a/api.md b/api.md index 871891a2b..8661d756b 100644 --- a/api.md +++ b/api.md @@ -11,12 +11,12 @@ its ↗ opens the live fullscreen sample, **ABAP** is the generated class. hold-out set (`ui5/holdout.json`) that measures the generator, so it is kept unported on purpose and is not part of the backlog — see the [README](README.md#coverage). -`✗` = **out of scope**: the control is deprecated or newer than UI5 1.71 -(not legacy-free ready / not 1.71-compatible), or the sample is not an app +`✗` = **out of scope**: the control is deprecated (not legacy-free ready), +or the sample is not an app view at all (UI5 test infrastructure, Component routing, view-templating and XMLComposite authoring demos — `ui5/scope-nonapp.json`) — these samples are listed for completeness but are not ported. A **⁺** after the class marks ports -that keep members newer than UI5 1.71 for 1:1 fidelity (declared as +that keep a control or members newer than UI5 1.71 for 1:1 fidelity (declared as POST_171 in the sidecar) — they need a correspondingly recent UI5. See the [README](README.md#coverage) for the per-module coverage summary. @@ -24,7 +24,7 @@ _Control metadata (Since, deprecation) from the OpenUI5 **1.152.0** `api.json`._ | Module | Control | Since | Deprecated | Sample | ABAP | |--------|---------|:-----:|------------|--------|:----:| -| sap.f | [AvatarGroup](https://sdk.openui5.org/api/sap.f.AvatarGroup) | 1.73 | | [AvatarGroup](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/AvatarGroup) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.AvatarGroup&sap-ui-xx-sample-lib=sap.f) | ✗ | +| sap.f | [AvatarGroup](https://sdk.openui5.org/api/sap.f.AvatarGroup) | 1.73 | | [AvatarGroup](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/AvatarGroup) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.AvatarGroup&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_662](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_662.clas.abap) **⁺** | | sap.f | [Card](https://sdk.openui5.org/api/sap.f.Card) | 1.64 | | [Card](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/Card) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.Card&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_117](https://github.com/abap2UI5/samples-controls/blob/main/src/01/04/z2ui5_cl_smpc_app_117.clas.abap) | | sap.f | [DynamicPage](https://sdk.openui5.org/api/sap.f.DynamicPage) | 1.42 | | [DynamicPageAnalyticalTable](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/DynamicPageAnalyticalTable) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.DynamicPageAnalyticalTable&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_559](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_559.clas.abap) **⁺** | | sap.f | [DynamicPage](https://sdk.openui5.org/api/sap.f.DynamicPage) | 1.42 | | [DynamicPageFreeStyle](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/DynamicPageFreeStyle) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.DynamicPageFreeStyle&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_170](https://github.com/abap2UI5/samples-controls/blob/main/src/01/04/z2ui5_cl_smpc_app_170.clas.abap) | @@ -52,12 +52,12 @@ _Control metadata (Since, deprecation) from the OpenUI5 **1.152.0** `api.json`._ | sap.f | [GridList](https://sdk.openui5.org/api/sap.f.GridList) | 1.60 | | [GridListKeyboardArrowsNavigation](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/GridListKeyboardArrowsNavigation) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.GridListKeyboardArrowsNavigation&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_582](https://github.com/abap2UI5/samples-controls/blob/main/src/01/04/z2ui5_cl_smpc_app_582.clas.abap) | | sap.f | [GridList](https://sdk.openui5.org/api/sap.f.GridList) | 1.60 | | [GridListModes](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/GridListModes) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.GridListModes&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_133](https://github.com/abap2UI5/samples-controls/blob/main/src/01/04/z2ui5_cl_smpc_app_133.clas.abap) | | sap.f | [GridList](https://sdk.openui5.org/api/sap.f.GridList) | 1.60 | | [GridListResponsiveColumnLayout](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/GridListResponsiveColumnLayout) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.GridListResponsiveColumnLayout&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_222](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_222.clas.abap) **⁺** | -| sap.f | [HeroBanner](https://sdk.openui5.org/api/sap.f.HeroBanner) | 1.152 | | [HeroBannerBasic](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/HeroBannerBasic) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.HeroBannerBasic&sap-ui-xx-sample-lib=sap.f) | ✗ | -| sap.f | [HeroBanner](https://sdk.openui5.org/api/sap.f.HeroBanner) | 1.152 | | [HeroBannerColumnsRatio](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/HeroBannerColumnsRatio) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.HeroBannerColumnsRatio&sap-ui-xx-sample-lib=sap.f) | ✗ | -| sap.f | [HeroBanner](https://sdk.openui5.org/api/sap.f.HeroBanner) | 1.152 | | [HeroBannerHeaderBlockAndActionsPlacement](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/HeroBannerHeaderBlockAndActionsPlacement) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.HeroBannerHeaderBlockAndActionsPlacement&sap-ui-xx-sample-lib=sap.f) | ✗ | -| sap.f | [HeroBanner](https://sdk.openui5.org/api/sap.f.HeroBanner) | 1.152 | | [HeroBannerIntegrationCard](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/HeroBannerIntegrationCard) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.HeroBannerIntegrationCard&sap-ui-xx-sample-lib=sap.f) | ✗ | -| sap.f | [HeroBanner](https://sdk.openui5.org/api/sap.f.HeroBanner) | 1.152 | | [HeroBannerUseCases](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/HeroBannerUseCases) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.HeroBannerUseCases&sap-ui-xx-sample-lib=sap.f) | ✗ | -| sap.f | [ProductSwitch](https://sdk.openui5.org/api/sap.f.ProductSwitch) | 1.72 | | [ProductSwitchItemWithImageSrc](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/ProductSwitchItemWithImageSrc) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.ProductSwitchItemWithImageSrc&sap-ui-xx-sample-lib=sap.f) | ✗ | +| sap.f | [HeroBanner](https://sdk.openui5.org/api/sap.f.HeroBanner) | 1.152 | | [HeroBannerBasic](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/HeroBannerBasic) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.HeroBannerBasic&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_667](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_667.clas.abap) **⁺** | +| sap.f | [HeroBanner](https://sdk.openui5.org/api/sap.f.HeroBanner) | 1.152 | | [HeroBannerColumnsRatio](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/HeroBannerColumnsRatio) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.HeroBannerColumnsRatio&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_668](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_668.clas.abap) **⁺** | +| sap.f | [HeroBanner](https://sdk.openui5.org/api/sap.f.HeroBanner) | 1.152 | | [HeroBannerHeaderBlockAndActionsPlacement](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/HeroBannerHeaderBlockAndActionsPlacement) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.HeroBannerHeaderBlockAndActionsPlacement&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_669](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_669.clas.abap) **⁺** | +| sap.f | [HeroBanner](https://sdk.openui5.org/api/sap.f.HeroBanner) | 1.152 | | [HeroBannerIntegrationCard](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/HeroBannerIntegrationCard) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.HeroBannerIntegrationCard&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_670](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_670.clas.abap) **⁺** | +| sap.f | [HeroBanner](https://sdk.openui5.org/api/sap.f.HeroBanner) | 1.152 | | [HeroBannerUseCases](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/HeroBannerUseCases) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.HeroBannerUseCases&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_671](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_671.clas.abap) **⁺** | +| sap.f | [ProductSwitch](https://sdk.openui5.org/api/sap.f.ProductSwitch) | 1.72 | | [ProductSwitchItemWithImageSrc](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/ProductSwitchItemWithImageSrc) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.ProductSwitchItemWithImageSrc&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_666](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_666.clas.abap) **⁺** | | sap.f | [ProductSwitch](https://sdk.openui5.org/api/sap.f.ProductSwitch) | 1.72 | | [ProductSwitchNavigation](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/ProductSwitchNavigation) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.ProductSwitchNavigation&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_165](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_165.clas.abap) **⁺** | | sap.f | [SemanticPage](https://sdk.openui5.org/api/sap.f.semantic.SemanticPage) | 1.46.0 | | [SemanticPage](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/SemanticPage) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.SemanticPage&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_166](https://github.com/abap2UI5/samples-controls/blob/main/src/01/04/z2ui5_cl_smpc_app_166.clas.abap) | | sap.f | [SemanticPage](https://sdk.openui5.org/api/sap.f.semantic.SemanticPage) | 1.46.0 | | [SemanticPageFreeStyle](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/SemanticPageFreeStyle) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.SemanticPageFreeStyle&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_529](https://github.com/abap2UI5/samples-controls/blob/main/src/01/04/z2ui5_cl_smpc_app_529.clas.abap) | @@ -66,18 +66,18 @@ _Control metadata (Since, deprecation) from the OpenUI5 **1.152.0** `api.json`._ | sap.f | [ShellBar](https://sdk.openui5.org/api/sap.f.ShellBar) | 1.63 | | [ShellBarWithMenuButton](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/ShellBarWithMenuButton) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.ShellBarWithMenuButton&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_152](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_152.clas.abap) **⁺** | | sap.f | [ShellBar](https://sdk.openui5.org/api/sap.f.ShellBar) | 1.63 | | [ShellBarWithSearch](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/ShellBarWithSearch) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.ShellBarWithSearch&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_218](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_218.clas.abap) **⁺** | | sap.f | [ShellBar](https://sdk.openui5.org/api/sap.f.ShellBar) | 1.63 | | [ShellBarWithSplitApp](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/ShellBarWithSplitApp) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.ShellBarWithSplitApp&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_585](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_585.clas.abap) **⁺** | -| sap.f | [SidePanel](https://sdk.openui5.org/api/sap.f.SidePanel) | 1.107 | | [SidePanel](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/SidePanel) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.SidePanel&sap-ui-xx-sample-lib=sap.f) | ✗ | -| sap.f | [SidePanel](https://sdk.openui5.org/api/sap.f.SidePanel) | 1.107 | | [SidePanelOverflow](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/SidePanelOverflow) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.SidePanelOverflow&sap-ui-xx-sample-lib=sap.f) | ✗ | -| sap.f | [SidePanel](https://sdk.openui5.org/api/sap.f.SidePanel) | 1.107 | | [SidePanelResizable](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/SidePanelResizable) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.SidePanelResizable&sap-ui-xx-sample-lib=sap.f) | ✗ | +| sap.f | [SidePanel](https://sdk.openui5.org/api/sap.f.SidePanel) | 1.107 | | [SidePanel](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/SidePanel) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.SidePanel&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_663](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_663.clas.abap) **⁺** | +| sap.f | [SidePanel](https://sdk.openui5.org/api/sap.f.SidePanel) | 1.107 | | [SidePanelOverflow](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/SidePanelOverflow) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.SidePanelOverflow&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_664](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_664.clas.abap) **⁺** | +| sap.f | [SidePanel](https://sdk.openui5.org/api/sap.f.SidePanel) | 1.107 | | [SidePanelResizable](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/SidePanelResizable) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.SidePanelResizable&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_665](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_665.clas.abap) **⁺** | | sap.f | [SidePanel](https://sdk.openui5.org/api/sap.f.SidePanel) | 1.107 | | [SidePanelSingle](https://github.com/SAP/openui5/tree/master/src/sap.f/test/sap/f/demokit/sample/SidePanelSingle) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.f.sample.SidePanelSingle&sap-ui-xx-sample-lib=sap.f) | [z2ui5_cl_smpc_app_136](https://github.com/abap2UI5/samples-controls/blob/main/src/02/04/z2ui5_cl_smpc_app_136.clas.abap) **⁺** | | sap.m | [ActionListItem](https://sdk.openui5.org/api/sap.m.ActionListItem) | | | [ActionListItem](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ActionListItem) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ActionListItem&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_001](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_001.clas.abap) | | sap.m | [~~ActionSelect~~](https://sdk.openui5.org/api/sap.m.ActionSelect) | 1.16 | 1.111 — with no replacement. The control is no longer considered part of the Fiori concept. | [ActionSelect](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ActionSelect) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ActionSelect&sap-ui-xx-sample-lib=sap.m) | ✗ | | sap.m | [~~ActionSheet~~](https://sdk.openui5.org/api/sap.m.ActionSheet) | 1.9.1 | 1.149 — use sap.m.Menu / sap.m.MenuItem instead. | [ActionSheet](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ActionSheet) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ActionSheet&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [Avatar](https://sdk.openui5.org/api/sap.m.Avatar) | 1.73 | | [Avatar](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/Avatar) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.Avatar&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [Avatar](https://sdk.openui5.org/api/sap.m.Avatar) | 1.73 | | [AvatarActiveState](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/AvatarActiveState) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.AvatarActiveState&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [Avatar](https://sdk.openui5.org/api/sap.m.Avatar) | 1.73 | | [AvatarBadgeIconColor](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/AvatarBadgeIconColor) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.AvatarBadgeIconColor&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [Avatar](https://sdk.openui5.org/api/sap.m.Avatar) | 1.73 | | [AvatarValueState](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/AvatarValueState) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.AvatarValueState&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [Avatar](https://sdk.openui5.org/api/sap.m.Avatar) | 1.73 | | [AvatarWithAffordance](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/AvatarWithAffordance) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.AvatarWithAffordance&sap-ui-xx-sample-lib=sap.m) | ✗ | +| sap.m | [Avatar](https://sdk.openui5.org/api/sap.m.Avatar) | 1.73 | | [Avatar](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/Avatar) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.Avatar&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_624](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_624.clas.abap) **⁺** | +| sap.m | [Avatar](https://sdk.openui5.org/api/sap.m.Avatar) | 1.73 | | [AvatarActiveState](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/AvatarActiveState) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.AvatarActiveState&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_625](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_625.clas.abap) **⁺** | +| sap.m | [Avatar](https://sdk.openui5.org/api/sap.m.Avatar) | 1.73 | | [AvatarBadgeIconColor](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/AvatarBadgeIconColor) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.AvatarBadgeIconColor&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_626](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_626.clas.abap) **⁺** | +| sap.m | [Avatar](https://sdk.openui5.org/api/sap.m.Avatar) | 1.73 | | [AvatarValueState](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/AvatarValueState) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.AvatarValueState&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_627](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_627.clas.abap) **⁺** | +| sap.m | [Avatar](https://sdk.openui5.org/api/sap.m.Avatar) | 1.73 | | [AvatarWithAffordance](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/AvatarWithAffordance) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.AvatarWithAffordance&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_628](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_628.clas.abap) **⁺** | | sap.m | [Bar](https://sdk.openui5.org/api/sap.m.Bar) | | | [Page](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/Page) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.Page&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_002](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_002.clas.abap) | | sap.m | [Bar](https://sdk.openui5.org/api/sap.m.Bar) | | | [ToolbarVsBar](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ToolbarVsBar) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ToolbarVsBar&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_189](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_189.clas.abap) | | sap.m | [Breadcrumbs](https://sdk.openui5.org/api/sap.m.Breadcrumbs) | 1.34 | | [Breadcrumbs](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/Breadcrumbs) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.Breadcrumbs&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_003](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_003.clas.abap) | @@ -136,11 +136,11 @@ _Control metadata (Since, deprecation) from the OpenUI5 **1.152.0** `api.json`._ | sap.m | [DisplayListItem](https://sdk.openui5.org/api/sap.m.DisplayListItem) | | | [DisplayListItem](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/DisplayListItem) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.DisplayListItem&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_020](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_020.clas.abap) | | sap.m | [DraftIndicator](https://sdk.openui5.org/api/sap.m.DraftIndicator) | 1.32.0 | | [DraftIndicator](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/DraftIndicator) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.DraftIndicator&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_021](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_021.clas.abap) | | sap.m | [DraftIndicator](https://sdk.openui5.org/api/sap.m.DraftIndicator) | 1.32.0 | | [SemanticPageDraftIndicator](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/SemanticPageDraftIndicator) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.SemanticPageDraftIndicator&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_448](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_448.clas.abap) | -| sap.m | [DynamicDateRange](https://sdk.openui5.org/api/sap.m.DynamicDateRange) | 1.92.0 | | [DynamicDateRange](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/DynamicDateRange) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.DynamicDateRange&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [DynamicDateRange](https://sdk.openui5.org/api/sap.m.DynamicDateRange) | 1.92.0 | | [DynamicDateRangeAndCalendarWeekNumbering](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/DynamicDateRangeAndCalendarWeekNumbering) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.DynamicDateRangeAndCalendarWeekNumbering&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [DynamicDateRange](https://sdk.openui5.org/api/sap.m.DynamicDateRange) | 1.92.0 | | [DynamicDateRangeHidden](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/DynamicDateRangeHidden) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.DynamicDateRangeHidden&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [DynamicDateRange](https://sdk.openui5.org/api/sap.m.DynamicDateRange) | 1.92.0 | | [DynamicDateRangeWithCustomOptions](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/DynamicDateRangeWithCustomOptions) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.DynamicDateRangeWithCustomOptions&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [ExpandableText](https://sdk.openui5.org/api/sap.m.ExpandableText) | 1.87 | | [ExpandableText](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ExpandableText) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ExpandableText&sap-ui-xx-sample-lib=sap.m) | ✗ | +| sap.m | [DynamicDateRange](https://sdk.openui5.org/api/sap.m.DynamicDateRange) | 1.92.0 | | [DynamicDateRange](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/DynamicDateRange) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.DynamicDateRange&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_639](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_639.clas.abap) **⁺** | +| sap.m | [DynamicDateRange](https://sdk.openui5.org/api/sap.m.DynamicDateRange) | 1.92.0 | | [DynamicDateRangeAndCalendarWeekNumbering](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/DynamicDateRangeAndCalendarWeekNumbering) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.DynamicDateRangeAndCalendarWeekNumbering&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_640](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_640.clas.abap) **⁺** | +| sap.m | [DynamicDateRange](https://sdk.openui5.org/api/sap.m.DynamicDateRange) | 1.92.0 | | [DynamicDateRangeHidden](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/DynamicDateRangeHidden) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.DynamicDateRangeHidden&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_641](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_641.clas.abap) **⁺** | +| sap.m | [DynamicDateRange](https://sdk.openui5.org/api/sap.m.DynamicDateRange) | 1.92.0 | | [DynamicDateRangeWithCustomOptions](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/DynamicDateRangeWithCustomOptions) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.DynamicDateRangeWithCustomOptions&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_642](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_642.clas.abap) **⁺** | +| sap.m | [ExpandableText](https://sdk.openui5.org/api/sap.m.ExpandableText) | 1.87 | | [ExpandableText](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ExpandableText) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ExpandableText&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_643](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_643.clas.abap) **⁺** | | sap.m | [FacetFilter](https://sdk.openui5.org/api/sap.m.FacetFilter) | | | [FacetFilterCustomFilters](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/FacetFilterCustomFilters) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.FacetFilterCustomFilters&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_557](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_557.clas.abap) **⁺** | | sap.m | [FacetFilter](https://sdk.openui5.org/api/sap.m.FacetFilter) | | | [FacetFilterLight](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/FacetFilterLight) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.FacetFilterLight&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_022](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_022.clas.abap) | | sap.m | [FacetFilter](https://sdk.openui5.org/api/sap.m.FacetFilter) | | | [FacetFilterSimple](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/FacetFilterSimple) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.FacetFilterSimple&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_235](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_235.clas.abap) | @@ -189,16 +189,16 @@ _Control metadata (Since, deprecation) from the OpenUI5 **1.152.0** `api.json`._ | sap.m | [IconTabBar](https://sdk.openui5.org/api/sap.m.IconTabBar) | | | [IconTabBarTabDensityMode](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IconTabBarTabDensityMode) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IconTabBarTabDensityMode&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_620](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_620.clas.abap) | | sap.m | [IconTabBar](https://sdk.openui5.org/api/sap.m.IconTabBar) | | | [IconTabSeparator](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IconTabSeparator) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IconTabSeparator&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_383](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_383.clas.abap) | | sap.m | [IconTabHeader](https://sdk.openui5.org/api/sap.m.IconTabHeader) | 1.15 | | [IconTabHeader](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IconTabHeader) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IconTabHeader&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_055](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_055.clas.abap) | -| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageEVR](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageEVR) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageEVR&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInAppCustom](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInAppCustom) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInAppCustom&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInCardNoActivities](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInCardNoActivities) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInCardNoActivities&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInCardNoEmail](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInCardNoEmail) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInCardNoEmail&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInDialog](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInDialog) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInDialog&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInPage](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInPage) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInPage&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInPageCustom](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInPageCustom) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInPageCustom&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInPageTNT](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInPageTNT) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInPageTNT&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInPageWithURI](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInPageWithURI) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInPageWithURI&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageSessionTimeout](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageSessionTimeout) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageSessionTimeout&sap-ui-xx-sample-lib=sap.m) | ✗ | +| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageEVR](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageEVR) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageEVR&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_629](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_629.clas.abap) **⁺** | +| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInAppCustom](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInAppCustom) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInAppCustom&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_630](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_630.clas.abap) **⁺** | +| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInCardNoActivities](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInCardNoActivities) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInCardNoActivities&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_631](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_631.clas.abap) **⁺** | +| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInCardNoEmail](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInCardNoEmail) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInCardNoEmail&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_632](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_632.clas.abap) **⁺** | +| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInDialog](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInDialog) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInDialog&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_633](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_633.clas.abap) **⁺** | +| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInPage](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInPage) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInPage&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_634](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_634.clas.abap) **⁺** | +| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInPageCustom](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInPageCustom) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInPageCustom&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_635](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_635.clas.abap) **⁺** | +| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInPageTNT](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInPageTNT) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInPageTNT&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_636](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_636.clas.abap) **⁺** | +| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageInPageWithURI](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageInPageWithURI) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageInPageWithURI&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_637](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_637.clas.abap) **⁺** | +| sap.m | [IllustratedMessage](https://sdk.openui5.org/api/sap.m.IllustratedMessage) | 1.98 | | [IllustratedMessageSessionTimeout](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/IllustratedMessageSessionTimeout) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.IllustratedMessageSessionTimeout&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_638](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_638.clas.abap) **⁺** | | sap.m | [Image](https://sdk.openui5.org/api/sap.m.Image) | | | [Image](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/Image) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.Image&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_399](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_399.clas.abap) **⁺** | | sap.m | [Image](https://sdk.openui5.org/api/sap.m.Image) | | | [ImageErrorWithIllustration](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ImageErrorWithIllustration) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ImageErrorWithIllustration&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_279](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_279.clas.abap) **⁺** | | sap.m | [Image](https://sdk.openui5.org/api/sap.m.Image) | | | [ImageModeBackground](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ImageModeBackground) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ImageModeBackground&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_031](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_031.clas.abap) | @@ -331,13 +331,13 @@ _Control metadata (Since, deprecation) from the OpenUI5 **1.152.0** `api.json`._ | sap.m | [OverflowToolbar](https://sdk.openui5.org/api/sap.m.OverflowToolbar) | 1.28 | | [ToolbarDesign](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ToolbarDesign) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ToolbarDesign&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_086](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_086.clas.abap) | | sap.m | [OverflowToolbar](https://sdk.openui5.org/api/sap.m.OverflowToolbar) | 1.28 | | [ToolbarEnabled](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ToolbarEnabled) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ToolbarEnabled&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_425](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_425.clas.abap) | | sap.m | [OverflowToolbarTokenizer](https://sdk.openui5.org/api/sap.m.OverflowToolbarTokenizer) | 1.139 | | [OverflowToolbarTokenizer](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/OverflowToolbarTokenizer) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.OverflowToolbarTokenizer&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_203](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_203.clas.abap) **⁺** | -| sap.m | [Container](https://sdk.openui5.org/api/sap.m.p13n.Container) | 1.96 | | [p13n.Container](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/Container) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.Container&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [Engine](https://sdk.openui5.org/api/sap.m.p13n.Engine) | 1.104 | | [p13n.Engine](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/Engine) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.Engine&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [Engine](https://sdk.openui5.org/api/sap.m.p13n.Engine) | 1.104 | | [p13n.EngineCustomFilters](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/EngineCustomFilters) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.EngineCustomFilters&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [Engine](https://sdk.openui5.org/api/sap.m.p13n.Engine) | 1.104 | | [p13n.EngineGridList](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/EngineGridList) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.EngineGridList&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [Engine](https://sdk.openui5.org/api/sap.m.p13n.Engine) | 1.104 | | [p13n.EngineGridTable](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/EngineGridTable) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.EngineGridTable&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [Engine](https://sdk.openui5.org/api/sap.m.p13n.Engine) | 1.104 | | [p13n.EngineMultipleController](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/EngineMultipleController) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.EngineMultipleController&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [Popup](https://sdk.openui5.org/api/sap.m.p13n.Popup) | 1.97 | | [p13n.Popup](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/Popup) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.Popup&sap-ui-xx-sample-lib=sap.m) | ✗ | +| sap.m | [Container](https://sdk.openui5.org/api/sap.m.p13n.Container) | 1.96 | | [p13n.Container](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/Container) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.Container&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_644](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_644.clas.abap) **⁺** | +| sap.m | [Engine](https://sdk.openui5.org/api/sap.m.p13n.Engine) | 1.104 | | [p13n.Engine](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/Engine) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.Engine&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_645](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_645.clas.abap) **⁺** | +| sap.m | [Engine](https://sdk.openui5.org/api/sap.m.p13n.Engine) | 1.104 | | [p13n.EngineCustomFilters](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/EngineCustomFilters) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.EngineCustomFilters&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_646](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_646.clas.abap) **⁺** | +| sap.m | [Engine](https://sdk.openui5.org/api/sap.m.p13n.Engine) | 1.104 | | [p13n.EngineGridList](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/EngineGridList) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.EngineGridList&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_647](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_647.clas.abap) **⁺** | +| sap.m | [Engine](https://sdk.openui5.org/api/sap.m.p13n.Engine) | 1.104 | | [p13n.EngineGridTable](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/EngineGridTable) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.EngineGridTable&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_648](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_648.clas.abap) **⁺** | +| sap.m | [Engine](https://sdk.openui5.org/api/sap.m.p13n.Engine) | 1.104 | | [p13n.EngineMultipleController](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/EngineMultipleController) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.EngineMultipleController&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_649](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_649.clas.abap) **⁺** | +| sap.m | [Popup](https://sdk.openui5.org/api/sap.m.p13n.Popup) | 1.97 | | [p13n.Popup](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/p13n/Popup) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.p13n.Popup&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_650](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_650.clas.abap) **⁺** | | sap.m | [Page](https://sdk.openui5.org/api/sap.m.Page) | | | [PageFloatingFooter](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/PageFloatingFooter) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.PageFloatingFooter&sap-ui-xx-sample-lib=sap.m) | ⊘ | | sap.m | [Page](https://sdk.openui5.org/api/sap.m.Page) | | | [PageListReportIconTabBar](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/PageListReportIconTabBar) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.PageListReportIconTabBar&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_406](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_406.clas.abap) **⁺** | | sap.m | [Page](https://sdk.openui5.org/api/sap.m.Page) | | | [PageListReportToolbar](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/PageListReportToolbar) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.PageListReportToolbar&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_405](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_405.clas.abap) **⁺** | @@ -363,16 +363,16 @@ _Control metadata (Since, deprecation) from the OpenUI5 **1.152.0** `api.json`._ | sap.m | [PlanningCalendar](https://sdk.openui5.org/api/sap.m.PlanningCalendar) | 1.34 | | [PlanningCalendarWeekNumbering](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/PlanningCalendarWeekNumbering) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.PlanningCalendarWeekNumbering&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_544](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_544.clas.abap) **⁺** | | sap.m | [PlanningCalendar](https://sdk.openui5.org/api/sap.m.PlanningCalendar) | 1.34 | | [PlanningCalendarWithLegend](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/PlanningCalendarWithLegend) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.PlanningCalendarWithLegend&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_541](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_541.clas.abap) **⁺** | | sap.m | [PlanningCalendar](https://sdk.openui5.org/api/sap.m.PlanningCalendar) | 1.34 | | [PlanningCalendarWithStickyHeader](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/PlanningCalendarWithStickyHeader) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.PlanningCalendarWithStickyHeader&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_542](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_542.clas.abap) | -| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.FileNameValidationSample](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/FileNameValidationSample) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.FileNameValidationSample&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.FilePreviewCustomPageContent](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/FilePreviewCustomPageContent) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.FilePreviewCustomPageContent&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.GridTableSimple](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/GridTableSimple) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.GridTableSimple&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.MultiplePluginInstances](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/MultiplePluginInstances) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.MultiplePluginInstances&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.ResponsiveTableFileDialogs](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/ResponsiveTableFileDialogs) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableFileDialogs&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.ResponsiveTableFilePreview](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/ResponsiveTableFilePreview) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableFilePreview&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.ResponsiveTableProgressIndicator](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/ResponsiveTableProgressIndicator) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableProgressIndicator&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.ResponsiveTableSimple](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/ResponsiveTableSimple) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableSimple&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.TreeTableSimple](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/TreeTableSimple) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.TreeTableSimple&sap-ui-xx-sample-lib=sap.m) | ✗ | -| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.TreeTableWithFolderHierarchy](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/TreeTableWithFolderHierarchy) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.TreeTableWithFolderHierarchy&sap-ui-xx-sample-lib=sap.m) | ✗ | +| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.FileNameValidationSample](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/FileNameValidationSample) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.FileNameValidationSample&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_652](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_652.clas.abap) **⁺** | +| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.FilePreviewCustomPageContent](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/FilePreviewCustomPageContent) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.FilePreviewCustomPageContent&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_653](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_653.clas.abap) **⁺** | +| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.GridTableSimple](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/GridTableSimple) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.GridTableSimple&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_654](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_654.clas.abap) **⁺** | +| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.MultiplePluginInstances](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/MultiplePluginInstances) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.MultiplePluginInstances&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_655](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_655.clas.abap) **⁺** | +| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.ResponsiveTableFileDialogs](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/ResponsiveTableFileDialogs) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableFileDialogs&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_656](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_656.clas.abap) **⁺** | +| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.ResponsiveTableFilePreview](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/ResponsiveTableFilePreview) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableFilePreview&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_657](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_657.clas.abap) **⁺** | +| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.ResponsiveTableProgressIndicator](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/ResponsiveTableProgressIndicator) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableProgressIndicator&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_658](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_658.clas.abap) **⁺** | +| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.ResponsiveTableSimple](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/ResponsiveTableSimple) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableSimple&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_659](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_659.clas.abap) **⁺** | +| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.TreeTableSimple](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/TreeTableSimple) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.TreeTableSimple&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_660](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_660.clas.abap) **⁺** | +| sap.m | [UploadSetwithTable](https://sdk.openui5.org/api/sap.m.plugins.UploadSetwithTable) | 1.124 | | [UploadSetwithTablePlugin.TreeTableWithFolderHierarchy](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadSetwithTablePlugin/TreeTableWithFolderHierarchy) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadSetwithTablePlugin.TreeTableWithFolderHierarchy&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_661](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_661.clas.abap) **⁺** | | sap.m | [Popover](https://sdk.openui5.org/api/sap.m.Popover) | | | [Popover](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/Popover) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.Popover&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_229](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_229.clas.abap) **⁺** | | sap.m | [Popover](https://sdk.openui5.org/api/sap.m.Popover) | | | [PopoverControllingCloseBehavior](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/PopoverControllingCloseBehavior) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.PopoverControllingCloseBehavior&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_094](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_094.clas.abap) **⁺** | | sap.m | [Popover](https://sdk.openui5.org/api/sap.m.Popover) | | | [PopoverNavCon](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/PopoverNavCon) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.PopoverNavCon&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_565](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_565.clas.abap) **⁺** | @@ -509,7 +509,7 @@ _Control metadata (Since, deprecation) from the OpenUI5 **1.152.0** `api.json`._ | sap.m | [~~UploadCollection~~](https://sdk.openui5.org/api/sap.m.UploadCollection) | | 1.88 — replaced by sap.m.upload.UploadSet | [UploadCollectionSortingFiltering](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadCollectionSortingFiltering) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadCollectionSortingFiltering&sap-ui-xx-sample-lib=sap.m) | ✗ | | sap.m | [~~UploadCollection~~](https://sdk.openui5.org/api/sap.m.UploadCollection) | | 1.88 — replaced by sap.m.upload.UploadSet | [UploadCollectionVersioning](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UploadCollectionVersioning) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UploadCollectionVersioning&sap-ui-xx-sample-lib=sap.m) | ✗ | | sap.m | [URLHelper](https://sdk.openui5.org/api/sap.m.URLHelper) | 1.10 | | [UrlHelper](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/UrlHelper) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.UrlHelper&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_084](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_084.clas.abap) | -| sap.m | [VariantManagement](https://sdk.openui5.org/api/sap.m.VariantManagement) | 1.103 | | [VariantManagement](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/VariantManagement) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.VariantManagement&sap-ui-xx-sample-lib=sap.m) | ✗ | +| sap.m | [VariantManagement](https://sdk.openui5.org/api/sap.m.VariantManagement) | 1.103 | | [VariantManagement](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/VariantManagement) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.VariantManagement&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_651](https://github.com/abap2UI5/samples-controls/blob/main/src/02/01/z2ui5_cl_smpc_app_651.clas.abap) **⁺** | | sap.m | [ViewSettingsDialog](https://sdk.openui5.org/api/sap.m.ViewSettingsDialog) | 1.16 | | [ViewSettingsDialog](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ViewSettingsDialog) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ViewSettingsDialog&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_098](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_098.clas.abap) | | sap.m | [ViewSettingsDialog](https://sdk.openui5.org/api/sap.m.ViewSettingsDialog) | 1.16 | | [ViewSettingsDialogCustom](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ViewSettingsDialogCustom) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ViewSettingsDialogCustom&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_295](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_295.clas.abap) | | sap.m | [ViewSettingsDialog](https://sdk.openui5.org/api/sap.m.ViewSettingsDialog) | 1.16 | | [ViewSettingsDialogCustomFilterDetails](https://github.com/SAP/openui5/tree/master/src/sap.m/test/sap/m/demokit/sample/ViewSettingsDialogCustomFilterDetails) [↗](https://sdk.openui5.org/resources/sap/ui/documentation/sdk/index.html?sap-ui-xx-sample-id=sap.m.sample.ViewSettingsDialogCustomFilterDetails&sap-ui-xx-sample-lib=sap.m) | [z2ui5_cl_smpc_app_296](https://github.com/abap2UI5/samples-controls/blob/main/src/01/01/z2ui5_cl_smpc_app_296.clas.abap) | diff --git a/catalogue-derived.json b/catalogue-derived.json index 08499f92e..4da8c3c54 100644 --- a/catalogue-derived.json +++ b/catalogue-derived.json @@ -35,6 +35,8 @@ "1.100", "1.101", "1.103", + "1.104", + "1.105", "1.106", "1.107", "1.109", @@ -57,11 +59,13 @@ "1.132", "1.133", "1.134", + "1.136", "1.137", "1.139", "1.140", "1.142", "1.143", + "1.146", "1.147", "1.149", "1.150", @@ -371,6 +375,22 @@ "sap.m.LinkTileContent", "sap.m.OverflowToolbarMenuButton", "sap.m.OverflowToolbarToggleButton", + "sap.m.DynamicDateRange", + "sap.m.ExpandableText", + "sap.m.p13n.AbstractContainerItem", + "sap.m.p13n.Container", + "sap.m.p13n.GroupPanel", + "sap.m.p13n.Popup", + "sap.m.p13n.SelectionPanel", + "sap.m.p13n.SortPanel", + "sap.m.table.columnmenu.QuickGroup", + "sap.m.table.columnmenu.QuickGroupItem", + "sap.m.VariantItem", + "sap.m.VariantManagement", + "sap.m.plugins.UploadSetwithTable", + "sap.m.upload.ActionsPlaceholder", + "sap.m.upload.UploadItemConfiguration", + "sap.m.upload.FilePreviewDialog", "sap.f.ShellBar", "sap.f.cards.CardBadgeCustomData", "sap.ui.unified.Menu", @@ -399,6 +419,9 @@ "sap.f.FlexibleColumnLayoutDataForDesktop", "sap.f.FlexibleColumnLayoutDataForTablet", "sap.tnt.SideNavigation", + "sap.f.AvatarGroup", + "sap.f.AvatarGroupItem", + "sap.f.HeroBanner", "sap.tnt.NavigationListGroup", "sap.tnt.ToolHeaderUtilitySeparator", "sap.tnt.SideNavigationSearchField", @@ -460,8 +483,8 @@ "z2ui5.cc.Storage" ], "counts": { - "ports": 641, - "controls": 389 + "ports": 689, + "controls": 408 }, "ports": [ {"class":"z2ui5_cl_smpc_app_001","description":"Use the Action List Item to trigger an action directly from a list","minUi5":"1.71","needs":[],"controls":[0,1,2],"controlCount":7}, @@ -573,7 +596,7 @@ {"class":"z2ui5_cl_smpc_app_107","description":"Semantic Page Master/Detail","minUi5":"1.71","needs":[],"controls":[3,78,122,123,147,137,112,124,138,126,128,139,129,140,141,142,131,143,144,145,132,133,134,135,146,15,2,136],"controlCount":30}, {"class":"z2ui5_cl_smpc_app_108","description":"PlanningCalendar with only one row without row header. On click on an interval a new appointment is created.","minUi5":"1.150","needs":[{"type":"member-too-new","name":"sap.ui.unified.CalendarAppointment.ariaHasPopup","since":"1.150"}],"controls":[175,176,20,33,9,2,177],"controlCount":8}, {"class":"z2ui5_cl_smpc_app_109","description":"SinglePlanningCalendar with multiple date selection functionality.","minUi5":"1.123","needs":[{"type":"member-too-new","name":"sap.m.SinglePlanningCalendar.selectedDatesChange","since":"1.123"},{"type":"member-too-new","name":"sap.m.SinglePlanningCalendar.weekNumberPress","since":"1.123"},{"type":"icon-too-new","name":"select-appointments","since":"1.96"}],"controls":[12,4,52,178,179,265,180,181,33,174,9,2,177],"controlCount":13}, - {"class":"z2ui5_cl_smpc_app_110","description":"Shell Bar example showing the control title as part of a mega menu, configurable by the app developer.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[302,258,167,168,2],"controlCount":6}, + {"class":"z2ui5_cl_smpc_app_110","description":"Shell Bar example showing the control title as part of a mega menu, configurable by the app developer.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[318,258,167,168,2],"controlCount":6}, {"class":"z2ui5_cl_smpc_app_111","description":"","minUi5":"1.71","needs":[],"controls":[50,51,19,12,46,90,20,21,9,2],"controlCount":11}, {"class":"z2ui5_cl_smpc_app_112","description":"Basic example of Color Picker. Note that you have to set the Color Picker mode to HSL to take advantage of the responsiveness of the control on a mobile device.","minUi5":"1.71","needs":[],"controls":[3,5,171,9,18,2,186],"controlCount":10}, {"class":"z2ui5_cl_smpc_app_113","description":"InfoLabel with all available color schemes","minUi5":"1.74","needs":[{"type":"member-too-new","name":"sap.tnt.InfoLabel.icon","since":"1.74"}],"controls":[58,75,7,251,2],"controlCount":33}, @@ -581,7 +604,7 @@ {"class":"z2ui5_cl_smpc_app_115","description":"Basic example showing most controls which are intended to be used inside a table.","minUi5":"1.71","needs":[],"controls":[3,23,29,117,45,12,13,149,83,4,5,14,7,20,150,56,15,2,188,189,190],"controlCount":48}, {"class":"z2ui5_cl_smpc_app_116","description":"This example shows subsections in expanded and collapsed mode.","minUi5":"1.71","needs":[],"controls":[12,7,2,26,214,215,216,217],"controlCount":81}, {"class":"z2ui5_cl_smpc_app_117","description":"This sample illustrates how to specify the predefined header and the content of the Card control.","minUi5":"1.71","needs":[],"controls":[35,39,3,29,43,117,11,1,83,7,20,9,15,2],"controlCount":21}, - {"class":"z2ui5_cl_smpc_app_118","description":"Different types of cards types arranged in a sap.f.GridContainer.","minUi5":"1.128","needs":[{"type":"control-too-new","name":"sap.f.cards.CardBadgeCustomData","since":"1.128"},{"type":"control-too-new","name":"sap.f.cards.CardBadgeCustomData","since":"1.128"},{"type":"control-too-new","name":"sap.f.cards.CardBadgeCustomData","since":"1.128"},{"type":"control-too-new","name":"sap.f.cards.CardBadgeCustomData","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.announcementText","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.announcementText","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.announcementText","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.announcementText","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.icon","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.icon","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.state","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.visibilityMode","since":"1.128"},{"type":"event-parameter-too-new","name":"sap.ui.integration.widgets.Card.parameters","since":"1.76"},{"type":"event-parameter-too-new","name":"sap.ui.integration.widgets.Card.parameters","since":"1.76"},{"type":"event-parameter-too-new","name":"sap.ui.integration.widgets.Card.parameters","since":"1.76"},{"type":"event-parameter-too-new","name":"sap.ui.integration.widgets.Card.parameters","since":"1.76"},{"type":"event-parameter-too-new","name":"sap.ui.integration.widgets.Card.parameters","since":"1.76"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[209,210,237,302,303,258,73,74,167,168,20,2,211],"controlCount":37}, + {"class":"z2ui5_cl_smpc_app_118","description":"Different types of cards types arranged in a sap.f.GridContainer.","minUi5":"1.128","needs":[{"type":"control-too-new","name":"sap.f.cards.CardBadgeCustomData","since":"1.128"},{"type":"control-too-new","name":"sap.f.cards.CardBadgeCustomData","since":"1.128"},{"type":"control-too-new","name":"sap.f.cards.CardBadgeCustomData","since":"1.128"},{"type":"control-too-new","name":"sap.f.cards.CardBadgeCustomData","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.announcementText","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.announcementText","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.announcementText","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.announcementText","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.icon","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.icon","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.state","since":"1.128"},{"type":"member-too-new","name":"sap.f.cards.CardBadgeCustomData.visibilityMode","since":"1.128"},{"type":"event-parameter-too-new","name":"sap.ui.integration.widgets.Card.parameters","since":"1.76"},{"type":"event-parameter-too-new","name":"sap.ui.integration.widgets.Card.parameters","since":"1.76"},{"type":"event-parameter-too-new","name":"sap.ui.integration.widgets.Card.parameters","since":"1.76"},{"type":"event-parameter-too-new","name":"sap.ui.integration.widgets.Card.parameters","since":"1.76"},{"type":"event-parameter-too-new","name":"sap.ui.integration.widgets.Card.parameters","since":"1.76"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[209,210,237,318,319,258,73,74,167,168,20,2,211],"controlCount":37}, {"class":"z2ui5_cl_smpc_app_119","description":"Shows a FixFlex control with a vertical layout.","minUi5":"1.71","needs":[],"controls":[55,7,24,2,191],"controlCount":5}, {"class":"z2ui5_cl_smpc_app_120","description":"With the HTML controls you can easily embed any kind of HTML content into your UI5 mobile application.","minUi5":"1.71","needs":[],"controls":[24,2,16],"controlCount":3}, {"class":"z2ui5_cl_smpc_app_121","description":"This sample shows an Upload Set control with a list of files to be uploaded and actions you can perform on them.","minUi5":"1.103","needs":[{"type":"control-too-new","name":"sap.m.upload.UploadSetToolbarPlaceholder","since":"1.103"},{"type":"member-too-new","name":"sap.m.upload.UploadSet.mode","since":"1.100"},{"type":"member-too-new","name":"sap.m.upload.UploadSet.afterItemRemoved","since":"1.83"}],"controls":[3,156,83,4,5,8,266,267,268,2],"controlCount":12}, @@ -591,15 +614,15 @@ {"class":"z2ui5_cl_smpc_app_125","description":"Simple splitter example with two content areas","minUi5":"1.71","needs":[],"controls":[40,3,2,194,195],"controlCount":7}, {"class":"z2ui5_cl_smpc_app_126","description":"Basic File Uploader Example","minUi5":"1.71","needs":[],"controls":[3,24,2,16,121],"controlCount":5}, {"class":"z2ui5_cl_smpc_app_127","description":"Many controls provide the associations ariaLabelledBy and ariaDescribedBy for accessibility purposes. The InvisibleText control can be used by application to provide hidden texts on the UI which can be referenced via these associations.","minUi5":"1.71","needs":[],"controls":[3,19,11,12,5,20,21,8,22,2],"controlCount":35}, - {"class":"z2ui5_cl_smpc_app_128","description":"SideNavigation in container with fixed width.","minUi5":"1.121","needs":[{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"icon-too-new","name":"people-connected","since":"1.96"}],"controls":[3,9,252,330,253,329,2],"controlCount":28}, + {"class":"z2ui5_cl_smpc_app_128","description":"SideNavigation in container with fixed width.","minUi5":"1.121","needs":[{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"icon-too-new","name":"people-connected","since":"1.96"}],"controls":[3,9,252,349,253,345,2],"controlCount":28}, {"class":"z2ui5_cl_smpc_app_129","description":"Formats and parses only the integer digits. The decimal digits are ignored.","minUi5":"1.71","needs":[],"controls":[45,12,7,2,26],"controlCount":14}, {"class":"z2ui5_cl_smpc_app_130","description":"A control's busy indicator can be used to block parts of the screen until an operation has finished. In this example we block the content of only one out of two panels.","minUi5":"1.71","needs":[],"controls":[3,5,46,7,21,8,56,2],"controlCount":9}, {"class":"z2ui5_cl_smpc_app_131","description":"Sample provides a link to the Theme Parameter Toolbox. There you can easily search, preview, and filter semantic theme parameters.","minUi5":"1.71","needs":[],"controls":[13,89,2,16],"controlCount":4}, - {"class":"z2ui5_cl_smpc_app_132","description":"SideNavigation with tags for status indicators and metadata.","minUi5":"1.149","needs":[{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,83,9,252,330,253,329,2],"controlCount":31}, + {"class":"z2ui5_cl_smpc_app_132","description":"SideNavigation with tags for status indicators and metadata.","minUi5":"1.149","needs":[{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,83,9,252,349,253,345,2],"controlCount":31}, {"class":"z2ui5_cl_smpc_app_133","description":"This is a sample for GridList with different modes of selection.","minUi5":"1.71","needs":[],"controls":[50,51,11,55,12,86,87,20,9,24,2,54],"controlCount":20}, - {"class":"z2ui5_cl_smpc_app_134","description":"ToolHeader that mimics the content of the Shell.","minUi5":"1.96","needs":[{"type":"icon-too-new","name":"da","since":"1.96"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,3,55,123,52,75,6,7,20,8,312,331,2],"controlCount":36}, + {"class":"z2ui5_cl_smpc_app_134","description":"ToolHeader that mimics the content of the Shell.","minUi5":"1.96","needs":[{"type":"icon-too-new","name":"da","since":"1.96"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,3,55,123,52,75,6,7,20,8,328,350,2],"controlCount":36}, {"class":"z2ui5_cl_smpc_app_135","description":"Formats the number by using the parameters defined for the given currency code. Either currency symbol, currency code or none of them can be included in the final formatted string. It parses the given string into an array which contains both the currency number and currency code.","minUi5":"1.71","needs":[],"controls":[45,12,7,2,26],"controlCount":18}, - {"class":"z2ui5_cl_smpc_app_136","description":"Demonstrates the usage of Side Panel with single action item.","minUi5":"1.107","needs":[{"type":"control-too-new","name":"sap.f.SidePanel","since":"1.107"},{"type":"aggregation-too-new","name":"sap.f.SidePanel.items","since":"1.107"},{"type":"aggregation-too-new","name":"sap.f.SidePanel.mainContent","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanel.toggle","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"}],"controls":[320,321,3,12,5,53,7,9,2],"controlCount":26}, + {"class":"z2ui5_cl_smpc_app_136","description":"Demonstrates the usage of Side Panel with single action item.","minUi5":"1.107","needs":[{"type":"control-too-new","name":"sap.f.SidePanel","since":"1.107"},{"type":"aggregation-too-new","name":"sap.f.SidePanel.items","since":"1.107"},{"type":"aggregation-too-new","name":"sap.f.SidePanel.mainContent","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanel.toggle","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"}],"controls":[336,337,3,12,5,53,7,9,2],"controlCount":26}, {"class":"z2ui5_cl_smpc_app_137","description":"Example for multi-header of table","minUi5":"1.71","needs":[],"controls":[45,12,4,5,7,20,2,188,189],"controlCount":27}, {"class":"z2ui5_cl_smpc_app_138","description":"Attaches side content area which is next to the main content of the page on larger screens taking different ratios between the two on different screen sizes and on phone size screens the side content area falls down under the main content area. Best viewed in full screen.","minUi5":"1.71","needs":[],"controls":[3,5,90,7,20,21,24,2,196],"controlCount":13}, {"class":"z2ui5_cl_smpc_app_139","description":"Calendar where the user can select a single day","minUi5":"1.71","needs":[],"controls":[3,12,7,24,2,61,16,182,200],"controlCount":9}, @@ -615,7 +638,7 @@ {"class":"z2ui5_cl_smpc_app_149","description":"Card Explorer is the application where you can learn more about integration cards.","minUi5":"1.71","needs":[],"controls":[55,13,9,2],"controlCount":4}, {"class":"z2ui5_cl_smpc_app_150","description":"Example how to use CodeEditor with IconTabHeader to create a tab-based experience.","minUi5":"1.71","needs":[],"controls":[74,93,187,2],"controlCount":5}, {"class":"z2ui5_cl_smpc_app_151","description":"islamic Calendar with secondary gregorian type","minUi5":"1.71","needs":[],"controls":[3,12,7,2,61,16,182],"controlCount":7}, - {"class":"z2ui5_cl_smpc_app_152","description":"Shell Bar example with a menu button and a plain title.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[302,258,2],"controlCount":3}, + {"class":"z2ui5_cl_smpc_app_152","description":"Shell Bar example with a menu button and a plain title.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[318,258,2],"controlCount":3}, {"class":"z2ui5_cl_smpc_app_153","description":"The sap.m.MaskInput control allows users to easily enter data in a certain format and in a fixed-width input (for example: date, time, credit card number, and others).","minUi5":"1.96","needs":[{"type":"member-too-new","name":"sap.m.MaskInput.showClearIcon","since":"1.96"},{"type":"member-too-new","name":"sap.m.MaskInput.showClearIcon","since":"1.96"},{"type":"member-too-new","name":"sap.m.MaskInput.showClearIcon","since":"1.96"},{"type":"member-too-new","name":"sap.m.MaskInput.showClearIcon","since":"1.96"}],"controls":[40,12,269,270,5,2,26],"controlCount":21}, {"class":"z2ui5_cl_smpc_app_154","description":"The control can be used for embedding formatted HTML text into your application.","minUi5":"1.71","needs":[],"controls":[44,9,2],"controlCount":3}, {"class":"z2ui5_cl_smpc_app_155","description":"Checkboxes allow users to select a subset of options. If you want to offer an off/on setting you should use the Switch control instead.","minUi5":"1.121","needs":[{"type":"member-too-new","name":"sap.m.CheckBox.required","since":"1.121"}],"controls":[23,12,9,2,197,26],"controlCount":26}, @@ -628,14 +651,14 @@ {"class":"z2ui5_cl_smpc_app_162","description":"The Horizontal Layout control is a simple way to align multiple controls horizontally. By default the contained controls are not wrapped. If you want more sophisticated layout options, consider Grid or Flex Box based layouts.","minUi5":"1.71","needs":[],"controls":[55,2,61],"controlCount":5}, {"class":"z2ui5_cl_smpc_app_163","description":"Toolbar items can be displayed depending on the current device.","minUi5":"1.71","needs":[],"controls":[148,3,5,7,21,8,18,2],"controlCount":21}, {"class":"z2ui5_cl_smpc_app_164","description":"Example for the different row modes","minUi5":"1.119","needs":[{"type":"member-too-new","name":"sap.ui.table.Table.rowMode","since":"1.119"}],"controls":[12,13,4,5,86,87,7,20,2,188,189],"controlCount":26}, - {"class":"z2ui5_cl_smpc_app_165","description":"This sample demonstrates the navigation behavior of Product Switch, configurable by the app developer.","minUi5":"1.72","needs":[{"type":"control-too-new","name":"sap.f.ProductSwitch","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitch.change","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitch.items","since":"1.72"},{"type":"aggregation-too-new","name":"sap.f.ProductSwitch.items","since":"1.72"},{"type":"control-too-new","name":"sap.f.ProductSwitchItem","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.src","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.subTitle","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.target","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.targetSrc","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.title","since":"1.72"}],"controls":[322,323,3,171,7,18,2,16],"controlCount":10}, + {"class":"z2ui5_cl_smpc_app_165","description":"This sample demonstrates the navigation behavior of Product Switch, configurable by the app developer.","minUi5":"1.72","needs":[{"type":"control-too-new","name":"sap.f.ProductSwitch","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitch.change","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitch.items","since":"1.72"},{"type":"aggregation-too-new","name":"sap.f.ProductSwitch.items","since":"1.72"},{"type":"control-too-new","name":"sap.f.ProductSwitchItem","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.src","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.subTitle","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.target","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.targetSrc","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.title","since":"1.72"}],"controls":[338,339,3,171,7,18,2,16],"controlCount":10}, {"class":"z2ui5_cl_smpc_app_166","description":"This sample demonstrates the use of a DraftIndicator in the footer area.","minUi5":"1.71","needs":[],"controls":[226,227,228,229,230,231,232,3,27,28,63,78,122,81,30,83,32,7,20,2,61,16,136],"controlCount":36}, - {"class":"z2ui5_cl_smpc_app_167","description":"A tool page layout with vertical navigation","minUi5":"1.133","needs":[{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[3,34,118,52,235,75,7,8,252,253,329,312,331,313,18,2],"controlCount":52}, + {"class":"z2ui5_cl_smpc_app_167","description":"A tool page layout with vertical navigation","minUi5":"1.133","needs":[{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[3,34,118,52,235,75,7,8,252,253,345,328,350,329,18,2],"controlCount":52}, {"class":"z2ui5_cl_smpc_app_168","description":"This sample represents the general usage of GridContainer.","minUi5":"1.71","needs":[],"controls":[35,209,210,237,39,3,29,43,117,104,11,94,12,1,71,83,46,75,53,7,72,20,33,9,15,2,211],"controlCount":73}, {"class":"z2ui5_cl_smpc_app_169","description":"Take advantage of sap.ui.layout.GridData to control the appearance of individual Grid children.","minUi5":"1.71","needs":[],"controls":[44,89,90,20,24,2,77,197,16],"controlCount":76}, {"class":"z2ui5_cl_smpc_app_170","description":"Dynamic Page freestyle example with a responsive sap.m.Table in the content area, showing that each control can be placed in the title and the header content areas.","minUi5":"1.71","needs":[],"controls":[35,36,37,38,233,234,10,3,27,28,173,12,13,81,30,31,83,4,52,235,32,7,20,21,8,18,2,61,16],"controlCount":61}, {"class":"z2ui5_cl_smpc_app_171","description":"Display Currencies in Table","minUi5":"1.71","needs":[],"controls":[27,28,30,31,32,7,2,190],"controlCount":15}, - {"class":"z2ui5_cl_smpc_app_172","description":"SideNavigation with unselectable parent items.","minUi5":"1.116","needs":[{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,9,252,253,329,2],"controlCount":19}, + {"class":"z2ui5_cl_smpc_app_172","description":"SideNavigation with unselectable parent items.","minUi5":"1.116","needs":[{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,9,252,253,345,2],"controlCount":19}, {"class":"z2ui5_cl_smpc_app_173","description":"The Vertical Layout control is a simple way to align multiple controls vertically. If you want more sophisticated layout options, consider Grid or Flex Box based layouts.","minUi5":"1.71","needs":[],"controls":[55,2,16],"controlCount":5}, {"class":"z2ui5_cl_smpc_app_174","description":"Shows how row highlights and alternating row colors can be used.","minUi5":"1.71","needs":[],"controls":[12,4,5,14,7,20,33,8,15,2,188,198,189,190],"controlCount":29}, {"class":"z2ui5_cl_smpc_app_175","description":"A SimpleForm that uses Toolbars as Form header and FormContainer headers.","minUi5":"1.71","needs":[],"controls":[3,45,12,14,20,21,8,9,15,2,197,26],"controlCount":35}, @@ -681,17 +704,17 @@ {"class":"z2ui5_cl_smpc_app_215","description":"Shows a FixFlex control where the minFlexSize is set to 400px.","minUi5":"1.71","needs":[],"controls":[27,28,81,82,30,156,31,83,4,32,7,20,2,191],"controlCount":26}, {"class":"z2ui5_cl_smpc_app_216","description":"This is an example of an ObjectPageHeaderContent.","minUi5":"1.71","needs":[],"controls":[3,12,81,31,83,205,7,150,219,2,16,220,221],"controlCount":32}, {"class":"z2ui5_cl_smpc_app_217","description":"This is an example of an ObjectPageHeader containing mainly KPIs.","minUi5":"1.71","needs":[],"controls":[12,81,31,7,107,2,16,26,214,222,215,216,217],"controlCount":56}, - {"class":"z2ui5_cl_smpc_app_218","description":"Shell Bar example with configured search functionality.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[324,302,258,167,168,166,2],"controlCount":8}, + {"class":"z2ui5_cl_smpc_app_218","description":"Shell Bar example with configured search functionality.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[340,318,258,167,168,166,2],"controlCount":8}, {"class":"z2ui5_cl_smpc_app_219","description":"Shows a FixFlex control with a horizontal layout.","minUi5":"1.71","needs":[],"controls":[55,7,24,2,191],"controlCount":5}, {"class":"z2ui5_cl_smpc_app_220","description":"Calendar with minimum date 2000-01-01 and maximum date 2050-12-31, some disabled days (in January 2016) and ability to show or hide week numbers.","minUi5":"1.71","needs":[],"controls":[58,12,53,7,24,2,61,16,182,200],"controlCount":12}, - {"class":"z2ui5_cl_smpc_app_221","description":"ToolHeader can contain IconTabHeader. When both controls are combined, the IconTabHeader supports only inline text. No icons can be used.","minUi5":"1.121","needs":[{"type":"member-too-new","name":"sap.m.IconTabFilter.interactionMode","since":"1.121"},{"type":"member-too-new","name":"sap.m.IconTabFilter.interactionMode","since":"1.121"},{"type":"member-too-new","name":"sap.m.IconTabFilter.interactionMode","since":"1.121"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"}],"controls":[3,74,93,167,255,168,52,7,312,2],"controlCount":78}, - {"class":"z2ui5_cl_smpc_app_222","description":"This layout displays a variable number of grid columns depending on available screen size. Grid row's height is dynamically determined by the height of the highest grid element on this row.","minUi5":"1.72","needs":[{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnLayout","since":"1.72"}],"controls":[50,51,12,46,90,20,33,21,9,2,310,311],"controlCount":41}, + {"class":"z2ui5_cl_smpc_app_221","description":"ToolHeader can contain IconTabHeader. When both controls are combined, the IconTabHeader supports only inline text. No icons can be used.","minUi5":"1.121","needs":[{"type":"member-too-new","name":"sap.m.IconTabFilter.interactionMode","since":"1.121"},{"type":"member-too-new","name":"sap.m.IconTabFilter.interactionMode","since":"1.121"},{"type":"member-too-new","name":"sap.m.IconTabFilter.interactionMode","since":"1.121"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"}],"controls":[3,74,93,167,255,168,52,7,328,2],"controlCount":78}, + {"class":"z2ui5_cl_smpc_app_222","description":"This layout displays a variable number of grid columns depending on available screen size. Grid row's height is dynamically determined by the height of the highest grid element on this row.","minUi5":"1.72","needs":[{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnLayout","since":"1.72"}],"controls":[50,51,12,46,90,20,33,21,9,2,326,327],"controlCount":41}, {"class":"z2ui5_cl_smpc_app_223","description":"The BlockLayout Cells can have links as titles. The link text overwrites the title text.","minUi5":"1.71","needs":[],"controls":[12,13,89,86,87,90,7,2,47,48,49,16,26],"controlCount":33}, {"class":"z2ui5_cl_smpc_app_224","description":"'Single selection' forces the user to choose exactly one out of many items. With the 'multi' selection the user can pick multiple items at the same time. This is helpful for e.g. batch processing. With 'includeItem' the selection is also changed when pressing the item.","minUi5":"1.71","needs":[],"controls":[1,4,14,76,20,8,15,2],"controlCount":12}, {"class":"z2ui5_cl_smpc_app_225","description":"This example demonstrates the Strict layout and the column resizing of the table.","minUi5":"1.91","needs":[{"type":"control-too-new","name":"sap.m.plugins.ColumnResizer","since":"1.91"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[27,28,30,31,32,7,272,2],"controlCount":19}, {"class":"z2ui5_cl_smpc_app_226","description":"The major layout features of the Grid control are shown in this example. Features like indentation, making content visible/invisible based on the screen size, moving content forward and backwards are demonstrated.","minUi5":"1.71","needs":[],"controls":[55,7,20,2,77,197,16],"controlCount":24}, - {"class":"z2ui5_cl_smpc_app_227","description":"Menu with Item Eventing","minUi5":"1.84","needs":[{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[3,2,61,304,305,306],"controlCount":14}, - {"class":"z2ui5_cl_smpc_app_228","description":"Menu with Menu Eventing","minUi5":"1.84","needs":[{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[3,2,61,304,305,306],"controlCount":14}, + {"class":"z2ui5_cl_smpc_app_227","description":"Menu with Item Eventing","minUi5":"1.84","needs":[{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[3,2,61,320,321,322],"controlCount":14}, + {"class":"z2ui5_cl_smpc_app_228","description":"Menu with Menu Eventing","minUi5":"1.84","needs":[{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[3,2,61,320,321,322],"controlCount":14}, {"class":"z2ui5_cl_smpc_app_229","description":"The Popover controls allows to show contextual information without leaving the current page. Press somewhere outside the popover to close it.","minUi5":"1.84","needs":[{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"},{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[3,55,4,235,8,18,2,16],"controlCount":16}, {"class":"z2ui5_cl_smpc_app_230","description":"Use of dynamic bound model mapping","minUi5":"1.71","needs":[],"controls":[7,107,2,26],"controlCount":5}, {"class":"z2ui5_cl_smpc_app_232","description":"This example demonstrates how to define shortcuts using commands in your application","minUi5":"1.84","needs":[{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"},{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[40,3,29,45,12,5,46,235,14,53,21,8,15,2],"controlCount":47}, @@ -702,8 +725,8 @@ {"class":"z2ui5_cl_smpc_app_237","description":"The ObjectMarker is a small building block representing an object by an icon or text and icon. Often it is used in a table.","minUi5":"1.71","needs":[],"controls":[27,28,30,156,32,7,2],"controlCount":12}, {"class":"z2ui5_cl_smpc_app_238","description":"Dynamic Page containing an sap.m.IconTabBar in the sticky subheader content area.","minUi5":"1.71","needs":[],"controls":[35,36,37,38,233,234,10,3,27,28,173,73,74,12,13,81,30,31,83,4,235,32,7,20,21,8,18,2,61,16],"controlCount":67}, {"class":"z2ui5_cl_smpc_app_239","description":"This example demonstrates ObjectPage with ObjectPageHeaderActionButtons and a GenericTag in the header.","minUi5":"1.71","needs":[],"controls":[10,173,12,13,81,83,7,20,24,2,61,16,26,218,222,215,216,217],"controlCount":105}, - {"class":"z2ui5_cl_smpc_app_240","description":"An example of adding navigatable legend to the calendar.","minUi5":"1.71","needs":[],"controls":[24,2,16,182,307,292,290],"controlCount":7}, - {"class":"z2ui5_cl_smpc_app_241","description":"SideNavigation with press event parameters and preventDefault.","minUi5":"1.137","needs":[{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.altKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.altKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.altKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.ctrlKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.ctrlKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.ctrlKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.metaKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.metaKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.metaKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.shiftKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.shiftKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.shiftKey","since":"1.137"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,23,34,11,45,12,9,252,253,329,18,2],"controlCount":20}, + {"class":"z2ui5_cl_smpc_app_240","description":"An example of adding navigatable legend to the calendar.","minUi5":"1.71","needs":[],"controls":[24,2,16,182,323,292,290],"controlCount":7}, + {"class":"z2ui5_cl_smpc_app_241","description":"SideNavigation with press event parameters and preventDefault.","minUi5":"1.137","needs":[{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.altKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.altKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.altKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.ctrlKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.ctrlKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.ctrlKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.metaKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.metaKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.metaKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.shiftKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.shiftKey","since":"1.137"},{"type":"event-parameter-too-new","name":"sap.tnt.NavigationListItem.shiftKey","since":"1.137"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,23,34,11,45,12,9,252,253,345,18,2],"controlCount":20}, {"class":"z2ui5_cl_smpc_app_242","description":"The Nav Container stacks multiple pages and offers an API to switch between them with some animation. Typically application developers would use the App control which inherits from NavContainer.","minUi5":"1.111","needs":[{"type":"member-too-new","name":"sap.m.NavContainer.navigationFinished","since":"1.111"}],"controls":[3,19,11,118,4,5,14,9,256,24,15,2],"controlCount":39}, {"class":"z2ui5_cl_smpc_app_243","description":"The Responsive Popover is an abstraction of Popover and Dialog. On the phone a Dialog will be shown. On tablet and desktop a Popover is shown.","minUi5":"1.129","needs":[{"type":"aggregation-too-new","name":"sap.m.ResponsivePopover.footer","since":"1.129"},{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"},{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[3,55,4,171,8,18,2,16],"controlCount":16}, {"class":"z2ui5_cl_smpc_app_244","description":"Dynamic Page demonstrating the breakpointChange event to adjust Avatar sizes responsively based on breakpoints.","minUi5":"1.147","needs":[{"type":"member-too-new","name":"sap.f.DynamicPage.breakpointChange","since":"1.147"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[36,37,38,258,10,3,58,11,12,13,89,156,4,123,52,7,20,8,9,2,16],"controlCount":59}, @@ -730,7 +753,7 @@ {"class":"z2ui5_cl_smpc_app_265","description":"This sample shows how bound filters work. It features a table of customers with a 'Select' control in each row. The 'Select' control uses the customer's region to filter the list of available account managers.","minUi5":"1.71","needs":[],"controls":[12,14,7,20,15,2,188,189],"controlCount":13}, {"class":"z2ui5_cl_smpc_app_266","description":"Nested Splitter example with 7 content areas","minUi5":"1.71","needs":[],"controls":[40,3,2,194,195],"controlCount":24}, {"class":"z2ui5_cl_smpc_app_267","description":"The side content and the main content take 50%/50% of the container on all screen sizes except on phone screens where there is a button implemented to toggle between each other.","minUi5":"1.71","needs":[],"controls":[3,55,5,90,7,20,21,9,24,2,196],"controlCount":16}, - {"class":"z2ui5_cl_smpc_app_268","description":"Example of ColorPicker in a popover using the thin wrapper control sap.ui.unified.ColorPickerPopover.","minUi5":"1.85","needs":[{"type":"member-too-new","name":"sap.ui.unified.ColorPickerPopover.liveChange","since":"1.85"}],"controls":[27,28,45,12,32,7,2,308],"controlCount":25}, + {"class":"z2ui5_cl_smpc_app_268","description":"Example of ColorPicker in a popover using the thin wrapper control sap.ui.unified.ColorPickerPopover.","minUi5":"1.85","needs":[{"type":"member-too-new","name":"sap.ui.unified.ColorPickerPopover.liveChange","since":"1.85"}],"controls":[27,28,45,12,32,7,2,324],"controlCount":25}, {"class":"z2ui5_cl_smpc_app_269","description":"Product page with comments example.","minUi5":"1.71","needs":[],"controls":[3,68,69,55,1,5,90,7,20,21,8,9,24,2,196,16],"controlCount":22}, {"class":"z2ui5_cl_smpc_app_270","description":"CSSGrid example nested grids.","minUi5":"1.71","needs":[],"controls":[4,46,90,7,20,9,24,2,192,193],"controlCount":30}, {"class":"z2ui5_cl_smpc_app_271","description":"Example of setting customLayout for different layout (screen) sizes.","minUi5":"1.71","needs":[],"controls":[11,4,46,86,87,90,7,20,33,9,24,2,192,203,204],"controlCount":43}, @@ -761,19 +784,19 @@ {"class":"z2ui5_cl_smpc_app_296","description":"You can filter the items in the filter details page using different string filter operators.","minUi5":"1.71","needs":[],"controls":[3,114,115,116,2,16],"controlCount":12}, {"class":"z2ui5_cl_smpc_app_297","description":"You can have custom tabs with your own defined content in the View Settings Dialog, as shown in this example.","minUi5":"1.132","needs":[{"type":"member-too-new","name":"sap.m.ViewSettingsDialog.beforeClose","since":"1.132"}],"controls":[3,117,12,46,86,87,276,114,115,116,24,2,16],"controlCount":59}, {"class":"z2ui5_cl_smpc_app_298","description":"The View Settings Dialog is standard UI pattern for specifying sorting, grouping and filtering. For a table it should be triggered by a button in the table header with the 'drop-down-list' icon. The active filter should be shown with the table's info bar. This example also shows the context menu for the items in the Table control.","minUi5":"1.137","needs":[{"type":"control-too-new","name":"sap.m.table.columnmenu.QuickResize","since":"1.137"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickResize.change","since":"1.137"},{"type":"control-too-new","name":"sap.m.table.columnmenu.ActionItem","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.ActionItem.label","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.ActionItem.press","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.Menu","since":"1.110"},{"type":"aggregation-too-new","name":"sap.m.table.columnmenu.Menu.items","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.QuickSort","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickSort.change","since":"1.110"},{"type":"aggregation-too-new","name":"sap.m.table.columnmenu.QuickSort.items","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.QuickSortItem","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickSortItem.key","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickSortItem.label","since":"1.110"},{"type":"member-too-new","name":"sap.m.Column.headerMenu","since":"1.98"}],"controls":[3,27,28,30,31,4,5,32,7,20,33,8,114,115,116,277,278,279,280,281,2],"controlCount":50}, - {"class":"z2ui5_cl_smpc_app_299","description":"SideNavigation with a quick create action button.","minUi5":"1.133","needs":[{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,34,45,12,9,252,253,329,18,2],"controlCount":17}, - {"class":"z2ui5_cl_smpc_app_300","description":"SideNavigation with long texts that wrap.","minUi5":"1.133","needs":[{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.SideNavigation.width","since":"1.120"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,34,45,12,9,252,330,253,329,18,2],"controlCount":40}, - {"class":"z2ui5_cl_smpc_app_301","description":"SideNavigation in a responsive popover.","minUi5":"1.134","needs":[{"type":"member-too-new","name":"sap.tnt.SideNavigation.design","since":"1.134"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.expanded","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.SideNavigation.width","since":"1.120"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[302,40,258,3,34,118,171,75,7,9,252,330,253,329,313,18,22,2],"controlCount":75}, - {"class":"z2ui5_cl_smpc_app_302","description":"A tool page layout with horizontal navigation (on desktop and tablet) and vertical navigation (on phone)","minUi5":"1.121","needs":[{"type":"member-too-new","name":"sap.m.IconTabFilter.interactionMode","since":"1.121"},{"type":"aggregation-too-new","name":"sap.tnt.ToolPage.subHeader","since":"1.93"},{"type":"member-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,3,74,93,55,118,123,52,75,6,7,20,174,8,252,253,329,312,331,313,2],"controlCount":51}, - {"class":"z2ui5_cl_smpc_app_303","description":"A tool page layout with horizontal navigation","minUi5":"1.121","needs":[{"type":"member-too-new","name":"sap.m.IconTabFilter.interactionMode","since":"1.121"},{"type":"aggregation-too-new","name":"sap.tnt.ToolPage.subHeader","since":"1.93"},{"type":"member-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,3,74,93,55,118,123,52,75,6,7,20,174,8,312,331,313,2],"controlCount":45}, + {"class":"z2ui5_cl_smpc_app_299","description":"SideNavigation with a quick create action button.","minUi5":"1.133","needs":[{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,34,45,12,9,252,253,345,18,2],"controlCount":17}, + {"class":"z2ui5_cl_smpc_app_300","description":"SideNavigation with long texts that wrap.","minUi5":"1.133","needs":[{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.SideNavigation.width","since":"1.120"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,34,45,12,9,252,349,253,345,18,2],"controlCount":40}, + {"class":"z2ui5_cl_smpc_app_301","description":"SideNavigation in a responsive popover.","minUi5":"1.134","needs":[{"type":"member-too-new","name":"sap.tnt.SideNavigation.design","since":"1.134"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.expanded","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.SideNavigation.width","since":"1.120"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[318,40,258,3,34,118,171,75,7,9,252,349,253,345,329,18,22,2],"controlCount":75}, + {"class":"z2ui5_cl_smpc_app_302","description":"A tool page layout with horizontal navigation (on desktop and tablet) and vertical navigation (on phone)","minUi5":"1.121","needs":[{"type":"member-too-new","name":"sap.m.IconTabFilter.interactionMode","since":"1.121"},{"type":"aggregation-too-new","name":"sap.tnt.ToolPage.subHeader","since":"1.93"},{"type":"member-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,3,74,93,55,118,123,52,75,6,7,20,174,8,252,253,345,328,350,329,2],"controlCount":51}, + {"class":"z2ui5_cl_smpc_app_303","description":"A tool page layout with horizontal navigation","minUi5":"1.121","needs":[{"type":"member-too-new","name":"sap.m.IconTabFilter.interactionMode","since":"1.121"},{"type":"aggregation-too-new","name":"sap.tnt.ToolPage.subHeader","since":"1.93"},{"type":"member-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"aggregation-too-new","name":"sap.m.IconTabFilter.items","since":"1.77"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,3,74,93,55,118,123,52,75,6,7,20,174,8,328,350,329,2],"controlCount":45}, {"class":"z2ui5_cl_smpc_app_304","description":"Calendar with more than one month","minUi5":"1.71","needs":[],"controls":[3,12,7,2,61,16,182,200],"controlCount":8}, {"class":"z2ui5_cl_smpc_app_305","description":"An example of recommended implementation of deselection logic when the calendar is in single selection mode.","minUi5":"1.95","needs":[{"type":"member-too-new","name":"sap.ui.unified.Calendar.showCurrentDateButton","since":"1.95"}],"controls":[12,7,24,2,61,16,182],"controlCount":7}, {"class":"z2ui5_cl_smpc_app_306","description":"Calendar where the user can select an interval or entire week (either by selecting its week number or by using SHIFT + Space).","minUi5":"1.71","needs":[],"controls":[12,7,24,2,61,16,182],"controlCount":10}, {"class":"z2ui5_cl_smpc_app_307","description":"Calendar where the user can select multiple days, entire weeks (either by selecting its week number or by using SHIFT + Space) and ranges (using SHIFT + ENTER/Left mouse click).","minUi5":"1.71","needs":[],"controls":[3,1,76,24,2,16,182],"controlCount":7}, - {"class":"z2ui5_cl_smpc_app_308","description":"Calendar with special days and legend","minUi5":"1.81","needs":[{"type":"member-too-new","name":"sap.ui.unified.DateTypeRange.secondaryType","since":"1.81"},{"type":"member-too-new","name":"sap.ui.unified.DateTypeRange.secondaryType","since":"1.81"},{"type":"member-too-new","name":"sap.ui.unified.DateTypeRange.color","since":"1.76"},{"type":"member-too-new","name":"sap.ui.unified.DateTypeRange.color","since":"1.76"}],"controls":[33,24,2,16,182,307,292,290],"controlCount":12}, + {"class":"z2ui5_cl_smpc_app_308","description":"Calendar with special days and legend","minUi5":"1.81","needs":[{"type":"member-too-new","name":"sap.ui.unified.DateTypeRange.secondaryType","since":"1.81"},{"type":"member-too-new","name":"sap.ui.unified.DateTypeRange.secondaryType","since":"1.81"},{"type":"member-too-new","name":"sap.ui.unified.DateTypeRange.color","since":"1.76"},{"type":"member-too-new","name":"sap.ui.unified.DateTypeRange.color","since":"1.76"}],"controls":[33,24,2,16,182,323,292,290],"controlCount":12}, {"class":"z2ui5_cl_smpc_app_309","description":"Basic example of Color Picker. Note that you have to set the Color Picker mode to HSL to take advantage of the responsiveness of the control on a mobile device.","minUi5":"1.71","needs":[],"controls":[3,5,171,9,18,2,186],"controlCount":10}, {"class":"z2ui5_cl_smpc_app_310","description":"Basic example of Color Picker. Note that you have to set the Color Picker mode to HSL to take advantage of the responsiveness of the control on a mobile device.","minUi5":"1.71","needs":[],"controls":[3,5,171,9,18,2,186],"controlCount":10}, - {"class":"z2ui5_cl_smpc_app_311","description":"Some menu items can be added to groups to allow single or multiple item selection.","minUi5":"1.127","needs":[{"type":"member-too-new","name":"sap.ui.unified.MenuItem.selected","since":"1.127"},{"type":"member-too-new","name":"sap.ui.unified.MenuItem.selected","since":"1.127"},{"type":"member-too-new","name":"sap.ui.unified.MenuItem.selected","since":"1.127"},{"type":"control-too-new","name":"sap.ui.unified.MenuItemGroup","since":"1.127"},{"type":"control-too-new","name":"sap.ui.unified.MenuItemGroup","since":"1.127"},{"type":"control-too-new","name":"sap.ui.unified.MenuItemGroup","since":"1.127"},{"type":"aggregation-too-new","name":"sap.ui.unified.MenuItemGroup.items","since":"1.127"},{"type":"aggregation-too-new","name":"sap.ui.unified.MenuItemGroup.items","since":"1.127"},{"type":"aggregation-too-new","name":"sap.ui.unified.MenuItemGroup.items","since":"1.127"},{"type":"member-too-new","name":"sap.ui.unified.MenuItemGroup.itemSelectionMode","since":"1.127"},{"type":"member-too-new","name":"sap.ui.unified.MenuItemGroup.itemSelectionMode","since":"1.127"},{"type":"member-too-new","name":"sap.ui.unified.MenuItemGroup.itemSelectionMode","since":"1.127"},{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[3,9,2,304,305,309],"controlCount":22}, + {"class":"z2ui5_cl_smpc_app_311","description":"Some menu items can be added to groups to allow single or multiple item selection.","minUi5":"1.127","needs":[{"type":"member-too-new","name":"sap.ui.unified.MenuItem.selected","since":"1.127"},{"type":"member-too-new","name":"sap.ui.unified.MenuItem.selected","since":"1.127"},{"type":"member-too-new","name":"sap.ui.unified.MenuItem.selected","since":"1.127"},{"type":"control-too-new","name":"sap.ui.unified.MenuItemGroup","since":"1.127"},{"type":"control-too-new","name":"sap.ui.unified.MenuItemGroup","since":"1.127"},{"type":"control-too-new","name":"sap.ui.unified.MenuItemGroup","since":"1.127"},{"type":"aggregation-too-new","name":"sap.ui.unified.MenuItemGroup.items","since":"1.127"},{"type":"aggregation-too-new","name":"sap.ui.unified.MenuItemGroup.items","since":"1.127"},{"type":"aggregation-too-new","name":"sap.ui.unified.MenuItemGroup.items","since":"1.127"},{"type":"member-too-new","name":"sap.ui.unified.MenuItemGroup.itemSelectionMode","since":"1.127"},{"type":"member-too-new","name":"sap.ui.unified.MenuItemGroup.itemSelectionMode","since":"1.127"},{"type":"member-too-new","name":"sap.ui.unified.MenuItemGroup.itemSelectionMode","since":"1.127"},{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[3,9,2,320,321,325],"controlCount":22}, {"class":"z2ui5_cl_smpc_app_312","description":"Form with one single group in a fullscreen app with a label field ratio of 3:5:4 in all sizes besides size S (12:12:0).","minUi5":"1.71","needs":[],"controls":[102,3,45,5,14,7,9,15,107,2,197,152,153,154,155],"controlCount":39}, {"class":"z2ui5_cl_smpc_app_313","description":"Form with one single group in a fullscreen app for long labels and fields, so some more space is available on medium screens (4:7:0). To avoid heavily stretched forms on extra large screens, the form gets a two-column layout in this size (4:7:0).","minUi5":"1.71","needs":[],"controls":[102,3,45,5,14,7,9,15,107,2,197,152,153,154,155],"controlCount":39}, {"class":"z2ui5_cl_smpc_app_314","description":"Form with two groups with long labels and fields in a fullscreen app.","minUi5":"1.71","needs":[],"controls":[102,3,45,5,14,7,9,15,107,2,197,152,153,154,155],"controlCount":49}, @@ -810,22 +833,22 @@ {"class":"z2ui5_cl_smpc_app_345","description":"You can see how the different properties of the sap.ui.layout.Grid affect it's final appearance.","minUi5":"1.71","needs":[],"controls":[44,89,90,20,24,2,77,16],"controlCount":114}, {"class":"z2ui5_cl_smpc_app_346","description":"Example of setting gridAutoRows and gridAutoColumns properties.","minUi5":"1.71","needs":[],"controls":[12,4,46,7,20,33,21,9,24,2,192,26],"controlCount":76}, {"class":"z2ui5_cl_smpc_app_347","description":"Example of setting the gridGap property and using of Layout Data.","minUi5":"1.71","needs":[],"controls":[45,12,4,46,90,7,20,9,24,2,192,193,26],"controlCount":37}, - {"class":"z2ui5_cl_smpc_app_348","description":"Example of using ResponsiveColumnLayout.","minUi5":"1.72","needs":[{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnLayout","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnLayout.layoutChange","since":"1.72"}],"controls":[35,12,46,90,7,20,33,21,9,2,192,310,311],"controlCount":80}, + {"class":"z2ui5_cl_smpc_app_348","description":"Example of using ResponsiveColumnLayout.","minUi5":"1.72","needs":[{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.rows","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnLayout","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnLayout.layoutChange","since":"1.72"}],"controls":[35,12,46,90,7,20,33,21,9,2,192,326,327],"controlCount":80}, {"class":"z2ui5_cl_smpc_app_349","description":"Example of setting gridTemplateRows and gridTemplateColumns properties.","minUi5":"1.71","needs":[],"controls":[29,12,4,46,90,7,20,9,24,15,2,192,26],"controlCount":49}, - {"class":"z2ui5_cl_smpc_app_350","description":"Example of using several grids nested in one main grid with ResponsiveColumnLayout, in order to achieve responsive home page design.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnLayout","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnLayout.layoutChange","since":"1.72"}],"controls":[35,209,210,237,39,258,3,11,55,13,1,71,75,76,7,20,33,8,9,312,313,2,211,192,310,311],"controlCount":102}, + {"class":"z2ui5_cl_smpc_app_350","description":"Example of using several grids nested in one main grid with ResponsiveColumnLayout, in order to achieve responsive home page design.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnItemLayoutData.columns","since":"1.72"},{"type":"control-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnLayout","since":"1.72"},{"type":"member-too-new","name":"sap.ui.layout.cssgrid.ResponsiveColumnLayout.layoutChange","since":"1.72"}],"controls":[35,209,210,237,39,258,3,11,55,13,1,71,75,76,7,20,33,8,9,328,329,2,211,192,326,327],"controlCount":102}, {"class":"z2ui5_cl_smpc_app_351","description":"Splitter where you can change contentAreas and their sizes live","minUi5":"1.71","needs":[],"controls":[40,3,23,11,45,5,7,24,2,61,194,195,16],"controlCount":22}, {"class":"z2ui5_cl_smpc_app_352","description":"Example which shows the different aggregations of the table","minUi5":"1.71","needs":[],"controls":[64,65,66,11,12,13,83,4,5,6,7,20,8,56,2,188,189,190],"controlCount":30}, - {"class":"z2ui5_cl_smpc_app_353","description":"Shows various drag-and-drop capabilities along with custom context menu alternatives for each action.","minUi5":"1.121","needs":[{"type":"control-too-new","name":"sap.m.plugins.ContextMenuSetting","since":"1.121"},{"type":"control-too-new","name":"sap.m.plugins.ContextMenuSetting","since":"1.121"},{"type":"member-too-new","name":"sap.m.plugins.ContextMenuSetting.scope","since":"1.121"},{"type":"member-too-new","name":"sap.m.plugins.ContextMenuSetting.scope","since":"1.121"}],"controls":[3,11,167,168,4,5,7,20,8,9,314,183,184,185,2,188,189],"controlCount":46}, + {"class":"z2ui5_cl_smpc_app_353","description":"Shows various drag-and-drop capabilities along with custom context menu alternatives for each action.","minUi5":"1.121","needs":[{"type":"control-too-new","name":"sap.m.plugins.ContextMenuSetting","since":"1.121"},{"type":"control-too-new","name":"sap.m.plugins.ContextMenuSetting","since":"1.121"},{"type":"member-too-new","name":"sap.m.plugins.ContextMenuSetting.scope","since":"1.121"},{"type":"member-too-new","name":"sap.m.plugins.ContextMenuSetting.scope","since":"1.121"}],"controls":[3,11,167,168,4,5,7,20,8,9,330,183,184,185,2,188,189],"controlCount":46}, {"class":"z2ui5_cl_smpc_app_354","description":"Example showing the different facets of filtering within a table","minUi5":"1.71","needs":[],"controls":[3,12,13,83,4,5,6,7,20,33,174,8,2,188,189,190],"controlCount":30}, {"class":"z2ui5_cl_smpc_app_355","description":"Example which focuses the handling of the table related Menus","minUi5":"1.71","needs":[],"controls":[12,13,167,168,4,5,7,20,33,8,2,188,189],"controlCount":28}, {"class":"z2ui5_cl_smpc_app_356","description":"Example showing the behavior of MultiSelectionPlugin","minUi5":"1.71","needs":[],"controls":[45,12,4,5,14,7,20,33,174,8,15,2,188,189,212,190],"controlCount":32}, {"class":"z2ui5_cl_smpc_app_357","description":"OData related example","minUi5":"1.128","needs":[{"type":"member-too-new","name":"sap.ui.table.Table.scrollThreshold","since":"1.128"}],"controls":[213,3,12,4,5,86,87,7,20,8,2,188,189,190],"controlCount":30}, {"class":"z2ui5_cl_smpc_app_358","description":"Shows an example how an OData metadata driven table creation can look like.","minUi5":"1.71","needs":[],"controls":[213,12,4,5,7,20,2,188,189,190],"controlCount":69}, - {"class":"z2ui5_cl_smpc_app_359","description":"Shows how row actions can be used.","minUi5":"1.72","needs":[{"type":"member-too-new","name":"sap.ui.table.RowSettings.navigated","since":"1.72"}],"controls":[12,4,5,14,7,20,33,8,15,2,188,315,316,198,189,190],"controlCount":29}, - {"class":"z2ui5_cl_smpc_app_360","description":"Shows cell selection, copy and paste interaction in the table.","minUi5":"1.119","needs":[{"type":"control-too-new","name":"sap.m.plugins.CellSelector","since":"1.119"},{"type":"control-too-new","name":"sap.ui.table.rowmodes.Fixed","since":"1.119"},{"type":"member-too-new","name":"sap.ui.table.rowmodes.Fixed.rowCount","since":"1.119"},{"type":"aggregation-too-new","name":"sap.ui.table.Table.rowMode","since":"1.119"},{"type":"control-too-new","name":"sap.m.plugins.CopyProvider","since":"1.110"},{"type":"member-too-new","name":"sap.m.plugins.CopyProvider.copy","since":"1.110"},{"type":"member-too-new","name":"sap.m.plugins.CopyProvider.extractData","since":"1.110"},{"type":"control-too-new","name":"sap.m.plugins.PasteProvider","since":"1.91"},{"type":"member-too-new","name":"sap.m.plugins.PasteProvider.pasteFor","since":"1.91"}],"controls":[213,3,12,4,123,5,14,7,20,8,287,288,317,15,2,188,189,212,318,190],"controlCount":34}, + {"class":"z2ui5_cl_smpc_app_359","description":"Shows how row actions can be used.","minUi5":"1.72","needs":[{"type":"member-too-new","name":"sap.ui.table.RowSettings.navigated","since":"1.72"}],"controls":[12,4,5,14,7,20,33,8,15,2,188,331,332,198,189,190],"controlCount":29}, + {"class":"z2ui5_cl_smpc_app_360","description":"Shows cell selection, copy and paste interaction in the table.","minUi5":"1.119","needs":[{"type":"control-too-new","name":"sap.m.plugins.CellSelector","since":"1.119"},{"type":"control-too-new","name":"sap.ui.table.rowmodes.Fixed","since":"1.119"},{"type":"member-too-new","name":"sap.ui.table.rowmodes.Fixed.rowCount","since":"1.119"},{"type":"aggregation-too-new","name":"sap.ui.table.Table.rowMode","since":"1.119"},{"type":"control-too-new","name":"sap.m.plugins.CopyProvider","since":"1.110"},{"type":"member-too-new","name":"sap.m.plugins.CopyProvider.copy","since":"1.110"},{"type":"member-too-new","name":"sap.m.plugins.CopyProvider.extractData","since":"1.110"},{"type":"control-too-new","name":"sap.m.plugins.PasteProvider","since":"1.91"},{"type":"member-too-new","name":"sap.m.plugins.PasteProvider.pasteFor","since":"1.91"}],"controls":[213,3,12,4,123,5,14,7,20,8,287,288,333,15,2,188,189,212,334,190],"controlCount":34}, {"class":"z2ui5_cl_smpc_app_361","description":"Selection example showing selection modes and selection behaviors of table.","minUi5":"1.71","needs":[],"controls":[3,23,29,117,45,12,13,83,4,5,14,53,7,20,8,56,15,2,188,189,190],"controlCount":54}, {"class":"z2ui5_cl_smpc_app_362","description":"Example showing the different kinds of sorting capabilities","minUi5":"1.71","needs":[],"controls":[3,12,13,4,5,7,20,8,2,188,189],"controlCount":25}, - {"class":"z2ui5_cl_smpc_app_363","description":"Example which shows table freeze with fixed columns","minUi5":"1.119","needs":[{"type":"control-too-new","name":"sap.ui.table.rowmodes.Fixed","since":"1.119"},{"type":"member-too-new","name":"sap.ui.table.rowmodes.Fixed.fixedBottomRowCount","since":"1.119"},{"type":"member-too-new","name":"sap.ui.table.rowmodes.Fixed.fixedTopRowCount","since":"1.119"},{"type":"aggregation-too-new","name":"sap.ui.table.Table.rowMode","since":"1.119"}],"controls":[3,23,29,117,45,12,13,83,4,5,14,7,20,8,56,15,2,188,189,318,190],"controlCount":49}, + {"class":"z2ui5_cl_smpc_app_363","description":"Example which shows table freeze with fixed columns","minUi5":"1.119","needs":[{"type":"control-too-new","name":"sap.ui.table.rowmodes.Fixed","since":"1.119"},{"type":"member-too-new","name":"sap.ui.table.rowmodes.Fixed.fixedBottomRowCount","since":"1.119"},{"type":"member-too-new","name":"sap.ui.table.rowmodes.Fixed.fixedTopRowCount","since":"1.119"},{"type":"aggregation-too-new","name":"sap.ui.table.Table.rowMode","since":"1.119"}],"controls":[3,23,29,117,45,12,13,83,4,5,14,7,20,8,56,15,2,188,189,334,190],"controlCount":49}, {"class":"z2ui5_cl_smpc_app_364","description":"Illustrates how to bind to data from an OData model without using $metadata annotations or navigation properties. Instead, treeAnnotationProperties is filled for the TreeBinding.","minUi5":"1.71","needs":[],"controls":[12,7,2,188,202],"controlCount":14}, {"class":"z2ui5_cl_smpc_app_365","description":"Shows how hierarchy maintenance can be done using drag and drop.","minUi5":"1.71","needs":[],"controls":[3,12,4,5,14,7,20,8,15,183,2,188,202,190],"controlCount":21}, {"class":"z2ui5_cl_smpc_app_366","description":"Illustrates how to bind to data from an OData model using $metadata annotations.","minUi5":"1.71","needs":[],"controls":[12,7,2,188,202],"controlCount":14}, @@ -869,7 +892,7 @@ {"class":"z2ui5_cl_smpc_app_404","description":"This example shows different TimePicker value states.","minUi5":"1.71","needs":[],"controls":[58,12,165,9,2],"controlCount":5}, {"class":"z2ui5_cl_smpc_app_405","description":"This page shows flexible sizing with a Toolbar. The upper part extends with its content, but doesn't react to viewport changes. The lower part reacts to the viewport size. The table inside takes the available space. If the minimum size of the table is reached, the page begins to scroll.","minUi5":"1.119","needs":[{"type":"aggregation-too-new","name":"sap.ui.table.AnalyticalTable.rowMode","since":"1.119"},{"type":"control-too-new","name":"sap.ui.table.rowmodes.Auto","since":"1.119"},{"type":"member-too-new","name":"sap.ui.table.rowmodes.Auto.rowContentHeight","since":"1.119"}],"controls":[3,19,12,4,5,6,86,87,7,20,8,9,107,2,26,282,283,284],"controlCount":38}, {"class":"z2ui5_cl_smpc_app_406","description":"This page shows flexible sizing with an Icon Tab Bar: The upper part extends with its content, but doesn't react to viewport changes. The Icon Tab Bar reacts to the viewport size. The table inside takes the available space. If the minimum size of the table is reached, the page begins to scroll.","minUi5":"1.119","needs":[{"type":"aggregation-too-new","name":"sap.ui.table.AnalyticalTable.rowMode","since":"1.119"},{"type":"control-too-new","name":"sap.ui.table.rowmodes.Auto","since":"1.119"},{"type":"member-too-new","name":"sap.ui.table.rowmodes.Auto.rowContentHeight","since":"1.119"}],"controls":[3,19,73,74,12,4,5,6,86,87,7,8,9,107,2,26,282,283,284],"controlCount":43}, - {"class":"z2ui5_cl_smpc_app_407","description":"SideNavigation with a search field in the filter section and filterable navigation items.","minUi5":"1.151","needs":[{"type":"member-too-new","name":"sap.tnt.NavigationList.highlightedText","since":"1.151"},{"type":"aggregation-too-new","name":"sap.tnt.SideNavigation.filterSection","since":"1.151"},{"type":"control-too-new","name":"sap.tnt.SideNavigationSearchField","since":"1.151"},{"type":"member-too-new","name":"sap.tnt.SideNavigationSearchField.ariaControls","since":"1.150"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.expanded","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.expanded","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.items","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.items","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.visible","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.visible","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,34,55,118,83,123,52,75,6,7,20,174,8,252,330,253,329,332,312,313,18,2],"controlCount":48}, + {"class":"z2ui5_cl_smpc_app_407","description":"SideNavigation with a search field in the filter section and filterable navigation items.","minUi5":"1.151","needs":[{"type":"member-too-new","name":"sap.tnt.NavigationList.highlightedText","since":"1.151"},{"type":"aggregation-too-new","name":"sap.tnt.SideNavigation.filterSection","since":"1.151"},{"type":"control-too-new","name":"sap.tnt.SideNavigationSearchField","since":"1.151"},{"type":"member-too-new","name":"sap.tnt.SideNavigationSearchField.ariaControls","since":"1.150"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"aggregation-too-new","name":"sap.tnt.NavigationListItem.tag","since":"1.149"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.ariaHasPopup","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.design","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.press","since":"1.133"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"control-too-new","name":"sap.tnt.NavigationListGroup","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.expanded","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.expanded","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.items","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.items","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.visible","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListGroup.visible","since":"1.121"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"},{"type":"member-too-new","name":"sap.tnt.NavigationListItem.selectable","since":"1.116"}],"controls":[3,34,55,118,83,123,52,75,6,7,20,174,8,252,349,253,345,351,328,329,18,2],"controlCount":48}, {"class":"z2ui5_cl_smpc_app_408","description":"This example shows the different layout of the blocks based on their ColumnLayout.","minUi5":"1.71","needs":[],"controls":[7,24,2,214,222,215,216,217],"controlCount":17}, {"class":"z2ui5_cl_smpc_app_409","description":"Uses a block in a view of another block","minUi5":"1.71","needs":[],"controls":[24,2,214,215,216,217],"controlCount":6}, {"class":"z2ui5_cl_smpc_app_410","description":"Uses of a block that is firing a dummy event","minUi5":"1.71","needs":[],"controls":[3,9,24,2,214,215,216,217],"controlCount":9}, @@ -911,8 +934,8 @@ {"class":"z2ui5_cl_smpc_app_446","description":"Subtle links should be used to indicate less important links in tables with a large number of links. In this example all columns contain links, only the first column is non-subtle.","minUi5":"1.71","needs":[],"controls":[27,28,13,30,32,7,20,21,2],"controlCount":20}, {"class":"z2ui5_cl_smpc_app_447","description":"MessageBox with the option to display detailed information.","minUi5":"1.71","needs":[],"controls":[3,2,16],"controlCount":6}, {"class":"z2ui5_cl_smpc_app_448","description":"Integration of Draft Indicator inside Semantic Page","minUi5":"1.71","needs":[],"controls":[63,45,12,78,122,82,124,128,129,130,131,2,26,136],"controlCount":14}, - {"class":"z2ui5_cl_smpc_app_449","description":"Flexible Column Layout where the first and the last columns have custom Landmark Info","minUi5":"1.95","needs":[{"type":"aggregation-too-new","name":"sap.f.FlexibleColumnLayout.landmarkInfo","since":"1.95"},{"type":"control-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.firstColumnLabel","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.lastColumnLabel","since":"1.95"}],"controls":[236,325,3,5,9,2],"controlCount":11}, - {"class":"z2ui5_cl_smpc_app_450","description":"Flexible Column Layout where the all the arrows have custom Landmark Info","minUi5":"1.95","needs":[{"type":"aggregation-too-new","name":"sap.f.FlexibleColumnLayout.landmarkInfo","since":"1.95"},{"type":"control-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.firstColumnBackArrowLabel","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.lastColumnForwardArrowLabel","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.middleColumnBackArrowLabel","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.middleColumnForwardArrowLabel","since":"1.95"}],"controls":[236,325,3,5,9,2],"controlCount":11}, + {"class":"z2ui5_cl_smpc_app_449","description":"Flexible Column Layout where the first and the last columns have custom Landmark Info","minUi5":"1.95","needs":[{"type":"aggregation-too-new","name":"sap.f.FlexibleColumnLayout.landmarkInfo","since":"1.95"},{"type":"control-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.firstColumnLabel","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.lastColumnLabel","since":"1.95"}],"controls":[236,341,3,5,9,2],"controlCount":11}, + {"class":"z2ui5_cl_smpc_app_450","description":"Flexible Column Layout where the all the arrows have custom Landmark Info","minUi5":"1.95","needs":[{"type":"aggregation-too-new","name":"sap.f.FlexibleColumnLayout.landmarkInfo","since":"1.95"},{"type":"control-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.firstColumnBackArrowLabel","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.lastColumnForwardArrowLabel","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.middleColumnBackArrowLabel","since":"1.95"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutAccessibleLandmarkInfo.middleColumnForwardArrowLabel","since":"1.95"}],"controls":[236,341,3,5,9,2],"controlCount":11}, {"class":"z2ui5_cl_smpc_app_451","description":"This example shows how you can add additional text and an Icon to the tabs in TabContainer.","minUi5":"1.71","needs":[],"controls":[108,109,7,107,2,152,153,154,155],"controlCount":15}, {"class":"z2ui5_cl_smpc_app_452","description":"Demonstrates MessageStrips with different colorSet and colorScheme properties.","minUi5":"1.143","needs":[{"type":"member-too-new","name":"sap.m.MessageStrip.colorScheme","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorScheme","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorScheme","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorScheme","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorScheme","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorScheme","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorScheme","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorScheme","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorScheme","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorScheme","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorSet","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorSet","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorSet","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorSet","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorSet","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorSet","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorSet","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorSet","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorSet","since":"1.143"},{"type":"member-too-new","name":"sap.m.MessageStrip.colorSet","since":"1.143"}],"controls":[12,89,46,14,15,2,61,16],"controlCount":19}, {"class":"z2ui5_cl_smpc_app_453","description":"This is a responsive Object Header with a Title, 2 Statuses/Attributes rendered next to the title in a fullScreenOptimized mode (fullScreenOptimized = true).","minUi5":"1.71","needs":[],"controls":[73,74,55,13,81,82,156,83,7,2,16],"controlCount":18}, @@ -1041,17 +1064,17 @@ {"class":"z2ui5_cl_smpc_app_576","description":"This is a good example of how to vertically align different elements within a Table's ColumnListItem row template.","minUi5":"1.71","needs":[],"controls":[27,28,45,30,31,4,32,7,20,2],"controlCount":17}, {"class":"z2ui5_cl_smpc_app_577","description":"FlexibleColumnLayout where the app programmatically scrolls to some item within the newly navigated column, once the column is fully resized","minUi5":"1.77","needs":[{"type":"member-too-new","name":"sap.f.FlexibleColumnLayout.restoreFocusOnBackNavigation","since":"1.77"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayout.autoFocus","since":"1.76"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayout.columnResize","since":"1.76"}],"controls":[36,37,38,236,3,12,89,81,83,7,20,2,61,16,26,218,215,216,217],"controlCount":25}, {"class":"z2ui5_cl_smpc_app_578","description":"Flexible Column Layout as an app with routing that displays different pages in the initial column. The first page is only displayed in OneColumn layout type","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[36,38,236,258,3,27,28,58,12,30,31,4,123,6,32,7,20,8,9,2,26,218,215,216,217],"controlCount":79}, - {"class":"z2ui5_cl_smpc_app_579","description":"Flexible Column Layout as an app with routing that starts with a single initial column.","minUi5":"1.128","needs":[{"type":"control-too-new","name":"sap.f.FlexibleColumnLayoutData","since":"1.128"},{"type":"aggregation-too-new","name":"sap.f.FlexibleColumnLayoutData.desktopLayoutData","since":"1.128"},{"type":"aggregation-too-new","name":"sap.f.FlexibleColumnLayoutData.tabletLayoutData","since":"1.128"},{"type":"control-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.threeColumnsBeginExpandedEndHidden","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.threeColumnsEndExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.threeColumnsMidExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.threeColumnsMidExpandedEndHidden","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.twoColumnsBeginExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.twoColumnsMidExpanded","since":"1.128"},{"type":"control-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.threeColumnsBeginExpandedEndHidden","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.threeColumnsEndExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.threeColumnsMidExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.threeColumnsMidExpandedEndHidden","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.twoColumnsBeginExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.twoColumnsMidExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayout.restoreFocusOnBackNavigation","since":"1.77"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayout.autoFocus","since":"1.76"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[36,38,236,326,327,328,258,3,27,28,58,12,13,30,31,4,123,6,32,7,20,8,9,2,26,218,215,216,217],"controlCount":78}, + {"class":"z2ui5_cl_smpc_app_579","description":"Flexible Column Layout as an app with routing that starts with a single initial column.","minUi5":"1.128","needs":[{"type":"control-too-new","name":"sap.f.FlexibleColumnLayoutData","since":"1.128"},{"type":"aggregation-too-new","name":"sap.f.FlexibleColumnLayoutData.desktopLayoutData","since":"1.128"},{"type":"aggregation-too-new","name":"sap.f.FlexibleColumnLayoutData.tabletLayoutData","since":"1.128"},{"type":"control-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.threeColumnsBeginExpandedEndHidden","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.threeColumnsEndExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.threeColumnsMidExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.threeColumnsMidExpandedEndHidden","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.twoColumnsBeginExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForDesktop.twoColumnsMidExpanded","since":"1.128"},{"type":"control-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.threeColumnsBeginExpandedEndHidden","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.threeColumnsEndExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.threeColumnsMidExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.threeColumnsMidExpandedEndHidden","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.twoColumnsBeginExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayoutDataForTablet.twoColumnsMidExpanded","since":"1.128"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayout.restoreFocusOnBackNavigation","since":"1.77"},{"type":"member-too-new","name":"sap.f.FlexibleColumnLayout.autoFocus","since":"1.76"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[36,38,236,342,343,344,258,3,27,28,58,12,13,30,31,4,123,6,32,7,20,8,9,2,26,218,215,216,217],"controlCount":78}, {"class":"z2ui5_cl_smpc_app_580","description":"Flexible Column Layout as an app with routing that starts with two initial columns.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[36,38,236,258,3,27,28,58,12,13,30,31,4,123,6,32,7,20,8,9,2,26,218,215,216,217],"controlCount":75}, {"class":"z2ui5_cl_smpc_app_581","description":"This is a sample for GridList item templates representing a typical tools page dashboard style.","minUi5":"1.71","needs":[],"controls":[50,51,3,19,11,12,83,4,46,7,20,33,21,8,9,251,56,2,224],"controlCount":88}, {"class":"z2ui5_cl_smpc_app_582","description":"This sample demonstrates the keyboard navigation between multiple grids","minUi5":"1.71","needs":[],"controls":[50,51,40,12,5,90,20,33,9,2,192,54,193,203,204],"controlCount":37}, - {"class":"z2ui5_cl_smpc_app_583","description":"Shell Bar example with enabled Product Switch, configurable by the app developer. The Product Switch control is in experimental state.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"control-too-new","name":"sap.f.ProductSwitch","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitch.change","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitch.items","since":"1.72"},{"type":"aggregation-too-new","name":"sap.f.ProductSwitch.items","since":"1.72"},{"type":"control-too-new","name":"sap.f.ProductSwitchItem","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.src","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.subTitle","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.target","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.targetSrc","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.title","since":"1.72"}],"controls":[322,323,302,258,171,18,2],"controlCount":7}, - {"class":"z2ui5_cl_smpc_app_584","description":"Example of Shell Bar in combination with Flexible Column Layout.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[36,38,236,302,258,3,27,28,58,11,12,13,167,168,30,31,4,123,5,6,32,7,20,8,9,2,26,218,215,216,217],"controlCount":81}, - {"class":"z2ui5_cl_smpc_app_585","description":"Example of Shell Bar in combination with Split App.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[324,302,258,167,168,118,75,7,252,253,329,313,2],"controlCount":24}, + {"class":"z2ui5_cl_smpc_app_583","description":"Shell Bar example with enabled Product Switch, configurable by the app developer. The Product Switch control is in experimental state.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"control-too-new","name":"sap.f.ProductSwitch","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitch.change","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitch.items","since":"1.72"},{"type":"aggregation-too-new","name":"sap.f.ProductSwitch.items","since":"1.72"},{"type":"control-too-new","name":"sap.f.ProductSwitchItem","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.src","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.subTitle","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.target","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.targetSrc","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.title","since":"1.72"}],"controls":[338,339,318,258,171,18,2],"controlCount":7}, + {"class":"z2ui5_cl_smpc_app_584","description":"Example of Shell Bar in combination with Flexible Column Layout.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[36,38,236,318,258,3,27,28,58,11,12,13,167,168,30,31,4,123,5,6,32,7,20,8,9,2,26,218,215,216,217],"controlCount":81}, + {"class":"z2ui5_cl_smpc_app_585","description":"Example of Shell Bar in combination with Split App.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"}],"controls":[340,318,258,167,168,118,75,7,252,253,345,329,2],"controlCount":24}, {"class":"z2ui5_cl_smpc_app_586","description":"AnchorBar has a different behavior based on the device","minUi5":"1.71","needs":[],"controls":[12,7,20,2,26,218,215,216,217],"controlCount":81}, {"class":"z2ui5_cl_smpc_app_587","description":"This example shows how to visualize numbers in parenthesis after the corresponding section titles in the AnchorBar","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,3,58,55,12,13,123,205,7,20,9,107,2,77,197,61,16,26,218,215,216,217],"controlCount":142}, {"class":"z2ui5_cl_smpc_app_588","description":"Object Page demonstrating how beforeNavigate event can be used to prevent default navigation behaviour","minUi5":"1.118","needs":[{"type":"member-too-new","name":"sap.uxap.ObjectPageLayout.beforeNavigate","since":"1.118"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,3,34,58,55,12,13,123,46,205,7,20,9,18,107,2,77,197,61,16,26,218,215,216,217],"controlCount":154}, - {"class":"z2ui5_cl_smpc_app_589","description":"ObjectPage sample with blocks that use different view types","minUi5":"1.127","needs":[{"type":"member-too-new","name":"sap.uxap.ObjectPageAccessibleLandmarkInfo.headerContentLabel","since":"1.127"}],"controls":[10,3,55,12,13,4,46,205,7,8,9,2,61,16,26,319,214,222,215,216,217],"controlCount":57}, + {"class":"z2ui5_cl_smpc_app_589","description":"ObjectPage sample with blocks that use different view types","minUi5":"1.127","needs":[{"type":"member-too-new","name":"sap.uxap.ObjectPageAccessibleLandmarkInfo.headerContentLabel","since":"1.127"}],"controls":[10,3,55,12,13,4,46,205,7,8,9,2,61,16,26,335,214,222,215,216,217],"controlCount":57}, {"class":"z2ui5_cl_smpc_app_590","description":"Object Page that focuses its first editable input in the currently selected section.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,10,3,58,55,45,12,13,205,14,7,20,9,15,2,61,16,207,26,218,215,216,217],"controlCount":81}, {"class":"z2ui5_cl_smpc_app_591","description":"Object Page automatically adjusts form layout to match block column layout","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,10,3,58,55,45,12,13,123,205,7,20,9,107,2,61,16,208,152,153,154,26,218,215,216,217],"controlCount":70}, {"class":"z2ui5_cl_smpc_app_592","description":"This sample showcases the lazy loading using the stashed property of the ObjectPageLazyLoader. It enables usage of lazy loading without the need to have Blocks","minUi5":"1.71","needs":[],"controls":[3,12,123,7,20,9,2,26,218,215,223,216,217],"controlCount":22}, @@ -1086,24 +1109,72 @@ {"class":"z2ui5_cl_smpc_app_621","description":"In this example assisted input is provided with table-like suggestions where several columns can display more details.","minUi5":"1.89","needs":[{"type":"member-too-new","name":"sap.m.Input.enableTableAutoPopinMode","since":"1.89"}],"controls":[27,28,45,12,2,16],"controlCount":47}, {"class":"z2ui5_cl_smpc_app_622","description":"Input checks are handled via the validation of the data binding. In this example there are two inputs that are validated (a) while the user types and (b) when the user continues the process. If the built-in validation types are not sufficient you can create your own, like the email type in this example.","minUi5":"1.71","needs":[],"controls":[3,45,12,2,16],"controlCount":7}, {"class":"z2ui5_cl_smpc_app_623","description":"This example demonstrates the different input field states, e.g. disabled, editable, with value help and value help only.","minUi5":"1.71","needs":[],"controls":[45,12,163,76,18,2,16],"controlCount":13}, - {"class":"z2ui5_cl_smpc_demo_001","description":"","minUi5":"1.71","needs":[],"controls":[247,248,229,230,40,3,27,28,68,69,58,19,11,73,74,106,12,1,81,30,31,83,5,46,205,6,333,32,7,20,21,8,9,56,2,16,26],"controlCount":77}, - {"class":"z2ui5_cl_smpc_demo_002","description":"","minUi5":"1.71","needs":[],"controls":[236,239,243,246,229,230,40,3,27,28,73,74,55,12,13,1,387,81,30,100,31,83,4,52,5,6,32,7,20,21,8,9,114,115,116,107,2,61,16,26],"controlCount":88}, + {"class":"z2ui5_cl_smpc_app_624","description":"This sample demonstrates different combinations of types, shapes, and sizes of the Avatar.","minUi5":"1.117","needs":[{"type":"member-too-new","name":"sap.m.Avatar.enabled","since":"1.117"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.customDisplaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.fallbackIcon","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.showBorder","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.showBorder","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,75,7,9,2,77],"controlCount":123}, + {"class":"z2ui5_cl_smpc_app_625","description":"This sample demonstrates toggling of Avatar Active state, when a User menu is opened/closed.","minUi5":"1.120","needs":[{"type":"member-too-new","name":"sap.m.Avatar.active","since":"1.120"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.showBorder","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Popover.titleAlignment","since":"1.72"}],"controls":[258,1,89,235,76,2],"controlCount":13}, + {"class":"z2ui5_cl_smpc_app_626","description":"This sample demonstrates different badge icon colors of the Avatar.","minUi5":"1.132","needs":[{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIconColor","since":"1.132"},{"type":"member-too-new","name":"sap.m.Avatar.badgeValueState","since":"1.116"},{"type":"member-too-new","name":"sap.m.Avatar.badgeValueState","since":"1.116"},{"type":"member-too-new","name":"sap.m.Avatar.badgeValueState","since":"1.116"},{"type":"member-too-new","name":"sap.m.Avatar.badgeValueState","since":"1.116"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"}],"controls":[258,75,7,9,2,77],"controlCount":80}, + {"class":"z2ui5_cl_smpc_app_627","description":"This sample demonstrates different badge value states of the Avatar.","minUi5":"1.116","needs":[{"type":"member-too-new","name":"sap.m.Avatar.badgeValueState","since":"1.116"},{"type":"member-too-new","name":"sap.m.Avatar.badgeValueState","since":"1.116"},{"type":"member-too-new","name":"sap.m.Avatar.badgeValueState","since":"1.116"},{"type":"member-too-new","name":"sap.m.Avatar.badgeValueState","since":"1.116"},{"type":"member-too-new","name":"sap.m.Avatar.badgeValueState","since":"1.116"},{"type":"icon-too-new","name":"information","since":"1.80"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeTooltip","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeTooltip","since":"1.77"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.imageFitType","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,75,7,9,2,77],"controlCount":18}, + {"class":"z2ui5_cl_smpc_app_628","description":"This sample demonstrates different combinations of types, shapes, and sizes of the Avatar with visual affordance.","minUi5":"1.77","needs":[{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeIcon","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeTooltip","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeTooltip","since":"1.77"},{"type":"member-too-new","name":"sap.m.Avatar.badgeTooltip","since":"1.77"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"aggregation-too-new","name":"sap.m.Avatar.detailBox","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displaySize","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.imageFitType","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,97,98,75,7,9,2,77],"controlCount":31}, + {"class":"z2ui5_cl_smpc_app_629","description":"Demonstrates the IllustratedMessage's 'enableVerticalResponsiveness' property.","minUi5":"1.104","needs":[{"type":"member-too-new","name":"sap.m.IllustratedMessage.enableVerticalResponsiveness","since":"1.104"},{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"aggregation-too-new","name":"sap.m.IllustratedMessage.additionalContent","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationType","since":"1.98"}],"controls":[3,273,9,2,159,160,161,195],"controlCount":9}, + {"class":"z2ui5_cl_smpc_app_630","description":"Shows how to import a Custom Illustration from an npm package into a UI5 application for usage with IllustratedMessage.","minUi5":"1.98","needs":[{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"aggregation-too-new","name":"sap.m.IllustratedMessage.additionalContent","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.description","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationSize","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationType","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.title","since":"1.98"}],"controls":[3,273,12,5,14,7,15,2,26],"controlCount":9}, + {"class":"z2ui5_cl_smpc_app_631","description":"IllustratedMessage as content of sap.f.Card. 'NoActivities' illustration type is being used for the Illustrated Message.","minUi5":"1.98","needs":[{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"aggregation-too-new","name":"sap.m.IllustratedMessage.additionalContent","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationType","since":"1.98"}],"controls":[35,39,3,273,2],"controlCount":5}, + {"class":"z2ui5_cl_smpc_app_632","description":"IllustratedMessage as content of sap.f.Card. 'NoEmail' illustration type is being used for the Illustrated Message.","minUi5":"1.98","needs":[{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationType","since":"1.98"}],"controls":[35,39,273,2],"controlCount":4}, + {"class":"z2ui5_cl_smpc_app_633","description":"IllustratedMessage as content of sap.m.Dialog.","minUi5":"1.98","needs":[{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationType","since":"1.98"}],"controls":[3,34,273,18,2],"controlCount":6}, + {"class":"z2ui5_cl_smpc_app_634","description":"The available illustrations are from the default ('sapIllus') illustration set.","minUi5":"1.104","needs":[{"type":"member-too-new","name":"sap.m.IllustratedMessage.enableVerticalResponsiveness","since":"1.104"},{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"aggregation-too-new","name":"sap.m.IllustratedMessage.additionalContent","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationSize","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationType","since":"1.98"}],"controls":[3,273,12,167,255,168,5,14,53,7,256,15,2,207,26],"controlCount":29}, + {"class":"z2ui5_cl_smpc_app_635","description":"The available properties of the IllustratedMessage are configurable in this sample. The available illustrations are from the 'custom' illustration set.","minUi5":"1.98","needs":[{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"aggregation-too-new","name":"sap.m.IllustratedMessage.additionalContent","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.description","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationSize","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationType","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.title","since":"1.98"}],"controls":[3,273,12,5,14,7,15,2,26],"controlCount":9}, + {"class":"z2ui5_cl_smpc_app_636","description":"The available properties of the IllustratedMessage are configurable in this sample. The available illustrations are from the 'tnt' illustration set.","minUi5":"1.98","needs":[{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"aggregation-too-new","name":"sap.m.IllustratedMessage.additionalContent","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.description","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationSize","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationType","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.title","since":"1.98"}],"controls":[3,273,12,5,14,7,15,2,207,26],"controlCount":17}, + {"class":"z2ui5_cl_smpc_app_637","description":"The available illustrations are from the default illustration set with the use of the 'src' property.","minUi5":"1.132","needs":[{"type":"member-too-new","name":"sap.m.IllustratedMessage.src","since":"1.132"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.enableVerticalResponsiveness","since":"1.104"},{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"aggregation-too-new","name":"sap.m.IllustratedMessage.additionalContent","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.description","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationSize","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.title","since":"1.98"}],"controls":[3,273,12,5,14,53,7,15,2,207,26],"controlCount":23}, + {"class":"z2ui5_cl_smpc_app_638","description":"All applications that require user sign-in should employ a mechanism for automating user sign-out. When the inactivity is about to reach that threshold, a session timeout dialog appears automatically to inform the user.","minUi5":"1.98","needs":[{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.description","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.illustrationType","since":"1.98"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.title","since":"1.98"}],"controls":[3,34,273,12,88,9,18,2],"controlCount":12}, + {"class":"z2ui5_cl_smpc_app_639","description":"The dynamic date range is a control that offers a choice of absolute and relative dates, using different offset from the current date. The list of values offered must be defined by the application.","minUi5":"1.92","needs":[{"type":"control-too-new","name":"sap.m.DynamicDateRange","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.change","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.placeholder","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.valueState","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.width","since":"1.92"}],"controls":[27,28,302,12,31,4,32,7,20,8,2,16],"controlCount":20}, + {"class":"z2ui5_cl_smpc_app_640","description":"This example shows the Dynamic Date Range control with Middle Eastern calendar week numbering.","minUi5":"1.111","needs":[{"type":"member-too-new","name":"sap.m.DynamicDateRange.calendarWeekNumbering","since":"1.111"},{"type":"control-too-new","name":"sap.m.DynamicDateRange","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.change","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.placeholder","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.valueState","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.width","since":"1.92"}],"controls":[27,28,302,12,31,4,32,7,20,8,2,16],"controlCount":20}, + {"class":"z2ui5_cl_smpc_app_641","description":"This example shows Dynamic Date Range which is opened by another control.","minUi5":"1.105","needs":[{"type":"member-too-new","name":"sap.m.DynamicDateRange.hideInput","since":"1.105"},{"type":"control-too-new","name":"sap.m.DynamicDateRange","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.change","since":"1.92"},{"type":"member-too-new","name":"sap.m.Link.ariaHasPopup","since":"1.86"},{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"},{"type":"member-too-new","name":"sap.m.Button.ariaHasPopup","since":"1.84"}],"controls":[3,302,12,13,20,9,2],"controlCount":12}, + {"class":"z2ui5_cl_smpc_app_642","description":"This example shows the Dynamic Date Range control with custom options for interval or date selection.","minUi5":"1.92","needs":[{"type":"control-too-new","name":"sap.m.DynamicDateRange","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.change","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.placeholder","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.valueState","since":"1.92"},{"type":"member-too-new","name":"sap.m.DynamicDateRange.width","since":"1.92"}],"controls":[27,28,302,12,31,4,32,7,20,8,2],"controlCount":25}, + {"class":"z2ui5_cl_smpc_app_643","description":"The ExpandableText control can be used to display a larger texts inside a table, list or form.","minUi5":"1.87","needs":[{"type":"control-too-new","name":"sap.m.ExpandableText","since":"1.87"},{"type":"member-too-new","name":"sap.m.ExpandableText.overflowMode","since":"1.87"},{"type":"member-too-new","name":"sap.m.ExpandableText.text","since":"1.87"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[27,28,303,32,7,2],"controlCount":15}, + {"class":"z2ui5_cl_smpc_app_644","description":"Dialog & Popover with a sap.m.P13nContainer as content.","minUi5":"1.96","needs":[{"type":"control-too-new","name":"sap.m.p13n.AbstractContainerItem","since":"1.96"},{"type":"control-too-new","name":"sap.m.p13n.AbstractContainerItem","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.AbstractContainerItem.key","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.AbstractContainerItem.key","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.AbstractContainerItem.text","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.AbstractContainerItem.text","since":"1.96"},{"type":"control-too-new","name":"sap.m.p13n.Container","since":"1.96"},{"type":"control-too-new","name":"sap.m.p13n.Container","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.Container.defaultView","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.Container.defaultView","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.Container.listLayout","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.Container.listLayout","since":"1.96"}],"controls":[3,34,12,96,111,171,7,9,304,305,2],"controlCount":24}, + {"class":"z2ui5_cl_smpc_app_645","description":"Responsive Table using the personalization Engine","minUi5":"1.110","needs":[{"type":"control-too-new","name":"sap.m.table.columnmenu.Menu","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.Menu.beforeOpen","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.Menu.showTableSettingsButton","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.Menu.tableSettingsPressed","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.QuickGroup","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickGroup.change","since":"1.110"},{"type":"aggregation-too-new","name":"sap.m.table.columnmenu.QuickGroup.items","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.QuickGroupItem","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickGroupItem.grouped","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickGroupItem.key","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickGroupItem.label","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.QuickSort","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickSort.change","since":"1.110"},{"type":"aggregation-too-new","name":"sap.m.table.columnmenu.QuickSort.items","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.QuickSortItem","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickSortItem.key","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickSortItem.label","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.QuickSortItem.sortOrder","since":"1.110"},{"type":"aggregation-too-new","name":"sap.m.Table.noData","since":"1.101"},{"type":"member-too-new","name":"sap.m.Column.headerMenu","since":"1.98"},{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"control-too-new","name":"sap.m.p13n.Popup","since":"1.97"},{"type":"member-too-new","name":"sap.m.p13n.Popup.close","since":"1.97"},{"type":"aggregation-too-new","name":"sap.m.p13n.Popup.panels","since":"1.97"},{"type":"control-too-new","name":"sap.m.p13n.SelectionPanel","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.enableCount","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.showHeader","since":"1.96"},{"type":"control-too-new","name":"sap.m.p13n.SortPanel","since":"1.96"},{"type":"control-too-new","name":"sap.m.plugins.ColumnResizer","since":"1.91"},{"type":"member-too-new","name":"sap.m.plugins.ColumnResizer.columnResize","since":"1.91"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[3,27,28,273,4,5,32,7,20,174,8,306,307,308,309,272,278,310,311,280,281,18,183,2],"controlCount":32}, + {"class":"z2ui5_cl_smpc_app_646","description":"Filtering using the personalization Engine","minUi5":"1.110","needs":[{"type":"control-too-new","name":"sap.m.table.columnmenu.ActionItem","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.ActionItem","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.ActionItem","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.ActionItem.icon","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.ActionItem.icon","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.ActionItem.icon","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.ActionItem.label","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.ActionItem.label","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.ActionItem.label","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.Menu","since":"1.110"},{"type":"aggregation-too-new","name":"sap.m.table.columnmenu.Menu.items","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.QuickGroup","since":"1.110"},{"type":"aggregation-too-new","name":"sap.m.table.columnmenu.QuickGroup.items","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.QuickGroupItem","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.QuickSort","since":"1.110"},{"type":"aggregation-too-new","name":"sap.m.table.columnmenu.QuickSort.items","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.QuickSortItem","since":"1.110"},{"type":"aggregation-too-new","name":"sap.m.Table.noData","since":"1.101"},{"type":"member-too-new","name":"sap.m.Column.headerMenu","since":"1.98"},{"type":"member-too-new","name":"sap.m.Column.headerMenu","since":"1.98"},{"type":"member-too-new","name":"sap.m.Column.headerMenu","since":"1.98"},{"type":"member-too-new","name":"sap.m.Column.headerMenu","since":"1.98"},{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"member-too-new","name":"sap.m.MultiInput.showClearIcon","since":"1.94"},{"type":"member-too-new","name":"sap.m.MultiInput.showClearIcon","since":"1.94"},{"type":"member-too-new","name":"sap.m.MultiInput.showClearIcon","since":"1.94"},{"type":"member-too-new","name":"sap.m.MultiInput.showClearIcon","since":"1.94"},{"type":"control-too-new","name":"sap.m.plugins.ColumnResizer","since":"1.91"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[3,27,28,34,273,12,149,4,5,32,7,20,150,174,8,9,272,277,278,310,311,280,281,15,183,2],"controlCount":52}, + {"class":"z2ui5_cl_smpc_app_647","description":"GridList using the personalization Engine","minUi5":"1.97","needs":[{"type":"control-too-new","name":"sap.m.p13n.Popup","since":"1.97"},{"type":"member-too-new","name":"sap.m.p13n.Popup.close","since":"1.97"},{"type":"aggregation-too-new","name":"sap.m.p13n.Popup.panels","since":"1.97"},{"type":"control-too-new","name":"sap.m.p13n.SelectionPanel","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.enableCount","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.showHeader","since":"1.96"}],"controls":[50,3,43,19,11,12,20,21,174,8,9,307,308,56,2],"controlCount":27}, + {"class":"z2ui5_cl_smpc_app_648","description":"Grid Table using the personalization Engine","minUi5":"1.119","needs":[{"type":"member-too-new","name":"sap.ui.table.Table.rowMode","since":"1.119"},{"type":"control-too-new","name":"sap.m.table.columnmenu.Menu","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.Menu.showTableSettingsButton","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.Menu.tableSettingsPressed","since":"1.110"},{"type":"member-too-new","name":"sap.ui.table.Column.headerMenu","since":"1.110"},{"type":"member-too-new","name":"sap.m.IllustratedMessage.enableVerticalResponsiveness","since":"1.104"},{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"control-too-new","name":"sap.m.p13n.Popup","since":"1.97"},{"type":"member-too-new","name":"sap.m.p13n.Popup.close","since":"1.97"},{"type":"aggregation-too-new","name":"sap.m.p13n.Popup.panels","since":"1.97"},{"type":"control-too-new","name":"sap.m.p13n.SelectionPanel","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.enableCount","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.showHeader","since":"1.96"},{"type":"control-too-new","name":"sap.m.p13n.SortPanel","since":"1.96"}],"controls":[3,273,12,4,5,7,20,174,8,307,308,309,278,18,2,188,189],"controlCount":19}, + {"class":"z2ui5_cl_smpc_app_649","description":"Personalization for Reponsive Table using multiple SelectionControllers","minUi5":"1.110","needs":[{"type":"control-too-new","name":"sap.m.table.columnmenu.ActionItem","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.ActionItem.icon","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.ActionItem.label","since":"1.110"},{"type":"member-too-new","name":"sap.m.table.columnmenu.ActionItem.press","since":"1.110"},{"type":"control-too-new","name":"sap.m.table.columnmenu.Menu","since":"1.110"},{"type":"aggregation-too-new","name":"sap.m.table.columnmenu.Menu.items","since":"1.110"},{"type":"aggregation-too-new","name":"sap.m.Table.noData","since":"1.101"},{"type":"member-too-new","name":"sap.m.Column.headerMenu","since":"1.98"},{"type":"control-too-new","name":"sap.m.IllustratedMessage","since":"1.98"},{"type":"control-too-new","name":"sap.m.p13n.Popup","since":"1.97"},{"type":"control-too-new","name":"sap.m.p13n.Popup","since":"1.97"},{"type":"member-too-new","name":"sap.m.p13n.Popup.close","since":"1.97"},{"type":"member-too-new","name":"sap.m.p13n.Popup.close","since":"1.97"},{"type":"aggregation-too-new","name":"sap.m.p13n.Popup.panels","since":"1.97"},{"type":"aggregation-too-new","name":"sap.m.p13n.Popup.panels","since":"1.97"},{"type":"control-too-new","name":"sap.m.p13n.SelectionPanel","since":"1.96"},{"type":"control-too-new","name":"sap.m.p13n.SelectionPanel","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.enableCount","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.enableCount","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.enableReorder","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.showHeader","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.showHeader","since":"1.96"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[3,27,28,273,4,5,32,7,20,174,8,307,308,277,278,18,183,2],"controlCount":24}, + {"class":"z2ui5_cl_smpc_app_650","description":"Dialog with sap.m.p13n/* Panels","minUi5":"1.97","needs":[{"type":"control-too-new","name":"sap.m.p13n.Popup","since":"1.97"},{"type":"member-too-new","name":"sap.m.p13n.Popup.close","since":"1.97"},{"type":"member-too-new","name":"sap.m.p13n.Popup.open","since":"1.97"},{"type":"aggregation-too-new","name":"sap.m.p13n.Popup.panels","since":"1.97"},{"type":"member-too-new","name":"sap.m.p13n.Popup.title","since":"1.97"},{"type":"member-too-new","name":"sap.m.p13n.Popup.warningText","since":"1.97"},{"type":"control-too-new","name":"sap.m.p13n.SelectionPanel","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.change","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.enableCount","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.showHeader","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SelectionPanel.title","since":"1.96"},{"type":"control-too-new","name":"sap.m.p13n.SortPanel","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SortPanel.change","since":"1.96"},{"type":"member-too-new","name":"sap.m.p13n.SortPanel.title","since":"1.96"}],"controls":[3,9,306,307,308,309,187,2],"controlCount":8}, + {"class":"z2ui5_cl_smpc_app_651","description":"VariantManagement with dedicated items","minUi5":"1.103","needs":[{"type":"control-too-new","name":"sap.m.VariantManagement","since":"1.103"},{"type":"member-too-new","name":"sap.m.VariantManagement.defaultKey","since":"1.103"},{"type":"aggregation-too-new","name":"sap.m.VariantManagement.items","since":"1.103"},{"type":"member-too-new","name":"sap.m.VariantManagement.manage","since":"1.103"},{"type":"member-too-new","name":"sap.m.VariantManagement.modified","since":"1.103"},{"type":"member-too-new","name":"sap.m.VariantManagement.popoverTitle","since":"1.103"},{"type":"member-too-new","name":"sap.m.VariantManagement.save","since":"1.103"},{"type":"member-too-new","name":"sap.m.VariantManagement.select","since":"1.103"},{"type":"member-too-new","name":"sap.m.VariantManagement.selectedKey","since":"1.103"},{"type":"member-too-new","name":"sap.m.VariantManagement.showFooter","since":"1.103"}],"controls":[36,38,3,4,46,20,8,312,313,2],"controlCount":11}, + {"class":"z2ui5_cl_smpc_app_652","description":"This example demonstrates the usage of fileNameValidationConfig property to configure file name validation for renaming a file.","minUi5":"1.136","needs":[{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.fileNameValidationConfig","since":"1.136"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.beforeUploadStarts","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.cloudFilePickerEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.itemRenamed","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"aggregation-too-new","name":"sap.m.plugins.UploadSetwithTable.rowConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"},{"type":"member-too-new","name":"sap.m.Table.hiddenInPopin","since":"1.77"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[36,3,23,27,28,34,11,55,45,12,13,167,255,168,89,4,52,6,32,7,20,174,8,9,314,315,316,18,56,2,26],"controlCount":72}, + {"class":"z2ui5_cl_smpc_app_653","description":"This example showcases how to display custom page content for non supported file types in the FilePreviewDialog control. The custom page content is displayed when the user tries to preview a file that is not supported by the FilePreviewDialog control. This sample demonstrates usage of customPageConentHandler property as a callback function to display custom page content.","minUi5":"1.125","needs":[{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.beforeUploadStarts","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.cloudFilePickerEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.itemRenamed","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.previewDialog","since":"1.124"},{"type":"aggregation-too-new","name":"sap.m.plugins.UploadSetwithTable.rowConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"},{"type":"control-too-new","name":"sap.m.upload.FilePreviewDialog","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.FilePreviewDialog.maxFileSizeforPreview","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.FilePreviewDialog.showCarouselArrows","since":"1.120"},{"type":"member-too-new","name":"sap.m.Table.hiddenInPopin","since":"1.77"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[36,3,27,28,34,11,55,45,12,13,167,255,168,89,4,52,6,32,7,20,174,8,9,314,315,317,316,18,56,2,26],"controlCount":64}, + {"class":"z2ui5_cl_smpc_app_654","description":"This example demonstrates the usage of UploadSetwithTable plugin for grid table with the features of upload, download, drag & drop, remove and rename of files. It also demonstrates how the uploaded files can be displayed in a table.","minUi5":"1.125","needs":[{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.beforeUploadStarts","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.cloudFilePickerEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.itemRenamed","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"}],"controls":[36,3,34,11,55,45,12,13,167,255,168,4,52,7,20,8,9,314,315,316,18,56,2,26,188,198,189],"controlCount":57}, + {"class":"z2ui5_cl_smpc_app_655","description":"This example demonstrates the usage of multiple plugin instances with multiple tables. The plugin instances are created for each table and the uploaded files are displayed in their respective tables.","minUi5":"1.125","needs":[{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.beforeUploadStarts","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.beforeUploadStarts","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.beforeUploadStarts","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.cloudFilePickerEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.cloudFilePickerEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.cloudFilePickerEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"aggregation-too-new","name":"sap.m.plugins.UploadSetwithTable.rowConfiguration","since":"1.124"},{"type":"aggregation-too-new","name":"sap.m.plugins.UploadSetwithTable.rowConfiguration","since":"1.124"},{"type":"aggregation-too-new","name":"sap.m.plugins.UploadSetwithTable.rowConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"},{"type":"member-too-new","name":"sap.m.Table.hiddenInPopin","since":"1.77"},{"type":"member-too-new","name":"sap.m.Table.hiddenInPopin","since":"1.77"},{"type":"member-too-new","name":"sap.m.Table.hiddenInPopin","since":"1.77"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[36,3,27,28,11,55,12,13,4,52,6,32,7,20,174,8,9,314,315,316,256,56,2],"controlCount":123}, + {"class":"z2ui5_cl_smpc_app_656","description":"This example demonstrates usage of itemValidationHandler callback to leverage additional validations and configurations for the items that are to be uploaded, and also the manual trigger of the upload process. The user input can be captured for each file with the help of the user dialog implemented at the application controller, before its upload.","minUi5":"1.125","needs":[{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.beforeUploadStarts","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.cloudFilePickerEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.itemRenamed","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"aggregation-too-new","name":"sap.m.plugins.UploadSetwithTable.rowConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"},{"type":"member-too-new","name":"sap.m.Table.hiddenInPopin","since":"1.77"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[36,3,27,28,29,34,11,55,45,12,13,167,255,168,4,52,6,32,7,20,21,174,8,9,314,315,316,18,56,151,2,26],"controlCount":79}, + {"class":"z2ui5_cl_smpc_app_657","description":"This example showcases how uploaded files can be previewed with FilePreviewDialog control and its related configuration. UploadSetwithTable plugin creates and uses default instance of FilePreviewDialog, if not defined.","minUi5":"1.125","needs":[{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.beforeUploadStarts","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.cloudFilePickerEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.itemRenamed","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.previewDialog","since":"1.124"},{"type":"aggregation-too-new","name":"sap.m.plugins.UploadSetwithTable.rowConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"},{"type":"control-too-new","name":"sap.m.upload.FilePreviewDialog","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.FilePreviewDialog.maxFileSizeforPreview","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.FilePreviewDialog.showCarouselArrows","since":"1.120"},{"type":"member-too-new","name":"sap.m.Table.hiddenInPopin","since":"1.77"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[36,3,27,28,34,11,55,45,12,13,167,255,168,4,52,6,32,7,20,174,8,9,314,315,317,316,18,56,2,26],"controlCount":61}, + {"class":"z2ui5_cl_smpc_app_658","description":"This example demonstrates the progress or termination of the items that are being uploaded. The upload progress is displayed for each item that is being uploaded. The users can terminate the upload process at any time.","minUi5":"1.125","needs":[{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.cloudFilePickerEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.itemRenamed","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"aggregation-too-new","name":"sap.m.plugins.UploadSetwithTable.rowConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadCompleted","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"},{"type":"member-too-new","name":"sap.m.Table.hiddenInPopin","since":"1.77"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[36,3,27,28,34,11,55,45,12,13,167,255,168,4,52,6,32,7,20,174,8,9,314,315,316,18,56,2,26],"controlCount":60}, + {"class":"z2ui5_cl_smpc_app_659","description":"This example demonstrates the usage of UploadSetwithTable plugin for responsive table with the features of upload, download, drag & drop, remove and rename of files. It also demonstrates how the uploaded files can be displayed in a table.","minUi5":"1.142","needs":[{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.itemRenameCanceled","since":"1.142"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.beforeUploadStarts","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.cloudFilePickerEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.itemRenamed","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"aggregation-too-new","name":"sap.m.plugins.UploadSetwithTable.rowConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"},{"type":"member-too-new","name":"sap.m.Table.hiddenInPopin","since":"1.77"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Column.importance","since":"1.76"},{"type":"member-too-new","name":"sap.m.Table.autoPopinMode","since":"1.76"}],"controls":[36,3,27,28,34,11,55,45,12,13,167,255,168,4,52,6,32,7,20,174,8,9,314,315,316,18,56,2,26],"controlCount":60}, + {"class":"z2ui5_cl_smpc_app_660","description":"This example demonstrates the usage of UploadSetwithTable plugin for tree table with the features of upload, download, drag & drop, remove and rename of files. It also demonstrates how the uploaded files can be displayed in a table.","minUi5":"1.139","needs":[{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isDirectoryPath","since":"1.139"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.beforeUploadStarts","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.cloudFilePickerEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.itemRenamed","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"}],"controls":[36,3,34,11,55,45,12,13,167,255,168,4,52,7,20,8,9,314,315,316,18,56,2,26,188,198,202],"controlCount":52}, + {"class":"z2ui5_cl_smpc_app_661","description":"This example demonstrates the usage of UploadSetwithTable plugin with a tree table featuring folder hierarchy, folder creation, folder uploads, folder navigation with breadcrumbs and folder management","minUi5":"1.139","needs":[{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isDirectoryPath","since":"1.139"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.isTrustedSourcePath","since":"1.125"},{"type":"control-too-new","name":"sap.m.plugins.UploadSetwithTable","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.actions","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.beforeUploadStarts","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.itemRenamed","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.multiple","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadEnabled","since":"1.124"},{"type":"member-too-new","name":"sap.m.plugins.UploadSetwithTable.uploadUrl","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.UploadItemConfiguration","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileNamePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.fileSizePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.mediaTypePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.previewablePath","since":"1.124"},{"type":"member-too-new","name":"sap.m.upload.UploadItemConfiguration.urlPath","since":"1.124"},{"type":"control-too-new","name":"sap.m.upload.ActionsPlaceholder","since":"1.120"},{"type":"member-too-new","name":"sap.m.upload.ActionsPlaceholder.placeholderFor","since":"1.120"}],"controls":[36,10,3,34,11,55,45,12,13,4,7,9,314,315,316,18,56,2,188,198,202],"controlCount":48}, + {"class":"z2ui5_cl_smpc_app_662","description":"This sample demonstrates the different group types and item sizes of the AvatarGroup control.","minUi5":"1.73","needs":[{"type":"control-too-new","name":"sap.f.AvatarGroup","since":"1.73"},{"type":"control-too-new","name":"sap.f.AvatarGroup","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroup.avatarDisplaySize","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroup.avatarDisplaySize","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroup.groupType","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroup.groupType","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroup.items","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroup.items","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroup.press","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroup.press","since":"1.73"},{"type":"control-too-new","name":"sap.f.AvatarGroupItem","since":"1.73"},{"type":"control-too-new","name":"sap.f.AvatarGroupItem","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroupItem.fallbackIcon","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroupItem.fallbackIcon","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroupItem.initials","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroupItem.initials","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroupItem.src","since":"1.73"},{"type":"member-too-new","name":"sap.f.AvatarGroupItem.src","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.backgroundColor","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.fallbackIcon","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.fallbackIcon","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.fallbackIcon","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.initials","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.press","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"},{"type":"member-too-new","name":"sap.m.Page.titleAlignment","since":"1.72"},{"type":"member-too-new","name":"sap.m.Page.titleAlignment","since":"1.72"},{"type":"member-too-new","name":"sap.m.Popover.titleAlignment","since":"1.72"}],"controls":[346,347,35,258,11,12,118,5,235,90,7,20,9,18,2,77,16],"controlCount":52}, + {"class":"z2ui5_cl_smpc_app_663","description":"Demonstrates the basic usage of Side Panel.","minUi5":"1.146","needs":[{"type":"aggregation-too-new","name":"sap.f.SidePanelItem.title","since":"1.146"},{"type":"control-too-new","name":"sap.f.SidePanel","since":"1.107"},{"type":"aggregation-too-new","name":"sap.f.SidePanel.items","since":"1.107"},{"type":"aggregation-too-new","name":"sap.f.SidePanel.mainContent","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanel.sidePanelPosition","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanel.toggle","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"}],"controls":[336,337,3,45,12,5,14,53,7,20,9,151,2],"controlCount":47}, + {"class":"z2ui5_cl_smpc_app_664","description":"Demonstrates the usage of Side Panel with overflow menu on desktop and tablet devices.","minUi5":"1.107","needs":[{"type":"control-too-new","name":"sap.f.SidePanel","since":"1.107"},{"type":"aggregation-too-new","name":"sap.f.SidePanel.items","since":"1.107"},{"type":"aggregation-too-new","name":"sap.f.SidePanel.mainContent","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanel.toggle","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"}],"controls":[336,337,3,12,5,53,7,9,2],"controlCount":61}, + {"class":"z2ui5_cl_smpc_app_665","description":"Demonstrates the usage of resizable Side Panel.","minUi5":"1.107","needs":[{"type":"control-too-new","name":"sap.f.SidePanel","since":"1.107"},{"type":"aggregation-too-new","name":"sap.f.SidePanel.items","since":"1.107"},{"type":"aggregation-too-new","name":"sap.f.SidePanel.mainContent","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanel.sidePanelResizable","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanel.toggle","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"control-too-new","name":"sap.f.SidePanelItem","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"},{"type":"member-too-new","name":"sap.f.SidePanelItem.icon","since":"1.107"}],"controls":[336,337,3,45,12,5,53,7,9,2],"controlCount":35}, + {"class":"z2ui5_cl_smpc_app_666","description":"This sample demonstrates the usage of Product Switch Item with imageSrc, configurable by the app developer.","minUi5":"1.140","needs":[{"type":"member-too-new","name":"sap.f.ProductSwitchItem.imageSrc","since":"1.140"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.imageSrc","since":"1.140"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.imageSrc","since":"1.140"},{"type":"control-too-new","name":"sap.f.ProductSwitch","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitch.change","since":"1.72"},{"type":"aggregation-too-new","name":"sap.f.ProductSwitch.items","since":"1.72"},{"type":"control-too-new","name":"sap.f.ProductSwitchItem","since":"1.72"},{"type":"control-too-new","name":"sap.f.ProductSwitchItem","since":"1.72"},{"type":"control-too-new","name":"sap.f.ProductSwitchItem","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.src","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.src","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.src","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.subTitle","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.subTitle","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.subTitle","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.target","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.target","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.target","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.targetSrc","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.targetSrc","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.targetSrc","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.title","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.title","since":"1.72"},{"type":"member-too-new","name":"sap.f.ProductSwitchItem.title","since":"1.72"}],"controls":[338,339,3,171,7,18,2,16],"controlCount":12}, + {"class":"z2ui5_cl_smpc_app_667","description":"A basic Hero Banner with a header text and overline text.","minUi5":"1.152","needs":[{"type":"control-too-new","name":"sap.f.HeroBanner","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.overlineText","since":"1.152"}],"controls":[348,5,9,2],"controlCount":4}, + {"class":"z2ui5_cl_smpc_app_668","description":"Demonstrates the three columnsRatio options: single column (no endContent), Equal, and FirstWider.","minUi5":"1.152","needs":[{"type":"control-too-new","name":"sap.f.HeroBanner","since":"1.152"},{"type":"control-too-new","name":"sap.f.HeroBanner","since":"1.152"},{"type":"control-too-new","name":"sap.f.HeroBanner","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.actions","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.columnsRatio","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.columnsRatio","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.endContent","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.endContent","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.overlineText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.overlineText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.overlineText","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.startContent","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.startContent","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.startContent","since":"1.152"}],"controls":[35,348,39,3,5,7,20,9,24,2],"controlCount":31}, + {"class":"z2ui5_cl_smpc_app_669","description":"Demonstrates actionsPlacement and headerBlockPlacement properties for controlling the position of the header and actions.","minUi5":"1.152","needs":[{"type":"control-too-new","name":"sap.f.HeroBanner","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.actions","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.actionsPlacement","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.columnsRatio","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.endContent","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerBlockPlacement","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.overlineText","since":"1.152"}],"controls":[35,348,39,3,5,20,9,2],"controlCount":11}, + {"class":"z2ui5_cl_smpc_app_670","description":"Demonstrates the use of sap.ui.integration.widgets.Card inside both the startContent (default slot) and endContent aggregations of the Hero Banner.","minUi5":"1.152","needs":[{"type":"control-too-new","name":"sap.f.HeroBanner","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.actions","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.columnsRatio","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.endContent","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.overlineText","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.startContent","since":"1.152"}],"controls":[348,3,5,9,2,211],"controlCount":8}, + {"class":"z2ui5_cl_smpc_app_671","description":"A collection of common Hero Banner use cases: header actions only, content with actions, actions below header, and header at bottom.","minUi5":"1.152","needs":[{"type":"control-too-new","name":"sap.f.HeroBanner","since":"1.152"},{"type":"control-too-new","name":"sap.f.HeroBanner","since":"1.152"},{"type":"control-too-new","name":"sap.f.HeroBanner","since":"1.152"},{"type":"control-too-new","name":"sap.f.HeroBanner","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.actions","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.actions","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.actions","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.actions","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.actionsPlacement","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.columnsRatio","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.columnsRatio","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.endContent","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.endContent","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerBlockPlacement","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.headerText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.overlineText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.overlineText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.overlineText","since":"1.152"},{"type":"member-too-new","name":"sap.f.HeroBanner.overlineText","since":"1.152"},{"type":"aggregation-too-new","name":"sap.f.HeroBanner.startContent","since":"1.152"}],"controls":[35,348,39,3,5,7,20,9,24,2],"controlCount":34}, + {"class":"z2ui5_cl_smpc_demo_001","description":"","minUi5":"1.71","needs":[],"controls":[247,248,229,230,40,3,27,28,68,69,58,19,11,73,74,106,12,1,81,30,31,83,5,46,205,6,352,32,7,20,21,8,9,56,2,16,26],"controlCount":77}, + {"class":"z2ui5_cl_smpc_demo_002","description":"","minUi5":"1.71","needs":[],"controls":[236,239,243,246,229,230,40,3,27,28,73,74,55,12,13,1,406,81,30,100,31,83,4,52,5,6,32,7,20,21,8,9,114,115,116,107,2,61,16,26],"controlCount":88}, {"class":"z2ui5_cl_smpc_demo_003","description":"","minUi5":"1.71","needs":[],"controls":[36,38,3,12,175,291,176,289,171,14,178,179,265,180,20,9,15,2,16,177,292],"controlCount":35}, - {"class":"z2ui5_cl_smpc_demo_004","description":"","minUi5":"1.71","needs":[],"controls":[236,40,102,3,41,23,117,58,44,11,55,45,12,97,98,13,1,269,270,78,122,118,81,82,30,100,83,5,147,46,103,84,75,6,86,87,76,7,60,20,33,21,8,9,164,114,115,116,119,120,24,2,47,48,49,77,197,16,152,153,154,155,26,388],"controlCount":414}, - {"class":"z2ui5_cl_smpc_demo_005","description":"","minUi5":"1.71","needs":[],"controls":[40,27,28,73,74,12,82,30,31,6,333,32,7,33,21,8,130,133,2,26],"controlCount":33}, - {"class":"z2ui5_cl_smpc_sapui5_001","description":"","minUi5":"1.71","needs":[],"controls":[3,58,13,5,333,7,334,335,2,77,197,336,337],"controlCount":35}, - {"class":"z2ui5_cl_smpc_sapui5_002","description":"","minUi5":"1.71","needs":[],"controls":[58,13,5,333,7,338,339,2,77,197,16,336,337],"controlCount":36}, - {"class":"z2ui5_cl_smpc_sapui5_003","description":"","minUi5":"1.71","needs":[],"controls":[58,13,5,333,7,340,341,2,77,197,16,336,337],"controlCount":27}, - {"class":"z2ui5_cl_smpc_sapui5_004","description":"","minUi5":"1.71","needs":[],"controls":[13,5,333,342,2,77,61,16,336,337],"controlCount":20}, - {"class":"z2ui5_cl_smpc_sapui5_005","description":"","minUi5":"1.71","needs":[],"controls":[5,333,343,344,2],"controlCount":5}, - {"class":"z2ui5_cl_smpc_sapui5_006","description":"","minUi5":"1.71","needs":[],"controls":[5,333,345,346,347,2],"controlCount":6}, - {"class":"z2ui5_cl_smpc_sapui5_007","description":"","minUi5":"1.71","needs":[],"controls":[5,333,348,349,2],"controlCount":5}, - {"class":"z2ui5_cl_smpc_sapui5_008","description":"","minUi5":"1.92","needs":[{"type":"aggregation-too-new","name":"sap.m.QuickViewPage.avatar","since":"1.92"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,5,263,260,261,262,350,351,352,353,354,355,356,18,2],"controlCount":19}, - {"class":"z2ui5_cl_smpc_sapui5_009","description":"","minUi5":"1.71","needs":[],"controls":[58,5,46,85,333,90,7,357,358,359,360,24,2],"controlCount":16}, - {"class":"z2ui5_cl_smpc_sapui5_010","description":"","minUi5":"1.71","needs":[],"controls":[5,333,2,361,362,363,364,365,366,367,368,369],"controlCount":12}, - {"class":"z2ui5_cl_smpc_sapui5_011","description":"","minUi5":"1.71","needs":[],"controls":[45,12,5,333,370,2,26],"controlCount":10}, - {"class":"z2ui5_cl_smpc_sapui5_012","description":"","minUi5":"1.96","needs":[{"type":"member-too-new","name":"sap.m.ComboBox.showClearIcon","since":"1.96"}],"controls":[36,37,38,3,29,333,20,371,372,15,2,373,374,375,376,377],"controlCount":18}, - {"class":"z2ui5_cl_smpc_sapui5_013","description":"","minUi5":"1.71","needs":[],"controls":[378,379,380,381,382,383,89,5,7,2,188,202],"controlCount":14}, - {"class":"z2ui5_cl_smpc_sapui5_014","description":"","minUi5":"1.71","needs":[],"controls":[378,379,384,385,380,381,382,386,12,89,5,75,333,7,256,2,188,202],"controlCount":19} + {"class":"z2ui5_cl_smpc_demo_004","description":"","minUi5":"1.71","needs":[],"controls":[236,40,102,3,41,23,117,58,44,11,55,45,12,97,98,13,1,269,270,78,122,118,81,82,30,100,83,5,147,46,103,84,75,6,86,87,76,7,60,20,33,21,8,9,164,114,115,116,119,120,24,2,47,48,49,77,197,16,152,153,154,155,26,407],"controlCount":414}, + {"class":"z2ui5_cl_smpc_demo_005","description":"","minUi5":"1.71","needs":[],"controls":[40,27,28,73,74,12,82,30,31,6,352,32,7,33,21,8,130,133,2,26],"controlCount":33}, + {"class":"z2ui5_cl_smpc_sapui5_001","description":"","minUi5":"1.71","needs":[],"controls":[3,58,13,5,352,7,353,354,2,77,197,355,356],"controlCount":35}, + {"class":"z2ui5_cl_smpc_sapui5_002","description":"","minUi5":"1.71","needs":[],"controls":[58,13,5,352,7,357,358,2,77,197,16,355,356],"controlCount":36}, + {"class":"z2ui5_cl_smpc_sapui5_003","description":"","minUi5":"1.71","needs":[],"controls":[58,13,5,352,7,359,360,2,77,197,16,355,356],"controlCount":27}, + {"class":"z2ui5_cl_smpc_sapui5_004","description":"","minUi5":"1.71","needs":[],"controls":[13,5,352,361,2,77,61,16,355,356],"controlCount":20}, + {"class":"z2ui5_cl_smpc_sapui5_005","description":"","minUi5":"1.71","needs":[],"controls":[5,352,362,363,2],"controlCount":5}, + {"class":"z2ui5_cl_smpc_sapui5_006","description":"","minUi5":"1.71","needs":[],"controls":[5,352,364,365,366,2],"controlCount":6}, + {"class":"z2ui5_cl_smpc_sapui5_007","description":"","minUi5":"1.71","needs":[],"controls":[5,352,367,368,2],"controlCount":5}, + {"class":"z2ui5_cl_smpc_sapui5_008","description":"","minUi5":"1.92","needs":[{"type":"aggregation-too-new","name":"sap.m.QuickViewPage.avatar","since":"1.92"},{"type":"control-too-new","name":"sap.m.Avatar","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.displayShape","since":"1.73"},{"type":"member-too-new","name":"sap.m.Avatar.src","since":"1.73"}],"controls":[258,5,263,260,261,262,369,370,371,372,373,374,375,18,2],"controlCount":19}, + {"class":"z2ui5_cl_smpc_sapui5_009","description":"","minUi5":"1.71","needs":[],"controls":[58,5,46,85,352,90,7,376,377,378,379,24,2],"controlCount":16}, + {"class":"z2ui5_cl_smpc_sapui5_010","description":"","minUi5":"1.71","needs":[],"controls":[5,352,2,380,381,382,383,384,385,386,387,388],"controlCount":12}, + {"class":"z2ui5_cl_smpc_sapui5_011","description":"","minUi5":"1.71","needs":[],"controls":[45,12,5,352,389,2,26],"controlCount":10}, + {"class":"z2ui5_cl_smpc_sapui5_012","description":"","minUi5":"1.96","needs":[{"type":"member-too-new","name":"sap.m.ComboBox.showClearIcon","since":"1.96"}],"controls":[36,37,38,3,29,352,20,390,391,15,2,392,393,394,395,396],"controlCount":18}, + {"class":"z2ui5_cl_smpc_sapui5_013","description":"","minUi5":"1.71","needs":[],"controls":[397,398,399,400,401,402,89,5,7,2,188,202],"controlCount":14}, + {"class":"z2ui5_cl_smpc_sapui5_014","description":"","minUi5":"1.71","needs":[],"controls":[397,398,403,404,399,400,401,405,12,89,5,75,352,7,256,2,188,202],"controlCount":19} ] } diff --git a/catalogue.json b/catalogue.json index 282b6e651..f89e645d8 100644 --- a/catalogue.json +++ b/catalogue.json @@ -25,11 +25,11 @@ }, "ui5Snapshot": "1.152.0", "counts": { - "entries": 641, + "entries": 689, "byStatus": { "checked": 59, "reviewed": 355, - "generated": 208, + "generated": 256, "demoapp": 5, "collection": 14 } @@ -657,6 +657,54 @@ {"class":"z2ui5_cl_smpc_app_621","file":"src/02/01/z2ui5_cl_smpc_app_621.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.InputAssistedTabularSuggestions","entity":"sap.m.Input","title":"Input - Assisted Tabular Suggestions","summary":"In this example assisted input is provided with table-like suggestions where several columns can display more details.","keywords":"input sap.m inputassistedtabularsuggestions verticallayout column label columnlistitem","status":"generated","deviations":["NOTE","POST_171"]}, {"class":"z2ui5_cl_smpc_app_622","file":"src/01/01/z2ui5_cl_smpc_app_622.clas.abap","category":"src/01","library":"sap.m","sample":"sap.m.sample.InputChecked","entity":"sap.m.Input","title":"Input - Checked","summary":"Input checks are handled via the validation of the data binding. In this example there are two inputs that are validated (a) while the user types and (b) when the user continues the process.","keywords":"input sap.m inputchecked verticallayout label button","status":"generated","deviations":["IMPROVISED","NOTE"]}, {"class":"z2ui5_cl_smpc_app_623","file":"src/01/01/z2ui5_cl_smpc_app_623.clas.abap","category":"src/01","library":"sap.m","sample":"sap.m.sample.InputStates","entity":"sap.m.Input","title":"Input - States","summary":"This example demonstrates the different input field states, e.g. disabled, editable, with value help and value help only.","keywords":"input sap.m inputstates verticallayout label selectdialog standardlistitem","status":"generated","deviations":["NOTE"]}, + {"class":"z2ui5_cl_smpc_app_624","file":"src/02/01/z2ui5_cl_smpc_app_624.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.Avatar","entity":"sap.m.Avatar","title":"Avatar","summary":"This sample demonstrates different combinations of types, shapes, and sizes of the Avatar.","keywords":"avatar sap.m scrollcontainer text grid vbox","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_625","file":"src/02/01/z2ui5_cl_smpc_app_625.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.AvatarActiveState","entity":"sap.m.Avatar","title":"Avatar with toggling of Active state","summary":"This sample demonstrates toggling of Avatar Active state, when a User menu is opened/closed.","keywords":"avatar sap.m avataractivestate popover list standardlistitem messagestrip","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_626","file":"src/02/01/z2ui5_cl_smpc_app_626.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.AvatarBadgeIconColor","entity":"sap.m.Avatar","title":"Avatar with Badge Icon Color","summary":"This sample demonstrates different badge icon colors of the Avatar.","keywords":"avatar sap.m avatarbadgeiconcolor scrollcontainer text grid vbox","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_627","file":"src/02/01/z2ui5_cl_smpc_app_627.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.AvatarValueState","entity":"sap.m.Avatar","title":"Avatar with badgeValueState","summary":"This sample demonstrates different badge value states of the Avatar.","keywords":"avatar sap.m avatarvaluestate scrollcontainer grid vbox text","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_628","file":"src/02/01/z2ui5_cl_smpc_app_628.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.AvatarWithAffordance","entity":"sap.m.Avatar","title":"Avatar with Visual Affordance","summary":"This sample demonstrates different combinations of types, shapes, and sizes of the Avatar with visual affordance.","keywords":"avatar sap.m avatarwithaffordance scrollcontainer text grid vbox lightbox lightboxitem","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_629","file":"src/02/01/z2ui5_cl_smpc_app_629.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.IllustratedMessageEVR","entity":"sap.m.IllustratedMessage","title":"Illustrated Message Enable Vertical Responsiveness","summary":"Demonstrates the IllustratedMessage's 'enableVerticalResponsiveness' property.","keywords":"illustratedmessage illustrated message sap.m illustratedmessageevr responsivesplitter panecontainer splitpane splitterlayoutdata button vbox","status":"generated","deviations":["POST_171"]}, + {"class":"z2ui5_cl_smpc_app_630","file":"src/02/01/z2ui5_cl_smpc_app_630.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.IllustratedMessageInAppCustom","entity":"sap.m.IllustratedMessage","title":"A demo application that imports a Custom Illustration Set from an npm package","summary":"Shows how to import a Custom Illustration from an npm package into a UI5 application for usage with IllustratedMessage.","keywords":"illustratedmessage illustrated message sap.m illustratedmessageinappcustom simpleform label select item text button","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_631","file":"src/02/01/z2ui5_cl_smpc_app_631.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.IllustratedMessageInCardNoActivities","entity":"sap.m.IllustratedMessage","title":"'NoActivities' Illustrated Message in a Card","summary":"IllustratedMessage as content of sap.f.Card. 'NoActivities' illustration type is being used for the Illustrated Message.","keywords":"illustratedmessage illustrated message sap.m illustratedmessageincardnoactivities card header button","status":"generated","deviations":["POST_171"]}, + {"class":"z2ui5_cl_smpc_app_632","file":"src/02/01/z2ui5_cl_smpc_app_632.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.IllustratedMessageInCardNoEmail","entity":"sap.m.IllustratedMessage","title":"'NoEmail' Illustrated Message in a Card","summary":"IllustratedMessage as content of sap.f.Card. 'NoEmail' illustration type is being used for the Illustrated Message.","keywords":"illustratedmessage illustrated message sap.m illustratedmessageincardnoemail card header","status":"generated","deviations":["POST_171"]}, + {"class":"z2ui5_cl_smpc_app_633","file":"src/02/01/z2ui5_cl_smpc_app_633.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.IllustratedMessageInDialog","entity":"sap.m.IllustratedMessage","title":"Illustrated Message in a Dialog","summary":"IllustratedMessage as content of sap.m.Dialog.","keywords":"illustratedmessage illustrated message sap.m illustratedmessageindialog button dialog","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_634","file":"src/02/01/z2ui5_cl_smpc_app_634.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.IllustratedMessageInPage","entity":"sap.m.IllustratedMessage","title":"Default Illustration Set (sapIllus)","summary":"The available illustrations are from the default ('sapIllus') illustration set.","keywords":"illustratedmessage illustrated message sap.m illustratedmessageinpage simpleform label columnelementdata switch text select item","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_635","file":"src/02/01/z2ui5_cl_smpc_app_635.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.IllustratedMessageInPageCustom","entity":"sap.m.IllustratedMessage","title":"Illustrated Message in a Page with Configurable Properties (Custom Illustration Set)","summary":"The available properties of the IllustratedMessage are configurable in this sample. The available illustrations are from the 'custom' illustration set.","keywords":"illustratedmessage illustrated message sap.m illustratedmessageinpagecustom simpleform label select item text button","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_636","file":"src/02/01/z2ui5_cl_smpc_app_636.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.IllustratedMessageInPageTNT","entity":"sap.m.IllustratedMessage","title":"Illustrated Message in a Page with Configurable Properties (TNT Illustration Set)","summary":"The available properties of the IllustratedMessage are configurable in this sample. The available illustrations are from the 'tnt' illustration set.","keywords":"illustratedmessage illustrated message sap.m illustratedmessageinpagetnt simpleform label columnelementdata select item text button","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_637","file":"src/02/01/z2ui5_cl_smpc_app_637.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.IllustratedMessageInPageWithURI","entity":"sap.m.IllustratedMessage","title":"Illustrative style illustrations using the 'src' property","summary":"The available illustrations are from the default illustration set with the use of the 'src' property.","keywords":"illustratedmessage illustrated message sap.m illustratedmessageinpagewithuri simpleform label columnelementdata switch text select item","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_638","file":"src/02/01/z2ui5_cl_smpc_app_638.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.IllustratedMessageSessionTimeout","entity":"sap.m.IllustratedMessage","title":"Illustrated Message Session Timeout","summary":"All applications that require user sign-in should employ a mechanism for automating user sign-out. When the inactivity is about to reach that threshold, a session timeout dialog appears automatically to inform the user.","keywords":"illustratedmessage illustrated message sap.m illustratedmessagesessiontimeout vbox label stepinput button dialog","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_639","file":"src/02/01/z2ui5_cl_smpc_app_639.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.DynamicDateRange","entity":"sap.m.DynamicDateRange","title":"Dynamic Date Range","summary":"The dynamic date range is a control that offers a choice of absolute and relative dates, using different offset from the current date. The list of values offered must be defined by the application.","keywords":"dynamicdaterange dynamic date range sap.m table overflowtoolbar title toolbarspacer label column text","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_640","file":"src/02/01/z2ui5_cl_smpc_app_640.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.DynamicDateRangeAndCalendarWeekNumbering","entity":"sap.m.DynamicDateRange","title":"Dynamic Date Range with calendarWeekNumbering","summary":"This example shows the Dynamic Date Range control with Middle Eastern calendar week numbering.","keywords":"dynamicdaterange dynamic date range sap.m dynamicdaterangeandcalendarweeknumbering table overflowtoolbar title toolbarspacer label column","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_641","file":"src/02/01/z2ui5_cl_smpc_app_641.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.DynamicDateRangeHidden","entity":"sap.m.DynamicDateRange","title":"Dynamic Date Range - Open by Another Control","summary":"This example shows Dynamic Date Range which is opened by another control.","keywords":"dynamicdaterange dynamic date range sap.m dynamicdaterangehidden title vbox label button link","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_642","file":"src/02/01/z2ui5_cl_smpc_app_642.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.DynamicDateRangeWithCustomOptions","entity":"sap.m.DynamicDateRange","title":"Dynamic Date Range with Custom Options","summary":"This example shows the Dynamic Date Range control with custom options for interval or date selection.","keywords":"dynamicdaterange dynamic date range sap.m dynamicdaterangewithcustomoptions table overflowtoolbar title toolbarspacer label column","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_643","file":"src/02/01/z2ui5_cl_smpc_app_643.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.ExpandableText","entity":"sap.m.ExpandableText","title":"Expandable Text","summary":"The ExpandableText control can be used to display a larger texts inside a table, list or form.","keywords":"expandabletext expandable text sap.m table column columnlistitem","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_644","file":"src/02/01/z2ui5_cl_smpc_app_644.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.p13n.Container","entity":"sap.m.p13n.Container","title":"p13n.Container usage in a Dialog/Popover","summary":"Dialog & Popover with a sap.m.P13nContainer as content.","keywords":"container sap.m.p13n p13n.container vbox radiobuttongroup radiobutton label button text","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_645","file":"src/02/01/z2ui5_cl_smpc_app_645.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.p13n.Engine","entity":"sap.m.p13n.Engine","title":"Personalization for responsive table","summary":"Responsive Table using the personalization Engine","keywords":"engine sap.m.p13n p13n.engine table overflowtoolbar title toolbarseparator toolbarspacer button text columnresizer menu","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_646","file":"src/02/01/z2ui5_cl_smpc_app_646.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.p13n.EngineCustomFilters","entity":"sap.m.p13n.Engine","title":"Personalization implementing custom filter controls","summary":"Filtering using the personalization Engine","keywords":"engine sap.m.p13n p13n.enginecustomfilters table overflowtoolbar title toolbarseparator toolbarspacer button columnresizer menu quicksort","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_647","file":"src/02/01/z2ui5_cl_smpc_app_647.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.p13n.EngineGridList","entity":"sap.m.p13n.Engine","title":"Personalization for grid list","summary":"GridList using the personalization Engine","keywords":"engine sap.m.p13n p13n.enginegridlist vbox toolbar title toolbarseparator toolbarspacer button gridlist customlistitem flexitemdata","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_648","file":"src/02/01/z2ui5_cl_smpc_app_648.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.p13n.EngineGridTable","entity":"sap.m.p13n.Engine","title":"Personalization for grid table","summary":"Grid Table using the personalization Engine","keywords":"engine sap.m.p13n p13n.enginegridtable table overflowtoolbar title toolbarseparator toolbarspacer button menu illustratedmessage label","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_649","file":"src/02/01/z2ui5_cl_smpc_app_649.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.p13n.EngineMultipleController","entity":"sap.m.p13n.Engine","title":"Personalization with multiple SelectionControllers","summary":"Personalization for Reponsive Table using multiple SelectionControllers","keywords":"engine sap.m.p13n p13n.enginemultiplecontroller table overflowtoolbar title toolbarseparator toolbarspacer button menu actionitem dragdropinfo","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_650","file":"src/02/01/z2ui5_cl_smpc_app_650.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.p13n.Popup","entity":"sap.m.p13n.Popup","title":"p13n.Popup usage","summary":"Dialog with sap.m.p13n/* Panels","keywords":"popup sap.m.p13n p13n.popup vbox button selectionpanel sortpanel grouppanel codeeditor","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_651","file":"src/02/01/z2ui5_cl_smpc_app_651.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.VariantManagement","entity":"sap.m.VariantManagement","title":"VariantManagement using dedicated items","summary":"VariantManagement with dedicated items","keywords":"variantmanagement variant management sap.m panel overflowtoolbar title toolbarspacer button dynamicpage dynamicpagetitle","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_652","file":"src/02/01/z2ui5_cl_smpc_app_652.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.UploadSetwithTablePlugin.FileNameValidationSample","entity":"sap.m.plugins.UploadSetwithTable","title":"Plugin for Responsive Table (sap.m.Table) - File Name validation configuration","summary":"This example demonstrates the usage of fileNameValidationConfig property to configure file name validation for renaming a file.","keywords":"uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.filenamevalidationsample dynamicpage vbox messagestrip text hbox checkbox","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_653","file":"src/02/01/z2ui5_cl_smpc_app_653.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.UploadSetwithTablePlugin.FilePreviewCustomPageContent","entity":"sap.m.plugins.UploadSetwithTable","title":"Plugin for Responsive Table (sap.m.Table) - File Preview with Custom Page Content for non supported file types","summary":"This example showcases how to display custom page content for non supported file types in the FilePreviewDialog control.","keywords":"uploadsetwithtable upload setwith table sap.m.plugins filepreviewcustompagecontent dynamicpage vbox messagestrip overflowtoolbar title toolbarspacer","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_654","file":"src/02/01/z2ui5_cl_smpc_app_654.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.UploadSetwithTablePlugin.GridTableSimple","entity":"sap.m.plugins.UploadSetwithTable","title":"Plugin for Grid Table (sap.ui.table.Table)","summary":"This example demonstrates the usage of UploadSetwithTable plugin for grid table with the features of upload, download, drag & drop, remove and rename of files. It also demonstrates how the uploaded files can be displayed in a table.","keywords":"uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.gridtablesimple dynamicpage overflowtoolbar title toolbarspacer actionsplaceholder button","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_655","file":"src/02/01/z2ui5_cl_smpc_app_655.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.UploadSetwithTablePlugin.MultiplePluginInstances","entity":"sap.m.plugins.UploadSetwithTable","title":"Plugin for Responsive Table (sap.m.Table) - Multiple plugin instances with multiple tables","summary":"This example demonstrates the usage of multiple plugin instances with multiple tables. The plugin instances are created for each table and the uploaded files are displayed in their respective tables.","keywords":"uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.multipleplugininstances dynamicpage vbox overflowtoolbar title toolbarspacer searchfield","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_656","file":"src/02/01/z2ui5_cl_smpc_app_656.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableFileDialogs","entity":"sap.m.plugins.UploadSetwithTable","title":"Plugin for Responsive Table (sap.m.Table) - File upload with user dialogs","summary":"This example demonstrates usage of itemValidationHandler callback to leverage additional validations and configurations for the items that are to be uploaded, and also the manual trigger of the upload process.","keywords":"uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.responsivetablefiledialogs dynamicpage overflowtoolbar title toolbarspacer searchfield overflowtoolbarlayoutdata","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_657","file":"src/02/01/z2ui5_cl_smpc_app_657.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableFilePreview","entity":"sap.m.plugins.UploadSetwithTable","title":"Plugin for Responsive Table (sap.m.Table) - File Preview","summary":"This example showcases how uploaded files can be previewed with FilePreviewDialog control and its related configuration. UploadSetwithTable plugin creates and uses default instance of FilePreviewDialog, if not defined.","keywords":"uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.responsivetablefilepreview dynamicpage overflowtoolbar title toolbarspacer searchfield overflowtoolbarlayoutdata","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_658","file":"src/02/01/z2ui5_cl_smpc_app_658.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableProgressIndicator","entity":"sap.m.plugins.UploadSetwithTable","title":"Plugin for Responsive Table (sap.m.Table) - Upload Progress and Upload Termination","summary":"This example demonstrates the progress or termination of the items that are being uploaded. The upload progress is displayed for each item that is being uploaded. The users can terminate the upload process at any time.","keywords":"uploadsetwithtable upload setwith table sap.m.plugins responsivetableprogressindicator dynamicpage overflowtoolbar title toolbarspacer searchfield overflowtoolbarlayoutdata","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_659","file":"src/02/01/z2ui5_cl_smpc_app_659.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableSimple","entity":"sap.m.plugins.UploadSetwithTable","title":"Plugin for Responsive Table (sap.m.Table)","summary":"This example demonstrates the usage of UploadSetwithTable plugin for responsive table with the features of upload, download, drag & drop, remove and rename of files. It also demonstrates how the uploaded files can be displayed in a table.","keywords":"uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.responsivetablesimple dynamicpage overflowtoolbar title toolbarspacer searchfield overflowtoolbarlayoutdata","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_660","file":"src/02/01/z2ui5_cl_smpc_app_660.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.UploadSetwithTablePlugin.TreeTableSimple","entity":"sap.m.plugins.UploadSetwithTable","title":"Plugin for Tree Table (sap.ui.table.TreeTable)","summary":"This example demonstrates the usage of UploadSetwithTable plugin for tree table with the features of upload, download, drag & drop, remove and rename of files. It also demonstrates how the uploaded files can be displayed in a table.","keywords":"uploadsetwithtable upload setwith table sap.m.plugins uploadsetwithtableplugin.treetablesimple dynamicpage treetable overflowtoolbar title toolbarspacer actionsplaceholder","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_661","file":"src/02/01/z2ui5_cl_smpc_app_661.clas.abap","category":"src/02","library":"sap.m","sample":"sap.m.sample.UploadSetwithTablePlugin.TreeTableWithFolderHierarchy","entity":"sap.m.plugins.UploadSetwithTable","title":"Plugin for Tree Table with folder hierarchy & folder uploads","summary":"This example demonstrates the usage of UploadSetwithTable plugin with a tree table featuring folder hierarchy, folder creation, folder uploads, folder navigation with breadcrumbs and folder management","keywords":"uploadsetwithtable upload setwith table sap.m.plugins treetablewithfolderhierarchy dynamicpage treetable overflowtoolbar breadcrumbs link actionsplaceholder","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_662","file":"src/02/04/z2ui5_cl_smpc_app_662.clas.abap","category":"src/02","library":"sap.f","sample":"sap.f.sample.AvatarGroup","entity":"sap.f.AvatarGroup","title":"Avatar Group","summary":"This sample demonstrates the different group types and item sizes of the AvatarGroup control.","keywords":"avatargroup avatar group sap.f slider verticallayout label avatargroupitem popover card hbox vbox","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_663","file":"src/02/04/z2ui5_cl_smpc_app_663.clas.abap","category":"src/02","library":"sap.f","sample":"sap.f.sample.SidePanel","entity":"sap.f.SidePanel","title":"Side Panel","summary":"Demonstrates the basic usage of Side Panel.","keywords":"sidepanel side panel sap.f button vbox label switch select listitem text sidepanelitem","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_664","file":"src/02/04/z2ui5_cl_smpc_app_664.clas.abap","category":"src/02","library":"sap.f","sample":"sap.f.sample.SidePanelOverflow","entity":"sap.f.SidePanel","title":"Side Panel with overflow menu","summary":"Demonstrates the usage of Side Panel with overflow menu on desktop and tablet devices.","keywords":"sidepanel side panel sap.f sidepaneloverflow button vbox label switch text sidepanelitem","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_665","file":"src/02/04/z2ui5_cl_smpc_app_665.clas.abap","category":"src/02","library":"sap.f","sample":"sap.f.sample.SidePanelResizable","entity":"sap.f.SidePanel","title":"Resizable Side Panel","summary":"Demonstrates the usage of resizable Side Panel.","keywords":"sidepanel side panel sap.f sidepanelresizable button vbox label switch text sidepanelitem input","status":"generated","deviations":["IMPROVISED","NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_666","file":"src/02/04/z2ui5_cl_smpc_app_666.clas.abap","category":"src/02","library":"sap.f","sample":"sap.f.sample.ProductSwitchItemWithImageSrc","entity":"sap.f.ProductSwitch","title":"Product Switch with imageSrc","summary":"This sample demonstrates the usage of Product Switch Item with imageSrc, configurable by the app developer.","keywords":"productswitch product switch sap.f productswitchitemwithimagesrc verticallayout button text responsivepopover productswitchitem","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_667","file":"src/02/04/z2ui5_cl_smpc_app_667.clas.abap","category":"src/02","library":"sap.f","sample":"sap.f.sample.HeroBannerBasic","entity":"sap.f.HeroBanner","title":"Hero Banner - Basic","summary":"A basic Hero Banner with a header text and overline text.","keywords":"herobanner hero banner sap.f herobannerbasic vbox","status":"generated","deviations":["POST_171"]}, + {"class":"z2ui5_cl_smpc_app_668","file":"src/02/04/z2ui5_cl_smpc_app_668.clas.abap","category":"src/02","library":"sap.f","sample":"sap.f.sample.HeroBannerColumnsRatio","entity":"sap.f.HeroBanner","title":"Hero Banner - Columns Ratio","summary":"Demonstrates the three columnsRatio options: single column (no endContent), Equal, and FirstWider.","keywords":"herobanner hero banner sap.f herobannercolumnsratio html title vbox button text card header","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_669","file":"src/02/04/z2ui5_cl_smpc_app_669.clas.abap","category":"src/02","library":"sap.f","sample":"sap.f.sample.HeroBannerHeaderBlockAndActionsPlacement","entity":"sap.f.HeroBanner","title":"Hero Banner - Header Block and Actions Placement","summary":"Demonstrates actionsPlacement and headerBlockPlacement properties for controlling the position of the header and actions.","keywords":"herobanner hero banner sap.f herobannerheaderblockandactionsplacement vbox button card header title","status":"generated","deviations":["POST_171"]}, + {"class":"z2ui5_cl_smpc_app_670","file":"src/02/04/z2ui5_cl_smpc_app_670.clas.abap","category":"src/02","library":"sap.f","sample":"sap.f.sample.HeroBannerIntegrationCard","entity":"sap.f.HeroBanner","title":"Hero Banner - Integration Card","summary":"Demonstrates the use of sap.ui.integration.widgets.Card inside both the startContent (default slot) and endContent aggregations of the Hero Banner.","keywords":"herobanner hero banner sap.f herobannerintegrationcard vbox button card","status":"generated","deviations":["NOTE","POST_171"]}, + {"class":"z2ui5_cl_smpc_app_671","file":"src/02/04/z2ui5_cl_smpc_app_671.clas.abap","category":"src/02","library":"sap.f","sample":"sap.f.sample.HeroBannerUseCases","entity":"sap.f.HeroBanner","title":"Hero Banner - Use Cases","summary":"A collection of common Hero Banner use cases: header actions only, content with actions, actions below header, and header at bottom.","keywords":"herobanner hero banner sap.f herobannerusecases html title vbox button text card header","status":"generated","deviations":["NOTE","POST_171"]}, {"class":"z2ui5_cl_smpc_demo_001","file":"src/04/z2ui5_cl_smpc_demo_001.clas.abap","category":"src/04","library":"sap.m","sample":"","entity":"","title":"Manage Products","summary":"Created with the 'Worklist App' tutorial. - the UI5 demo app \"Manage Products\", rebuilt as one self-contained abap2UI5 class.","keywords":"manage products app title icontabbar icontabfilter icontabseparator table toolbar toolbarspacer searchfield column","status":"demoapp","deviations":[]}, {"class":"z2ui5_cl_smpc_demo_002","file":"src/04/z2ui5_cl_smpc_demo_002.clas.abap","category":"src/04","library":"sap.m","sample":"","entity":"","title":"Browse Orders","summary":"Master-detail app for browsing orders. - the UI5 demo app \"Browse Orders\", rebuilt as one self-contained abap2UI5 class.","keywords":"browse orders app flexiblecolumnlayout viewsettingsdialog viewsettingsfilteritem viewsettingsitem title list toolbar overflowtoolbar searchfield","status":"demoapp","deviations":[]}, {"class":"z2ui5_cl_smpc_demo_003","file":"src/04/z2ui5_cl_smpc_demo_003.clas.abap","category":"src/04","library":"sap.m","sample":"","entity":"","title":"Team Calendar","summary":"Calendar demo app for team and team members. - the UI5 demo app \"Team Calendar\", rebuilt as one self-contained abap2UI5 class.","keywords":"team calendar app dynamicpagetitle title verticallayout responsivepopover planningcalendarlegend calendarlegenditem planningcalendar select button","status":"demoapp","deviations":[]}, diff --git a/docs/history.md b/docs/history.md index ff7e64743..f9eb87607 100644 --- a/docs/history.md +++ b/docs/history.md @@ -7,7 +7,51 @@ same-change discipline as AGENTS.md §10). The current point-in-time state [STATUS.md](../STATUS.md). Numbers quoted inside these sections are snapshots of their date and are NOT kept current._ -## 2026-10-08 (latest) — e2e-nightly green again: three modules that had fallen behind the app and the framework +## 2026-10-20 (latest) — controls newer than UI5 1.71 come into scope: 48 ports, coverage 669 / 669 + +**Decision (maintainer).** A sample whose control is newer than UI5 1.71 is no +longer out of scope. The rule cost 48 samples on 12 controls — `sap.m.Avatar`, +`IllustratedMessage`, `DynamicDateRange`, `ExpandableText`, the `sap.m.p13n` +Container/Engine/Popup, `VariantManagement`, `plugins.UploadSetwithTable`, +`sap.f.AvatarGroup`, `SidePanel`, `ProductSwitch` and `HeroBanner` — while +`src/02` already held 221 ports needing a newer runtime for a member. Such a +port now keeps the control 1:1 and declares it as a `POST_171` deviation +naming it, which files it under `src/02`; `generate-coverage.mjs` fails a +post-1.71 control port without that deviation, `scaffold.mjs` writes it, and +`scope-of.mjs` reports the control `IN_SCOPE`. The four `newer` entries of +`ui5/scope-exceptions.json` (apps 136/141/165/203, all already POST_171) went +with the rule, and `lib-packages.mjs` reads the release level from POST_171 +alone. + +**Ports.** Apps 624–671 in seven batches (b49, b50, b52–b56), every gate +green. What did not port 1:1, by gap: + +- **Illustration sets** cannot be registered (no `IllustrationPool` target) — + 630, 635–638 render without the `Custom`/`tnt` illustration; new ❌ row in + CAPABILITIES.md. +- **Function-typed properties** stay out of reach: `p13n.Popup.reset` (650), + `FilterPanel.itemFactory` (645/646, a Dialog improvised instead), + `UploadSetwithTable.itemValidationHandler` (656) and + `customPageContentHandler` (653); app-written `DynamicDateOption` subclasses + (642). +- **The p13n Engine** is controller JS: 645–649 keep the state in ABAP, feed + the panels via `setP13nData` and apply what `getP13nData` returns through + the Popup's `close` args. `sap.ui.fl` VariantManagement is dropped there. +- **Uploads** are emulated by vetoing `beforeUploadStarts` and adding the row + in the backend (652–661); an uploaded row has no blob to preview. +- **Render harness:** `sap.f.AvatarGroup` loops ("Rendering has been + re-started too many times") even in a minimal static view, so 662 declares a + `render_smoke` skip. + +25 ports carry `LIVE_TEST`s (event-arg expressions such as +`${$source>}.toDates( … )`, plugin calls with a live binding Context, the +session-timeout countdown) for the next e2e run to close. The advisory budget +moved by what the originals carry (+14 missing-accessibility, +13 +editable-control-without-binding, +1 event-on-disabled-control), and +`7bit_ascii` excludes 649/668/671 for the original's `Müller` and `€` — the +shared rule set in abap2UI5 changed first. + +## 2026-10-08 — e2e-nightly green again: three modules that had fallen behind the app and the framework The nightly of 2026-10-08 (run 37756011169, abap2UI5 main at 57ee33b) was red on three apps in shards 1 and 4, every other badge of the README green. diff --git a/meta/interactions/z2ui5_cl_smpc_app_351.mjs b/meta/interactions/z2ui5_cl_smpc_app_351.mjs index 7af744ff4..8ce05c786 100644 --- a/meta/interactions/z2ui5_cl_smpc_app_351.mjs +++ b/meta/interactions/z2ui5_cl_smpc_app_351.mjs @@ -45,7 +45,7 @@ const SPLITTER = `ui5All().find((c) => !c.bIsDestroyed && c.getMetadata().getNam // (measured 2026-08-21). const press = async (page, name) => { await Promise.all([ - page.waitForResponse((r) => r.request().method() === 'POST' && r.url().includes(':3000'), { timeout: 15000 }), + page.waitForResponse((r) => r.request().method() === 'POST' && new URL(r.url()).origin === new URL(page.url()).origin, { timeout: 15000 }), page.getByRole('button', { name, exact: true }).click(), ]); // The RESPONSE is not the RE-RENDER. abap2UI5 rebuilds the view after the diff --git a/meta/interactions/z2ui5_cl_smpc_app_353.mjs b/meta/interactions/z2ui5_cl_smpc_app_353.mjs index fe7fa9203..fa0abc0a0 100644 --- a/meta/interactions/z2ui5_cl_smpc_app_353.mjs +++ b/meta/interactions/z2ui5_cl_smpc_app_353.mjs @@ -50,7 +50,7 @@ const selectRow = async (page, tableId, index) => { const n = await cells.count(); if (n <= index) throw new Error(`${tableId} rendered ${n} row selector cell(s), need index ${index}`); await Promise.all([ - page.waitForResponse((r) => r.request().method() === 'POST' && r.url().includes(':3000'), { timeout: 15000 }), + page.waitForResponse((r) => r.request().method() === 'POST' && new URL(r.url()).origin === new URL(page.url()).origin, { timeout: 15000 }), dispatchMouse(cells.nth(index)), ]); }; diff --git a/meta/interactions/z2ui5_cl_smpc_app_600.mjs b/meta/interactions/z2ui5_cl_smpc_app_600.mjs index c013a4477..e783b523e 100644 --- a/meta/interactions/z2ui5_cl_smpc_app_600.mjs +++ b/meta/interactions/z2ui5_cl_smpc_app_600.mjs @@ -2,6 +2,27 @@ import { waitForUi5, ui5All } from '../../scripts/lib-e2e.mjs'; export default async (page, expect) => { + // backend round trips in flight - every POST to the app's own origin + let inflight = 0; + const own = (r) => r.method() === 'POST' && new URL(r.url()).origin === new URL(page.url()).origin; + page.on('request', (r) => { if (own(r)) inflight++; }); + const done = (r) => { if (own(r)) inflight = Math.max(0, inflight - 1); }; + page.on('requestfinished', done); + page.on('requestfailed', done); + // no POST in flight for 500 ms in a row (a probe's POST starts a beat after + // the firing that caused it, so one idle sample is not enough) + const settle = async () => { + const deadline = Date.now() + 15000; + let idleSince = null; + for (;;) { + if (inflight === 0) { + idleSince ??= Date.now(); + if (Date.now() - idleSince >= 500) return; + } else idleSince = null; + if (Date.now() > deadline) throw new Error(`backend round trips still in flight after 15 s (${inflight})`); + await new Promise((r) => setTimeout(r, 50)); + } + }; await waitForUi5(page, () => { const t = ui5All().find((c) => c.getMetadata().getName() === 'sap.m.Tree'); return t && t.getMode() === 'MultiSelect' && t.getItems().length >= 2; @@ -54,14 +75,12 @@ export default async (page, expect) => { // Each veto probe is a real round trip - the wire fires DRAG_START whether or // not the default was prevented. An event dispatched while one is still in // flight is swallowed, which is why the drop below silently did nothing when - // it followed the probes directly. Wait for the round trips to land: the - // global BusyIndicator element is shown for the whole request and hidden - // again when the response is applied. - await page.waitForFunction(() => { - const b = document.getElementById('sapUiBusyIndicator'); - return !b || getComputedStyle(b).visibility === 'hidden'; - }, null, { timeout: 15000 }); - + // it followed the probes directly. Wait for the round trips to land by + // counting the backend POSTs themselves: the global BusyIndicator used for + // this until 2026-10-20 appears only after UI5's show DELAY, so under the + // load of a full-corpus run it still read "hidden" while a probe was in + // flight, and the drop was swallowed again (nightly-style run, 1 of 676). + await settle(); // and the drop still reparents: Node2 onto Node1, the backend moves the node // and the tree redraws with one root left await page.evaluate(() => { diff --git a/meta/interactions/z2ui5_cl_smpc_app_625.mjs b/meta/interactions/z2ui5_cl_smpc_app_625.mjs new file mode 100644 index 000000000..2fcadf4d2 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_625.mjs @@ -0,0 +1,86 @@ +// AvatarActiveState: the Avatar press round-trip toggles the two-way bound +// `active` flag and follows up with control_by_id userMenu openBy myAvatar / +// close; a list item press closes the menu; the Popover's afterClose +// (POPOVER_CLOSE) resets the flag when the menu is dismissed any other way. +// +// Every leg asserts BOTH halves of the wire on the RENDERED controls - the +// Avatar's bound active property (only the backend writes it) and the +// Popover's open state (only the follow-up action changes it) - read off the +// controls that are still in the document (the outgoing view stays in the +// registry while a round-trip rebuilds it). +import { waitForUi5, waitForIdle, UI5_ALL_SRC } from '../../scripts/lib-e2e.mjs'; + +const state = () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const av = ui5All().find((c) => c.getMetadata().getName() === 'sap.m.Avatar' && c.getId().endsWith('myAvatar') && live(c)); + const pop = ui5All().find((c) => c.getMetadata().getName() === 'sap.m.Popover' && c.getId().endsWith('userMenu') && !c.bIsDestroyed); + return { active: av ? av.getActive() : null, open: pop ? pop.isOpen() : null }; +}; + +async function waitState(page, want, msg) { + await waitForUi5(page, (w) => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const av = ui5All().find((c) => c.getMetadata().getName() === 'sap.m.Avatar' && c.getId().endsWith('myAvatar') && live(c)); + const pop = ui5All().find((c) => c.getMetadata().getName() === 'sap.m.Popover' && c.getId().endsWith('userMenu') && !c.bIsDestroyed); + if (!av || !pop) return false; + const os = pop.oPopup && pop.oPopup.getOpenState(); + // a popup that is OPENING/CLOSING is not settled yet + if (os === 'OPENING' || os === 'CLOSING') return false; + return av.getActive() === w.active && pop.isOpen() === w.open; + }, msg, want); + await waitForIdle(page); +} + +async function pressAvatar(page) { + // the Avatar is an ; focus + Enter goes through its own + // press handling even where the unthemed box would refuse a click + await page.evaluate(() => { + const el = [...document.querySelectorAll('[id$="myAvatar"]')].find((e) => document.body.contains(e)); + el.focus(); + }); + await page.keyboard.press('Enter'); +} + +export default async (page, expect) => { + // the unthemed Avatar measures 0x0 (no sapFAvatar CSS, and its image comes + // from sdk.openui5.org, which the harness 404s) - require it in the DOM + await waitForUi5(page, () => ui5All().some((c) => c.getMetadata().getName() === 'sap.m.Avatar' && c.getId().endsWith('myAvatar') && c.getDomRef() && c.hasListeners('press')), + 'the press-wired Avatar myAvatar did not render'); + await waitForIdle(page); + await expect(await page.evaluate(`(() => { ${UI5_ALL_SRC} return (${state.toString()})(); })()`), 'the initial state (inactive, menu closed)') + .toEqual({ active: false, open: false }); + + // 1st press: AVATAR_PRESS -> active = true + openBy myAvatar + await pressAvatar(page); + await waitState(page, { active: true, open: true }, 'the first Avatar press did not set the bound active flag and open the user menu by the Avatar'); + await expect(page.locator('.sapMPopover').filter({ hasText: 'Recent Activities' }).first(), 'the open user menu').toBeVisible(); + + // the menu is opened BY the Avatar (openBy myAvatar), not centred + const opener = await page.evaluate(() => { + const pop = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getMetadata().getName() === 'sap.m.Popover' && c.getId().endsWith('userMenu') && !c.bIsDestroyed); + const o = pop && pop._oOpenBy; + return o ? (o.id || o.getId?.() || '') : ''; + }); + await expect(/myAvatar/.test(opener), `the user menu's opener is the Avatar (got "${opener}")`).toBeTruthy(); + + // 2nd press while open: AVATAR_PRESS -> active = false + close + await pressAvatar(page); + await waitState(page, { active: false, open: false }, 'the second Avatar press did not reset the active flag and close the user menu'); + // and it STAYS closed - no autoclose/press race reopening it + await page.waitForTimeout(800); + await waitState(page, { active: false, open: false }, 'the user menu reopened (or the flag flipped back) after the second Avatar press'); + + // list item press: LIST_ITEM_PRESS -> active = false + close (afterClose round-trip follows) + await pressAvatar(page); + await waitState(page, { active: true, open: true }, 'the third Avatar press did not reopen the user menu'); + await page.locator('.sapMPopover li').filter({ hasText: 'Settings' }).first().click(); + await waitState(page, { active: false, open: false }, 'pressing the Settings list item did not close the user menu and reset the active flag'); + + // afterClose alone: dismiss with Escape - no app event but POPOVER_CLOSE resets the flag + await pressAvatar(page); + await waitState(page, { active: true, open: true }, 'the fourth Avatar press did not reopen the user menu'); + await page.keyboard.press('Escape'); + await waitState(page, { active: false, open: false }, 'closing the user menu with Escape did not reach afterClose (POPOVER_CLOSE) to reset the active flag'); +}; + diff --git a/meta/interactions/z2ui5_cl_smpc_app_638.mjs b/meta/interactions/z2ui5_cl_smpc_app_638.mjs new file mode 100644 index 000000000..410b4e689 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_638.mjs @@ -0,0 +1,76 @@ +// IllustratedMessageSessionTimeout: Open Dialog arms a backend START_TIMER +// COUNTER_TICK (1000 ms) that re-arms itself per tick; every tick pushes +// /iSecondsLeft and /bIsExpiring into the still-open popup. Proved here: the +// description counts down 3-2-1-0 in that order, the dialog then switches to +// the expired state (title, Sign In + Close visible, Continue Working gone), +// Close destroys it, and Continue Working on a fresh dialog closes it and +// stops the counter (no later tick reopens or changes anything); the global +// busy overlay is never painted during the countdown. +import { waitForUi5, waitForIdle, waitForPopup, UI5_ALL_SRC } from '../../scripts/lib-e2e.mjs'; + +const readDialog = `(() => { ${UI5_ALL_SRC} + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const dlg = ui5All().find((c) => c.getMetadata().getName() === 'sap.m.Dialog' && !c.bIsDestroyed && c.isOpen()); + if (!dlg) return null; + const im = ui5All().find((c) => c.getMetadata().getName() === 'sap.m.IllustratedMessage' && live(c)); + const btns = dlg.getButtons().filter((b) => !b.bIsDestroyed).map((b) => b.getVisible() ? b.getText() : null).filter(Boolean); + return { title: im && im.getTitle(), description: im && im.getDescription(), buttons: btns }; +})()`; + +export default async (page, expect) => { + await waitForIdle(page); + await page.getByRole('button', { name: 'Open Dialog', exact: true }).click(); + await waitForPopup(page, 'Session Info'); + + // sample the description every 100 ms until the expired state (or 15 s) + const seen = await page.evaluate(async (src) => { + const read = () => (0, eval)(src); + const out = []; + const t0 = Date.now(); + while (Date.now() - t0 < 15000) { + const d = read(); + const bi = document.getElementById('sapUiBusyIndicator'); + if (bi && bi.offsetParent !== null) out.push('BUSY'); + const s = d ? `${d.title} | ${d.description}` : 'closed'; + if (out[out.length - 1] !== s) out.push(s); + if (d && /has expired/.test(d.title || '')) break; + await new Promise((r) => setTimeout(r, 100)); + } + return out; + }, readDialog); + const counts = seen.map((s) => (s.match(/signed out in (\d+) seconds/) || [])[1]).filter(Boolean); + // 3-2-1, then straight to expired: like the original's _decrementCounter, + // the tick that reaches 0 sets iSecondsLeft 0 AND bIsExpiring false in one + // go, so "0 seconds" is never on screen there either + await expect(counts, `the description counted down 3-2-1 (saw ${JSON.stringify(seen)})`).toEqual(['3', '2', '1']); + await expect(seen[seen.length - 1], 'the dialog switched to the expired state') + .toBe('Your session has expired. | Sign in to pick up where you left off.'); + + // no visible busy overlay between ticks: a plain START_TIMER tick calls + // BusyIndicator.show( ) with UI5's default 1000 ms delay, so a tick that + // answers inside a second never paints it (it IS raised once per tick - + // 4 show( ) calls for open + 3 ticks, measured 2026-10-20) + await expect(seen.includes('BUSY'), `the busy overlay showed during the countdown (${JSON.stringify(seen)})`).toBe(false); + const expired = await page.evaluate(readDialog); + await expect(expired && expired.buttons, 'the expired dialog shows Sign In and Close, not Continue Working').toEqual(['Sign In', 'Close']); + await waitForIdle(page); + + // Close (DIALOG_CLOSE) destroys the popup + await page.getByRole('button', { name: 'Close', exact: true }).click(); + await waitForUi5(page, () => !ui5All().some((c) => c.getMetadata().getName() === 'sap.m.Dialog' && !c.bIsDestroyed && c.isOpen()), + 'Close in the expired dialog did not destroy the Session Info dialog'); + await waitForIdle(page); + + // a fresh dialog, then Continue Working while it is counting: closes it and + // the pending/next tick must not bring anything back + await page.getByRole('button', { name: 'Open Dialog', exact: true }).click(); + await waitForPopup(page, 'Session Info'); + const fresh = await page.evaluate(readDialog); + await expect(fresh && fresh.title, 'a reopened dialog starts in the expiring state again').toBe('Your session will expire soon.'); + await expect(fresh && fresh.buttons, 'the expiring dialog shows only Continue Working').toEqual(['Continue Working']); + await page.getByRole('button', { name: 'Continue Working', exact: true }).click(); + await waitForUi5(page, () => !ui5All().some((c) => c.getMetadata().getName() === 'sap.m.Dialog' && !c.bIsDestroyed && c.isOpen()), + 'Continue Working did not close the Session Info dialog'); + await page.waitForTimeout(4000); + await expect(await page.evaluate(readDialog), 'no tick reopened the dialog after Continue Working').toBe(null); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_639.mjs b/meta/interactions/z2ui5_cl_smpc_app_639.mjs new file mode 100644 index 000000000..63b7fc740 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_639.mjs @@ -0,0 +1,45 @@ +// the payments filter: DynamicDateRange change -> valueState + binding_call filter +// Driven like a user selection: setValue + fireChange({ value, valid }), the +// event the DynamicDateRange itself fires when its popover's Apply commits. +// The wire is ${$source>}.toDates(value)[0|1]; the backend answers with the +// valueState and a binding_call filter on the payments-table items. +// toDates() returns sap.ui.core.date.UniversalDate, not a Date: without the +// port's .getJSDate() (guarded for the one-date FROM/TO, whose [1] is +// undefined) the arg reached ABAP as {oDate, sCalendarType} instead of the +// local ISO string, and the BT/GT filter matched 0 rows (red until 2026-10-21). +import { waitForUi5, ui5All } from '../../scripts/lib-e2e.mjs'; + +const fire = (page, value, valid) => page.evaluate(([v, ok]) => { + const ddr = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getMetadata().getName() === 'sap.m.DynamicDateRange'); + // the values travel as [y, m, d] triples - a Date does not survive evaluate( ) + const value = v && { operator: v.operator, values: v.values.map((d) => new Date(d[0], d[1], d[2])) }; + ddr.setValue(value); + ddr.fireChange({ value, valid: ok }); +}, [value, valid]); + +const state = ([r, s]) => { + const t = ui5All().find((x) => /payments-table$/.test(x.getId()) && !x.bIsDestroyed); + const d = ui5All().find((x) => x.getMetadata().getName() === 'sap.m.DynamicDateRange' && !x.bIsDestroyed); + return !!t && !!d && t.getItems().length === r && d.getValueState() === s; +}; + +export default async (page, expect) => { + await waitForUi5(page, state, 'the payments-table never came up with its 16 rows and valueState None', [16, 'None']); + + // an invalid entry: setValueState(Error) round-trips, the rows stay + await fire(page, { operator: 'DATERANGE', values: [[2021, 5, 1], [2021, 5, 30]] }, false); + await waitForUi5(page, state, 'valid=false never set the valueState to Error', [16, 'Error']); + + // a June 2021 range: BT over the two toDates dates keeps only the June 2021 rows + await fire(page, { operator: 'DATERANGE', values: [[2021, 5, 1], [2021, 5, 30]] }, true); + await waitForUi5(page, state, 'the June 2021 DATERANGE never filtered the payments-table to its 2 June 2021 rows (toDates -> BT binding_call)', [2, 'None']); + + // FROM 9 June 2021 maps to GT on toDates()[0] + await fire(page, { operator: 'FROM', values: [[2021, 5, 9]] }, true); + await waitForUi5(page, state, 'FROM 9 June 2021 never filtered to the 15 rows after 9 June 2021 00:00 (GT)', [15, 'None']); + + // a cleared value sends no dates and clears the filter + await fire(page, null, true); + await waitForUi5(page, state, 'clearing the value never cleared the filter', [16, 'None']); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_640.mjs b/meta/interactions/z2ui5_cl_smpc_app_640.mjs new file mode 100644 index 000000000..f2e8f6d84 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_640.mjs @@ -0,0 +1,46 @@ +// the payments filter with calendarWeekNumbering MiddleEastern: change -> valueState + binding_call filter +// Driven like a user selection: setValue + fireChange({ value, valid }), the +// event the DynamicDateRange itself fires when its popover's Apply commits. +// The wire is ${$source>}.toDates(value)[0|1]; the backend answers with the +// valueState and a binding_call filter on the payments-table items. +// toDates() returns sap.ui.core.date.UniversalDate, not a Date: without the +// port's .getJSDate() (guarded for the one-date FROM/TO, whose [1] is +// undefined) the arg reached ABAP as {oDate, sCalendarType} instead of the +// local ISO string, and the BT/GT filter matched 0 rows (red until 2026-10-21). +import { waitForUi5, ui5All } from '../../scripts/lib-e2e.mjs'; + +const fire = (page, value, valid) => page.evaluate(([v, ok]) => { + const ddr = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getMetadata().getName() === 'sap.m.DynamicDateRange'); + // the values travel as [y, m, d] triples - a Date does not survive evaluate( ) + const value = v && { operator: v.operator, values: v.values.map((d) => new Date(d[0], d[1], d[2])) }; + ddr.setValue(value); + ddr.fireChange({ value, valid: ok }); +}, [value, valid]); + +const state = ([r, s]) => { + const t = ui5All().find((x) => /payments-table$/.test(x.getId()) && !x.bIsDestroyed); + const d = ui5All().find((x) => x.getMetadata().getName() === 'sap.m.DynamicDateRange' && !x.bIsDestroyed); + return !!t && !!d && t.getItems().length === r && d.getValueState() === s; +}; + +export default async (page, expect) => { + await waitForUi5(page, state, 'the payments-table never came up with its 16 rows and valueState None', [16, 'None']); + await waitForUi5(page, () => ui5All().some((c) => c.getMetadata().getName() === 'sap.m.DynamicDateRange' + && c.getCalendarWeekNumbering() === 'MiddleEastern'), 'the DynamicDateRange never carried calendarWeekNumbering MiddleEastern'); + // an invalid entry: setValueState(Error) round-trips, the rows stay + await fire(page, { operator: 'DATERANGE', values: [[2021, 5, 1], [2021, 5, 30]] }, false); + await waitForUi5(page, state, 'valid=false never set the valueState to Error', [16, 'Error']); + + // a June 2021 range: BT over the two toDates dates keeps only the June 2021 rows + await fire(page, { operator: 'DATERANGE', values: [[2021, 5, 1], [2021, 5, 30]] }, true); + await waitForUi5(page, state, 'the June 2021 DATERANGE never filtered the payments-table to its 2 June 2021 rows (toDates -> BT binding_call)', [2, 'None']); + + // FROM 9 June 2021 maps to GT on toDates()[0] + await fire(page, { operator: 'FROM', values: [[2021, 5, 9]] }, true); + await waitForUi5(page, state, 'FROM 9 June 2021 never filtered to the 15 rows after 9 June 2021 00:00 (GT)', [15, 'None']); + + // a cleared value sends no dates and clears the filter + await fire(page, null, true); + await waitForUi5(page, state, 'clearing the value never cleared the filter', [16, 'None']); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_641.mjs b/meta/interactions/z2ui5_cl_smpc_app_641.mjs new file mode 100644 index 000000000..e511fb0aa --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_641.mjs @@ -0,0 +1,50 @@ +// DynamicDateRangeHidden: three anchors (two Buttons, a Link) open ONE +// hideInput DynamicDateRange through a round-trip-free control_by_id openBy +// carrying $event.oSource.sId; its change round-trips the operator, the value +// count and values[0]/[1] as ` + ''`, and ABAP composes the toast. +// +// Booted THEMED (sidecar e2e_smoke.theme): unthemed, the opened popover's +// focus restore bounces off the hidden input and Popover.onfocusin recurses +// until the stack overflows - the original's own openBy(getDomRef()) does the +// same headless, so it is the harness (the 016 class), not the port. +import { waitForUi5, ui5All } from '../../scripts/lib-e2e.mjs'; + +const isOpen = () => { + const ddr = ui5All().find((c) => c.getMetadata().getName() === 'sap.m.DynamicDateRange'); + return !!ddr && !!ddr._oPopup && ddr._oPopup.isOpen(); +}; + +export default async (page, expect) => { + await waitForUi5(page, () => { + const ddr = ui5All().find((c) => c.getMetadata().getName() === 'sap.m.DynamicDateRange' && c.getId().endsWith('HiddenDDR')); + const anchors = ui5All().filter((c) => ['sap.m.Button', 'sap.m.Link'].includes(c.getMetadata().getName()) + && c.getDomRef() && c.getAriaHasPopup && c.getAriaHasPopup() === 'Dialog'); + return !!ddr && ddr.getHideInput() === true && anchors.length === 3; + }, 'the hidden DynamicDateRange and its three anchors did not all render'); + + // the text Button opens the hidden picker anchored to itself (openBy, no round trip) + await page.getByRole('button', { name: 'Open Dynamic Date Range', exact: true }).first().click(); + await waitForUi5(page, isOpen, 'the Button anchor never opened the hidden DynamicDateRange (control_by_id openBy)'); + + // a real pick: "Today" applies at once, fires change, and ABAP composes the toast + await page.locator('.sapMPopover li').filter({ hasText: /^\s*Today\s*$/ }).first().click(); + await expect(page.locator('.sapMMessageToast').last(), 'the ABAP-composed toast for the Today pick') + .toContainText('Operator: TODAY'); + + // the Link opens it too + await page.locator('a.sapMLnk').filter({ hasText: 'Open Dynamic Date Range' }).first().click(); + await waitForUi5(page, isOpen, 'the Link anchor never opened the hidden DynamicDateRange (control_by_id openBy)'); + + // a two-value selection, committed like the popover's Apply: both Dates reach the toast as their toString + await page.evaluate(() => { + const ddr = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getMetadata().getName() === 'sap.m.DynamicDateRange'); + const value = { operator: 'DATERANGE', values: [new Date(2021, 5, 1), new Date(2021, 5, 30)] }; + ddr.setValue(value); + ddr.fireChange({ value, valid: true }); + }); + const toast = page.locator('.sapMMessageToast').filter({ hasText: 'DATERANGE' }).last(); + await expect(toast, 'the DATERANGE toast operator').toContainText('Operator: DATERANGE'); + await expect(toast, 'the DATERANGE toast first value').toContainText('Value 1: Tue Jun 01 2021'); + await expect(toast, 'the DATERANGE toast second value').toContainText('Value 2: Wed Jun 30 2021'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_642.mjs b/meta/interactions/z2ui5_cl_smpc_app_642.mjs new file mode 100644 index 000000000..53ca27e25 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_642.mjs @@ -0,0 +1,46 @@ +// the orders filter: DynamicDateRange change -> valueState + binding_call filter +// Driven like a user selection: setValue + fireChange({ value, valid }), the +// event the DynamicDateRange itself fires when its popover's Apply commits. +// The wire is ${$source>}.toDates(value)[0|1]; the backend answers with the +// valueState and a binding_call filter on the orders-table items. +// toDates() returns sap.ui.core.date.UniversalDate, not a Date: without the +// port's .getJSDate() (guarded for the one-date FROM/TO, whose [1] is +// undefined) the arg reached ABAP as {oDate, sCalendarType} instead of the +// local ISO string, and the BT/GT filter matched 0 rows (red until 2026-10-21). +import { waitForUi5, ui5All } from '../../scripts/lib-e2e.mjs'; + +const fire = (page, value, valid) => page.evaluate(([v, ok]) => { + const ddr = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getMetadata().getName() === 'sap.m.DynamicDateRange'); + // the values travel as [y, m, d] triples - a Date does not survive evaluate( ) + const value = v && { operator: v.operator, values: v.values.map((d) => new Date(d[0], d[1], d[2])) }; + ddr.setValue(value); + ddr.fireChange({ value, valid: ok }); +}, [value, valid]); + +const state = ([r, s]) => { + const t = ui5All().find((x) => /orders-table$/.test(x.getId()) && !x.bIsDestroyed); + const d = ui5All().find((x) => x.getMetadata().getName() === 'sap.m.DynamicDateRange' && !x.bIsDestroyed); + return !!t && !!d && t.getItems().length === r && d.getValueState() === s; +}; + +export default async (page, expect) => { + await waitForUi5(page, state, 'the orders-table never came up with its 28 rows and valueState None', [28, 'None']); + + // an invalid entry: setValueState(Error) round-trips, the rows stay + await fire(page, { operator: 'DATERANGE', values: [[2021, 5, 1], [2021, 5, 30]] }, false); + await waitForUi5(page, state, 'valid=false never set the valueState to Error', [28, 'Error']); + + // a June 2021 range: BT over the two toDates dates keeps only the June 2021 rows + await fire(page, { operator: 'DATERANGE', values: [[2021, 5, 1], [2021, 5, 30]] }, true); + await waitForUi5(page, state, 'the June 2021 DATERANGE never filtered the orders-table to its 4 June 2021 rows (toDates -> BT binding_call)', [4, 'None']); + + // FROM maps to GT on toDates()[0] - over PERFOMDATETIME, kept 1:1 with the original's + // copied _createFilter: no order carries that path, so every row is hidden + await fire(page, { operator: 'FROM', values: [[2021, 5, 9]] }, true); + await waitForUi5(page, state, 'FROM never hid every row - kept 1:1, the original filters the path PerfomDateTime no order carries', [0, 'None']); + + // a cleared value sends no dates and clears the filter + await fire(page, null, true); + await waitForUi5(page, state, 'clearing the value never cleared the filter', [28, 'None']); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_644.mjs b/meta/interactions/z2ui5_cl_smpc_app_644.mjs new file mode 100644 index 000000000..a627fbb82 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_644.mjs @@ -0,0 +1,51 @@ +// p13n.Container in a Dialog and a ResponsivePopover: "Add custom view" is a +// backend row plus a view rebuild, and the follow-up action queued behind it +// must re-open d1/p1 on the REBUILT view - with the fourth view in it +import { waitForIdle, waitForUi5, waitForPopup } from '../../scripts/lib-e2e.mjs'; + +// open popup with this id, its p13n.Container carrying n views (live control +// only). n counts the Container's own "$default" navigation view, which list +// layout adds in front of the three static ones - and so does the original's +// addCustomView, which names the new view "View " + getViews().length: the +// last view must be View / key view, so the first added one is +// "View 4" / view4, never a second "View 3" +const openWithViews = (want) => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const pop = ui5All().find((c) => c.getId().endsWith('--' + want.pop) && !c.bIsDestroyed && c.isOpen && c.isOpen()); + const cont = ui5All().find((c) => c.getId().endsWith('--' + want.cont) && live(c)); + const last = cont && cont.getViews()[want.n - 1]; + return !!pop && !!cont && cont.getViews().length === want.n + && last.getText() === `View ${want.n - 1}` && last.getKey() === `view${want.n - 1}`; +}; + +export default async (page, expect) => { + await waitForIdle(page); + // Dialog (the default choice) + await page.getByRole('button', { name: 'Show P13nContainer used in Popup' }).click(); + await waitForPopup(page, 'My custom p13n Dialog'); + await waitForUi5(page, openWithViews, 'the Dialog did not open with its three static views', + { pop: 'd1', cont: 'P13nContainer', n: 4 }); + await waitForIdle(page); + await page.getByRole('button', { name: 'Add custom view' }).first().click(); + await waitForIdle(page); + await waitForUi5(page, openWithViews, + 'Add custom view (dialog) did not come back as an OPEN d1 whose container carries a fourth view "View 4" (key view4)', + { pop: 'd1', cont: 'P13nContainer', n: 5 }); + await page.getByRole('button', { name: 'Close Dialog' }).click(); + await waitForUi5(page, () => !ui5All().some((c) => c.getId().endsWith('--d1') && !c.bIsDestroyed && c.isOpen()), + 'Close Dialog did not close d1'); + + // Popover: pick it in the two-way bound RadioButtonGroup, then open + await page.getByRole('radio', { name: 'Popover' }).click(); + await waitForIdle(page); + await page.getByRole('button', { name: 'Show P13nContainer used in Popup' }).click(); + await waitForPopup(page, 'My custom p13n Popover'); + await waitForUi5(page, openWithViews, 'the two-way bound "Popover" choice did not open p1', + { pop: 'p1', cont: 'P13nContainerPopover', n: 4 }); + await waitForIdle(page); + await (await waitForPopup(page, 'My custom p13n Popover')).getByRole('button', { name: 'Add custom view' }).click(); + await waitForIdle(page); + await waitForUi5(page, openWithViews, + 'Add custom view (popover) did not come back as an OPEN p1 whose container carries a fourth view "View 4" (key view4)', + { pop: 'p1', cont: 'P13nContainerPopover', n: 5 }); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_645.mjs b/meta/interactions/z2ui5_cl_smpc_app_645.mjs new file mode 100644 index 000000000..ec2959a9e --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_645.mjs @@ -0,0 +1,172 @@ +// p13n.Engine: the Settings button sends setP13nData and opens the p13n.Popup; +// its close wire hands the panels' getP13nData( true ) back and the backend +// re-orders/shows the columns and sorts the rows. Then the column menu: its +// beforeOpen round-trip fills the QuickSort item, and a quick sort re-sorts. +import { waitForIdle, waitForUi5, revealInOverflow } from '../../scripts/lib-e2e.mjs'; + +// the rendered table's visible column headers and its rows' first cells, in order +const tableState = () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && live(c)); + if (!t) return null; + const cols = t.getColumns().filter((c) => c.getVisible()).map((c) => { + const h = c.getHeader(); + return h && h.getText ? h.getText() : ''; + }); + const rows = t.getItems().filter((i) => i.isA('sap.m.ColumnListItem')).map((i) => i.getCells().map((x) => x.getText())); + return { cols, rows, sort: t.getColumns().map((c) => c.getSortIndicator()) }; +}; + +export default async (page, expect) => { + // the frontend logs a failed view rebuild and carries on with an empty page + const rebuildErrors = []; + page.on('console', (m) => { const d = /duplicate id '([^']+)'/.exec(m.text()); if (d) rebuildErrors.push(d[1].replace(/^.*--/, '')); }); + const rebuildsFailed = () => (rebuildErrors.length ? ` (rebuild died: duplicate id ${rebuildErrors[0]})` : ''); + const state = () => page.evaluate(`(() => { const ui5All = () => Object.values(sap.ui.require("sap/ui/core/Element").registry.all()); return (${tableState.toString()})(); })()`); + await waitForIdle(page); + const before = await state(); + expect(before.cols, 'the initial visible columns').toEqual(['First Name', 'Last Name', 'City']); + + // Settings -> setP13nData + open + const settings = page.getByRole('button', { name: 'Settings' }); + await revealInOverflow(page, settings); + await settings.click(); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--p13nPopup-dialog') && !c.bIsDestroyed && c.isOpen()), + 'the Settings button did not open the p13n.Popup'); + await waitForIdle(page); + await waitForUi5(page, () => { + const p = ui5All().find((c) => c.getId().endsWith('--columnsPanel') && !c.bIsDestroyed); + const d = p && p.getP13nData(); + return !!d && d.length === 4 && d[3].name === 'size_col' && d[3].visible === false; + }, 'the Settings press never handed the Columns panel its setP13nData state'); + + // Columns: tick "Size" the way a user does - focus its row, press Space + const sizeRow = await page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + const p = all.find((c) => c.getId().endsWith('--columnsPanel') && !c.bIsDestroyed); + const row = p._oListControl.getItems().find((i) => i.getBindingContext(p.P13N_MODEL).getProperty('name') === 'size_col'); + return row && row.getId(); + }); + expect(!!sizeRow, 'a "Size" row in the Columns panel').toBeTruthy(); + await page.evaluate((id) => document.getElementById(id).focus(), sizeRow); + await page.keyboard.press('Space'); + // Sort: the SortPanel's state as its rows would leave it - First Name ascending + await page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + const p = all.find((c) => c.getId().endsWith('--sortPanel') && !c.bIsDestroyed); + const d = p.getP13nData(); + d.forEach((e) => { e.sorted = e.name === 'firstName_col'; e.descending = false; }); + d.sort((a, b) => (b.sorted ? 1 : 0) - (a.sorted ? 1 : 0)); + p.setP13nData(d); + }); + await page.locator('[id$="--p13nPopup-confirmBtn"]').click(); + await waitForIdle(page); + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && live(c)); + if (!t) return false; + const cols = t.getColumns().filter((c) => c.getVisible()).map((c) => (c.getHeader() || {}).getText?.()); + const first = t.getItems().filter((i) => i.isA('sap.m.ColumnListItem')).map((i) => i.getCells()[0].getText()); + return cols.join() === 'First Name,Last Name,City,Size' && first.join() === 'John,Maria,Peter,Petra,Thomas'; + }, 'closing the p13n.Popup with OK did not show the Size column and sort the rows by First Name'); + + // the column menu: beforeOpen round-trips the column's p13nKey, the backend + // fills the QuickSort/QuickGroup items while the menu is already open + await waitForIdle(page); + const cityHeader = await page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const col = all.find((c) => c.isA('sap.m.Column') && live(c) && c.data('p13nKey') === 'city_col'); + return col && col.getId(); + }); + await page.locator(`[id="${cityHeader}"]`).click(); + await waitForIdle(page); + await waitForUi5(page, () => ui5All().some((c) => c.isA('sap.m.table.columnmenu.QuickSortItem') && !c.bIsDestroyed + && c.getKey() === 'city_col' && c.getLabel() === 'City' && c.getSortOrder() === 'None'), + 'the column menu\'s beforeOpen round-trip never filled the QuickSort item with the City column'); + // the QuickSort's own "sort descending" button (icon-only, located through the registry) + const desc = await page.evaluate(() => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const b = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.isA('sap.m.Button') && live(c) && c.getIcon() === 'sap-icon://sort-descending'); + return b && b.getId(); + }); + expect(!!desc, 'the QuickSort "sort descending" button in the open column menu').toBeTruthy(); + await page.locator(`[id="${desc}"]`).click(); + await waitForIdle(page); + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && live(c)); + if (!t) return false; + const city = t.getColumns().find((c) => c.data('p13nKey') === 'city_col'); + const cities = t.getItems().filter((i) => i.isA('sap.m.ColumnListItem')).map((i) => i.getCells()[2].getText()); + return city.getSortIndicator() === 'Descending' && cities[cities.length - 1] === 'Heidelberg' && cities[0] === 'Walldorf' + && t.getColumns().filter((c) => c.getSortIndicator() !== 'None').length === 1; + }, 'the quick sort "descending" on City did not re-sort the rows (Heidelberg last) with only City carrying the sort indicator'); + + // quick group from the same menu: its Switch, toggled by keyboard + await waitForIdle(page); + const cityHeader2 = await page.evaluate(() => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const col = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.isA('sap.m.Column') && live(c) && c.data('p13nKey') === 'city_col'); + return col && col.getId(); + }); + await page.locator(`[id="${cityHeader2}"]`).click(); + await waitForIdle(page); + await waitForUi5(page, () => ui5All().some((c) => c.isA('sap.m.table.columnmenu.QuickSortItem') && !c.bIsDestroyed + && c.getKey() === 'city_col' && c.getSortOrder() === 'Descending'), + 'the re-opened column menu did not show City as sorted descending (beforeOpen round-trip)'); + const groupSwitch = await page.evaluate(() => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const sw = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()).find((c) => c.isA('sap.m.Switch') && live(c)); + return sw && sw.getId(); + }); + expect(!!groupSwitch, 'the QuickGroup switch in the open column menu').toBeTruthy(); + await page.evaluate((id) => document.getElementById(id).focus(), groupSwitch); + await page.keyboard.press('Space'); + await waitForIdle(page); + // the third view rebuild since the popup was last opened + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && live(c)); + if (!t) return false; + const heads = t.getItems().filter((i) => i.isA('sap.m.GroupHeaderListItem')).map((i) => i.getTitle()); + return heads.length === 2 && /Walldorf/.test(heads[0]) && /Heidelberg/.test(heads[1]); + }, `quick group on City did not group the rows${rebuildsFailed()}`); + + // the column drop (DragDropInfo on the columns aggregation): City's header + // dragged onto the left half of Last Name's drops it Before; the wire + // carries the dragged/dropped columns' p13nKey and the drop position + await waitForIdle(page); + const headerOf = (key) => page.evaluate((k) => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const col = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.isA('sap.m.Column') && live(c) && c.data('p13nKey') === k); + return col && col.getId(); + }, key); + const cityId = await headerOf('city_col'); + const lastId = await headerOf('lastName_col'); + const target = page.locator(`[id="${lastId}"]`); + const box = await target.boundingBox(); + const [dropReq] = await Promise.all([ + page.waitForRequest((r) => r.method() === 'POST' && /"EVENT":"COLUMN_MOVE"/.test(r.postData() || ''), { timeout: 10000 }), + page.locator(`[id="${cityId}"]`).dragTo(target, { targetPosition: { x: 4, y: box.height / 2 } }), + ]); + expect(JSON.parse(dropReq.postData()).value.S_FRONT.T_EVENT_ARG, 'the column drop arguments') + .toEqual(['city_col', 'lastName_col', 'Before']); + await waitForIdle(page); + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && live(c)); + return !!t && t.getColumns().filter((c) => c.getVisible()).map((c) => c.data('p13nKey')).join() + === 'firstName_col,city_col,lastName_col,size_col'; + }, `dropping City before Last Name did not re-order the columns${rebuildsFailed()}`); + + // the popup lives only while it is open (a POPUP-slot fragment the close + // handler destroys), so no panel outlives it - a p13n.Popup declared in the + // view leaked its never-opened panels, and two rebuilds later the + // alternating view id collided with them + await waitForUi5(page, () => !ui5All().some((c) => !c.bIsDestroyed && ['columnsPanel', 'sortPanel', 'groupPanel'].some((p) => c.getId().endsWith('--' + p))), + 'a p13n panel outlived its closed popup (the view-declared Popup leak)'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_646.mjs b/meta/interactions/z2ui5_cl_smpc_app_646.mjs new file mode 100644 index 000000000..863381b24 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_646.mjs @@ -0,0 +1,77 @@ +// EngineCustomFilters: the improvised filter Dialog's MultiInputs. Picking a +// suggestion creates a Token, whose tokenUpdate wire carries addedTokens as a +// JSON array; the backend writes it into the bound tokens aggregation, and OK +// rebuilds the table's items binding with the EQ filters +import { waitForIdle, waitForUi5, waitForPopup, revealInOverflow } from '../../scripts/lib-e2e.mjs'; + +const ROWS = () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getId().endsWith('--persoTable') && live(c)); + return t ? t.getItems().map((i) => i.getCells()[0].getText() + '/' + i.getCells()[2].getText()) : null; +}; + +export default async (page, expect) => { + await waitForIdle(page); + expect((await page.evaluate(ROWS)).length, 'the unfiltered table rows').toBe(14); + const settings = page.getByRole('button', { name: 'Settings' }); + await revealInOverflow(page, settings); + await settings.click(); + await waitForPopup(page, 'Custom Filter Settings'); + await waitForIdle(page); + + // City: type "Berl", take the suggestion - a Token, round-tripped as addedTokens + const city = page.locator('[id$="--cityFilter-inner"]'); + await city.click(); + await city.pressSequentially('Berl', { delay: 50 }); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--cityFilter') && !c.bIsDestroyed + && c._getSuggestionsPopover && c._getSuggestionsPopover() && c._getSuggestionsPopover().isOpen()), + 'typing "Berl" into the City MultiInput opened no suggestions'); + await page.keyboard.press('ArrowDown'); + await page.keyboard.press('Enter'); + await waitForIdle(page); + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const mi = ui5All().find((c) => c.getId().endsWith('--cityFilter') && live(c)); + return !!mi && mi.getTokens().map((t) => t.getText()).join() === 'Berlin' + && !!mi.getBinding('tokens') && mi.getBinding('tokens').getLength() === 1; + }, 'the suggestion-created "Berlin" token did not come back through the bound tokens aggregation'); + + await (await waitForPopup(page, 'Custom Filter Settings')).getByRole('button', { name: 'OK' }).click(); + await waitForIdle(page); + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && live(c)); + if (!t) return false; + const rows = t.getItems().map((i) => i.getCells()[2].getText()); + return rows.length === 4 && rows.every((c) => c === 'Berlin'); + }, 'OK in the filter dialog did not filter the table down to the four Berlin rows'); + + // re-open: the dialog is seeded with the Berlin condition; remove the token + // by keyboard (Backspace selects it, a second Backspace deletes it) - the + // removedTokens half of the wire - and OK lifts the filter again + await waitForIdle(page); + const settings2 = page.getByRole('button', { name: 'Settings' }); + await revealInOverflow(page, settings2); + await settings2.click(); + await waitForPopup(page, 'Custom Filter Settings'); + await waitForIdle(page); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--cityFilter') && !c.bIsDestroyed && c.getDomRef() + && c.getTokens().map((t) => t.getText()).join() === 'Berlin'), 'the re-opened dialog was not seeded with the Berlin token'); + await page.locator('[id$="--cityFilter-inner"]').click(); + await page.keyboard.press('Backspace'); + await page.keyboard.press('Backspace'); + await waitForIdle(page); + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const mi = ui5All().find((c) => c.getId().endsWith('--cityFilter') && live(c)); + return !!mi && mi.getTokens().length === 0 && mi.getBinding('tokens').getLength() === 0; + }, 'deleting the Berlin token did not empty the bound tokens aggregation (removedTokens)'); + await (await waitForPopup(page, 'Custom Filter Settings')).getByRole('button', { name: 'OK' }).click(); + await waitForIdle(page); + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && live(c)); + return !!t && t.getItems().length === 14; + }, 'OK after removing the token did not lift the filter (14 rows)'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_647.mjs b/meta/interactions/z2ui5_cl_smpc_app_647.mjs new file mode 100644 index 000000000..2d7fb7069 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_647.mjs @@ -0,0 +1,50 @@ +// p13n.Engine on a GridList: the Settings button seeds the SelectionPanel with +// setP13nData and opens the p13n.Popup; on OK the close wire hands back +// getP13nData( true ) and the backend re-orders and hides the list items +import { waitForIdle, waitForUi5 } from '../../scripts/lib-e2e.mjs'; + +// the id of the SelectionPanel row whose p13n entry carries this name +const panelRow = (page, panel, name) => page.evaluate(([panel, name]) => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + // the RENDERED panel - a never-opened popup's panels outlive their view + const p = all.find((c) => c.getId().endsWith('--' + panel) && !c.bIsDestroyed && c.getDomRef()); + const row = p && p._oListControl.getItems().find((i) => i.getBindingContext(p.P13N_MODEL).getProperty('name') === name); + return row ? row.getId() : null; +}, [panel, name]); + +export default async (page, expect) => { + await waitForIdle(page); + await page.getByRole('button', { name: /settings/i }).first().click(); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--p13nPopup-dialog') && !c.bIsDestroyed && c.isOpen()), + 'the Settings button did not open the p13n.Popup'); + await waitForUi5(page, () => { + const p = ui5All().find((c) => c.getId().endsWith('--itemsPanel') && !c.bIsDestroyed); + const d = p && p.getP13nData(); + return !!d && d.length === 5 && d.every((e) => e.visible === true) && d[4].label === 'John Williams'; + }, 'the Settings press never handed the SelectionPanel its setP13nData state'); + + // John Williams to the top (focus the row, Ctrl+Home - the panel's own + // move-to-top shortcut), Petra Maier unticked (focus, Space) + const john = await panelRow(page, 'itemsPanel', 'person5'); + expect(!!john, 'a "John Williams" row in the panel').toBeTruthy(); + await page.evaluate((id) => document.getElementById(id).focus(), john); + await page.keyboard.press('Control+Home'); + const petra = await panelRow(page, 'itemsPanel', 'person2'); + await page.evaluate((id) => document.getElementById(id).focus(), petra); + await page.keyboard.press('Space'); + await waitForUi5(page, () => { + const p = ui5All().find((c) => c.getId().endsWith('--itemsPanel') && !c.bIsDestroyed); + const d = p.getP13nData(true).map((e) => e.name); + return d.join() === 'person5,person1,person3,person4'; + }, 'the panel did not take the move-to-top and the untick'); + + await page.locator('[id$="--p13nPopup-confirmBtn"]').click(); + await waitForIdle(page); + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const l = ui5All().find((c) => c.getId().endsWith('--persoList') && live(c)); + if (!l) return false; + const names = l.getItems().filter(live).map((i) => i.getDomRef().textContent); + return names.length === 4 && /John/.test(names[0]) && /Williams/.test(names[0]) && !names.some((n) => /Petra/.test(n)); + }, 'closing the p13n.Popup with OK did not lead the GridList with John Williams and drop Petra Maier'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_648.mjs b/meta/interactions/z2ui5_cl_smpc_app_648.mjs new file mode 100644 index 000000000..3a29555b7 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_648.mjs @@ -0,0 +1,139 @@ +// p13n.Engine on a sap.ui.table.Table: the Settings button seeds the Columns +// and Sort panels with setP13nData and opens the p13n.Popup; on OK the close +// wire hands back both panels' getP13nData( true ) and the backend rebuilds +// the columns (order, visibility) and the rows' sorter. Then the table's own +// columnResize, sort and columnMove events, each carrying the column's +// .data('p13nKey'), driven from the column header the way a user does. +import { waitForIdle, waitForUi5 } from '../../scripts/lib-e2e.mjs'; + +const P13N_ROW = ([panel, name]) => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + // the RENDERED panel - a never-opened popup's panels outlive their view + const p = all.find((c) => c.getId().endsWith('--' + panel) && !c.bIsDestroyed && c.getDomRef()); + const row = p && p._oListControl.getItems().find((i) => i.getBindingContext(p.P13N_MODEL).getProperty('name') === name); + return row ? row.getId() : null; +}; +// the DOM id of the live table's header cell for the column with this p13nKey +const HEADER = (key) => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getId().endsWith('--persoTable') && live(c)); + const col = t && t.getColumns().find((c) => c.data('p13nKey') === key); + const cell = col && document.querySelector(`.sapUiTableHeaderCell[data-sap-ui-colid="${col.getId()}"]`); + return cell ? cell.id : null; +}; + +export default async (page, expect) => { + const rebuildErrors = []; + page.on('console', (m) => { const d = /duplicate id '([^']+)'/.exec(m.text()); if (d) rebuildErrors.push(d[1].replace(/^.*--/, '')); }); + const rebuildsFailed = () => (rebuildErrors.length ? ` (rebuild died: duplicate id ${rebuildErrors[0]})` : ''); + const focusHeader = async (key) => { + const id = await page.evaluate(HEADER, key); + expect(!!id, `a rendered header cell for ${key}`).toBeTruthy(); + await page.evaluate((id) => document.getElementById(id).focus(), id); + return id; + }; + + await waitForIdle(page); + // the toolbar's icon-only settings button (no tooltip, so no accessible name) + const settingsId = await page.evaluate(() => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const b = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.isA('sap.m.Button') && c.getIcon() === 'sap-icon://action-settings' && !c.bIsDestroyed + && c.getParent() && c.getParent().isA('sap.m.OverflowToolbar')); + return b && b.getId(); + }); + const settings = page.locator(`[id="${settingsId}"]`); + if (!(await settings.count())) { + // folded into the toolbar's overflow: open it with its own button (focus + Enter; + // a pointer click lands on the table's extension area and never reaches it) + const tb = await page.evaluate((id) => sap.ui.require('sap/ui/core/Element').getElementById(id).getParent().getId(), settingsId); + await page.evaluate((tb) => document.getElementById(`${tb}-overflowButton`).focus(), tb); + await page.keyboard.press('Enter'); + await settings.waitFor({ state: 'attached', timeout: 5000 }); + } + await page.evaluate((id) => document.getElementById(id).focus(), settingsId); + await page.keyboard.press('Enter'); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--p13nPopup-dialog') && !c.bIsDestroyed && c.isOpen()), + 'the Settings button did not open the p13n.Popup'); + await waitForUi5(page, () => { + const p = ui5All().find((c) => c.getId().endsWith('--gridColumnsPanel') && !c.bIsDestroyed); + const d = p && p.getP13nData(); + return !!d && d.length === 4 && d[3].name === 'size_col' && d[3].visible === false; + }, 'the Settings press never handed the Columns panel its setP13nData state'); + + // Columns: tick Size (focus its row, Space); Sort: First Name ascending + const size = await page.evaluate(P13N_ROW, ['gridColumnsPanel', 'size_col']); + await page.evaluate((id) => document.getElementById(id).focus(), size); + await page.keyboard.press('Space'); + await page.evaluate(() => { + const p = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getId().endsWith('--gridSortPanel') && !c.bIsDestroyed); + const d = p.getP13nData(); + d.forEach((e) => { e.sorted = e.name === 'firstName_col'; e.descending = false; }); + d.sort((a, b) => (b.sorted ? 1 : 0) - (a.sorted ? 1 : 0)); + p.setP13nData(d); + }); + await page.locator('[id$="--p13nPopup-confirmBtn"]').click(); + await waitForIdle(page); + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && live(c)); + if (!t) return false; + const cols = t.getColumns().filter((c) => c.getVisible()).map((c) => c.getLabel().getText()); + const first = t.getBinding('rows').getContexts(0, 5).map((x) => x.getProperty('FIRSTNAME')); + return cols.join() === 'First Name,Last Name,City,Size' && first.join() === 'John,Maria,Peter,Petra,Thomas' + && t.getColumns()[0].getSortOrder() === 'Ascending'; + }, 'closing the p13n.Popup with OK did not show the Size column and sort the rows by First Name'); + + // columnResize: Shift+ArrowLeft on the Last Name header (no rebuild - the + // backend keeps the width for the next one) + await waitForIdle(page); + await focusHeader('lastName_col'); + await page.keyboard.press('Shift+ArrowLeft'); + await waitForIdle(page); + + // sort: the City header's column menu, its "sort descending" quick action + await focusHeader('city_col'); + await page.keyboard.press('Enter'); + await waitForUi5(page, () => ui5All().some((c) => c.isA('sap.m.Button') && !c.bIsDestroyed && c.getDomRef() + && c.getIcon() === 'sap-icon://sort-descending'), 'the City column menu did not offer a sort-descending action'); + const desc = await page.evaluate(() => Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.isA('sap.m.Button') && !c.bIsDestroyed && c.getDomRef() && c.getIcon() === 'sap-icon://sort-descending').getId()); + await page.locator(`[id="${desc}"]`).click(); + await waitForIdle(page); + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && live(c)); + if (!t) return false; + const byKey = (k) => t.getColumns().find((c) => c.data('p13nKey') === k); + const cities = t.getBinding('rows').getContexts(0, 5).map((x) => x.getProperty('CITY')); + return byKey('city_col').getSortOrder() === 'Descending' && byKey('firstName_col').getSortOrder() === 'None' + && cities[4] === 'Heidelberg' && byKey('lastName_col').getWidth() !== '11rem'; + }, `sorting City descending from the column menu did not re-sort the rows, or the earlier columnResize width was lost${rebuildsFailed()}`); + + // columnMove: Ctrl+ArrowLeft on the City header (prevented, moved by the backend) + await waitForIdle(page); + await focusHeader('city_col'); + const [moveReq] = await Promise.all([ + page.waitForRequest((r) => r.method() === 'POST' && /"EVENT":"COLUMN_MOVE"/.test(r.postData() || ''), { timeout: 10000 }), + page.keyboard.press('Control+ArrowLeft'), + ]); + // the wire itself: the moved column's p13nKey and its new position + expect(JSON.parse(moveReq.postData()).value.S_FRONT.T_EVENT_ARG, 'the columnMove arguments').toEqual(['city_col', 1]); + await waitForIdle(page); + // the third view rebuild since the popup was last opened + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && live(c)); + return !!t && t.getColumns().filter((c) => c.getVisible()).map((c) => c.data('p13nKey')).join() + === 'firstName_col,city_col,lastName_col,size_col'; + }, `moving City one to the left did not re-order the columns${rebuildsFailed()}`); + + // the popup lives only while it is open (a POPUP-slot fragment the close + // handler destroys), so no panel outlives it - a p13n.Popup declared in the + // view leaked its never-opened panels, and two rebuilds later the + // alternating view id collided with them + await waitForUi5(page, () => !ui5All().some((c) => !c.bIsDestroyed && ['gridColumnsPanel', 'gridSortPanel'].some((p) => c.getId().endsWith('--' + p))), + 'a p13n panel outlived its closed popup (the view-declared Popup leak)'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_649.mjs b/meta/interactions/z2ui5_cl_smpc_app_649.mjs new file mode 100644 index 000000000..149981d06 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_649.mjs @@ -0,0 +1,85 @@ +// p13n.Engine with two controllers: the Columns and the Rows button each send +// setP13nData and open their own p13n.Popup; each close wire hands back its +// panel's getP13nData( true ) and the backend hides/re-orders columns or rows +import { waitForIdle, waitForUi5 } from '../../scripts/lib-e2e.mjs'; + +const P13N_ROW = ([panel, name]) => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + // the RENDERED panel - a never-opened popup's panels outlive their view + const p = all.find((c) => c.getId().endsWith('--' + panel) && !c.bIsDestroyed && c.getDomRef()); + const row = p && p._oListControl.getItems().find((i) => i.getBindingContext(p.P13N_MODEL).getProperty('name') === name); + return row ? row.getId() : null; +}; +// a header-toolbar button by icon - [its id, its toolbar's id]; it may sit +// folded in the toolbar's overflow, so it is not required to be rendered +const TOOLBAR_BUTTON = (icon) => { + const b = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.isA('sap.m.Button') && !c.bIsDestroyed && c.getIcon() === icon + && c.getParent() && c.getParent().isA('sap.m.OverflowToolbar') && !c.getParent().bIsDestroyed); + return b ? [b.getId(), b.getParent().getId()] : null; +}; +// the live table: visible column headers and visible rows' first cells +const TABLE = () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const t = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getId().endsWith('--persoTable') && live(c)); + if (!t) return null; + return { + cols: t.getColumns().filter((c) => c.getVisible()).map((c) => (c.getHeader() || {}).getText?.()), + rows: t.getItems().filter((i) => i.getVisible()).map((i) => i.data('p13nKey')), + }; +}; + +export default async (page, expect) => { + const rebuildErrors = []; + page.on('console', (m) => { const d = /duplicate id '([^']+)'/.exec(m.text()); if (d) rebuildErrors.push(d[1].replace(/^.*--/, '')); }); + const rebuildsFailed = () => (rebuildErrors.length ? ` (rebuild died: duplicate id ${rebuildErrors[0]})` : ''); + const table = () => page.evaluate(TABLE); + const openAndTick = async (icon, popup, panel, name) => { + await waitForIdle(page); + const found = await page.evaluate(TOOLBAR_BUTTON, icon); + expect(!!found, `the toolbar button ${icon}${rebuildsFailed()}`).toBeTruthy(); + const [btn, tb] = found; + if (!(await page.locator(`[id="${btn}"]`).count())) { + // folded into the overflow: open it with its own button (focus + Enter) + await page.evaluate((tb) => document.getElementById(`${tb}-overflowButton`).focus(), tb); + await page.keyboard.press('Enter'); + await page.locator(`[id="${btn}"]`).waitFor({ state: 'visible', timeout: 5000 }); + } + await page.locator(`[id="${btn}"]`).click(); + await waitForUi5(page, (popup) => ui5All().some((c) => c.getId().endsWith(`--${popup}-dialog`) && !c.bIsDestroyed && c.isOpen()), + `${icon} did not open ${popup}`, popup); + await waitForIdle(page); + const row = await page.evaluate(P13N_ROW, [panel, name]); + expect(!!row, `a ${name} row in ${panel} (seeded by setP13nData)`).toBeTruthy(); + await page.evaluate((id) => document.getElementById(id).focus(), row); + await page.keyboard.press('Space'); + await page.locator(`[id$="--${popup}-confirmBtn"]`).click(); + await waitForIdle(page); + }; + + expect(await table(), 'the initial table').toEqual({ + cols: ['ID', 'First Name', 'Last Name', 'City'], rows: ['P1', 'P2', 'P3', 'P4', 'P5'] }); + + // Columns popup: untick "City" + await openAndTick('sap-icon://action-settings', 'columnsPopup', 'tableColumnsPanel', 'city_col'); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef())); + return !!t && t.getColumns().filter((c) => c.getVisible()).map((c) => c.data('p13nKey')).join() === 'id_col,firstName_col,lastName_col'; + }, `OK in the Columns popup did not hide the City column${rebuildsFailed()}`); + + // Rows popup: untick "Petra Maier" + // the second view rebuild, with the Rows popup never opened before + await openAndTick('sap-icon://add-employee', 'rowsPopup', 'rowsPanel', 'P2'); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--persoTable') && !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef())); + return !!t && t.getItems().filter((i) => i.getVisible()).map((i) => i.data('p13nKey')).join() === 'P1,P3,P4,P5'; + }, `OK in the Rows popup did not hide Petra Maier's row${rebuildsFailed()}`); + + // the popup lives only while it is open (a POPUP-slot fragment the close + // handler destroys), so no panel outlives it - a p13n.Popup declared in the + // view leaked its never-opened panels, and two rebuilds later the + // alternating view id collided with them + await waitForUi5(page, () => !ui5All().some((c) => !c.bIsDestroyed && ['tableColumnsPanel', 'rowsPanel'].some((p) => c.getId().endsWith('--' + p))), + 'a p13n panel outlived its closed popup (the view-declared Popup leak)'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_650.mjs b/meta/interactions/z2ui5_cl_smpc_app_650.mjs new file mode 100644 index 000000000..cb384f0d1 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_650.mjs @@ -0,0 +1,60 @@ +// p13n.Popup: the open/change wires carry the panels' getP13nData( ) through +// the event source - toggling a column in the SelectionPanel the way the UI +// does (focus the row, Space) must land in the backend and come back as the +// CodeEditor's JSON - byte for byte what the original's +// JSON.stringify( { columns, sort, group }, null, ' ' ) prints for the +// panels' live data. The data travels as array args (an event-handler +// expression has no JSON global, so the wires cannot stringify it) and the +// backend prints it. +import { waitForIdle, waitForUi5, waitForPopup } from '../../scripts/lib-e2e.mjs'; + +export default async (page, expect) => { + await waitForIdle(page); + await page.getByRole('button', { name: 'Show p13n.Popup' }).click(); + await waitForPopup(page, 'My Custom View Settings'); + await waitForIdle(page); + // the seeded setP13nData arrived: City visible, Country/Region not + await waitForUi5(page, () => { + const p = ui5All().find((c) => c.getId().endsWith('columnsPanel') && !c.bIsDestroyed); + const d = p && p.getP13nData(); + return d && d.length === 3 && d[0].visible === true && d[1].visible === false; + }, 'the columns panel never received the setP13nData seed'); + // tick "Country" in the panel's own list: focus its row and press Space + const rowId = await page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + const p = all.find((c) => c.getId().endsWith('columnsPanel') && !c.bIsDestroyed); + const it = p._oListControl.getItems().find((i) => i.getBindingContext(p.P13N_MODEL).getProperty('name') === 'key2'); + return it ? it.getId() : null; + }); + expect(!!rowId, 'a "Country" row in the Columns panel').toBeTruthy(); + await page.evaluate((id) => document.getElementById(id).focus(), rowId); + await page.keyboard.press('Space'); + await waitForIdle(page); + await waitForUi5(page, () => { + const p = ui5All().find((c) => c.getId().endsWith('columnsPanel') && !c.bIsDestroyed); + return p.getP13nData()[1].visible === true; + }, 'Space on the Country row did not tick it in the panel'); + await waitForUi5(page, () => { + const e = ui5All().find((c) => c.getId().endsWith('p13nEditor') && !c.bIsDestroyed && c.getDomRef()); + if (!e) return false; + try { + const j = JSON.parse(e.getValue()); + const c = j.columns.find((x) => x.name === 'key2'); + return c && c.visible === true && j.sort[0].sorted === true && j.group[0].grouped === true; + } catch (x) { return false; } + }, 'ticking Country in the Columns panel never came back as the CodeEditor JSON (columns.key2.visible = true)'); + // the whole text: what the original's JSON.stringify( { columns, sort, + // group }, null, ' ' ) prints for the panels' live values - their items + // keyed in _initialData's order (the port's panels hold the same values, + // their keys reordered on the way through the framework) + await waitForUi5(page, () => { + const live = (id) => ui5All().find((c) => c.getId().endsWith(id) && !c.bIsDestroyed).getP13nData(); + const e = ui5All().find((c) => c.getId().endsWith('p13nEditor') && !c.bIsDestroyed && c.getDomRef()); + const want = JSON.stringify({ + columns: live('columnsPanel').map((i) => ({ visible: i.visible, name: i.name, label: i.label })), + sort: live('sortPanel').map((i) => ({ sorted: i.sorted, name: i.name, label: i.label, descending: i.descending })), + group: live('groupPanel').map((i) => ({ grouped: i.grouped, name: i.name, label: i.label })), + }, null, ' '); + return !!e && e.getValue() === want; + }, 'the CodeEditor text is not JSON.stringify( { columns, sort, group }, null, \' \' ) of the panels'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_651.mjs b/meta/interactions/z2ui5_cl_smpc_app_651.mjs new file mode 100644 index 000000000..08e1e6d98 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_651.mjs @@ -0,0 +1,139 @@ +// VariantManagement with static VariantItems the backend emits from its table: +// Save As (the save event's name + boolean flags create a backend row and the +// defaultKey, and the rebuilt view shows it), Manage (rename and delete in the +// dialog: the deleted keys and the renamed entries arrive as JSON arrays and +// the backend applies both - the REBUILT control must show them, and keep +// them across the next round-trip), then select from the "my Favorites" +// popover (key round-trip, two-way selectedKey) +import { waitForIdle, waitForUi5, revealInOverflow } from '../../scripts/lib-e2e.mjs'; + +// the live VariantManagement's state: selected/default key, modified, items +const VM = () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const vm = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getId().endsWith('--vm') && c.isA('sap.m.VariantManagement') && live(c)); + if (!vm) return null; + return { + selected: vm.getSelectedKey(), def: vm.getDefaultKey(), modified: vm.getModified(), + items: vm.getItems().map((i) => `${i.getKey()}=${i.getTitle()}`), + }; +}; + +export default async (page, expect) => { + const vm = () => page.evaluate(VM); + const openVm = async () => { + await waitForIdle(page); + // the icon-only trigger measures 0x0 unthemed: press it by keyboard + await page.evaluate(() => document.querySelector('[id$="--vm-trigger"]').focus()); + await page.keyboard.press('Enter'); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--vm-popover') && !c.bIsDestroyed && c.isOpen()), + 'the variant trigger did not open the "my Favorites" popover'); + }; + // the panel's OverflowToolbar folds its button away - reveal and press together + const toggleModified = async () => { + await waitForIdle(page); + const btn = page.getByRole('button', { name: 'Toggle Modify View' }); + await revealInOverflow(page, btn); + await btn.click(); + }; + const toast = (text) => waitForUi5(page, (t) => [...document.querySelectorAll('.sapMMessageToast')].some((e) => e.textContent.includes(t)), + `no "${text}" toast`, text); + + await waitForIdle(page); + expect(await vm(), 'the initial variant state').toEqual({ + selected: '2', def: '2', modified: false, items: ['Standard=Entry1', '2=Entry2', '3=Entry3', '4=Entry4'] }); + + // Toggle Modify View, then Save As "MyView" as the default + await toggleModified(); + await waitForIdle(page); + expect((await vm()).modified, 'the modified flag after Toggle Modify View').toBe(true); + await openVm(); + await page.locator('[id$="--vm-saveas"]').click(); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--vm-savedialog') && !c.bIsDestroyed && c.isOpen()), + 'Save As did not open the save dialog'); + const name = page.locator('[id$="--vm-name-inner"]'); + await name.fill('MyView'); + await page.locator('.sapMCb[id$="--vm-default"]').click(); + await page.locator('[id$="--vm-variantsave"]').click(); + await waitForIdle(page); + await toast("New view 'MyView' created"); + await waitForUi5(page, () => { + const vm = ui5All().find((c) => c.getId().endsWith('--vm') && c.isA('sap.m.VariantManagement') && !c.bIsDestroyed && c.getDomRef()); + const mine = vm && vm.getItems().find((i) => i.getTitle() === 'MyView'); + return !!mine && /^key_/.test(mine.getKey()) && vm.getDefaultKey() === mine.getKey() && vm.getModified() === false + && mine.getAuthor() === 'sample' && mine.getSharing() === 'Private'; + }, 'Save As "MyView" (default) did not come back as a backend row with key_..., the defaultKey and modified reset'); + + // Manage: rename Entry2, delete Entry3, Save + await openVm(); + await page.locator('[id$="--vm-manage"]').click(); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--vm-managementdialog') && !c.bIsDestroyed && c.isOpen()), + 'Manage did not open the management dialog'); + const rows = await page.evaluate(() => { + const vm = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getId().endsWith('--vm') && c.isA('sap.m.VariantManagement') && !c.bIsDestroyed && c.getDomRef()); + const keys = vm.getItems().map((i) => i.getKey()); + return { e2: keys.indexOf('2'), e3: keys.indexOf('3') }; + }); + // type only once the dialog has finished opening: a field filled while it + // is still OPENING is re-rendered away and the rename never registers + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--vm-managementdialog') && !c.bIsDestroyed + && c.oPopup && c.oPopup.getOpenState() === 'OPEN'), 'the management dialog never finished opening'); + const rename = page.locator(`[id$="--vm-manage-input-${rows.e2}-inner"]`); + await rename.fill('Renamed2'); + await rename.press('Enter'); + // the input is two-way bound to the item's title: the rename is in once the + // ITEM carries it - the manage event reads it from there on Save + await waitForUi5(page, () => { + const vm = ui5All().find((c) => c.getId().endsWith('--vm') && c.isA('sap.m.VariantManagement') && !c.bIsDestroyed && c.getDomRef()); + const it = vm && vm.getItems().find((i) => i.getKey() === '2'); + return !!it && it.getTitle() === 'Renamed2'; + }, 'the rename in the Manage Views input never reached the Entry2 item'); + await page.locator(`[id$="--vm-manage-del-${rows.e3}"]`).click(); + const vmBefore = await page.evaluate(() => Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getId().endsWith('--vm') && c.isA('sap.m.VariantManagement') && !c.bIsDestroyed && c.getDomRef()).getId()); + // the manage event fires once the dialog has closed: wait for ITS request, + // or the next press races it and the busy guard drops one of the two + const [manageReq] = await Promise.all([ + page.waitForRequest((r) => r.method() === 'POST' && /"EVENT":"MANAGE"/.test(r.postData() || ''), { timeout: 10000 }), + page.locator('[id$="--vm-managementsave"]').click(), + ]); + const manageArgs = JSON.parse(manageReq.postData()).value.S_FRONT.T_EVENT_ARG; + expect([manageArgs[0], manageArgs[1]], 'the manage event\'s deleted and renamed arguments') + .toEqual([['3'], [{ key: '2', name: 'Renamed2' }]]); + await waitForIdle(page); + // one more round-trip, then the items of the control the backend REBUILT + // (a new instance, not the one the dialog edited in place) + await toggleModified(); + await waitForIdle(page); + await waitForUi5(page, (before) => { + const vm = ui5All().find((c) => c.getId().endsWith('--vm') && c.isA('sap.m.VariantManagement') && !c.bIsDestroyed && c.getDomRef() + && document.body.contains(c.getDomRef())); + if (!vm || vm.getId() === before) return false; + const items = vm.getItems(); + return !items.some((i) => i.getKey() === '3') && items.find((i) => i.getKey() === '2').getTitle() === 'Renamed2' + && items.length === 4; + }, 'Manage did not delete Entry3 in the backend (deleted keys) and keep the Entry2 rename (renamed) in the rebuilt view', vmBefore); + + // select "Entry1" (Standard) from the popover + /* the popover list is filled: the items are static VariantItems. A bound + items template made it EMPTY on UI5 1.152, which filters that list (on + its internal $mVariants model, properties visible/favorite) with the + template's paths VISIBLE/FAVORITE - every item filtered out. */ + await openVm(); + const entry1 = await page.evaluate(() => { + const list = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .find((c) => c.getId().endsWith('--vm-list') && !c.bIsDestroyed); + const it = list && list.getItems().find((i) => i.getText() === 'Entry1'); + return it && it.getDomRef() ? it.getId() : null; + }); + expect(!!entry1, 'an "Entry1" item rendered in the "my Favorites" popover list').toBeTruthy(); + await page.locator(`[id="${entry1}"]`).click(); + await waitForIdle(page); + await toast('Selected Key: Standard'); + await waitForUi5(page, () => { + const vm = ui5All().find((c) => c.getId().endsWith('--vm') && c.isA('sap.m.VariantManagement') && !c.bIsDestroyed && c.getDomRef()); + return !!vm && vm.getSelectedKey() === 'Standard' && vm.getModel().getProperty('/SELECTEDKEY') === 'Standard' + && vm.getModified() === false; + }, 'selecting Entry1 did not write selectedKey Standard back to the model'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_652.mjs b/meta/interactions/z2ui5_cl_smpc_app_652.mjs new file mode 100644 index 000000000..12949ac5c --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_652.mjs @@ -0,0 +1,177 @@ +// sap.m.plugins.UploadSetwithTable - FileNameValidationSample. Closes the +// LIVE_TEST: the plugin calls by id through control_by_id with a live binding +// Context as the event arg (renameItem, openFilePreview, download), the +// selectionChange paths driving the toolbar flags, the itemRenamed wire, the +// vetoed beforeUploadStarts (the backend plays the mock server), the remove +// MessageBox, the binding_call search - and (d) setFileNameValidationConfig +// reached with a JSON object, which the plugin's rename dialog then validates +// against. +import { waitForIdle, revealInOverflow, waitForPopup } from '../../scripts/lib-e2e.mjs'; + +// the table's live rows (filtered ones drop out), the model rows and the four flags +const state = (page) => page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()).filter((c) => !c.bIsDestroyed); + const live = (c) => c.getDomRef() && document.body.contains(c.getDomRef()); + const t = all.find((c) => c.getId().endsWith('--table-uploadSet') && live(c)); + const p = all.find((c) => c.getId().endsWith('--uploadSetPlugin')); + const en = (s) => { const b = all.find((c) => c.getId().endsWith(`--${s}`)); return b ? b.getEnabled() : null; }; + return { + rows: t.getItems().filter((i) => i.getBindingContext()).map((i) => i.getBindingContext().getProperty('FILENAME')), + model: t.getModel().getProperty(t.getBinding('items').getPath()).map((r) => ({ name: r.FILENAME, size: r.FILESIZE })), + dl: en('downloadSelectedButton'), rm: en('removeDocumentButton'), rn: en('renameButton'), ed: en('editUrlButton'), + config: p ? p.getFileNameValidationConfig() : null, + }; +}); + +async function until(page, pred, msg) { + const deadline = Date.now() + 15000; + let s; + for (;;) { + s = await state(page); + if (pred(s)) return s; + if (Date.now() > deadline) throw new Error(`${msg} - last state ${JSON.stringify(s).slice(0, 400)}`); + await page.waitForTimeout(250); + } +} + +const selectRow = async (page, i) => { + await page.locator(`[id$="table-uploadSet-${i}-selectMulti"]`).first().click(); + await waitForIdle(page); +}; + +// the rename dialog the plugin builds itself: type, read the input's value state +async function renameInput(page, value) { + const dlg = await waitForPopup(page, 'Rename Document'); + const input = dlg.locator('input').first(); + await input.fill(value); + return page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + const d = all.find((c) => !c.bIsDestroyed && c.isA('sap.m.Dialog') && c.isOpen() && c.getTitle() === 'Rename Document'); + return d.getContent()[1].getValueState(); + }); +} + +// a popup the module closed must really be gone before the page is driven again +// (title null: no dialog at all may stay open) +async function waitForClosed(page, title) { + await page.waitForFunction((t) => !Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .some((c) => !c.bIsDestroyed && c.isA('sap.m.Dialog') && c.isOpen() && (t === null || c.getTitle() === t)), + title, { timeout: 10000 }).catch(() => { throw new Error(`the ${title === null ? 'preview' : `"${title}"`} dialog never closed`); }); +} + +async function openRename(page) { + const rn = page.getByRole('button', { name: 'Rename', exact: true }); + await revealInOverflow(page, rn); + await rn.first().click(); + return waitForPopup(page, 'Rename Document'); +} + +export default async (page, expect) => { + await waitForIdle(page); + const start = await until(page, (s) => s.rows.length === 6, 'the six documents never rendered'); + expect(start.dl, 'Download disabled with no selection').toBe(false); + expect(start.config, 'the view literal fileNameValidationConfig').toEqual({ mode: 'override', characters: '@$#' }); + + /* ---- selectionChange -> the two bound flags ---------------------------- */ + await selectRow(page, 0); + await until(page, (s) => s.dl && s.rm && s.rn && s.ed, 'selecting one row never enabled Download/Remove/Rename/Edit URL'); + await selectRow(page, 1); + await until(page, (s) => s.dl && !s.rm && !s.rn && !s.ed, 'two selected rows did not leave only Download enabled'); + await selectRow(page, 1); + await until(page, (s) => s.dl && s.rm && s.rn, 'deselecting back to one row did not re-enable the single-row buttons'); + + /* ---- download( , true ) through control_by_id ------------ */ + const docUrl = 'https://sdk.openui5.org/test-resources/sap/m/UploadSetwithTableSampleFiles/Business%20Plan%20Agenda.doc'; + await page.route('**/UploadSetwithTableSampleFiles/**', (r) => r.fulfill({ status: 200, contentType: 'application/msword', body: 'e2e' })); + await page.evaluate(() => { + const P = sap.ui.require('sap/m/plugins/UploadSetwithTable').prototype; + window.__dl = []; + if (!P.__e2eDl) { + P.__e2eDl = P.download; + P.download = function (ctx, ask) { + window.__dl.push({ ctx: !!(ctx && ctx.isA && ctx.isA('sap.ui.model.Context')), path: ctx && ctx.getPath && ctx.getPath(), ask }); + return P.__e2eDl.apply(this, arguments); + }; + } + }); + const dlBtn = page.getByRole('button', { name: 'Download', exact: true }); + await revealInOverflow(page, dlBtn); + const [req] = await Promise.all([ + page.waitForRequest((r) => r.url().includes('UploadSetwithTableSampleFiles'), { timeout: 10000 }) + .catch(() => { throw new Error('download( ) never fetched the selected row\'s document URL'); }), + dlBtn.first().click(), + ]); + const dl = await page.evaluate(() => window.__dl); + expect(dl.length, 'plugin.download calls').toBe(1); + expect(dl[0], 'download got the live Context of row 0 and bAskForLocation').toEqual({ ctx: true, path: dl[0].path, ask: true }); + if (!/\/0$/.test(dl[0].path)) throw new Error(`download was handed ${dl[0].path}, not the selected row 0`); + expect(req.url(), 'the fetched document').toBe(docUrl); + + /* ---- renameItem( ) + the view's literal validation config */ + await openRename(page); + expect(await renameInput(page, 'bad@name'), "'@' under the literal override '@$#'").toBe('Error'); + expect(await renameInput(page, 'okname'), 'a clean name').toBe('None'); + // back to the unchanged name, so Cancel closes without the discard box + await renameInput(page, 'Invoice summary'); + await page.getByRole('button', { name: 'Cancel', exact: true }).click(); + await waitForClosed(page, 'Rename Document'); + + /* ---- (d) Configure -> setFileNameValidationConfig with a JSON object ---- */ + const chars = page.locator('[id$="--charInput-inner"]'); + await chars.fill('xyz'); + await waitForIdle(page); + await page.getByRole('button', { name: 'Configure', exact: true }).click(); + await expect(page.locator('.sapMMessageToast'), 'the Configure toast') + .toContainText('Configuration mode: override, Characters: xyz'); + await until(page, (s) => s.config && s.config.characters === 'xyz', + 'Configure never reached setFileNameValidationConfig'); + expect((await state(page)).config, 'the applied config object').toEqual({ mode: 'override', characters: 'xyz' }); + // the plugin's rename dialog now validates against the NEW set + await openRename(page); + expect(await renameInput(page, 'bad@name'), "'@' is allowed once override is 'xyz'").toBe('None'); + expect(await renameInput(page, 'xname'), "'x' is restricted once override is 'xyz'").toBe('Error'); + + /* ---- itemRenamed -> the backend writes the new name into the row -------- */ + expect(await renameInput(page, 'Renamed'), 'the new name').toBe('None'); + await page.getByRole('button', { name: 'Apply', exact: true }).click(); + await expect(page.locator('.sapMMessageToast'), 'the rename toast').toContainText('Document Renamed.'); + await until(page, (s) => s.model[0].name === 'Renamed.doc' && s.rows[0] === 'Renamed.doc', + 'itemRenamed never wrote Renamed.doc into row 0'); + + /* ---- openFilePreview( ) ----------------------- */ + await page.locator('[id*="table-uploadSet-0"] .sapMLnk', { hasText: 'Renamed.doc' }).first().click(); + const preview = await waitForPopup(page, 'Renamed.doc'); + await expect(preview, 'the FilePreviewDialog').toContainText('Renamed.doc'); + await preview.getByRole('button', { name: 'Close', exact: true }).click(); + await waitForClosed(page, null); + + /* ---- upload: beforeUploadStarts vetoed, the backend adds the row -------- */ + // the veto is the point: the plugin must never POST to its uploadUrl + const uploadPosts = []; + page.on('request', (r) => { if (r.url().includes('/uploadFiles')) uploadPosts.push(r.url()); }); + const body = Buffer.from('e2e upload payload'); + await page.locator('input[type=file][id$="uploadSetPlugin-uploader-fu"]').setInputFiles({ + name: 'e2e-upload.txt', mimeType: 'text/plain', buffer: body, + }); + await expect(page.locator('.sapMMessageToast'), 'the upload toast').toContainText('Document Added'); + const up = await until(page, (s) => s.model.length === 7 && s.rows.includes('e2e-upload.txt'), + 'the vetoed upload never added the backend row'); + expect(up.model[0], 'the unshifted row carries name and size').toEqual({ name: 'e2e-upload.txt', size: body.length }); + + expect(uploadPosts.length, 'requests to /uploadFiles (the vetoed upload)').toBe(0); + + /* ---- remove via the row's decline button + MessageBox ------------------- */ + const idx = up.rows.indexOf('Instructions.pdf'); + await page.locator(`[id$="table-uploadSet-${idx}"] button`).last().click(); + const box = await waitForPopup(page, 'Are you sure you want to remove the document Instructions.pdf'); + await box.getByRole('button', { name: 'Remove', exact: true }).click(); + await until(page, (s) => s.model.length === 6 && !s.rows.includes('Instructions.pdf'), + 'Remove never dropped Instructions.pdf'); + await until(page, (s) => !s.dl && !s.rm, 'the removal did not reset the toolbar flags'); + + /* ---- search: the binding_call filter on FILENAME ------------------------ */ + await page.locator('.sapMSF input').first().fill('e2e'); + await until(page, (s) => s.rows.length === 1 && s.rows[0] === 'e2e-upload.txt', 'the search never filtered the rows'); + await page.locator('.sapMSF input').first().fill(''); + await until(page, (s) => s.rows.length === 6, 'clearing the search did not bring the rows back'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_653.mjs b/meta/interactions/z2ui5_cl_smpc_app_653.mjs new file mode 100644 index 000000000..c7eb1303a --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_653.mjs @@ -0,0 +1,165 @@ +// sap.m.plugins.UploadSetwithTable - FilePreviewCustomPageContent. Closes the +// LIVE_TEST: the plugin calls by id through control_by_id with a live binding +// Context as the event arg (download, renameItem, openFilePreview - the latter +// into the view's own FilePreviewDialog via the previewDialog association), the +// selectionChange paths driving the toolbar flags, the arg-less itemRenamed +// toast, the vetoed beforeUploadStarts (the backend plays the mock server), the +// remove MessageBox and the binding_call search. +import { waitForIdle, revealInOverflow, waitForPopup } from '../../scripts/lib-e2e.mjs'; + +// the table's live rows (filtered ones drop out), the model rows and the four flags +const state = (page) => page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()).filter((c) => !c.bIsDestroyed); + const live = (c) => c.getDomRef() && document.body.contains(c.getDomRef()); + const t = all.find((c) => c.getId().endsWith('--table-uploadSet') && live(c)); + const p = all.find((c) => c.getId().endsWith('--uploadSetPlugin')); + const en = (s) => { const b = all.find((c) => c.getId().endsWith(`--${s}`)); return b ? b.getEnabled() : null; }; + return { + rows: t.getItems().filter((i) => i.getBindingContext()).map((i) => i.getBindingContext().getProperty('FILENAME')), + model: t.getModel().getProperty(t.getBinding('items').getPath()).map((r) => ({ name: r.FILENAME, size: r.FILESIZE })), + dl: en('downloadSelectedButton'), rm: en('removeDocumentButton'), rn: en('renameButton'), ed: en('editUrlButton'), + }; +}); + +async function until(page, pred, msg) { + const deadline = Date.now() + 15000; + let s; + for (;;) { + s = await state(page); + if (pred(s)) return s; + if (Date.now() > deadline) throw new Error(`${msg} - last state ${JSON.stringify(s).slice(0, 400)}`); + await page.waitForTimeout(250); + } +} + +const selectRow = async (page, i) => { + await page.locator(`[id$="table-uploadSet-${i}-selectMulti"]`).first().click(); + await waitForIdle(page); +}; + +// the rename dialog the plugin builds itself: type, read the input's value state +async function renameInput(page, value) { + const dlg = await waitForPopup(page, 'Rename Document'); + const input = dlg.locator('input').first(); + await input.fill(value); + return page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + const d = all.find((c) => !c.bIsDestroyed && c.isA('sap.m.Dialog') && c.isOpen() && c.getTitle() === 'Rename Document'); + return d.getContent()[1].getValueState(); + }); +} + +// a popup the module closed must really be gone before the page is driven again +// (title null: no dialog at all may stay open) +async function waitForClosed(page, title) { + await page.waitForFunction((t) => !Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .some((c) => !c.bIsDestroyed && c.isA('sap.m.Dialog') && c.isOpen() && (t === null || c.getTitle() === t)), + title, { timeout: 10000 }).catch(() => { throw new Error(`the ${title === null ? 'preview' : `"${title}"`} dialog never closed`); }); +} + +async function openRename(page) { + const rn = page.getByRole('button', { name: 'Rename', exact: true }); + await revealInOverflow(page, rn); + await rn.first().click(); + return waitForPopup(page, 'Rename Document'); +} + +export default async (page, expect) => { + await waitForIdle(page); + const start = await until(page, (s) => s.rows.length === 7, 'the seven documents never rendered'); + expect(start.rows[0], 'row 0').toBe('Instructions.pdf'); + expect(start.dl, 'Download disabled with no selection').toBe(false); + + /* ---- selectionChange -> the two bound flags ---------------------------- */ + await selectRow(page, 0); + await until(page, (s) => s.dl && s.rm && s.rn && s.ed, 'selecting one row never enabled Download/Remove/Rename/Edit URL'); + await selectRow(page, 1); + await until(page, (s) => s.dl && !s.rm && !s.rn && !s.ed, 'two selected rows did not leave only Download enabled'); + await selectRow(page, 1); + await until(page, (s) => s.dl && s.rm && s.rn, 'deselecting back to one row did not re-enable the single-row buttons'); + + /* ---- download( , true ) through control_by_id ------------ */ + const docUrl = 'https://sdk.openui5.org/test-resources/sap/m/UploadSetwithTableSampleFiles/Instructions.pdf'; + await page.route('**/UploadSetwithTableSampleFiles/**', (r) => r.fulfill({ status: 200, contentType: 'application/pdf', body: 'e2e' })); + await page.evaluate(() => { + const P = sap.ui.require('sap/m/plugins/UploadSetwithTable').prototype; + window.__dl = []; + if (!P.__e2eDl) { + P.__e2eDl = P.download; + P.download = function (ctx, ask) { + window.__dl.push({ ctx: !!(ctx && ctx.isA && ctx.isA('sap.ui.model.Context')), path: ctx && ctx.getPath && ctx.getPath(), ask }); + return P.__e2eDl.apply(this, arguments); + }; + } + }); + const dlBtn = page.getByRole('button', { name: 'Download', exact: true }); + await revealInOverflow(page, dlBtn); + const [req] = await Promise.all([ + page.waitForRequest((r) => r.url().includes('UploadSetwithTableSampleFiles'), { timeout: 10000 }) + .catch(() => { throw new Error('download( ) never fetched the selected row\'s document URL'); }), + dlBtn.first().click(), + ]); + const dl = await page.evaluate(() => window.__dl); + expect(dl.length, 'plugin.download calls').toBe(1); + expect(dl[0], 'download got the live Context of row 0 and bAskForLocation').toEqual({ ctx: true, path: dl[0].path, ask: true }); + if (!/\/0$/.test(dl[0].path)) throw new Error(`download was handed ${dl[0].path}, not the selected row 0`); + expect(req.url(), 'the fetched document').toBe(docUrl); + + /* ---- renameItem( ) -> itemRenamed (toast only) ---------- */ + await openRename(page); + expect(await renameInput(page, 'bad/name'), "'/' is in the default restricted set").toBe('Error'); + expect(await renameInput(page, 'Renamed'), 'the new name').toBe('None'); + await page.getByRole('button', { name: 'Apply', exact: true }).click(); + await expect(page.locator('.sapMMessageToast'), 'the rename toast').toContainText('Document Renamed.'); + await waitForClosed(page, 'Rename Document'); + await waitForIdle(page); + // this variant's onDocumentRenamedSuccess does not write the model - as in the original + expect((await state(page)).model[0].name, 'row 0 keeps its name in the model').toBe('Instructions.pdf'); + + /* ---- openFilePreview( ) into the view's dialog */ + await page.locator('[id*="table-uploadSet-2"] .sapMLnk', { hasText: 'Test Image.png' }).first().click(); + const preview = await waitForPopup(page, 'Test Image.png'); + await expect(preview, 'the FilePreviewDialog').toContainText('Test Image.png'); + // the plugin previews through the view's dialog (the previewDialog association) + const pv = await page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()).filter((c) => !c.bIsDestroyed); + const p = all.find((c) => c.getId().endsWith('--uploadSetPlugin')); + const d = sap.ui.require('sap/ui/core/Element').getElementById(p.getPreviewDialog()); + return { id: d && d.getId(), item: d && d._previewItem && d._previewItem.getFileName() }; + }); + if (!/--FilePreviewDialog$/.test(pv.id || '') || pv.item !== 'Test Image.png') { + throw new Error(`the preview did not go through the view's FilePreviewDialog with Test Image.png: ${JSON.stringify(pv)}`); + } + await preview.getByRole('button', { name: 'Close', exact: true }).click(); + await waitForClosed(page, null); + + /* ---- upload: beforeUploadStarts vetoed, the backend adds the row -------- */ + // the veto is the point: the plugin must never POST to its uploadUrl + const uploadPosts = []; + page.on('request', (r) => { if (r.url().includes('/uploadFiles')) uploadPosts.push(r.url()); }); + const body = Buffer.from('e2e upload payload'); + await page.locator('input[type=file][id$="uploadSetPlugin-uploader-fu"]').setInputFiles({ + name: 'e2e-upload.txt', mimeType: 'text/plain', buffer: body, + }); + await expect(page.locator('.sapMMessageToast'), 'the upload toast').toContainText('Document Added'); + const up = await until(page, (s) => s.model.length === 8 && s.rows.includes('e2e-upload.txt'), + 'the vetoed upload never added the backend row'); + expect(up.model[0], 'the unshifted row carries name and size').toEqual({ name: 'e2e-upload.txt', size: body.length }); + + expect(uploadPosts.length, 'requests to /uploadFiles (the vetoed upload)').toBe(0); + + /* ---- remove via the row's decline button + MessageBox ------------------- */ + const idx = up.rows.indexOf('Document.txt'); + await page.locator(`[id$="table-uploadSet-${idx}"] button`).last().click(); + const box = await waitForPopup(page, 'Are you sure you want to remove the document Document.txt'); + await box.getByRole('button', { name: 'Remove', exact: true }).click(); + await until(page, (s) => s.model.length === 7 && !s.rows.includes('Document.txt'), + 'Remove never dropped Document.txt'); + await until(page, (s) => !s.dl && !s.rm, 'the removal did not reset the toolbar flags'); + + /* ---- search: the binding_call filter on FILENAME ------------------------ */ + await page.locator('.sapMSF input').first().fill('zip'); + await until(page, (s) => s.rows.length === 1 && s.rows[0] === 'Sample Zip File.zip', 'the search never filtered the rows'); + await page.locator('.sapMSF input').first().fill(''); + await until(page, (s) => s.rows.length === 7, 'clearing the search did not bring the rows back'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_654.mjs b/meta/interactions/z2ui5_cl_smpc_app_654.mjs new file mode 100644 index 000000000..2c64c600c --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_654.mjs @@ -0,0 +1,155 @@ +// sap.m.plugins.UploadSetwithTable - GridTableSimple (sap.ui.table.Table). +// Closes the LIVE_TEST: rowSelectionChange carrying getSelectedIndices( ) and +// driving the toolbar flags, the plugin calls by id through control_by_id with +// a live Context resolved by index (download, renameItem) or taken from the +// template Link (openFilePreview), the itemRenamed wire writing the new name, +// the vetoed beforeUploadStarts (the backend plays the mock server) and the +// remove MessageBox. +import { waitForIdle, revealInOverflow, waitForPopup, dispatchMouse } from '../../scripts/lib-e2e.mjs'; + +// the table's live rows (filtered ones drop out), the model rows and the four flags +const state = (page) => page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()).filter((c) => !c.bIsDestroyed); + const live = (c) => c.getDomRef() && document.body.contains(c.getDomRef()); + const t = all.find((c) => c.getId().endsWith('--table-uploadSet') && live(c)); + const p = all.find((c) => c.getId().endsWith('--uploadSetPlugin')); + const en = (s) => { const b = all.find((c) => c.getId().endsWith(`--${s}`)); return b ? b.getEnabled() : null; }; + return { + rows: t.getRows().filter((r) => r.getBindingContext()).map((r) => r.getBindingContext().getProperty('FILENAME')), + sel: t.getSelectedIndices(), + model: t.getModel().getProperty(t.getBinding('rows').getPath()).map((r) => ({ name: r.FILENAME, size: r.FILESIZE })), + dl: en('downloadSelectedButton'), rm: en('removeDocumentButton'), rn: en('renameButton'), ed: en('editUrlButton'), + }; +}); + +async function until(page, pred, msg) { + const deadline = Date.now() + 15000; + let s; + for (;;) { + s = await state(page); + if (pred(s)) return s; + if (Date.now() > deadline) throw new Error(`${msg} - last state ${JSON.stringify(s).slice(0, 400)}`); + await page.waitForTimeout(250); + } +} + +// the row selector sits under the data cells: a real click is intercepted, the +// mousedown/mouseup/click sequence is what sap.ui.table's pointer extension acts on +const selectRow = async (page, i) => { + await dispatchMouse(page.locator(`[id$="--table-uploadSet-rowsel${i}"]`).first()); + await waitForIdle(page); +}; + +// the rename dialog the plugin builds itself: type, read the input's value state +async function renameInput(page, value) { + const dlg = await waitForPopup(page, 'Rename Document'); + const input = dlg.locator('input').first(); + await input.fill(value); + return page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + const d = all.find((c) => !c.bIsDestroyed && c.isA('sap.m.Dialog') && c.isOpen() && c.getTitle() === 'Rename Document'); + return d.getContent()[1].getValueState(); + }); +} + +// a popup the module closed must really be gone before the page is driven again +// (title null: no dialog at all may stay open) +async function waitForClosed(page, title) { + await page.waitForFunction((t) => !Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .some((c) => !c.bIsDestroyed && c.isA('sap.m.Dialog') && c.isOpen() && (t === null || c.getTitle() === t)), + title, { timeout: 10000 }).catch(() => { throw new Error(`the ${title === null ? 'preview' : `"${title}"`} dialog never closed`); }); +} + +async function openRename(page) { + const rn = page.getByRole('button', { name: 'Rename', exact: true }); + await revealInOverflow(page, rn); + await rn.first().click(); + return waitForPopup(page, 'Rename Document'); +} + +export default async (page, expect) => { + await waitForIdle(page); + const start = await until(page, (s) => s.rows.length === 9, 'the nine documents never rendered'); + expect(start.rows[0], 'row 0').toBe('Invoice summary.doc'); + expect(start.dl, 'Download disabled with no selection').toBe(false); + + /* ---- rowSelectionChange (getSelectedIndices) -> the two bound flags ---- */ + await selectRow(page, 0); + await until(page, (s) => s.dl && s.rm && s.rn && s.ed, 'selecting one row never enabled Download/Remove/Rename/Edit URL'); + await selectRow(page, 1); + await until(page, (s) => s.sel.length === 2 && s.dl && !s.rm && !s.rn && !s.ed, 'two selected rows did not leave only Download enabled'); + await selectRow(page, 1); + await until(page, (s) => s.sel.length === 1 && s.dl && s.rm && s.rn, 'deselecting back to one row did not re-enable the single-row buttons'); + + /* ---- download( getContextByIndex( ), true ) ----------- */ + const docUrl = 'https://sdk.openui5.org/test-resources/sap/m/UploadSetwithTableSampleFiles/Business%20Plan%20Agenda.doc'; + await page.route('**/UploadSetwithTableSampleFiles/**', (r) => r.fulfill({ status: 200, contentType: 'application/msword', body: 'e2e' })); + await page.evaluate(() => { + const P = sap.ui.require('sap/m/plugins/UploadSetwithTable').prototype; + window.__dl = []; + if (!P.__e2eDl) { + P.__e2eDl = P.download; + P.download = function (ctx, ask) { + window.__dl.push({ ctx: !!(ctx && ctx.isA && ctx.isA('sap.ui.model.Context')), path: ctx && ctx.getPath && ctx.getPath(), ask }); + return P.__e2eDl.apply(this, arguments); + }; + } + }); + const dlBtn = page.getByRole('button', { name: 'Download', exact: true }); + await revealInOverflow(page, dlBtn); + const [req] = await Promise.all([ + page.waitForRequest((r) => r.url().includes('UploadSetwithTableSampleFiles'), { timeout: 10000 }) + .catch(() => { throw new Error('download( ) never fetched the selected row\'s document URL'); }), + dlBtn.first().click(), + ]); + const dl = await page.evaluate(() => window.__dl); + expect(dl.length, 'plugin.download calls').toBe(1); + expect(dl[0], 'download got the live Context of row 0 and bAskForLocation').toEqual({ ctx: true, path: dl[0].path, ask: true }); + if (!/\/0$/.test(dl[0].path)) throw new Error(`download was handed ${dl[0].path}, not the selected row 0`); + expect(req.url(), 'the fetched document').toBe(docUrl); + + /* ---- renameItem -> itemRenamed writes the new name into the row ------- */ + await openRename(page); + expect(await renameInput(page, 'bad/name'), "'/' is in the default restricted set").toBe('Error'); + expect(await renameInput(page, 'Renamed'), 'the new name').toBe('None'); + await page.getByRole('button', { name: 'Apply', exact: true }).click(); + await expect(page.locator('.sapMMessageToast'), 'the rename toast').toContainText('Document Renamed.'); + await until(page, (s) => s.model[0].name === 'Renamed.doc' && s.rows[0] === 'Renamed.doc', + 'itemRenamed never wrote Renamed.doc into row 0'); + + /* ---- openFilePreview( ) ------------- */ + await page.locator('[id$="--table-uploadSet"] .sapMLnk', { hasText: 'Renamed.doc' }).first().click(); + const preview = await waitForPopup(page, 'Renamed.doc'); + await expect(preview, 'the FilePreviewDialog').toContainText('Renamed.doc'); + await preview.getByRole('button', { name: 'Close', exact: true }).click(); + await waitForClosed(page, null); + + /* ---- upload: beforeUploadStarts vetoed, the backend adds the row -------- */ + // the veto is the point: the plugin must never POST to its uploadUrl + const uploadPosts = []; + page.on('request', (r) => { if (r.url().includes('/uploadFiles')) uploadPosts.push(r.url()); }); + const body = Buffer.from('e2e upload payload'); + await page.locator('input[type=file][id$="uploadSetPlugin-uploader-fu"]').setInputFiles({ + name: 'e2e-upload.txt', mimeType: 'text/plain', buffer: body, + }); + await expect(page.locator('.sapMMessageToast'), 'the upload toast').toContainText('Document Added'); + const up = await until(page, (s) => s.model.length === 10 && s.rows.includes('e2e-upload.txt'), + 'the vetoed upload never added the backend row'); + expect(up.model[0], 'the unshifted row carries name and size').toEqual({ name: 'e2e-upload.txt', size: body.length }); + + expect(uploadPosts.length, 'requests to /uploadFiles (the vetoed upload)').toBe(0); + + /* ---- remove via the row's decline button + MessageBox ------------------- */ + const btn = await page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + const b = all.find((c) => !c.bIsDestroyed && c.isA('sap.m.Button') && c.getIcon() === 'sap-icon://decline' && c.getDomRef() + && c.getBindingContext() && c.getBindingContext().getProperty('FILENAME') === 'Instructions.pdf'); + return b ? b.getId() : null; + }); + if (!btn) throw new Error('the Instructions.pdf row rendered no decline button'); + await page.locator(`[id="${btn}"]`).click(); + const box = await waitForPopup(page, 'Are you sure you want to remove the document Instructions.pdf'); + await box.getByRole('button', { name: 'Remove', exact: true }).click(); + await until(page, (s) => s.model.length === 9 && !s.rows.includes('Instructions.pdf'), + 'Remove never dropped Instructions.pdf'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_655.mjs b/meta/interactions/z2ui5_cl_smpc_app_655.mjs new file mode 100644 index 000000000..00042753f --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_655.mjs @@ -0,0 +1,135 @@ +// sap.m.plugins.UploadSetwithTable - MultiplePluginInstances: three tables, +// three plugins. Closes the LIVE_TEST: each table's selectionChange (its id +// plus getSelectedContexts().length) driving ITS Download flag only; the plugin +// calls by id through control_by_id with a live Context - download on the +// second plugin, openFilePreview on the third - each landing on its own plugin +// instance; the vetoed beforeUploadStarts with $event.oSource.data('itemsPath') +// filing the backend row into the right array; the remove MessageBox (which, +// as in the original, clears the first table's selection) and the search that +// filters the first table. +import { waitForIdle, revealInOverflow, waitForPopup } from '../../scripts/lib-e2e.mjs'; + +const TABLES = ['table-uploadSet', 'table-uploadSet-instance2', 'table-uploadSet-instance3']; + +// per table: live rows (filtered ones drop out), model rows, its Download flag +const state = (page) => page.evaluate((ids) => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()).filter((c) => !c.bIsDestroyed); + const live = (c) => c.getDomRef() && document.body.contains(c.getDomRef()); + const en = (s) => { const b = all.find((c) => c.getId().endsWith(`--${s}`)); return b ? b.getEnabled() : null; }; + const btns = ['downloadSelectedButton', 'downloadSelectedButton-instance2', 'downloadSelectedButton-instance3']; + return ids.map((id, i) => { + const t = all.find((c) => c.getId().endsWith(`--${id}`) && live(c)); + return { + rows: t.getItems().filter((r) => r.getBindingContext()).map((r) => r.getBindingContext().getProperty('FILENAME')), + model: t.getModel().getProperty(t.getBinding('items').getPath()).map((r) => ({ name: r.FILENAME, size: r.FILESIZE })), + dl: en(btns[i]), + }; + }); +}, TABLES); + +async function until(page, pred, msg) { + const deadline = Date.now() + 15000; + let s; + for (;;) { + s = await state(page); + if (pred(s)) return s; + if (Date.now() > deadline) throw new Error(`${msg} - last state ${JSON.stringify(s.map((t) => ({ rows: t.rows, dl: t.dl }))).slice(0, 500)}`); + await page.waitForTimeout(250); + } +} + +const selectRow = async (page, table, i) => { + await page.locator(`[id$="--${table}-${i}-selectMulti"]`).first().click(); + await waitForIdle(page); +}; + +// a popup the module closed must really be gone before the page is driven again +// (title null: no dialog at all may stay open) +async function waitForClosed(page, title) { + await page.waitForFunction((t) => !Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .some((c) => !c.bIsDestroyed && c.isA('sap.m.Dialog') && c.isOpen() && (t === null || c.getTitle() === t)), + title, { timeout: 10000 }).catch(() => { throw new Error(`the ${title === null ? 'preview' : `"${title}"`} dialog never closed`); }); +} + +export default async (page, expect) => { + await waitForIdle(page); + const start = await until(page, (s) => s.every((t) => t.rows.length === 3), 'the three tables never rendered three rows each'); + expect(start.map((t) => t.rows[0]), 'the first row of each table') + .toEqual(['Invoice summary.doc', 'Document.txt', 'Test Video.mp4']); + expect(start.map((t) => t.dl), 'no Download enabled without a selection').toEqual([false, false, false]); + + /* ---- selectionChange: each table drives its own Download flag ---------- */ + await selectRow(page, TABLES[1], 0); + await until(page, (s) => !s[0].dl && s[1].dl && !s[2].dl, 'selecting in table 2 did not enable exactly its Download'); + await selectRow(page, TABLES[0], 0); + await until(page, (s) => s[0].dl && s[1].dl && !s[2].dl, 'selecting in table 1 did not enable its Download'); + + /* ---- download on the SECOND plugin with table 2's live Context --------- */ + await page.route('**/UploadSetwithTableSampleFiles/**', (r) => r.fulfill({ status: 200, contentType: 'text/plain', body: 'e2e' })); + await page.evaluate(() => { + const P = sap.ui.require('sap/m/plugins/UploadSetwithTable').prototype; + window.__calls = []; + if (!P.__e2eWrapped) { + P.__e2eWrapped = true; + for (const m of ['download', 'openFilePreview']) { + const orig = P[m]; + P[m] = function (ctx) { + window.__calls.push({ m, plugin: this.getId().replace(/^.*--/, ''), + ctx: !!(ctx && ctx.isA && ctx.isA('sap.ui.model.Context')), path: ctx && ctx.getPath && ctx.getPath() }); + return orig.apply(this, arguments); + }; + } + } + }); + const dl2 = page.locator('[id$="--downloadSelectedButton-instance2"]'); + await revealInOverflow(page, dl2); + const [req] = await Promise.all([ + page.waitForRequest((r) => r.url().includes('UploadSetwithTableSampleFiles'), { timeout: 10000 }) + .catch(() => { throw new Error('download( ) never fetched table 2\'s selected document'); }), + dl2.first().click(), + ]); + expect(req.url(), 'the fetched document').toBe('https://sdk.openui5.org/test-resources/sap/m/UploadSetwithTableSampleFiles/Document.txt'); + expect(await page.evaluate(() => window.__calls), 'the download call') + .toEqual([{ m: 'download', plugin: 'uploadSetPlugin-instance2', ctx: true, path: '/T_ITEMSINSTANCE2/0' }]); + + /* ---- openFilePreview on the THIRD plugin from its Link's Context ------- */ + await page.locator('[id$="--table-uploadSet-instance3"] .sapMLnk', { hasText: 'Test Video.mp4' }).first().click(); + const preview = await waitForPopup(page, 'Test Video.mp4'); + await expect(preview, 'the FilePreviewDialog').toContainText('Test Video.mp4'); + const calls = await page.evaluate(() => window.__calls); + expect(calls[calls.length - 1], 'the preview call') + .toEqual({ m: 'openFilePreview', plugin: 'uploadSetPlugin-instance3', ctx: true, path: '/T_ITEMSINSTANCE3/0' }); + await preview.getByRole('button', { name: 'Close', exact: true }).click(); + await waitForClosed(page, null); + + /* ---- upload through plugin 2: itemsPath files the row into ITS array --- */ + // the veto is the point: the plugin must never POST to its uploadUrl + const uploadPosts = []; + page.on('request', (r) => { if (r.url().includes('/uploadFiles')) uploadPosts.push(r.url()); }); + const body = Buffer.from('e2e upload payload'); + await page.locator('input[type=file][id$="--uploadSetPlugin-instance2-uploader-fu"]').setInputFiles({ + name: 'e2e-upload.txt', mimeType: 'text/plain', buffer: body, + }); + await expect(page.locator('.sapMMessageToast'), 'the upload toast').toContainText('Document Added'); + const up = await until(page, (s) => s[1].model.length === 4 && s[1].rows.includes('e2e-upload.txt'), + 'the vetoed upload never added the row to table 2'); + expect(up[1].model[0], 'the unshifted row carries name and size').toEqual({ name: 'e2e-upload.txt', size: body.length }); + expect([up[0].model.length, up[2].model.length], 'tables 1 and 3 untouched').toEqual([3, 3]); + + expect(uploadPosts.length, 'requests to /uploadFiles (the vetoed upload)').toBe(0); + + /* ---- remove in table 1 via the decline button + MessageBox ------------- */ + const idx = up[0].rows.indexOf('Business Plan Topics.xls'); + await page.locator(`[id$="--table-uploadSet-${idx}"] button`).last().click(); + const box = await waitForPopup(page, 'Are you sure you want to remove the document Business Plan Topics.xls'); + await box.getByRole('button', { name: 'Remove', exact: true }).click(); + await until(page, (s) => s[0].model.length === 2 && !s[0].rows.includes('Business Plan Topics.xls'), + 'Remove never dropped Business Plan Topics.xls'); + await until(page, (s) => !s[0].dl && s[1].dl, 'the removal did not clear table 1\'s Download flag (only)'); + + /* ---- search: the binding_call filter on the FIRST table ---------------- */ + await page.locator('.sapMSF input').first().fill('Invoice'); + await until(page, (s) => s[0].rows.length === 1 && s[0].rows[0] === 'Invoice summary.doc', 'the search never filtered table 1'); + await page.locator('.sapMSF input').first().fill(''); + await until(page, (s) => s[0].rows.length === 2, 'clearing the search did not bring table 1 back'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_656.mjs b/meta/interactions/z2ui5_cl_smpc_app_656.mjs new file mode 100644 index 000000000..efbc1c6d4 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_656.mjs @@ -0,0 +1,189 @@ +// sap.m.plugins.UploadSetwithTable - ResponsiveTableFileDialogs. Closes the +// LIVE_TEST: the plugin calls by id through control_by_id with a live binding +// Context as the event arg (download, renameItem, openFilePreview), the +// selectionChange paths driving the toolbar flags, the itemRenamed wire writing +// the new name, the remove MessageBox, the binding_call search - and this +// variant's point, the vetoed beforeUploadStarts queuing the file into the +// FileUpload dialog (Browse through fileSelectionHandler, the per-file document +// type, the pending-file removal, Add filing it under the chosen type). +import { waitForIdle, revealInOverflow, waitForPopup } from '../../scripts/lib-e2e.mjs'; + +// the table's live rows (filtered ones drop out), the model rows and the four flags +const state = (page) => page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()).filter((c) => !c.bIsDestroyed); + const live = (c) => c.getDomRef() && document.body.contains(c.getDomRef()); + const t = all.find((c) => c.getId().endsWith('--table-uploadSet') && live(c)); + const p = all.find((c) => c.getId().endsWith('--uploadSetPlugin')); + const up = all.find((c) => c.isA('sap.m.Dialog') && c.isOpen() && c.getTitle() === 'Add Document by Upload'); + const en = (s) => { const b = all.find((c) => c.getId().endsWith(`--${s}`)); return b ? b.getEnabled() : null; }; + return { + rows: t.getItems().filter((i) => i.getBindingContext()).map((i) => i.getBindingContext().getProperty('FILENAME')), + model: t.getModel().getProperty(t.getBinding('items').getPath()).map((r) => ({ name: r.FILENAME, size: r.FILESIZE, type: r.DOCUMENTTYPE })), + // the FileUpload popup carries its own copy of the model + pending: ((up && up.getModel().getProperty('/T_SELECTEDITEMS')) || []).map((r) => ({ name: r.FILENAME, type: r.FILECATEGORYSELECTED })), + add: !!(up && up.getModel().getProperty('/ADD_ENABLED')), + dl: en('downloadSelectedButton'), rm: en('removeDocumentButton'), rn: en('renameButton'), ed: en('editUrlButton'), + }; +}); + +async function until(page, pred, msg) { + const deadline = Date.now() + 15000; + let s; + for (;;) { + s = await state(page); + if (pred(s)) return s; + if (Date.now() > deadline) throw new Error(`${msg} - last state ${JSON.stringify({ ...s, rows: s.rows.length, model: s.model.length }).slice(0, 500)}`); + await page.waitForTimeout(250); + } +} + +const selectRow = async (page, i) => { + await page.locator(`[id$="table-uploadSet-${i}-selectMulti"]`).first().click(); + await waitForIdle(page); +}; + +// the rename dialog the plugin builds itself: type, read the input's value state +async function renameInput(page, value) { + const dlg = await waitForPopup(page, 'Rename Document'); + const input = dlg.locator('input').first(); + await input.fill(value); + return page.evaluate(() => { + const all = Object.values(sap.ui.require('sap/ui/core/Element').registry.all()); + const d = all.find((c) => !c.bIsDestroyed && c.isA('sap.m.Dialog') && c.isOpen() && c.getTitle() === 'Rename Document'); + return d.getContent()[1].getValueState(); + }); +} + +// a popup the module closed must really be gone before the page is driven again +// (title null: no dialog at all may stay open) +async function waitForClosed(page, title) { + await page.waitForFunction((t) => !Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .some((c) => !c.bIsDestroyed && c.isA('sap.m.Dialog') && c.isOpen() && (t === null || c.getTitle() === t)), + title, { timeout: 10000 }).catch(() => { throw new Error(`the ${title === null ? 'preview' : `"${title}"`} dialog never closed`); }); +} + +async function openRename(page) { + const rn = page.getByRole('button', { name: 'Rename', exact: true }); + await revealInOverflow(page, rn); + await rn.first().click(); + return waitForPopup(page, 'Rename Document'); +} + +export default async (page, expect) => { + await waitForIdle(page); + const start = await until(page, (s) => s.rows.length === 9, 'the nine documents never rendered'); + expect(start.dl, 'Download disabled with no selection').toBe(false); + + /* ---- selectionChange -> the two bound flags ---------------------------- */ + await selectRow(page, 0); + await until(page, (s) => s.dl && s.rm && s.rn && s.ed, 'selecting one row never enabled Download/Remove/Rename/Edit URL'); + await selectRow(page, 1); + await until(page, (s) => s.dl && !s.rm && !s.rn && !s.ed, 'two selected rows did not leave only Download enabled'); + await selectRow(page, 1); + await until(page, (s) => s.dl && s.rm && s.rn, 'deselecting back to one row did not re-enable the single-row buttons'); + + /* ---- download( , true ) through control_by_id ------------ */ + const docUrl = 'https://sdk.openui5.org/test-resources/sap/m/UploadSetwithTableSampleFiles/Business%20Plan%20Agenda.doc'; + await page.route('**/UploadSetwithTableSampleFiles/**', (r) => r.fulfill({ status: 200, contentType: 'application/msword', body: 'e2e' })); + await page.evaluate(() => { + const P = sap.ui.require('sap/m/plugins/UploadSetwithTable').prototype; + window.__dl = []; + if (!P.__e2eDl) { + P.__e2eDl = P.download; + P.download = function (ctx, ask) { + window.__dl.push({ ctx: !!(ctx && ctx.isA && ctx.isA('sap.ui.model.Context')), path: ctx && ctx.getPath && ctx.getPath(), ask }); + return P.__e2eDl.apply(this, arguments); + }; + } + }); + const dlBtn = page.getByRole('button', { name: 'Download', exact: true }); + await revealInOverflow(page, dlBtn); + const [req] = await Promise.all([ + page.waitForRequest((r) => r.url().includes('UploadSetwithTableSampleFiles'), { timeout: 10000 }) + .catch(() => { throw new Error('download( ) never fetched the selected row\'s document URL'); }), + dlBtn.first().click(), + ]); + const dl = await page.evaluate(() => window.__dl); + expect(dl.length, 'plugin.download calls').toBe(1); + expect(dl[0], 'download got the live Context of row 0 and bAskForLocation').toEqual({ ctx: true, path: dl[0].path, ask: true }); + if (!/\/0$/.test(dl[0].path)) throw new Error(`download was handed ${dl[0].path}, not the selected row 0`); + expect(req.url(), 'the fetched document').toBe(docUrl); + + /* ---- renameItem( ) + the plugin's default restricted set */ + await openRename(page); + expect(await renameInput(page, 'bad/name'), "'/' is in the default restricted set").toBe('Error'); + /* ---- itemRenamed -> the backend writes the new name into the row -------- */ + expect(await renameInput(page, 'Renamed'), 'the new name').toBe('None'); + await page.getByRole('button', { name: 'Apply', exact: true }).click(); + await expect(page.locator('.sapMMessageToast'), 'the rename toast').toContainText('Document Renamed.'); + await until(page, (s) => s.model[0].name === 'Renamed.doc' && s.rows[0] === 'Renamed.doc', + 'itemRenamed never wrote Renamed.doc into row 0'); + + /* ---- openFilePreview( ) ----------------------- */ + await page.locator('[id*="table-uploadSet-0"] .sapMLnk', { hasText: 'Renamed.doc' }).first().click(); + const preview = await waitForPopup(page, 'Renamed.doc'); + await expect(preview, 'the FilePreviewDialog').toContainText('Renamed.doc'); + await preview.getByRole('button', { name: 'Close', exact: true }).click(); + await waitForClosed(page, null); + + /* ---- upload: beforeUploadStarts vetoed -> the FileUpload dialog -------- */ + // the veto is the point: the plugin must never POST to its uploadUrl + const uploadPosts = []; + page.on('request', (r) => { if (r.url().includes('/uploadFiles')) uploadPosts.push(r.url()); }); + const one = Buffer.from('e2e upload one'); + await page.locator('input[type=file][id$="uploadSetPlugin-uploader-fu"]').setInputFiles({ + name: 'e2e-one.txt', mimeType: 'text/plain', buffer: one, + }); + let dlg = await waitForPopup(page, 'Add Document by Upload'); + await expect(dlg, 'the picked file waits in the dialog').toContainText('e2e-one.txt'); + await until(page, (s) => s.pending.length === 1 && s.pending[0].type === 'Invoice' && s.add, + 'the queued file never got its preset type / the Add button'); + // Browse -> the plugin's fileSelectionHandler opens the file dialog again + const [chooser] = await Promise.all([ + page.waitForEvent('filechooser', { timeout: 10000 }) + .catch(() => { throw new Error('Browse never reached fileSelectionHandler (no file chooser opened)'); }), + dlg.getByRole('button', { name: 'Browse', exact: true }).click(), + ]); + await chooser.setFiles({ name: 'e2e-two.txt', mimeType: 'text/plain', buffer: Buffer.from('two') }); + await until(page, (s) => s.pending.length === 2 && s.pending[1].name === 'e2e-two.txt', + 'the second file never joined the dialog'); + // handleRemove - the second file leaves the dialog + dlg = await waitForPopup(page, 'Add Document by Upload'); + await dlg.locator('tr', { hasText: 'e2e-two.txt' }).locator('button').last().click(); + await until(page, (s) => s.pending.length === 1 && s.pending[0].name === 'e2e-one.txt', + 'the decline button never removed the queued file'); + // the document type ComboBox, two-way bound, with its selectionChange wire + dlg = await waitForPopup(page, 'Add Document by Upload'); + const combo = dlg.locator('.sapMComboBox input').first(); + // real keystrokes: the type-ahead picks the item, Enter commits the selection + await combo.click(); + await combo.press('Control+a'); + await combo.pressSequentially('Legal'); + await combo.press('Enter'); + await waitForIdle(page); + await until(page, (s) => s.pending[0].type === 'Legal Document' && s.add, 'the chosen type never reached the queued file'); + await dlg.getByRole('button', { name: 'Add', exact: true }).click(); + await expect(page.locator('.sapMMessageToast'), 'the upload toast').toContainText('Document Added'); + const up = await until(page, (s) => s.model.length === 10 && s.rows.includes('e2e-one.txt'), + 'Add never filed the queued document'); + expect(up.model[0], 'the unshifted row carries name, size and the chosen type') + .toEqual({ name: 'e2e-one.txt', size: one.length, type: 'Legal Document' }); + await waitForClosed(page, 'Add Document by Upload'); + + expect(uploadPosts.length, 'requests to /uploadFiles (the vetoed upload)').toBe(0); + + /* ---- remove via the row's decline button + MessageBox ------------------- */ + const idx = up.rows.indexOf('Instructions.pdf'); + await page.locator(`[id$="table-uploadSet-${idx}"] button`).last().click(); + const box = await waitForPopup(page, 'Are you sure you want to remove the document Instructions.pdf'); + await box.getByRole('button', { name: 'Remove', exact: true }).click(); + await until(page, (s) => s.model.length === 9 && !s.rows.includes('Instructions.pdf'), + 'Remove never dropped Instructions.pdf'); + await until(page, (s) => !s.dl && !s.rm, 'the removal did not reset the toolbar flags'); + + /* ---- search: the binding_call filter on FILENAME ------------------------ */ + await page.locator('.sapMSF input').first().fill('e2e'); + await until(page, (s) => s.rows.length === 1 && s.rows[0] === 'e2e-one.txt', 'the search never filtered the rows'); + await page.locator('.sapMSF input').first().fill(''); + await until(page, (s) => s.rows.length === 9, 'clearing the search did not bring the rows back'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_657.mjs b/meta/interactions/z2ui5_cl_smpc_app_657.mjs new file mode 100644 index 000000000..af953a1bd --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_657.mjs @@ -0,0 +1,18 @@ +// app 657 — sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableFilePreview +// +// The view is app 659's plus a declared upload:FilePreviewDialog +// (showCarouselArrows, maxFileSizeforPreview 50) that the plugin's +// previewDialog association names. So the LIVE_TEST legs are 659's - the +// plugin calls by id with a live Context (openFilePreview / renameItem / +// download), selectionChange driving the toolbar flags, the itemRenamed wire, +// the vetoed beforeUploadStarts, search and the Remove MessageBox - and the +// preview leg additionally asserts that the Link's openFilePreview ran through +// THAT dialog (its id, its two settings, the pressed row as preview item) +// rather than a default one the plugin would create without the association. +import { responsiveTableLegs } from './z2ui5_cl_smpc_app_659.mjs'; + +export default async (page, expect) => { + await responsiveTableLegs(page, expect, { previewDialog: 'FilePreviewDialog' }); + expect(await page.evaluate(() => Object.values(sap.ui.require('sap/ui/core/Element').registry.all()) + .filter((c) => c.isA('sap.m.upload.FilePreviewDialog')).length), 'FilePreviewDialog instances (no default one beside the declared)').toBe(1); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_658.mjs b/meta/interactions/z2ui5_cl_smpc_app_658.mjs new file mode 100644 index 000000000..f92eba1d2 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_658.mjs @@ -0,0 +1,34 @@ +// app 658 — sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableProgressIndicator +// +// The view is app 659's with one difference the LIVE_TEST names: no vetoed +// beforeUploadStarts - the upload really goes out as a POST to /uploadFiles, +// and the uploadCompleted wire transports ${$parameters>/item}.getFileName( ), +// getUrl( ), getFileSize( ) and ${$parameters>/status}; the backend adds the +// row (id, no media type) and toasts 'Document Added' on a 201 only. The +// sample's mock server is switched off, so the harness plays it: the upload +// is answered 201 by a page route, and the row plus the toast must follow. +// Every other leg - the plugin calls by id with a live Context, selection +// flags, rename, preview, search, Remove MessageBox - is 659's. +import { responsiveTableLegs } from './z2ui5_cl_smpc_app_659.mjs'; +import { waitForUi5, waitForIdle } from '../../scripts/lib-e2e.mjs'; + +const FILE = 'input[type="file"][id$="uploadSetPlugin-uploader-fu"]'; + +async function upload(page, expect) { + let posted = 0; + await page.route('**/uploadFiles', (route) => { posted += 1; return route.fulfill({ status: 201, body: '' }); }); + await page.locator(FILE).setInputFiles({ name: 'probe.txt', mimeType: 'text/plain', buffer: Buffer.alloc(1536, 'a') }); + await expect(page.locator('body'), 'the 201 upload toast').toContainText('Document Added'); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed && c.getDomRef()); + if (!t || t.getItems().length !== 9) return false; + const r = t.getItems()[0].getBindingContext().getObject(); + return r.FILENAME === 'probe.txt' && r.ID === 'id1' && r.FILESIZE === 1536 && r.FILESIZE_UNITS === '1.50 KB' + && r.UPLOADSTATE === 'Complete' && !r.MEDIATYPE; + }, 'the completed upload never became the new first row (probe.txt, id1, 1536 bytes = 1.50 KB, Complete, no media type)'); + expect(posted, 'POSTs to /uploadFiles (the upload must really go out)').toBe(1); + await page.unroute('**/uploadFiles'); + await waitForIdle(page); +} + +export default (page, expect) => responsiveTableLegs(page, expect, { upload }); diff --git a/meta/interactions/z2ui5_cl_smpc_app_659.mjs b/meta/interactions/z2ui5_cl_smpc_app_659.mjs new file mode 100644 index 000000000..9b7c3458c --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_659.mjs @@ -0,0 +1,186 @@ +// app 659 — sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableSimple +// +// The LIVE_TEST asks for what only a running app shows: (a) the plugin calls +// by id (uploadSetPlugin) through control_by_id's unlisted-method path - +// openFilePreview with the Link's binding Context, renameItem and download +// with the table's first selected Context - each handing a live Context +// object through untouched; (b) selectionChange transporting the selected +// contexts' paths (the toolbar flags follow) and the itemRenamed wire reading +// the renamed item's binding path; (c) the vetoed beforeUploadStarts with the +// file's size. Plus the roundtrip-free search (binding_call filter) and the +// Remove MessageBox. Each leg asserts the EFFECT: a bound enabled flag, the +// filtered rows, an opened plugin dialog, a model row that changed. +import { waitForUi5, waitForIdle, waitForPopup, revealInOverflow, UI5_ALL_SRC } from '../../scripts/lib-e2e.mjs'; + +// the live table, never the outgoing one a round-trip is tearing down +const TABLE = `ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed + && c.getDomRef() && document.body.contains(c.getDomRef()))`; +const names = (page) => page.evaluate(`(() => { ${UI5_ALL_SRC} const t = ${TABLE}; + return t ? t.getItems().map((i) => i.getBindingContext().getProperty('FILENAME')) : null; })()`); +const enabled = (page) => page.evaluate(`(() => { ${UI5_ALL_SRC} + const b = (s) => { const c = ui5All().find((x) => x.getId().endsWith('--' + s) && !x.bIsDestroyed); return c ? c.getEnabled() : null; }; + return { download: b('downloadSelectedButton'), remove: b('removeDocumentButton'), rename: b('renameButton'), edit: b('editUrlButton') }; })()`); + +async function toggleRow(page, i) { + const id = await page.evaluate(`(() => { ${UI5_ALL_SRC} const t = ${TABLE}; + const r = t && t.getItems()[${i}]; return r ? r.getMultiSelectControl(true).getId() : null; })()`); + if (!id) throw new Error(`row ${i} has no multi-select checkbox`); + await page.locator(`[id="${id}"]`).click(); +} + +async function pressToolbar(page, id) { + const btn = page.locator(`[id$="--${id}"]`).first(); + await revealInOverflow(page, btn); + await btn.click(); +} + +// Shared with 657 (ResponsiveTableFilePreview) and 658 (ProgressIndicator), +// whose views are this one plus a declared FilePreviewDialog, resp. an +// uploadCompleted wire instead of the vetoed beforeUploadStarts: +// previewDialog - the id suffix of the view's own FilePreviewDialog, which +// the plugin must reuse instead of creating a default one +// upload - async (page, expect) => {...} replacing the upload leg +export async function responsiveTableLegs(page, expect, { previewDialog = null, upload = null } = {}) { + // a POST to the sample's /uploadFiles would mean the veto did not take + const uploads = []; + page.on('request', (r) => { if (/\/uploadFiles/.test(r.url())) uploads.push(r.url()); }); + await waitForIdle(page); + expect(await names(page), 'the nine documents.json rows').toEqual([ + 'Invoice summary.doc', 'Business Plan Topics.xls', 'Instructions.pdf', 'Document.txt', 'Test Image.png', + 'Test Attachment.gif', 'Test Video.mp4', 'Sample Zip File.zip', 'Transmission.vds']); + + // ---------------------------------------------------------------- search + // liveChange -> binding_call filter FILENAME Contains ${$source>/value} + const search = page.locator('.sapMSF input[type="search"]').first(); + await search.click(); + await search.pressSequentially('Test'); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed && c.getDomRef()); + const n = t && t.getItems().map((i) => i.getBindingContext().getProperty('FILENAME')); + return n && n.length === 3 && n.every((x) => x.includes('Test')); + }, 'typing "Test" into the SearchField never filtered the table to its three Test rows'); + await search.fill(''); + await search.press('Enter'); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed && c.getDomRef()); + return t && t.getItems().length === 9; + }, 'clearing the SearchField never brought the nine rows back'); + await waitForIdle(page); + + // ------------------------------------------------------------- selection + expect(await enabled(page), 'the toolbar flags before any selection') + .toEqual({ download: false, remove: false, rename: false, edit: false }); + await toggleRow(page, 0); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--renameButton') && !c.bIsDestroyed && c.getEnabled()), + 'selecting one row never enabled Rename - the selectionChange wire did not deliver its context path'); + expect(await enabled(page), 'one row selected').toEqual({ download: true, remove: true, rename: true, edit: true }); + await waitForIdle(page); + await toggleRow(page, 1); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--renameButton') && !c.bIsDestroyed && !c.getEnabled()), + 'a second selected row never disabled Rename'); + expect(await enabled(page), 'two rows selected').toEqual({ download: true, remove: false, rename: false, edit: false }); + await waitForIdle(page); + await toggleRow(page, 1); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--renameButton') && !c.bIsDestroyed && c.getEnabled()), + 'deselecting the second row never re-enabled Rename'); + await waitForIdle(page); + + // spy on the plugin: what control_by_id hands it must be the live Context + await page.evaluate(`(() => { ${UI5_ALL_SRC} + const p = ui5All().find((c) => c.getId().endsWith('--uploadSetPlugin')); + window.__usp = { calls: [], dl: [] }; + for (const m of ['download', 'renameItem', 'openFilePreview']) { + const orig = p[m]; + p[m] = function (...a) { + window.__usp.calls.push({ m, ctx: !!(a[0] && a[0].isA && a[0].isA('sap.ui.model.Context')), + path: a[0] && a[0].getPath ? a[0].getPath() : String(a[0]), rest: a.slice(1) }); + return orig.apply(this, a); + }; + } + const dl = p._initiateFileDownload; + p._initiateFileDownload = function (item, ask) { window.__usp.dl.push({ name: item.getFileName(), url: item.getUrl(), ask }); + return dl.apply(this, arguments); }; + })()`); + const calls = () => page.evaluate(() => window.__usp); + + // -------------------------------------------------------------- download + await pressToolbar(page, 'downloadSelectedButton'); + await page.waitForFunction(() => window.__usp.dl.length > 0, undefined, { timeout: 10000 }).catch(() => {}); + const d = await calls(); + expect(d.calls.find((c) => c.m === 'download'), 'download( ) reached the plugin with the first selected Context and true') + .toEqual({ m: 'download', ctx: true, path: '/T_ITEMS/0', rest: [true] }); + expect(d.dl[0] && d.dl[0].name, 'the plugin resolved the Context to its upload item and started the download') + .toBe('Invoice summary.doc'); + + // ---------------------------------------------------------------- rename + await pressToolbar(page, 'renameButton'); + const dlg = await waitForPopup(page, 'Rename Document'); + expect((await calls()).calls.find((c) => c.m === 'renameItem'), 'renameItem( ) got the selected row\'s Context') + .toEqual({ m: 'renameItem', ctx: true, path: '/T_ITEMS/0', rest: [] }); + const input = dlg.locator('input').first(); + await input.fill('Renamed summary'); + await dlg.getByRole('button', { name: 'Apply' }).click(); + await expect(page.locator('body'), 'the itemRenamed toast').toContainText('Document Renamed.'); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed && c.getDomRef()); + return t && t.getItems()[0].getBindingContext().getProperty('FILENAME') === 'Renamed summary.doc'; + }, 'the itemRenamed wire never wrote "Renamed summary.doc" into row /T_ITEMS/0 of the backend model'); + await waitForIdle(page); + + // --------------------------------------------------------------- preview + await page.locator('.sapMLnk', { hasText: 'Business Plan Topics.xls' }).first().click(); + await waitForUi5(page, () => ui5All().some((c) => c.isA('sap.m.upload.FilePreviewDialog') && c._previewItem + && c._previewItem.getFileName() === 'Business Plan Topics.xls'), + 'pressing the file-name Link never opened the plugin\'s FilePreviewDialog on that row'); + if (previewDialog) { + const used = await page.evaluate(`(() => { ${UI5_ALL_SRC} + const p = ui5All().find((c) => c.getId().endsWith('--uploadSetPlugin')); + const d = sap.ui.require('sap/ui/core/Element').getElementById(p.getPreviewDialog()); + return d ? { id: d.getId().split('--').pop(), arrows: d.getShowCarouselArrows(), max: d.getMaxFileSizeforPreview(), + item: d._previewItem && d._previewItem.getFileName() } : null; })()`); + expect(used, 'the preview ran through the view\'s declared FilePreviewDialog') + .toEqual({ id: previewDialog, arrows: true, max: 50, item: 'Business Plan Topics.xls' }); + } + expect((await calls()).calls.find((c) => c.m === 'openFilePreview'), 'openFilePreview( ) got the Link\'s own Context') + .toEqual({ m: 'openFilePreview', ctx: true, path: '/T_ITEMS/1', rest: [] }); + await waitForUi5(page, () => ui5All().some((c) => c.isA('sap.m.Dialog') && c.isOpen() && c.getDomRef() + && /Business Plan Topics/.test(c.getDomRef().textContent)), 'the preview dialog never opened on screen'); + await page.keyboard.press('Escape'); + await waitForUi5(page, () => !ui5All().some((c) => c.isA('sap.m.Dialog') && c.isOpen()), 'the preview dialog never closed'); + await waitForIdle(page); + + // ---------------------------------------------------------------- remove + // the row's decline button -> REMOVE_ROW with its path -> MessageBox.warning + const declineId = await page.evaluate(`(() => { ${UI5_ALL_SRC} const t = ${TABLE}; + return t.getItems()[0].getCells()[6].getId(); })()`); + await page.locator(`[id="${declineId}"]`).click(); + const box = await waitForPopup(page, 'Are you sure you want to remove the document Renamed summary.doc'); + await box.getByRole('button', { name: 'Remove' }).click(); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed && c.getDomRef()); + return t && t.getItems().length === 8 && t.getItems()[0].getBindingContext().getProperty('FILENAME') === 'Business Plan Topics.xls'; + }, 'confirming Remove never dropped the renamed row'); + await waitForUi5(page, () => ui5All().some((c) => c.getId().endsWith('--downloadSelectedButton') && !c.bIsDestroyed && !c.getEnabled()), + 'the removal never reset the toolbar flags'); + expect(await enabled(page), 'after removal').toEqual({ download: false, remove: false, rename: false, edit: false }); + await waitForIdle(page); + + // ---------------------------------------------------------------- upload + if (upload) { await upload(page, expect); return; } + // a real file pick on the plugin's FileUploader: beforeUploadStarts is + // vetoed (no XHR) and the backend unshifts the mock server's row + await page.locator('input[type="file"][id$="uploadSetPlugin-uploader-fu"]').setInputFiles({ + name: 'probe.txt', mimeType: 'text/plain', buffer: Buffer.alloc(1536, 'a') }); + await expect(page.locator('body'), 'the upload toast').toContainText('Document Added'); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed && c.getDomRef()); + if (!t || t.getItems().length !== 9) return false; + const r = t.getItems()[0].getBindingContext().getObject(); + return r.FILENAME === 'probe.txt' && r.MEDIATYPE === 'text/plain' && r.FILESIZE === 1536 + && r.FILESIZE_UNITS === '1.50 KB' && r.UPLOADSTATE === 'Complete'; + }, 'the picked file never became the new first row (probe.txt, text/plain, 1536 bytes = 1.50 KB, Complete)'); + await page.waitForTimeout(500); + expect(uploads, 'requests to /uploadFiles (the veto must stop the XHR)').toEqual([]); +}; + +export default (page, expect) => responsiveTableLegs(page, expect); diff --git a/meta/interactions/z2ui5_cl_smpc_app_660.mjs b/meta/interactions/z2ui5_cl_smpc_app_660.mjs new file mode 100644 index 000000000..5bed5eb31 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_660.mjs @@ -0,0 +1,158 @@ +// app 660 — sap.m.sample.UploadSetwithTablePlugin.TreeTableSimple +// +// The LIVE_TEST asks for (a) the plugin calls by id (uploadSetPlugin) through +// control_by_id's unlisted-method path - openFilePreview with the template +// Link's binding Context, renameItem and download with +// getContextByIndex(getSelectedIndices()[0]) - each handing a live Context +// through untouched; (b) rowSelectionChange transporting the rows binding's +// selected context paths (nested ones like /T_ITEMS/0/ITEMS/0) and the +// itemRenamed wire reading the renamed item's binding path; (c) the vetoed +// beforeUploadStarts with the file's size. The legs below drive each through +// a real gesture and assert its effect: the bound toolbar flags (files vs a +// folder), the Context the plugin received and what it resolved it to, the +// rename written into a NESTED node, the preview dialog on the pressed row, +// the Remove MessageBox dropping a row, and the picked file's new row. +import { waitForUi5, waitForIdle, waitForPopup, revealInOverflow, dispatchMouse, UI5_ALL_SRC } from '../../scripts/lib-e2e.mjs'; + +const TABLE = `ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed + && c.getDomRef() && document.body.contains(c.getDomRef()))`; +// the shown rows' file names, top to bottom +const shown = (page) => page.evaluate(`(() => { ${UI5_ALL_SRC} const t = ${TABLE}; + return t.getRows().map((r) => r.getBindingContext() && r.getBindingContext().getProperty('FILENAME')).filter(Boolean); })()`); +const model = (page, path) => page.evaluate(`(() => { ${UI5_ALL_SRC} const t = ${TABLE}; + return t.getModel().getProperty(${JSON.stringify(path)}); })()`); +const enabled = (page) => page.evaluate(`(() => { ${UI5_ALL_SRC} + const b = (s) => { const c = ui5All().find((x) => x.getId().endsWith('--' + s) && !x.bIsDestroyed); return c ? c.getEnabled() : null; }; + return { download: b('downloadSelectedButton'), single: b('renameButton') }; })()`); + +// the row selector of the row SHOWING `name`: it sits under the data cells, +// so only a dispatched mouse sequence reaches it (e2e-debugging guide) +async function toggleRow(page, name) { + const i = (await shown(page)).indexOf(name); + if (i < 0) throw new Error(`no row shows "${name}"`); + await dispatchMouse(page.locator(`[id$="--table-uploadSet-rowsel${i}"]`).first()); +} +async function flagsBecome(page, want, msg) { + await waitForUi5(page, (w) => { + const b = (s) => { const c = ui5All().find((x) => x.getId().endsWith('--' + s) && !x.bIsDestroyed); return c && c.getEnabled(); }; + return b('downloadSelectedButton') === w.download && b('renameButton') === w.single; + }, msg, want); + await waitForIdle(page); +} +async function pressToolbar(page, id) { + const btn = page.locator(`[id$="--${id}"]`).first(); + await revealInOverflow(page, btn); + await btn.click(); +} + +export default async (page, expect) => { + const uploads = []; + page.on('request', (r) => { if (/\/uploadFiles/.test(r.url())) uploads.push(r.url()); }); + await waitForIdle(page); + expect(await shown(page), 'the five top-level nodes').toEqual( + ['Documents', 'Test Video.mp4', 'Sample Zip File.zip', 'Attachments', 'Transmission.vds']); + + // expand Documents: its file and its Invoices folder come in under it + await dispatchMouse(page.locator('[id$="--table-uploadSet-rows-row0-treeicon"]').first()); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed && c.getDomRef()); + return t && t.getRows()[1].getBindingContext() && t.getRows()[1].getBindingContext().getPath() === '/T_ITEMS/0/ITEMS/0'; + }, 'expanding Documents never showed its nested Document.txt'); + expect(await shown(page), 'Documents expanded').toEqual( + ['Documents', 'Document.txt', 'Invoices', 'Test Video.mp4', 'Sample Zip File.zip', 'Attachments', 'Transmission.vds']); + + // ------------------------------------------------------------- selection + // the nested file alone: Download and the single-file buttons + expect(await enabled(page), 'flags before any selection').toEqual({ download: false, single: false }); + await toggleRow(page, 'Document.txt'); + await flagsBecome(page, { download: true, single: true }, + 'selecting the nested Document.txt never enabled Download and Rename - rowSelectionChange did not deliver /T_ITEMS/0/ITEMS/0 as a file'); + // plus a folder: both off, as onSelectionChange decides + await toggleRow(page, 'Invoices'); + await flagsBecome(page, { download: false, single: false }, 'selecting the Invoices folder as well never disabled the buttons'); + await toggleRow(page, 'Invoices'); + await flagsBecome(page, { download: true, single: true }, 'deselecting the folder never re-enabled the buttons'); + + await page.evaluate(`(() => { ${UI5_ALL_SRC} + const p = ui5All().find((c) => c.getId().endsWith('--uploadSetPlugin')); + window.__usp = { calls: [], dl: [] }; + for (const m of ['download', 'renameItem', 'openFilePreview']) { + const orig = p[m]; + p[m] = function (...a) { + window.__usp.calls.push({ m, ctx: !!(a[0] && a[0].isA && a[0].isA('sap.ui.model.Context')), + path: a[0] && a[0].getPath ? a[0].getPath() : String(a[0]), rest: a.slice(1) }); + return orig.apply(this, a); + }; + } + const dl = p._initiateFileDownload; + p._initiateFileDownload = function (item, ask) { window.__usp.dl.push({ name: item.getFileName(), ask }); + return dl.apply(this, arguments); }; + })()`); + const calls = () => page.evaluate(() => window.__usp); + + // -------------------------------------------------------------- download + await pressToolbar(page, 'downloadSelectedButton'); + await page.waitForFunction(() => window.__usp.dl.length > 0, undefined, { timeout: 10000 }).catch(() => {}); + const d = await calls(); + expect(d.calls.find((c) => c.m === 'download'), 'download( ) got the selected nested row\'s Context and true') + .toEqual({ m: 'download', ctx: true, path: '/T_ITEMS/0/ITEMS/0', rest: [true] }); + expect(d.dl[0] && d.dl[0].name, 'the plugin resolved it to its upload item and started the download').toBe('Document.txt'); + + // ---------------------------------------------------------------- rename + await pressToolbar(page, 'renameButton'); + const dlg = await waitForPopup(page, 'Rename Document'); + expect((await calls()).calls.find((c) => c.m === 'renameItem'), 'renameItem( ) got the selected row\'s Context') + .toEqual({ m: 'renameItem', ctx: true, path: '/T_ITEMS/0/ITEMS/0', rest: [] }); + await dlg.locator('input').first().fill('Notes'); + await dlg.getByRole('button', { name: 'Apply' }).click(); + await expect(page.locator('body'), 'the itemRenamed toast').toContainText('Document Renamed.'); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed && c.getDomRef()); + return t && t.getModel().getProperty('/T_ITEMS/0/ITEMS/0/FILENAME') === 'Notes.txt'; + }, 'the itemRenamed wire never wrote "Notes.txt" into the nested node /T_ITEMS/0/ITEMS/0'); + await waitForIdle(page); + + // --------------------------------------------------------------- preview + await page.locator('.sapMLnk', { hasText: 'Test Video.mp4' }).first().click(); + await waitForUi5(page, () => ui5All().some((c) => c.isA('sap.m.upload.FilePreviewDialog') && c._previewItem + && c._previewItem.getFileName() === 'Test Video.mp4'), + 'pressing the file-name Link never opened the plugin\'s FilePreviewDialog on that row'); + expect((await calls()).calls.find((c) => c.m === 'openFilePreview'), 'openFilePreview( ) got the template Link\'s own Context') + .toEqual({ m: 'openFilePreview', ctx: true, path: '/T_ITEMS/1', rest: [] }); + await waitForUi5(page, () => ui5All().some((c) => c.isA('sap.m.Dialog') && c.isOpen() && c.getDomRef() + && /Test Video/.test(c.getDomRef().textContent)), 'the preview dialog never opened on screen'); + await page.keyboard.press('Escape'); + await waitForUi5(page, () => !ui5All().some((c) => c.isA('sap.m.Dialog') && c.isOpen()), 'the preview dialog never closed'); + await waitForIdle(page); + + // ---------------------------------------------------------------- remove + const declineId = await page.evaluate(`(() => { ${UI5_ALL_SRC} const t = ${TABLE}; + const r = t.getRows().find((x) => x.getBindingContext() && x.getBindingContext().getProperty('FILENAME') === 'Transmission.vds'); + return r ? r.getCells()[r.getCells().length - 1].getId() : null; })()`); + if (!declineId) throw new Error('the Transmission.vds row has no remove button'); + await page.locator(`[id="${declineId}"]`).click(); + const box = await waitForPopup(page, 'Are you sure you want to remove the document Transmission.vds'); + await box.getByRole('button', { name: 'Remove' }).click(); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed && c.getDomRef()); + const top = t && t.getModel().getProperty('/T_ITEMS'); + return top && top.length === 4 && !top.some((x) => x.FILENAME === 'Transmission.vds'); + }, 'confirming Remove never dropped Transmission.vds'); + await waitForIdle(page); + + // ---------------------------------------------------------------- upload + await page.locator('input[type="file"][id$="uploadSetPlugin-uploader-fu"]').setInputFiles({ + name: 'probe.txt', mimeType: 'text/plain', buffer: Buffer.alloc(1536, 'a') }); + await expect(page.locator('body'), 'the upload toast').toContainText('Document Added'); + await waitForUi5(page, () => { + const t = ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed && c.getDomRef()); + const top = t && t.getModel().getProperty('/T_ITEMS'); + if (!top || top.length !== 5) return false; + const r = top[0]; + return r.FILENAME === 'probe.txt' && r.MEDIATYPE === 'text/plain' && r.FILESIZE === 1536 + && r.FILESIZE_UNITS === '1.50 KB' && r.UPLOADSTATE === 'Complete'; + }, 'the picked file never became the new first node (probe.txt, text/plain, 1536 bytes = 1.50 KB, Complete)'); + expect(await model(page, '/T_ITEMS/0/FILENAME'), 'the new first node').toBe('probe.txt'); + await page.waitForTimeout(500); + expect(uploads, 'requests to /uploadFiles (the veto must stop the XHR)').toEqual([]); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_661.mjs b/meta/interactions/z2ui5_cl_smpc_app_661.mjs new file mode 100644 index 000000000..e8b24545d --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_661.mjs @@ -0,0 +1,227 @@ +// app 661 — sap.m.sample.UploadSetwithTablePlugin.TreeTableWithFolderHierarchy +// +// The LIVE_TEST asks for (a) the two-handler Rename press (.eB(RENAME); +// .eF(control_by_id renameItem)) with its argument - the first selected +// context, or null for a folder - and openFilePreview with the Link's binding +// Context, both through control_by_id's unlisted-method path; (b) +// rowSelectionChange transporting the selected context paths and the +// itemRenamed wire reading the item's binding path; (c) the vetoed +// beforeUploadStarts with the file's size; (d) DOWNLOAD_B64_FILE with an +// https test-resources URL and clearSelection after a navigation. Around +// those, the backend-ported controller: folder navigation (Link and +// Breadcrumbs), Add Folder, Rename Folder, row delete and Remove All. Every +// leg drives a real gesture and asserts the effect on the bound rows, flags, +// breadcrumbs or the plugin call. +import { waitForUi5, waitForIdle, waitForPopup, revealInOverflow, dispatchMouse, pressBreadcrumb, UI5_ALL_SRC } from '../../scripts/lib-e2e.mjs'; + +const TABLE = `ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed + && c.getDomRef() && document.body.contains(c.getDomRef()))`; +const shown = (page) => page.evaluate(`(() => { ${UI5_ALL_SRC} const t = ${TABLE}; + return t.getRows().map((r) => r.getBindingContext() && r.getBindingContext().getProperty('FILENAME')).filter(Boolean); })()`); +const flags = (page) => page.evaluate(`(() => { ${UI5_ALL_SRC} + const b = (s) => { const c = ui5All().find((x) => x.getId().endsWith('--' + s) && !x.bIsDestroyed); return c ? c.getEnabled() : null; }; + return { download: b('downloadSelectedButton'), rename: b('renameButton'), removeAll: b('removeAllButton') }; })()`); +const crumbs = (page) => page.evaluate(`(() => { ${UI5_ALL_SRC} + const b = ui5All().find((c) => c.getId().endsWith('--breadcrumbs') && !c.bIsDestroyed); + return { links: b.getLinks().map((l) => l.getText()), current: b.getCurrentLocationText() }; })()`); + +async function rowsBecome(page, want, msg) { + await waitForUi5(page, (w) => { + const t = ui5All().find((c) => c.getId().endsWith('--table-uploadSet') && !c.bIsDestroyed && c.getDomRef()); + const n = t && t.getRows().map((r) => r.getBindingContext() && r.getBindingContext().getProperty('FILENAME')).filter(Boolean); + return n && JSON.stringify(n) === JSON.stringify(w); + }, `${msg} - wanted rows ${JSON.stringify(want)}`, want); + await waitForIdle(page); +} +// the row selector of the row SHOWING `name` sits under the data cells, so +// only a dispatched mouse sequence reaches it (e2e-debugging guide) +async function toggleRow(page, name) { + const i = (await shown(page)).indexOf(name); + if (i < 0) throw new Error(`no row shows "${name}"`); + await dispatchMouse(page.locator(`[id$="--table-uploadSet-rowsel${i}"]`).first()); +} +async function flagsBecome(page, want, msg) { + await waitForUi5(page, (w) => { + const b = (s) => { const c = ui5All().find((x) => x.getId().endsWith('--' + s) && !x.bIsDestroyed); return c && c.getEnabled(); }; + return b('downloadSelectedButton') === w.download && b('renameButton') === w.rename && b('removeAllButton') === w.removeAll; + }, `${msg} - wanted ${JSON.stringify(want)}`, want); + await waitForIdle(page); +} +async function press(page, id) { + const btn = page.locator(`[id$="--${id}"]`).first(); + await revealInOverflow(page, btn); + await btn.click(); +} +async function pressLink(page, text) { + await page.locator('.sapUiTableCell .sapMLnk', { hasText: text }).first().click(); +} +// The Breadcrumbs can overflow (canOverflow, importance Medium), and in the +// unthemed harness the toolbar does push them into its popover - where they +// render collapsed into their Select. Reveal, then take whichever form shows. +async function pressCrumb(page, text) { + await revealInOverflow(page, page.locator('.sapMBreadcrumbs')); + await pressBreadcrumb(page, text); +} +const toast = (page, text, label) => page.waitForFunction((t) => [...document.querySelectorAll('.sapMMessageToast')] + .some((e) => e.textContent.includes(t)), text, { timeout: 10000 }).catch(() => { throw new Error(`no toast "${text}" (${label})`); }); + +export default async (page, expect) => { + const uploads = []; + page.on('request', (r) => { if (/uploadFiles/.test(r.url())) uploads.push(r.url()); }); + await waitForIdle(page); + const ROOT = ['My Documents', 'Document.txt', 'Business Plan Topics.xls', 'sample-zip-file.zip', 'Temporary Files']; + expect(await shown(page), 'the root of documents.json').toEqual(ROOT); + expect(await crumbs(page), 'the root breadcrumbs').toEqual({ links: [], current: 'Attachments' }); + + // spy on the plugin and on the anchor DOWNLOAD_B64_FILE clicks + await page.evaluate(`(() => { ${UI5_ALL_SRC} + const p = ui5All().find((c) => c.getId().endsWith('--uploadPlugin')); + window.__usp = { calls: [], anchors: [] }; + for (const m of ['renameItem', 'openFilePreview']) { + const orig = p[m]; + p[m] = function (...a) { + window.__usp.calls.push({ m, ctx: !!(a[0] && a[0].isA && a[0].isA('sap.ui.model.Context')), + path: a[0] && a[0].getPath ? a[0].getPath() : String(a[0]) }); + return orig.apply(this, a); + }; + } + // the anchor is recorded, not followed: its href is a CROSS-origin https + // URL, where Chromium ignores the download attribute and would navigate + // the tab away from the app under test + const click = HTMLAnchorElement.prototype.click; + HTMLAnchorElement.prototype.click = function () { + if (this.hasAttribute('download')) { window.__usp.anchors.push({ href: this.href, download: this.download, + attached: document.body.contains(this) }); return; } + return click.apply(this, arguments); + }; + })()`); + const spy = () => page.evaluate(() => window.__usp); + + // ------------------------------------------------------------- selection + expect(await flags(page), 'flags before any selection').toEqual({ download: false, rename: false, removeAll: false }); + await toggleRow(page, 'Document.txt'); + await flagsBecome(page, { download: true, rename: true, removeAll: false }, + 'selecting the file Document.txt never enabled Download and Rename - rowSelectionChange did not deliver its path'); + await toggleRow(page, 'Temporary Files'); + await flagsBecome(page, { download: false, rename: false, removeAll: false }, 'a file plus a folder never disabled Download and Rename'); + await toggleRow(page, 'Temporary Files'); + await flagsBecome(page, { download: true, rename: true, removeAll: false }, 'deselecting the folder never re-enabled them'); + + // -------------------------------------------------------------- download + await press(page, 'downloadSelectedButton'); + await toast(page, 'Download initiated for 1 file(s)', 'onDownloadFiles'); + expect((await spy()).anchors, 'the DOWNLOAD_B64_FILE anchor').toEqual([{ + href: 'https://sdk.openui5.org/test-resources/sap/m/UploadSetwithTableSampleFiles/Document.txt', + download: 'Document.txt', attached: true }]); + await waitForIdle(page); + + // ----------------------------------------------------------- rename file + // two handlers on one press: the backend RENAME (a file: nothing to do) + // and the plugin's renameItem with the selected Context + await press(page, 'renameButton'); + const dlg = await waitForPopup(page, 'Rename Document'); + expect((await spy()).calls.filter((c) => c.m === 'renameItem'), 'renameItem( ) got the selected file\'s Context') + .toEqual([{ m: 'renameItem', ctx: true, path: '/T_ITEMS/1' }]); + await dlg.locator('input').first().fill('Readme'); + await dlg.getByRole('button', { name: 'Apply' }).click(); + await toast(page, 'File renamed successfully', 'itemRenamed'); + await rowsBecome(page, ['My Documents', 'Readme.txt', 'Business Plan Topics.xls', 'sample-zip-file.zip', 'Temporary Files'], + 'the itemRenamed wire never wrote Readme.txt into the node at /T_ITEMS/1'); + + // --------------------------------------------------------- rename folder + // select exactly the folder (whatever the rebuilt rows kept selected) + await page.evaluate(`(() => { ${UI5_ALL_SRC} const t = ${TABLE}; window.__sel = t.getSelectedIndices(); })()`); + for (const i of await page.evaluate(() => window.__sel)) { + await dispatchMouse(page.locator(`[id$="--table-uploadSet-rowsel${i}"]`).first()); + await waitForIdle(page); + } + await toggleRow(page, 'Temporary Files'); + await flagsBecome(page, { download: false, rename: true, removeAll: false }, 'selecting only the folder never enabled Rename alone'); + await press(page, 'renameButton'); + const rf = await waitForPopup(page, 'Rename Folder'); + const renames = (await spy()).calls.filter((c) => c.m === 'renameItem'); + expect(renames[renames.length - 1], 'the second handler handed renameItem null for a folder') + .toEqual({ m: 'renameItem', ctx: false, path: 'null' }); + await rf.locator('input').first().fill('Scratch'); + await rf.locator('input').first().press('Tab'); + await rf.getByRole('button', { name: 'OK' }).click(); + await toast(page, 'Folder renamed successfully', 'RENAME_FOLDER_OK'); + await rowsBecome(page, ['My Documents', 'Readme.txt', 'Business Plan Topics.xls', 'sample-zip-file.zip', 'Scratch'], + 'the Rename Folder dialog never renamed Temporary Files to Scratch'); + + // --------------------------------------------------------------- preview + await pressLink(page, 'Business Plan Topics.xls'); + await waitForUi5(page, () => ui5All().some((c) => c.isA('sap.m.upload.FilePreviewDialog') && c._previewItem + && c._previewItem.getFileName() === 'Business Plan Topics.xls'), + 'pressing the file Link never opened the plugin\'s FilePreviewDialog on that row'); + expect((await spy()).calls.filter((c) => c.m === 'openFilePreview'), 'openFilePreview( ) got the Link\'s own Context') + .toEqual([{ m: 'openFilePreview', ctx: true, path: '/T_ITEMS/2' }]); + await page.keyboard.press('Escape'); + await waitForUi5(page, () => !ui5All().some((c) => c.isA('sap.m.Dialog') && c.isOpen()), 'the preview dialog never closed'); + await waitForIdle(page); + + // ------------------------------------------- navigate in + Remove All + // a folder Link opens the folder: rows, breadcrumbs, and clearSelection + await pressLink(page, 'Scratch'); + await rowsBecome(page, ['Notes.txt'], 'the Scratch folder Link never opened the folder'); + expect(await crumbs(page), 'breadcrumbs inside Scratch').toEqual({ links: ['Attachments'], current: 'Scratch' }); + expect(await page.evaluate(`(() => { ${UI5_ALL_SRC} return ${TABLE}.getSelectedIndices(); })()`), + 'the TreeTable selection after the navigation (clearSelection)').toEqual([]); + expect(await flags(page), 'flags after the navigation').toEqual({ download: false, rename: false, removeAll: false }); + await toggleRow(page, 'Notes.txt'); + await flagsBecome(page, { download: true, rename: true, removeAll: true }, 'selecting every item of the folder never enabled Remove All'); + await press(page, 'removeAllButton'); + const all = await waitForPopup(page, 'Delete All Items'); + await expect(all, 'the Remove All confirm').toContainText('Are you sure you want to delete ALL 1 item(s) in this folder?'); + await all.getByRole('button', { name: 'OK' }).click(); + await toast(page, '1 item(s) deleted successfully', 'deleteAllSelectedItems'); + await rowsBecome(page, [], 'Remove All never emptied the folder'); + + // ------------------------------------------------- breadcrumb back home + await pressCrumb(page, 'Attachments'); + await rowsBecome(page, ['My Documents', 'Readme.txt', 'Business Plan Topics.xls', 'sample-zip-file.zip', 'Scratch'], + 'the Attachments breadcrumb never brought the root back'); + expect(await crumbs(page), 'breadcrumbs back at the root').toEqual({ links: [], current: 'Attachments' }); + + // ------------------------------------------ one level deeper and back + await pressLink(page, 'My Documents'); + await rowsBecome(page, ['Images', 'Reports', 'Third Quarter Results.ppt'], 'the My Documents Link never opened the folder'); + await pressLink(page, 'Images'); + await rowsBecome(page, ['Animation.gif', 'Screenshots'], 'the Images Link never opened the folder'); + expect(await crumbs(page), 'breadcrumbs inside Images').toEqual({ links: ['Attachments', 'My Documents'], current: 'Images' }); + await pressCrumb(page, 'My Documents'); + await rowsBecome(page, ['Images', 'Reports', 'Third Quarter Results.ppt'], 'the My Documents breadcrumb never went one level up'); + + // ------------------------------------------------------------ add folder + await press(page, 'addFolderButton'); + const cf = await waitForPopup(page, 'Create New Folder'); + await cf.locator('input').first().fill('Drafts'); + await cf.locator('input').first().press('Tab'); + await cf.getByRole('button', { name: 'Create' }).click(); + await toast(page, 'New folder created: Drafts', 'createFolderWithName'); + await rowsBecome(page, ['Drafts', 'Images', 'Reports', 'Third Quarter Results.ppt'], 'Add Folder never unshifted Drafts into the open folder'); + + // ------------------------------------------------------------ row delete + const declineId = await page.evaluate(`(() => { ${UI5_ALL_SRC} const t = ${TABLE}; + const r = t.getRows().find((x) => x.getBindingContext() && x.getBindingContext().getProperty('FILENAME') === 'Third Quarter Results.ppt'); + return r ? r.getCells()[r.getCells().length - 1].getId() : null; })()`); + if (!declineId) throw new Error('the Third Quarter Results.ppt row has no delete button'); + await page.locator(`[id="${declineId}"]`).click(); + const del = await waitForPopup(page, 'Delete File'); + await expect(del, 'the delete confirm').toContainText("Are you sure you want to delete the file 'Third Quarter Results.ppt'?"); + await del.getByRole('button', { name: 'OK' }).click(); + await toast(page, "File 'Third Quarter Results.ppt' deleted successfully", 'onRemoveItemHandler'); + await rowsBecome(page, ['Drafts', 'Images', 'Reports'], 'confirming the delete never dropped the file'); + + // ---------------------------------------------------------------- upload + // filed into the OPEN folder behind its folders; no XHR (vetoed) + await page.locator('input[type="file"][id$="uploadPlugin-uploader-fu"]').setInputFiles({ + name: 'probe.txt', mimeType: 'text/plain', buffer: Buffer.alloc(1536, 'a') }); + await toast(page, 'Upload completed successfully.', 'beforeUploadStarts'); + await rowsBecome(page, ['Drafts', 'Images', 'Reports', 'probe.txt'], 'the picked file never landed behind the folders of My Documents'); + const row = await page.evaluate(`(() => { ${UI5_ALL_SRC} const t = ${TABLE}; + const o = t.getModel().getProperty('/T_ITEMS/3'); return { n: o.FILENAME, m: o.MIMETYPE, s: o.SIZE, u: o.SIZE_UNITS, st: o.UPLOADSTATE, by: o.UPLOADEDBY }; })()`); + expect(row, 'the uploaded node').toEqual({ n: 'probe.txt', m: 'text/plain', s: 1536, u: '1.50 KB', st: 'Complete', by: 'Current User' }); + await page.waitForTimeout(500); + expect(uploads, 'requests to uploadFiles (the veto must stop the XHR)').toEqual([]); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_app_670.mjs b/meta/interactions/z2ui5_cl_smpc_app_670.mjs new file mode 100644 index 000000000..446512bf5 --- /dev/null +++ b/meta/interactions/z2ui5_cl_smpc_app_670.mjs @@ -0,0 +1,47 @@ +// HeroBannerIntegrationCard: two sap.ui.integration Cards in the HeroBanner's +// startContent and endContent slots load their manifests by absolute URL +// from sdk.openui5.org and render their List content. +// +// HARNESS: e2e-smoke routes every sdk.openui5.org request to the local UI5 +// package sources and answers 404 for anything it cannot resolve there - and +// /test-resources/... is never resolvable (resolveLocal( ) only maps +// /resources/), so on the default boot both Cards get a 404 manifest and +// render empty (header null, "CardCard"; measured 2026-10-20). The claim +// under test IS the cross-origin fetch from the live demo kit, so this module +// lets exactly those two manifest URLs through to the network (a route +// registered later wins over the harness' catch-all) and reloads the app. +// Serving the archived ui5/ copies instead would prove the Card wiring but +// not the fetch. Needs network access to sdk.openui5.org, like a themed boot. +import { waitForUi5 } from '../../scripts/lib-e2e.mjs'; + +const MANIFEST = /\/test-resources\/sap\/f\/demokit\/sample\/HeroBannerIntegrationCard\/(start|end)ContentManifest\.json$/; + +export default async (page, expect) => { + const fetched = []; + page.on('response', (r) => { + const u = new URL(r.url()); + if (u.hostname === 'sdk.openui5.org' && MANIFEST.test(u.pathname)) fetched.push(`${r.status()} ${u.pathname.split('/').pop()}`); + }); + await page.route((u) => u.hostname === 'sdk.openui5.org' && MANIFEST.test(u.pathname), (route) => route.continue()); + await page.reload({ waitUntil: 'domcontentloaded' }); + + await waitForUi5(page, () => { + const live = (c) => !c.bIsDestroyed && c.getDomRef() && document.body.contains(c.getDomRef()); + const banner = ui5All().find((c) => c.getMetadata().getName() === 'sap.f.HeroBanner' && live(c)); + if (!banner) return false; + const title = (card) => { + const h = card && !card.bIsDestroyed && card.getCardHeader && card.getCardHeader(); + return h ? h.getTitle() : null; + }; + const start = banner.getStartContent()[0]; + const end = banner.getEndContent()[0]; + return title(start) === 'Pending Approvals' && title(end) === 'Upcoming Events' + && /Expense Report Q2/.test(start.getDomRef()?.innerText || '') + && /Team Meeting/.test(end.getDomRef()?.innerText || ''); + }, 'the HeroBanner Cards did not render their manifests\' headers (Pending Approvals in startContent, Upcoming Events in endContent) and List content'); + + await expect(fetched.sort(), 'both manifests were fetched cross-origin from sdk.openui5.org with HTTP 200') + .toEqual(['200 endContentManifest.json', '200 startContentManifest.json']); + await expect(page.locator('body'), 'the start card header on screen').toContainText('Pending Approvals'); + await expect(page.locator('body'), 'the end card header on screen').toContainText('Upcoming Events'); +}; diff --git a/meta/interactions/z2ui5_cl_smpc_demo_004.mjs b/meta/interactions/z2ui5_cl_smpc_demo_004.mjs index 1ed9c61d6..99628073c 100644 --- a/meta/interactions/z2ui5_cl_smpc_demo_004.mjs +++ b/meta/interactions/z2ui5_cl_smpc_demo_004.mjs @@ -336,7 +336,7 @@ export default async (page, expect) => { * 2026-10-08, never locally) */ const enter = async (suffix) => { await Promise.all([ - page.waitForResponse((r) => r.request().method() === 'POST' && r.url().includes(':3000'), { timeout: 15000 }) + page.waitForResponse((r) => r.request().method() === 'POST' && new URL(r.url()).origin === new URL(page.url()).origin, { timeout: 15000 }) .catch(() => { throw new Error(`Enter on the card field ${suffix} sent no round-trip`); }), cardInput(suffix).press('Enter'), ]); diff --git a/meta/z2ui5_cl_smpc_app_624.json b/meta/z2ui5_cl_smpc_app_624.json new file mode 100644 index 000000000..09782e49e --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_624.json @@ -0,0 +1,36 @@ +{ + "class": "z2ui5_cl_smpc_app_624", + "sample": "sap.m.sample.Avatar", + "entity": "sap.m.Avatar", + "file": "src/02/01/z2ui5_cl_smpc_app_624.clas.abap", + "batch": "b52", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "the eight pressable Avatars toast client-side via control_global MESSAGE_TOAST.show with '{0} Pressed' filled by $event.oSource.sId (roundtrip-free) - the app has no on_event" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.Avatar control (since UI5 1.73) is newer than 1.71 and is the whole point of this sample - kept 1:1 (all 30 Avatars, every displaySize/displayShape/backgroundColor/customDisplaySize/fallbackIcon/showBorder value of the original, including the AvatarColor values Transparent/TileIcon/Placeholder/Random), the app needs a UI5 release >= 1.73." + }, + { + "type": "POST_171", + "what": "the Avatar property enabled (since UI5 1.117) is kept 1:1 on the 'Disabled' Avatar (enabled=\"false\") - the app needs a UI5 release >= 1.117 to render it disabled. Like the original it still carries a press wire that can never fire (the view-gates advisory on that line is the original's own shape)." + }, + { + "type": "NOTE", + "what": "onInit's JSONModel (Speakers/Woman01/Woman02/Screw/Lamp = sap.ui.require.toUrl('sap/m/images/...')) is seeded in model_init as the default-model root fields speakers/woman01/woman02/screw/lamp; the module paths have no server-side resolution, so they are pinned to the OpenUI5 host https://sdk.openui5.org/test-resources/sap/m/images/ (same file names, the folder the sample's resourceRoots sap.m.images points at) per the runtime asset-URL rule. The Avatar.src bindings {/Speakers} {/Woman01} {/Woman02} {/Screw} {/Lamp} stay bindings (client->_bind), which structural-diff cannot read statically." + }, + { + "type": "NOTE", + "what": "onPress toasts oEvent.getSource().getId() + ' Pressed'. All eight press wires reproduce that client-side and roundtrip-free (follow_up_action control_global MESSAGE_TOAST.show, template '{0} Pressed' filled by $event.oSource.sId, app 127 precedent); the id itself is a UI5 runtime value whose view prefix differs from the original's." + }, + { + "type": "NOTE", + "what": "the multi-line text attribute of the 'If there is no image...' Text (a line break plus tab indentation inside the attribute in the original view.xml) is written as one line with a single space at the break: XML attribute normalization turns the break and tabs into spaces, which sap.m.Text collapses when rendering, so the output is identical. The original's typo 'proivided' is kept verbatim." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_625.json b/meta/z2ui5_cl_smpc_app_625.json new file mode 100644 index 000000000..972fd96dd --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_625.json @@ -0,0 +1,40 @@ +{ + "class": "z2ui5_cl_smpc_app_625", + "sample": "sap.m.sample.AvatarActiveState", + "entity": "sap.m.Avatar", + "file": "src/02/01/z2ui5_cl_smpc_app_625.clas.abap", + "batch": "b52", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "AVATAR_PRESS round-trip toggles the bound ACTIVE flag and follows up with control_by_id userMenu openBy myAvatar / close; LIST_ITEM_PRESS closes it the same way" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.Avatar control (since UI5 1.73) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.73." + }, + { + "type": "POST_171", + "what": "the Avatar property active (since UI5 1.120) is what this sample demonstrates. The original never writes it in the view - the controller calls setActive( ) - so the port binds it two-way to the ABAP flag active (an extra attribute, the scalar-to-binding move of the recipe); the app needs a UI5 release >= 1.120 to show the active state." + }, + { + "type": "POST_171", + "what": "the Popover property titleAlignment (since UI5 1.72, value Center) is kept 1:1 from Popover.fragment.xml - the app needs a UI5 release >= 1.72 for the centered title." + }, + { + "type": "NOTE", + "what": "onInit loads Popover.fragment.xml with Fragment.load and adds it to the view's dependents; the port declares the same Popover (id userMenu) 1:1 in the view's mvc:dependents aggregation, and the UserMenu.fragment.xml the Popover pulls in through a core:Fragment reference is inlined into it (the List with its eight StandardListItem rows, verbatim) - so the core:Fragment element itself is dropped, and the two core:FragmentDefinition roots are gone with the separate files." + }, + { + "type": "NOTE", + "what": "the controller logic is moved to the backend: onPress (read getActive( ), setActive( !active ), then close( ) or openBy( source )) becomes the AVATAR_PRESS round-trip that flips the bound active flag and follows up with client->follow_up_action( cs_event-control_by_id ) close or openBy anchored to myAvatar; onPopoverClose (afterClose) becomes POPOVER_CLOSE resetting the flag; onListItemPress becomes LIST_ITEM_PRESS resetting the flag and closing the Popover. The original does this client-side, the port needs one round-trip per press, so the active state and the popover appear after that round-trip rather than instantly." + }, + { + "type": "NOTE", + "what": "the round-trip sequence is unverified in a running system: Avatar press -> active true + openBy, second press -> active false + close (sap.m.Popover keeps its opener in the autoclose areas, so the second press should reach AVATAR_PRESS rather than an autoclose), list item press -> close + afterClose round-trip, and that the bound active property follows each step. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_625.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_626.json b/meta/z2ui5_cl_smpc_app_626.json new file mode 100644 index 000000000..49ec934fb --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_626.json @@ -0,0 +1,28 @@ +{ + "class": "z2ui5_cl_smpc_app_626", + "sample": "sap.m.sample.AvatarBadgeIconColor", + "entity": "sap.m.Avatar", + "file": "src/02/01/z2ui5_cl_smpc_app_626.clas.abap", + "batch": "b52", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "the 24 Avatars toast client-side via control_global MESSAGE_TOAST.show with '{0} Pressed' filled by $event.oSource.sId (roundtrip-free) - the app has no on_event" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.Avatar control (since UI5 1.73) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.73." + }, + { + "type": "POST_171", + "what": "the Avatar properties badgeIcon (since UI5 1.77), badgeIconColor (since UI5 1.132, its enum sap.m.AvatarBadgeColor too, with the values Indication1..Indication10 only since UI5 1.140) and badgeValueState (since UI5 1.116) are what this sample demonstrates and are kept 1:1 on all 24 Avatars - the app needs a UI5 release >= 1.140 to render every badge colour." + }, + { + "type": "NOTE", + "what": "onPress toasts oEvent.getSource().getId() + ' Pressed'. All 24 press wires reproduce that client-side and roundtrip-free (follow_up_action control_global MESSAGE_TOAST.show, template '{0} Pressed' filled by $event.oSource.sId, app 127 precedent); the id itself is a UI5 runtime value whose view prefix differs from the original's." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_627.json b/meta/z2ui5_cl_smpc_app_627.json new file mode 100644 index 000000000..19beac0d3 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_627.json @@ -0,0 +1,36 @@ +{ + "class": "z2ui5_cl_smpc_app_627", + "sample": "sap.m.sample.AvatarValueState", + "entity": "sap.m.Avatar", + "file": "src/02/01/z2ui5_cl_smpc_app_627.clas.abap", + "batch": "b52", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "the 5 Avatars toast client-side via control_global MESSAGE_TOAST.show with '{0} Pressed' filled by $event.oSource.sId (roundtrip-free) - the app has no on_event" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.Avatar control (since UI5 1.73) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.73." + }, + { + "type": "POST_171", + "what": "the Avatar properties badgeIcon and badgeTooltip (since UI5 1.77) and badgeValueState (since UI5 1.116) are what this sample demonstrates and are kept 1:1 - the app needs a UI5 release >= 1.116 to render the badge value states." + }, + { + "type": "POST_171", + "what": "the icon sap-icon://information (in the icon font since UI5 1.80) is kept 1:1 as the badgeIcon of the 'Information' Avatar - below 1.80 the badge renders with no icon; covered by the >= 1.116 the badgeValueState already needs." + }, + { + "type": "NOTE", + "what": "onInit's JSONModel (GettyImages/Shutterstock/LowShutterstock = sap.ui.require.toUrl('sap/m/images/...')) is seeded in model_init as the default-model root fields gettyimages and lowshutterstock - Shutterstock is never bound by this view, so it stays out of the model (unbound mock keys are not inlined). The module paths have no server-side resolution, so they are pinned to the OpenUI5 host https://sdk.openui5.org/test-resources/sap/m/images/ (same file names, the folder the sample's resourceRoots sap.m.images points at) per the runtime asset-URL rule. The bindings Avatar.src {/GettyImages} and {/LowShutterstock} stay bindings (client->_bind), which structural-diff cannot read statically." + }, + { + "type": "NOTE", + "what": "onPress toasts oEvent.getSource().getId() + ' Pressed'. All 5 press wires reproduce that client-side and roundtrip-free (follow_up_action control_global MESSAGE_TOAST.show, template '{0} Pressed' filled by $event.oSource.sId, app 127 precedent); the id itself is a UI5 runtime value whose view prefix differs from the original's." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_628.json b/meta/z2ui5_cl_smpc_app_628.json new file mode 100644 index 000000000..71d2bc26e --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_628.json @@ -0,0 +1,32 @@ +{ + "class": "z2ui5_cl_smpc_app_628", + "sample": "sap.m.sample.AvatarWithAffordance", + "entity": "sap.m.Avatar", + "file": "src/02/01/z2ui5_cl_smpc_app_628.clas.abap", + "batch": "b52", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "the seven pressable Avatars toast client-side via control_global MESSAGE_TOAST.show with '{0} Pressed' filled by $event.oSource.sId (roundtrip-free); the LightBox opens by the Avatar itself - the app has no on_event" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.Avatar control (since UI5 1.73) is newer than 1.71 and is the whole point of this sample - kept 1:1 (including its detailBox aggregation with the LightBox/LightBoxItem), the app needs a UI5 release >= 1.73." + }, + { + "type": "POST_171", + "what": "the Avatar properties badgeIcon and badgeTooltip (since UI5 1.77) are what this sample demonstrates and are kept 1:1 - the app needs a UI5 release >= 1.77 to render the affordance badges and their tooltips." + }, + { + "type": "NOTE", + "what": "onInit's JSONModel (GettyImages/Shutterstock/LowShutterstock/LightBox = sap.ui.require.toUrl('sap/m/images/...')) is seeded in model_init as default-model root fields of the same names; the module paths have no server-side resolution, so they are pinned to the OpenUI5 host https://sdk.openui5.org/test-resources/sap/m/images/ (same file names, the folder the sample's resourceRoots sap.m.images points at) per the runtime asset-URL rule. The bindings Avatar.src {/GettyImages} {/Shutterstock} {/LowShutterstock} {/LightBox} and LightBoxItem.imageSrc {/LightBox} stay bindings (client->_bind), which structural-diff cannot read statically." + }, + { + "type": "NOTE", + "what": "onPress toasts oEvent.getSource().getId() + ' Pressed'. All 7 press wires reproduce that client-side and roundtrip-free (follow_up_action control_global MESSAGE_TOAST.show, template '{0} Pressed' filled by $event.oSource.sId, app 127 precedent); the id itself is a UI5 runtime value whose view prefix differs from the original's." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_629.json b/meta/z2ui5_cl_smpc_app_629.json new file mode 100644 index 000000000..4af96c61f --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_629.json @@ -0,0 +1,23 @@ +{ + "class": "z2ui5_cl_smpc_app_629", + "sample": "sap.m.sample.IllustratedMessageEVR", + "entity": "sap.m.IllustratedMessage", + "file": "src/02/01/z2ui5_cl_smpc_app_629.clas.abap", + "batch": "b53", + "audit": { + "frontend_action": false, + "event_t_arg": false + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.IllustratedMessage control (since UI5 1.98) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.98." + }, + { + "type": "POST_171", + "what": "the IllustratedMessage property enableVerticalResponsiveness (since UI5 1.104) is newer than 1.71 but kept 1:1 - the app needs a UI5 release >= 1.104. Declared by policy: the property gate does not know IllustratedMessage (absent from ui5/properties.json) and passes it silently." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_630.json b/meta/z2ui5_cl_smpc_app_630.json new file mode 100644 index 000000000..2e6ee0bf8 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_630.json @@ -0,0 +1,39 @@ +{ + "class": "z2ui5_cl_smpc_app_630", + "sample": "sap.m.sample.IllustratedMessageInAppCustom", + "entity": "sap.m.IllustratedMessage", + "file": "src/02/01/z2ui5_cl_smpc_app_630.clas.abap", + "batch": "b53", + "audit": { + "frontend_action": false, + "event_t_arg": false + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.IllustratedMessage control (since UI5 1.98) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.98." + }, + { + "type": "POST_171", + "what": "the Illustration Size Select offers the sap.m.IllustratedMessageSize values ExtraSmall, Small, Medium and Large (enum values since UI5 1.136; Auto and Base since 1.98), bound as model data into illustrationSize exactly like the original's library-derived list - selecting one needs a UI5 release >= 1.136. Declared by policy: a bound enum value is invisible to every gate." + }, + { + "type": "NOTE", + "what": "the original's Select change handlers (onSelectSize) only copy selectedItem.getKey() into the model path the IllustratedMessage binds; the port binds each Select's selectedKey two-way to that same field instead (an attribute the original view does not carry), so the illustration follows the selection on the client with no round-trip - the app-009 prefer-a-bindable-property pattern. The Select change attribute is therefore dropped vs the original view." + }, + { + "type": "IMPROVISED", + "what": "the original Component.js registers the 'Custom' illustration set via sap.m.IllustrationPool.registerIllustrationSet( { setFamily, setURI } ) in its init. abap2UI5 has no Component of its own and no frontend action reaches IllustrationPool (the CONTROL_GLOBAL targets carry ICON_POOL registerFont for icon fonts, but no illustration-pool counterpart), so the port cannot register the set: illustrationType Custom-EmptyCart is kept verbatim, but the four Custom-*-EmptyCart.svg assets and metadata.json are never loaded, so the IllustratedMessage renders its title, description and Button with an EMPTY illustration area and UI5 logs 'The illustration set Custom is not registered'. The assets are not reachable as a plain URL either: IllustratedMessage.src only accepts the sap-illustration:// scheme, which resolves through the same registry. The view itself is kept 1:1. Upstream request: an ILLUSTRATION_POOL global target with registerIllustrationSet( setFamily, setURI ), the exact analogue of ICON_POOL." + }, + { + "type": "NOTE", + "what": "this sample's point is the BUILD pipeline (a UI5 CLI custom task add-illustrations-task.js that validates and copies the illustrations of an npm package, mock-external-package/ui5-illustrations-library, into webapp/resources/illustrations) - tooling with no abap2UI5 counterpart. Only its runtime view (webapp/view/Main.view.xml, identical to IllustratedMessageInPageCustom) is ported." + } + ], + "render_smoke": { + "skip": true, + "reason": "the port cannot register the Custom illustration set (see the IMPROVISED deviation), so the IllustratedMessage's illustrationType Custom-EmptyCart makes IllustrationPool log 'The illustration set Custom is not registered', which the render harness reports. The rest of the view renders. Lifts when an ILLUSTRATION_POOL frontend action exists and the port registers the set." + } +} diff --git a/meta/z2ui5_cl_smpc_app_631.json b/meta/z2ui5_cl_smpc_app_631.json new file mode 100644 index 000000000..8662f8f3e --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_631.json @@ -0,0 +1,19 @@ +{ + "class": "z2ui5_cl_smpc_app_631", + "sample": "sap.m.sample.IllustratedMessageInCardNoActivities", + "entity": "sap.m.IllustratedMessage", + "file": "src/02/01/z2ui5_cl_smpc_app_631.clas.abap", + "batch": "b53", + "audit": { + "frontend_action": false, + "event_t_arg": false + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.IllustratedMessage control (since UI5 1.98) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.98." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_632.json b/meta/z2ui5_cl_smpc_app_632.json new file mode 100644 index 000000000..5b679a1a0 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_632.json @@ -0,0 +1,19 @@ +{ + "class": "z2ui5_cl_smpc_app_632", + "sample": "sap.m.sample.IllustratedMessageInCardNoEmail", + "entity": "sap.m.IllustratedMessage", + "file": "src/02/01/z2ui5_cl_smpc_app_632.clas.abap", + "batch": "b53", + "audit": { + "frontend_action": false, + "event_t_arg": false + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.IllustratedMessage control (since UI5 1.98) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.98." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_633.json b/meta/z2ui5_cl_smpc_app_633.json new file mode 100644 index 000000000..80c57df67 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_633.json @@ -0,0 +1,24 @@ +{ + "class": "z2ui5_cl_smpc_app_633", + "sample": "sap.m.sample.IllustratedMessageInDialog", + "entity": "sap.m.IllustratedMessage", + "file": "src/02/01/z2ui5_cl_smpc_app_633.clas.abap", + "batch": "b53", + "audit": { + "frontend_action": true, + "event_t_arg": false, + "note": "follow_up_action( cs_event-popup_close ) on the dialog's Close button" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.IllustratedMessage control (since UI5 1.98) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.98." + }, + { + "type": "NOTE", + "what": "the controller-built Dialog (Fragment.load of fragments/Dialog + addDependent + open) is shown with client->popup_display( ) of the same fragment, rebuilt 1:1; onDialogClose's close() is the roundtrip-free follow_up_action( cs_event-popup_close ) on the Close Button press." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_634.json b/meta/z2ui5_cl_smpc_app_634.json new file mode 100644 index 000000000..08d4d4274 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_634.json @@ -0,0 +1,39 @@ +{ + "class": "z2ui5_cl_smpc_app_634", + "sample": "sap.m.sample.IllustratedMessageInPage", + "entity": "sap.m.IllustratedMessage", + "file": "src/02/01/z2ui5_cl_smpc_app_634.clas.abap", + "batch": "b53", + "audit": { + "frontend_action": false, + "event_t_arg": false + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.IllustratedMessage control (since UI5 1.98) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.98." + }, + { + "type": "POST_171", + "what": "the IllustratedMessage property enableVerticalResponsiveness (since UI5 1.104) is newer than 1.71 but kept 1:1 - the app needs a UI5 release >= 1.104. Declared by policy: the property gate does not know IllustratedMessage (absent from ui5/properties.json) and passes it silently." + }, + { + "type": "POST_171", + "what": "the Illustration Size Select offers the sap.m.IllustratedMessageSize values ExtraSmall, Small, Medium and Large (enum values since UI5 1.136; Auto and Base since 1.98), bound as model data into illustrationSize exactly like the original's library-derived list - selecting one needs a UI5 release >= 1.136. Declared by policy: a bound enum value is invisible to every gate." + }, + { + "type": "NOTE", + "what": "the original's Select change handlers (onSelectSize, onSelectType) only copy selectedItem.getKey() into the model path the IllustratedMessage binds; the port binds each Select's selectedKey two-way to that same field instead (an attribute the original view does not carry), so the illustration follows the selection on the client with no round-trip - the app-009 prefer-a-bindable-property pattern. The Select change attribute is therefore dropped vs the original view." + }, + { + "type": "NOTE", + "what": "the Switch change handler onSwitchEVS only re-writes oEvent.getParameter('state') into /sSelectedEVS, which the Switch state binding already writes two-way - the port keeps the two-way state binding and drops the redundant Switch change attribute (no loss; enableVerticalResponsiveness and the expression-bound Text follow on the client)." + }, + { + "type": "NOTE", + "what": "the 32 illustration types are the original's own literal aIMITypeData list (key = the sap.m.IllustratedMessageType value, text = its name), in its order; the six sizes are its aIMISizeData list (key = text = the IllustratedMessageSize value). /sSelectedEVS is seeded from the IllustratedMessage default (false), which is what the original reads back via byId('im').getEnableVerticalResponsiveness()." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_635.json b/meta/z2ui5_cl_smpc_app_635.json new file mode 100644 index 000000000..e6538a13f --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_635.json @@ -0,0 +1,35 @@ +{ + "class": "z2ui5_cl_smpc_app_635", + "sample": "sap.m.sample.IllustratedMessageInPageCustom", + "entity": "sap.m.IllustratedMessage", + "file": "src/02/01/z2ui5_cl_smpc_app_635.clas.abap", + "batch": "b53", + "audit": { + "frontend_action": false, + "event_t_arg": false + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.IllustratedMessage control (since UI5 1.98) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.98." + }, + { + "type": "POST_171", + "what": "the Illustration Size Select offers the sap.m.IllustratedMessageSize values ExtraSmall, Small, Medium and Large (enum values since UI5 1.136; Auto and Base since 1.98), bound as model data into illustrationSize exactly like the original's library-derived list - selecting one needs a UI5 release >= 1.136. Declared by policy: a bound enum value is invisible to every gate." + }, + { + "type": "NOTE", + "what": "the original's Select change handlers (onSelectSize) only copy selectedItem.getKey() into the model path the IllustratedMessage binds; the port binds each Select's selectedKey two-way to that same field instead (an attribute the original view does not carry), so the illustration follows the selection on the client with no round-trip - the app-009 prefer-a-bindable-property pattern. The Select change attribute is therefore dropped vs the original view." + }, + { + "type": "IMPROVISED", + "what": "the original Component.js registers the 'Custom' illustration set via sap.m.IllustrationPool.registerIllustrationSet( { setFamily, setURI } ) in its init. abap2UI5 has no Component of its own and no frontend action reaches IllustrationPool (the CONTROL_GLOBAL targets carry ICON_POOL registerFont for icon fonts, but no illustration-pool counterpart), so the port cannot register the set: illustrationType Custom-EmptyCart is kept verbatim, but the four Custom-*-EmptyCart.svg assets and metadata.json are never loaded, so the IllustratedMessage renders its title, description and Button with an EMPTY illustration area and UI5 logs 'The illustration set Custom is not registered'. The assets are not reachable as a plain URL either: IllustratedMessage.src only accepts the sap-illustration:// scheme, which resolves through the same registry. The view itself is kept 1:1. Upstream request: an ILLUSTRATION_POOL global target with registerIllustrationSet( setFamily, setURI ), the exact analogue of ICON_POOL." + } + ], + "render_smoke": { + "skip": true, + "reason": "the port cannot register the Custom illustration set (see the IMPROVISED deviation), so the IllustratedMessage's illustrationType Custom-EmptyCart makes IllustrationPool log 'The illustration set Custom is not registered', which the render harness reports. The rest of the view renders. Lifts when an ILLUSTRATION_POOL frontend action exists and the port registers the set." + } +} diff --git a/meta/z2ui5_cl_smpc_app_636.json b/meta/z2ui5_cl_smpc_app_636.json new file mode 100644 index 000000000..1ce0ead36 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_636.json @@ -0,0 +1,35 @@ +{ + "class": "z2ui5_cl_smpc_app_636", + "sample": "sap.m.sample.IllustratedMessageInPageTNT", + "entity": "sap.m.IllustratedMessage", + "file": "src/02/01/z2ui5_cl_smpc_app_636.clas.abap", + "batch": "b53", + "audit": { + "frontend_action": false, + "event_t_arg": false + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.IllustratedMessage control (since UI5 1.98) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.98." + }, + { + "type": "POST_171", + "what": "the Illustration Size Select offers the sap.m.IllustratedMessageSize values ExtraSmall, Small, Medium and Large (enum values since UI5 1.136; Auto and Base since 1.98), bound as model data into illustrationSize exactly like the original's library-derived list - selecting one needs a UI5 release >= 1.136. Declared by policy: a bound enum value is invisible to every gate." + }, + { + "type": "NOTE", + "what": "the original's Select change handlers (onSelectSize, onSelectType) only copy selectedItem.getKey() into the model path the IllustratedMessage binds; the port binds each Select's selectedKey two-way to that same field instead (an attribute the original view does not carry), so the illustration follows the selection on the client with no round-trip - the app-009 prefer-a-bindable-property pattern. The Select change attribute is therefore dropped vs the original view." + }, + { + "type": "IMPROVISED", + "what": "the original Component.js registers the 'tnt' illustration set via sap.m.IllustrationPool.registerIllustrationSet( { setFamily, setURI } ) in its init. abap2UI5 has no Component of its own and no frontend action reaches IllustrationPool (the CONTROL_GLOBAL targets carry ICON_POOL registerFont for icon fonts, but no illustration-pool counterpart), so the port cannot register the set: every tnt-* type the Illustration Type Select offers resolves to no registered set, so the illustration area stays EMPTY (title, description and Button still render) and UI5 logs 'The illustration set tnt is not registered'. The view itself is kept 1:1. Upstream request: an ILLUSTRATION_POOL global target with registerIllustrationSet( setFamily, setURI ), the exact analogue of ICON_POOL." + }, + { + "type": "NOTE", + "what": "the type list is the original's _populateIllustrationTypes result - every key of sap.tnt.IllustratedMessageType in declaration order (46 keys at OpenUI5 1.152, key = tnt-, text = ), which overwrites the onInit placeholder [tnt-FaceID] before the view binds, so the port seeds the final list directly. The enum is read at runtime in the original, so a newer release may list more types than the port." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_637.json b/meta/z2ui5_cl_smpc_app_637.json new file mode 100644 index 000000000..39017ed99 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_637.json @@ -0,0 +1,47 @@ +{ + "class": "z2ui5_cl_smpc_app_637", + "sample": "sap.m.sample.IllustratedMessageInPageWithURI", + "entity": "sap.m.IllustratedMessage", + "file": "src/02/01/z2ui5_cl_smpc_app_637.clas.abap", + "batch": "b53", + "audit": { + "frontend_action": false, + "event_t_arg": false + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.IllustratedMessage control (since UI5 1.98) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.98." + }, + { + "type": "POST_171", + "what": "the IllustratedMessage property enableVerticalResponsiveness (since UI5 1.104) is newer than 1.71 but kept 1:1 - the app needs a UI5 release >= 1.104. Declared by policy: the property gate does not know IllustratedMessage (absent from ui5/properties.json) and passes it silently." + }, + { + "type": "POST_171", + "what": "the Illustration Size Select offers the sap.m.IllustratedMessageSize values ExtraSmall, Small, Medium and Large (enum values since UI5 1.136; Auto and Base since 1.98), bound as model data into illustrationSize exactly like the original's library-derived list - selecting one needs a UI5 release >= 1.136. Declared by policy: a bound enum value is invisible to every gate." + }, + { + "type": "NOTE", + "what": "the original's Select change handlers (onSelectSize, onSelectType) only copy selectedItem.getKey() into the model path the IllustratedMessage binds; the port binds each Select's selectedKey two-way to that same field instead (an attribute the original view does not carry), so the illustration follows the selection on the client with no round-trip - the app-009 prefer-a-bindable-property pattern. The Select change attribute is therefore dropped vs the original view." + }, + { + "type": "NOTE", + "what": "the Switch change handler onSwitchEVS only re-writes oEvent.getParameter('state') into /sSelectedEVS, which the Switch state binding already writes two-way - the port keeps the two-way state binding and drops the redundant Switch change attribute (no loss; enableVerticalResponsiveness and the expression-bound Text follow on the client)." + }, + { + "type": "POST_171", + "what": "the IllustratedMessage property src (since UI5 1.132), the point of this sample, is kept 1:1 bound to /sSelectedSRC - the app needs a UI5 release >= 1.132. Declared by policy: the property gate does not know IllustratedMessage and passes it silently." + }, + { + "type": "IMPROVISED", + "what": "the original Component.js registers the 'tnt' illustration set via sap.m.IllustrationPool.registerIllustrationSet( { setFamily, setURI } ) in its init. abap2UI5 has no Component of its own and no frontend action reaches IllustrationPool (the CONTROL_GLOBAL targets carry ICON_POOL registerFont for icon fonts, but no illustration-pool counterpart), so the port cannot register the set: the 72 sap-illustration:// entries (the default sapIllus set) render, but the 46 sap-illustration://tnt/ entries resolve to no registered set and leave the illustration area EMPTY with 'The illustration set tnt is not registered' logged. The view itself is kept 1:1. Upstream request: an ILLUSTRATION_POOL global target with registerIllustrationSet( setFamily, setURI ), the exact analogue of ICON_POOL." + }, + { + "type": "NOTE", + "what": "the Illustration URI list is computed in the original from Object.keys of sap.m.IllustratedMessageType and sap.tnt.IllustratedMessageType at runtime; the port inlines the same values in the same order (72 + 46 at OpenUI5 1.152) and builds the identical sap-illustration:// and sap-illustration://tnt/ keys in model_init. A newer release may list more types than the port." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_638.json b/meta/z2ui5_cl_smpc_app_638.json new file mode 100644 index 000000000..c41c577a9 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_638.json @@ -0,0 +1,36 @@ +{ + "class": "z2ui5_cl_smpc_app_638", + "sample": "sap.m.sample.IllustratedMessageSessionTimeout", + "entity": "sap.m.IllustratedMessage", + "file": "src/02/01/z2ui5_cl_smpc_app_638.clas.abap", + "batch": "b53", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "follow_up_action( cs_event-start_timer COUNTER_TICK 1000 ) re-armed per tick" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.IllustratedMessage control (since UI5 1.98) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.98." + }, + { + "type": "IMPROVISED", + "what": "the i18n ResourceModel the controller sets on the view is dropped and every {i18n>KEY} is folded to its English literal from i18n/i18n.properties (DialogTitle, ContinueWorking, SignIn, Close, TitleExpiring, TitleExpired, DescriptionExpiringBegin, DescriptionExpiringEnd, DescriptionExpired) - abap2UI5 has no i18n model by design, so the runtime language switch is lost." + }, + { + "type": "IMPROVISED", + "what": "the original Component.js registers the 'tnt' illustration set via sap.m.IllustrationPool.registerIllustrationSet( { setFamily, setURI } ) in its init. abap2UI5 has no Component of its own and no frontend action reaches IllustrationPool (the CONTROL_GLOBAL targets carry ICON_POOL registerFont for icon fonts, but no illustration-pool counterpart), so the port cannot register the set: illustrationType tnt-SessionExpiring / tnt-SessionExpired (expression-bound 1:1 on /bIsExpiring) resolve to no registered set, so the dialog shows the title, the counting description and the buttons with an EMPTY illustration area and UI5 logs 'The illustration set tnt is not registered'. The view itself is kept 1:1. Upstream request: an ILLUSTRATION_POOL global target with registerIllustrationSet( setFamily, setURI ), the exact analogue of ICON_POOL." + }, + { + "type": "NOTE", + "what": "the controller-built Dialog (Fragment.load + addDependent) is shown with client->popup_display( ) of the same fragment. The StepInput's literal value 3 becomes a two-way binding (field expiration, seeded 3) because the controller reads it via byId('expirationInput').getValue(). The setInterval( 1000 ) counter runs in ABAP: OPEN_DIALOG does _onCounterStart and arms follow_up_action( cs_event-start_timer COUNTER_TICK 1000 ), each COUNTER_TICK does _decrementCounter and re-arms it until the count reaches 0 (then /bIsExpiring = false); onDialogClose/onSignIn (DIALOG_CLOSE, SIGN_IN) stop it and destroy the popup." + }, + { + "type": "NOTE", + "what": "the counter is a backend round-trip per second instead of the original's client-side setInterval: each tick pushes /iSecondsLeft and /bIsExpiring into the still-open popup (model push without a view rebuild), and any other round-trip cancels the pending start_timer. Verify in a running system that the description counts down 3-2-1-0, the dialog switches to the expired state with the Sign In and Close buttons, and that the busy indicator does not flicker on every tick. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_638.mjs). Each tick is armed with START_TIMER's no-busy flag (third argument, `X` for abap_true) since 2026-10-20, so a backend slower than UI5's 1 s busy delay does not flash the overlay over the countdown." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_639.json b/meta/z2ui5_cl_smpc_app_639.json new file mode 100644 index 000000000..24873b915 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_639.json @@ -0,0 +1,44 @@ +{ + "class": "z2ui5_cl_smpc_app_639", + "sample": "sap.m.sample.DynamicDateRange", + "entity": "sap.m.DynamicDateRange", + "file": "src/02/01/z2ui5_cl_smpc_app_639.clas.abap", + "batch": "b54", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "the change handler round-trips the valid flag, the operator and the two toDates dates; on_event applies the filter with follow_up_action( binding_call ) on the table's items" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.DynamicDateRange control (since UI5 1.92.0) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.92.0." + }, + { + "type": "NOTE", + "what": "onChange round-trips: the change wire carries ${$parameters>/valid}, ${$parameters>/value/operator} and the two dates of ${$source>}.toDates(value) (the control's own toDates, guarded by a ternary for a cleared value; each Date reaches ABAP as a local ISO timestamp), and the backend applies the controller's _createFilter as follow_up_action( binding_call ) on the payments-table items - FROM/FROMDATETIME as GT, TO/TODATETIME as LT, everything else as BT, an empty value clearing the filter. Rows are filtered on their ISO string, which orders like the original's Date compare. toDates returns sap.ui.core.date.UniversalDate objects, not JS Dates, so each date is sent as .getJSDate() (the second guarded, since FROM/TO yield one date): a bare UniversalDate serialized as {oDate, sCalendarType} and filtered every row away (found by the e2e interaction, 2026-10-20)." + }, + { + "type": "NOTE", + "what": "the controller's setValueState(ValueState.Error/None) is the bound valueState attribute (value_state, seeded None), set in on_event from the valid parameter." + }, + { + "type": "NOTE", + "what": "the controller's _dateFormatter function (DateFormat pattern 'MMMM dd YY, hh:mm:ss') is not an allowed formatter; the PERFOMDATETIME cell keeps the same pattern as a standard sap.ui.model.type.DateTime binding with formatOptions.source over the ISO string the ABAP model holds - same output, the formatter attribute is gone." + }, + { + "type": "NOTE", + "what": "the env named model ({env>/filterInputWidth}) is folded into the default model as FILTERINPUTWIDTH, seeded server-side from client->get( )-s_device-system with the original's !Device.system.phone ? '300px' : 'auto' rule." + }, + { + "type": "NOTE", + "what": "the mock rows are built in model_init exactly as the controller's aPayments/aOrders: getIcrementedDateFromToday(days, months, years) is reproduced by shifted_now on sy-datum / sy-uzeit (server date and time, not the browser's) with the JS month and day overflow; the fixed UI5Date.getInstance(2021, 5, ...) rows are their ISO literal (month 5 = June)." + }, + { + "type": "NOTE", + "what": "unverified in a running system: the ${$source>}.toDates(${$parameters>/value})[0] event-arg expression with its ternary guard, the Date projection to a local ISO string, and the binding_call filter that follows. **e2e-verified 2026-10-21** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_639.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_640.json b/meta/z2ui5_cl_smpc_app_640.json new file mode 100644 index 000000000..8c28b0757 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_640.json @@ -0,0 +1,52 @@ +{ + "class": "z2ui5_cl_smpc_app_640", + "sample": "sap.m.sample.DynamicDateRangeAndCalendarWeekNumbering", + "entity": "sap.m.DynamicDateRange", + "file": "src/02/01/z2ui5_cl_smpc_app_640.clas.abap", + "batch": "b54", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "the change handler round-trips the valid flag, the operator and the two toDates dates; on_event applies the filter with follow_up_action( binding_call ) on the table's items" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.DynamicDateRange control (since UI5 1.92.0) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.92.0." + }, + { + "type": "POST_171", + "what": "DynamicDateRange.calendarWeekNumbering (since UI5 1.111) with the CalendarWeekNumbering enum value MiddleEastern is the point of this sample - kept 1:1, the app needs a UI5 release >= 1.111." + }, + { + "type": "NOTE", + "what": "the original's _createFilter calls the static DynamicDateRange.toDates(oValue, 'MiddleEastern'); the port calls the source control's own toDates, which applies the control's calendarWeekNumbering - the same MiddleEastern week." + }, + { + "type": "NOTE", + "what": "onChange round-trips: the change wire carries ${$parameters>/valid}, ${$parameters>/value/operator} and the two dates of ${$source>}.toDates(value) (the control's own toDates, guarded by a ternary for a cleared value; each Date reaches ABAP as a local ISO timestamp), and the backend applies the controller's _createFilter as follow_up_action( binding_call ) on the payments-table items - FROM/FROMDATETIME as GT, TO/TODATETIME as LT, everything else as BT, an empty value clearing the filter. Rows are filtered on their ISO string, which orders like the original's Date compare. toDates returns sap.ui.core.date.UniversalDate objects, not JS Dates, so each date is sent as .getJSDate() (the second guarded, since FROM/TO yield one date): a bare UniversalDate serialized as {oDate, sCalendarType} and filtered every row away (found by the e2e interaction, 2026-10-20)." + }, + { + "type": "NOTE", + "what": "the controller's setValueState(ValueState.Error/None) is the bound valueState attribute (value_state, seeded None), set in on_event from the valid parameter." + }, + { + "type": "NOTE", + "what": "the controller's _dateFormatter function (DateFormat pattern 'MMMM dd YY, hh:mm:ss') is not an allowed formatter; the PERFOMDATETIME cell keeps the same pattern as a standard sap.ui.model.type.DateTime binding with formatOptions.source over the ISO string the ABAP model holds - same output, the formatter attribute is gone." + }, + { + "type": "NOTE", + "what": "the env named model ({env>/filterInputWidth}) is folded into the default model as FILTERINPUTWIDTH, seeded server-side from client->get( )-s_device-system with the original's !Device.system.phone ? '300px' : 'auto' rule." + }, + { + "type": "NOTE", + "what": "the mock rows are built in model_init exactly as the controller's aPayments/aOrders: getIcrementedDateFromToday(days, months, years) is reproduced by shifted_now on sy-datum / sy-uzeit (server date and time, not the browser's) with the JS month and day overflow; the fixed UI5Date.getInstance(2021, 5, ...) rows are their ISO literal (month 5 = June)." + }, + { + "type": "NOTE", + "what": "unverified in a running system: the ${$source>}.toDates(${$parameters>/value})[0] event-arg expression with its ternary guard, the Date projection to a local ISO string, and the binding_call filter that follows. **e2e-verified 2026-10-21** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_640.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_641.json b/meta/z2ui5_cl_smpc_app_641.json new file mode 100644 index 000000000..58f546a7e --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_641.json @@ -0,0 +1,44 @@ +{ + "class": "z2ui5_cl_smpc_app_641", + "sample": "sap.m.sample.DynamicDateRangeHidden", + "entity": "sap.m.DynamicDateRange", + "file": "src/02/01/z2ui5_cl_smpc_app_641.clas.abap", + "batch": "b54", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "the three anchors open the hidden DynamicDateRange roundtrip-free via follow_up_action( control_by_id, openBy, $event.oSource.sId ) (the app 016 DatePickerHidden idiom); the change handler round-trips operator, value count and the first two values, and the backend composes the toast" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.DynamicDateRange control (since UI5 1.92.0) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.92.0." + }, + { + "type": "POST_171", + "what": "DynamicDateRange.hideInput and DynamicDateRange.openBy (both since UI5 1.105) are the sample's central mechanism - kept 1:1, the app needs a UI5 release >= 1.105." + }, + { + "type": "POST_171", + "what": "Button.ariaHasPopup (since UI5 1.84) is kept 1:1 on both Button controls - the app needs a UI5 release >= 1.84 to render it." + }, + { + "type": "POST_171", + "what": "Link.ariaHasPopup (since UI5 1.86) is kept 1:1 - the app needs a UI5 release >= 1.86 to render it." + }, + { + "type": "NOTE", + "what": "changeDateHandler's MessageToast is composed in ABAP (on_event CHANGE) instead of in the controller: the wire carries ${$parameters>/value/operator}, the values count and values[0]/values[1] (no standard option has more than two values), each value as ` + ''` so a Date arrives as its toString and a boolean 'included' flag as true/false - exactly what the original's string concatenation prints." + }, + { + "type": "NOTE", + "what": "unverified in a running system: the openBy anchor opening the hidden DynamicDateRange popover (app 016's hidden DatePicker loops in Popover.onfocusin HEADLESS only), and the `${$parameters>/value/values/0} + ''` string-concatenation event args reaching the toast. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_641.mjs)." + } + ], + "e2e_smoke": { + "theme": true, + "reason": "unthemed, the hidden DynamicDateRange popover opened by openBy loops in Popover.onfocusin (focus restore bounces off the hidden input) until the stack overflows - the original openBy(getDomRef()) does the same headless; themed it opens cleanly and the interaction drives the pick" + } +} diff --git a/meta/z2ui5_cl_smpc_app_642.json b/meta/z2ui5_cl_smpc_app_642.json new file mode 100644 index 000000000..1e00652bb --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_642.json @@ -0,0 +1,52 @@ +{ + "class": "z2ui5_cl_smpc_app_642", + "sample": "sap.m.sample.DynamicDateRangeWithCustomOptions", + "entity": "sap.m.DynamicDateRange", + "file": "src/02/01/z2ui5_cl_smpc_app_642.clas.abap", + "batch": "b54", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "the change handler round-trips the valid flag, the operator and the two toDates dates; on_event applies the filter with follow_up_action( binding_call ) on the table's items" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.DynamicDateRange control (since UI5 1.92.0) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.92.0." + }, + { + "type": "IMPROVISED", + "what": "the controller's addGroup('Custom', 'Custom Options') and the four custom options it adds to the customOptions aggregation (CustomPreviousXWeekend 'X To Last Weekend', CustomPreviousXWorkWeek 'X To Last Work Week', CustomLastChristmas 'Last Christmas', CustomBusinessDay 'Business Day') are not ported: each is an app-authored DynamicDateOption subclass whose getValueHelpUITypes/format/parse/toDates are JS code, which a thin frontend cannot ship (no app JS modules; a plain DynamicDateOption in the view has no toDates). The DynamicDateRange shows only its standard options." + }, + { + "type": "NOTE", + "what": "kept 1:1 with the original: _createFilter's FROM/FROMDATETIME and TO/TODATETIME branches filter the path PerfomDateTime (copied from the sibling sample), which no order row carries, so those operators hide every row - only the BT branch filters orderTime. The port issues the same paths (PERFOMDATETIME / ORDERTIME)." + }, + { + "type": "NOTE", + "what": "onChange round-trips: the change wire carries ${$parameters>/valid}, ${$parameters>/value/operator} and the two dates of ${$source>}.toDates(value) (the control's own toDates, guarded by a ternary for a cleared value; each Date reaches ABAP as a local ISO timestamp), and the backend applies the controller's _createFilter as follow_up_action( binding_call ) on the orders-table items - FROM/FROMDATETIME as GT, TO/TODATETIME as LT, everything else as BT, an empty value clearing the filter. Rows are filtered on their ISO string, which orders like the original's Date compare. toDates returns sap.ui.core.date.UniversalDate objects, not JS Dates, so each date is sent as .getJSDate() (the second guarded, since FROM/TO yield one date): a bare UniversalDate serialized as {oDate, sCalendarType} and filtered every row away (found by the e2e interaction, 2026-10-20)." + }, + { + "type": "NOTE", + "what": "the controller's setValueState(ValueState.Error/None) is the bound valueState attribute (value_state, seeded None), set in on_event from the valid parameter." + }, + { + "type": "NOTE", + "what": "the controller's _dateFormatter function (DateFormat pattern 'MMMM dd YY, hh:mm:ss') is not an allowed formatter; the ORDERTIME cell keeps the same pattern as a standard sap.ui.model.type.DateTime binding with formatOptions.source over the ISO string the ABAP model holds - same output, the formatter attribute is gone." + }, + { + "type": "NOTE", + "what": "the env named model ({env>/filterInputWidth}) is folded into the default model as FILTERINPUTWIDTH, seeded server-side from client->get( )-s_device-system with the original's !Device.system.phone ? '300px' : 'auto' rule." + }, + { + "type": "NOTE", + "what": "the mock rows are built in model_init exactly as the controller's aPayments/aOrders: getIcrementedDateFromToday(days, months, years) is reproduced by shifted_now on sy-datum / sy-uzeit (server date and time, not the browser's) with the JS month and day overflow; the fixed UI5Date.getInstance(2021, 5, ...) rows are their ISO literal (month 5 = June). The orders' extra getChristmasDay(currentYear - 1) row is 25 December of the previous year at the current time; the original's setUTCDate (instead of setDate) only differs around midnight UTC. totalPrice is computed in model_init like the original's onInit forEach." + }, + { + "type": "NOTE", + "what": "unverified in a running system: the ${$source>}.toDates(${$parameters>/value})[0] event-arg expression with its ternary guard, the Date projection to a local ISO string, and the binding_call filter that follows. **e2e-verified 2026-10-21** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_642.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_643.json b/meta/z2ui5_cl_smpc_app_643.json new file mode 100644 index 000000000..a72a78493 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_643.json @@ -0,0 +1,31 @@ +{ + "class": "z2ui5_cl_smpc_app_643", + "sample": "sap.m.sample.ExpandableText", + "entity": "sap.m.ExpandableText", + "file": "src/02/01/z2ui5_cl_smpc_app_643.clas.abap", + "batch": "b54", + "audit": { + "frontend_action": false, + "event_t_arg": false + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.ExpandableText control (since UI5 1.87) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.87." + }, + { + "type": "POST_171", + "what": "ExpandableText.overflowMode (since UI5 1.87, enum sap.m.ExpandableTextOverflowMode InPlace/Popover) is bound per row as in the original." + }, + { + "type": "POST_171", + "what": "Table.autoPopinMode (since UI5 1.76) is kept 1:1 - the app needs a UI5 release >= 1.87 anyway for the control." + }, + { + "type": "NOTE", + "what": "the controller's onInit products are seeded in model_init verbatim; the shared Lorem ipsum tail of the four attribute1 texts is held once in a local and appended, the resulting strings are byte-identical to the original's." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_644.json b/meta/z2ui5_cl_smpc_app_644.json new file mode 100644 index 000000000..3c6130306 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_644.json @@ -0,0 +1,36 @@ +{ + "class": "z2ui5_cl_smpc_app_644", + "sample": "sap.m.sample.p13n.Container", + "entity": "sap.m.p13n.Container", + "file": "src/02/01/z2ui5_cl_smpc_app_644.clas.abap", + "batch": "b55", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "follow_up_action( control_by_id ): d1 open/close and p1 openBy openBtn; the layout RadioButtonGroup passes its selectedIndex" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.p13n.Container control (since UI5 1.96) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.96." + }, + { + "type": "POST_171", + "what": "the sap.m.p13n.AbstractContainerItem control (since UI5 1.96) and its key and text properties are newer than 1.71 - kept 1:1 as the container's views." + }, + { + "type": "NOTE", + "what": "addCustomView adds a new AbstractContainerItem (text View , key view, n = getViews( ).length before the add, which counts the Container's own $default view - the navigation list it adds in list layout - next to the three static ones, so the first added view is View 4/view4 as in the original; the port counts its rows plus that one) to the container of the pressed popup. The port keeps one ABAP row per view for each of the two containers and emits the container's views from it in a loop - the three original views with their VBox/Text content, the added ones without content, as the original adds them - so the add is a backend row plus a view rebuild that re-opens the popup the button sat in (d1 via open, p1 via openBy openBtn). The rebuild resets the container to its defaultView view2 where the original stays on the currently shown view." + }, + { + "type": "NOTE", + "what": "onContainerOpen reads dialogChose.getSelectedButton( ).getText( ) == 'Dialog'; the port binds that RadioButtonGroup's selectedIndex two-way and opens d1 for index 0 (Dialog) and p1 for index 1 (Popover), via control_by_id open / openBy with openBtn as anchor after the round-trip. selectLayout stays a select wire carrying selectedIndex and sets listLayout = (index === 0) on the default model; the layout group's selectedIndex is bound as well so a rebuilt view keeps the chosen radio button in line with listLayout. closeDialog (getParent( ).close( )) is a view-wired control_by_id d1 close with no round-trip." + }, + { + "type": "NOTE", + "what": "re-opening d1/p1 by a follow-up action directly after the view rebuild that an Add custom view press triggers is unverified in a running system. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_644.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_645.json b/meta/z2ui5_cl_smpc_app_645.json new file mode 100644 index 000000000..c2f459de2 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_645.json @@ -0,0 +1,48 @@ +{ + "class": "z2ui5_cl_smpc_app_645", + "sample": "sap.m.sample.p13n.Engine", + "entity": "sap.m.p13n.Engine", + "file": "src/02/01/z2ui5_cl_smpc_app_645.clas.abap", + "batch": "b55", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "follow_up_action( control_by_id ): setP13nData on the Selection/Sort/GroupPanel of the p13n.Popup fragment shown with popup_display (JSON arrays built in ABAP, view = POPUP); the popup's close passes the reason and the three panels' getP13nData( true ); the column menu, QuickSort/QuickGroup, ColumnResizer and drop wires pass p13nKey custom data and item getters" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.p13n.Engine (since UI5 1.104) is the subject of this sample. It is a JavaScript singleton, not a control - the port expresses what it does with the sap.m.p13n.Popup control (since 1.97, its close event and panels aggregation), the SelectionPanel control (since 1.96, its showHeader and enableCount properties) and the SortPanel control (since 1.96); the app needs a UI5 release >= 1.110." + }, + { + "type": "POST_171", + "what": "kept 1:1 from the original view and newer than 1.71: sap.m.Table autoPopinMode (1.76) and its noData aggregation holding an IllustratedMessage (aggregation 1.101, control 1.98), sap.m.Column headerMenu (1.98), the sap.m.plugins ColumnResizer control with its columnResize event (1.91), and the sap.m.table.columnmenu controls (all 1.110): Menu with beforeOpen, showTableSettingsButton and tableSettingsPressed, QuickSort with change and its items aggregation, QuickSortItem with key, label and sortOrder, QuickGroup with change and its items aggregation, QuickGroupItem with key, label and grouped." + }, + { + "type": "IMPROVISED", + "what": "Engine.getInstance( ).register( ) with the Columns, Sorter, Groups, ColumnWidth and Filter controllers, Engine.show( ), retrieveState( )/applyState( ) and the stateChange event are controller JavaScript no abap2UI5 wire can run. The port does the Engine's work in the backend: it keeps the state (column order and visibility, column widths, sorters, groups) in ABAP, and the settings button and the column menu's table settings button open a p13n:Popup with a p13n:SelectionPanel (showHeader/enableCount as the SelectionController creates it), a p13n:SortPanel and a p13n:GroupPanel (queryLimit 1, as the GroupController sets it for a sap.m.Table) - controls the port builds as a popup_display fragment, which the original view does not have (Popup, SelectionPanel, SortPanel, GroupPanel) - opened fresh on every press and destroyed (popup_destroy) in its close handler, as Engine.show( ) creates the popup per call. Right after opening it, the backend hands each panel the controllers' adaptation data via setP13nData (active entries first in state order, the others sorted by label); on close with reason Ok the panels' getP13nData( true ) come back and handleStateChange is reproduced in ABAP: updateColumns (hide all, show and move the state's columns to the front, widths from the state, sort indicators), createGroups/createSorters (one group sorter per group, then the sorters, a sorter on a grouped path only setting its direction) and bindItems - the items binding is composed by the backend as a binding-info string with that sorter list, and the view emits the Column controls and the cell template's Text cells in state order from a loop, so every state change is a view rebuild. The Engine's popup carries the title View Settings and contentHeight 50rem/contentWidth 45rem, which the declared Popup does not." + }, + { + "type": "NOTE", + "what": "the p13n:Popup is built as a popup_display fragment of its own instead of a dependent of the table because of a UI5 leak: sap.m.p13n.Popup.addPanel moves its panels into an internal Container that only the Dialog created by open( ) takes as content, and Popup.exit destroys only that Dialog (sap/m/p13n/Popup.js, UI5 1.152) - so a Popup that is declared in a view and never opened leaks its Container and panels when the view is destroyed. abap2UI5 alternates the main view's id (mainView/mainView2) on every view_display, so two rebuilds later the leaked panels' ids collide with the new view's own and the rebuild dies on a duplicate id. A Popup that exists only while it is open (as Engine.show( ) creates it) has nothing to leak; any port that declares a p13n.Popup in a view it re-creates without opening the popup hits this." + }, + { + "type": "IMPROVISED", + "what": "the Filter controller is dropped: its panel, sap.m.p13n.FilterPanel, renders each condition through itemFactory, a function-typed property (the FilterController passes a factory creating an Input bound to $p13n>conditions/0/values/0) that no abap2UI5 wire can supply - so the popup has no Filter tab, no filter can be set, createFilters has nothing to build, and the filterInfo info toolbar (kept with visible false, filterInfoText and its Remove All Filters Button) can never appear; its two press handlers (onFilterInfoPress on the OverflowToolbar, onClearFilterPress on the Button) are therefore not wired. Capability gap - a curated frontend module exporting a default itemFactory would close it." + }, + { + "type": "NOTE", + "what": "the column menu is driven from the backend: beforeOpen transports the opened column's p13nKey custom data and the backend sets the QuickSortItem/QuickGroupItem key, label, sortOrder and grouped through bound model fields (the original sets them on the items directly); QuickSort change and QuickGroup change carry ${$parameters>/item}.getKey( ) plus getSortOrder( )/getGrouped( ) and do what onSort/onGroup do (clear all sorters/groups, push the column's), ColumnResizer columnResize stores the column width in the ColumnWidth state (the resizer has already sized the column), and the column drop does onColumnMove's position arithmetic on the backend's column order and moves the column in the visible-column state. The cell template's Text cells are emitted per column from the column state's model path, so their bindings {FIRSTNAME}, {LASTNAME}, {CITY} and {SIZE} (the original's {firstName}, {lastName}, {city}, {size}) are composed at run time and not visible to a static diff." + }, + { + "type": "IMPROVISED", + "what": "the sap.ui.fl VariantManagement (vm:VariantManagement p13nVm for persoTable) is dropped: variant persistence through sap.ui.fl needs a flex-enabled component with an LRep connector and the $FlexVariants model, none of which an abap2UI5 app provides, and the sap.ui.fl library is not part of the corpus' render harness. Without the Engine the control would have nothing to save." + }, + { + "type": "NOTE", + "what": "the p13n.Popup close wire ($event.oSource.getPanels( )[n].getP13nData( true ) - read back as JSON arrays of the panels' items), the setP13nData JSON arguments, the custom-data args (.data('p13nKey') on the column, dragged and dropped control) and the QuickSortItem/QuickGroupItem update arriving after beforeOpen's round-trip while the menu is already open are source-derived, not run in a live system. **e2e-verified 2026-10-21** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_645.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_646.json b/meta/z2ui5_cl_smpc_app_646.json new file mode 100644 index 000000000..f9c80392d --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_646.json @@ -0,0 +1,40 @@ +{ + "class": "z2ui5_cl_smpc_app_646", + "sample": "sap.m.sample.p13n.EngineCustomFilters", + "entity": "sap.m.p13n.Engine", + "file": "src/02/01/z2ui5_cl_smpc_app_646.clas.abap", + "batch": "b55", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "follow_up_action( control_by_id ): open/close of the filter Dialog; each MultiInput's tokenUpdate passes addedTokens and removedTokens" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.p13n.Engine (since UI5 1.104) is the subject of this sample - a JavaScript singleton, not a control, so it cannot be kept (see the IMPROVISED entries); the app needs a UI5 release >= 1.110 for the controls below." + }, + { + "type": "POST_171", + "what": "kept 1:1 from the original view and newer than 1.71: sap.m.Table autoPopinMode (1.76) and its noData aggregation holding an IllustratedMessage (aggregation 1.101, control 1.98), sap.m.Column headerMenu (1.98), the sap.m.plugins ColumnResizer control (1.91), and the sap.m.table.columnmenu controls (all 1.110): Menu with its items aggregation, QuickSort and QuickGroup with their items aggregation, QuickSortItem, QuickGroupItem, and ActionItem with icon and label. From the controller's itemFactory: sap.m.MultiInput showClearIcon (1.94)." + }, + { + "type": "IMPROVISED", + "what": "the sample's point - a FilterController whose itemFactory callback builds a MultiInput per filter field inside the Engine's sap.m.p13n.FilterPanel (since 1.121) - is not expressible: itemFactory is a function-typed property (a controller closure per row) and no abap2UI5 wire can supply a function, and the FilterPanel calls it for every condition row it renders. The port keeps what the factory produces and builds it declaratively: the settings button opens a Dialog (title Custom Filter Settings, contentHeight 50rem, contentWidth 45rem - the settings the controller passes to Engine.show( )) declared in the table's dependents, holding one Label and one MultiInput per filter field (showValueHelp false, showClearIcon true, suggestionItems over /items showing that field, the existing conditions as Token controls bound to a backend table per field), plus an OK Button and a Cancel Button - controls the original view does not have (Dialog, VBox, Label, MultiInput, Token, core:Item, two more Button controls). The FilterPanel's own row UI (a field ComboBox adding one row at a time) is replaced by the four fields shown at once. tokenUpdate transports addedTokens/removedTokens and the backend adds/removes the field's EQ condition like the factory's handler; OK applies them - createFilters' flat array of EQ filters (UI5 ORs the filters on one path and ANDs the paths) is composed by the backend into the items binding-info string and the view rebuilt, which is what getBinding( 'items' ).filter( ) did; Cancel closes the dialog and the next open re-seeds the tokens from the applied conditions, as the Engine discards a cancelled panel." + }, + { + "type": "IMPROVISED", + "what": "the sap.ui.fl VariantManagement (vm:VariantManagement p13nVm for persoTable) is dropped: variant persistence through sap.ui.fl needs a flex-enabled component with an LRep connector and the $FlexVariants model, none of which an abap2UI5 app provides, and the sap.ui.fl library is not part of the corpus' render harness. Without the Engine the control would have nothing to save." + }, + { + "type": "NOTE", + "what": "the column menu (QuickSort/QuickGroup with empty items, three ActionItems), the ColumnResizer and the DragDropInfo on the columns carry no handlers in the original view and the controller registers only the Filter controller - they are kept 1:1 as inert configuration, exactly as the sample ships them." + }, + { + "type": "NOTE", + "what": "the tokenUpdate args (${$parameters>/addedTokens} and removedTokens, read back as JSON arrays of the tokens' properties) and the bound tokens aggregation receiving a suggestion-created Token are unverified in a running system. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_646.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_647.json b/meta/z2ui5_cl_smpc_app_647.json new file mode 100644 index 000000000..7f131c6c0 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_647.json @@ -0,0 +1,32 @@ +{ + "class": "z2ui5_cl_smpc_app_647", + "sample": "sap.m.sample.p13n.EngineGridList", + "entity": "sap.m.p13n.Engine", + "file": "src/02/01/z2ui5_cl_smpc_app_647.clas.abap", + "batch": "b55", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "follow_up_action( control_by_id ): setP13nData on the SelectionPanel (JSON array built in ABAP) and open on the p13n.Popup; the popup's close event passes the reason and getP13nData( true )" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.p13n.Engine (since UI5 1.104) is the subject of this sample. It is a JavaScript singleton, not a control - the port expresses what it does with the sap.m.p13n.Popup control (since 1.97, its close event and panels aggregation) and the sap.m.p13n.SelectionPanel control (since 1.96, its showHeader and enableCount properties), all newer than 1.71; the app needs a UI5 release >= 1.97." + }, + { + "type": "IMPROVISED", + "what": "Engine.getInstance( ).register( ) with an Items SelectionController and Engine.show( ) are controller JavaScript no abap2UI5 wire can run. The port does the Engine's work in the backend: it keeps the Items state (visible person keys, in order) in ABAP, and the settings button opens a p13n:Popup with one p13n:SelectionPanel (showHeader/enableCount as the SelectionController creates it) that the port declares in the GridList's dependents - both are therefore controls the original view does not have (Popup, SelectionPanel). Before opening, the backend hands the panel the controller's adaptation data via setP13nData (visible persons first in state order, then the hidden ones sorted by label, labels from the MetadataHelper); on close with reason Ok, the panel's getP13nData( true ) comes back and handleStateChange is reproduced in ABAP - the bound /items become the visible persons in the chosen order. The Engine's popup carries the panel's title (Fields) and the contentHeight 35rem/contentWidth 32rem settings, which the declared Popup does not." + }, + { + "type": "IMPROVISED", + "what": "the sap.ui.fl VariantManagement (vm:VariantManagement p13nVm for persoList) and the GridList's sap.ui.fl:flexibility attribute are dropped: variant persistence through sap.ui.fl needs a flex-enabled component with an LRep connector and the $FlexVariants model, none of which an abap2UI5 app provides, and the sap.ui.fl library is not part of the corpus' render harness. Without the Engine the control would have nothing to save." + }, + { + "type": "NOTE", + "what": "the p13n.Popup close wire ($event.oSource.getPanels( )[0].getP13nData( true ) - read back as a JSON array of the panel's items) and the setP13nData JSON argument are source-derived, not run in a live system. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_647.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_648.json b/meta/z2ui5_cl_smpc_app_648.json new file mode 100644 index 000000000..c51a67db6 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_648.json @@ -0,0 +1,44 @@ +{ + "class": "z2ui5_cl_smpc_app_648", + "sample": "sap.m.sample.p13n.EngineGridTable", + "entity": "sap.m.p13n.Engine", + "file": "src/02/01/z2ui5_cl_smpc_app_648.clas.abap", + "batch": "b55", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "follow_up_action( control_by_id ): setP13nData on the Selection/SortPanel of the p13n.Popup fragment shown with popup_display (JSON arrays built in ABAP, view = POPUP); the popup's close passes the reason and both panels' getP13nData( true ); the table's sort, columnResize and columnMove wires pass the column's p13nKey custom data plus sortOrder/width/newPos" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.p13n.Engine (since UI5 1.104) is the subject of this sample. It is a JavaScript singleton, not a control - the port expresses what it does with the sap.m.p13n.Popup control (since 1.97, its close event and panels aggregation), the SelectionPanel control (since 1.96, its showHeader and enableCount properties) and the SortPanel control (since 1.96); the app needs a UI5 release >= 1.119." + }, + { + "type": "POST_171", + "what": "kept 1:1 from the original view and newer than 1.71: sap.ui.table.Table rowMode (1.119, the string form Auto), sap.ui.table.Column headerMenu (1.110), the sap.m.table.columnmenu Menu control with showTableSettingsButton and tableSettingsPressed (1.110), and the IllustratedMessage control (1.98) with enableVerticalResponsiveness (1.104) in the table's noData." + }, + { + "type": "IMPROVISED", + "what": "Engine.getInstance( ).register( ) with the Columns, Sorter, Groups and ColumnWidth controllers, Engine.show( ), retrieveState( )/applyState( ) and the stateChange event are controller JavaScript no abap2UI5 wire can run. The port does the Engine's work in the backend: it keeps the state (column order and visibility, column widths, sorters) in ABAP, and the settings button and the column menu's table settings button open a p13n:Popup with a p13n:SelectionPanel (showHeader/enableCount as the SelectionController creates it) and a p13n:SortPanel - Engine.show( ['Columns', 'Sorter'] ) - controls the port builds as a popup_display fragment, which the original view does not have (Popup, SelectionPanel, SortPanel) - opened fresh on every press and destroyed (popup_destroy) in its close handler, as Engine.show( ) creates the popup per call. Right after opening it, the backend hands both panels the controllers' adaptation data via setP13nData (active entries first in state order, the others sorted by label); on close with reason Ok the panels' getP13nData( true ) come back and handleStateChange is reproduced in ABAP: every column hidden, the state's columns shown and moved to the front in state order, widths from the state or the _mIntialWidth 11rem, each sorted column's sortOrder set, and the rows binding sorted - composed by the backend as a binding-info string with that sorter list. The view emits the Column controls (with their Label and template Text, whose binding {FIRSTNAME}, {LASTNAME}, {CITY} or {SIZE} - the original's {firstName}, {lastName}, {city}, {size} - comes from the column state's path) in state order from a loop, so every state change is a view rebuild. The registered Groups controller has no panel in the original's show( ) call either and is not reproduced. The Engine's popup carries the title View Settings and contentHeight 35rem/contentWidth 32rem, which the declared Popup does not." + }, + { + "type": "NOTE", + "what": "the p13n:Popup is built as a popup_display fragment of its own instead of a dependent of the table because of a UI5 leak: sap.m.p13n.Popup.addPanel moves its panels into an internal Container that only the Dialog created by open( ) takes as content, and Popup.exit destroys only that Dialog (sap/m/p13n/Popup.js, UI5 1.152) - so a Popup that is declared in a view and never opened leaks its Container and panels when the view is destroyed. abap2UI5 alternates the main view's id (mainView/mainView2) on every view_display, so two rebuilds later the leaked panels' ids collide with the new view's own and the rebuild dies on a duplicate id. A Popup that exists only while it is open (as Engine.show( ) creates it) has nothing to leak; any port that declares a p13n.Popup in a view it re-creates without opening the popup hits this. The panel ids (gridColumnsPanel/gridSortPanel, invented by the port - the Engine creates its panels without one) are distinct from the other p13n fragment ports' (app 645's columnsPanel/sortPanel/groupPanel): the render gate loads every popup fragment without an id prefix into a shared page pool, where the same leak keeps a never-opened fragment's panels registered, so equal ids in two ports collided there." + }, + { + "type": "NOTE", + "what": "the table's own events drive the same state as in the original: sort (onSort) transports the column's p13nKey custom data and sortOrder and replaces the sorters with that column's, columnResize stores the width in the ColumnWidth state (the table has already sized the column), and columnMove is vetoed with check_prevent_default exactly like oEvt.preventDefault( ) and then moves the column to newPos in the visible-column state. The original also calls Column.setSorted( true ), deprecated since 1.120; the port sets only sortOrder, which is what the sort indicator shows." + }, + { + "type": "IMPROVISED", + "what": "the sap.ui.fl VariantManagement (vm:VariantManagement p13nVm for persoTable) and the table's sap.ui.fl:flexibility attribute are dropped: variant persistence through sap.ui.fl needs a flex-enabled component with an LRep connector and the $FlexVariants model, none of which an abap2UI5 app provides, and the sap.ui.fl library is not part of the corpus' render harness. Without the Engine the control would have nothing to save." + }, + { + "type": "NOTE", + "what": "the p13n.Popup close wire ($event.oSource.getPanels( )[n].getP13nData( true ) - read back as JSON arrays of the panels' items), the setP13nData JSON arguments and the .data('p13nKey') args on the sort/columnResize/columnMove column parameter are source-derived, not run in a live system. **e2e-verified 2026-10-21** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_648.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_649.json b/meta/z2ui5_cl_smpc_app_649.json new file mode 100644 index 000000000..375e44426 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_649.json @@ -0,0 +1,44 @@ +{ + "class": "z2ui5_cl_smpc_app_649", + "sample": "sap.m.sample.p13n.EngineMultipleController", + "entity": "sap.m.p13n.Engine", + "file": "src/02/01/z2ui5_cl_smpc_app_649.clas.abap", + "batch": "b55", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "follow_up_action( control_by_id ): setP13nData on the SelectionPanel of whichever of the two p13n.Popup fragments popup_display shows (JSON arrays built in ABAP, view = POPUP); the popups' close events pass the reason and getP13nData( true ); the column drop passes the dragged/dropped p13nKey and the drop position" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.p13n.Engine (since UI5 1.104) is the subject of this sample. It is a JavaScript singleton, not a control - the port expresses what it does with the sap.m.p13n.Popup control (since 1.97, its close event and panels aggregation) and the sap.m.p13n.SelectionPanel control (since 1.96, its showHeader, enableCount and enableReorder properties); the app needs a UI5 release >= 1.110." + }, + { + "type": "POST_171", + "what": "kept 1:1 from the original view and newer than 1.71: sap.m.Table autoPopinMode (1.76) and its noData aggregation holding an IllustratedMessage (aggregation 1.101, control 1.98), sap.m.Column headerMenu (1.98), the sap.m.table.columnmenu Menu control with its items aggregation and the ActionItem control with icon, label and press (all 1.110)." + }, + { + "type": "IMPROVISED", + "what": "Engine.getInstance( ).register( ) with a Columns and a Rows SelectionController and Engine.show( ) are controller JavaScript no abap2UI5 wire can run. The port does the Engine's work in the backend: it keeps the order and visibility of the table's columns and of its five items in ABAP, and each settings button (and the column menu's Columns ActionItem) opens a p13n:Popup with one p13n:SelectionPanel (showHeader/enableCount as the SelectionController creates it, enableReorder false for Rows) - two Popup and two SelectionPanel controls the port builds as two popup_display fragments, which the original view does not have - each opened fresh on its press and destroyed (popup_destroy) in its close handler, as Engine.show( ) creates the popup per call. Right after opening one, the backend hands each panel the controller's adaptation data via setP13nData (visible entries first in state order, then the hidden ones sorted by label; labels from the two MetadataHelpers); on close with reason Ok the panel's getP13nData( true ) comes back and handleStateChange is reproduced in ABAP: every column/item hidden, the state's entries shown and moved to the front in state order. The view emits the Column and ColumnListItem controls (and every item's Text cells, which follow their column) from those two tables in a loop, so a state change is a view rebuild. The Engine's popups carry the panel's title (Fields) and contentHeight 35rem/contentWidth 32rem, which the declared Popup controls do not." + }, + { + "type": "NOTE", + "what": "the p13n:Popup is built as a popup_display fragment of its own instead of a dependent of the table because of a UI5 leak: sap.m.p13n.Popup.addPanel moves its panels into an internal Container that only the Dialog created by open( ) takes as content, and Popup.exit destroys only that Dialog (sap/m/p13n/Popup.js, UI5 1.152) - so a Popup that is declared in a view and never opened leaks its Container and panels when the view is destroyed. abap2UI5 alternates the main view's id (mainView/mainView2) on every view_display, so two rebuilds later the leaked panels' ids collide with the new view's own and the rebuild dies on a duplicate id. A Popup that exists only while it is open (as Engine.show( ) creates it) has nothing to leak; any port that declares a p13n.Popup in a view it re-creates without opening the popup hits this. The panel ids (tableColumnsPanel/rowsPanel, invented by the port - the Engine creates its panels without one) are distinct from the other p13n fragment ports' (app 645's columnsPanel/sortPanel/groupPanel): the render gate loads every popup fragment without an id prefix into a shared page pool, where the same leak keeps a never-opened fragment's panels registered, so equal ids in two ports collided there." + }, + { + "type": "NOTE", + "what": "onColumnMove computes the drop position from the dragged/dropped column indices and applyState( { Columns: [ { key, position } ] } ) moves the column there. The port transports both columns' p13nKey custom data and the dropPosition, does the same arithmetic on the backend's column order and moves the key in the visible-column state before re-emitting the view. The original handler searches the retrieved state with oColumn.data('p13nKey') on plain state objects, which throws as soon as the state holds a column, so in the demo kit the drop does not move anything; the port implements the move the handler evidently intends (the identical handler of sap.m.sample.p13n.Engine, which uses .key)." + }, + { + "type": "IMPROVISED", + "what": "the sap.ui.fl VariantManagement (vm:VariantManagement p13nVm for persoTable) is dropped: variant persistence through sap.ui.fl needs a flex-enabled component with an LRep connector and the $FlexVariants model, none of which an abap2UI5 app provides, and the sap.ui.fl library is not part of the corpus' render harness. Without the Engine the control would have nothing to save." + }, + { + "type": "NOTE", + "what": "the p13n.Popup close wires ($event.oSource.getPanels( )[0].getP13nData( true ) - read back as a JSON array of the panel's items), the setP13nData JSON argument and the drop wire's .data('p13nKey') args are source-derived, not run in a live system. **e2e-verified 2026-10-21** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_649.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_650.json b/meta/z2ui5_cl_smpc_app_650.json new file mode 100644 index 000000000..bcd3704ba --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_650.json @@ -0,0 +1,40 @@ +{ + "class": "z2ui5_cl_smpc_app_650", + "sample": "sap.m.sample.p13n.Popup", + "entity": "sap.m.p13n.Popup", + "file": "src/02/01/z2ui5_cl_smpc_app_650.clas.abap", + "batch": "b55", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "follow_up_action( control_by_id setP13nData ) seeds the three panels and control_by_id open opens the popup; the close toast is a view-wired control_global MESSAGE_TOAST; the panels' getP13nData( ) travels as an array event arg the frontend sends as JSON" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.p13n.Popup control (since UI5 1.97) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.97." + }, + { + "type": "POST_171", + "what": "the SelectionPanel and SortPanel controls of sap.m.p13n (since UI5 1.96) and their members title, enableCount, showHeader and change are newer than 1.71 - kept 1:1 as the popup's panels." + }, + { + "type": "IMPROVISED", + "what": "Popup.reset is a function-typed property: the original's controller callback (reset -> _setInitialData + parseP13nState) is resolved by the XML template processor against the controller, and no abap2UI5 wire can supply a function, so the attribute is dropped and the popup shows no Reset button (warningText is kept 1:1 but has no visible effect without the callback). Capability gap - a curated frontend module exporting a reset callback that fires a named backend event would close it." + }, + { + "type": "NOTE", + "what": "the controller's _setInitialData (setP13nData on the three panels with _initialData, verbatim) is issued as three follow_up_action( control_by_id setP13nData ) calls with the JSON array as argument. The original seeds once, on the first open (_bIsOpen guard); the port seeds after every render of the view, which is observably the same - the panels hold the initial data until the user first edits them and keep the edits across later opens - and also re-seeds the fresh panels a rebuilt view creates. onContainerOpen's popup.open( ) is a control_by_id open call after the round-trip; the popup is in Dialog mode, where open( ) ignores its source argument. The JSON argument reaches the panels through the framework's JSON layer, which orders each object's keys alphabetically, so the port's panels hold the same items and values with their keys in another order - invisible in the panels, and the editor text is printed by the backend in _initialData's order (see the parseP13nState note)." + }, + { + "type": "NOTE", + "what": "parseP13nState writes JSON.stringify( { columns, sort, group }, null, ' ' ) into the CodeEditor with setValue. The panels are not reachable from a panel's change event, so each change wire sends its own panel's getP13nData( ) as an event argument and the backend keeps the last array per panel; an added open event on the Popup captures all three panels via getPanels( ) so the panels not yet changed are known. An event-handler expression knows only $controller and $event as globals - JSON.stringify( ) itself is refused there (Unsupported global identifier 'JSON') and no round-trip is sent - so the array travels as it is: the frontend serializes an array argument as JSON and the backend receives it compactly, with each object's keys in alphabetical order. The backend prints it the way JSON.stringify( ..., null, ' ' ) does: the three arrays nested in one object, two-space indent, one key per line, each item's keys in the order _initialData gives them (visible/name/label, sorted/name/label/descending, grouped/name/label) - the panels only change the values of those keys, never add one, so the text is the original's output byte for byte. The change toast (P13n panel change reason:) is raised by the backend in the same round-trip; the close toast (Dialog close reason: ) is client-composed with no round-trip." + }, + { + "type": "NOTE", + "what": "the getP13nData( ) array args of the change/open events (getPanels( )[n].getP13nData( ) through the event source, read back as compact JSON arrays) and the setP13nData JSON argument are source-derived, not run in a live system. **e2e-verified 2026-10-21** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_650.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_651.json b/meta/z2ui5_cl_smpc_app_651.json new file mode 100644 index 000000000..59b463bbf --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_651.json @@ -0,0 +1,32 @@ +{ + "class": "z2ui5_cl_smpc_app_651", + "sample": "sap.m.sample.VariantManagement", + "entity": "sap.m.VariantManagement", + "file": "src/02/01/z2ui5_cl_smpc_app_651.clas.abap", + "batch": "b55", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "follow_up_action( control_global MESSAGE_TOAST show ) carries the original's closeOnBrowserNavigation toast option; select/save/manage pass their event parameters via t_arg (manage: the deleted, renamed, fav and exe arrays as JSON)" + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.VariantManagement control (since UI5 1.103) is newer than 1.71 and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.103." + }, + { + "type": "NOTE", + "what": "the original declares its four VariantItem controls statically and the controller adds (onSave -> addItem) and removes (onManage -> removeItem) items imperatively. The port keeps the VariantItem controls static as well - one per row of a backend table seeded with the four original entries (values verbatim, all ten properties), emitted in a loop - so the backend can add and delete views by re-rendering the view: a Save As that creates a view and every Manage rebuild it. An items binding with a template would be the shorter form, but it breaks the control on UI5 1.152: VariantManagement filters its own popover and Manage Views lists (bound to its internal $mVariants ManagedObjectModel, properties visible and favorite) with the paths it reads off the app's items TEMPLATE (_getFilters/_resolveTemplatePath: VISIBLE, FAVORITE), which that model does not have, so every view is filtered out and the my Favorites list stays empty. Because the items are not bound, the manage handler applies everything the Manage Views dialog changed on them, as the control's manage event reports it: the deleted keys (removed), renamed (title), fav (favorite) and exe (executeOnSelect), and like _checkCurrentVariant falls back to the standard (first) view when the selected one was deleted. selectedKey, defaultKey and modified are bound two-way: the Toggle Modify View button flips modified in the backend (setModified), select and save reset it, and a manage change of the default view (onManage's setDefaultKey( def )) reaches the model through the bound defaultKey." + }, + { + "type": "NOTE", + "what": "a new view's key is built from an ABAP timestamp (key_) instead of JavaScript's Date.now( ) milliseconds - unique per save as in the original, a different digit format. The three MessageToast texts are composed in the backend with the same wording and carry the original's closeOnBrowserNavigation option through the control_global MESSAGE_TOAST call." + }, + { + "type": "NOTE", + "what": "the manage event's deleted, renamed, fav and exe parameters are transported as ${$parameters>/...} array args and read back as JSON, and the save event's boolean parameters (overwrite, execute, def, public) as abap_bool - unverified in a running system, as is a rename/favorite/execute-on-select change from the Manage Views dialog surviving the view rebuild the manage event triggers. **e2e-verified 2026-10-21** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_651.mjs)." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_652.json b/meta/z2ui5_cl_smpc_app_652.json new file mode 100644 index 000000000..1ddb2b798 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_652.json @@ -0,0 +1,63 @@ +{ + "class": "z2ui5_cl_smpc_app_652", + "sample": "sap.m.sample.UploadSetwithTablePlugin.FileNameValidationSample", + "entity": "sap.m.plugins.UploadSetwithTable", + "file": "src/02/01/z2ui5_cl_smpc_app_652.clas.abap", + "batch": "b56", + "audit": { + "frontend_action": true, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.plugins.UploadSetwithTable control (since UI5 1.124) is newer than 1.71 and is the whole point of this sample - kept 1:1 in the table's dependents as plugins:UploadSetwithTable (the original's dotted plugins.UploadSetwithTable under the sap.m default namespace), with its rowConfiguration aggregation; the app needs a UI5 release >= 1.124. Every member it carries (uploadUrl, multiple, cloudFilePickerEnabled, the actions association, beforeUploadStarts, itemRenamed) is as new as the plugin, and fileNameValidationConfig - the member this sample is about, kept as the view's literal {mode: 'override', characters: '@$#'} - is @since 1.136, so the app needs UI5 >= 1.136." + }, + { + "type": "POST_171", + "what": "the plugin's companion controls are kept 1:1 and are post-1.71 too: sap.m.upload.ActionsPlaceholder (@since 1.120, with placeholderFor - the toolbar slot the plugin renders its upload button into) and sap.m.upload.UploadItemConfiguration (@since 1.124; fileNamePath, mediaTypePath, urlPath, previewablePath and fileSizePath @1.124, isTrustedSourcePath @1.125), written upload:UploadItemConfiguration for the original's dotted upload.UploadItemConfiguration." + }, + { + "type": "POST_171", + "what": "sap.m.Column importance (@since 1.76) on the File Name and action columns, and sap.m.Table autoPopinMode (@since 1.76) and hiddenInPopin (@since 1.77), are kept 1:1 from the original table." + }, + { + "type": "NOTE", + "what": "The named JSONModel documents (manifest dataSource model/documents.json) is folded into the default model: every {documents>x} binding is the row field {X} and the items path is the bound T_ITEMS, still as the original's {path, templateShareable: false} binding info. All six rows are inlined, and the top-level mode, characters, isConfigureButtonEnabled and defaultCharacterSet keys are model fields too (mode is kept PROTECTED - no binding reads it); the url and imageUrl fields are host-absolutized to https://sdk.openui5.org/test-resources/... because an abap2UI5 app has no demo-kit root to resolve the relative test-resources paths against. The UploadItemConfiguration paths name the upper-case ABAP fields (FILENAME, MEDIATYPE, URL, PREVIEWABLE, FILESIZE, TRUSTEDSOURCE) instead of fileName/mediaType/... - the same model columns. IMAGEURL and UPLOADSTATE are bound with omit_initial_paths, so a row the mock gives no imageUrl/uploadState still reads undefined and the original's own Image/Icon visible expressions and highlight expression decide exactly as in the sample." + }, + { + "type": "NOTE", + "what": "The controller formatters getIconSrc (UploadSetwithTable.getIconForFileType - IconPool's media-type table, the file-extension fallback with sap-icon://card for images) and getFileSizeWithUnits (KB/MB/GB with two decimals) run in ABAP (icon_for, size_with_units) and the row carries the finished values in two port fields, ICON and FILESIZE_UNITS, which core:Icon.src and the File Size Text bind - the thin-frontend rule; the {parts: [...], formatter: ...} bindings are gone with them." + }, + { + "type": "NOTE", + "what": "The validation panel: the three CheckBoxes keep their ids (cbInclude, cbExclude, cbOverride) and their select wire transports $event.oSource.getId(), from which the backend makes the three boxes one choice exactly like onCheckboxSelect (their selected is bound; cbOverride starts selected as in the view); charInput's value is bound to characters and its liveChange wire carries ${$parameters>/newValue} (onInputChange reads newValue, the bound model only follows on change) with check_queue_last and check_no_busy, and both recompute isConfigureButtonEnabled, which the Configure button's enabled binds as in the original. Configure calls the plugin's setFileNameValidationConfig through control_by_id on the plugin with the {mode, characters} object as a JSON argument (characters JSON-escaped), shows the original's toast text, and remembers the payload so view_display re-issues it after a rebuild (the view's literal config would otherwise come back). The note Text binds the default character set /:\\*?\"<>|[]{}@#$ of documents.json." + }, + { + "type": "NOTE", + "what": "design='Bold' is dropped from the three Text controls of the panel: sap.m.Text has no design property (it is sap.m.Label's), and the view fails to load with it - the render gate measured 'Error found in View' on exactly that node. Nothing visible is lost, since the attribute never reached a control." + }, + { + "type": "IMPROVISED", + "what": "Upload: the sample starts a sinon fake XHR server (model/mockserver.js) in beforeUploadStarts, which answers the POST to /uploadFiles with 201 and unshifts the new document. There is no such endpoint behind an abap2UI5 app, so the port plays the mock server's part in the backend: beforeUploadStarts is a backend wire with check_prevent_default (the plugin's own veto - no XHR is sent) that transports the item's file name, media type and size, and the backend unshifts the row the mock server would have created (uploadState Complete, revision 00, In work, Jane Burns, Invoice, trustedSource) and shows the 'Document Added' toast at once rather than after the sample's one-second setTimeout. Lost with it: the uploaded file's blob: object URL (an uploaded row has an empty url, so it cannot be previewed or downloaded) and the random uid id (a running number); uploadCompleted and onActivated are not wired (no upload completes, and the plugin is addressed by an added id uploadSetPlugin instead of the instance onActivated handed the controller); URLListValidator.add('blob') is dropped. Several files picked at once fire beforeUploadStarts back to back and abap2UI5 runs one round-trip at a time: check_queue_last keeps the last one, so only the first and the last of them are added." + }, + { + "type": "IMPROVISED", + "what": "onDownloadFiles calls the plugin's download( context, true ) for EVERY selected row; a UI5 event expression has no loop, so the port's Download button calls download for the first selected row only, through a view-wired control_by_id on the plugin whose argument is $controller.getView().byId('table-uploadSet').getSelectedContexts()[0]." + }, + { + "type": "NOTE", + "what": "Unverified in a running system: (a) the plugin calls by id (uploadSetPlugin, an id the original does not carry) through the unlisted-method path of control_by_id - openFilePreview with the Link's $event.oSource.getBindingContext(), renameItem and download with $controller.getView().byId('table-uploadSet').getSelectedContexts()[0] - each handing the live Context object through castArgAuto untouched; (b) selectionChange transporting $event.oSource.getSelectedContexts().join() (Context.toString is the binding path) and the itemRenamed wire reading ${$parameters>/item}.getBindingContext().getPath(); (c) the vetoed beforeUploadStarts and ${$parameters>/item}.getFileObject().size; (d) setFileNameValidationConfig reached with a JSON object argument through castArgAuto, and the plugin's rename dialog then validating against it. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_652.mjs)." + }, + { + "type": "NOTE", + "what": "onSelectionChange's setEnabled calls become two bound flags: Download is enabled for one or more selected rows, Remove/Rename/Edit URL for exactly one. onSearch's Filter('fileName', Contains, query) is the view-wired binding_call filter on the table's items with ${$source>/value} - roundtrip-free, and like any binding filter it does not survive a view rebuild. onDocumentRenamedSuccess writes the new name into the row in the backend (the itemRenamed wire carries the row's path and the item's file name) and toasts 'Document Renamed.' with duration 2000. After a removal the port resets the selection AND the four buttons; the original's removeSelections( ) fires no selectionChange, so there the buttons stayed enabled on an empty selection." + }, + { + "type": "IMPROVISED", + "what": "The AddViaUrl fragment is the port's popup with its ids kept (addViaUrlDialog, addViaUrlSimpleform, urlInputLabel, urlInput, nameInputLabel, nameInput, addDocumentBtn), and what openAddOrEditDialog / _isValidName / _validateAddOrEditUrlDialog set through Element.getElementById is bound instead: the Dialog title (Add URL / Edit URL), the begin button text (Add / Apply), urlInputLabel.required, both Input values and their valueState / valueStateText. Cancel closes it with popup_close. Add validates name and URL in the backend (the unanchored URL regex reduced to its required part, a ftp/http/https scheme followed by a non-blank) and then adds the row directly - uploadItemViaUrl takes a JS Promise and the controller adds a documentUrl header field to the item, neither transportable, and the mock server's answer is exactly that row (the URL as typed, an empty media type and size 0). showEditConfirmation's controller-built sap.m.Dialog (type Message, state Warning, title Warning, Save / DiscardChanges) is a MessageBox.warning with the same title, text, actions and Save emphasized; Save updates the selected row's fileName and url and closes the fragment, DiscardChanges only closes the box. removeItem's MessageBox.warning keeps its text, actions Remove/CANCEL, emphasizedAction, styleClass and initialFocus; its explicit icon option is the warning box's own icon anyway." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_653.json b/meta/z2ui5_cl_smpc_app_653.json new file mode 100644 index 000000000..898189f9a --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_653.json @@ -0,0 +1,63 @@ +{ + "class": "z2ui5_cl_smpc_app_653", + "sample": "sap.m.sample.UploadSetwithTablePlugin.FilePreviewCustomPageContent", + "entity": "sap.m.plugins.UploadSetwithTable", + "file": "src/02/01/z2ui5_cl_smpc_app_653.clas.abap", + "batch": "b56", + "audit": { + "frontend_action": true, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.plugins.UploadSetwithTable control (since UI5 1.124) is newer than 1.71 and is the whole point of this sample - kept 1:1 in the table's dependents as plugins:UploadSetwithTable (the original's dotted plugins.UploadSetwithTable under the sap.m default namespace), with its rowConfiguration aggregation and its previewDialog association pointing at the FilePreviewDialog; the app needs a UI5 release >= 1.124. Every member it carries (uploadUrl, multiple, cloudFilePickerEnabled, the actions and previewDialog associations, beforeUploadStarts, itemRenamed) is as new as the plugin." + }, + { + "type": "POST_171", + "what": "the plugin's companion controls are kept 1:1 and are post-1.71 too: sap.m.upload.ActionsPlaceholder (@since 1.120, with placeholderFor - the toolbar slot the plugin renders its upload button into) and sap.m.upload.UploadItemConfiguration (@since 1.124; fileNamePath, mediaTypePath, urlPath, previewablePath and fileSizePath @1.124, isTrustedSourcePath @1.125), written upload:UploadItemConfiguration for the original's dotted upload.UploadItemConfiguration." + }, + { + "type": "POST_171", + "what": "sap.m.upload.FilePreviewDialog (@since 1.120) is kept in the table's dependents with its id FilePreviewDialog, showCarouselArrows and maxFileSizeforPreview (both @1.120); the plugin's previewDialog association names it, so openFilePreview opens this dialog instead of a default instance." + }, + { + "type": "IMPROVISED", + "what": "The point of this variant is lost: FilePreviewDialog.customPageContentHandler='.pageContentHandler' is a function-typed property - the controller's callback returns a Promise that resolves, for the application/xml row, to a sap.ui.codeeditor.CodeEditor holding a hard-coded invoice XML, and rejects (no content) for every other type. A function cannot be bound or transported from the backend, so the attribute is dropped and the External XML document.xml row previews as an unsupported type with the dialog's default no-preview illustration - exactly what the second MessageStrip promises for the zip file only. Both MessageStrips are kept 1:1, so the first one now describes a behaviour the port does not show." + }, + { + "type": "POST_171", + "what": "sap.m.Column importance (@since 1.76) on the File Name and action columns, and sap.m.Table autoPopinMode (@since 1.76) and hiddenInPopin (@since 1.77), are kept 1:1 from the original table." + }, + { + "type": "NOTE", + "what": "The named JSONModel documents (manifest dataSource model/documents.json) is folded into the default model: every {documents>x} binding is the row field {X} and the items path is the bound T_ITEMS, still as the original's {path, templateShareable: false} binding info. All eight rows are inlined; the url and imageUrl fields are host-absolutized to https://sdk.openui5.org/test-resources/... because an abap2UI5 app has no demo-kit root to resolve the relative test-resources paths against. The UploadItemConfiguration paths name the upper-case ABAP fields (FILENAME, MEDIATYPE, URL, PREVIEWABLE, FILESIZE, TRUSTEDSOURCE) instead of fileName/mediaType/... - the same model columns. IMAGEURL and UPLOADSTATE are bound with omit_initial_paths, so a row the mock gives no imageUrl/uploadState still reads undefined and the original's own Image/Icon visible expressions and highlight expression decide exactly as in the sample." + }, + { + "type": "NOTE", + "what": "The controller formatters getIconSrc (UploadSetwithTable.getIconForFileType - IconPool's media-type table, the file-extension fallback with sap-icon://card for images) and getFileSizeWithUnits (KB/MB/GB with two decimals) run in ABAP (icon_for, size_with_units) and the row carries the finished values in two port fields, ICON and FILESIZE_UNITS, which core:Icon.src and the File Size Text bind - the thin-frontend rule; the {parts: [...], formatter: ...} bindings are gone with them." + }, + { + "type": "IMPROVISED", + "what": "Upload: the sample starts a sinon fake XHR server (model/mockserver.js) in beforeUploadStarts, which answers the POST to /uploadFiles with 201 and unshifts the new document. There is no such endpoint behind an abap2UI5 app, so the port plays the mock server's part in the backend: beforeUploadStarts is a backend wire with check_prevent_default (the plugin's own veto - no XHR is sent) that transports the item's file name, media type and size, and the backend unshifts the row the mock server would have created (uploadState Complete, revision 00, In work, Jane Burns, Invoice, trustedSource) and shows the 'Document Added' toast at once rather than after the sample's one-second setTimeout. Lost with it: the uploaded file's blob: object URL (an uploaded row has an empty url, so it cannot be previewed or downloaded) and the random uid id (a running number); uploadCompleted and onActivated are not wired (no upload completes, and the plugin is addressed by an added id uploadSetPlugin instead of the instance onActivated handed the controller); URLListValidator.add('blob') is dropped. Several files picked at once fire beforeUploadStarts back to back and abap2UI5 runs one round-trip at a time: check_queue_last keeps the last one, so only the first and the last of them are added." + }, + { + "type": "IMPROVISED", + "what": "onDownloadFiles calls the plugin's download( context, true ) for EVERY selected row; a UI5 event expression has no loop, so the port's Download button calls download for the first selected row only, through a view-wired control_by_id on the plugin whose argument is $controller.getView().byId('table-uploadSet').getSelectedContexts()[0]." + }, + { + "type": "NOTE", + "what": "Unverified in a running system: (a) the plugin calls by id (uploadSetPlugin, an id the original does not carry) through the unlisted-method path of control_by_id - openFilePreview with the Link's $event.oSource.getBindingContext(), renameItem and download with $controller.getView().byId('table-uploadSet').getSelectedContexts()[0] - each handing the live Context object through castArgAuto untouched; (b) selectionChange transporting $event.oSource.getSelectedContexts().join() (Context.toString is the binding path); (c) the vetoed beforeUploadStarts and ${$parameters>/item}.getFileObject().size. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_653.mjs)." + }, + { + "type": "NOTE", + "what": "onSelectionChange's setEnabled calls become two bound flags: Download is enabled for one or more selected rows, Remove/Rename/Edit URL for exactly one. onSearch's Filter('fileName', Contains, query) is the view-wired binding_call filter on the table's items with ${$source>/value} - roundtrip-free, and like any binding filter it does not survive a view rebuild. This variant's onDocumentRenamedSuccess only toasts 'Document Renamed.' with duration 2000 (it does not write the new name into the model, so the row keeps its old name - as in the original); the itemRenamed wire therefore carries no arguments. After a removal the port resets the selection AND the four buttons; the original's removeSelections( ) fires no selectionChange, so there the buttons stayed enabled on an empty selection." + }, + { + "type": "IMPROVISED", + "what": "The AddViaUrl fragment is the port's popup with its ids kept (addViaUrlDialog, addViaUrlSimpleform, urlInputLabel, urlInput, nameInputLabel, nameInput, addDocumentBtn), and what openAddOrEditDialog / _isValidName / _validateAddOrEditUrlDialog set through Element.getElementById is bound instead: the Dialog title (Add URL / Edit URL), the begin button text (Add / Apply), urlInputLabel.required, both Input values and their valueState / valueStateText. Cancel closes it with popup_close. Add validates name and URL in the backend (the unanchored URL regex reduced to its required part, a ftp/http/https scheme followed by a non-blank) and then adds the row directly - uploadItemViaUrl takes a JS Promise and the controller adds a documentUrl header field to the item, neither transportable, and the mock server's answer is exactly that row (the URL as typed, an empty media type and size 0). showEditConfirmation's controller-built sap.m.Dialog (type Message, state Warning, title Warning, Save / DiscardChanges) is a MessageBox.warning with the same title, text, actions and Save emphasized; Save updates the selected row's fileName and url and closes the fragment, DiscardChanges only closes the box. removeItem's MessageBox.warning keeps its text, actions Remove/CANCEL, emphasizedAction, styleClass and initialFocus; its explicit icon option is the warning box's own icon anyway." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_654.json b/meta/z2ui5_cl_smpc_app_654.json new file mode 100644 index 000000000..1e7d9e65f --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_654.json @@ -0,0 +1,51 @@ +{ + "class": "z2ui5_cl_smpc_app_654", + "sample": "sap.m.sample.UploadSetwithTablePlugin.GridTableSimple", + "entity": "sap.m.plugins.UploadSetwithTable", + "file": "src/02/01/z2ui5_cl_smpc_app_654.clas.abap", + "batch": "b56", + "audit": { + "frontend_action": true, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.plugins.UploadSetwithTable control (since UI5 1.124) is newer than 1.71 and is the whole point of this sample - kept 1:1 in the sap.ui.table.Table's dependents as plugins:UploadSetwithTable (the original's dotted m:plugins.UploadSetwithTable), with the UploadItemConfiguration as its default rowConfiguration aggregation; the app needs a UI5 release >= 1.124. Every member it carries (uploadUrl, multiple, cloudFilePickerEnabled, the actions association, beforeUploadStarts, itemRenamed) is as new as the plugin." + }, + { + "type": "POST_171", + "what": "the plugin's companion controls are kept 1:1 and are post-1.71 too: sap.m.upload.ActionsPlaceholder (@since 1.120, with placeholderFor - the toolbar slot the plugin renders its upload button into) and sap.m.upload.UploadItemConfiguration (@since 1.124; fileNamePath, mediaTypePath, urlPath, previewablePath and fileSizePath @1.124, isTrustedSourcePath @1.125), written upload:UploadItemConfiguration for the original's dotted m:upload.UploadItemConfiguration." + }, + { + "type": "NOTE", + "what": "The named JSONModel documents (manifest dataSource model/documents.json) is folded into the default model: every {documents>x} binding is the row field {X} and the Table's rows are the bound T_ITEMS. All nine rows are inlined; the url and imageUrl fields are host-absolutized to https://sdk.openui5.org/test-resources/... because an abap2UI5 app has no demo-kit root to resolve the relative test-resources paths against. The UploadItemConfiguration paths name the upper-case ABAP fields (FILENAME, MEDIATYPE, URL, PREVIEWABLE, FILESIZE, TRUSTEDSOURCE) instead of fileName/mediaType/... - the same model columns. IMAGEURL and UPLOADSTATE are bound with omit_initial_paths, so a row the mock gives no imageUrl/uploadState still reads undefined and the original's own Image/Icon visible expressions and the RowSettings highlight expression decide exactly as in the sample." + }, + { + "type": "NOTE", + "what": "The controller formatters getIconSrc (UploadSetwithTable.getIconForFileType - IconPool's media-type table, the file-extension fallback with sap-icon://card for images) and getFileSizeWithUnits (KB/MB/GB with two decimals) run in ABAP (icon_for, size_with_units) and the row carries the finished values in two port fields, ICON and FILESIZE_UNITS, which core:Icon.src and the File Size Text bind - the thin-frontend rule; the {parts: [...], formatter: ...} bindings are gone with them." + }, + { + "type": "IMPROVISED", + "what": "Upload: the sample starts a sinon fake XHR server (model/mockserver.js) in beforeUploadStarts, which answers the POST to /uploadFiles with 201 and unshifts the new document. There is no such endpoint behind an abap2UI5 app, so the port plays the mock server's part in the backend: beforeUploadStarts is a backend wire with check_prevent_default (the plugin's own veto - no XHR is sent) that transports the item's file name, media type and size, and the backend unshifts the row the mock server would have created (uploadState Complete, revision 00, In work, Jane Burns, Invoice, trustedSource) and shows the 'Document Added' toast at once rather than after the sample's one-second setTimeout. Lost with it: the uploaded file's blob: object URL (an uploaded row has an empty url, so it cannot be previewed or downloaded) and the random uid id (a running number); uploadCompleted and onActivated are not wired (no upload completes, and the plugin is addressed by an added id uploadSetPlugin instead of the instance onActivated handed the controller); URLListValidator.add('blob') is dropped. Several files picked at once fire beforeUploadStarts back to back and abap2UI5 runs one round-trip at a time: check_queue_last keeps the last one, so only the first and the last of them are added." + }, + { + "type": "IMPROVISED", + "what": "onDownloadFiles maps getSelectedIndices( ) to contexts and calls the plugin's download( context, true ) for EVERY selected row; a UI5 event expression has no loop, so the port's Download button calls download for the first selected row only, through a view-wired control_by_id on the plugin whose argument is $controller.getView().byId('table-uploadSet').getContextByIndex(...getSelectedIndices()[0])." + }, + { + "type": "NOTE", + "what": "Unverified in a running system: (a) the plugin calls by id (uploadSetPlugin, an id the original does not carry) through the unlisted-method path of control_by_id - openFilePreview with the template Link's $event.oSource.getBindingContext(), renameItem and download with $controller.getView().byId('table-uploadSet').getContextByIndex($controller.getView().byId('table-uploadSet').getSelectedIndices()[0]) - each handing the live Context object through castArgAuto untouched; (b) rowSelectionChange transporting $event.oSource.getSelectedIndices().join() and the itemRenamed wire reading ${$parameters>/item}.getBindingContext().getPath(); (c) the vetoed beforeUploadStarts and ${$parameters>/item}.getFileObject().size. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_654.mjs)." + }, + { + "type": "NOTE", + "what": "onSelectionChange's setEnabled calls become two bound flags: Download is enabled for one or more selected rows, Remove/Rename/Edit URL for exactly one; the selection travels as the row indices (the table neither sorts nor filters, so a row index is the model index). onDocumentRenamedSuccess writes the new name into the row in the backend (the itemRenamed wire carries the row's path and the item's file name) and toasts 'Document Renamed.' with duration 2000. removeItem splices the row out of /items; its oTable.removeSelections( ) does not exist on sap.ui.table.Table, so the selection stays on the same indices in both the original and the port." + }, + { + "type": "IMPROVISED", + "what": "The AddViaUrl fragment is the port's popup with its ids kept (addViaUrlDialog, addViaUrlSimpleform, urlInputLabel, urlInput, nameInputLabel, nameInput, addDocumentBtn), and what openAddOrEditDialog / _isValidName / _validateAddOrEditUrlDialog set through Element.getElementById is bound instead: the Dialog title (Add URL / Edit URL), the begin button text (Add / Apply), urlInputLabel.required, both Input values and their valueState / valueStateText. Cancel closes it with popup_close. Add validates name and URL in the backend (the unanchored URL regex reduced to its required part, a ftp/http/https scheme followed by a non-blank) and then adds the row directly - uploadItemViaUrl takes a JS Promise and the controller adds a documentUrl header field to the item, neither transportable, and the mock server's answer is exactly that row (the URL as typed, an empty media type and size 0). showEditConfirmation's controller-built sap.m.Dialog (type Message, state Warning, title Warning, Save / DiscardChanges) is a MessageBox.warning with the same title, text, actions and Save emphasized; Save updates the selected row's fileName and url and closes the fragment, DiscardChanges only closes the box. removeItem's MessageBox.warning keeps its text, actions Remove/CANCEL, emphasizedAction, styleClass and initialFocus; its explicit icon option is the warning box's own icon anyway." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_655.json b/meta/z2ui5_cl_smpc_app_655.json new file mode 100644 index 000000000..4c33ed34f --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_655.json @@ -0,0 +1,59 @@ +{ + "class": "z2ui5_cl_smpc_app_655", + "sample": "sap.m.sample.UploadSetwithTablePlugin.MultiplePluginInstances", + "entity": "sap.m.plugins.UploadSetwithTable", + "file": "src/02/01/z2ui5_cl_smpc_app_655.clas.abap", + "batch": "b56", + "audit": { + "frontend_action": true, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.plugins.UploadSetwithTable control (since UI5 1.124) is newer than 1.71 and is the whole point of this sample - three instances, each kept 1:1 in its table's dependents as plugins:UploadSetwithTable (the original's dotted plugins.UploadSetwithTable under the sap.m default namespace) with its rowConfiguration aggregation and its customData (the core:CustomData itemsPath the controller reads); the app needs a UI5 release >= 1.124. Every member they carry (uploadUrl, multiple, cloudFilePickerEnabled, the actions association, beforeUploadStarts) is as new as the plugin." + }, + { + "type": "POST_171", + "what": "the plugin's companion controls are kept 1:1 and are post-1.71 too: sap.m.upload.ActionsPlaceholder (@since 1.120, with placeholderFor - the toolbar slot the plugin renders its upload button into) and sap.m.upload.UploadItemConfiguration (@since 1.124; fileNamePath, mediaTypePath, urlPath, previewablePath and fileSizePath @1.124, isTrustedSourcePath @1.125), written upload:UploadItemConfiguration for the original's dotted upload.UploadItemConfiguration." + }, + { + "type": "POST_171", + "what": "sap.m.Column importance (@since 1.76) on the File Name and action columns, and sap.m.Table autoPopinMode (@since 1.76) and hiddenInPopin (@since 1.77), are kept 1:1 from the original table." + }, + { + "type": "NOTE", + "what": "The named JSONModel documents (manifest dataSource model/documents.json) is folded into the default model: every {documents>x} binding is the row field {X}, and the three arrays items, items-instance2 and items-instance3 are the bound T_ITEMS, T_ITEMSINSTANCE2 and T_ITEMSINSTANCE3 (an ABAP name cannot carry the hyphen), still as the original's {path, templateShareable: false} binding info. All nine rows (three per array) are inlined; the url and imageUrl fields are host-absolutized to https://sdk.openui5.org/test-resources/... because an abap2UI5 app has no demo-kit root to resolve the relative test-resources paths against. The UploadItemConfiguration paths name the upper-case ABAP fields (FILENAME, MEDIATYPE, URL, PREVIEWABLE, FILESIZE, TRUSTEDSOURCE) instead of fileName/mediaType/... - the same model columns. IMAGEURL and UPLOADSTATE are bound with omit_initial_paths, so a row the mock gives no imageUrl/uploadState still reads undefined and the original's own Image/Icon visible expressions and highlight expression decide exactly as in the sample." + }, + { + "type": "NOTE", + "what": "The controller formatters getIconSrc (UploadSetwithTable.getIconForFileType - IconPool's media-type table, the file-extension fallback with sap-icon://card for images) and getFileSizeWithUnits (KB/MB/GB with two decimals) run in ABAP (icon_for, size_with_units) and the row carries the finished values in two port fields, ICON and FILESIZE_UNITS, which core:Icon.src and the File Size Text bind - the thin-frontend rule; the {parts: [...], formatter: ...} bindings are gone with them." + }, + { + "type": "IMPROVISED", + "what": "Upload: the sample starts a sinon fake XHR server (model/mockserver.js) in beforeUploadStarts, which answers the POST to /uploadFiles with 201 and unshifts the new document. There is no such endpoint behind an abap2UI5 app, so the port plays the mock server's part in the backend: beforeUploadStarts is a backend wire with check_prevent_default (the plugin's own veto - no XHR is sent) that transports the item's file name, media type and size plus the plugin's own customData itemsPath ($event.oSource.data('itemsPath') - what onBeforeUploadStarts hands the mock server as instancePath), and the backend unshifts into that array the row the mock server would have created (uploadState Complete, revision 00, In work, Jane Burns, Invoice, trustedSource) and shows the 'Document Added' toast at once rather than after the sample's one-second setTimeout. Lost with it: the uploaded file's blob: object URL (an uploaded row has an empty url, so it cannot be previewed or downloaded) and the random uid id (a running number); uploadCompleted and onActivated are not wired (no upload completes, and each plugin is addressed by an added id - uploadSetPlugin, uploadSetPlugin-instance2, uploadSetPlugin-instance3 - instead of the instances onActivated handed the controller); URLListValidator.add('blob') is dropped. Several files picked at once fire beforeUploadStarts back to back and abap2UI5 runs one round-trip at a time: check_queue_last keeps the last one, so only the first and the last of them are added." + }, + { + "type": "IMPROVISED", + "what": "onDownloadFiles calls download( context, true ) for EVERY selected row of the table; a UI5 event expression has no loop, so each Download button calls download for the first selected row of its own table only, through a view-wired control_by_id on that table's plugin with $controller.getView().byId().getSelectedContexts()[0]. (The original always ends up in its first plugin instance - it looks for 'instance2' in the id of the table's PARENT, the VBox - which downloads the same files, since download only reads the context it is given.)" + }, + { + "type": "NOTE", + "what": "Unverified in a running system: (a) the plugin calls by id (uploadSetPlugin, uploadSetPlugin-instance2, uploadSetPlugin-instance3 - ids the original does not carry) through the unlisted-method path of control_by_id - openFilePreview with the Link's $event.oSource.getBindingContext() and download with $controller.getView().byId(
).getSelectedContexts()[0] - each handing the live Context object through castArgAuto untouched; (b) the vetoed beforeUploadStarts with ${$parameters>/item}.getFileObject().size and $event.oSource.data('itemsPath'). **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_655.mjs)." + }, + { + "type": "NOTE", + "what": "The controller's quirks are kept 1:1 where they decide what happens to the data: every SearchField's onSearch filters the FIRST table (byId('table-uploadSet')) - the three liveChange wires are the same view-wired binding_call filter on that table; removeItem splices the clicked row's index out of /items and clears the first table's selection whichever table the row belongs to (the MessageBox still names the clicked document) - the port deletes from T_ITEMS by the index in the row's binding path. Where the quirk only picks an equivalent instance the port is direct: openPreview reads 'instance2' from the template Link's generated id, so the original always previews through the first plugin; each port Link calls its own table's plugin. onSelectionChange enables each table's Download button from its own selection (the wire carries the table id and getSelectedContexts().length); after a removal the first table's Download button is disabled with its cleared selection (removeSelections fires no selectionChange, so the original left it enabled)." + }, + { + "type": "NOTE", + "what": "removeItem's MessageBox.warning keeps its text, actions Remove/CANCEL, emphasizedAction, styleClass and initialFocus; its explicit icon option is the warning box's own icon anyway. The mock server's 'Document Added' toast follows at once instead of after the controller's one-second setTimeout (see the upload deviation)." + }, + { + "type": "NOTE", + "what": "The sample ships view/fragment/AddViaUrl.fragment.xml (a Dialog addViaUrlDialog holding a form:SimpleForm addViaUrlSimpleform with two Label controls urlInputLabel and nameInputLabel - both required - two Input controls urlInput and nameInput, and the Button controls addDocumentBtn and Cancel), but nothing in this variant loads it: its view has no Add menu and its controller no openAddOrEditDialog / handleAddViaUrl. The port does not build the dead fragment, so structural_diff, which unions every archived fragment with the view, counts its controls as missing." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_656.json b/meta/z2ui5_cl_smpc_app_656.json new file mode 100644 index 000000000..9dee082cc --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_656.json @@ -0,0 +1,59 @@ +{ + "class": "z2ui5_cl_smpc_app_656", + "sample": "sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableFileDialogs", + "entity": "sap.m.plugins.UploadSetwithTable", + "file": "src/02/01/z2ui5_cl_smpc_app_656.clas.abap", + "batch": "b56", + "audit": { + "frontend_action": true, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.plugins.UploadSetwithTable control (since UI5 1.124) is newer than 1.71 and is the whole point of this sample - kept 1:1 in the table's dependents as plugins:UploadSetwithTable (the original's dotted plugins.UploadSetwithTable under the sap.m default namespace), with its rowConfiguration aggregation; the app needs a UI5 release >= 1.124. Every member it carries (uploadUrl, multiple, cloudFilePickerEnabled, the actions association, beforeUploadStarts, itemRenamed) is as new as the plugin." + }, + { + "type": "POST_171", + "what": "the plugin's companion controls are kept 1:1 and are post-1.71 too: sap.m.upload.ActionsPlaceholder (@since 1.120, with placeholderFor - the toolbar slot the plugin renders its upload button into) and sap.m.upload.UploadItemConfiguration (@since 1.124; fileNamePath, mediaTypePath, urlPath, previewablePath and fileSizePath @1.124, isTrustedSourcePath @1.125), written upload:UploadItemConfiguration for the original's dotted upload.UploadItemConfiguration." + }, + { + "type": "POST_171", + "what": "sap.m.Column importance (@since 1.76) on the File Name and action columns, and sap.m.Table autoPopinMode (@since 1.76) and hiddenInPopin (@since 1.77), are kept 1:1 from the original table." + }, + { + "type": "NOTE", + "what": "The named JSONModel documents (manifest dataSource model/documents.json) is folded into the default model: every {documents>x} binding is the row field {X} and the items path is the bound T_ITEMS, still as the original's {path, templateShareable: false} binding info. All nine rows are inlined; the url and imageUrl fields are host-absolutized to https://sdk.openui5.org/test-resources/... because an abap2UI5 app has no demo-kit root to resolve the relative test-resources paths against. The UploadItemConfiguration paths name the upper-case ABAP fields (FILENAME, MEDIATYPE, URL, PREVIEWABLE, FILESIZE, TRUSTEDSOURCE) instead of fileName/mediaType/... - the same model columns. IMAGEURL and UPLOADSTATE are bound with omit_initial_paths, so a row the mock gives no imageUrl/uploadState still reads undefined and the original's own Image/Icon visible expressions and highlight expression decide exactly as in the sample." + }, + { + "type": "NOTE", + "what": "The controller formatters getIconSrc (UploadSetwithTable.getIconForFileType - IconPool's media-type table, the file-extension fallback with sap-icon://card for images) and getFileSizeWithUnits (KB/MB/GB with two decimals) run in ABAP (icon_for, size_with_units) and the row carries the finished values in two port fields, ICON and FILESIZE_UNITS, which core:Icon.src and the File Size Text bind - the thin-frontend rule; the {parts: [...], formatter: ...} bindings are gone with them." + }, + { + "type": "IMPROVISED", + "what": "Upload: the sample starts a sinon fake XHR server (model/mockserver.js) in beforeUploadStarts, which answers the POST to /uploadFiles with 201 and unshifts the new document. There is no such endpoint behind an abap2UI5 app, so the port plays the mock server's part in the backend: beforeUploadStarts is a backend wire with check_prevent_default (the plugin's own veto - no XHR is sent) that transports the item's file name, media type and size, and the backend queues the file for the FileUpload dialog (see the next deviation); its Add then unshifts, per file, the row the mock server would have created (uploadState Complete, revision 00, In work, Jane Burns, the chosen document type, trustedSource) and shows 'Document Added' once, at once rather than after the sample's one-second setTimeout. Lost with it: the uploaded file's blob: object URL (an uploaded row has an empty url, so it cannot be previewed or downloaded) and the random uid id (a running number); uploadCompleted and onActivated are not wired (no upload completes, and the plugin is addressed by an added id uploadSetPlugin instead of the instance onActivated handed the controller); URLListValidator.add('blob') is dropped. Several files picked at once fire beforeUploadStarts back to back and abap2UI5 runs one round-trip at a time: check_queue_last keeps the last one, so only the first and the last of them reach the dialog." + }, + { + "type": "IMPROVISED", + "what": "The point of this variant, the FileUpload dialog, is driven differently: the original sets itemValidationHandler='.itemValidationCallback' on the plugin - a function-typed property that cannot be bound or transported, so it is dropped - and that callback parks each picked item with its Promise resolve/reject, then opens the FileUpload fragment on a dialog-local JSONModel {selectedItems, types}. In the port the vetoed beforeUploadStarts collects the file into T_SELECTEDITEMS (fileName, fileCategorySelected preset to the first category, plus the port's media type and size) and opens the fragment as the popup, rebuilt 1:1 (Dialog, Toolbar with Title/ToolbarSpacer/Browse Button, the Table with its three Columns, the ComboBox over T_TYPES from getFileCategories with selectedKey, the valueState expression and valueStateText, core:ListItem, the decline Button, Add and Cancel); its named-model-free bindings /selectedItems and /types become the bound T_SELECTEDITEMS and T_TYPES. Browse calls the plugin's fileSelectionHandler through control_by_id. The ComboBox selectionChange names .onDocumentTypeChange, which the controller does not define; the port wires it to recompute the Add button's enabled (the isAddButtonEnabled formatter: at least one file and every file typed), which the original re-evaluated through its parts binding. handleRemove reads the item and its reject callback from two core:CustomData elements (key item and key reject) on the decline Button; they are dropped - the backend removes the row by its binding path. handleConfirmation resolves each Promise after adding a documentType header field, which the mock server files the document under; the port adds the rows itself with the chosen document type. Cancel (closeFileUplaodFragment) discards the queued files." + }, + { + "type": "IMPROVISED", + "what": "onDownloadFiles calls the plugin's download( context, true ) for EVERY selected row; a UI5 event expression has no loop, so the port's Download button calls download for the first selected row only, through a view-wired control_by_id on the plugin whose argument is $controller.getView().byId('table-uploadSet').getSelectedContexts()[0]." + }, + { + "type": "NOTE", + "what": "Unverified in a running system: (a) the plugin calls by id (uploadSetPlugin, an id the original does not carry) through the unlisted-method path of control_by_id - openFilePreview with the Link's $event.oSource.getBindingContext(), renameItem and download with $controller.getView().byId('table-uploadSet').getSelectedContexts()[0] - each handing the live Context object through castArgAuto untouched; (b) selectionChange transporting $event.oSource.getSelectedContexts().join() (Context.toString is the binding path) and the itemRenamed wire reading ${$parameters>/item}.getBindingContext().getPath(); (c) the vetoed beforeUploadStarts and ${$parameters>/item}.getFileObject().size. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_656.mjs)." + }, + { + "type": "NOTE", + "what": "onSelectionChange's setEnabled calls become two bound flags: Download is enabled for one or more selected rows, Remove/Rename/Edit URL for exactly one. onSearch's Filter('fileName', Contains, query) is the view-wired binding_call filter on the table's items with ${$source>/value} - roundtrip-free, and like any binding filter it does not survive a view rebuild. onDocumentRenamedSuccess writes the new name into the row in the backend (the itemRenamed wire carries the row's path and the item's file name) and toasts 'Document Renamed.' with duration 2000. After a removal the port resets the selection AND the four buttons; the original's removeSelections( ) fires no selectionChange, so there the buttons stayed enabled on an empty selection." + }, + { + "type": "IMPROVISED", + "what": "The AddViaUrl fragment is the port's popup with its ids kept (addViaUrlDialog, addViaUrlSimpleform, urlInputLabel, urlInput, nameInputLabel, nameInput, addDocumentBtn), and what openAddOrEditDialog / _isValidName / _validateAddOrEditUrlDialog set through Element.getElementById is bound instead: the Dialog title (Add URL / Edit URL), the begin button text (Add / Apply), urlInputLabel.required, both Input values and their valueState / valueStateText. Cancel closes it with popup_close. Add validates name and URL in the backend (the unanchored URL regex reduced to its required part, a ftp/http/https scheme followed by a non-blank) and then adds the row directly - uploadItemViaUrl takes a JS Promise and the controller adds a documentUrl header field to the item, neither transportable, and the mock server's answer is exactly that row (the URL as typed, an empty media type and size 0). showEditConfirmation's controller-built sap.m.Dialog (type Message, state Warning, title Warning, Save / DiscardChanges) is a MessageBox.warning with the same title, text, actions and Save emphasized; Save updates the selected row's fileName and url and closes the fragment, DiscardChanges only closes the box. removeItem's MessageBox.warning keeps its text, actions Remove/CANCEL, emphasizedAction, styleClass and initialFocus; its explicit icon option is the warning box's own icon anyway." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_657.json b/meta/z2ui5_cl_smpc_app_657.json new file mode 100644 index 000000000..22366856e --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_657.json @@ -0,0 +1,59 @@ +{ + "class": "z2ui5_cl_smpc_app_657", + "sample": "sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableFilePreview", + "entity": "sap.m.plugins.UploadSetwithTable", + "file": "src/02/01/z2ui5_cl_smpc_app_657.clas.abap", + "batch": "b56", + "audit": { + "frontend_action": true, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.plugins.UploadSetwithTable control (since UI5 1.124) is newer than 1.71 and is the whole point of this sample - kept 1:1 in the table's dependents as plugins:UploadSetwithTable (the original's dotted plugins.UploadSetwithTable under the sap.m default namespace), with its rowConfiguration aggregation and its previewDialog association pointing at the FilePreviewDialog; the app needs a UI5 release >= 1.124. Every member it carries (uploadUrl, multiple, cloudFilePickerEnabled, the actions and previewDialog associations, beforeUploadStarts, itemRenamed) is as new as the plugin." + }, + { + "type": "POST_171", + "what": "the plugin's companion controls are kept 1:1 and are post-1.71 too: sap.m.upload.ActionsPlaceholder (@since 1.120, with placeholderFor - the toolbar slot the plugin renders its upload button into) and sap.m.upload.UploadItemConfiguration (@since 1.124; fileNamePath, mediaTypePath, urlPath, previewablePath and fileSizePath @1.124, isTrustedSourcePath @1.125), written upload:UploadItemConfiguration for the original's dotted upload.UploadItemConfiguration." + }, + { + "type": "POST_171", + "what": "sap.m.upload.FilePreviewDialog (@since 1.120) is the point of this variant and is kept 1:1 in the table's dependents with its id FilePreviewDialog, showCarouselArrows and maxFileSizeforPreview (both @1.120); the plugin's previewDialog association names it, so openFilePreview opens this dialog (with carousel arrows and the 50 MB preview limit) instead of a default instance." + }, + { + "type": "POST_171", + "what": "sap.m.Column importance (@since 1.76) on the File Name and action columns, and sap.m.Table autoPopinMode (@since 1.76) and hiddenInPopin (@since 1.77), are kept 1:1 from the original table." + }, + { + "type": "NOTE", + "what": "The named JSONModel documents (manifest dataSource model/documents.json) is folded into the default model: every {documents>x} binding is the row field {X} and the items path is the bound T_ITEMS, still as the original's {path, templateShareable: false} binding info. All nine rows are inlined; the url and imageUrl fields are host-absolutized to https://sdk.openui5.org/test-resources/... because an abap2UI5 app has no demo-kit root to resolve the relative test-resources paths against. The UploadItemConfiguration paths name the upper-case ABAP fields (FILENAME, MEDIATYPE, URL, PREVIEWABLE, FILESIZE, TRUSTEDSOURCE) instead of fileName/mediaType/... - the same model columns. IMAGEURL and UPLOADSTATE are bound with omit_initial_paths, so a row the mock gives no imageUrl/uploadState still reads undefined and the original's own Image/Icon visible expressions and highlight expression decide exactly as in the sample." + }, + { + "type": "NOTE", + "what": "The controller formatters getIconSrc (UploadSetwithTable.getIconForFileType - IconPool's media-type table, the file-extension fallback with sap-icon://card for images) and getFileSizeWithUnits (KB/MB/GB with two decimals) run in ABAP (icon_for, size_with_units) and the row carries the finished values in two port fields, ICON and FILESIZE_UNITS, which core:Icon.src and the File Size Text bind - the thin-frontend rule; the {parts: [...], formatter: ...} bindings are gone with them." + }, + { + "type": "IMPROVISED", + "what": "Upload: the sample starts a sinon fake XHR server (model/mockserver.js) in beforeUploadStarts, which answers the POST to /uploadFiles with 201 and unshifts the new document. There is no such endpoint behind an abap2UI5 app, so the port plays the mock server's part in the backend: beforeUploadStarts is a backend wire with check_prevent_default (the plugin's own veto - no XHR is sent) that transports the item's file name, media type and size, and the backend unshifts the row the mock server would have created (uploadState Complete, revision 00, In work, Jane Burns, Invoice, trustedSource) and shows the 'Document Added' toast at once rather than after the sample's one-second setTimeout. Lost with it: the uploaded file's blob: object URL (an uploaded row has an empty url, so it cannot be previewed or downloaded) and the random uid id (a running number); uploadCompleted and onActivated are not wired (no upload completes, and the plugin is addressed by an added id uploadSetPlugin instead of the instance onActivated handed the controller); URLListValidator.add('blob') is dropped. Several files picked at once fire beforeUploadStarts back to back and abap2UI5 runs one round-trip at a time: check_queue_last keeps the last one, so only the first and the last of them are added." + }, + { + "type": "IMPROVISED", + "what": "onDownloadFiles calls the plugin's download( context, true ) for EVERY selected row; a UI5 event expression has no loop, so the port's Download button calls download for the first selected row only, through a view-wired control_by_id on the plugin whose argument is $controller.getView().byId('table-uploadSet').getSelectedContexts()[0]." + }, + { + "type": "NOTE", + "what": "Unverified in a running system: (a) the plugin calls by id (uploadSetPlugin, an id the original does not carry) through the unlisted-method path of control_by_id - openFilePreview with the Link's $event.oSource.getBindingContext(), renameItem and download with $controller.getView().byId('table-uploadSet').getSelectedContexts()[0] - each handing the live Context object through castArgAuto untouched; (b) selectionChange transporting $event.oSource.getSelectedContexts().join() (Context.toString is the binding path) and the itemRenamed wire reading ${$parameters>/item}.getBindingContext().getPath(); (c) the vetoed beforeUploadStarts and ${$parameters>/item}.getFileObject().size. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_657.mjs)." + }, + { + "type": "NOTE", + "what": "onSelectionChange's setEnabled calls become two bound flags: Download is enabled for one or more selected rows, Remove/Rename/Edit URL for exactly one. onSearch's Filter('fileName', Contains, query) is the view-wired binding_call filter on the table's items with ${$source>/value} - roundtrip-free, and like any binding filter it does not survive a view rebuild. onDocumentRenamedSuccess writes the new name into the row in the backend (the itemRenamed wire carries the row's path and the item's file name) and toasts 'Document Renamed.' with duration 2000. After a removal the port resets the selection AND the four buttons; the original's removeSelections( ) fires no selectionChange, so there the buttons stayed enabled on an empty selection." + }, + { + "type": "IMPROVISED", + "what": "The AddViaUrl fragment is the port's popup with its ids kept (addViaUrlDialog, addViaUrlSimpleform, urlInputLabel, urlInput, nameInputLabel, nameInput, addDocumentBtn), and what openAddOrEditDialog / _isValidName / _validateAddOrEditUrlDialog set through Element.getElementById is bound instead: the Dialog title (Add URL / Edit URL), the begin button text (Add / Apply), urlInputLabel.required, both Input values and their valueState / valueStateText. Cancel closes it with popup_close. Add validates name and URL in the backend (the unanchored URL regex reduced to its required part, a ftp/http/https scheme followed by a non-blank) and then adds the row directly - uploadItemViaUrl takes a JS Promise and the controller adds a documentUrl header field to the item, neither transportable, and the mock server's answer is exactly that row (the URL as typed, an empty media type and size 0). showEditConfirmation's controller-built sap.m.Dialog (type Message, state Warning, title Warning, Save / DiscardChanges) is a MessageBox.warning with the same title, text, actions and Save emphasized; Save updates the selected row's fileName and url and closes the fragment, DiscardChanges only closes the box. removeItem's MessageBox.warning keeps its text, actions Remove/CANCEL, emphasizedAction, styleClass and initialFocus; its explicit icon option is the warning box's own icon anyway." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_658.json b/meta/z2ui5_cl_smpc_app_658.json new file mode 100644 index 000000000..6f5a46bad --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_658.json @@ -0,0 +1,55 @@ +{ + "class": "z2ui5_cl_smpc_app_658", + "sample": "sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableProgressIndicator", + "entity": "sap.m.plugins.UploadSetwithTable", + "file": "src/02/01/z2ui5_cl_smpc_app_658.clas.abap", + "batch": "b56", + "audit": { + "frontend_action": true, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.plugins.UploadSetwithTable control (since UI5 1.124) is newer than 1.71 and is the whole point of this sample - kept 1:1 in the table's dependents as plugins:UploadSetwithTable (the original's dotted plugins.UploadSetwithTable under the sap.m default namespace), with its rowConfiguration aggregation; the app needs a UI5 release >= 1.124. Every member it carries (uploadUrl, multiple, cloudFilePickerEnabled, the actions association, beforeUploadStarts, itemRenamed, uploadCompleted) is as new as the plugin." + }, + { + "type": "POST_171", + "what": "the plugin's companion controls are kept 1:1 and are post-1.71 too: sap.m.upload.ActionsPlaceholder (@since 1.120, with placeholderFor - the toolbar slot the plugin renders its upload button into) and sap.m.upload.UploadItemConfiguration (@since 1.124; fileNamePath, mediaTypePath, urlPath, previewablePath and fileSizePath @1.124, isTrustedSourcePath @1.125), written upload:UploadItemConfiguration for the original's dotted upload.UploadItemConfiguration." + }, + { + "type": "POST_171", + "what": "sap.m.Column importance (@since 1.76) on the File Name and action columns, and sap.m.Table autoPopinMode (@since 1.76) and hiddenInPopin (@since 1.77), are kept 1:1 from the original table, as is its growing='true'." + }, + { + "type": "NOTE", + "what": "The named JSONModel documents (manifest dataSource model/documents.json) is folded into the default model: every {documents>x} binding is the row field {X} and the items path is the bound T_ITEMS, still as the original's {path, templateShareable: false} binding info. All nine rows are inlined; the url and imageUrl fields are host-absolutized to https://sdk.openui5.org/test-resources/... because an abap2UI5 app has no demo-kit root to resolve the relative test-resources paths against. The UploadItemConfiguration paths name the upper-case ABAP fields (FILENAME, MEDIATYPE, URL, PREVIEWABLE, FILESIZE, TRUSTEDSOURCE) instead of fileName/mediaType/... - the same model columns. IMAGEURL and UPLOADSTATE are bound with omit_initial_paths, so a row the mock gives no imageUrl/uploadState still reads undefined and the original's own Image/Icon visible expressions and highlight expression decide exactly as in the sample." + }, + { + "type": "NOTE", + "what": "The controller formatters getIconSrc (UploadSetwithTable.getIconForFileType - IconPool's media-type table, the file-extension fallback with sap-icon://card for images) and getFileSizeWithUnits (KB/MB/GB with two decimals) run in ABAP (icon_for, size_with_units) and the row carries the finished values in two port fields, ICON and FILESIZE_UNITS, which core:Icon.src and the File Size Text bind - the thin-frontend rule; the {parts: [...], formatter: ...} bindings are gone with them." + }, + { + "type": "IMPROVISED", + "what": "Upload progress - the point of this variant - is not reproduced. The controller's onBeforeUploadStarts builds a ColumnListItem in JS (a Text with the file name, a VBox with a ProgressIndicator 'Uploading..' label, a stop Button wired to terminateUpload, four empty Controls and a decline Button), inserts it with oTable.insertItem and drives it from the item's uploadProgress / uploadTerminated events; none of these controls exist in the view and their handlers are JS closures over live UploadItem instances, so beforeUploadStarts is not wired at all and no progress row appears. The upload itself goes out as in the original (the sample switches its mock server OFF here, so the POST to /uploadFiles reaches whatever server hosts the app and does not answer 201). onUploadCompleted is a backend wire: it transports the item's file name, url, getFileSize( ) and the response status, and the backend unshifts the row the controller builds - id 'id' plus a running number where the controller appends new Date().getTime(), no media type because the controller stores it under fileType (which no binding reads), uploadState Complete - and shows 'Document Added' only for a status of 201, like the controller (without its one-second setTimeout). The progress rows' bookkeeping (aProgressItems) and URLListValidator.add('blob') are dropped. Several files picked at once complete back to back while abap2UI5 runs one round-trip at a time: check_queue_last keeps the last one, so only the first and the last of them are added. onActivated is not wired; the plugin is addressed by an added id uploadSetPlugin instead of the instance onActivated handed the controller." + }, + { + "type": "IMPROVISED", + "what": "onDownloadFiles calls the plugin's download( context, true ) for EVERY selected row; a UI5 event expression has no loop, so the port's Download button calls download for the first selected row only, through a view-wired control_by_id on the plugin whose argument is $controller.getView().byId('table-uploadSet').getSelectedContexts()[0]." + }, + { + "type": "NOTE", + "what": "Unverified in a running system: (a) the plugin calls by id (uploadSetPlugin, an id the original does not carry) through the unlisted-method path of control_by_id - openFilePreview with the Link's $event.oSource.getBindingContext(), renameItem and download with $controller.getView().byId('table-uploadSet').getSelectedContexts()[0] - each handing the live Context object through castArgAuto untouched; (b) selectionChange transporting $event.oSource.getSelectedContexts().join() (Context.toString is the binding path) and the itemRenamed wire reading ${$parameters>/item}.getBindingContext().getPath(); (c) the uploadCompleted wire with ${$parameters>/item}.getFileSize() and ${$parameters>/status}. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_658.mjs)." + }, + { + "type": "NOTE", + "what": "onSelectionChange's setEnabled calls become two bound flags: Download is enabled for one or more selected rows, Remove/Rename/Edit URL for exactly one. onSearch's Filter('fileName', Contains, query) is the view-wired binding_call filter on the table's items with ${$source>/value} - roundtrip-free, and like any binding filter it does not survive a view rebuild. onDocumentRenamedSuccess writes the new name into the row in the backend (the itemRenamed wire carries the row's path and the item's file name) and toasts 'Document Renamed.' with duration 2000. After a removal the port resets the selection AND the four buttons; the original's removeSelections( ) fires no selectionChange, so there the buttons stayed enabled on an empty selection." + }, + { + "type": "IMPROVISED", + "what": "The AddViaUrl fragment is the port's popup with its ids kept (addViaUrlDialog, addViaUrlSimpleform, urlInputLabel, urlInput, nameInputLabel, nameInput, addDocumentBtn), and what openAddOrEditDialog / _isValidName / _validateAddOrEditUrlDialog set through Element.getElementById is bound instead: the Dialog title (Add URL / Edit URL), the begin button text (Add / Apply), urlInputLabel.required, both Input values and their valueState / valueStateText. Cancel closes it with popup_close. Add validates name and URL in the backend (the unanchored URL regex reduced to its required part, a ftp/http/https scheme followed by a non-blank) and then adds the row directly - uploadItemViaUrl takes a JS Promise and the controller adds a documentUrl header field to the item, neither transportable; with the mock server off, the empty file's upload completes without a 201, so onUploadCompleted adds the row (the URL as typed, size 0) and shows no toast, which is what the port does. showEditConfirmation's controller-built sap.m.Dialog (type Message, state Warning, title Warning, Save / DiscardChanges) is a MessageBox.warning with the same title, text, actions and Save emphasized; Save updates the selected row's fileName and url and closes the fragment, DiscardChanges only closes the box. removeItem's MessageBox.warning keeps its text, actions Remove/CANCEL, emphasizedAction, styleClass and initialFocus; its explicit icon option is the warning box's own icon anyway." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_659.json b/meta/z2ui5_cl_smpc_app_659.json new file mode 100644 index 000000000..76a2af4b5 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_659.json @@ -0,0 +1,55 @@ +{ + "class": "z2ui5_cl_smpc_app_659", + "sample": "sap.m.sample.UploadSetwithTablePlugin.ResponsiveTableSimple", + "entity": "sap.m.plugins.UploadSetwithTable", + "file": "src/02/01/z2ui5_cl_smpc_app_659.clas.abap", + "batch": "b56", + "audit": { + "frontend_action": true, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.plugins.UploadSetwithTable control (since UI5 1.124) is newer than 1.71 and is the whole point of this sample - kept 1:1 in the table's dependents as plugins:UploadSetwithTable (the original's dotted plugins.UploadSetwithTable under the sap.m default namespace), with its rowConfiguration aggregation; the app needs a UI5 release >= 1.124. Every member it carries (uploadUrl, multiple, cloudFilePickerEnabled, the actions association, beforeUploadStarts, itemRenamed and itemRenameCanceled - the last one @since 1.142) is as new as the plugin or newer, so the app needs UI5 >= 1.142 for the rename-cancel toast." + }, + { + "type": "POST_171", + "what": "the plugin's companion controls are kept 1:1 and are post-1.71 too: sap.m.upload.ActionsPlaceholder (@since 1.120, with placeholderFor - the toolbar slot the plugin renders its upload button into) and sap.m.upload.UploadItemConfiguration (@since 1.124; fileNamePath, mediaTypePath, urlPath, previewablePath and fileSizePath @1.124, isTrustedSourcePath @1.125), written upload:UploadItemConfiguration for the original's dotted upload.UploadItemConfiguration." + }, + { + "type": "POST_171", + "what": "sap.m.Column importance (@since 1.76) on the File Name and action columns, and sap.m.Table autoPopinMode (@since 1.76) and hiddenInPopin (@since 1.77), are kept 1:1 from the original table." + }, + { + "type": "NOTE", + "what": "The named JSONModel documents (manifest dataSource model/documents.json) is folded into the default model: every {documents>x} binding is the row field {X} and the items path is the bound T_ITEMS, still as the original's {path, templateShareable: false} binding info. All nine rows are inlined; the url and imageUrl fields are host-absolutized to https://sdk.openui5.org/test-resources/... because an abap2UI5 app has no demo-kit root to resolve the relative test-resources paths against. The UploadItemConfiguration paths name the upper-case ABAP fields (FILENAME, MEDIATYPE, URL, PREVIEWABLE, FILESIZE, TRUSTEDSOURCE) instead of fileName/mediaType/... - the same model columns. IMAGEURL and UPLOADSTATE are bound with omit_initial_paths, so a row the mock gives no imageUrl/uploadState still reads undefined and the original's own Image/Icon visible expressions and highlight expression decide exactly as in the sample." + }, + { + "type": "NOTE", + "what": "The controller formatters getIconSrc (UploadSetwithTable.getIconForFileType - IconPool's media-type table, the file-extension fallback with sap-icon://card for images) and getFileSizeWithUnits (KB/MB/GB with two decimals) run in ABAP (icon_for, size_with_units) and the row carries the finished values in two port fields, ICON and FILESIZE_UNITS, which core:Icon.src and the File Size Text bind - the thin-frontend rule; the {parts: [...], formatter: ...} bindings are gone with them." + }, + { + "type": "IMPROVISED", + "what": "Upload: the sample starts a sinon fake XHR server (model/mockserver.js) in beforeUploadStarts, which answers the POST to /uploadFiles with 201 and unshifts the new document. There is no such endpoint behind an abap2UI5 app, so the port plays the mock server's part in the backend: beforeUploadStarts is a backend wire with check_prevent_default (the plugin's own veto - no XHR is sent) that transports the item's file name, media type and size, and the backend unshifts the row the mock server would have created (uploadState Complete, revision 00, In work, Jane Burns, Invoice, trustedSource) and shows the 'Document Added' toast at once rather than after the sample's one-second setTimeout. Lost with it: the uploaded file's blob: object URL (an uploaded row has an empty url, so it cannot be previewed or downloaded) and the random uid id (a running number); uploadCompleted and onActivated are not wired (no upload completes, and the plugin is addressed by an added id uploadSetPlugin instead of the instance onActivated handed the controller); URLListValidator.add('blob') is dropped. Several files picked at once fire beforeUploadStarts back to back and abap2UI5 runs one round-trip at a time: check_queue_last keeps the last one, so only the first and the last of them are added." + }, + { + "type": "IMPROVISED", + "what": "onDownloadFiles calls the plugin's download( context, true ) for EVERY selected row; a UI5 event expression has no loop, so the port's Download button calls download for the first selected row only, through a view-wired control_by_id on the plugin whose argument is $controller.getView().byId('table-uploadSet').getSelectedContexts()[0]." + }, + { + "type": "NOTE", + "what": "Unverified in a running system: (a) the plugin calls by id (uploadSetPlugin, an id the original does not carry) through the unlisted-method path of control_by_id - openFilePreview with the Link's $event.oSource.getBindingContext(), renameItem and download with $controller.getView().byId('table-uploadSet').getSelectedContexts()[0] - each handing the live Context object through castArgAuto untouched; (b) selectionChange transporting $event.oSource.getSelectedContexts().join() (Context.toString is the binding path) and the itemRenamed wire reading ${$parameters>/item}.getBindingContext().getPath(); (c) the vetoed beforeUploadStarts and ${$parameters>/item}.getFileObject().size. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_659.mjs)." + }, + { + "type": "NOTE", + "what": "onSelectionChange's setEnabled calls become two bound flags: Download is enabled for one or more selected rows, Remove/Rename/Edit URL for exactly one. onSearch's Filter('fileName', Contains, query) is the view-wired binding_call filter on the table's items with ${$source>/value} - roundtrip-free, and like any binding filter it does not survive a view rebuild. onDocumentRenamedSuccess writes the new name into the row in the backend (the itemRenamed wire carries the row's path and the item's file name) and toasts 'Document Renamed.' with duration 2000; itemRenameCanceled toasts 'Document Rename Cancelled.'. After a removal the port resets the selection AND the four buttons; the original's removeSelections( ) fires no selectionChange, so there the buttons stayed enabled on an empty selection." + }, + { + "type": "IMPROVISED", + "what": "The AddViaUrl fragment is the port's popup with its ids kept (addViaUrlDialog, addViaUrlSimpleform, urlInputLabel, urlInput, nameInputLabel, nameInput, addDocumentBtn), and what openAddOrEditDialog / _isValidName / _validateAddOrEditUrlDialog set through Element.getElementById is bound instead: the Dialog title (Add URL / Edit URL), the begin button text (Add / Apply), urlInputLabel.required, both Input values and their valueState / valueStateText. Cancel closes it with popup_close. Add validates name and URL in the backend (the unanchored URL regex reduced to its required part, a ftp/http/https scheme followed by a non-blank) and then adds the row directly - uploadItemViaUrl takes a JS Promise and the controller adds a documentUrl header field to the item, neither transportable, and the mock server's answer is exactly that row (the URL as typed, an empty media type and size 0). showEditConfirmation's controller-built sap.m.Dialog (type Message, state Warning, title Warning, Save / DiscardChanges) is a MessageBox.warning with the same title, text, actions and Save emphasized; Save updates the selected row's fileName and url and closes the fragment, DiscardChanges only closes the box. removeItem's MessageBox.warning keeps its text, actions Remove/CANCEL, emphasizedAction, styleClass and initialFocus; its explicit icon option is the warning box's own icon anyway." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_660.json b/meta/z2ui5_cl_smpc_app_660.json new file mode 100644 index 000000000..602f7e7d3 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_660.json @@ -0,0 +1,51 @@ +{ + "class": "z2ui5_cl_smpc_app_660", + "sample": "sap.m.sample.UploadSetwithTablePlugin.TreeTableSimple", + "entity": "sap.m.plugins.UploadSetwithTable", + "file": "src/02/01/z2ui5_cl_smpc_app_660.clas.abap", + "batch": "b56", + "audit": { + "frontend_action": true, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.plugins.UploadSetwithTable control (since UI5 1.124) is newer than 1.71 and is the whole point of this sample - kept 1:1 in the sap.ui.table.TreeTable's dependents as plugins:UploadSetwithTable (the original's dotted m:plugins.UploadSetwithTable), with the UploadItemConfiguration as its default rowConfiguration aggregation; the app needs a UI5 release >= 1.124. Every member it carries (uploadUrl, multiple, cloudFilePickerEnabled, the actions association, beforeUploadStarts, itemRenamed) is as new as the plugin." + }, + { + "type": "POST_171", + "what": "the plugin's companion controls are kept 1:1 and are post-1.71 too: sap.m.upload.ActionsPlaceholder (@since 1.120, with placeholderFor - the toolbar slot the plugin renders its upload button into) and sap.m.upload.UploadItemConfiguration (@since 1.124; fileNamePath, mediaTypePath, urlPath, previewablePath and fileSizePath @1.124, isTrustedSourcePath @1.125 and isDirectoryPath @1.139 - the app needs UI5 >= 1.139), written upload:UploadItemConfiguration for the original's dotted m:upload.UploadItemConfiguration." + }, + { + "type": "NOTE", + "what": "The named JSONModel documents (manifest dataSource model/documents.json) is folded into the default model: every {documents>x} binding is the row field {X} and the TreeTable's rows are the bound T_ITEMS - documents.json is a folder tree three levels deep, so T_ITEMS has one row type per level (every level carrying every field, the upper two their ITEMS; an empty ITEMS array is a leaf to the JSON tree binding, like the original's absent property). All nine nodes (three folders, six files) are inlined; the revision and id columns of the original are commented out of its view, so revision is not carried (id is - the Edit URL lookup uses it); the url and imageUrl fields are host-absolutized to https://sdk.openui5.org/test-resources/... because an abap2UI5 app has no demo-kit root to resolve the relative test-resources paths against. The UploadItemConfiguration paths name the upper-case ABAP fields (FILENAME, MEDIATYPE, URL, PREVIEWABLE, FILESIZE, TRUSTEDSOURCE) instead of fileName/mediaType/... - the same model columns. IMAGEURL and UPLOADSTATE are bound with omit_initial_paths, so a row the mock gives no imageUrl/uploadState still reads undefined and the original's own Image/Icon visible expressions and the RowSettings highlight expression decide exactly as in the sample." + }, + { + "type": "NOTE", + "what": "The controller formatters getIconSrc (sap-icon://folder-full for a directory, else UploadSetwithTable.getIconForFileType - IconPool's media-type table, the file-extension fallback with sap-icon://card for images) and getFileSizeWithUnits (KB/MB/GB with two decimals; a folder has no fileSize, so its cell stays empty) run in ABAP (icon_for, size_with_units) and the row carries the finished values in two port fields, ICON and FILESIZE_UNITS, which core:Icon.src and the File Size Text bind - the thin-frontend rule; the {parts: [...], formatter: ...} bindings are gone with them." + }, + { + "type": "IMPROVISED", + "what": "Upload: the sample starts a sinon fake XHR server (model/mockserver.js) in beforeUploadStarts, which answers the POST to /uploadFiles with 201 and unshifts the new document. There is no such endpoint behind an abap2UI5 app, so the port plays the mock server's part in the backend: beforeUploadStarts is a backend wire with check_prevent_default (the plugin's own veto - no XHR is sent) that transports the item's file name, media type and size, and the backend unshifts the row the mock server would have created (uploadState Complete, revision 00, In work, Jane Burns, Invoice, trustedSource) and shows the 'Document Added' toast at once rather than after the sample's one-second setTimeout. Lost with it: the uploaded file's blob: object URL (an uploaded row has an empty url, so it cannot be previewed or downloaded) and the random uid id (a running number); uploadCompleted and onActivated are not wired (no upload completes, and the plugin is addressed by an added id uploadSetPlugin instead of the instance onActivated handed the controller); URLListValidator.add('blob') is dropped. Several files picked at once fire beforeUploadStarts back to back and abap2UI5 runs one round-trip at a time: check_queue_last keeps the last one, so only the first and the last of them are added." + }, + { + "type": "IMPROVISED", + "what": "onDownloadFiles maps the TreeTable's getSelectedIndices( ) to contexts and calls the plugin's download( context, true ) for EVERY selected row; a UI5 event expression has no loop, so the port's Download button calls download for the first selected row only, through a view-wired control_by_id on the plugin whose argument is $controller.getView().byId('table-uploadSet').getContextByIndex(...getSelectedIndices()[0])." + }, + { + "type": "NOTE", + "what": "Unverified in a running system: (a) the plugin calls by id (uploadSetPlugin, an id the original does not carry) through the unlisted-method path of control_by_id - openFilePreview with the template Link's $event.oSource.getBindingContext(), renameItem and download with $controller.getView().byId('table-uploadSet').getContextByIndex($controller.getView().byId('table-uploadSet').getSelectedIndices()[0]) - each handing the live Context object through castArgAuto untouched; (b) rowSelectionChange transporting $event.oSource.getBinding('rows').getSelectedContexts().join() (Context.toString is the binding path, e.g. /T_ITEMS/0/ITEMS/1) and the itemRenamed wire reading ${$parameters>/item}.getBindingContext().getPath(); (c) the vetoed beforeUploadStarts and ${$parameters>/item}.getFileObject().size. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_660.mjs)." + }, + { + "type": "NOTE", + "what": "onSelectionChange reads the rows binding's selected contexts and tells files from folders: Download is enabled for one or more selected files, Remove/Rename/Edit URL for exactly one file, and both stay disabled as soon as a folder is selected - two bound flags, decided in the backend from the selected rows' binding paths. onDocumentRenamedSuccess writes the new name into the renamed node at whatever depth it sits (the itemRenamed wire carries its path and the item's file name) and toasts 'Document Renamed.' with duration 2000. The controller's quirks are kept: removeItem splices index split('/')[2] of the row's path out of /items - for a file inside a folder that is its TOP-LEVEL folder, which is removed with everything in it - and its removeSelections( ) does not exist on sap.ui.table.TreeTable, so the selection stays; the Edit URL Save looks the selected row up by id in the top-level /items only, so for a file inside a folder the original's Object.assign throws and nothing is saved - the port saves nothing either, without the error." + }, + { + "type": "IMPROVISED", + "what": "The AddViaUrl fragment is the port's popup with its ids kept (addViaUrlDialog, addViaUrlSimpleform, urlInputLabel, urlInput, nameInputLabel, nameInput, addDocumentBtn), and what openAddOrEditDialog / _isValidName / _validateAddOrEditUrlDialog set through Element.getElementById is bound instead: the Dialog title (Add URL / Edit URL), the begin button text (Add / Apply), urlInputLabel.required, both Input values and their valueState / valueStateText. Cancel closes it with popup_close. Add validates name and URL in the backend (the unanchored URL regex reduced to its required part, a ftp/http/https scheme followed by a non-blank) and then adds the row directly - uploadItemViaUrl takes a JS Promise and the controller adds a documentUrl header field to the item, neither transportable, and the mock server's answer is exactly that row (the URL as typed, an empty media type and size 0). showEditConfirmation's controller-built sap.m.Dialog (type Message, state Warning, title Warning, Save / DiscardChanges) is a MessageBox.warning with the same title, text, actions and Save emphasized; Save updates the selected row's fileName and url and closes the fragment, DiscardChanges only closes the box. removeItem's MessageBox.warning keeps its text, actions Remove/CANCEL, emphasizedAction, styleClass and initialFocus; its explicit icon option is the warning box's own icon anyway." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_661.json b/meta/z2ui5_cl_smpc_app_661.json new file mode 100644 index 000000000..4eb478931 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_661.json @@ -0,0 +1,55 @@ +{ + "class": "z2ui5_cl_smpc_app_661", + "sample": "sap.m.sample.UploadSetwithTablePlugin.TreeTableWithFolderHierarchy", + "entity": "sap.m.plugins.UploadSetwithTable", + "file": "src/02/01/z2ui5_cl_smpc_app_661.clas.abap", + "batch": "b56", + "audit": { + "frontend_action": true, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.m.plugins.UploadSetwithTable control (since UI5 1.124) is newer than 1.71 and is the whole point of this sample - kept 1:1 in the sap.ui.table.TreeTable's dependents as plugins:UploadSetwithTable (the original's dotted m:plugins.UploadSetwithTable) with its own id uploadPlugin and the UploadItemConfiguration as its default rowConfiguration aggregation; the app needs a UI5 release >= 1.124. Every member it carries (uploadUrl, multiple, uploadEnabled, the actions association, beforeUploadStarts, itemRenamed) is as new as the plugin." + }, + { + "type": "POST_171", + "what": "the plugin's companion controls are kept 1:1 and are post-1.71 too: sap.m.upload.ActionsPlaceholder (@since 1.120, with placeholderFor - the toolbar slot the plugin renders its upload button into) and sap.m.upload.UploadItemConfiguration (@since 1.124; fileNamePath, mediaTypePath, urlPath, previewablePath and fileSizePath @1.124, isTrustedSourcePath @1.125 and isDirectoryPath @1.139 - the app needs UI5 >= 1.139), written upload:UploadItemConfiguration for the original's dotted m:upload.UploadItemConfiguration." + }, + { + "type": "NOTE", + "what": "The named JSONModel documents (loaded in onInit from model/documents.json) is folded into the default model, and the folder navigation moves from the frontend to the backend. The controller re-binds the TreeTable's rows to /items (bindTableItems) and keeps /history and the Breadcrumbs' currentLocationText in the model; the port keeps the whole tree flat in a PROTECTED table (every node with its parent's documentId - all 15 nodes of documents.json, the document URLs host-absolutized to https://sdk.openui5.org/test-resources/...) and binds the rows to T_ITEMS, which it rebuilds as the open folder's subtree (one row type per level, four levels - the depth of documents.json; a folder created deeper than four levels below the open folder exists but is not shown until one navigates closer), and binds the Breadcrumbs' links to T_HISTORY and currentLocationText to CURRENTLOCATIONTEXT. The rowConfiguration paths name the upper-case ABAP fields (FILENAME, MIMETYPE, URL, SIZE, ISDIRECTORY, PREVIEWABLE, TRUSTEDSOURCE) instead of fileName/mimeType/... - the same columns. The mock's type and thumbnailUrl keys are not carried: nothing binds them. IMAGEURL (no node has one) and UPLOADSTATE are bound with omit_initial_paths, so the original's undefined checks in the Image/Icon visible expressions and the RowSettings highlight decide as in the sample." + }, + { + "type": "NOTE", + "what": "The controller formatters getIconSrc (sap-icon://folder-full for a directory, else UploadSetwithTable.getIconForFileType - IconPool's media-type table, the file-extension fallback) and formatFileSize (getFileSizeWithUnits: KB/MB/GB with two decimals - a folder's size 0 reads 0.00 KB as in the original) run in ABAP and the node carries the finished values in two port fields, ICON and SIZE_UNITS, which core:Icon.src and the File Size Text bind - the thin-frontend rule; the {parts: [...], formatter: ...} bindings are gone with them." + }, + { + "type": "IMPROVISED", + "what": "Upload: the sample starts a sinon fake XHR server (model/mockserver.js, started with the open folder's path) in beforeUploadStarts, which answers the POST to ./uploadFiles with 201 and files the new document into the open folder in front of its first file. There is no such endpoint behind an abap2UI5 app, so the port plays the mock server's part in the backend: beforeUploadStarts is a backend wire with check_prevent_default (the plugin's own veto - no XHR is sent) that transports the item's file name, media type and size, and the backend inserts the document into the open folder behind its folders (uploadedBy Current User, uploadState Complete, trustedSource) and shows 'Upload completed successfully.' at once rather than after the controller's two-second setTimeout in uploadCompleted. Lost with it: the uploaded file's blob: object URL (an uploaded row has an empty url, so it cannot be previewed or downloaded), the random uid documentId (upload-), and the browser-locale uploadedDate (new Date().toLocaleDateString()) - the port writes the server date in the ISO form the mock's own dates use (the same for a folder created with Add Folder). uploadCompleted and onActivated are not wired (no upload completes, and the plugin is addressed by its own id uploadPlugin); URLListValidator.add('blob') is dropped. Several files picked at once fire beforeUploadStarts back to back and abap2UI5 runs one round-trip at a time: check_queue_last keeps the last one, so only the first and the last of them are added." + }, + { + "type": "NOTE", + "what": "TreeTable.toggleOpenState='.onToggleOpenState' is not wired: the controller's handler is empty (its comment says no action is needed), and a backend wire with nothing to do would only cost a round-trip per expand and collapse." + }, + { + "type": "NOTE", + "what": "The controller's handlers are ported 1:1 in the backend: onSelectionChange (the rows binding's selected contexts arrive as their paths - Download for files only, Rename for exactly one file or one folder, Remove All only while every item of the open folder is selected); onItemPress / navigateToFolder (a folder Link opens the folder: the rows, the history up to its parent and the current location text) and onBreadcrumbPress (a history Link, found by its binding path - the controller's indexOfLink - opens that level, Attachments the root; the -1 branch for the current location text cannot fire, the Breadcrumbs render it as text); onDownloadFiles (one click per selected file through the DOWNLOAD_B64_FILE frontend action - the same anchor trick the controller builds with document.createElement - and its toasts); onCreateFolder / onCreateFolderDialogPress / createFolderWithName (the CreateFolderDialog fragment as the popup with folderNameInput bound, the empty-name and duplicate-name toasts, the new folder unshifted into the one selected folder or the open one, with the controller's fields and toast texts); onRemoveItemHandler (MessageBox.confirm 'Delete File', and on OK the file is filtered out of the OPEN folder's items - for a file shown inside an expanded subfolder that deletes nothing while the toast still says it did, as in the original); onRemoveAllHandler / deleteAllSelectedItems (its checks, the 'Delete All Items' confirm and the count toast; a removed folder takes its content with it). After a navigation the port also clears the TreeTable's selection (clearSelection) and the three buttons - the controller's bindRows drops the selection too but leaves the buttons as they were. The Create dialog is destroyed on Create where the controller only closes it for reuse; it opens empty either way." + }, + { + "type": "IMPROVISED", + "what": "onRenameItem decides per selected row: a folder goes to renameFolderWithDialog, a sap.m.Dialog the controller builds in JS (title Rename Folder, an Input with the current name at width 100%, OK emphasized and Cancel) - the port builds that Dialog as its popup, so its Dialog, Input and the two Button controls are controls the original's views do not contain; OK renames the folder when the trimmed name is new and toasts 'Folder renamed successfully'. A file goes to the plugin's renameItem( context ), which only the browser can hand over, so the Rename button's press carries TWO handlers separated by ';' (UI5's EventHandlerResolver splits them): the backend RENAME event and a view-wired control_by_id renameItem on uploadPlugin whose argument is the first selected context of the rows binding - or null when that row is a folder, which renameItem ignores. onDocumentRenamedSuccess writes the new name into the node in the backend and toasts 'File renamed successfully' (duration 2000)." + }, + { + "type": "NOTE", + "what": "Unverified in a running system: (a) the two-handler press on the Rename button (.eB(...); .eF(...)) and its renameItem argument $controller.getView().byId('table-uploadSet').getBinding('rows').getSelectedContexts()[0] (null for a folder) through the unlisted-method path of control_by_id, and openFilePreview with the Link's $event.oSource.getBindingContext(); (b) rowSelectionChange transporting $event.oSource.getBinding('rows').getSelectedContexts().join() (Context.toString is the binding path) and the itemRenamed wire reading ${$parameters>/item}.getBindingContext().getPath(); (c) the vetoed beforeUploadStarts and ${$parameters>/item}.getFileObject().size; (d) DOWNLOAD_B64_FILE with an https test-resources URL and clearSelection after a navigation. **e2e-verified 2026-10-20** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_661.mjs)." + }, + { + "type": "NOTE", + "what": "The sample ships view/fragment/AddViaUrl.fragment.xml (a Dialog addViaUrlDialog with contentWidth and contentHeight under a core:FragmentDefinition carrying templateShareable and class, holding a form:SimpleForm addViaUrlSimpleform with two Label controls urlInputLabel and nameInputLabel - both required - two Input controls urlInput and nameInput, and the Button controls addDocumentBtn and Cancel), but nothing in this variant loads it: its view has no Add menu and its controller no openAddOrEditDialog. The port does not build the dead fragment, so structural_diff, which unions every archived fragment with the view, counts its controls, attributes and ids as missing." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_662.json b/meta/z2ui5_cl_smpc_app_662.json new file mode 100644 index 000000000..d2d80763c --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_662.json @@ -0,0 +1,52 @@ +{ + "class": "z2ui5_cl_smpc_app_662", + "sample": "sap.f.sample.AvatarGroup", + "entity": "sap.f.AvatarGroup", + "file": "src/02/04/z2ui5_cl_smpc_app_662.clas.abap", + "batch": "b49", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "the Slider's liveChange round-trips (check_queue_last + check_no_busy) and the backend sets the VerticalLayout width; both AvatarGroup presses round-trip and on_event builds the individual or the group popover (popover_display anchored at the pressed control's id); the group popover's NavContainer is driven by control_by_id to/back in the popover slot." + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "NOTE", + "what": "Three JSONModels are folded onto the one default model: the named items model (model/avatargroup.json, {items>/content} -> {/T_CONTENT}, totalCount kept as a non-bound attribute), the unnamed settings model ({/viewPortPercentWidth} -> {/VIEWPORTPERCENTWIDTH}, {/popoverTitle} -> {/POPOVERTITLE}), the personData model (a structure S_PERSON, bound absolutely as {/S_PERSON/...} since there is no element binding) and the groupedAvatars model (T_GROUPED, the Grid's bound content). Same data and leaf names, so a prefix-drop. The JSON's per-row tooltip key ('1'..'15') is bound nowhere and stays out of the row type." + }, + { + "type": "NOTE", + "what": "onSliderMoved reads the slider value and calls setWidth( value + '%' ) on the VerticalLayout vl1. The port binds VerticalLayout.width to VL_WIDTH and computes the string in on_event on a liveChange round-trip carrying check_queue_last and check_no_busy (the per-drag-step wire shape), so the backend ends on the slider's last value. VIEWPORTPERCENTWIDTH is seeded 100 and VL_WIDTH '100%' as in onInit / the view." + }, + { + "type": "NOTE", + "what": "onIndividualPress / onGroupPress / _getContent / _getAvatarModel are rebuilt in ABAP. The press event transports overflowButtonPressed, avatarsDisplayed, the eventSource id (the popover anchor) and the pressed item's row index (${$parameters>/eventSource}.getBindingContext().getPath().split('/').pop()); the Group-type AvatarGroup anchors at $event.oSource.sId as onGroupPress anchors at oEvent.getSource(). The popover rows are the avatars from avatarsDisplayed on (all for Group), the title 'Team Members ()' and the contentHeight formula ((n DIV 2 + n MOD 2) * 68 + 48 px) are computed in ABAP. The backgroundColor _getAvatarModel reads off AvatarGroupItem.getAvatarColor( ) is derived in ABAP from the rule AvatarGroup.addItem applies (Accent1..Accent10 by item position, round robin) instead of being read from the control - same value, no control call." + }, + { + "type": "IMPROVISED", + "what": "IndividualPopover.fragment.xml and GroupPopover.fragment.xml are built in on_event (popover_display) and Card.fragment.xml is inlined into both, as the original's two core:Fragment references load it twice - so the port carries the Card subtree twice (control extra Card, VerticalLayout, HBox, Avatar, VBox, Title, Text, Label controls) and drops both core:Fragment references. Each popover is rebuilt per press instead of being cached, which also makes oNavCon.to(oMainPage) on every open implicit (a fresh NavContainer starts on its first page). openBy( ).addStyleClass('sapFAvatarGroupPopover') becomes a class attribute on each Popover. onAvatarPress's setContentWidth('450px') is a no-op (the Popover already declares 450px) and its oGroupPopover.focus( ) is dropped; the NavContainer moves with control_by_id to( detail ) / back( ) in the popover slot, the contentHeight follows the bound POPOVER_HEIGHT (375px on the detail page, the computed height after navButtonPress)." + }, + { + "type": "NOTE", + "what": "GroupPopover.fragment.xml binds the grid Avatar's fallbackIcon to {personData>/fallbackIcon} - the individual personData model, not the row's groupedAvatars model - so every grid avatar shows the fallback icon of whichever person was last opened. Ported verbatim as the absolute {/S_PERSON/FALLBACKICON} binding rather than repaired. S_PERSON-BACKGROUNDCOLOR is seeded Accent6 (the sap.m.Avatar default): the empty personData model leaves the property undefined, while an empty string on the enum-typed backgroundColor would make UI5 reject the whole popover." + }, + { + "type": "NOTE", + "what": "The two avatar image src values are host-absolutized to https://sdk.openui5.org/test-resources/sap/f/images/Woman_avatar_01.png and Woman_avatar_02.png (the JSON's ./test-resources/... resolves against the Demo Kit). Row fields the JSON omits (initials, src, fallbackIcon) are left initial - all three are plain string/URI properties whose empty value renders like undefined." + }, + { + "type": "POST_171", + "what": "the sap.f.AvatarGroup and sap.f.AvatarGroupItem controls (since UI5 1.73) are newer than 1.71 and are the whole point of this sample - kept 1:1. The inlined card also uses sap.m.Avatar (@since 1.73, its press @since 1.73) and the Popover and Page titleAlignment property (@since 1.72), so the app needs a UI5 release >= 1.73." + } + ], + "render_smoke": { + "skip": true, + "reason": "sap.f.AvatarGroup itself loops in the static headless render harness: 'Rendering has been re-started too many times (21)' (its onAfterRendering resize handling re-invalidates the group). Reproduced 2026-10-20 with a minimal view outside this port - an l:VerticalLayout holding one AvatarGroup with three static AvatarGroupItem initials, no binding, no event - which fails the same way, and with each of this port's two AvatarGroups removed in turn; the docs/history.md 2026-07-24 entries record the same headless AvatarGroup render-restart loop. A harness boundary, not the port: the view reconstructs and the property and structure gates run in full. Verified against the render each run - the skip is honoured only while it still errors." + }, + "e2e_smoke": { + "theme": true, + "reason": "sap.f.AvatarGroup sizes itself from its own CSS: unthemed it measures unstyled avatars, re-renders with fewer and loops (\"Rendering has been re-started too many times\"). Booted with the theme CSS it renders once and passes - verified 2026-10-20." + } +} diff --git a/meta/z2ui5_cl_smpc_app_663.json b/meta/z2ui5_cl_smpc_app_663.json new file mode 100644 index 000000000..946bc51e0 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_663.json @@ -0,0 +1,31 @@ +{ + "class": "z2ui5_cl_smpc_app_663", + "sample": "sap.f.sample.SidePanel", + "entity": "sap.f.SidePanel", + "file": "src/02/04/z2ui5_cl_smpc_app_663.clas.abap", + "batch": "b49", + "audit": { + "frontend_action": false, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "NOTE", + "what": "onToggle vetoes the firing when the Switch for its direction is on (event.preventDefault) and resets that Switch with a toast. Reproduced 1:1 with the app-136 idiom: s_ctrl-prevent_default_expr (!${$parameters>/expanded} && {/PREVENT_COLLAPSE}) || (${$parameters>/expanded} && {/PREVENT_EXPAND}) is evaluated when the event fires against the two two-way bound Switch states, the event still reaches the backend, and on_event raises the matching toast and resets that Switch through the automatic model push - no view_display( ), since the expanded item lives in the control. Unlike app 136's single-item panel, selecting a different item fires TWO toggle events back to back (collapse of the old item, then expand of the new one), so the wire also sets check_queue_last: without it the second firing would be dropped while the first round-trip is in flight and a vetoed expand would never get its toast and Switch reset." + }, + { + "type": "IMPROVISED", + "what": "onToggle's third branch destroys the content of the expanding item whose AUTO-GENERATED id ends in 2 and adds a controller-built VBox (a Text 'Dynamically added content', then Label 'Label 1'..'Label 3' each followed by an Input). abap2UI5 builds no controls on the client, so the port declares that VBox, Text, Label and Input content statically inside the third SidePanelItem ('Go to office', the one item the original ships empty). Content of a SidePanelItem is only visible while the item is expanded, by which time the original has added it, so the screen shows the same thing; two things differ. (1) The original recreates the Inputs on every expansion, so typed values are wiped on re-expand - the port's Inputs keep them. (2) The original picks the item by parsing the digits of its auto id (parseInt(oItem.getId().replace(/^\\D+/g, ''))), which counts every control created with the uid token 'item' before it - the SidePanel's two core:ListItem controls of the Select take __item0 and __item1 in a standalone run, so the counter actually lands on 'Run' there, and inside the Demo Kit app (a global counter shared with the shell's own list items) it hardly ever equals 2 at all. The port follows the evident intent, the item at index 2 of the items aggregation, and needs no toggle logic for it." + }, + { + "type": "NOTE", + "what": "The Select edits the named settings model ({settings>/sidePanelPosition}, seeded in onInit from the panel's own getSidePanelPosition( ) default Right) and its change handler onChangePosition calls setSidePanelPosition with the selected key. The port folds the model onto the default model ({/SIDEPANELPOSITION}, seeded Right from the control default) and binds SidePanel.sidePanelPosition two-way to the same field, so the client-side model update moves the panel without a round-trip - the Select's change attribute is dropped because the binding does its job." + }, + { + "type": "POST_171", + "what": "the SidePanel and SidePanelItem controls (both since UI5 1.107) are newer than 1.71 and are the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.146: the Run item uses the SidePanelItem title aggregation (a sap.m.Title, @since 1.146), and the SidePanelPosition enum the sidePanelPosition property takes is @since 1.104." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_664.json b/meta/z2ui5_cl_smpc_app_664.json new file mode 100644 index 000000000..ae02f374e --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_664.json @@ -0,0 +1,27 @@ +{ + "class": "z2ui5_cl_smpc_app_664", + "sample": "sap.f.sample.SidePanelOverflow", + "entity": "sap.f.SidePanel", + "file": "src/02/04/z2ui5_cl_smpc_app_664.clas.abap", + "batch": "b49", + "audit": { + "frontend_action": false, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "NOTE", + "what": "onToggle vetoes the firing when the Switch for its direction is on (event.preventDefault) and resets that Switch with a toast. Reproduced 1:1 with the app-136 idiom: s_ctrl-prevent_default_expr (!${$parameters>/expanded} && {/PREVENT_COLLAPSE}) || (${$parameters>/expanded} && {/PREVENT_EXPAND}) is evaluated when the event fires against the two two-way bound Switch states, the event still reaches the backend, and on_event raises the matching toast and resets that Switch through the automatic model push - no view_display( ), since the expanded item lives in the control. Unlike app 136's single-item panel, selecting a different item fires TWO toggle events back to back (collapse of the old item, then expand of the new one), so the wire also sets check_queue_last: without it the second firing would be dropped while the first round-trip is in flight and a vetoed expand would never get its toast and Switch reset." + }, + { + "type": "IMPROVISED", + "what": "onToggle's third branch replaces the content of an expanding item whose AUTO-GENERATED id ends in a number above 1 (parseInt(oItem.getId().replace(/^\\D+/g, ''))) with a controller-built Text \"Dynamically created content for item ''\". abap2UI5 builds no controls on the client, so the port declares that Text statically inside every ENABLED SidePanelItem past the second (13 Text controls; the three disabled items 'Go to office', 'Go to the theater' and 'Draw a picture' can never expand and get none). Item content is only visible while the item is expanded, by which time the original has added it, so the screen shows the same text. The auto-id rule is followed by its evident intent, the item index in the aggregation: in a standalone run 'Run' and 'Go home' are __item0/__item1 and keep their static content, while inside the Demo Kit app the id counter is shared with the shell's own list items and even those two get replaced - the port does not reproduce that accident." + }, + { + "type": "POST_171", + "what": "the SidePanel and SidePanelItem controls (both since UI5 1.107) are newer than 1.71 and are the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.107." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_665.json b/meta/z2ui5_cl_smpc_app_665.json new file mode 100644 index 000000000..a508d361c --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_665.json @@ -0,0 +1,27 @@ +{ + "class": "z2ui5_cl_smpc_app_665", + "sample": "sap.f.sample.SidePanelResizable", + "entity": "sap.f.SidePanel", + "file": "src/02/04/z2ui5_cl_smpc_app_665.clas.abap", + "batch": "b49", + "audit": { + "frontend_action": false, + "event_t_arg": true + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "NOTE", + "what": "onToggle vetoes the firing when the Switch for its direction is on (event.preventDefault) and resets that Switch with a toast. Reproduced 1:1 with the app-136 idiom: s_ctrl-prevent_default_expr (!${$parameters>/expanded} && {/PREVENT_COLLAPSE}) || (${$parameters>/expanded} && {/PREVENT_EXPAND}) is evaluated when the event fires against the two two-way bound Switch states, the event still reaches the backend, and on_event raises the matching toast and resets that Switch through the automatic model push - no view_display( ), since the expanded item lives in the control. Unlike app 136's single-item panel, selecting a different item fires TWO toggle events back to back (collapse of the old item, then expand of the new one), so the wire also sets check_queue_last: without it the second firing would be dropped while the first round-trip is in flight and a vetoed expand would never get its toast and Switch reset." + }, + { + "type": "IMPROVISED", + "what": "onToggle's third branch destroys the content of the expanding item whose AUTO-GENERATED id ends in 2 and adds a controller-built VBox (a Text 'Dynamically added content', then Label 'Label 1'..'Label 3' each followed by an Input). abap2UI5 builds no controls on the client, so the port declares that VBox, Text, Label and Input content statically inside the third SidePanelItem ('Go to office', the one item the original ships empty). Content of a SidePanelItem is only visible while the item is expanded, by which time the original has added it, so the screen shows the same thing; two things differ. (1) The original recreates the Inputs on every expansion, so typed values are wiped on re-expand - the port's Inputs keep them. (2) The original picks the item by parsing the digits of its auto id (parseInt(oItem.getId().replace(/^\\D+/g, ''))), which counts every control created with the uid token 'item' before it - in a standalone run that is 'Go to office' (__item2), inside the Demo Kit app the counter is shared with the shell's own list items and hardly ever equals 2. The port follows the evident intent, the item at index 2 of the items aggregation, and needs no toggle logic for it." + }, + { + "type": "POST_171", + "what": "the SidePanel and SidePanelItem controls (both since UI5 1.107) are newer than 1.71 and are the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.109: sidePanelResizable is @since 1.109 (SidePanel.js), kept as the sample's subject." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_666.json b/meta/z2ui5_cl_smpc_app_666.json new file mode 100644 index 000000000..a14c3e3b7 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_666.json @@ -0,0 +1,32 @@ +{ + "class": "z2ui5_cl_smpc_app_666", + "sample": "sap.f.sample.ProductSwitchItemWithImageSrc", + "entity": "sap.f.ProductSwitch", + "file": "src/02/04/z2ui5_cl_smpc_app_666.clas.abap", + "batch": "b49", + "audit": { + "frontend_action": true, + "event_t_arg": true, + "note": "the trigger press round-trips and on_event builds the fragment's ResponsivePopover with the f:ProductSwitch, anchored by id via popover_display (the app-165 shape); fnChange toasts and redirects off ${$parameters>/itemPressed}.getTargetSrc() through two chained client actions; the phone-only Close endButton closes with popover_close." + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "NOTE", + "what": "The view is the trigger Button plus two explanatory Texts; the ProductSwitch lives in ProductSwitchItemWithImageSrc.fragment.xml, which onInit loads once and fnOpen opens at pSwitchBtn (openBy). The port rebuilds the fragment as a core:FragmentDefinition in on_event and shows it with popover_display( by_id = pSwitchBtn ) - the documented fragment-popover path of app 165. The three ProductSwitchItem controls stay static 1:1 (the original binds no model). fnChange - MessageToast 'Redirecting to ' plus URLHelper.redirect( targetSrc, true ) - is two client actions chained on the one change event, both reading the pressed item off the event (${$parameters>/itemPressed}.getTargetSrc())." + }, + { + "type": "NOTE", + "what": "onInit gives the popover an Emphasized 'Close' endButton on a phone only (Device.system.phone), wired to fnClose. The branch stays a branch, as in app 165: the Button is declared once with visible bound to {= ${device>/system/phone} } and closes with the roundtrip-free popover_close action - so the port carries 2 Button controls where the original view declares 1, the second being the controller-built one." + }, + { + "type": "NOTE", + "what": "The imageSrc assets are host-absolutized to https://sdk.openui5.org/ (test-resources/sap/ui/documentation/sdk/images/HT-1002.jpg and test-resources/sap/m/images/Woman_avatar_01.png, which the original resolves relative to the Demo Kit); the SVG item keeps the original's absolute www.sap.com logo URL verbatim." + }, + { + "type": "POST_171", + "what": "the sap.f.ProductSwitch and sap.f.ProductSwitchItem controls (since UI5 1.72) are newer than 1.71 and are the whole point of this sample - kept 1:1. The sample's subject, ProductSwitchItem.imageSrc, is @since 1.140 (ProductSwitchItem.js), so the app needs a UI5 release >= 1.140." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_667.json b/meta/z2ui5_cl_smpc_app_667.json new file mode 100644 index 000000000..c7e7e77e8 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_667.json @@ -0,0 +1,19 @@ +{ + "class": "z2ui5_cl_smpc_app_667", + "sample": "sap.f.sample.HeroBannerBasic", + "entity": "sap.f.HeroBanner", + "file": "src/02/04/z2ui5_cl_smpc_app_667.clas.abap", + "batch": "b50", + "audit": { + "frontend_action": false, + "event_t_arg": false + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.f.HeroBanner control is newer than 1.71 (sap/f/HeroBanner.js: @ui5-experimental-since 1.152 - an EXPERIMENTAL wrapper around the UI5 Web Components fiori HeroBanner, extending sap.ui.core.webc.WebComponent) and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.152." + } + ] +} diff --git a/meta/z2ui5_cl_smpc_app_668.json b/meta/z2ui5_cl_smpc_app_668.json new file mode 100644 index 000000000..91ae1ffb7 --- /dev/null +++ b/meta/z2ui5_cl_smpc_app_668.json @@ -0,0 +1,23 @@ +{ + "class": "z2ui5_cl_smpc_app_668", + "sample": "sap.f.sample.HeroBannerColumnsRatio", + "entity": "sap.f.HeroBanner", + "file": "src/02/04/z2ui5_cl_smpc_app_668.clas.abap", + "batch": "b50", + "audit": { + "frontend_action": false, + "event_t_arg": false + }, + "status": "generated", + "checked": null, + "deviations": [ + { + "type": "POST_171", + "what": "the sap.f.HeroBanner control is newer than 1.71 (sap/f/HeroBanner.js: @ui5-experimental-since 1.152 - an EXPERIMENTAL wrapper around the UI5 Web Components fiori HeroBanner, extending sap.ui.core.webc.WebComponent) and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.152. HeroBanner members used: the actions, startContent and endContent aggregations and the columnsRatio property with its sap.f.HeroBannerColumnsRatio values Equal and FirstWider - all @ui5-experimental-since 1.152 with the control." + }, + { + "type": "NOTE", + "what": "The sample's main.css (one rule, .heroBannerWhiteText { color: var(--sapTextInvertedColor) }, the class the startContent Text carries) is shipped with the port: it is injected through a core:HTML control carrying a ` + + )->tag( `Title` + )->a( n = `text` v = `No columnsRatio (single column)` + )->a( n = `level` v = `H4` + )->a( n = `class` v = `sapUiSmallMarginBottom sapUiSmallMarginTop sapUiSmallMarginBegin` + + )->ele( `VBox` + )->a( n = `class` v = `sapUiMediumMarginBeginEnd` + + )->ele( n = `HeroBanner` ns = `f` + )->a( n = `headerText` v = `Welcome back, Sarah` + )->a( n = `overlineText` v = `Monday, May 26, 2026` + + )->ele( n = `actions` ns = `f` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://receipt` + )->a( n = `text` v = `Approve Invoices` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://shipping-status` + )->a( n = `text` v = `Track Deliveries` + + )->end( + )->ele( n = `startContent` ns = `f` + )->tag( `Text` + )->a( n = `class` v = `heroBannerWhiteText` + )->a( n = `text` v = `Here you can insert any additional information that may be relevant to the context. ` && + `This section serves as a placeholder for content that can provide more in-depth ` && + `explanations, supplementary data, or any other pertinent details that the reader might need.` + + )->end( + )->end( + )->end( + + )->tag( `Title` + )->a( n = `text` v = `columnsRatio="Equal" (equal width columns)` + )->a( n = `level` v = `H4` + )->a( n = `class` v = `sapUiSmallMarginBottom sapUiMediumMarginTop sapUiSmallMarginBegin` + + )->ele( `VBox` + )->a( n = `class` v = `sapUiMediumMarginBeginEnd` + + )->ele( n = `HeroBanner` ns = `f` + )->a( n = `headerText` v = `Hi, David` + )->a( n = `overlineText` v = `Monday, May 26, 2026` + )->a( n = `columnsRatio` v = `Equal` + + )->ele( n = `startContent` ns = `f` + )->ele( n = `Card` ns = `f` + )->ele( n = `header` ns = `f` + )->tag( n = `Header` ns = `card` + )->a( n = `title` v = `Leave Balance` + )->a( n = `subtitle` v = `Days remaining` + + )->end( + )->ele( n = `content` ns = `f` + )->ele( `VBox` + )->a( n = `class` v = `sapUiSmallMargin` + + )->tag( `Title` + )->a( n = `text` v = `18 of 30` + )->a( n = `level` v = `H3` + + )->end( + )->end( + )->end( + )->end( + )->ele( n = `endContent` ns = `f` + )->ele( n = `Card` ns = `f` + )->ele( n = `header` ns = `f` + )->tag( n = `Header` ns = `card` + )->a( n = `title` v = `Next Payroll` + )->a( n = `subtitle` v = `June 2026` + + )->end( + )->ele( n = `content` ns = `f` + )->ele( `VBox` + )->a( n = `class` v = `sapUiSmallMargin` + + )->tag( `Title` + )->a( n = `text` v = `Jun 30` + )->a( n = `level` v = `H3` + + )->end( + )->end( + )->end( + )->end( + )->end( + )->end( + + )->tag( `Title` + )->a( n = `text` v = `columnsRatio="FirstWider" (start column twice as wide)` + )->a( n = `level` v = `H4` + )->a( n = `class` v = `sapUiSmallMarginBottom sapUiMediumMarginTop sapUiSmallMarginBegin` + + )->ele( `VBox` + )->a( n = `class` v = `sapUiMediumMarginBeginEnd` + + )->ele( n = `HeroBanner` ns = `f` + )->a( n = `headerText` v = `Good Afternoon, Thomas` + )->a( n = `overlineText` v = `Monday, May 26, 2026` + )->a( n = `columnsRatio` v = `FirstWider` + + )->ele( n = `startContent` ns = `f` + )->ele( n = `Card` ns = `f` + )->ele( n = `header` ns = `f` + )->tag( n = `Header` ns = `card` + )->a( n = `title` v = `Sales Pipeline` + )->a( n = `subtitle` v = `Q2 2026` + + )->end( + )->ele( n = `content` ns = `f` + )->ele( `VBox` + )->a( n = `class` v = `sapUiSmallMargin` + + )->tag( `Title` + )->a( n = `text` v = `€4.2M` + )->a( n = `level` v = `H3` + + )->end( + )->end( + )->end( + )->end( + )->ele( n = `endContent` ns = `f` + )->ele( n = `Card` ns = `f` + )->ele( n = `header` ns = `f` + )->tag( n = `Header` ns = `card` + )->a( n = `title` v = `Overdue Tasks` + )->a( n = `subtitle` v = `Action needed` + + )->end( + )->ele( n = `content` ns = `f` + )->ele( `VBox` + )->a( n = `class` v = `sapUiSmallMargin` + + )->tag( `Title` + )->a( n = `text` v = `3` + )->a( n = `level` v = `H3` ). + + client->view_display( view->stringify( ) ). + + ENDMETHOD. + +ENDCLASS. diff --git a/src/02/04/z2ui5_cl_smpc_app_668.clas.xml b/src/02/04/z2ui5_cl_smpc_app_668.clas.xml new file mode 100644 index 000000000..7ab716fce --- /dev/null +++ b/src/02/04/z2ui5_cl_smpc_app_668.clas.xml @@ -0,0 +1,16 @@ + + + + + + Z2UI5_CL_SMPC_APP_668 + E + sap.f - HeroBannerColumnsRatio + 1 + X + X + X + + + + diff --git a/src/02/04/z2ui5_cl_smpc_app_669.clas.abap b/src/02/04/z2ui5_cl_smpc_app_669.clas.abap new file mode 100644 index 000000000..23da86036 --- /dev/null +++ b/src/02/04/z2ui5_cl_smpc_app_669.clas.abap @@ -0,0 +1,90 @@ +" @keywords herobanner hero banner sap.f herobannerheaderblockandactionsplacement vbox button card header title +" @summary Demonstrates actionsPlacement and headerBlockPlacement properties for controlling the position of the header and actions. +" @origin sap.f.sample.HeroBannerHeaderBlockAndActionsPlacement - https://sdk.openui5.org/entity/sap.f.HeroBanner/sample/sap.f.sample.HeroBannerHeaderBlockAndActionsPlacement (status: generated - machine-written, not yet reviewed) +CLASS z2ui5_cl_smpc_app_669 DEFINITION PUBLIC. + + PUBLIC SECTION. + INTERFACES z2ui5_if_app. + + PROTECTED SECTION. + DATA client TYPE REF TO z2ui5_if_client. + + METHODS view_display. + + PRIVATE SECTION. +ENDCLASS. + + +CLASS z2ui5_cl_smpc_app_669 IMPLEMENTATION. + + METHOD z2ui5_if_app~main. + + me->client = client. + IF client->check_on_navigated( ). + view_display( ). + ENDIF. + + ENDMETHOD. + + + METHOD view_display. + + DATA(view) = z2ui5_cl_ui5_view_builder=>factory( ). + + view->ele( n = `View` ns = `mvc` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` + )->a( n = `xmlns:f` v = `sap.f` + )->a( n = `xmlns:card` v = `sap.f.cards` + )->a( n = `height` v = `100%` + )->a( n = `displayBlock` v = `true` + + )->ele( `Page` + )->a( n = `showHeader` v = `false` + + )->ele( `content` + )->ele( `VBox` + )->a( n = `class` v = `sapUiMediumMarginBeginEnd sapUiMediumMarginTop` + + )->ele( n = `HeroBanner` ns = `f` + )->a( n = `headerText` v = `Good Morning, Anna` + )->a( n = `overlineText` v = `Monday, May 26, 2026` + )->a( n = `columnsRatio` v = `Equal` + )->a( n = `actionsPlacement` v = `BottomStart` + )->a( n = `headerBlockPlacement` v = `Bottom` + + )->ele( n = `actions` ns = `f` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://create` + )->a( n = `text` v = `New Request` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://document` + )->a( n = `text` v = `Create Report` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://email` + )->a( n = `text` v = `Send Message` + + )->end( + )->ele( n = `endContent` ns = `f` + )->ele( n = `Card` ns = `f` + )->a( n = `width` v = `100%` + + )->ele( n = `header` ns = `f` + )->tag( n = `Header` ns = `card` + )->a( n = `title` v = `Open Tickets` + )->a( n = `subtitle` v = `Support` + + )->end( + )->ele( n = `content` ns = `f` + )->ele( `VBox` + )->a( n = `class` v = `sapUiSmallMargin` + + )->tag( `Title` + )->a( n = `text` v = `42` + )->a( n = `level` v = `H3` ). + + client->view_display( view->stringify( ) ). + + ENDMETHOD. + +ENDCLASS. diff --git a/src/02/04/z2ui5_cl_smpc_app_669.clas.xml b/src/02/04/z2ui5_cl_smpc_app_669.clas.xml new file mode 100644 index 000000000..8ab0c06ad --- /dev/null +++ b/src/02/04/z2ui5_cl_smpc_app_669.clas.xml @@ -0,0 +1,16 @@ + + + + + + Z2UI5_CL_SMPC_APP_669 + E + sap.f - HeroBannerHeaderBlockAndActionsPlacement + 1 + X + X + X + + + + diff --git a/src/02/04/z2ui5_cl_smpc_app_670.clas.abap b/src/02/04/z2ui5_cl_smpc_app_670.clas.abap new file mode 100644 index 000000000..1ebd7a60f --- /dev/null +++ b/src/02/04/z2ui5_cl_smpc_app_670.clas.abap @@ -0,0 +1,78 @@ +" @keywords herobanner hero banner sap.f herobannerintegrationcard vbox button card +" @summary Demonstrates the use of sap.ui.integration.widgets.Card inside both the startContent (default slot) and endContent aggregations of the Hero Banner. +" @origin sap.f.sample.HeroBannerIntegrationCard - https://sdk.openui5.org/entity/sap.f.HeroBanner/sample/sap.f.sample.HeroBannerIntegrationCard (status: generated - machine-written, not yet reviewed) +CLASS z2ui5_cl_smpc_app_670 DEFINITION PUBLIC. + + PUBLIC SECTION. + INTERFACES z2ui5_if_app. + + PROTECTED SECTION. + DATA client TYPE REF TO z2ui5_if_client. + + METHODS view_display. + + PRIVATE SECTION. +ENDCLASS. + + +CLASS z2ui5_cl_smpc_app_670 IMPLEMENTATION. + + METHOD z2ui5_if_app~main. + + me->client = client. + IF client->check_on_navigated( ). + view_display( ). + ENDIF. + + ENDMETHOD. + + + METHOD view_display. + + DATA(view) = z2ui5_cl_ui5_view_builder=>factory( ). + + view->ele( n = `View` ns = `mvc` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` + )->a( n = `xmlns:f` v = `sap.f` + )->a( n = `xmlns:w` v = `sap.ui.integration.widgets` + )->a( n = `height` v = `100%` + )->a( n = `displayBlock` v = `true` + + )->ele( `Page` + )->a( n = `showHeader` v = `false` + + )->ele( `content` + )->ele( `VBox` + )->a( n = `class` v = `sapUiMediumMarginBeginEnd sapUiMediumMarginTop` + + )->ele( n = `HeroBanner` ns = `f` + )->a( n = `headerText` v = `Good Morning, John` + )->a( n = `overlineText` v = `Thursday, July 10, 2026` + )->a( n = `columnsRatio` v = `FirstWider` + + )->ele( n = `actions` ns = `f` + )->tag( `Button` + )->a( n = `text` v = `Explore` + )->a( n = `type` v = `Emphasized` + )->tag( `Button` + )->a( n = `text` v = `Settings` + + )->end( + " both Card manifests by URL, as in the original - absolutized to + " the OpenUI5 host, since the demo kit's relative test-resources + " path has no document root to resolve against here + )->ele( n = `startContent` ns = `f` + )->tag( n = `Card` ns = `w` + )->a( n = `manifest` v = `https://sdk.openui5.org/test-resources/sap/f/demokit/sample/HeroBannerIntegrationCard/startContentManifest.json` + + )->end( + )->ele( n = `endContent` ns = `f` + )->tag( n = `Card` ns = `w` + )->a( n = `manifest` v = `https://sdk.openui5.org/test-resources/sap/f/demokit/sample/HeroBannerIntegrationCard/endContentManifest.json` ). + + client->view_display( view->stringify( ) ). + + ENDMETHOD. + +ENDCLASS. diff --git a/src/02/04/z2ui5_cl_smpc_app_670.clas.xml b/src/02/04/z2ui5_cl_smpc_app_670.clas.xml new file mode 100644 index 000000000..4e13c83a2 --- /dev/null +++ b/src/02/04/z2ui5_cl_smpc_app_670.clas.xml @@ -0,0 +1,16 @@ + + + + + + Z2UI5_CL_SMPC_APP_670 + E + sap.f - HeroBannerIntegrationCard + 1 + X + X + X + + + + diff --git a/src/02/04/z2ui5_cl_smpc_app_671.clas.abap b/src/02/04/z2ui5_cl_smpc_app_671.clas.abap new file mode 100644 index 000000000..8f921d15c --- /dev/null +++ b/src/02/04/z2ui5_cl_smpc_app_671.clas.abap @@ -0,0 +1,206 @@ +" @keywords herobanner hero banner sap.f herobannerusecases html title vbox button text card header +" @summary A collection of common Hero Banner use cases: header actions only, content with actions, actions below header, and header at bottom. +" @origin sap.f.sample.HeroBannerUseCases - https://sdk.openui5.org/entity/sap.f.HeroBanner/sample/sap.f.sample.HeroBannerUseCases (status: generated - machine-written, not yet reviewed) +CLASS z2ui5_cl_smpc_app_671 DEFINITION PUBLIC. + + PUBLIC SECTION. + INTERFACES z2ui5_if_app. + + PROTECTED SECTION. + DATA client TYPE REF TO z2ui5_if_client. + + METHODS view_display. + + PRIVATE SECTION. +ENDCLASS. + + +CLASS z2ui5_cl_smpc_app_671 IMPLEMENTATION. + + METHOD z2ui5_if_app~main. + + me->client = client. + IF client->check_on_navigated( ). + view_display( ). + ENDIF. + + ENDMETHOD. + + + METHOD view_display. + + DATA(view) = z2ui5_cl_ui5_view_builder=>factory( ). + + view->ele( n = `View` ns = `mvc` + )->a( n = `xmlns` v = `sap.m` + )->a( n = `xmlns:mvc` v = `sap.ui.core.mvc` + )->a( n = `xmlns:f` v = `sap.f` + )->a( n = `xmlns:card` v = `sap.f.cards` + )->a( n = `xmlns:core` v = `sap.ui.core` + )->a( n = `height` v = `100%` + )->a( n = `displayBlock` v = `true` + + )->ele( `Page` + )->a( n = `showHeader` v = `false` + + )->ele( `content` + " the sample's main.css, injected via a core:HTML content attribute + " (see CAPABILITIES.md) - literal braces escaped in a backtick literal + )->tag( n = `HTML` ns = `core` + )->a( n = `content` v = `` + + )->tag( `Title` + )->a( n = `text` v = `Header Actions Only` + )->a( n = `level` v = `H4` + )->a( n = `class` v = `sapUiSmallMarginBottom sapUiSmallMarginTop sapUiSmallMarginBegin` + + )->ele( `VBox` + )->a( n = `class` v = `sapUiMediumMarginBeginEnd` + + )->ele( n = `HeroBanner` ns = `f` + )->a( n = `headerText` v = `Welcome, Lisa` + )->a( n = `overlineText` v = `Tuesday, May 27, 2026` + + )->ele( n = `actions` ns = `f` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://action-settings` + )->a( n = `text` v = `Settings` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://activity-individual` + )->a( n = `text` v = `Activity Log` + + )->end( + )->end( + )->end( + + )->tag( `Title` + )->a( n = `text` v = `Content with Actions` + )->a( n = `level` v = `H4` + )->a( n = `class` v = `sapUiSmallMarginBottom sapUiMediumMarginTop sapUiSmallMarginBegin` + + )->ele( `VBox` + )->a( n = `class` v = `sapUiMediumMarginBeginEnd` + + )->ele( n = `HeroBanner` ns = `f` + )->a( n = `headerText` v = `Good Morning, Robert` + )->a( n = `overlineText` v = `Tuesday, May 27, 2026` + + )->ele( n = `actions` ns = `f` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://task` + )->a( n = `text` v = `Review Approvals` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://add-document` + )->a( n = `text` v = `Create Report` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://collaborate` + )->a( n = `text` v = `Team Overview` + + )->end( + )->ele( n = `startContent` ns = `f` + )->tag( `Text` + )->a( n = `class` v = `heroBannerWhiteText` + )->a( n = `text` v = `You have 3 pending approvals and 12 new notifications since your last visit. ` && + `Review your tasks below or use the quick actions to get started.` + + )->end( + )->end( + )->end( + + )->tag( `Title` + )->a( n = `text` v = `Actions Below Header (actionsPlacement="BottomStart")` + )->a( n = `level` v = `H4` + )->a( n = `class` v = `sapUiSmallMarginBottom sapUiMediumMarginTop sapUiSmallMarginBegin` + + )->ele( `VBox` + )->a( n = `class` v = `sapUiMediumMarginBeginEnd` + + )->ele( n = `HeroBanner` ns = `f` + )->a( n = `headerText` v = `Hello, Emma` + )->a( n = `overlineText` v = `Wednesday, May 28, 2026` + )->a( n = `actionsPlacement` v = `BottomStart` + )->a( n = `columnsRatio` v = `Equal` + + )->ele( n = `actions` ns = `f` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://create` + )->a( n = `text` v = `New Request` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://add-document` + )->a( n = `text` v = `Create Report` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://collaborate` + )->a( n = `text` v = `Team Overview` + + )->end( + )->ele( n = `endContent` ns = `f` + )->ele( n = `Card` ns = `f` + )->a( n = `width` v = `100%` + + )->ele( n = `header` ns = `f` + )->tag( n = `Header` ns = `card` + )->a( n = `title` v = `Open Tickets` + )->a( n = `subtitle` v = `Support` + + )->end( + )->ele( n = `content` ns = `f` + )->ele( `VBox` + )->a( n = `class` v = `sapUiSmallMargin` + + )->tag( `Title` + )->a( n = `text` v = `42` + )->a( n = `level` v = `H3` + + )->end( + )->end( + )->end( + )->end( + )->end( + )->end( + + )->tag( `Title` + )->a( n = `text` v = `Header at Bottom (headerBlockPlacement="Bottom")` + )->a( n = `level` v = `H4` + )->a( n = `class` v = `sapUiSmallMarginBottom sapUiMediumMarginTop sapUiSmallMarginBegin` + + )->ele( `VBox` + )->a( n = `class` v = `sapUiMediumMarginBeginEnd sapUiMediumMarginBottom` + + )->ele( n = `HeroBanner` ns = `f` + )->a( n = `headerText` v = `Good Afternoon, James` + )->a( n = `overlineText` v = `Wednesday, May 28, 2026` + )->a( n = `columnsRatio` v = `FirstWider` + )->a( n = `headerBlockPlacement` v = `Bottom` + + )->ele( n = `actions` ns = `f` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://cart` + )->a( n = `text` v = `Orders` + )->tag( `Button` + )->a( n = `icon` v = `sap-icon://task` + )->a( n = `text` v = `Tasks` + + )->end( + )->ele( n = `endContent` ns = `f` + )->ele( n = `Card` ns = `f` + )->a( n = `width` v = `100%` + + )->ele( n = `header` ns = `f` + )->tag( n = `Header` ns = `card` + )->a( n = `title` v = `Revenue YTD` + )->a( n = `subtitle` v = `Q2 2026` + + )->end( + )->ele( n = `content` ns = `f` + )->ele( `VBox` + )->a( n = `class` v = `sapUiSmallMargin` + + )->tag( `Title` + )->a( n = `text` v = `€4.2M` + )->a( n = `level` v = `H3` ). + + client->view_display( view->stringify( ) ). + + ENDMETHOD. + +ENDCLASS. diff --git a/src/02/04/z2ui5_cl_smpc_app_671.clas.xml b/src/02/04/z2ui5_cl_smpc_app_671.clas.xml new file mode 100644 index 000000000..aac077e5e --- /dev/null +++ b/src/02/04/z2ui5_cl_smpc_app_671.clas.xml @@ -0,0 +1,16 @@ + + + + + + Z2UI5_CL_SMPC_APP_671 + E + sap.f - HeroBannerUseCases + 1 + X + X + X + + + + diff --git a/src/z2ui5_cl_smpc_app_000.clas.abap b/src/z2ui5_cl_smpc_app_000.clas.abap index cbe3da4cf..ee46f4899 100644 --- a/src/z2ui5_cl_smpc_app_000.clas.abap +++ b/src/z2ui5_cl_smpc_app_000.clas.abap @@ -998,8 +998,42 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. DATA text1 TYPE string. DATA text2 TYPE string. + text1 = `NOTE: Three JSONModels are folded onto the one default model: the named items model (model/avatargroup.json, {items>/content} -> {/T_CONTENT}, totalCount kept as a non-bound attribute), the unnamed` && + ` settings model ({/viewPortPercentWidth} -> {/VIEWPORTPERCENTWIDTH}, {/popoverTitle} -> {/POPOVERTITLE}), the personData model (a structure S_PERSON, bound absolutely as {/S_PERSON/...} since there is` && + ` no element binding) and the groupedAvatars model (T_GROUPED, the Grid's bound content). Same data and leaf names, so a prefix-drop. The JSON's per-row tooltip key ('1'..'15') is bound nowhere and` && + ` stays out of the row type. // NOTE: onSliderMoved reads the slider value and calls setWidth( value + '%' ) on the VerticalLayout vl1. The port binds VerticalLayout.width to VL_WIDTH and computes the` && + ` string in on_event on a liveChange round-trip carrying check_queue_last and check_no_busy (the per-drag-step wire shape), so the backend ends on the slider's last value. VIEWPORTPERCENTWIDTH is` && + ` seeded 100 and VL_WIDTH '100%' as in onInit / the view. // NOTE: onIndividualPress / onGroupPress / _getContent / _getAvatarModel are rebuilt in ABAP. The press event transports`. + text1 = text1 && ` overflowButtonPressed, avatarsDisplayed, the eventSource id (the popover anchor) and the pressed item's row index (${$parameters>/eventSource}.getBindingContext().getPath().split('/').pop()); the` && + ` Group-type AvatarGroup anchors at $event.oSource.sId as onGroupPress anchors at oEvent.getSource(). The popover rows are the avatars from avatarsDisplayed on (all for Group), the title 'Team Members` && + ` ()' and the contentHeight formula ((n DIV 2 + n MOD 2) * 68 + 48 px) are computed in ABAP. The backgroundColor _getAvatarModel reads off AvatarGroupItem.getAvatarColor( ) is derived in ABAP from` && + ` the rule AvatarGroup.addItem applies (Accent1..Accent10 by item position, round robin) instead of being read from the control - same value, no control call. // IMPROVISED:` && + ` IndividualPopover.fragment.xml and GroupPopover.fragment.xml are built in on_event (popover_display) and Card.fragment.xml is inlined into both, as the original's two core:Fragment references load it` && + ` twice - so the port carries the Card subtree twice (control extra Card, VerticalLayout, HBox, Avatar, VBox, Title, Text, Label controls) and drops both core:Fragment references. Each popover is`. + text1 = text1 && ` rebuilt per press instead of being cached, which also makes oNavCon.to(oMainPage) on every open implicit (a fresh NavContainer starts on its first page). openBy(` && + ` ).addStyleClass('sapFAvatarGroupPopover') becomes a class attribute on each Popover. onAvatarPress's setContentWidth('450px') is a no-op (the Popover already declares 450px) and its` && + ` oGroupPopover.focus( ) is dropped; the NavContainer moves with control_by_id to( detail ) / back( ) in the popover slot, the contentHeight follows the bound POPOVER_HEIGHT (375px on the detail page,` && + ` the computed height after navButtonPress). // NOTE: GroupPopover.fragment.xml binds the grid Avatar's fallbackIcon to {personData>/fallbackIcon} - the individual personData model, not the row's` && + ` groupedAvatars model - so every grid avatar shows the fallback icon of whichever person was last opened. Ported verbatim as the absolute {/S_PERSON/FALLBACKICON} binding rather than repaired.` && + ` S_PERSON-BACKGROUNDCOLOR is seeded Accent6 (the sap.m.Avatar default): the empty personData model leaves the property undefined, while an empty string on the enum-typed backgroundColor would make UI5`. + text1 = text1 && ` reject the whole popover. // NOTE: The two avatar image src values are host-absolutized to https://sdk.openui5.org/test-resources/sap/f/images/Woman_avatar_01.png and Woman_avatar_02.png (the JSON's` && + ` ./test-resources/... resolves against the Demo Kit). Row fields the JSON omits (initials, src, fallbackIcon) are left initial - all three are plain string/URI properties whose empty value renders` && + ` like undefined. // POST-1.71: the sap.f.AvatarGroup and sap.f.AvatarGroupItem controls (since UI5 1.73) are newer than 1.71 and are the whole point of this sample - kept 1:1. The inlined card also` && + ` uses sap.m.Avatar (@since 1.73, its press @since 1.73) and the Popover and Page titleAlignment property (@since 1.72), so the app needs a UI5 release >= 1.73.`. result = VALUE #( - ( module = `sap.f` control = `sap.f.Card` name = `Card` class = `z2ui5_cl_smpc_app_117` path = `src/01/04/z2ui5_cl_smpc_app_117.clas.abap` + ( module = `sap.f` control = `sap.f.AvatarGroup` name = `AvatarGroup` class = `z2ui5_cl_smpc_app_662` path = `src/02/04/z2ui5_cl_smpc_app_662.clas.abap` + score = 5 + score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 1 reworked, live-test). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close` && + ` look.` + since = `1.73` + since_post171 = abap_true + is_post171 = abap_true + notes = text1 + post171 = `the sap.f.AvatarGroup and sap.f.AvatarGroupItem controls (since UI5 1.73) are newer than 1.71 and are the whole point of this sample - kept 1:1. The inlined card also uses sap.m.Avatar (@since 1.73,` && + ` its press @since 1.73) and the Popover and Page titleAlignment property (@since 1.72), so the app needs a UI5 release >= 1.73.` ) ). + + result = VALUE #( BASE result + ( module = `sap.f` control = `sap.f.Card` name = `Card` class = `z2ui5_cl_smpc_app_117` path = `src/01/04/z2ui5_cl_smpc_app_117.clas.abap` score = 3 score_tip = `Rating 3 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 1 noted). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.64` @@ -1026,7 +1060,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` which an abap2UI5 app has no document root to resolve against, so the port points at https://sdk.openui5.org/... instead. The values are otherwise the mock's own. Added 2026-08-23: this port did the` && ` rewrite without declaring it, one of 17 found by re-counting the corpus-wide claim that every port doing it had a declaration.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.DynamicPage` name = `DynamicPageAnalyticalTable` class = `z2ui5_cl_smpc_app_559` path = `src/02/04/z2ui5_cl_smpc_app_559.clas.abap` + ( module = `sap.f` control = `sap.f.DynamicPage` name = `DynamicPageAnalyticalTable` class = `z2ui5_cl_smpc_app_559` path = `src/02/04/z2ui5_cl_smpc_app_559.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked, live-test). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close` && ` look.` @@ -1051,7 +1085,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. text1 = text1 && ` string keeps the exact value; TYPE i would truncate (an earlier version did, via json-to-abap's first-row inference — tool since fixed). Price stays packed (DECIMALS 2) for the Currency type binding,` && ` decimals preserved.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.DynamicPage` name = `DynamicPageFreeStyle` class = `z2ui5_cl_smpc_app_170` path = `src/01/04/z2ui5_cl_smpc_app_170.clas.abap` + ( module = `sap.f` control = `sap.f.DynamicPage` name = `DynamicPageFreeStyle` class = `z2ui5_cl_smpc_app_170` path = `src/01/04/z2ui5_cl_smpc_app_170.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.42` @@ -1077,7 +1111,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` Avatars, seeded XL) and toasts Media Range: (px) exactly like onBreakpointChange. @since verified fork-openui5/src/sap.f/src/sap/f/DynamicPage.js:315. Requires a UI5 release >= 1.147;` && ` on older releases the event never fires and the Avatars keep the seeded XL (the property gate is blind to sap.f event params).`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.DynamicPage` name = `DynamicPageResponsiveAvatar` class = `z2ui5_cl_smpc_app_244` path = `src/02/04/z2ui5_cl_smpc_app_244.clas.abap` + ( module = `sap.f` control = `sap.f.DynamicPage` name = `DynamicPageResponsiveAvatar` class = `z2ui5_cl_smpc_app_244` path = `src/02/04/z2ui5_cl_smpc_app_244.clas.abap` score = 4 score_tip = `Rating 4 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 2 noted, live-test). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.42` @@ -1105,7 +1139,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` so every press snapped the IconTabBar back to the Products tab (neither side declares a selectedKey) and reset the pinnable header and the scroll position. The bound property needs no re-render: the` && ` model diff is pushed automatically.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.DynamicPage` name = `DynamicPageWithStickySubheader` class = `z2ui5_cl_smpc_app_238` path = `src/01/04/z2ui5_cl_smpc_app_238.clas.abap` + ( module = `sap.f` control = `sap.f.DynamicPage` name = `DynamicPageWithStickySubheader` class = `z2ui5_cl_smpc_app_238` path = `src/01/04/z2ui5_cl_smpc_app_238.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.42` @@ -1149,7 +1183,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` in a running system: the Bank Transfer and Cash on Delivery branches, the delivery-address branch, the two discard confirmations, the DynamicPage's sticky subheader over the wizard and the review`. text1 = text1 && ` page's six Edit links.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.DynamicPage` name = `DynamicPageWithWizard` class = `z2ui5_cl_smpc_app_560` path = `src/01/04/z2ui5_cl_smpc_app_560.clas.abap` + ( module = `sap.f` control = `sap.f.DynamicPage` name = `DynamicPageWithWizard` class = `z2ui5_cl_smpc_app_560` path = `src/01/04/z2ui5_cl_smpc_app_560.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 2 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.42` @@ -1183,7 +1217,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` MidColumnFullScreen, not TwoColumnsMidExpanded. This sample builds its semantic helper with maxColumnsCount: 1, and getNextUIState short-circuits to MidColumnFullScreen in that case - which is what` && ` hides the begin column and makes the return to OneColumn a begin-column resize from zero width, the event the sample exists to demonstrate.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutColumnResize` class = `z2ui5_cl_smpc_app_577` path = `src/02/04/z2ui5_cl_smpc_app_577.clas.abap` + ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutColumnResize` class = `z2ui5_cl_smpc_app_577` path = `src/02/04/z2ui5_cl_smpc_app_577.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked, live-test). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close` && ` look.` @@ -1204,7 +1238,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` Standard, so the middle column rendered a different background from the sample. Removed 2026-08-24. No gate saw it: structural-diff has no 'attr extra' kind, so an attribute a port ADDS is never` && ` compared.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutLandmarkInfo` class = `z2ui5_cl_smpc_app_449` path = `src/02/04/z2ui5_cl_smpc_app_449.clas.abap` + ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutLandmarkInfo` class = `z2ui5_cl_smpc_app_449` path = `src/02/04/z2ui5_cl_smpc_app_449.clas.abap` score = 4 score_tip = `Rating 4 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.46` @@ -1225,7 +1259,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` Standard, so the middle column rendered a different background from the sample. Removed 2026-08-24. No gate saw it: structural-diff has no 'attr extra' kind, so an attribute a port ADDS is never` && ` compared.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutLandmarkInfoArrow` class = `z2ui5_cl_smpc_app_450` path = `src/02/04/z2ui5_cl_smpc_app_450.clas.abap` + ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutLandmarkInfoArrow` class = `z2ui5_cl_smpc_app_450` path = `src/02/04/z2ui5_cl_smpc_app_450.clas.abap` score = 4 score_tip = `Rating 4 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.46` @@ -1247,7 +1281,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` with no user-visible effect and is not reproduced - all three pages exist from the start. **e2e-verified 2026-07-30** (transpiled-framework interaction, scripts/e2e-smoke.mjs): pressing the first` && ` master list item round-trips LIST_PRESS and the mid column renders (the two-way bound layout flipped to TwoColumnsBeginExpanded).`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutSimple` class = `z2ui5_cl_smpc_app_234` path = `src/01/04/z2ui5_cl_smpc_app_234.clas.abap` + ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutSimple` class = `z2ui5_cl_smpc_app_234` path = `src/01/04/z2ui5_cl_smpc_app_234.clas.abap` score = 3 score_tip = `Rating 3 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.46` @@ -1322,7 +1356,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. text1 = text1 && ` precedent of app 575); non-arrow firings return without touching anything. // NOTE: Component.js raises the model size limit; the port issues cs_event-set_size_limit for MAIN. The collection is 123` && ` rows and the JSONModel caps a bound aggregation at 100, so without it the table stopped 23 rows short of the count its own title reports.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutWithFullscreenPage` class = `z2ui5_cl_smpc_app_578` path = `src/02/04/z2ui5_cl_smpc_app_578.clas.abap` + ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutWithFullscreenPage` class = `z2ui5_cl_smpc_app_578` path = `src/02/04/z2ui5_cl_smpc_app_578.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked, live-test). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close` && ` look.` @@ -1373,7 +1407,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` own title reports. // NOTE: The items binding carries no client-side sorter. It used to keep the original's sorter: { path: 'NAME' }, which ClientListBinding re-applies on every model change - so the` && ` ABAP sort was undone immediately and the Sort button round-tripped without changing anything. The original replaces the declared sorter through oBinding.sort( ); here the backend owns the order.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutWithOneColumnStart` class = `z2ui5_cl_smpc_app_579` path = `src/02/04/z2ui5_cl_smpc_app_579.clas.abap` + ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutWithOneColumnStart` class = `z2ui5_cl_smpc_app_579` path = `src/02/04/z2ui5_cl_smpc_app_579.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked, live-test). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close` && ` look.` @@ -1425,7 +1459,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` own title reports. // NOTE: The items binding carries no client-side sorter. It used to keep the original's sorter: { path: 'NAME' }, which ClientListBinding re-applies on every model change - so the` && ` ABAP sort was undone immediately and the Sort button round-tripped without changing anything. The original replaces the declared sorter through oBinding.sort( ); here the backend owns the order.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutWithTwoColumnStart` class = `z2ui5_cl_smpc_app_580` path = `src/02/04/z2ui5_cl_smpc_app_580.clas.abap` + ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `FlexibleColumnLayoutWithTwoColumnStart` class = `z2ui5_cl_smpc_app_580` path = `src/02/04/z2ui5_cl_smpc_app_580.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked, live-test). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close` && ` look.` @@ -1481,7 +1515,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` ClientListBinding re-applies on every model change - so the ABAP sort was undone immediately and the Sort button round-tripped without changing anything. The original replaces the declared sorter` && ` through oBinding.sort( ); here the backend owns the order.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `ShellBarWithFlexibleColumnLayout` class = `z2ui5_cl_smpc_app_584` path = `src/02/04/z2ui5_cl_smpc_app_584.clas.abap` + ( module = `sap.f` control = `sap.f.FlexibleColumnLayout` name = `ShellBarWithFlexibleColumnLayout` class = `z2ui5_cl_smpc_app_584` path = `src/02/04/z2ui5_cl_smpc_app_584.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked, live-test). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close` && ` look.` @@ -1522,7 +1556,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` URL onto the OpenUI5 host (the corpus asset rule) fixed the render as a side effect, the skip went stale, and the gate demanded its removal - which is exactly what a re-verified skip is for. Both are`. text1 = text1 && ` gone now; the port renders clean.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridContainer` name = `GridContainer` class = `z2ui5_cl_smpc_app_168` path = `src/02/04/z2ui5_cl_smpc_app_168.clas.abap` + ( module = `sap.f` control = `sap.f.GridContainer` name = `GridContainer` class = `z2ui5_cl_smpc_app_168` path = `src/02/04/z2ui5_cl_smpc_app_168.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked, live-test). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close` && ` look.` @@ -1547,7 +1581,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` layoutChange wire has no counterpart and the two GridContainerSettings the view declares (layout and layoutXS) already carry the responsive sizing. // NOTE: The drag-and-drop reorder of the ten grid` && ` items and the three rebuilt cards are unverified in a running system. **e2e-verified 2026-08-25** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_526.mjs).`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridContainer` name = `GridContainerDragAndDrop` class = `z2ui5_cl_smpc_app_526` path = `src/01/04/z2ui5_cl_smpc_app_526.clas.abap` + ( module = `sap.f` control = `sap.f.GridContainer` name = `GridContainerDragAndDrop` class = `z2ui5_cl_smpc_app_526` path = `src/01/04/z2ui5_cl_smpc_app_526.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 2 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.65` @@ -1563,7 +1597,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` ToggleButton.press as attr missing) - same treatment as app 168, which ships the same helper. // NOTE: The drag and drop between the List and the GridContainer, in both directions and within each` && ` container, is unverified in a running system. **e2e-verified 2026-08-25** (nightly e2e interaction, meta/interactions/z2ui5_cl_smpc_app_527.mjs).`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridContainer` name = `GridContainerDragAndDropFromList` class = `z2ui5_cl_smpc_app_527` path = `src/01/04/z2ui5_cl_smpc_app_527.clas.abap` + ( module = `sap.f` control = `sap.f.GridContainer` name = `GridContainerDragAndDropFromList` class = `z2ui5_cl_smpc_app_527` path = `src/01/04/z2ui5_cl_smpc_app_527.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 2 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.65` @@ -1588,7 +1622,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` manifest's action is mailto:{email} with no subject, so only EMAIL travels. // NOTE: The objectContent/contact manifest header carries "icon": { "text": "DM" }, an initials avatar. The rebuilt` && ` card:Header keeps title and subtitle only; sap.f.cards.Header.iconInitials is base-version and would have expressed it.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridContainer` name = `GridContainersNavigation` class = `z2ui5_cl_smpc_app_528` path = `src/02/04/z2ui5_cl_smpc_app_528.clas.abap` + ( module = `sap.f` control = `sap.f.GridContainer` name = `GridContainersNavigation` class = `z2ui5_cl_smpc_app_528` path = `src/02/04/z2ui5_cl_smpc_app_528.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 3 reworked, live-test). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close` && ` look.` @@ -1600,13 +1634,13 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` but is not pressable, so the withAction card's navigation silently does nothing.` ) ). result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridList` name = `GridListBasic` class = `z2ui5_cl_smpc_app_111` path = `src/01/04/z2ui5_cl_smpc_app_111.clas.abap` + ( module = `sap.f` control = `sap.f.GridList` name = `GridListBasic` class = `z2ui5_cl_smpc_app_111` path = `src/01/04/z2ui5_cl_smpc_app_111.clas.abap` score = 2 score_tip = `Rating 2 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 1 noted). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.60` notes = `NOTE: The Slider drives the panel width via a roundtrip-free expression binding ({= ${slider} + '%' }) over the two-way slider value, instead of the original onSliderMoved setWidth handler;` && ` Slider.liveChange is therefore not wired (the width tracks the slider client-side). The full 27-row item set is inlined.` ) - ( module = `sap.f` control = `sap.f.GridList` name = `GridListBoxContainer` class = `z2ui5_cl_smpc_app_144` path = `src/01/04/z2ui5_cl_smpc_app_144.clas.abap` + ( module = `sap.f` control = `sap.f.GridList` name = `GridListBoxContainer` class = `z2ui5_cl_smpc_app_144` path = `src/01/04/z2ui5_cl_smpc_app_144.clas.abap` score = 3 score_tip = `Rating 3 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 2 noted). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.60` @@ -1621,7 +1655,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` custom f:headerToolbar (Toolbar with Title, ToolbarSpacer, SearchField - the SearchField has no handler in the original). The 27 items are inlined 1:1 from the sample's own model/items.json; the` && ` GridListItem template (VBox>VBox+FlexItemData, Title, Label) binds {TITLE}/{SUBTITLE} 1:1.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridList` name = `GridListBoxContainerGrouping` class = `z2ui5_cl_smpc_app_176` path = `src/01/04/z2ui5_cl_smpc_app_176.clas.abap` + ( module = `sap.f` control = `sap.f.GridList` name = `GridListBoxContainerGrouping` class = `z2ui5_cl_smpc_app_176` path = `src/01/04/z2ui5_cl_smpc_app_176.clas.abap` score = 2 score_tip = `Rating 2 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 2 noted). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.60` @@ -1637,7 +1671,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` OverflowToolbar designs the first list contrasts (Solid with sapContrast, plain Solid, Transparent). // NOTE: the twelve icon-only Buttons of the first and third list are tooltip-less in the sample` && ` (Sort, Group, Edit, Delete and Information). The port gives each a tooltip so they are reachable with a screen reader - the accessibility additions in this port.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridList` name = `GridListBoxContainerReal` class = `z2ui5_cl_smpc_app_581` path = `src/01/04/z2ui5_cl_smpc_app_581.clas.abap` + ( module = `sap.f` control = `sap.f.GridList` name = `GridListBoxContainerReal` class = `z2ui5_cl_smpc_app_581` path = `src/01/04/z2ui5_cl_smpc_app_581.clas.abap` score = 4 score_tip = `Rating 4 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 1 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.60` @@ -1649,7 +1683,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` breakpoint on either side. // NOTE: GridResponsiveLayout.layoutChange is wired to a client-composed MessageToast (control_global MESSAGE_TOAST, template 'Layout changed to {0}' filled by` && ` ${$parameters>/layout}) reproducing onLayoutChange 1:1 without a backend round-trip. The layoutChange attribute itself is kept, so structural-diff sees no difference.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridList` name = `GridListBreakPoints` class = `z2ui5_cl_smpc_app_213` path = `src/01/04/z2ui5_cl_smpc_app_213.clas.abap` + ( module = `sap.f` control = `sap.f.GridList` name = `GridListBreakPoints` class = `z2ui5_cl_smpc_app_213` path = `src/01/04/z2ui5_cl_smpc_app_213.clas.abap` score = 3 score_tip = `Rating 3 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 2 noted). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.60` @@ -1668,7 +1702,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` item with 'After' when the pointer is over no item at all, and that item can be the dragged one, which yields drag_pos = drop_pos = lines - 1 and an insert index of lines + 2. The index is clamped` && ` now. Under the transpiler the runtime splices like JS, so this is one of the defects that only shows on a real system.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridList` name = `GridListDragAndDrop` class = `z2ui5_cl_smpc_app_148` path = `src/01/04/z2ui5_cl_smpc_app_148.clas.abap` + ( module = `sap.f` control = `sap.f.GridList` name = `GridListDragAndDrop` class = `z2ui5_cl_smpc_app_148` path = `src/01/04/z2ui5_cl_smpc_app_148.clas.abap` score = 3 score_tip = `Rating 3 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.60` @@ -1692,7 +1726,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` inside a grid reach its border and raise the toast, and that dragging the slider narrows the container without a round trip. **e2e-verified 2026-08-25** (nightly e2e interaction,` && ` meta/interactions/z2ui5_cl_smpc_app_582.mjs).`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridList` name = `GridListKeyboardArrowsNavigation` class = `z2ui5_cl_smpc_app_582` path = `src/01/04/z2ui5_cl_smpc_app_582.clas.abap` + ( module = `sap.f` control = `sap.f.GridList` name = `GridListKeyboardArrowsNavigation` class = `z2ui5_cl_smpc_app_582` path = `src/01/04/z2ui5_cl_smpc_app_582.clas.abap` score = 5 score_tip = `Rating 5 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 2 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.60` @@ -1715,7 +1749,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` 122/124 had and closed: 'a sample whose stylesheet is not in ui5/ is an archive gap to close, not a reason to drop the CSS'. main.css now sits in ui5/sap.f/GridListModes/ (closing the AGENTS section` && ` 4 archive gap) and reaches the view through a core:HTML style leaf.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridList` name = `GridListModes` class = `z2ui5_cl_smpc_app_133` path = `src/01/04/z2ui5_cl_smpc_app_133.clas.abap` + ( module = `sap.f` control = `sap.f.GridList` name = `GridListModes` class = `z2ui5_cl_smpc_app_133` path = `src/01/04/z2ui5_cl_smpc_app_133.clas.abap` score = 4 score_tip = `Rating 4 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 0 reworked). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.60` @@ -1729,7 +1763,7 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. ` Fully static view reproduced 1:1: a ToggleButton, a Slider (value=100), and a Panel (headerToolbar Toolbar+Title) hosting an f:GridList with a ResponsiveColumnLayout and five static f:GridListItems`. text1 = text1 && ` (columns/rows 4/4, 3/2, 3/2, 1/1, 1/1), each a VBox with a Title and 1..5 Labels; no bound data.`. result = VALUE #( BASE result - ( module = `sap.f` control = `sap.f.GridList` name = `GridListResponsiveColumnLayout` class = `z2ui5_cl_smpc_app_222` path = `src/02/04/z2ui5_cl_smpc_app_222.clas.abap` + ( module = `sap.f` control = `sap.f.GridList` name = `GridListResponsiveColumnLayout` class = `z2ui5_cl_smpc_app_222` path = `src/02/04/z2ui5_cl_smpc_app_222.clas.abap` score = 3 score_tip = `Rating 3 of 5 - how much attention this port deserves (complexity + rework + review + test-priority: complex, 2 noted). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` since = `1.60` @@ -1738,6 +1772,114 @@ CLASS z2ui5_cl_smpc_app_000 IMPLEMENTATION. post171 = `The GridList customLayout uses sap.ui.layout.cssgrid.ResponsiveColumnLayout and per-item ResponsiveColumnItemLayoutData with columns/rows (control + members since 1.72), kept 1:1; requires a UI5` && ` release >= 1.72.` ) ). + result = VALUE #( BASE result + ( module = `sap.f` control = `sap.f.HeroBanner` name = `HeroBannerBasic` class = `z2ui5_cl_smpc_app_667` path = `src/02/04/z2ui5_cl_smpc_app_667.clas.abap` + score = 1 + score_tip = `Rating 1 of 5 - how much attention this port deserves (complexity + rework + review + test-priority). 1 = simple faithful 1:1, 5 = complex / reworked / worth a close look.` + since = `1.152` + since_post171 = abap_true + is_post171 = abap_true + notes = `POST-1.71: the sap.f.HeroBanner control is newer than 1.71 (sap/f/HeroBanner.js: @ui5-experimental-since 1.152 - an EXPERIMENTAL wrapper around the UI5 Web Components fiori HeroBanner, extending` && + ` sap.ui.core.webc.WebComponent) and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.152.` + post171 = `the sap.f.HeroBanner control is newer than 1.71 (sap/f/HeroBanner.js: @ui5-experimental-since 1.152 - an EXPERIMENTAL wrapper around the UI5 Web Components fiori HeroBanner, extending` && + ` sap.ui.core.webc.WebComponent) and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.152.` ) ). + + text1 = `POST-1.71: the sap.f.HeroBanner control is newer than 1.71 (sap/f/HeroBanner.js: @ui5-experimental-since 1.152 - an EXPERIMENTAL wrapper around the UI5 Web Components fiori HeroBanner, extending` && + ` sap.ui.core.webc.WebComponent) and is the whole point of this sample - kept 1:1, the app needs a UI5 release >= 1.152. HeroBanner members used: the actions, startContent and endContent aggregations` && + ` and the columnsRatio property with its sap.f.HeroBannerColumnsRatio values Equal and FirstWider - all @ui5-experimental-since 1.152 with the control. // NOTE: The sample's main.css (one rule,` && + ` .heroBannerWhiteText { color: var(--sapTextInvertedColor) }, the class the startContent Text carries) is shipped with the port: it is injected through a core:HTML control carrying a + + + +
+
+ + \ No newline at end of file diff --git a/ui5/sap.m/p13n.Container/manifest.json b/ui5/sap.m/p13n.Container/manifest.json new file mode 100644 index 000000000..61bc32bcb --- /dev/null +++ b/ui5/sap.m/p13n.Container/manifest.json @@ -0,0 +1,31 @@ +{ + "sap.app": { + "id": "sap.m.sample.p13n.Container", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui5": { + "rootView": { + "viewName": "sap.m.sample.p13n.Container.P13nContainer", + "type": "XML", + "async": true + }, + "dependencies": { + "libs": { + "sap.m": {}, + "sap.ui.core": {}, + "sap.ui.layout": {} + } + }, + "config": { + "sample": { + "files": [ + "P13nContainer.view.xml", + "P13nContainer.controller.js", + "manifest.json" + ] + } + } + } +} \ No newline at end of file diff --git a/ui5/sap.m/p13n.Engine/Component.js b/ui5/sap.m/p13n.Engine/Component.js new file mode 100644 index 000000000..b4b6d61e6 --- /dev/null +++ b/ui5/sap.m/p13n.Engine/Component.js @@ -0,0 +1,15 @@ +sap.ui.define([ + 'sap/ui/core/UIComponent' +], function(UIComponent) { + "use strict"; + + const Component = UIComponent.extend("sap.m.sample.p13n.Engine.Component", { + + metadata: { + manifest: "json" + } + }); + + return Component; + +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.Engine/Engine.controller.js b/ui5/sap.m/p13n.Engine/Engine.controller.js new file mode 100644 index 000000000..e19b574ce --- /dev/null +++ b/ui5/sap.m/p13n.Engine/Engine.controller.js @@ -0,0 +1,373 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller', + 'sap/ui/model/json/JSONModel', + 'sap/m/p13n/Engine', + 'sap/m/p13n/SelectionController', + 'sap/m/p13n/SortController', + 'sap/m/p13n/GroupController', + 'sap/m/p13n/FilterController', + 'sap/m/p13n/MetadataHelper', + 'sap/ui/model/Sorter', + 'sap/m/ColumnListItem', + 'sap/m/Text', + 'sap/ui/core/library', + 'sap/m/table/ColumnWidthController', + 'sap/ui/model/Filter' +], function(Controller, JSONModel, Engine, SelectionController, SortController, GroupController, FilterController, MetadataHelper, Sorter, ColumnListItem, Text, coreLibrary, ColumnWidthController, Filter) { + "use strict"; + + return Controller.extend("sap.m.sample.p13n.Engine.Page", { + + onInit: function() { + const oData = { + items: [{ + key: "P1", + firstName: "Peter", + lastName: "Mueller", + size: "1.75", + city: "Walldorf" + }, + { + key: "P2", + firstName: "Petra", + lastName: "Maier", + size: "1.85", + city: "Walldorf" + }, + { + key: "P3", + firstName: "Thomas", + lastName: "Smith", + size: "1.95", + city: "Heidelberg" + }, + { + key: "P4", + firstName: "John", + lastName: "Williams", + size: "1.65", + city: "Walldorf" + }, + { + key: "P5", + firstName: "Maria", + lastName: "Jones", + size: "1.55", + city: "Walldorf" + } + ] + }; + + const oModel = new JSONModel(oData); + this._oModel = oModel; + + this.getView().setModel(oModel); + + this._registerForP13n(); + }, + + onExit: function() { + Engine.getInstance().detachStateChange(this.handleStateChange, this); + }, + + _registerForP13n: function() { + const oTable = this.byId("persoTable"); + + this.oMetadataHelper = new MetadataHelper([{ + key: "firstName_col", + label: "First Name", + path: "firstName" + }, + { + key: "lastName_col", + label: "Last Name", + path: "lastName" + }, + { + key: "city_col", + label: "City", + path: "city" + }, + { + key: "size_col", + label: "Size", + path: "size" + } + ]); + + Engine.getInstance().register(oTable, { + helper: this.oMetadataHelper, + controller: { + Columns: new SelectionController({ + targetAggregation: "columns", + control: oTable + }), + Sorter: new SortController({ + control: oTable + }), + Groups: new GroupController({ + control: oTable + }), + ColumnWidth: new ColumnWidthController({ + control: oTable + }), + Filter: new FilterController({ + control: oTable + }) + } + }); + + Engine.getInstance().attachStateChange(this.handleStateChange, this); + }, + + openPersoDialog: function(oEvt) { + this._openPersoDialog(["Columns", "Sorter", "Groups", "Filter"], oEvt.getSource()); + }, + + _openPersoDialog: function(aPanels, oSource) { + var oTable = this.byId("persoTable"); + + Engine.getInstance().show(oTable, aPanels, { + contentHeight: aPanels.length > 1 ? "50rem" : "35rem", + contentWidth: aPanels.length > 1 ? "45rem" : "32rem", + source: oSource || oTable + }); + }, + + _getKey: function(oControl) { + return oControl.data("p13nKey"); + }, + + handleStateChange: function(oEvt) { + const oTable = this.byId("persoTable"); + const oState = oEvt.getParameter("state"); + + if (!oState) { + return; + } + + //Update the columns per selection in the state + this.updateColumns(oState); + + //Create Filters & Sorters + const aFilter = this.createFilters(oState); + const aGroups = this.createGroups(oState); + const aSorter = this.createSorters(oState, aGroups); + + const aCells = oState.Columns.map(function(oColumnState) { + return new Text({ + text: "{" + this.oMetadataHelper.getProperty(oColumnState.key).path + "}" + }); + }.bind(this)); + + //rebind the table with the updated cell template + oTable.bindItems({ + templateShareable: false, + path: '/items', + sorter: aSorter.concat(aGroups), + filters: aFilter, + template: new ColumnListItem({ + cells: aCells + }) + }); + + }, + + createFilters: function(oState) { + const aFilter = []; + Object.keys(oState.Filter).forEach((sFilterKey) => { + const filterPath = this.oMetadataHelper.getProperty(sFilterKey).path; + + oState.Filter[sFilterKey].forEach(function(oConditon) { + aFilter.push(new Filter(filterPath, oConditon.operator, oConditon.values[0])); + }); + }); + + this.byId("filterInfo").setVisible(aFilter.length > 0); + + return aFilter; + }, + + createSorters: function(oState, aExistingSorter) { + const aSorter = aExistingSorter || []; + oState.Sorter.forEach(function(oSorter) { + const oExistingSorter = aSorter.find(function(oSort) { + return oSort.sPath === this.oMetadataHelper.getProperty(oSorter.key).path; + }.bind(this)); + + if (oExistingSorter) { + oExistingSorter.bDescending = !!oSorter.descending; + } else { + aSorter.push(new Sorter(this.oMetadataHelper.getProperty(oSorter.key).path, oSorter.descending)); + } + }.bind(this)); + + oState.Sorter.forEach((oSorter) => { + const oCol = this.byId("persoTable").getColumns().find((oColumn) => oColumn.data("p13nKey") === oSorter.key); + if (oSorter.sorted !== false) { + oCol.setSortIndicator(oSorter.descending ? coreLibrary.SortOrder.Descending : coreLibrary.SortOrder.Ascending); + } + }); + + return aSorter; + }, + + createGroups: function(oState) { + const aGroupings = []; + oState.Groups.forEach(function(oGroup) { + aGroupings.push(new Sorter(this.oMetadataHelper.getProperty(oGroup.key).path, false, true)); + }.bind(this)); + + oState.Groups.forEach((oSorter) => { + const oCol = this.byId("persoTable").getColumns().find((oColumn) => oColumn.data("p13nKey") === oSorter.key); + oCol.data("grouped", true); + }); + + return aGroupings; + }, + + updateColumns: function(oState) { + const oTable = this.byId("persoTable"); + + oTable.getColumns().forEach((oColumn, iIndex) => { + oColumn.setVisible(false); + oColumn.setWidth(oState.ColumnWidth[this._getKey(oColumn)]); + oColumn.setSortIndicator(coreLibrary.SortOrder.None); + oColumn.data("grouped", false); + }); + + oState.Columns.forEach((oProp, iIndex) => { + const oCol = oTable.getColumns().find((oColumn) => oColumn.data("p13nKey") === oProp.key); + oCol.setVisible(true); + + oTable.removeColumn(oCol); + oTable.insertColumn(oCol, iIndex); + }); + }, + + beforeOpenColumnMenu: function(oEvt) { + const oMenu = this.byId("menu"); + const oColumn = oEvt.getParameter("openBy"); + const oSortItem = oMenu.getQuickActions()[0].getItems()[0]; + const oGroupItem = oMenu.getQuickActions()[1].getItems()[0]; + + oSortItem.setKey(this._getKey(oColumn)); + oSortItem.setLabel(oColumn.getHeader().getText()); + oSortItem.setSortOrder(oColumn.getSortIndicator()); + + oGroupItem.setKey(this._getKey(oColumn)); + oGroupItem.setLabel(oColumn.getHeader().getText()); + oGroupItem.setGrouped(oColumn.data("grouped")); + }, + + onFilterInfoPress: function(oEvt) { + this._openPersoDialog(["Filter"], oEvt.getSource()); + }, + + onSort: function(oEvt) { + const oSortItem = oEvt.getParameter("item"); + const oTable = this.byId("persoTable"); + const sAffectedProperty = oSortItem.getKey(); + const sSortOrder = oSortItem.getSortOrder(); + + //Apply the state programatically on sorting through the column menu + //1) Retrieve the current personalization state + Engine.getInstance().retrieveState(oTable).then(function(oState) { + + //2) Modify the existing personalization state --> clear all sorters before + oState.Sorter.forEach(function(oSorter) { + oSorter.sorted = false; + }); + + if (sSortOrder !== coreLibrary.SortOrder.None) { + oState.Sorter.push({ + key: sAffectedProperty, + descending: sSortOrder === coreLibrary.SortOrder.Descending + }); + } + + //3) Apply the modified personalization state to persist it in the VariantManagement + Engine.getInstance().applyState(oTable, oState); + }); + }, + + onGroup: function(oEvt) { + const oGroupItem = oEvt.getParameter("item"); + const oTable = this.byId("persoTable"); + const sAffectedProperty = oGroupItem.getKey(); + + //1) Retrieve the current personalization state + Engine.getInstance().retrieveState(oTable).then(function(oState) { + + //2) Modify the existing personalization state --> clear all groupings before + oState.Groups.forEach(function(oSorter) { + oSorter.grouped = false; + }); + + if (oGroupItem.getGrouped()) { + oState.Groups.push({ + key: sAffectedProperty + }); + } + + //3) Apply the modified personalization state to persist it in the VariantManagement + Engine.getInstance().applyState(oTable, oState); + }); + }, + + onColumnMove: function(oEvt) { + const oDraggedColumn = oEvt.getParameter("draggedControl"); + const oDroppedColumn = oEvt.getParameter("droppedControl"); + + if (oDraggedColumn === oDroppedColumn) { + return; + } + + const oTable = this.byId("persoTable"); + const sDropPosition = oEvt.getParameter("dropPosition"); + const iDraggedIndex = oTable.indexOfColumn(oDraggedColumn); + const iDroppedIndex = oTable.indexOfColumn(oDroppedColumn); + const iNewPos = iDroppedIndex + (sDropPosition == "Before" ? 0 : 1) + (iDraggedIndex < iDroppedIndex ? -1 : 0); + const sKey = this._getKey(oDraggedColumn); + + Engine.getInstance().retrieveState(oTable).then(function(oState) { + + const oCol = oState.Columns.find(function(oColumn) { + return oColumn.key === sKey; + }) || { + key: sKey + }; + oCol.position = iNewPos; + + Engine.getInstance().applyState(oTable, { + Columns: [oCol] + }); + }); + }, + + onColumnResize: function(oEvt) { + const oColumn = oEvt.getParameter("column"); + const sWidth = oEvt.getParameter("width"); + const oTable = this.byId("persoTable"); + + const oColumnState = {}; + oColumnState[this._getKey(oColumn)] = sWidth; + + Engine.getInstance().applyState(oTable, { + ColumnWidth: oColumnState + }); + }, + + onClearFilterPress: function(oEvt) { + const oTable = this.byId("persoTable"); + Engine.getInstance().retrieveState(oTable).then(function(oState) { + for (var sKey in oState.Filter) { + oState.Filter[sKey].map((condition) => { + condition.filtered = false; + }); + } + Engine.getInstance().applyState(oTable, oState); + }); + } + }); +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.Engine/Engine.view.xml b/ui5/sap.m/p13n.Engine/Engine.view.xml new file mode 100644 index 000000000..7d8eaa2c8 --- /dev/null +++ b/ui5/sap.m/p13n.Engine/Engine.view.xml @@ -0,0 +1,88 @@ + + + + +
+ + + + + <ToolbarSeparator/> + <vm:VariantManagement id="p13nVm" for="persoTable"/> + <ToolbarSpacer/> + <Button icon="sap-icon://action-settings" press=".openPersoDialog" tooltip="Settings"/> + </OverflowToolbar> + </headerToolbar> + <infoToolbar> + <OverflowToolbar id="filterInfo" visible="false" design="Info" active="true" press=".onFilterInfoPress" > + <Text id="filterInfoText" wrapping="false" text="Table filter active" /> + <ToolbarSpacer /> + <Button tooltip="Remove All Filters" icon="sap-icon://decline" type="Transparent" press=".onClearFilterPress" /> + </OverflowToolbar> + </infoToolbar> + <dependents> + <plugins:ColumnResizer columnResize=".onColumnResize"/> + <columnmenu:Menu id="menu" beforeOpen=".beforeOpenColumnMenu" showTableSettingsButton="true" tableSettingsPressed=".openPersoDialog"> + <columnmenu:QuickSort change=".onSort"> + <columnmenu:items> + <columnmenu:QuickSortItem></columnmenu:QuickSortItem> + </columnmenu:items> + </columnmenu:QuickSort> + <columnmenu:QuickGroup change=".onGroup"> + <columnmenu:items> + <columnmenu:QuickGroupItem></columnmenu:QuickGroupItem> + </columnmenu:items> + </columnmenu:QuickGroup> + </columnmenu:Menu> + </dependents> + + <dragDropConfig> + <dnd:DragDropInfo sourceAggregation="columns" targetAggregation="columns" dropPosition="Between" drop=".onColumnMove"/> + </dragDropConfig> + + <noData> + <IllustratedMessage/> + </noData> + + <columns> + <Column app:p13nKey="firstName_col" headerMenu="menu"> + <header> + <Text text="First Name"/> + </header> + </Column> + <Column app:p13nKey="lastName_col" headerMenu="menu"> + <Text text="Last Name"/> + </Column> + <Column app:p13nKey="city_col" headerMenu="menu"> + <Text text="City"/> + </Column> + <Column app:p13nKey="size_col" hAlign="End" visible="false" headerMenu="menu"> + <Text text="Size"/> + </Column> + </columns> + + <items> + <ColumnListItem> + <Text text="{firstName}"/> + <Text text="{lastName}"/> + <Text text="{city}"/> + <Text text="{size}"/> + </ColumnListItem> + </items> + </Table> + + </Page> + +</mvc:View> diff --git a/ui5/sap.m/p13n.Engine/index.html b/ui5/sap.m/p13n.Engine/index.html new file mode 100644 index 000000000..d4fb1fd68 --- /dev/null +++ b/ui5/sap.m/p13n.Engine/index.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Engine + + + + + + + +
+
+ + \ No newline at end of file diff --git a/ui5/sap.m/p13n.Engine/manifest.json b/ui5/sap.m/p13n.Engine/manifest.json new file mode 100644 index 000000000..79720dd14 --- /dev/null +++ b/ui5/sap.m/p13n.Engine/manifest.json @@ -0,0 +1,32 @@ +{ + "sap.app": { + "id": "sap.m.sample.p13n.Engine", + "type": "application", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui5": { + "rootView": { + "viewName": "sap.m.sample.p13n.Engine.Engine", + "type": "XML", + "async": true, + "id": "app" + }, + "dependencies": { + "libs": { + "sap.ui.fl": {}, + "sap.ui.layout": {} + } + }, + "config": { + "sample": { + "files": [ + "Engine.view.xml", + "Engine.controller.js", + "manifest.json" + ] + } + } + } +} \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineCustomFilters/Component.js b/ui5/sap.m/p13n.EngineCustomFilters/Component.js new file mode 100644 index 000000000..5f55bf54a --- /dev/null +++ b/ui5/sap.m/p13n.EngineCustomFilters/Component.js @@ -0,0 +1,15 @@ +sap.ui.define([ + 'sap/ui/core/UIComponent' +], function(UIComponent) { + "use strict"; + + const Component = UIComponent.extend("sap.m.sample.p13n.EngineCustomFilters.Component", { + + metadata: { + manifest: "json" + } + }); + + return Component; + +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineCustomFilters/Engine.controller.js b/ui5/sap.m/p13n.EngineCustomFilters/Engine.controller.js new file mode 100644 index 000000000..7813021a1 --- /dev/null +++ b/ui5/sap.m/p13n.EngineCustomFilters/Engine.controller.js @@ -0,0 +1,260 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller', + 'sap/ui/model/json/JSONModel', + 'sap/m/p13n/Engine', + 'sap/m/p13n/FilterController', + 'sap/m/p13n/MetadataHelper', + 'sap/ui/model/Filter', + 'sap/m/Token', + 'sap/m/MultiInput', + 'sap/ui/core/Item' +], function(Controller, JSONModel, Engine, FilterController, MetadataHelper, Filter, Token, MultiInput, Item) { + "use strict"; + + return Controller.extend("sap.m.sample.p13n.EngineCustomFilters.Page", { + + onInit: function() { + const oData = { + items: [{ + key: "P1", + firstName: "Peter", + lastName: "Mueller", + size: "1.75", + city: "Walldorf" + }, + { + key: "P2", + firstName: "Petra", + lastName: "Maier", + size: "1.85", + city: "Berlin" + }, + { + key: "P3", + firstName: "Thomas", + lastName: "Smith", + size: "1.95", + city: "Berlin" + }, + { + key: "P4", + firstName: "John", + lastName: "Mueller", + size: "1.65", + city: "Walldorf" + }, + { + key: "P5", + firstName: "Maria", + lastName: "Jones", + size: "1.55", + city: "Walldorf" + }, + { + key: "P6", + firstName: "Christine", + lastName: "Smith", + size: "1.95", + city: "Manchester" + }, + { + key: "P7", + firstName: "Hobin", + lastName: "Rood", + size: "1.85", + city: "Manchester" + }, + { + key: "P8", + firstName: "Nils", + lastName: "Mueller", + size: "1.75", + city: "Walldorf" + }, + { + key: "P9", + firstName: "Helga", + lastName: "Maier", + size: "1.85", + city: "Berlin" + }, + { + key: "P10", + firstName: "Torsten", + lastName: "Smith", + size: "1.95", + city: "Berlin" + }, + { + key: "P11", + firstName: "Yannick", + lastName: "Mueller", + size: "1.65", + city: "London" + }, + { + key: "P12", + firstName: "Peter", + lastName: "Jones", + size: "1.75", + city: "Walldorf" + }, + { + key: "P13", + firstName: "Christine", + lastName: "Jones", + size: "1.65", + city: "Dresden" + }, + { + key: "P14", + firstName: "Nils", + lastName: "Maier", + size: "1.65", + city: "Manchester" + } + ] + }; + + const oModel = new JSONModel(oData); + this._oModel = oModel; + + this.getView().setModel(oModel); + + this._registerForP13n(); + }, + + onExit: function() { + Engine.getInstance().detachStateChange(this.handleStateChange, this); + }, + + _registerForP13n: function() { + const oTable = this.byId("persoTable"); + + const oMetadataHelper = new MetadataHelper([{ + key: "firstName_col", + label: "First Name", + path: "firstName" + }, + { + key: "lastName_col", + label: "Last Name", + path: "lastName" + }, + { + key: "city_col", + label: "City", + path: "city" + }, + { + key: "size_col", + label: "Size", + path: "size" + } + ]); + + this.oMetadataHelper = oMetadataHelper; + + Engine.getInstance().register(oTable, { + helper: this.oMetadataHelper, + controller: { + Filter: new FilterController({ + control: oTable, + itemFactory: function(oItem, oFilterPanel) { + const oP13nItem = oFilterPanel.getItemByKey(oItem.name); + + const multiInput = new MultiInput({ + showValueHelp: false, + showClearIcon: true, + tokenUpdate: function(oEvt) { + oEvt.getParameter("addedTokens").forEach(function(oToken) { + oP13nItem.conditions.push({ + operator: "EQ", + values: [oToken.getText()] + }); + }); + + oEvt.getParameter("removedTokens").forEach(function(oToken) { + const oRemoveCondition = oP13nItem.conditions.find(function(oConditon) { + return oConditon.values[0] == oToken.getText(); + }); + const iConditionIndex = oP13nItem.conditions.indexOf(oRemoveCondition); + oP13nItem.conditions.splice(iConditionIndex, 1); + }); + + // Use FilterPanel#setP13nData to update the FilterPanel model to create personalization changes + let aUdatedP13nData = oFilterPanel.getP13nData(); + aUdatedP13nData = aUdatedP13nData.map((oFilterPanelItem) => { + return oFilterPanelItem.name == oP13nItem.name ? oP13nItem : oFilterPanelItem; + }); + oFilterPanel.setP13nData(aUdatedP13nData); + }, + // Use FilterPanel#getP13nData & FilterPanel#getItemByKey to retrieve the existing conditions + tokens: oP13nItem.conditions.map((oConditon) => new Token({ + text: oConditon.values[0] + })), + suggestionItems: { + path: "/items", + factory: function(sId, oContext) { + return new Item({ + key: oContext.getProperty("key"), + text: `${oContext.getProperty(oMetadataHelper.getPath(oItem.name))}` + }); + } + } + }); + + return multiInput; + } + }) + } + }); + + Engine.getInstance().attachStateChange(this.handleStateChange, this); + }, + + openPersoDialog: function(oEvt) { + const oTable = this.byId("persoTable"); + + Engine.getInstance().show(oTable, ["Filter"], { + title: "Custom Filter Settings", + contentHeight: "50rem", + contentWidth: "45rem", + source: oEvt.getSource() + }); + }, + + _getKey: function(oControl) { + return oControl.data("p13nKey"); + }, + + handleStateChange: function(oEvt) { + const oTable = this.byId("persoTable"); + const oState = oEvt.getParameter("state"); + + if (!oState) { + return; + } + + //Create Filters & Sorters + const aFilter = this.createFilters(oState); + + //rebind the table with the updated cell template + oTable.getBinding("items").filter(aFilter); + + }, + + createFilters: function(oState) { + const aFilter = []; + Object.keys(oState.Filter).forEach((sFilterKey) => { + const filterPath = this.oMetadataHelper.getProperty(sFilterKey).path; + + oState.Filter[sFilterKey].forEach(function(oConditon) { + aFilter.push(new Filter(filterPath, oConditon.operator, oConditon.values[0])); + }); + }); + + return aFilter; + } + }); +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineCustomFilters/Engine.view.xml b/ui5/sap.m/p13n.EngineCustomFilters/Engine.view.xml new file mode 100644 index 000000000..bfbd785aa --- /dev/null +++ b/ui5/sap.m/p13n.EngineCustomFilters/Engine.view.xml @@ -0,0 +1,87 @@ + + + + +
+ + + + + <ToolbarSeparator/> + <vm:VariantManagement id="p13nVm" for="persoTable"/> + <ToolbarSpacer/> + <Button icon="sap-icon://action-settings" press=".openPersoDialog" tooltip="Settings"/> + </OverflowToolbar> + </headerToolbar> + + <dependents> + <plugins:ColumnResizer/> + <columnmenu:Menu id="menu"> + <columnmenu:QuickSort> + <columnmenu:items> + <columnmenu:QuickSortItem></columnmenu:QuickSortItem> + </columnmenu:items> + </columnmenu:QuickSort> + <columnmenu:QuickGroup> + <columnmenu:items> + <columnmenu:QuickGroupItem></columnmenu:QuickGroupItem> + </columnmenu:items> + </columnmenu:QuickGroup> + <columnmenu:items> + <columnmenu:ActionItem icon="sap-icon://sort" label="Sort"/> + <columnmenu:ActionItem icon="sap-icon://group-2" label="Group"/> + <columnmenu:ActionItem icon="sap-icon://table-column" label="Columns"/> + </columnmenu:items> + </columnmenu:Menu> + </dependents> + + <dragDropConfig> + <dnd:DragDropInfo sourceAggregation="columns" targetAggregation="columns" dropPosition="Between"/> + </dragDropConfig> + + <noData> + <IllustratedMessage/> + </noData> + + <columns> + <Column app:p13nKey="firstName_col" headerMenu="menu"> + <header> + <Text text="First Name"/> + </header> + </Column> + <Column app:p13nKey="lastName_col" headerMenu="menu"> + <Text text="Last Name"/> + </Column> + <Column app:p13nKey="city_col" headerMenu="menu"> + <Text text="City"/> + </Column> + <Column app:p13nKey="size_col" hAlign="End" headerMenu="menu"> + <Text text="Size"/> + </Column> + </columns> + + <items> + <ColumnListItem> + <Text text="{firstName}"/> + <Text text="{lastName}"/> + <Text text="{city}"/> + <Text text="{size}"/> + </ColumnListItem> + </items> + </Table> + + </Page> + +</mvc:View> diff --git a/ui5/sap.m/p13n.EngineCustomFilters/index.html b/ui5/sap.m/p13n.EngineCustomFilters/index.html new file mode 100644 index 000000000..a665e042c --- /dev/null +++ b/ui5/sap.m/p13n.EngineCustomFilters/index.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>EngineCustomFilters + + + + + + + +
+
+ + \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineCustomFilters/manifest.json b/ui5/sap.m/p13n.EngineCustomFilters/manifest.json new file mode 100644 index 000000000..b15f5639b --- /dev/null +++ b/ui5/sap.m/p13n.EngineCustomFilters/manifest.json @@ -0,0 +1,32 @@ +{ + "sap.app": { + "id": "sap.m.sample.p13n.Engine", + "type": "application", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui5": { + "rootView": { + "viewName": "sap.m.sample.p13n.EngineCustomFilters.Engine", + "type": "XML", + "async": true, + "id": "app" + }, + "dependencies": { + "libs": { + "sap.ui.fl": {}, + "sap.ui.layout": {} + } + }, + "config": { + "sample": { + "files": [ + "Engine.view.xml", + "Engine.controller.js", + "manifest.json" + ] + } + } + } +} \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineGridList/Component.js b/ui5/sap.m/p13n.EngineGridList/Component.js new file mode 100644 index 000000000..81e5093b4 --- /dev/null +++ b/ui5/sap.m/p13n.EngineGridList/Component.js @@ -0,0 +1,15 @@ +sap.ui.define([ + 'sap/ui/core/UIComponent' +], function(UIComponent) { + "use strict"; + + const Component = UIComponent.extend("sap.m.sample.p13n.EngineGridListComponent", { + + metadata: { + manifest: "json" + } + }); + + return Component; + +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineGridList/Engine.controller.js b/ui5/sap.m/p13n.EngineGridList/Engine.controller.js new file mode 100644 index 000000000..7b17b1d8b --- /dev/null +++ b/ui5/sap.m/p13n.EngineGridList/Engine.controller.js @@ -0,0 +1,130 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller', + 'sap/ui/model/json/JSONModel', + 'sap/m/p13n/Engine', + 'sap/m/p13n/SelectionController', + 'sap/m/p13n/MetadataHelper' +], function(Controller, JSONModel, Engine, SelectionController, MetadataHelper) { + "use strict"; + + return Controller.extend("sap.m.sample.p13n.EngineGridList.Page", { + + onInit: function() { + const oData = { + items: [{ + key: "person1", + firstName: "Peter", + lastName: "Mueller", + size: "1.75", + city: "Walldorf" + }, + { + key: "person2", + firstName: "Petra", + lastName: "Maier", + size: "1.85", + city: "Walldorf" + }, + { + key: "person3", + firstName: "Thomas", + lastName: "Smith", + size: "1.95", + city: "Walldorf" + }, + { + key: "person4", + firstName: "Maria", + lastName: "Jones", + size: "1.55", + city: "Walldorf" + }, + { + key: "person5", + firstName: "John", + lastName: "Williams", + size: "1.65", + city: "Walldorf" + } + ] + }; + + const oModel = new JSONModel(oData); + + this.getView().setModel(oModel); + + this._registerForP13n(); + }, + + _registerForP13n: function() { + const oGridList = this.byId("persoList"); + + this.oMetadataHelper = new MetadataHelper([{ + key: "person1", + label: "Peter Mueller" + }, + { + key: "person2", + label: "Petra Maier" + }, + { + key: "person3", + label: "Thomas Smith" + }, + { + key: "person4", + label: "Maria Jones" + }, + { + key: "person5", + label: "John Williams" + } + ]); + + Engine.getInstance().register(oGridList, { + helper: this.oMetadataHelper, + controller: { + Items: new SelectionController({ + targetAggregation: "items", + getKeyForItem: function(oListItem) { + return oListItem.getBindingContext().getProperty("key"); + }, + control: oGridList + }) + } + }); + + Engine.getInstance().attachStateChange(this.handleStateChange, this); + }, + + onExit: function() { + Engine.getInstance().detachStateChange(this.handleStateChange, this); + }, + + openPersoDialog: function(oEvt) { + const oGridList = this.byId("persoList"); + + Engine.getInstance().show(oGridList, ["Items"], { + contentHeight: "35rem", + contentWidth: "32rem", + source: oEvt.getSource() + }); + }, + + handleStateChange: function(oEvt) { + const oState = oEvt.getParameter("state"); + + const aPersonData = this.getView().getModel().getProperty("/items"); + + const aUpdatedPersonData = []; + oState.Items.forEach(function(oStateItem, iIndex) { + const oModelItem = aPersonData.find(function(oModelItem) { + return oModelItem.key === oStateItem.key; + }); + aUpdatedPersonData.push(oModelItem); + }); + + this.getView().getModel().setProperty("/items", aUpdatedPersonData); + } + }); +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineGridList/Engine.view.xml b/ui5/sap.m/p13n.EngineGridList/Engine.view.xml new file mode 100644 index 000000000..bd75794e2 --- /dev/null +++ b/ui5/sap.m/p13n.EngineGridList/Engine.view.xml @@ -0,0 +1,65 @@ + + + + + + + + <ToolbarSeparator/> + <vm:VariantManagement id="p13nVm" for="persoList"/> + <ToolbarSpacer/> + <Button icon="sap-icon://action-settings" press=".openPersoDialog"/> + </content> + </Toolbar> + + <f:GridList id="persoList" items="{path: '/items'}" sap.ui.fl:flexibility="sap/m/flexibility/EngineFlex"> + <f:items> + <CustomListItem type="Active"> + <layoutData> + <FlexItemData + growFactor="1" + shrinkFactor="0"/> + </layoutData> + <HBox justifyContent="SpaceBetween"> + <VBox + justifyContent="SpaceBetween" + class="sapUiSmallMarginTop sapUiSmallMarginBegin"> + <VBox app:p13nKey="firstName"> + <Title text="First Name"/> + <Label text="{firstName}"/> + </VBox> + <VBox app:p13nKey="lastName"> + <Title text="Last Name"/> + <Label text="{lastName}"/> + </VBox> + <VBox app:p13nKey="city"> + <Title text="City"/> + <Label text="{city}"/> + </VBox> + <VBox app:p13nKey="size"> + <Title text="Size"/> + <Label text="{size}"/> + </VBox> + </VBox> + <core:Icon + src="sap-icon://customer" + size="2.5rem" + class="sapUiSmallMarginTop sapUiSmallMarginEnd sapUiSmallMarginBottom"/> + </HBox> + </CustomListItem> + </f:items> + </f:GridList> + </VBox> +</mvc:View> diff --git a/ui5/sap.m/p13n.EngineGridList/index.html b/ui5/sap.m/p13n.EngineGridList/index.html new file mode 100644 index 000000000..5f17164ea --- /dev/null +++ b/ui5/sap.m/p13n.EngineGridList/index.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>EngineGridList + + + + + + + +
+
+ + \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineGridList/manifest.json b/ui5/sap.m/p13n.EngineGridList/manifest.json new file mode 100644 index 000000000..b7963f441 --- /dev/null +++ b/ui5/sap.m/p13n.EngineGridList/manifest.json @@ -0,0 +1,32 @@ +{ + "sap.app": { + "id": "sap.m.sample.p13n.EngineGridList", + "type": "application", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui5": { + "rootView": { + "viewName": "sap.m.sample.p13n.EngineGridList.Engine", + "type": "XML", + "async": true, + "id": "app" + }, + "dependencies": { + "libs": { + "sap.ui.fl": {}, + "sap.ui.layout": {} + } + }, + "config": { + "sample": { + "files": [ + "Engine.view.xml", + "Engine.controller.js", + "manifest.json" + ] + } + } + } +} \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineGridTable/Component.js b/ui5/sap.m/p13n.EngineGridTable/Component.js new file mode 100644 index 000000000..a266342a2 --- /dev/null +++ b/ui5/sap.m/p13n.EngineGridTable/Component.js @@ -0,0 +1,15 @@ +sap.ui.define([ + 'sap/ui/core/UIComponent' +], function(UIComponent) { + "use strict"; + + const Component = UIComponent.extend("sap.m.sample.p13n.EngineGridTableComponent", { + + metadata: { + manifest: "json" + } + }); + + return Component; + +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineGridTable/Engine.controller.js b/ui5/sap.m/p13n.EngineGridTable/Engine.controller.js new file mode 100644 index 000000000..54dffbb2c --- /dev/null +++ b/ui5/sap.m/p13n.EngineGridTable/Engine.controller.js @@ -0,0 +1,238 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller', + 'sap/ui/model/json/JSONModel', + 'sap/m/p13n/Engine', + 'sap/m/p13n/SelectionController', + 'sap/m/p13n/SortController', + 'sap/m/p13n/GroupController', + 'sap/m/p13n/MetadataHelper', + 'sap/ui/model/Sorter', + 'sap/ui/core/library', + 'sap/m/table/ColumnWidthController' +], function(Controller, JSONModel, Engine, SelectionController, SortController, GroupController, MetadataHelper, Sorter, CoreLibrary, ColumnWidthController) { + "use strict"; + + return Controller.extend("sap.m.sample.p13n.EngineGridTable.Page", { + + onInit: function() { + const oData = { + items: [{ + firstName: "Peter", + lastName: "Mueller", + size: "1.75", + city: "Walldorf" + }, + { + firstName: "Petra", + lastName: "Maier", + size: "1.85", + city: "Walldorf" + }, + { + firstName: "Thomas", + lastName: "Smith", + size: "1.95", + city: "Heidelberg" + }, + { + firstName: "John", + lastName: "Williams", + size: "1.65", + city: "Walldorf" + }, + { + firstName: "Maria", + lastName: "Jones", + size: "1.55", + city: "Walldorf" + } + ] + }; + + const oModel = new JSONModel(oData); + + this.getView().setModel(oModel); + + this._registerForP13n(); + }, + + onExit: function() { + Engine.getInstance().detachStateChange(this.handleStateChange, this); + }, + + _registerForP13n: function() { + const oTable = this.byId("persoTable"); + + this.oMetadataHelper = new MetadataHelper([{ + key: "firstName_col", + label: "First Name", + path: "firstName" + }, + { + key: "lastName_col", + label: "Last Name", + path: "lastName" + }, + { + key: "city_col", + label: "City", + path: "city" + }, + { + key: "size_col", + label: "Size", + path: "size" + } + ]); + + this._mIntialWidth = { + "firstName_col": "11rem", + "lastName_col": "11rem", + "city_col": "11rem", + "size_col": "11rem" + }; + + Engine.getInstance().register(oTable, { + helper: this.oMetadataHelper, + controller: { + Columns: new SelectionController({ + targetAggregation: "columns", + control: oTable + }), + Sorter: new SortController({ + control: oTable + }), + Groups: new GroupController({ + control: oTable + }), + ColumnWidth: new ColumnWidthController({ + control: oTable + }) + } + }); + + Engine.getInstance().attachStateChange(this.handleStateChange, this); + }, + + openPersoDialog: function(oEvt) { + const oTable = this.byId("persoTable"); + + Engine.getInstance().show(oTable, ["Columns", "Sorter"], { + contentHeight: "35rem", + contentWidth: "32rem", + source: oEvt.getSource() + }); + }, + + onColumnHeaderItemPress: function(oEvt) { + const oTable = this.byId("persoTable"); + const sPanel = oEvt.getSource().getIcon().indexOf("sort") >= 0 ? "Sorter" : "Columns"; + + Engine.getInstance().show(oTable, [sPanel], { + contentHeight: "35rem", + contentWidth: "32rem", + source: oTable + }); + }, + + onSort: function(oEvt) { + const oTable = this.byId("persoTable"); + const sAffectedProperty = this._getKey(oEvt.getParameter("column")); + const sSortOrder = oEvt.getParameter("sortOrder"); + + //Apply the state programatically on sorting through the column menu + //1) Retrieve the current personalization state + Engine.getInstance().retrieveState(oTable).then(function(oState) { + + //2) Modify the existing personalization state --> clear all sorters before + oState.Sorter.forEach(function(oSorter) { + oSorter.sorted = false; + }); + oState.Sorter.push({ + key: sAffectedProperty, + descending: sSortOrder === CoreLibrary.SortOrder.Descending + }); + + //3) Apply the modified personalization state to persist it in the VariantManagement + Engine.getInstance().applyState(oTable, oState); + }); + }, + + onColumnMove: function(oEvt) { + const oTable = this.byId("persoTable"); + const oAffectedColumn = oEvt.getParameter("column"); + const iNewPos = oEvt.getParameter("newPos"); + const sKey = this._getKey(oAffectedColumn); + oEvt.preventDefault(); + + Engine.getInstance().retrieveState(oTable).then(function(oState) { + + const oCol = oState.Columns.find(function(oColumn) { + return oColumn.key === sKey; + }) || { + key: sKey + }; + oCol.position = iNewPos; + + Engine.getInstance().applyState(oTable, { + Columns: [oCol] + }); + }); + }, + + _getKey: function(oControl) { + return oControl.data("p13nKey"); + }, + + handleStateChange: function(oEvt) { + const oTable = this.byId("persoTable"); + const oState = oEvt.getParameter("state"); + + if (!oState) { + return; + } + + oTable.getColumns().forEach(function(oColumn) { + + const sKey = this._getKey(oColumn); + const sColumnWidth = oState.ColumnWidth[sKey]; + + oColumn.setWidth(sColumnWidth || this._mIntialWidth[sKey]); + + oColumn.setVisible(false); + oColumn.setSortOrder(CoreLibrary.SortOrder.None); + }.bind(this)); + + oState.Columns.forEach(function(oProp, iIndex) { + const oCol = this.byId("persoTable").getColumns().find((oColumn) => oColumn.data("p13nKey") === oProp.key); + oCol.setVisible(true); + + oTable.removeColumn(oCol); + oTable.insertColumn(oCol, iIndex); + }.bind(this)); + + const aSorter = []; + oState.Sorter.forEach(function(oSorter) { + const oColumn = this.byId("persoTable").getColumns().find((oColumn) => oColumn.data("p13nKey") === oSorter.key); + /** @deprecated As of version 1.120 */ + oColumn.setSorted(true); + oColumn.setSortOrder(oSorter.descending ? CoreLibrary.SortOrder.Descending : CoreLibrary.SortOrder.Ascending); + aSorter.push(new Sorter(this.oMetadataHelper.getProperty(oSorter.key).path, oSorter.descending)); + }.bind(this)); + oTable.getBinding("rows").sort(aSorter); + }, + + onColumnResize: function(oEvt) { + const oColumn = oEvt.getParameter("column"); + const sWidth = oEvt.getParameter("width"); + const oTable = this.byId("persoTable"); + + const oColumnState = {}; + oColumnState[this._getKey(oColumn)] = sWidth; + + Engine.getInstance().applyState(oTable, { + ColumnWidth: oColumnState + }); + } + }); +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineGridTable/Engine.view.xml b/ui5/sap.m/p13n.EngineGridTable/Engine.view.xml new file mode 100644 index 000000000..a8e18c4cd --- /dev/null +++ b/ui5/sap.m/p13n.EngineGridTable/Engine.view.xml @@ -0,0 +1,61 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + diff --git a/ui5/sap.m/p13n.EngineGridTable/index.html b/ui5/sap.m/p13n.EngineGridTable/index.html new file mode 100644 index 000000000..fc29000da --- /dev/null +++ b/ui5/sap.m/p13n.EngineGridTable/index.html @@ -0,0 +1,35 @@ + + + + + + EngineGridTable + + + + + + + +
+
+ + \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineGridTable/manifest.json b/ui5/sap.m/p13n.EngineGridTable/manifest.json new file mode 100644 index 000000000..8d90ccb91 --- /dev/null +++ b/ui5/sap.m/p13n.EngineGridTable/manifest.json @@ -0,0 +1,32 @@ +{ + "sap.app": { + "id": "sap.m.sample.p13n.EngineGridTable", + "type": "application", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui5": { + "rootView": { + "viewName": "sap.m.sample.p13n.EngineGridTable.Engine", + "type": "XML", + "async": true, + "id": "app" + }, + "dependencies": { + "libs": { + "sap.ui.fl": {}, + "sap.ui.layout": {} + } + }, + "config": { + "sample": { + "files": [ + "Engine.view.xml", + "Engine.controller.js", + "manifest.json" + ] + } + } + } +} \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineMultipleController/Component.js b/ui5/sap.m/p13n.EngineMultipleController/Component.js new file mode 100644 index 000000000..fc186c97a --- /dev/null +++ b/ui5/sap.m/p13n.EngineMultipleController/Component.js @@ -0,0 +1,15 @@ +sap.ui.define([ + 'sap/ui/core/UIComponent' +], function(UIComponent) { + "use strict"; + + const Component = UIComponent.extend("sap.m.sample.p13n.EngineMultipleController.Component", { + + metadata: { + manifest: "json" + } + }); + + return Component; + +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineMultipleController/Engine.controller.js b/ui5/sap.m/p13n.EngineMultipleController/Engine.controller.js new file mode 100644 index 000000000..e592dfd5b --- /dev/null +++ b/ui5/sap.m/p13n.EngineMultipleController/Engine.controller.js @@ -0,0 +1,195 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller', + 'sap/ui/model/json/JSONModel', + 'sap/m/p13n/Engine', + 'sap/m/p13n/SelectionController', + 'sap/m/p13n/MetadataHelper', + 'sap/ui/core/library' +], function (Controller, JSONModel, Engine, SelectionController, MetadataHelper, coreLibrary) { + "use strict"; + + return Controller.extend("sap.m.sample.p13n.EngineMultipleController.Page", { + + onInit: function () { + this._registerForP13n(); + }, + + onExit: function() { + Engine.getInstance().detachStateChange(this.handleStateChange, this); + }, + + _registerForP13n: function () { + const oTable = this.byId("persoTable"); + + this.oMetadataHelper = new MetadataHelper([{ + key: "id_col", + label: "ID", + path: "id" + }, + { + key: "firstName_col", + label: "First Name", + path: "firstName" + }, + { + key: "lastName_col", + label: "Last Name", + path: "lastName" + }, + { + key: "city_col", + label: "City", + path: "city" + }, + { + key: "size_col", + label: "Size", + path: "size" + } + ]); + + const _oMetadataHelperRows = new MetadataHelper([{ + key: "P1", + label: "Peter Müller", + path: "id" + }, + { + key: "P2", + label: "Petra Maier", + path: "id" + }, + { + key: "P3", + label: "Thomas Smith", + path: "id" + }, + { + key: "P4", + label: "John Williams", + path: "id" + }, + { + key: "P5", + label: "Maria Jones", + path: "id" + } + ]); + + Engine.getInstance().register(oTable, { + helper: this.oMetadataHelper, + controller: { + Columns: new SelectionController({ + targetAggregation: "columns", + control: oTable, + persistenceIdentifier: "selection-columns" + }), + Rows: new SelectionController({ + targetAggregation: "items", + helper: _oMetadataHelperRows, + control: oTable, + persistenceIdentifier: "selection-items", + enableReorder: false + }) + } + }); + + Engine.getInstance().attachStateChange(this.handleStateChange, this); + }, + + openPersoDialog: function (oEvt) { + const oTable = this.byId("persoTable"); + + Engine.getInstance().show(oTable, ["Columns"], { + contentHeight: "35rem", + contentWidth: "32rem", + source: oEvt.getSource() + }); + }, + + openPersoDialogPeople: function (oEvt) { + const oTable = this.byId("persoTable"); + + Engine.getInstance().show(oTable, ["Rows"], { + contentHeight: "35rem", + contentWidth: "32rem", + source: oEvt.getSource() + }); + }, + + _getKey: function (oControl) { + return oControl.data("p13nKey"); + }, + + handleStateChange: function (oEvt) { + const oTable = this.byId("persoTable"); + const oState = oEvt.getParameter("state"); + + if (!oState) { + return; + } + + oTable.getColumns().forEach(function (oColumn, iIndex) { + oColumn.setVisible(false); + oColumn.setSortIndicator(coreLibrary.SortOrder.None); + oColumn.data("grouped", false); + }); + + oState.Columns.forEach(function (oProp, iIndex) { + const oCol = this.byId("persoTable").getColumns().find((oColumn) => oColumn.data("p13nKey") === oProp.key); + if (oCol) { + oCol.setVisible(true); + + oTable.removeColumn(oCol); + oTable.insertColumn(oCol, iIndex); + } + }.bind(this)); + + oTable.getItems().forEach(function (oItem, iIndex) { + oItem.setVisible(false); + }); + + oState.Rows.forEach(function (oProp, iIndex) { + const aItems = this.byId("persoTable").getItems(); + // var oRelevantCol = aItems[0].getCells().find((cell) => true); + + // find index of cell with "id", that can be used later + const oFoundItem = aItems.find((oItem) => oItem.getCells()[0].getText() == oProp.key); + + oFoundItem.setVisible(true); + + oTable.removeItem(oFoundItem); + oTable.insertItem(oFoundItem, iIndex); + }.bind(this)); + }, + + onColumnMove: function (oEvt) { + const oDraggedColumn = oEvt.getParameter("draggedControl"); + const oDroppedColumn = oEvt.getParameter("droppedControl"); + + if (oDraggedColumn === oDroppedColumn) { + return; + } + + const oTable = this.byId("persoTable"); + const sDropPosition = oEvt.getParameter("dropPosition"); + const iDraggedIndex = oTable.indexOfColumn(oDraggedColumn); + const iDroppedIndex = oTable.indexOfColumn(oDroppedColumn); + const iNewPos = iDroppedIndex + (sDropPosition == "Before" ? 0 : 1) + (iDraggedIndex < iDroppedIndex ? -1 : 0); + const sKey = this._getKey(oDraggedColumn); + + Engine.getInstance().retrieveState(oTable).then(function (oState) { + + const oCol = oState.Columns.find(function (oColumn) { + return oColumn.data("p13nKey") === sKey; + }) || { + key: sKey + }; + oCol.position = iNewPos; + + Engine.getInstance().applyState(oTable, { + Columns: [oCol] + }); + }); + } + }); +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineMultipleController/Engine.view.xml b/ui5/sap.m/p13n.EngineMultipleController/Engine.view.xml new file mode 100644 index 000000000..30060ba53 --- /dev/null +++ b/ui5/sap.m/p13n.EngineMultipleController/Engine.view.xml @@ -0,0 +1,107 @@ + + + + + + + + + + <ToolbarSeparator/> + <vm:VariantManagement id="p13nVm" for="persoTable"/> + <ToolbarSpacer/> + <Button icon="sap-icon://action-settings" press=".openPersoDialog" tooltip="Settings"/> + <Button icon="sap-icon://add-employee" press=".openPersoDialogPeople" tooltip="Settings"/> + </OverflowToolbar> + </headerToolbar> + + <dependents> + <columnmenu:Menu id="menu"> + <columnmenu:items> + <columnmenu:ActionItem icon="sap-icon://table-column" label="Columns" press=".openPersoDialog"/> + </columnmenu:items> + </columnmenu:Menu> + </dependents> + + <dragDropConfig> + <dnd:DragDropInfo sourceAggregation="columns" targetAggregation="columns" dropPosition="Between" drop=".onColumnMove"/> + </dragDropConfig> + + <noData> + <IllustratedMessage/> + </noData> + + <columns> + <Column app:p13nKey="id_col" headerMenu="menu"> + <header> + <Text text="ID"/> + </header> + </Column> + <Column app:p13nKey="firstName_col" headerMenu="menu"> + <Text text="First Name"/> + </Column> + <Column app:p13nKey="lastName_col" headerMenu="menu"> + <Text text="Last Name"/> + </Column> + <Column app:p13nKey="city_col" headerMenu="menu"> + <Text text="City"/> + </Column> + <Column app:p13nKey="size_col" hAlign="End" visible="false" headerMenu="menu"> + <Text text="Size"/> + </Column> + </columns> + + <items> + <ColumnListItem app:p13nKey="P1"> + <Text text="P1"/> + <Text text="Peter"/> + <Text text="Mueller"/> + <Text text="Walldorf"/> + <Text text="1.75"/> + </ColumnListItem> + <ColumnListItem app:p13nKey="P2"> + <Text text="P2"/> + <Text text="Petra"/> + <Text text="Maier"/> + <Text text="Walldorf"/> + <Text text="1.85"/> + </ColumnListItem> + <ColumnListItem app:p13nKey="P3"> + <Text text="P3"/> + <Text text="Thomas"/> + <Text text="Smith"/> + <Text text="Walldorf"/> + <Text text="1.95"/> + </ColumnListItem> + <ColumnListItem app:p13nKey="P4"> + <Text text="P4"/> + <Text text="John"/> + <Text text="Williams"/> + <Text text="Walldorf"/> + <Text text="1.65"/> + </ColumnListItem> + <ColumnListItem app:p13nKey="P5"> + <Text text="P5"/> + <Text text="Maria"/> + <Text text="Jones"/> + <Text text="Walldorf"/> + <Text text="1.55"/> + </ColumnListItem> + </items> + </Table> + + </Page> + +</mvc:View> diff --git a/ui5/sap.m/p13n.EngineMultipleController/index.html b/ui5/sap.m/p13n.EngineMultipleController/index.html new file mode 100644 index 000000000..d2fd1c879 --- /dev/null +++ b/ui5/sap.m/p13n.EngineMultipleController/index.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>EngineMultipleController + + + + + + + +
+
+ + \ No newline at end of file diff --git a/ui5/sap.m/p13n.EngineMultipleController/manifest.json b/ui5/sap.m/p13n.EngineMultipleController/manifest.json new file mode 100644 index 000000000..c292fc368 --- /dev/null +++ b/ui5/sap.m/p13n.EngineMultipleController/manifest.json @@ -0,0 +1,32 @@ +{ + "sap.app": { + "id": "sap.m.sample.p13n.EngineMultipleController", + "type": "application", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui5": { + "rootView": { + "viewName": "sap.m.sample.p13n.EngineMultipleController.Engine", + "type": "XML", + "async": true, + "id": "app" + }, + "dependencies": { + "libs": { + "sap.ui.fl": {}, + "sap.ui.layout": {} + } + }, + "config": { + "sample": { + "files": [ + "Engine.view.xml", + "Engine.controller.js", + "manifest.json" + ] + } + } + } +} \ No newline at end of file diff --git a/ui5/sap.m/p13n.Popup/Component.js b/ui5/sap.m/p13n.Popup/Component.js new file mode 100644 index 000000000..ef997d566 --- /dev/null +++ b/ui5/sap.m/p13n.Popup/Component.js @@ -0,0 +1,15 @@ +sap.ui.define([ + 'sap/ui/core/UIComponent' +], function(UIComponent) { + "use strict"; + + const Component = UIComponent.extend("sap.m.sample.p13n.Popup.Component", { + + metadata: { + manifest: "json" + } + }); + + return Component; + +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.Popup/P13nPanels.controller.js b/ui5/sap.m/p13n.Popup/P13nPanels.controller.js new file mode 100644 index 000000000..102b0d761 --- /dev/null +++ b/ui5/sap.m/p13n.Popup/P13nPanels.controller.js @@ -0,0 +1,125 @@ +sap.ui.define([ + 'sap/ui/core/mvc/Controller', + 'sap/ui/model/json/JSONModel', + 'sap/m/MessageToast' +], function(Controller, JSONModel, MessageToast) { + "use strict"; + + return Controller.extend("sap.m.sample.p13n.Popup.Page", { + + onInit: function() { + this._oCurrentP13nData = null; + this.getView().setModel(new JSONModel({ + dialogMode: true, + listLayout: true + })); + + this._bIsOpen = false; + }, + + _initialData: { + columns: [{ + visible: true, + name: "key1", + label: "City" + }, + { + visible: false, + name: "key2", + label: "Country" + }, + { + visible: false, + name: "key3", + label: "Region" + } + ], + sort: [{ + sorted: true, + name: "key1", + label: "City", + descending: true + }, + { + sorted: false, + name: "key2", + label: "Country", + descending: false + }, + { + sorted: false, + name: "key3", + label: "Region", + descending: false + } + ], + group: [{ + grouped: true, + name: "key1", + label: "City" + }, + { + grouped: false, + name: "key2", + label: "Country" + }, + { + grouped: false, + name: "key3", + label: "Region" + } + ] + }, + + _setInitialData: function() { + const oView = this.getView(); + + const oSelectionPanel = oView.byId("columnsPanel"); + const oSortPanel = oView.byId("sortPanel"); + const oGroupPanel = oView.byId("groupPanel"); + + oSelectionPanel.setP13nData(this._initialData.columns); + oSortPanel.setP13nData(this._initialData.sort); + oGroupPanel.setP13nData(this._initialData.group); + }, + + onContainerOpen: function(oEvt) { + const oView = this.getView(); + const oPopup = oView.byId("p13nPopup"); + if (!this._bIsOpen) { + this._setInitialData(); + this._bIsOpen = true; + } + + oPopup.open(oEvt.getSource()); + }, + + onClose: function(oEvt) { + const sReason = oEvt.getParameter("reason"); + MessageToast.show("Dialog close reason: " + sReason); + }, + + reset: function(oEvt) { + this._setInitialData(); + this.parseP13nState(); + }, + + parseP13nState: function(oEvt) { + + if (oEvt) { + MessageToast.show("P13n panel change reason:" + oEvt.getParameter("reason")); + } + + const oView = this.getView(); + const oEditor = oView.byId("p13nEditor"); + + const oP13nState = { + columns: oView.byId("columnsPanel").getP13nData(), + sort: oView.byId("sortPanel").getP13nData(), + group: oView.byId("groupPanel").getP13nData() + }; + + oEditor.setValue(JSON.stringify(oP13nState, null, ' ')); + } + }); +}); \ No newline at end of file diff --git a/ui5/sap.m/p13n.Popup/P13nPanels.view.xml b/ui5/sap.m/p13n.Popup/P13nPanels.view.xml new file mode 100644 index 000000000..206538013 --- /dev/null +++ b/ui5/sap.m/p13n.Popup/P13nPanels.view.xml @@ -0,0 +1,26 @@ + + + + +