Skip to content

fix(studio): Interfaces lists a package's pages, dashboards, reports and views no nav entry names - #26982

Merged
objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/project-thread-9g76ju
Oct 28, 2026
Merged

objectstack-fleet[bot] merged 6 commits into
mainfrom
claude/project-thread-9g76ju

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread
Fixes #26889

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:Studio › Interfaces 的左栏在导航树下新增「不在导航中」分区(页面/仪表板/报表/视图),列出包内没有导航项打开的条目;没有 app 的包也列出,点开进现有画布与检查器。
  • 为什么改:原来左栏只画导航树,菜单外的列表视图、记录页、模块包的仪表板在 Studio 里打不开(HotCRM 18.2.0 实测 65 个视图只见 4 个)。
  • 风险与回滚:只改 Interfaces 左栏的列表与无 app 空状态,不改导航的编辑与保存;回滚即 revert 本 PR。
  • 先看:StudioDesignSurface.tsx 的 navOpenedItems / OffNavSections 与画布空状态条件;packageSurfaces.ts 的 keep 参数;新测试文件。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design/InterfacesPillar.offNavItems-26889.test.tsx,预期 7/7 通过。
  • 需要你做的:无,席位落地。

What changes

  • The Interfaces rail lists what no nav entry opens. Under the navigation tree (or under the "no app yet" notice), a "Not in navigation" block holds one collapsible section per type, Pages, Dashboards, Reports, then Views, listing the package's items of that type that no nav entry opens. A row opens its item in the pillar's existing canvas and inspector, exactly as a tree row does (pickSurface, shared with the tree, keeps the held-widget confirmation). On a read-only package the canvas opens read-only, as it does for a tree row. Nothing is written by listing: no nav entry is added.
  • One reader, reused. The items come from loadPackageSurfaces (published ∪ draft, published label wins, a draft-only item by its _drafts label). It gains an optional keep filter over the published rows, fed each type's own MetadataResourceConfig.listFilter, so the rail lists what Setup › Metadata lists: the aggregated view container the server keeps beside its expanded view items is not an item. No third reader was added.
  • No item is listed twice. navOpenedItems walks the nav buffer with the tree's own binding (resolveSurface): a page / dashboard / report entry's target, and the view an object entry's viewName names, under the view item's name (OBJECT.VIEWNAME, via listViewTargetOf). A plain object entry opens its object, so that object's views stay listed. The sections are hidden while nav editing (the rail is the nav editor then) and while the app is still resolving.
  • A package with no app keeps its rail notice with the sections under it; its canvas keeps the empty state until a row opens an item (appStatus === 'missing' && !error && !current).
  • Strings: five engine.studio.if.offNav.* rows in the studio namespace (en, zh); none in metadata-admin/i18n.ts. Changeset: @object-ui/i18n patch.
  • Test mocks: StudioDesignSurface.interfacesCreate-11823 and interfacesCreatePage-11823 served another package's item from the pillar's own package-scoped list, which the server never does; their mock now keeps scope (inScope), the assertions are unchanged.

