Skip to content

fix(app-shell): show Studio nav entries in the menu's order, and let a canvas drag write order - #27039

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-onxyby
Oct 28, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-onxyby

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread
Fixes #26979

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:Studio「界面」左栏导航树与导航编辑画布,改为按 order 排列,与运行时菜单一致;画布拖拽排序时必要时写入被拖条目的 order。
  • 为什么改:运行时菜单按 order 排序,Studio 却按数组顺序显示,设置了 order 的条目在设计器和发布后的菜单里位置不同,拖拽也可能看不出效果。
  • 风险与回滚:只动 app-shell(私有包)三处源码加测试;没有设置 order 的应用显示与拖拽结果不变;回滚即还原本 PR。
  • 先看:AppNavCanvas.tsx 的 moveItem 与 inMenuOrder;StudioDesignSurface.tsx 的 NavTree;新测试块 railNavOrder-26979。
  • 两分钟验证:pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design/StudioDesignSurface.railLabels.test.tsx -t railNavOrder,预期 4 个测试全部通过。
  • 需要你做的:无,席位落地。

What changes

  • The Studio Interfaces rail (NavTree) and the nav canvas (AppNavCanvas) list every level through one new helper, inMenuOrder (exported from AppNavCanvas.tsx): order ascending, an absent order as 0, ties in authored order. That is the running menu's rule, byNavOrder in @object-ui/layout, which the sidebar applies at the top level and inside each group. Selection ids, renames and removals still address the authored array index.
  • A canvas drop rewrites the root array in the new shown order and writes the moved entry's order only when its current weight no longer falls between its new neighbours'; it then takes its neighbour's weight and the stable sort keeps it where it was dropped. At most one order write per drop, and none for an app whose entries carry no order.
  • NavNode (navSurface.ts) and the canvas's RawNav declare the spec's order?: number, type only.

