Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,14 @@
"runsOn": "Cloud + Standard ≥ 7.40 SP08",
"syntax": "v740sp08",
"shared": []
},
{
"dir": "10",
"branch": "10-ai-llm",
"title": "AI / LLM",
"runsOn": "Cloud + Standard ≥ 7.40 SP08",
"syntax": "v751",
"note": "The HTTP transport comes once per stack, and each half activates on its own stack only: src/10/01 (cl_http_client on an SM59 destination) on Standard, src/10/02 (cl_web_http_client_manager on a BTP destination) on ABAP Cloud, src/10/03 only where SAP's ABAP AI SDK is installed. An activation error for the half your system does not have is expected - the samples create the transport by name and use the one that is there. That is also why this branch is linted at 7.51 although the package runs from 7.40 SP08: everything but src/10/02 parses at 7.40 SP08, and src/10/02 is ABAP Cloud code whose released enums need 7.51 syntax.",
"shared": []
}
]
4 changes: 2 additions & 2 deletions .github/workflows/create-package-branches.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ name: create-package-branches
# Every branch is verified before it is pushed: abaplint at the release that
# package declares, which is what keeps the "Runs on" column of the README
# honest and what catches a package that has quietly grown a dependency on one
# of the other eight. On a pull request the whole thing runs except the push,
# of the other nine. On a pull request the whole thing runs except the push,
# so a change that would break a branch fails while it can still be fixed.

on:
Expand All @@ -32,7 +32,7 @@ concurrency:
# pushes to main share refs/heads/main and the newest wins, which is what we
# want - a superseded run would publish older content. A pull request run
# gets its own group. Sharing one group across refs would let a pull request
# cancel a main run mid-publish and leave the nine branches half updated,
# cancel a main run mid-publish and leave the ten branches half updated,
# some at the new main and some at the old, without anything going red.
group: create-package-branches-${{ github.ref }}
cancel-in-progress: true
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ is a link to the class file, which is the qualification.

## 3. The generated one-package branches