Tests

  • InterfacesPillar.offNavItems-26889.test.tsx (new, 7 tests): the four sections list exactly the off-nav items (record page, draft-only page, dashboard, report, view); nav-opened items appear once (in the tree), the viewName view and the aggregated container never in the sections; a view, a record page and a dashboard each open in the canvas with the row active; a no-app package keeps its notice and opens its dashboard and page; read-only opens with no onPatch and no save, writable with one; a package whose every item an entry opens draws no sections (with a positive control).
  • Ablation 1 (drop the non-nav read: loadPackageSurfaces(…).catch( replaced by Promise.resolve([] as PackageSurface[]).catch(): 7/7 red; restored, blob equals HEAD.
  • Ablation 2 (drop the nav dedupe filter): the listing, the listed-once and the control tests red (3/7); restored, blob equals HEAD.

Acceptance notes

  • A ?surface= deep link to an off-nav item (for example the running app's Edit app on a record page route) still restores to the first nav leaf: the restore reads the nav tree only, in the app load, outside this card's declared region. Reported for the seat to file.
  • The sections are open by default; Views sits last because a package ships many.
  • A type whose read fails lists nothing, as the pillar's object read leaves its picker empty.

Verification

All readings at head c11187f3 (the fix commits plus a merge of origin/main), app-shell dependency closure rebuilt after the merge.

Tests (local, under the shared verification lock)
  • pnpm --dir ui exec vitest run on the new test, both edited create tests, and the nav-tree, no-app-label and read-only Interfaces tests: 6 files, 54 tests passed.
  • Before the merge, at d9302876: the whole packages/app-shell/src/views/studio-design/ directory, 234 files; the two create tests failed on the mock described above, then passed after it was scoped. Outside importers of the changed modules (2 files) plus packages/i18n/: 91 files passed. App-shell term tests (zh-base-term, studio-locale, metadata-form-i18n): 19 tests passed.
  • pnpm --filter @object-ui/app-shell run type-check: exit 0. pnpm --filter @object-ui/i18n run type-check: exit 0. eslint on the changed files: 0 errors, no warning on a changed line.
  • pnpm check:new-line-citations: 0 new citations.
Derived gates (dispatch-gates --commands; reconciled with --ran: 34 derived, 34 run, 0 not measured)
  • node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
  • node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
  • node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
  • node scripts/check-closing-keyword-parity.mjs :: exit 0
  • node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
  • node scripts/check-comment-mask-corpus.mjs :: exit 0
  • node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
  • node scripts/check-empty-changeset.mjs --self-test :: exit 0
  • node scripts/check-sdui-manifest.mjs :: exit 0
  • node scripts/check-sdui-manifest.mjs --self-test :: exit 0
  • node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
  • node scripts/release-pending-publish.mjs --self-test :: exit 0
  • pnpm --dir ui exec vitest run scripts/ :: exit 0
  • pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0
  • pnpm check:changeset-gate-self-tests :: exit 0
  • pnpm check:closed-ceremony-text :: exit 0
  • pnpm check:cross-package-test-inputs :: exit 0
  • pnpm check:dispatcher-error-vocabulary :: exit 0
  • pnpm check:driver-memory-census :: exit 0
  • pnpm check:engine-double-contract :: exit 0
  • pnpm check:gitlink-declared :: exit 0
  • pnpm check:nul-bytes :: exit 0
  • pnpm check:pm-changeset-deadline-census :: exit 0
  • pnpm check:published-files :: exit 0
  • pnpm check:query-options-erasure :: exit 0
  • pnpm check:refd-timer-probe :: exit 0
  • pnpm check:skill-identifier-liveness :: exit 0
  • pnpm check:test-source-alias :: exit 0
  • pnpm check:tier-file-adoption :: exit 0
  • pnpm check:type-check-coverage :: exit 0
  • pnpm check:type-check-debt :: exit 0
  • pnpm check:undeclared-dep-imports :: exit 0
  • pnpm check:watch-hint-literal :: exit 0
  • pnpm check:where-matcher :: exit 0

Families CI runs beyond the derived list are read from this PR's check-runs, not re-run locally.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes. (changed files linted locally; the repo-wide run is CI's)
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: not touched.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English (the maintainer brief above is the os-dev order's Chinese section).
  • The Before Submitting list in CONTRIBUTING.md is done.

Generated by Claude Code

…and views no nav entry names

The Interfaces rail listed only the app's navigation tree, so an item no
entry opens, and every item of a package with no app, could not be opened
in Studio. Under the tree, one section per type now lists the package's
items no entry opens (published and draft, through loadPackageSurfaces
narrowed by each type's list filter); a row opens its item in the existing
canvas and inspector. A no-app package keeps its notice with the sections
under it, and its canvas leaves the empty state once an item is opened.

Claude-Session: https://claude.ai/code/session_01JQwxbZJXVERQKCsD3gtpru
Co-authored-by: Claude <noreply@anthropic.com>
…oped list per package

The two tests that refuse an identifier another package holds served that
package's item from the pillar's own scoped list too, which the server never
does; the Interfaces rail now reads that list, so the mock keeps scope.

Claude-Session: https://claude.ai/code/session_01JQwxbZJXVERQKCsD3gtpru
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tooling labels Oct 28, 2026
…prefixed template

The view-cache guard (viewCacheInvalidation.guard) refuses any app-shell file
that interpolates a view-prefixed template string, the adapter cache key's
shape. The set of items nav entries open is not a cache key; its keys now go
through itemKeyOf.

Claude-Session: https://claude.ai/code/session_01JQwxbZJXVERQKCsD3gtpru
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · seat domain:ui#5 · session_01JQwxbXGpVJHZTXXerMoY4C · head e6d81a62 · 2026-10-28T00:48Z

席位意见:Interfaces 左栏在导航树(或「此包还没有应用」提示)之下,按页面 / 仪表盘 / 报表 / 视图分组列出导航没有指向的条目,点开用现有画布和检查器;只读包照样只读打开。复用 loadPackageSurfaces,没有新增第三个读取器。

  1. Shape: Fixes #26889; 8 files, +490/−20: StudioDesignSurface.tsx (new OffNavSections / OffNavSection right after NavTree, one effect loading the four types, the rail children, and the no-app empty state now yields once a row is opened), packageSurfaces.ts +8/−1 (optional keep filter = the type's registry listFilter, so the view container is left out as Setup › Metadata leaves it out), one new test file (260 lines), two create tests' mocks now honour packageId, studio namespace en/zh +6 each, and a patch changeset for @object-ui/i18n. StudioRail props untouched (seat 1's Studio rails: a search with no matches shows a blank list with no "no matches" message (object rail, permission-set rail) #26733).
  2. Premise measured: the seat read the source diff. Items a nav leaf already opens are filtered out by navOpenedItems (an object entry's viewName included), so nothing is listed twice; sections are empty until the app read settles and the package matches; reads re-run on publish, draft and metadata refresh. Dev: 7/7 new tests; two ablations red, restored.
  3. Gates / check-runs: PR check-runs on e6d81a62: 43 success, 10 skipped, 0 failure; Lint & Repo Gates, TypeScript Type Check and Check Changeset success. One red on the reported head c11187f3 (Test UI 10/16: viewCacheInvalidation.guard refuses a view-prefixed template string) was the dev's own; e6d81a62 routes keys through an itemKeyOf helper (+6/−3, one file). Dev's local run on e6d81a62: 34 derived, 34 run, --ran reconciled; app-shell type-check exit 0.
  4. Accepted deviations: import-block lines in StudioDesignSurface.tsx; the two create tests' mocks; Views listed last. The report cites head c11187f3; the amendment (head e6d81a62, the fix commit, CI green) is carried here.
  5. Out of scope: a ?surface= deep link to an off-nav item still restores the first nav leaf: Acceptance notes (reading only, not reproduced); the seat files it if the next Interfaces card reproduces it. Skills-docs: none — Studio listing only.
  6. Landing: not Tier H (no governed path, +510 lines); ready for landing (ready + auto-merge).

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 28, 2026 00:49
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 28, 2026 00:49
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 28, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to a conflict with the base branch Oct 28, 2026
…-9g76ju

# Conflicts:
#	ui/packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · re-arm

ACCEPT stands · seat domain:ui#5 · session_01JQwxbXGpVJHZTXXerMoY4C · head 4b64c9d1 · 2026-10-28T02:41Z

席位意见:合并队列因 #26977 先落地而弹出本 PR;开发者合并 origin/main(7eb613c3)两侧都保留,PR 改动本身没变,原 ACCEPT 继续有效。

@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 28, 2026
Merged via the queue into main with commit 6aba7cb Oct 28, 2026
53 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-9g76ju branch October 28, 2026 04:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tooling

Projects

None yet

2 participants