Repository navigation
feat(studio): a contributed nav entry shows the label the live app shows, and a contributor-only package says where its entries go - #30371
Merged
Conversation
…a contributor-only package says where its entries go The contributed nav row reads the label the live app shows, by (app, id) in the served app row the Interfaces pillar already reads; the id stays as a second line. A package with no app of its own that declares navigation contributions counts its entries from the target owner's served customization read and says so, with an Open button; any fallback keeps the old text. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jSRtrD4WV4w6qQDYJ2
…om its double The no-app empty state now asks the listed package manifests whether the package contributes navigation elsewhere; this file's packages-io double answers an empty list instead of reaching the network. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jSRtrD4WV4w6qQDYJ2
…age-list read The no-app empty state took the open package's declared navigation targets from a package-list request of its own. The Studio surface already reads the listed manifests, so it now hands them to the Interfaces pillar and the empty state sends only the owner lookup and the owner's customization read. The Interfaces create pin's packages-io double goes back to main's. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QsR2jSRtrD4WV4w6qQDYJ2
…-a2d68g The Interfaces nav rail moved to InterfacesNavRail.tsx on main; the contributed-row label context and helper move with it. Claude-Session: https://claude.ai/code/session_01Utp6Cb8MSvSrJz9nXGSj2F Co-authored-by: Claude <noreply@anthropic.com>
…e new studio keys Claude-Session: https://claude.ai/code/session_01Utp6Cb8MSvSrJz9nXGSj2F Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG Known red, not this PR's · Lint UI (job 127132323590). Same signature as main-red anchor #30367: |
…-a2d68g Claude-Session: https://claude.ai/code/session_01Utp6Cb8MSvSrJz9nXGSj2F Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG 维护者速读
席位核对 — ACCEPT · head 5aff45c
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Bill · project thread
domain:ui#3 · os-bill · session_01Utp6CbPN5UYMnBaNJPJWfG
维护者速读
Fixes #29851
Clause-②: yes (widening) — five new
@object-ui/i18nstudio keys, inenandzhMetadata-protocol: none
What changes
(app, id)in the app row the Interfaces pillar already reads (GET /meta/app?package=), which serves the folded navigation.servedContributedNavOfkeeps only the ids the published layer does not hold and that occur exactly once in the served tree, so an id the base also holds, or one two contributions share, keeps the bare id and no label is guessed. A label-less entry reads what it inherits through the rail's own resolver (navEntryLabelTextplususeNavTargetLabel). No request is added. This is a lookup by id in a served read, not the join on names ruling 6566915346 refuses.navigationContributionsnow says "This package has no app of its own. It adds N navigation entries to OWNER's app.", with an Open button, in the canvas and in the rail. The declared app is an address only: its owner comes from the servedGET /meta/app/:app(_packageId), and the count from the owner's servedGET /packages/:owner/customizationscontributions, filtered bykind: nav, thispackageIdand that app. At most two reads per declared target app (one customization read per owner), sent only on that empty state. When the package is disabled, the target app is missing, either read fails, or the count is 0, the text stays "This package has no app yet."fetchListedPackageManifests, passed down aslistedManifests), so it sends no package-list request of its own.engine.studio.if.noOwnApp,.noOwnAppTitle,.contributesOne,.contributesOther,.openOwner, in the studioenandzhpacks. No metadata key is added.StudioDesignSurface.tsxintoInterfacesNavRail.tsx(move-only split, [maintainer] refactor(app-shell): split StudioDesignSurface.tsx (12,882 lines) along its component seams, one move-only slice per PR #29988). The merge takes main's move and carries this card's rail hunks with it:InterfacesServedContributedNavContext, thelabelpassed toContributedRailRowinContributedNavRows, andcontributedNavLabel.InterfacesNavRail.tsxis outside the claim's listed file surface by name only; it holds the same code the claim named inStudioDesignSurface.tsx.Tests
contributionRows.test.ts: the served entries keyed by id at any depth and never the base's own; an id the base also holds keeps no label; an id two contributions share keeps no label; no served row or another app's gives nothing; the declared target apps are addresses, each once, in order; the count of the owner's served nav contributions for the package and app.StudioDesignSurface.oneSurface-28572.test.tsx, a new top-leveldescribein the existing harness: a unique id shows its served label with the id as a second line and a shared id keeps the bare id; CONTROL, no served fold keeps the id alone; a contributor-only package says what it adds from two reads and opens the owner; FALLBACK disabled package; FALLBACK missing target app (the owner is never read); FALLBACK failed app read or failed owner read; FALLBACK 0 entries; CONTROL, a package with no app that declares no contribution reads nothing more.Acceptance notes
StudioDesignSurface.tsxin the imports, the surface's package-list effect, theInterfacesPillarprops and its no-app empty state; Studio: add a new action to an installed app's object, saved in the customization package #30088 holds that file's actions branch, a different region. It touches none ofObjectListViewInspector.tsx(Studio Interfaces: a draft-only object's nav entry opens a non-existent 'Default view', and the first edit there creates a second default list view #30177, [Decision] Selection-bar actions cannot be configured in Studio: should the view panel offer them? #30089),ObjectActionsPanel.tsx(Studio: add a new action to an installed app's object, saved in the customization package #30088) orStudioBundleItemEditor.tsx(Studio translation editor: a source-to-translation table with visible gaps, replacing the raw JSON boxes #30285).Clause-②: noon the resume branch; it now saysyes (widening), as the five new published i18n keys make it. The level stayspatch(kindnone).Verification
All readings on head
98ed7206f4(main merged at9afcd6a6b6), repository objectstack-ai/objectstack.Type-check and tests
pnpm exec turbo run type-check --filter=@object-ui/app-shell --filter=@object-ui/i18n --concurrency=2: Tasks 69 successful, 69 total; lock VERDICT command-exit 0.ui/) over every test file that importscontributionRows,StudioRailCustomizations,InterfacesNavRailorStudioDesignSurface(193 files, bygit grep), pluspackages/i18n/: Test Files 288 passed (288); Tests 2728 passed, 13 skipped (2741); lock VERDICT command-exit 0.pnpm --dir ui exec vitest run scripts/: Test Files 170 passed, 2 skipped (172); Tests 4985 passed, 2 skipped.pnpm check:new-line-citations(ui): 0 new citations.Derived gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 35 families from 9 changed paths (661 changed lines, under the 3000 threshold). All 35 ran and exited 0,node scripts/check-sdui-manifest.mjsincluded.dispatch-gates --ran: 35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN.Ablation (each leg restored, git diff HEAD empty after)
servedContributedNavOfforced to return nothing (node scripts/ablation-replace.mjs, anchor hit 1 to 0): 4 pins red, the three helper pins and "a unique id shows its served label with the id as a second line". Restored blob equals HEAD.if (count === 0) return null;deleted fromuseContributedElsewhere: 2 pins red, "FALLBACK: a disabled package" and "FALLBACK: 0 entries for the declared app". Restored blob equals HEAD.Live, en and zh, fresh boot of the merged tree
Backend
examples/app-multi-package,objectstack dev --seed-admin --freshon its own port; the Console fromui/apps/consolesrc through Vite pointed at it; Chromium through Playwright.ui-seat3/issue-29851/shots/in the project folder (en-base-contributed-row.png,en-contributor-empty-state.png,zh-base-contributed-row.png,zh-contributor-empty-state.png).Measured request counts
GET /api/v1/packages, no/meta/app/:appand no other package's customizations. Multi-Package Orders (contributor only): the same twoGET /api/v1/packages, plusGET /meta/app/multi_crmandGET /packages/com.example.multi.core/customizations. The empty state adds two reads and no package-list read.GET /api/v1/packages, 24 listed): 11 declarenavigationContributionsforsetup. One of them iscom.objectstack.setup, which owns the app and never reaches the empty state, so 10 contributor-only packages show the new sentence forsetup.com.objectstack.mcp.connect-agent-uialso targetsaccount(ownercom.objectstack.account), so it sends four reads and reads "It adds 1 navigation entry to Setup’s app." and "It adds 1 navigation entry to Account’s app.". Across the 10 that is 11 targets, 22 reads in all, each sent only when that package's pillar is opened.Generated by Claude Code