From b4fa38ace97d52103e8e8155046dcbceba110034 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 23 Aug 2026 14:31:02 +0000 Subject: [PATCH] Leave the overview app off the page in web/ Z2UI5_CL_SMPS_APP_000 is this same catalogue rendered inside a system, and as a card on https://abap2ui5.github.io/samples-stack/ it answered the page's own question with a contradiction: "Needs nothing beyond abap2UI5", on a page whose premise is that every sample here needs something from the system. It also took a technology chip of its own that filtered ten groups down to one entry, itself. So the cut happens in generate-web-index.mjs, before the page ever sees it: the class and its Overview group are dropped, and the page shows 31 samples in 9 groups where SAMPLES.md and catalogue.json keep showing 32 - their reader is inside the repository already, and there the overview app is a sample somebody starts. The page names it in "How to run one" instead, which is where a way of browsing belongs rather than a thing to browse for. Consequences: - scan-samples.mjs exports OVERVIEW_CLASS, so the two generators behind the page name the class from one place. - generate-screenshots.mjs photographs what the page draws a card for and therefore skips it too - a picture no card loads is a render per deploy for nothing. Measured again: 18 of 31 app views render, the same 13 skips. - web/stack.js loses every `DATA.overviewApp` special case: every package it draws now has a branch and a README, so the package line, the Branch link and the package card are unconditional again, and apps.json no longer carries the field. Verified with a headless render of the page against a freshly generated apps.json: 31 cards, nine chips, no APP_000, every card with its three links. --- AGENTS.md | 11 ++++++++++- scripts/generate-screenshots.mjs | 16 ++++++++++------ scripts/generate-web-index.mjs | 25 +++++++++++++++++++++---- scripts/lib/read-packages.mjs | 6 +++++- scripts/lib/scan-samples.mjs | 12 +++++++++++- web/README.md | 13 +++++++++++++ web/index.html | 3 ++- web/stack.js | 29 +++++++++++++++++------------ 8 files changed, 89 insertions(+), 26 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 5726863..96b6f04 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -340,6 +340,15 @@ what matters here: and the README's package table (what a package plays together with). Adding a sample or a package therefore needs **no step for the page**: `npm run samples:md`, and it is on both. +- **The overview app is not on it.** `Z2UI5_CL_SMPS_APP_000` is this same + catalogue inside a system, and as a card it contradicted the page: *needs + nothing beyond abap2UI5*, on a page built around what a sample needs from the + system — plus a technology chip that filtered ten groups down to itself. + `generate-web-index.mjs` drops the class and its group (and + `generate-screenshots.mjs` takes no picture of it), the page names it in *How + to run one* instead, and `SAMPLES.md` and `catalogue.json` keep it — their + reader is in the repository already. So the page shows **31 samples in 9 + groups** where the two catalogues show 32. - **`web/apps.json` is generated and not committed** — `npm run web:index` writes it, `deploy-web` writes it again on every deploy. A committed copy would put a diff of derived data on every sample pull request. @@ -353,7 +362,7 @@ what matters here: A view the harness cannot render is reported and skipped, and the page treats the missing file as "no picture" (the `` removes itself), so a card without a thumbnail is normal, not broken. Measured over the corpus - (2026-08): **19 of 32 app views render.** The 13 skips are three stable + (2026-08): **18 of 31 app views render.** The 13 skips are three stable categories — `sap.ui.comp` controls (SAPUI5-only, absent from the harness's OpenUI5 runtime: 7 of the 9 Smart Controls samples), `z2ui5.cc` custom controls that do not load headless (the WebSocket, MIME-audio and diff --git a/scripts/generate-screenshots.mjs b/scripts/generate-screenshots.mjs index 2de4a1d..da215b8 100644 --- a/scripts/generate-screenshots.mjs +++ b/scripts/generate-screenshots.mjs @@ -20,7 +20,7 @@ * sample pull request carries no binary diff. The page treats a missing * picture as "no picture" (the removes itself), so this script is * allowed to skip what it cannot photograph. Measured over the whole corpus - * (2026-08): 19 of 32 app views render; the three skip reasons are stable and + * (2026-08): 18 of 31 app views render; the three skip reasons are stable and * documented in AGENTS.md §8 - `sap.ui.comp` is SAPUI5-only and not in the * harness's OpenUI5 runtime, `z2ui5.cc` custom controls do not load headless, * and the mock model seeds an empty ObjectStatus state. Each skipped card @@ -41,7 +41,7 @@ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import { screenshotFiles } from '@abap2ui5/linter'; -import { scanSamples } from './lib/scan-samples.mjs'; +import { scanSamples, OVERVIEW_CLASS } from './lib/scan-samples.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const argOut = process.argv.indexOf('--out'); @@ -63,10 +63,14 @@ const SIZE = { width: 800, height: 600 }; * would take all pictures with it. */ const CHUNK = 25; -/* Every app of the repository, the same scan the page itself is built from - - * helpers (behavior pools, demo data, the APC protocol class) have no card - * and get no picture. */ -const apps = scanSamples(ROOT).filter((s) => s.isApp).slice(0, LIMIT); +/* Every app the page shows a card for, the same scan and the same cut the page + * itself is built from - helpers (behavior pools, demo data, the APC protocol + * class) have no card and get no picture, and neither does the overview app, + * which generate-web-index.mjs leaves off the page (it says why). Photographing + * it would cost a render per deploy for a file nothing loads. */ +const apps = scanSamples(ROOT) + .filter((s) => s.isApp && s.cls !== OVERVIEW_CLASS) + .slice(0, LIMIT); fs.mkdirSync(OUT, { recursive: true }); let written = 0; diff --git a/scripts/generate-web-index.mjs b/scripts/generate-web-index.mjs index 062c143..ca1e362 100644 --- a/scripts/generate-web-index.mjs +++ b/scripts/generate-web-index.mjs @@ -28,6 +28,17 @@ * cannot work is worse than no link, so the cards link into the SOURCE and * into the package README that says how to set the sample up. * + * THE OVERVIEW APP IS NOT ON THIS PAGE. `Z2UI5_CL_SMPS_APP_000` is this same + * catalogue rendered inside a system, and as a card it answered the page's own + * question with a contradiction — *needs nothing beyond abap2UI5*, on a page + * whose premise is that everything here needs something from the system — while + * taking a technology chip of its own that filtered ten groups down to itself. + * It is a way to browse the corpus, not something to browse the corpus for, so + * the page names it in *How to run one* and leaves the cards to the samples. + * Dropped here rather than in web/stack.js: the page draws what it is given, + * and SAMPLES.md and catalogue.json still carry the overview app, because a + * reader of those is inside the repository already. + * * Where every fact comes from — no fact is restated here, all of them are read * out of what the repository already keeps: * @@ -56,7 +67,7 @@ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; -import { scanSamples, sampleTitle } from './lib/scan-samples.mjs'; +import { scanSamples, sampleTitle, OVERVIEW_CLASS } from './lib/scan-samples.mjs'; import { packages, OVERVIEW_PKG } from './lib/read-packages.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); @@ -148,11 +159,18 @@ function abapDoc(source) { /* `count` is the page's own derived state — apps per group, for the chips — * so it is added here rather than carried by the shared package merge. */ -const byDir = new Map(packages(ROOT).map((p) => [p.dir, { ...p, count: 0 }])); +const byDir = new Map(packages(ROOT) + .filter((p) => p.dir !== OVERVIEW_PKG.dir) + .map((p) => [p.dir, { ...p, count: 0 }])); const all = scanSamples(ROOT); const apps = []; -for (const s of all.filter((x) => x.isApp)) { +/* The overview app and its group, left out for the reason at the top of this + * file. It is the only app of `src/` itself, so dropping the class and dropping + * the group are the same cut made twice — and it has to happen before the + * unknown-package check below, which is there to catch an app that landed in a + * subpackage by accident. */ +for (const s of all.filter((x) => x.isApp && x.cls !== OVERVIEW_CLASS)) { const pkg = byDir.get(s.pkg); /* A subpackage — src/03/01 holds the business object, not an app. If an app * ever lands in one, the page would silently lose it, so say so instead. */ @@ -176,7 +194,6 @@ const index = { repo: REPO, source: SOURCE, tree: TREE, - overviewApp: OVERVIEW_PKG.dir, packages: [...byDir.values()], apps, }; diff --git a/scripts/lib/read-packages.mjs b/scripts/lib/read-packages.mjs index 3142f61..ea62fdb 100644 --- a/scripts/lib/read-packages.mjs +++ b/scripts/lib/read-packages.mjs @@ -31,7 +31,11 @@ import path from 'path'; * branch's own syntax version, and the lowest of those is v740sp08 — so * 7.40 SP08 is measured, exactly like the numbers in packages.json. Cloud * likewise: the overview resolves every sample by name at runtime and calls no - * on-premise API, which is what puts it on the cloud-capable branches. */ + * on-premise API, which is what puts it on the cloud-capable branches. + * + * The page in web/ is the one consumer that drops this group again — there the + * overview app is not a sample of the stack but the same catalogue in a system, + * and generate-web-index.mjs says why. catalogue.json keeps it. */ export const OVERVIEW_PKG = { dir: '.', branch: 'main', diff --git a/scripts/lib/scan-samples.mjs b/scripts/lib/scan-samples.mjs index ee5cd64..bb5c3b2 100644 --- a/scripts/lib/scan-samples.mjs +++ b/scripts/lib/scan-samples.mjs @@ -129,6 +129,16 @@ export function scanSamples(root) { return out.sort((a, b) => a.pkg.localeCompare(b.pkg) || a.cls.localeCompare(b.cls)); } +/** + * The overview app — the catalogue of this repository inside a system. + * + * An app like any other to abapGit, to the checks and to SAMPLES.md, and the + * one app the page in web/ leaves out (generate-web-index.mjs says why). The + * two generators behind that page name it from here rather than each keeping + * a copy of the string. + */ +export const OVERVIEW_CLASS = 'z2ui5_cl_smps_app_000'; + /* * The overview app's own catalogue, read back out — for the COMPLETENESS check * only, no longer as a source of text. @@ -150,7 +160,7 @@ export function scanSamples(root) { */ const ENTRY = /sample\(\s*no\s*=\s*`([^`]*)`[\s\S]*?title\s*=\s*`([^`]*)`[\s\S]*?detail\s*=\s*`([^`]*)`[\s\S]*?classname\s*=\s*`([^`]*)`/g; -export function scanOverview(root, overviewClass = 'z2ui5_cl_smps_app_000') { +export function scanOverview(root, overviewClass = OVERVIEW_CLASS) { const file = path.join(root, 'src', `${overviewClass}.clas.abap`); const text = fs.readFileSync(file, 'utf8'); const byClass = new Map(); diff --git a/web/README.md b/web/README.md index b1acb74..f8c6cc1 100644 --- a/web/README.md +++ b/web/README.md @@ -27,6 +27,17 @@ one scan (`scripts/lib/scan-samples.mjs`) so they cannot disagree: | the package READMEs | somebody who has already picked a technology | | this page | somebody who has installed nothing and is asking whether their system can run any of it | +**The overview app is the one view that is not itself a card here.** It is this +same catalogue rendered inside a system, so as a card it said *needs nothing +beyond abap2UI5* on a page whose whole premise is that every sample needs +something from the system, and it took a technology chip of its own that +filtered the corpus down to one entry — itself. `generate-web-index.mjs` drops +the class and its group before the page ever sees them, and *How to run one* +names it in prose instead, where a way of browsing belongs. It stays in +[`SAMPLES.md`](../SAMPLES.md) and in +[`catalogue.json`](../catalogue.json), whose readers are inside the repository +already. + That last question is what makes this page different from the two next door. [samples](https://abap2ui5.github.io/samples/) publishes a learning path, because *"where do I start"* is what a newcomer arrives with; @@ -147,6 +158,8 @@ reported and skipped — the `sap.ui.comp` smart controls (SAPUI5-only, not in the harness's OpenUI5 runtime) and the `z2ui5.cc` custom controls, mostly — and the `` removes itself when its file is missing, so a card without a thumbnail is complete, not broken. AGENTS.md §8 carries the measured count. +The script photographs exactly what the page draws a card for, so it skips the +overview app too — a picture no card loads is a render per deploy for nothing. ## Running it locally diff --git a/web/index.html b/web/index.html index 926fe8f..d958305 100644 --- a/web/index.html +++ b/web/index.html @@ -122,7 +122,8 @@

