You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 47c457b
Browse filesBrowse the repository at this point in the historyBrowse files
feat(console): after a reload, the package page still says how many sample records a purge would delete (#30653)
<!-- claude-projects-attribution: {"github_login":"os-sales"} -->
_Requested by **Sales** · [project
thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4Uu562dBE8bEQM37ezqErQj94)_
domain:ui#6 · os-sales · session_01L6bhgTRFYJtEzJqfKEhD7C
Fixes#30616
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:已装应用的详情页每次打开都会去读服务端 #30613
新接口给出的「此刻清除会删几条示例记录」,清除确认框和离开页面后的横幅都用这个数;刷新页面后不再丢失。
- 为什么改:#30537 只在本次浏览器会话里装过才知道条数,刷新后确认框说不出会删几条,横幅也不再出现。
- 风险与回滚:只多一个只读 GET,不碰清除逻辑和匹配规则;读不到时退回原来的会话内数字。确认框那句文案在 10
种语言里去掉了「即本次安装载入的数量」半句(键不变,没有新增键,首屏 en 包 gzip 反而少 9 字节)。回滚即还原本 PR。
- 先看:`MarketplacePackagePage.tsx` 新增的读数 effect 与
`localSampleCount`;`sampleDataNotice.ts` 的 `noteServedSampleCount`
和代次判断;`en.ts` 的 `purgeConfirmAtMost`。
- 两分钟验证:`cd ui && pnpm exec vitest run
packages/app-shell/src/console/marketplace/__tests__/MarketplacePackagePage.sampleDataNotice-30323.test.tsx`,预期
20 个全绿,其中 #30616 两个 describe 共 8 个。
- 需要你做的:无,席位落地。
## What changes
PR #30613 added `GET
/api/v1/marketplace/install-local/:manifestId/sample-data`, which
answers how many rows a sample-data purge would delete right now,
counted with the purge's own matcher and keep-rules. The console only
knew a count for an install made in the same browser session (PR
#30537); after a reload the purge confirm had no count and the banner
that follows the installer to the app was gone.
- **`marketplaceApi.countLocalSampleData(manifestId)`** reads that route
and answers `{ manifestId, count, unidentified }`, or `null` when the
read is refused, fails, or carries no non-negative integer `count`.
- **The package page reads the count on every visit** of a local install
the runtime loaded (not for a `notLoaded` entry), and again every time
the install-local listing is read, which already happens after an
install, a reseed and a purge. The answer goes into the existing session
record (`sampleDataNotice.ts`) through the new `noteServedSampleCount`:
- a count above zero updates the record in place, or starts one when
this session had none (a standing banner and a pending confirm request
stay with it);
- `count: 0` drops the record and withdraws its banner.
- **Freshness.** A read that began before an install, reseed or purge of
this session answered is older than that answer and is ignored: the
record keeps a per-package generation that those three answers bump, and
the read compares the generation it saw when it started. The effect's
cleanup also drops a superseded read. A failed read changes nothing, so
the confirm keeps the count this session's install answered.
- **The confirm** now reads its count when it is drawn
(`localSampleCount`), so a count that lands while it is open reaches it;
the state keeps only the target. A cloud purge draws no count, as
before.
- **The banner** needs no change of its own: it is raised on leaving
from the session record, so a served count above zero raises it after a
reload too, and `count: 0` leaves nothing to raise.
- **Copy, no new key.** `marketplace.detail.purgeConfirmAtMost` said the
count was "the number this install loaded", false for the runtime's
count. All 10 packs drop that clause and keep the upper bound, e.g. en
`Up to {{count}} sample records will be deleted.`, zh `最多删除 {{count}}
条示例记录。`, ru reworded to `не более {{count}} …` with the
singular-genitive `_one`. The upper bound holds for both sources: the
served count is exact, and the session count is at most what a purge
deletes. The eager `en` pack shrinks (see Verification); `#30588`'s
ceiling is untouched.
`unidentified` is read but not drawn: saying it needs a new string,
which the eager `en` pack has no room for until #30588 moves strings to
a lazy namespace.
## Tests
`ui/packages/app-shell/src/console/marketplace/__tests__/MarketplacePackagePage.sampleDataNotice-30323.test.tsx`
is this surface's shared harness, so the new pins are two top-level
`describe`s there (one stubbed `fetch` routed by path; the real
`marketplaceApi`):
- a visit with no install this session reads the count once and the
confirm draws `count=42`;
- that count raises the banner on leaving;
- `count: 0` drops a record the session held: no count line in the
confirm, no banner on leaving;
- after an in-session install of 369, the re-read count 360 is the one
the confirm draws, and the install note keeps 369;
- CONTROL: a refused read (403) keeps the install's 369;
- CONTROL: a `notLoaded` entry is never counted;
- unit: a read whose generation predates an install's answer does not
replace it; one taken after does, and `0` drops the record.
Support edits: 13 suites that mock `../marketplaceApi` gain
`countLocalSampleData: async () => null`, and the offline local-menu
suite (`…offlineLocalMenu-11627.test.tsx`) now calls `cleanup()` before
`vi.unstubAllGlobals()`, because a reseed or purge re-reads the count
after the test body returns and that read reached a socket once the
double was gone.
## Acceptance notes
- Every listing read now brings one more GET (the count). The listing is
read on visit and after install, reseed and purge only.
- A visit to the package page of an app holding sample data now raises
the leave banner even when this session did not install it. That is the
card's ask ("read the count on any visit"); the banner is dismissable
and a purge withdraws it.
- `unidentified` is not drawn (no string budget, see above).
- **Merge order with PR #30640** (lane card #30588, which moves the
marketplace strings out of the eager packs into a lazy `marketplace`
namespace): this PR changes the values of the `purgeConfirmAtMost`
family in `ui/packages/i18n/src/locales/*.ts`. Whichever of the two
lands second carries the new values into the namespace files; if PR
#30640 lands first, this branch merges `main` and moves the change
there.
## Verification
<details><summary>Ablation: the count read removed, 5 of the new pins go
red</summary>
`node scripts/ablation-replace.mjs --file
ui/packages/app-shell/src/console/marketplace/MarketplacePackagePage.tsx
--anchor 'const served = await countLocalSampleData(manifestId);'
--replacement 'const served = null as …;' -- …vitest run
…sampleDataNotice-30323.test.tsx`: anchor 1 → 0, blob `3ab826d5e075 →
87d8ee093b8e`; `Tests 5 failed | 15 passed (20)` (the five page-level
#30616 pins); restored, blob == HEAD and `git diff HEAD` empty. The
app-shell suite reads this page from `src/` (relative import), so no
build sits between the mutation and the run.
</details>
<details><summary>Eager en pack, gzip bytes (the CI Build & E2E UI
ceiling is 60,000)</summary>
Console built from this branch (`turbo run build
--filter='@object-ui/console^...'`, then `CI=true vite build` in
`ui/apps/console`); `dist/eager-closure.json` reads
`assets/i18n-locale-en-*.js` at 192,979 raw / **59,942** gzip. The same
chunk with the three old `purgeConfirmAtMost` strings swapped back in,
re-gzipped with `zlib.gzipSync` (level 6, what the report uses): 193,081
raw / **59,951** gzip. So −9 B gzip, −102 B raw. `node
scripts/check-eager-closure-budget.mjs` (in `ui/`): exit 0.
</details>
<details><summary>Local tests and gates</summary>
All on head `eef04e97` (this branch merged with `main` at `af8aab1b`)
unless noted. Lock readings are the lock's own VERDICT lines.
- `pnpm --dir ui exec vitest run packages/i18n/
packages/app-shell/src/console/marketplace/` (after rebuilding
`@object-ui/app-shell^...` on the merged tree): Test Files 146 passed
(146), Tests 1898 passed, 13 skipped.
- `pnpm --filter @object-ui/app-shell run type-check` (source and
tests): exit 0, on `5581ff5d` (the merge brought no file under
`ui/packages/app-shell` or `ui/packages/i18n`).
- `pnpm --dir ui exec vitest run scripts/`: 170 files passed, 2 skipped;
4970 tests passed.
- `node ui/scripts/check-i18n-en-drift.mjs --base origin/main`: exit 0,
every changed en value followed by all nine packs. `pnpm --dir ui run
check:i18n-keys`: exit 0 (4,210 keys). `node
ui/scripts/check-eager-closure-budget.mjs`: exit 0 (on `5581ff5d`'s
console build).
- eslint on every changed source and test: 0 errors; the warnings are
pre-existing `no-explicit-any` / one unused var in the page.
- `node scripts/pm/dispatch-gates.mjs --commands`: 35 derived families,
every one exit 0; `--ran` reconciles 35 run, 0 NOT-MEASURED, 0 UNRUN.
- **NOT MEASURED: the whole `@object-ui/app-shell` suite** (2,303 test
files; stopped after 40 minutes at `--maxWorkers=2` on a shared box).
The local run is narrowed to the marketplace directory and the i18n
package, the two trees whose files this diff changes or whose mocks name
the API it extends; `Test UI` runs the rest.
**Live stack** (showcase `objectstack dev --fresh`, the fake marketplace
control plane from #30325's rig, console via vite; evidence in the
project's shared files, not committed):
- curl, rig package with 3 seed records: count 3 after install, still 3
after a user adds a record of their own, purge answers `deleted: 3`,
count 0 after, the user's record stays.
- Browser, a 13-record package installed through the API and the package
page then opened fresh (no install answer in this browser session): two
`GET …/sample-data` reads; the ⋯ menu's purge confirm reads `Up to 13
sample records will be deleted.`; leaving the page by its back link
raises `"Acme Deals" has sample data.` with the purge action. After a
purge (`deleted: 13`, count 0), a fresh visit and leave raises no
banner.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L6bhgTRFYJtEzJqfKEhD7C)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
feat(console): after a reload, the package page still says how many sample records a purge would delete
7
+
8
+
Clause-②: no
9
+
Metadata-protocol: none
10
+
11
+
-**The count on any visit.** The package page of a local install now reads the runtime's count of the sample rows a purge would delete right now (`GET /api/v1/marketplace/install-local/:manifestId/sample-data`), on every visit and again after an install, a reseed or a purge. Before, the purge confirm and the banner that follows the installer to the app knew a count only for an install made in the same browser session; a reload lost it.
12
+
-**The confirm.** The local purge confirm draws that count. When it cannot be read (refused, failed), it draws the count this session's install answered, as before. A read that began before an install, reseed or purge of this session answered is older than that answer and is not used.
13
+
-**The banner.** A count above zero raises the sample-data banner on leaving the page, as an install of this session does. A count of `0` drops what the session knew: no banner, and no count line in the confirm.
14
+
-**Types.**`marketplaceApi` gains `countLocalSampleData` and `LocalSampleDataCount`.
15
+
-**Strings.**`@object-ui/i18n` rewords `marketplace.detail.purgeConfirmAtMost` (all plural forms) in all 10 locales: it no longer says the count is "the number this install loaded", which is not what the runtime's count is. It stays an upper bound ("Up to N sample records will be deleted."), true of both counts. No key is added.
Copy file name to clipboardExpand all lines: ui/packages/app-shell/src/console/marketplace/__tests__/MarketplacePackagePage.displayLocale-9909.test.tsx
Copy file name to clipboardExpand all lines: ui/packages/app-shell/src/console/marketplace/__tests__/MarketplacePackagePage.offlineLocalMenu-11627.test.tsx
Copy file name to clipboardExpand all lines: ui/packages/app-shell/src/console/marketplace/__tests__/MarketplacePackagePage.releaseNotes-28891.test.tsx
0 commit comments