Why this shape (the card's two options, measured)

  • The menu sorts by order at every level, stably. A drag that only rewrote order (shape b) cannot fix entries whose order was written by the API or the inspector before any drag: the rail and canvas would still list array order. So both lists sort (shape a), and then a drag has to write order or it does nothing visible. Normalising the array to the shown order lets one neighbour-weight write place the entry, which is the fewest order writes that keeps the builder equal to the menu.
  • byNavOrder is not imported: navOrder.ts is internal to @object-ui/layout and publishing it would widen that package's entry point. Per the seat's claim amendment on the card, Studio states the same rule locally and a test renders NavigationRenderer beside the rail and the canvas over the same entries, so the two rules cannot drift without a red test.
  • AppNavCanvas is shared with Setup's app editor (AppPreview.tsx), which mounts the same component: the sorted listing and the drop behaviour are the same there.

Tests

StudioDesignSurface.railNavOrder-26979 in StudioDesignSurface.railLabels.test.tsx renders the real InterfacesPillar rail, AppNavCanvas and NavigationRenderer:

  • entries with order [3, 1, 2] plus a group whose children carry [2, 1] read in one order on all three;
  • a drag in the canvas leaves all three agreeing, and only the moved entry changes (it gains order; every other entry is the same object);
  • control: entries without order keep array order, and a drag among them writes no order.

Ablations (each self-restoring through scripts/ablation-replace.mjs, blob equal to HEAD after restore):

mutation result
inMenuOrder stops sorting 2 of 4 red (agreement, drag)
the drop's order write removed 1 of 4 red (drag)
NavTree lists array order 2 of 4 red (agreement, drag)

The first attempt at the sort ablation was refused by the tool (its replacement text already occurred in the file), so it did not run; it was rerun with a distinct replacement.

Acceptance notes

  • Not changed, outside the file surface: on load the Interfaces pillar opens the first resolvable leaf of the authored array (firstLeaf in the load effect), which can now differ from the rail's first row when order reorders the top. Observation only.
  • No changeset: the diff touches only @object-ui/app-shell, which is private: true.

Verification

All local readings on head 42f2d1b4 unless noted. Exit codes captured before any pipe.

Derived gate families (24): all exit 0, reconciled with dispatch-gates --ran

node scripts/pm/dispatch-gates.mjs --commands derived 24 families for this diff; each ran on 42f2d1b4 and exited 0. --ran answers: "24 derived famil(ies) accounted for — 24 run, 0 NOT-MEASURED". The set includes node scripts/check-sdui-manifest.mjs (and its --self-test), node scripts/check-comment-mask-corpus.mjs, pnpm --dir ui exec vitest run scripts/, pnpm check:cross-package-test-inputs, pnpm check:test-source-alias, pnpm check:type-check-coverage, pnpm check:type-check-debt and pnpm check:nul-bytes.

Package tests and extra families (on 54fb22e; the later commit adds one comment and one lint directive)
  • pnpm --dir ui exec vitest run packages/app-shell/src/views/studio-design/: Test Files 243 passed (243), Tests 1761 passed (1761).
  • pnpm --dir ui exec vitest run packages/app-shell/src/views/metadata-admin/previews/ packages/app-shell/src/views/metadata-admin/studio-locale.i18n.test.tsx: Test Files 148 passed (148), Tests 1678 passed (1678). Covers Setup's AppPreview mount of the canvas.
  • pnpm --filter @object-ui/app-shell type-check: exit 0.
  • pnpm --dir ui run check:spec-symbols: exit 0. pnpm --dir ui run check:new-line-citations: 0 new citations, exit 0.
  • eslint on the four changed files: 0 errors; on 42f2d1b4 the new export adds no warning (it carries the same directive as navPayloadOf).
  • On 42f2d1b4: StudioDesignSurface.railLabels.test.tsx whole file, Tests 60 passed (60).

Not run locally, CI-owned: the repo-wide pnpm lint, test:repo, and the full UI suite.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic.
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes.
  • 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: its generated artifacts are regenerated and committed.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JQwxbWATiRKGB7bP2VvNAG


Generated by Claude Code

…a canvas drop write order

The Interfaces rail and AppNavCanvas listed nav entries in array order while
the running menu sorts each level by order. Both now list a level through
inMenuOrder (the menu's byNavOrder rule), and a canvas drop writes the array
in the new shown order plus the moved entry's order when its weight no longer
falls between its new neighbours'.

Claude-Session: https://claude.ai/code/session_01JQwxbWATiRKGB7bP2VvNAG
Co-Authored-By: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 28, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · seat domain:ui#5 · session_01JQwxbXGpVJHZTXXerMoY4C · head 42f2d1b4 · 2026-10-28T02:56Z

席位意见:Studio「界面」左栏导航树和导航画布按运行时菜单的规则排列(order 升序、缺省按 0、同值保持编写顺序);画布拖拽后数组按显示顺序重写,被拖条目仅在必要时写一次 order,没有 order 的应用不写。byNavOrder 未导出,靠与 NavigationRenderer 同屏渲染的测试保持两条规则一致。

  1. Shape: Fixes #26979; 4 files, +276/−12: AppNavCanvas.tsx (inMenuOrder, the sorted root and child listing, moveItem), StudioDesignSurface.tsx +7/−2 (the import line and NavTree's listing only), navSurface.ts +2 (order?: number on NavNode, type only), and the test block railNavOrder-26979 in StudioDesignSurface.railLabels.test.tsx. skip-changeset: @object-ui/app-shell is private: true; @object-ui/layout untouched.
  2. Premise measured: the seat read the source diff. inMenuOrder is byNavOrder's rule (order ?? 0 ascending over a stable sort) with array indexes kept, so selection ids, renames and removals still address the authored array. moveItem rebuilds the root in shown order, splices the entry to the drop position, and writes order only when the entry's weight falls outside its new neighbours' (it takes the neighbour's weight; the stable sort then holds it on the dropped side). The seat checked the tie cases ([1,1,2], drop first / last). Dev: 4/4 new tests render the rail, the canvas and NavigationRenderer together; 3 ablations red, restored.
  3. Gates / check-runs: PR check-runs on 42f2d1b4: 43 success, 15 skipped, 0 failure; Lint & Repo Gates, TypeScript Type Check, Type Check UI and Check Changeset success. Dev's local run: 24 derived, 24 run, --ran reconciled; studio-design/ 243 files / 1761 tests and metadata-admin/previews/ 148 files / 1678 tests (Setup's AppPreview mount included) green; app-shell type-check exit 0.
  4. Accepted deviations: the triage's "one comparator: import byNavOrder" line, superseded by the seat's amendment 6458269227 (no export; local rule pinned by a parity test); the navSurface.ts type line the amendment allowed; inMenuOrder exported from AppNavCanvas.tsx with the same lint directive as navPayloadOf (never reaches the package entry).
  5. Out of scope: the Interfaces pillar's first-open leaf (firstLeaf) still follows array order, so it can differ from the rail's first row once order reorders the top: Acceptance notes, reading only; the seat files it if an Interfaces card reproduces it. Skills-docs: none — Studio listing order only.
  6. Landing: not Tier H (no governed path, +288 lines); ready for landing (ready + auto-merge).

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 28, 2026 02:57
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 28, 2026 02:57
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 28, 2026
Merged via the queue into main with commit fbc1656 Oct 28, 2026
59 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-onxyby branch October 28, 2026 05:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Studio Interfaces: the nav rail and canvas list entries in array order and ignore order, while the running menu sorts by it

2 participants