How to run one

Every card copies that for you. Or start Z2UI5_CL_SMPS_APP_000, the overview app — the same catalogue inside your system, which lists what is installed and greys out what - is not. + is not. It is the one app of this repository with no card above, because it + is this catalogue rather than a sample of the stack. diff --git a/web/stack.js b/web/stack.js index 43d78a5..e0a5c7b 100644 --- a/web/stack.js +++ b/web/stack.js @@ -20,8 +20,15 @@ * APC channel, a launchpad. Each app would open there and fail, so the links * go to the source and to the package README that says how to set it up. * - * THE TECHNOLOGY FACET IS CHIPS, not a select: ten values, and seeing all - * ten at once is half the answer to "what is even in this repository". + * THE TECHNOLOGY FACET IS CHIPS, not a select: nine values, and seeing all + * nine at once is half the answer to "what is even in this repository". + * + * THE OVERVIEW APP IS NOT IN apps.json, and nothing here has to know that: + * `Z2UI5_CL_SMPS_APP_000` is this same catalogue inside a system, not a + * sample of the stack, and generate-web-index.mjs leaves it and its group + * out (it says why). So every package here has a branch and a README of its + * own, and every app belongs to one — which is what lets this file draw a + * card and a package without asking whether it is the special one. */ /* ------------------------------------------------------------------ state */ @@ -172,10 +179,9 @@ function drawPackageLine(f) { els.pkgline.innerHTML = ` ${esc(p.title)} — ${md(p.topic)}. Plays together with ${md(p.needs)}. Runs on ${esc(p.runsOn)}. - ${p.dir === DATA.overviewApp ? '' : ` - Install it alone from the branch - ${esc(p.branch)}, - or read its README.`} + Install it alone from the branch + ${esc(p.branch)}, + or read its README. ${p.note ? `
${md(p.note)}` : ''}`; } @@ -230,8 +236,7 @@ function card(app, tokens) {
Source ↗ Setup ↗ - ${app.pkg === DATA.overviewApp ? '' : - `Branch ↗`} + Branch ↗
`; } @@ -246,10 +251,10 @@ function drawPackages() {

${md(p.topic)}

Plays together with ${md(p.needs)}

- ${p.dir === DATA.overviewApp ? 'src' : `src/${esc(p.dir)}`} · + src/${esc(p.dir)} · ${esc(p.runsOn)} · - ${p.count} sample${p.count === 1 ? '' : 's'} - ${p.dir === DATA.overviewApp ? '' : ` · ${esc(p.branch)}`} + ${p.count} sample${p.count === 1 ? '' : 's'} · + ${esc(p.branch)}

${p.note ? `

${md(p.note)}

` : ''} `).join(''); @@ -316,7 +321,7 @@ async function boot() { for (const app of DATA.apps) app.hay = haystack(app, PKG.get(app.pkg)); els.total.textContent = String(DATA.apps.length); - els.pkgcount.textContent = String(DATA.packages.filter((p) => p.dir !== DATA.overviewApp).length); + els.pkgcount.textContent = String(DATA.packages.length); buildFacets(); drawPackages();