abapGit imports a whole repository; there is no sparse checkout. Nine packages
abapGit imports a whole repository; there is no sparse checkout. Ten packages
with different floors would mean a system that wants OData also takes APC and
gets activation errors for technology it never asked for. So every package is
force-pushed to its own branch by `create-package-branches.yaml`, and the
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ npm ci
npm run check # abaplint + abap2UI5-linter + the overview check
```

`npm run check` is what CI runs. Work on `main`; the nine package branches are
`npm run check` is what CI runs. Work on `main`; the ten package branches are
generated and force-pushed from it, so anything committed there is lost at the
next build.
33 changes: 26 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[![abap version](https://img.shields.io/badge/abap%20version-standard%20%28%E2%89%A5%201909%29-blue)](#setup)
[![namespace](https://img.shields.io/badge/namespace-z2ui5__cl__smps-blue)](abaplint.jsonc)
[![abap2UI5](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fabap2UI5%2Fsamples-stack%2Fbadges%2Fabap2ui5.json)](#what-is-in-here)
[![AI-ready: llms.txt · skills · MCP](https://img.shields.io/badge/AI--ready-llms.txt%20%C2%B7%20skills%20%C2%B7%20MCP-blue)](https://abap2ui5.github.io/docs/get_started/ai.html)
<br>
<br>
[![abap-standard](https://github.com/abap2UI5/samples-stack/actions/workflows/abap-standard.yaml/badge.svg)](https://github.com/abap2UI5/samples-stack/actions/workflows/abap-standard.yaml)
Expand All @@ -20,7 +21,7 @@
# abap2UI5 — samples-stack

**Learn how abap2UI5 plays with your stack — OData, RAP, Smart Controls,
WebSockets, the Fiori Launchpad and more.**
WebSockets, the Fiori Launchpad, language models and more.**

abap2UI5 is more than a standalone framework for building apps. At its core it
is deliberately agnostic: it makes no assumption about where your data comes
Expand All @@ -30,8 +31,8 @@ plugs into what your system already offers.

This repository shows exactly that. OData, Smart Controls, RAP with and without
draft, RAP business events, stateful sessions and ABAP locks, WebSockets via
AMC/APC, the MIME repository, the Fiori Launchpad — abap2UI5 works alongside
each of them, and each one keeps doing what it is good at. Nothing here
AMC/APC, the MIME repository, the Fiori Launchpad, a large language model over
HTTPS — abap2UI5 works alongside each of them, and each one keeps doing what it is good at. Nothing here
replaces an existing technology; everything here complements one. Whether you
use any of it is entirely up to you — *everything is possible, nothing is
required*.
Expand All @@ -51,9 +52,19 @@ for and try it out — the others can wait until you need them.
> card says what the sample needs from that system before you install
> anything.

Building with an AI coding agent? The
[AI page](https://abap2ui5.github.io/docs/get_started/ai.html) of the
documentation sets up the skills and the
[MCP server](https://github.com/abap2UI5/mcp-server) — whose sample search
covers every sample here:
`claude mcp add abap2ui5 -- npx --yes -p @abap2ui5/mcp-server abap2ui5-mcp`.
The Claude Code plugin is two commands:
`/plugin marketplace add abap2UI5/abap2UI5`, then
`/plugin install abap2ui5@abap2ui5`.

## Which package do I need?

Most readers need exactly one. The nine areas are unrelated technologies, none
Most readers need exactly one. The ten areas are unrelated technologies, none
depends on another — so find the row that says what you came to do, take that
package, and skip the rest:

Expand All @@ -68,6 +79,7 @@ package, and skip the rest:
| Push messages from ABAP into every open browser tab, without JavaScript | [`src/07`](src/07/README.md) — AMC/APC | on-premise; activate one ICF node in `SICF` |
| Play or serve a file the MIME repository already holds | [`src/08`](src/08/README.md) — MIME Play Audio | on-premise; activate one ICF service in `SICF` |
| Expose your app in the Fiori Launchpad — tile, startup parameters, cross-app navigation | [`src/09`](src/09/README.md) — Launchpad | a launchpad with a tile pointing at abap2UI5 |
| Call a large language model from your app — a chat, or a table summarized by AI | [`src/10`](src/10/README.md) — AI / LLM | an HTTPS destination to an LLM endpoint (SM59 or BTP), or SAP's ABAP AI SDK |

Each package README opens with a **What you need** section that turns the last
column into concrete steps; the table below adds the exact release floors.
Expand All @@ -85,6 +97,7 @@ column into concrete steps; the table below adds the exact release floors.
| [`src/07`](src/07) | **[AMC/APC](src/07/README.md)** — a news feed over WebSocket | on-premise APC/AMC, the ICF node `Z2UI5_APC_SMP_2` | Standard only, ≥ 7.50 |
| [`src/08`](src/08) | **[MIME Play Audio](src/08/README.md)** — play a sound from the MIME repository | the ICF service `/SAP/PUBLIC/BC/ABAP/mime_demo` | Standard only, ≥ 7.50 |
| [`src/09`](src/09) | **[Launchpad](src/09/README.md)** — startup parameters, shell title, cross-app navigation | a Fiori Launchpad with a tile pointing at abap2UI5 | Cloud + Standard ≥ 7.40 SP08 |
| [`src/10`](src/10) | **[AI / LLM](src/10/README.md)** — chat with a language model, summarize a table with AI | an HTTPS destination to an LLM endpoint (SM59 or BTP), or SAP's ABAP AI SDK | Cloud + Standard ≥ 7.40 SP08 |

The numbering is a reading order, not a dependency chain: `01` starts where
most systems already are — an activated OData service — and each package from
Expand Down Expand Up @@ -125,6 +138,11 @@ is the higher of two floors:
business events lift `05` to 2021. If `RAISE ENTITY EVENT` does not activate on
your system, `05` is out of reach and nothing else in this repository is
affected.
- *the HTTP client of the stack.* `10` calls a language model over HTTPS, and
the two stacks release different clients for that — `cl_http_client` on an
SM59 destination on Standard, `cl_web_http_client_manager` on ABAP Cloud. So
the package carries one small transport class per stack, each activating on
its own stack only, and the samples pick whichever is there at runtime.

The repository **as a whole** therefore asks for 1909, because `03`–`05` do. A
single package can ask for much less — which matters if you are only here for one
Expand All @@ -133,7 +151,7 @@ of them.
## Setup

1. Install [abap2UI5](https://github.com/abap2UI5/abap2UI5).
2. Pull this repository with [abapGit](https://abapgit.org) — `main` for all nine
2. Pull this repository with [abapGit](https://abapgit.org) — `main` for all ten
packages, or the branch of the single package you came for (see
[One package at a time](#one-package-at-a-time)). `main` as a whole runs on
ABAP Platform >= 1909 or a BTP ABAP Environment — that is what EML asks for,
Expand Down Expand Up @@ -166,7 +184,7 @@ It is also the honest answer to *what does my system actually support*: the
overview looks every sample up at runtime instead of referencing it statically, so
a package your release cannot activate — or one you never installed — is listed
with its Open button disabled and a Status saying so, rather than taking the whole
overview down. Start it first, and the list tells you which of the nine packages
overview down. Start it first, and the list tells you which of the ten packages
this system can run.

## One package at a time
Expand All @@ -192,6 +210,7 @@ overview app and nothing else:
| [`07-amc-apc`](../../tree/07-amc-apc) | [`src/07`](src/07) — AMC/APC | Standard only, ≥ 7.50 |
| [`08-mime`](../../tree/08-mime) | [`src/08`](src/08) — MIME Play Audio | Standard only, ≥ 7.50 |
| [`09-launchpad`](../../tree/09-launchpad) | [`src/09`](src/09) — Launchpad | Cloud + Standard ≥ 7.40 SP08 |
| [`10-ai-llm`](../../tree/10-ai-llm) | [`src/10`](src/10) — AI / LLM | Cloud + Standard ≥ 7.40 SP08 |

The overview app ships on every branch and keeps listing **every sample in the
repository**, so it stays the catalogue of what the other branches hold — the
Expand Down Expand Up @@ -264,7 +283,7 @@ in CI. The node checks carry no dependencies, so they take seconds.
| `check-prose-names` | every class name written in prose exists — including the sibling repositories' |
| `check-framework-pin` | the abaplint config pins abap2UI5 to a release tag, never to whatever is on `main` |
| `check-catalogue` | `catalogue.json` and `catalogue-derived.json` are in sync with the tree — and with them every package has a README row that parses, every app sits in a package, and none is missing its `@summary` or `@keywords` |
| `create-package-branches` | rebuilds the nine per-package branches, each verified with abaplint at its own release before it is pushed |
| `create-package-branches` | rebuilds the ten per-package branches, each verified with abaplint at its own release before it is pushed |

`check-overview` exists because the overview app names its samples as strings and
resolves them at runtime — that is what lets it survive a package the system cannot
Expand Down
23 changes: 20 additions & 3 deletions SAMPLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# The sample catalogue

Every app in this repository — 32 of them — with what it shows and a
Every app in this repository — 35 of them — with what it shows and a
link to its source. This is the [overview app](src/z2ui5_cl_smps_app_000.clas.abap)
as a page you can read here, before installing anything.

Expand Down Expand Up @@ -108,12 +108,21 @@ type who does not know it exists. `Ctrl+F` on this page uses them.
| Cross-App Navigation Sender<br>hands two values over to another tile<br><sub>launchpad fiori flp cross app navigation sender intent</sub> | [`Z2UI5_CL_SMPS_APP_483`](src/09/z2ui5_cl_smps_app_483.clas.abap) |
| Cross-App Navigation Receiver<br>reads them back out of its startup parameters<br><sub>launchpad fiori flp cross app navigation receiver intent</sub> | [`Z2UI5_CL_SMPS_APP_484`](src/09/z2ui5_cl_smps_app_484.clas.abap) |

### AI / LLM — `src/10`

| Sample | Class |
|---|---|
| Settings and Connection Test<br>where the two AI samples get their model from - provider, destination, model and key, saved once and tested with one press<br><sub>ai llm chat settings configuration destination sm59 islm</sub> | [`Z2UI5_CL_SMPS_APP_013`](src/10/z2ui5_cl_smps_app_013.clas.abap) |
| Chat with a Language Model<br>a chat with a real language model over HTTPS - the conversation goes out, the answer comes back, the provider is configuration<br><sub>ai llm chat chatbot feedinput feedlistitem anthropic openai</sub> | [`Z2UI5_CL_SMPS_APP_014`](src/10/z2ui5_cl_smps_app_014.clas.abap) |
| Summarize a Table with AI<br>a table of sales figures and one button - the rows go to a language model as context, its summary comes back into a panel<br><sub>ai llm chat summarize table prompt hygiene anthropic</sub> | [`Z2UI5_CL_SMPS_APP_015`](src/10/z2ui5_cl_smps_app_015.clas.abap) |

---

## Not samples

8 classes here are not apps and carry no tile: behavior pools,
demo data, an event consumer and the generated APC protocol class. They are
16 classes here are not apps and carry no tile: behavior pools,
demo data, an event consumer, the generated APC protocol class and the
language-model layer the AI samples call. They are
reached **by** a sample rather than looked up, which is why they are exempt from
the keyword rule — but a catalogue that claims to account for the tree has to be
able to say they exist.
Expand All @@ -128,3 +137,11 @@ able to say they exist.
| [`Z2UI5_CL_SMPS_BP_TCK`](src/05/01/z2ui5_cl_smps_bp_tck.clas.abap) | RAP Events Demo - Ticket Behavior Pool |
| [`Z2UI5_CL_SMPS_EVT_TCK`](src/05/01/z2ui5_cl_smps_evt_tck.clas.abap) | RAP Events Demo - Local Event Consumer (writes log) |
| [`Z2UI5_CL_SMPS_APP_489_WS`](src/07/z2ui5_cl_smps_app_489_ws.clas.abap) | Generated APC WebSocket protocol impementation class |
| [`Z2UI5_CL_SMPS_LLM_CLAUDE`](src/10/z2ui5_cl_smps_llm_claude.clas.abap) | LLM - Anthropic Messages API |
| [`Z2UI5_CL_SMPS_LLM_FACTORY`](src/10/z2ui5_cl_smps_llm_factory.clas.abap) | LLM - Configuration and Provider Factory |
| [`Z2UI5_CL_SMPS_LLM_JSON`](src/10/z2ui5_cl_smps_llm_json.clas.abap) | LLM - JSON Written and Read by Hand |
| [`Z2UI5_CL_SMPS_LLM_OPENAI`](src/10/z2ui5_cl_smps_llm_openai.clas.abap) | LLM - OpenAI-Compatible Chat Completions |
| [`Z2UI5_CX_SMPS_LLM`](src/10/z2ui5_cx_smps_llm.clas.abap) | LLM - Exception |
| [`Z2UI5_CL_SMPS_LLM_SM59`](src/10/01/z2ui5_cl_smps_llm_sm59.clas.abap) | LLM - HTTP Transport over an SM59 Destination |
| [`Z2UI5_CL_SMPS_LLM_CLOUD`](src/10/02/z2ui5_cl_smps_llm_cloud.clas.abap) | LLM - HTTP Transport for ABAP Cloud |
| [`Z2UI5_CL_SMPS_LLM_ISLM`](src/10/03/z2ui5_cl_smps_llm_islm.clas.abap) | LLM - SAP ABAP AI SDK (ISLM) |
15 changes: 11 additions & 4 deletions catalogue-derived.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,19 @@
"sap.m.QuickView",
"sap.m.QuickViewPage",
"sap.m.ToggleButton",
"z2ui5.cc.Websocket"
"z2ui5.cc.Websocket",
"sap.m.CheckBox",
"sap.m.Select",
"sap.ui.core.Item",
"sap.m.ObjectNumber"
],
"counts": {
"samples": 32,
"controls": 50,
"samples": 35,
"controls": 54,
"noChain": 0
},
"samples": [
{"class":"Z2UI5_CL_SMPS_APP_000","minUi5":"1.71","needs":[],"controls":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],"controlCount":216},
{"class":"Z2UI5_CL_SMPS_APP_000","minUi5":"1.71","needs":[],"controls":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17],"controlCount":238},
{"class":"Z2UI5_CL_SMPS_APP_001","minUi5":"1.71","needs":[],"controls":[1,22,37,7,10,17,38],"controlCount":21},
{"class":"Z2UI5_CL_SMPS_APP_002","minUi5":"1.71","needs":[],"controls":[1,39,22,37,7,10,17,38],"controlCount":22},
{"class":"Z2UI5_CL_SMPS_APP_003","minUi5":"1.71","needs":[],"controls":[1,2,3,22,7,10,11,12,13,18,17],"controlCount":19},
Expand All @@ -78,6 +82,9 @@
{"class":"Z2UI5_CL_SMPS_APP_010","minUi5":"1.71","needs":[],"controls":[1,2,3,39,40,22,37,6,7,10,11,12,13,18,41,15,17,38],"controlCount":55},
{"class":"Z2UI5_CL_SMPS_APP_011","minUi5":"1.71","needs":[],"controls":[1,2,3,22,37,7,10,11,12,13,18,41,17,38],"controlCount":29},
{"class":"Z2UI5_CL_SMPS_APP_012","minUi5":"1.71","needs":[],"controls":[1,2,3,7,10,11,12,13,18,41,17],"controlCount":18},
{"class":"Z2UI5_CL_SMPS_APP_013","minUi5":"1.71","needs":[],"controls":[1,50,22,37,5,23,7,51,10,41,52,17,38],"controlCount":28},
{"class":"Z2UI5_CL_SMPS_APP_014","minUi5":"1.71","needs":[],"controls":[1,43,44,22,45,5,7,10,14,17],"controlCount":11},
{"class":"Z2UI5_CL_SMPS_APP_015","minUi5":"1.71","needs":[],"controls":[1,2,3,22,37,5,53,7,8,10,11,12,14,17],"controlCount":38},
{"class":"Z2UI5_CL_SMPS_APP_313","minUi5":"1.71","needs":[],"controls":[7,10,19,20,21,17],"controlCount":6},
{"class":"Z2UI5_CL_SMPS_APP_314","minUi5":"1.71","needs":[],"controls":[2,3,22,7,10,11,12,13,18,17],"controlCount":31},
{"class":"Z2UI5_CL_SMPS_APP_315","minUi5":"1.71","needs":[],"controls":[2,3,7,10,11,12,13,18,17],"controlCount":35},
Expand Down
Loading
Loading