Repository navigation
feat(layout): a collapsed sidebar nav group shows its reachable child count - #26103
Merged
objectstack-fleet[bot] merged 4 commits intoOct 26, 2026
Merged
Conversation
Claude-Session: https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SMps7wq7rBTk53e8KTSEup Co-authored-by: Claude <noreply@anthropic.com>
…v-group-child-count
Contributor
Author
席位核对ACCEPT ·
|
objectstack-fleet
Bot
deleted the
claude/issue-25876-nav-group-child-count
branch
October 26, 2026 12:39
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.
Fixes #25876
Clause-②: no
Metadata-protocol: none
What changes
A collapsed sidebar navigation group now shows how many entries it holds, as a small count badge between its label and its chevron (
ui/packages/layout/src/NavigationRenderer.tsx). Before, a closed group drew a label and a chevron and nothing else, so a closed group holding one entry looked exactly like one holding ten.passesNavItemGuards(thevisibleexpression,requiredPermissions, therequiresObject/requiresServicecapability gates, adocentry's readability check), counted through nested groups. Separators and the groups themselves are not entries, and anactionentry counts only when the host wiresonAction.hasVisibleNavigationItemsran is now a module-local generator,visibleNavigationEntries.hasVisibleNavigationItemstakes its first entry (still stopping at the first hit) and the new module-localcountVisibleNavigationItemscounts them all. The count therefore cannot disagree with whether the group renders, or with what it shows once opened. No export is added or changed.!isOpen). An open group's entries are in view. A group holding the current route is forced open, so it never shows a count.Badgewitharia-hidden="true", so the disclosure's accessible name stays the group label (NavigationRenderer.groupDefaultOpen-13336.test.tsxuses exact button names and passes unmodified). The disclosure already announces collapsed or expanded.HIDDEN_ICON_LABEL_NO_POINTERandHIDDEN_ICON_LABEL_NOT_FOCUSABLE, the same classes the group label carries. The chevron'sml-automoves to the badge while it shows, so the badge and chevron sit together at the right edge.The card's second bullet is void
The card also asked that "when the console replaces a report group's children with one index link, draw the group as that single entry". The seat's claim voided this bullet after checking
origin/main: the console never folds a group's children. 「全部报表」 is a static siblingSidebarGroupatUnifiedSidebar.tsx:595-619. Flattening single-child groups would be a new product rule for every app, and the card does not ask for one. This PR adds only the count badge. No single-child flattening is implemented.Tests
New:
ui/packages/layout/src/__tests__/NavigationRenderer.groupChildCount-25876.test.tsx, 6 cases.main's renderer (commit 3e21743, the test alone): 4 failed, 2 passed. The failures were the guarded count, the collapse/expand toggle, the nested group's own count, and the icon-mode classes. The two that passed are preservation pins: the accessible name is unchanged, and a group holding the route is forced open and shows no count.visible-hidden entry, a permission-denied entry, a separator, anactionwith no dispatcher, a nestedvisible-hidden entry and the nested group itself are not counted. The two nested leaves are.node scripts/ablation-replace.mjsreplacedcountVisibleNavigationItems(children, guardOptions)withcountVisibleNavigationItems(children, { hasActionHandler: !!onAction }), which drops the visibility and permission guards. The anchor went 1 → 0 and the blob went 71eca7a7 → c44ada02. Result: 3 failed / 3 passed. The restore was verified as blob == HEAD (71eca7a7) withgit diff HEADempty. The tests import../NavigationRendererfromsrc, so there is nodistleg.Run at head
279ce1d9(after mergingorigin/main), under the verify lock:pnpm --filter @object-ui/layout test: Test Files 46 passed (46), Tests 384 passed (384).pnpm --filter @object-ui/layout type-check: exit 0.vitest run packages/app-shell/src/layout/__tests__/UnifiedSidebar(fromui/): Test Files 16 passed (16), Tests 70 passed (70). This includesUnifiedSidebar.iconModeLabelFocus-12795.NavigationRenderer.iconModeLabelHitTest-12744is in the layout run above.node scripts/check-sdui-manifest.mjs: exit 0. The record is untouched, as expected:@object-ui/layoutis outside the registry closure.Gates, local subset, at head
279ce1d9:node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 34 commands. All 34 ran, and each exited 0 (:: exit 0, captured before any pipe).dispatch-gates --ranreported: "34 derived famil(ies) accounted for — 34 run, 0 NOT-MEASURED (a DERIVED zero — all 34 recorded an exit code and none of them is 3)". ESLint on the three touched files found 0 errors; its 21 warnings were already there. Every other family is left to CI.Acceptance notes
ui/packages/layout/src/__tests__/AppSchemaRenderer.mobileTabOrder-11395.test.tsx, case "expanded: false… a collapsed group's children stay tabs". It found the sidebar group trigger byel.textContent === 'Sales'. A closed trigger now also contains the aria-hidden count, so its text isSales2. The lookup now matches a closed trigger (aria-expanded="false") whose first child, the label text node, readsSales. The assertion still checks the same things: the trigger exists outside the bar, and the bar's tabs areDeals,Leads. Only the test changed.AppSchemaRenderer.tsxitself is untouched. The change is in its own commit (c809cd2, together with the changeset) and is easy to drop if the seat prefers another route.variant="secondary", so it reads as information, not as thedefault(primary) colour that an authored leafbadgetakes by default.Generated by Claude Code