Repository navigation
finding(components): an action:bar inline action authored with component: 'action:menu' or 'action:group' renders nothing — the action vanishes from the toolbar and a ?runAction= deep link to it runs nothing #10345
Description
Activity
objectstack-fleet commented
on Sep 24, 2026 ContributorAuthorMore actions分诊首次定级:
priority:p2·bug·domain:ui·needs-user-decision—— 工具栏里把一个动作的显示方式设成「下拉菜单」或「按钮组」,这个动作就从工具栏上消失了,深链接也执行不了;设计器里明明提供这两个选项,而「单个动作设成菜单是什么意思」需要维护者定Path:
packages/components/src/renderers/action/action-bar.tsx(按action.component || 'action:button'取渲染器,把单个动作铺进它的 schema)→action-menu.tsx(if (actions.length === 0) return null;)/action:groupTriage: lands in
@object-ui/components⇒domain:ui,bug,priority:p2,needs-user-decision(findingremoved — graded); rationale:@objectstack/spec'sActionSchema.componentenum offers'action:menu'("Dropdown menu") and'action:group'("Button Group") and the metadata-admin inspector offers both, butaction:barhands a SINGLE action to renderers that readschema.actionsand returnnull, so the action silently vanishes and a?runAction=deep link runs nothing; the repair turns on what those two values MEAN for a single action (overflow placement, a one-button menu/group, or refusal in the spec), which is a contract-meaning call for the maintainer.分诊席 #6015,2026-09-24T19:26Z。⛔ 不认领、不派发。本席读完了卡面(本卡尚无评论),并在 objectui
origin/main1f8ef0a8和 objectstackorigin/mainb81da66df7上核对。本席核对
- spec:
ActionSchema.component是z.enum(['action:button', 'action:icon', 'action:menu' /* Dropdown menu */, 'action:group' /* Button Group */]),描述为「Visual component override」。上方注释写着「Defaults to 'button' or 'menu_item' based on location, but can be overridden」。 - 渲染:
action-bar.tsx本身已经有一个溢出菜单(「Render a single overflow menu … at most ONE "More" button per bar」),用的正是ComponentRegistry.get('action:menu'),传进去的是actions: combinedOverflow。 - 卡面的探针表(
action:menu/action:group成员执行 0 次、不渲染按钮)是 finding(components):action:iconnever consumesautoTrigger— a?runAction=deep link to an icon-rendered toolbar action is armed, consumed, and does nothing (the #4162 signature on a third renderer) #10274 的开发在 PR fix(components): action:icon consumes autoTrigger through the shared hook (objectui#10274) #10342 的 head 上测的,本席没有重跑。
需要维护者决定:单个动作的
component: 'action:menu' | 'action:group'是什么意思- A(本席建议):当成「放在哪里」来理解。
action:menu表示把这个动作放进工具栏已有的「更多」下拉菜单;action:group表示把它和相邻动作渲染成一个按钮组。- 理由:spec 注释说的正是「按位置默认是按钮或菜单项,可以覆盖」,工具栏也已经有这个溢出菜单,改动集中在
action-bar.tsx的分发逻辑,不改契约。
- B:让菜单和按钮组的渲染器也能接受单个动作,渲染成「只有一项的下拉菜单」和「只有一个按钮的按钮组」。改动小,但用户看到的形状很奇怪。
- C:在 spec 里拒绝单个动作使用这两个值。 这是收窄契约,要改 objectstack 的 spec 和设计器的选项,而且已经写成这样的元数据会在校验时失败。
⇒ 不管选哪个,今天的「静默消失」都必须消除。
定级说明
p2:设计器里可选、spec 里合法,结果动作静默消失,深链接也什么都不执行。不给 p1:不涉及数据或权限,只有专门选了这两个值才会触发。
裁决后的执行要点
action-bar.tsx正被 finding(components):action:iconnever consumesautoTrigger— a?runAction=deep link to an icon-rendered toolbar action is armed, consumed, and does nothing (the #4162 signature on a third renderer) #10274 的 PR fix(components): action:icon consumes autoTrigger through the shared hook (objectui#10274) #10342 修改(action:icon成员),⛔ 排在它后面,或者在它落地之后再动手。- 把卡面的四行探针表做成测试:按钮、图标、菜单、按钮组四种成员,执行次数和渲染出的按钮都要钉住。
- 深链接
?runAction=指向这类成员时,必须能执行。
Generated by Claude Code
- spec:
- addedbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatand removed
on Sep 24, 2026 objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsRuling: batch #224 item 1 · letter A (a single action's
action:menu/action:groupis a PLACEMENT) · maintainer 「批 #224 同意」 (chat, director seat summon #29,session_01EcrTi7s5oDYPHS4Pi7h31d) 2026-09-25T02:15ZDirector seat, summon #29. Presented with recommendation A (fallback C); the maintainer agreed. Thread re-read to its last comment (5820756170) in this act.
Ruled: A. On an
action:bar, a single action'scomponentis read as where it goes, which is the spec's own comment: "Defaults to 'button' or 'menu_item' based on location, but can be overridden".action:menuputs the action into the bar's existing single overflow menu (the one "More" button).action:grouprenders it in a button group with its adjacentaction:groupmembers.- The dispatch lives in
action-bar.tsx. ⛔ No contract change, and ⛔ the menu and group renderers are not taught to accept a single action (B). - The silent vanish is gone: every member renders somewhere, and a
?runAction=deep link to it runs. - Pins: the card's four-row probe (button, icon, menu, group), with run count and rendered placement for each, plus the deep-link case.
- What counts as "adjacent" for
action:groupis the dev's to measure and state in the PR.
Execution:
needs-user-decision→pm:queuein this stroke. Serial after objectui#10274 / PR #10342 (it also editsaction-bar.tsx).priority:p2,buganddomain:uistand.
Generated by Claude Code
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 —
domain:uiexecution seat 4
Session:session_01BP8CMtACxTdLjqR6rhd33C
Branch:claude/issue-10345-action-bar-menu-group-placement
Worktree:objectui-issue-10345
Domain:domain:ui
Seat:domain:ui#4
File surface:packages/components/src/renderers/action/action-bar.tsx: the inline member dispatch and its docblock. It reads a single action'scomponent: 'action:menu'as a place in the bar's one overflow menu, and'action:group'as a place in a button group with its adjacentaction:groupmembers.- Tests beside it under
packages/components/src/renderers/action/__tests__/. - One
.changeset/10345-…md.
Stop on breach; explain in the report. Per the ruling, the
action:menu/action:grouprenderers are ⛔ not taught to accept a single action, and no contract moves.
Container & model:M,mode:subagent,model: opus— executes ruling5825579152(letter A)
Clause-②: no
Thread-read: 5825579152
Serial constraints cleared:- The predecessor, objectui#10274's PR objectui#10342 (the last holder of
action-bar.tsx), merged 2026-09-24T19:34Z. - The open-PR file lists read 2026-09-25T02:44Z show one hit, draft PR objectui#8941 (lucide bump). It edits one line of the docblock usage example in
action-bar.tsx(thetrash-2icon), so it is hunk-disjoint from the member dispatch; this claim leaves that example line alone. - The live
pm:dispatchedclaims of the other seats, read 2026-09-25T02:43Z, name no file underpackages/components/src/renderers/action/.
Clause-②: no. The spec'sActionSchema.componentenum already accepts both values; the bar starts honouring them as placement, as the spec's own comment says. No declared key, schema, export or accept set moves.
Generated by Claude Code
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 10345, "status": "done", "branch": "claude/issue-10345-action-bar-menu-group-placement", "pr": "https://github.com/objectstack-ai/objectui/pull/10470", "session": "session_01BP8CMtACxTdLjqR6rhd33C — the dispatching seat's session; this subagent run carries the parent's id (the commit Claude-Session trailers and the fleet-write route derived from CLAUDE_CODE_REMOTE_SESSION_ID both name it)", "premise_still_valid": true, "summary": "Ruling A is carried entirely inside action-bar.tsx. A member authored component 'action:menu' is taken out before the maxVisible split and placed in the bar's one existing overflow menu. A member authored 'action:group' renders inline through the action:button renderer, inside the existing custom ButtonGroup primitive (role=group), shared with the adjacent action:group members of the drawn inline row; the docblock's opening paragraph now says this, and the trash-2 example line is untouched. A2 measured: action-group.tsx draws its own InlineActionButton, which consumes no autoTrigger and gates visible fail-soft, so routing grouped members through that renderer would leave the deep link dead. Having the bar draw the group, with action:button members, is the compliant route inside the file surface; no needs_decision fork was needed, action-menu.tsx and action-group.tsx are untouched, and no contract moved. A1 held (the menu's existing ActionAutoTrigger runs a menu-placed member's deep link). A3: menu-placed members do not count toward maxVisible. A4: the overflow order is the spilled actions, then the menu-placed ones, each in bar order, then the separator and the system actions (page:header's relative order). A5 is pinned for both placements. One pending changeset sentence was corrected (see tests). The coordinator's resume note said no branch existed; in fact the empty-branch probe push had landed at 0348bc9f1 before the 429 cut, and the work continued on it.", "tests": "All readings are at HEAD da122c4cf. (1) New suite action-bar-member-placement-10345.test.tsx: 21/21 passed. It holds the card's four-row probe (button, icon, menu and group rows each read 1 run, placed inline / inline / More menu / button group), the deep-link rows (armed the way ObjectView maps ?runAction=, run once, re-renders with fresh objects do not re-run, unflagged runs nothing), A3/A4 accounting and order, 'adjacent' semantics, and A5 gates (hidden menu member stays hidden and its deep link is refused with the objectui#4191 notice; hidden group member not drawn; disabled menu item; requiredPermissions at both placements, each with a held-capability control leg). (2) Reverse proof, run under trap-restore from the committed fix: action-bar.tsx was replaced with its BASE 0348bc9f1 blob, removing the placement branch. On disk before: inlineRow=2, inlineActions.map=0; after: inlineRow=0, inlineActions.map=1, and the hash e986327a equalled the base blob. The suite read 'Tests 19 failed | 2 passed (21)'. The 2 passing are the action:button/action:icon probe rows, which are correct in both worlds. The menu/group probe rows read 'expected vi.fn() to be called 1 times, but got 0 times'. The restore used git checkout HEAD; the hash dd60d8a9 equalled the HEAD blob and git diff HEAD was 0 lines. The first ablation run exposed the two requiredPermissions rows as vacuous (they stayed green because the defect also reads absent), so held control legs were added and the ablation re-run. (3) Targeted vitest over 38 files (32 @object-ui/components suites: every one naming action-bar, action:bar, action:menu, action:group or useAutoTriggerOnce, plus every file under renderers/action/__tests__; 4 app-shell deep-link consumers: EnvironmentListToolbar deepLinkArming/deepLinkOverflow/main and useOfferedNavRunAction; 2 script pins naming action:bar): 'Test Files 38 passed (38) / Tests 668 passed (668)', lock VERDICT command-exit 0. (4) Closure build pnpm --filter '@object-ui/components^...' build: exit 0, 8 of 47 projects. Then pnpm --filter @object-ui/components type-check (tsc --noEmit AND tsc -p tsconfig.test.json): exit 0, and --listFiles confirms both configs include action-bar.tsx and the new test. (5) eslint on the 2 touched source files with the repo config: 0 errors; 5 warnings, the same 5 as on the BASE blob, all on untouched lines. (6) check-changeset-presence 0, check-changeset-no-major 0, check:new-line-citations 0 (0 new citations), check:control-bytes 0, check:changeset-claims 0 ('No pending changeset names a file this change touches'), check-vi-mock-override-shape 0, check-test-path-roots 0, check-lint-coverage 0. (7) Changesets: new .changeset/10345-action-bar-menu-group-placement.md ('@object-ui/components': patch). The pending objectui#10274 changeset's sentence 'action:bar renders each inline action with the renderer its component names' became false (an inline action:group member now renders through action:button), so it was narrowed to action:button / action:icon, body only; the front-matter md5 is unchanged. The pending 6306, 7415, 4191 and 5493 changesets were read and judged still true (their spread and 'decided by maxVisible' sentences describe members whose component does not place them; the literal 'type: componentType, actionType: action.type' spread is kept). Local gates were hand-derived from objectui package.json and lint.yml, since dispatch-gates.mjs does not cover objectui. NOT MEASURED: the ButtonGroup's rendered look in a real browser (jsdom computes no Tailwind, so the attached styling and empty:hidden were not observed). The CI farm (pnpm lint, full pnpm test shards, Build & E2E) is left to CI; its state is in_progress/unread at report time.", "mcp_calls": "0 — no MCP GitHub tools called", "api_writes": "2 — both via the fleet-write relay as objectstack-fleet[bot] (each one repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create, i.e. POST /repos/objectstack-ai/objectui/pulls, draft=true, opening #10470, relay run 36092791117 concluded success; (2) this os-dev-report comment, POST /repos/objectstack-ai/objectui/issues/10345/comments via post-stamped.mjs. Plus git push (not REST): the empty-branch probe, then three pushes of the branch. No label writes (objectui labels are path-synced by labeler.yml and the dispatch named none). No PR body PATCH.", "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · noted, not filed (dormant, zero producer) — action:group's own leaves (InlineActionButton, DropdownActionItem in action-group.tsx) consume no autoTrigger, while auto-trigger.ts states 'every renderer that can receive an action consumes it'. No host sends a flagged action into a standalone action:group today; the ?runAction= host (ObjectView, EnvironmentListToolbar) composes an action:bar. Recorded in PR #10470 Acceptance notes.", "carrier: 承接者:无 · noted, not filed (pre-existing observation) — an overflow whose every entry is hidden by its own visible still renders an empty More trigger; this was already true for spilled actions before this change. Recorded in PR #10470 Acceptance notes." ] }
Generated by Claude Code
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actions✅ ACCEPT: objectui#10470 at
da122c4, landing now (ready → merge queue)domain:uiseat #4,session_01BP8CMtACxTdLjqR6rhd33C. I read the dev report5826498127and checked it against the diff, the tree and CI. The contract-review record is on the PR. This executes ruling5825579152(letter A): on anaction:bar, a single action'scomponentis its PLACEMENT.Implemented-by: claude/issue-10345-action-bar-menu-group-placement Reviewed-by: session_01BP8CMtACxTdLjqR6rhd33Citem reading action:menuThe member leaves the row candidates before the maxVisiblecut and joins the bar's one existing overflow menu, after the spilled actions and before the separator and system actions (page:header's relative order). It spends no inline slot, and an overflow holding only such members still draws exactly one More button. Its deep link runs through the menu's existing per-actionActionAutoTrigger(A1)action:groupConsecutive action:groupmembers of the drawn inline row (after ordering, themaxVisiblecut and menu placement) render through theaction:buttonrenderer inside the repo'sButtonGroupprimitive (role="group").[G1, G2, Plain, G3]gives two groups. A group tail cut bymaxVisiblelands in the More menu as plain items. That is the dev's measured reading of "adjacent", as the ruling left itwhy not the action:grouprendererIts leaves consume no autoTriggerand gatevisiblefail-soft, so routing members there would leave the ruling's deep-link requirement unmet. Fixing that means editingaction-group.tsx, outside the claim. The bar-drawn group is the in-surface compliant route: the reviewer judged it within the ruling's letter, not a quiet fork. ⛔action-menu.tsxandaction-group.tsxare untouched, and no contract movedgates requiredPermissions,visible(fail-closed) anddisabledgate a relocated member exactly as they gate an inline one (A5)unchanged bars A bar with no menu or group member renders the same element tree: the same slices, keys, spread and datapins 21 cases on the real registered renderers under a real ActionProvider, with no module mocks. Reverting the file to base gives 19 red and 2 green (the button and icon rows, correct in both worlds). The tworequiredPermissionsrows carry held-capability control legs, so they are not vacuoussurface The claim's three items, plus .changeset/10274-action-icon-auto-trigger.md: body only, frontmatter sha256 identical at base and head. Ratified here. Its sentence "action:bar renders each inline action with the renderer its component names" was true at base and becomes false with this PR, because an inlineaction:groupmember now renders throughaction:button. Correcting it in the same PR is what.claude/agents/os-dev.mdrequires. Thetrash-2example line is byte-identical, which keeps it hunk-disjoint from draft PR objectui#8941changesets Every sentence is true at head. patchon@object-ui/components. The pending 6306, 7415, 4191 and 5493 changesets stay trueClause-② no. Both enum values were already legal and now render. No export or accepted set movesboundary Fixes #10345is the only closing keyword, and there are no model identifiersCI 43 check-runs on da122c4: 40 success, 3 skipped by design, 0 redOut of scope
- To be filed at the seat's next fire (this fire's three-card cap is spent on objectui#10474, finding(plugin-form): the default
object-formarm draws a section's members in field-pool order, not the order the section lists them; the other five arms keep the section's order #10475 and finding(plugin-form): the defaultobject-formarm drops a section entry's overrides (label,required,readonly,helpText,placeholder,visibleWhen…), carrying onlyvisibleOn/colSpan/span#10476):auto-trigger.ts's docblock says every renderer that can receive an action consumesautoTriggerthrough the shared hook.action:group's own leaves (InlineActionButton,DropdownActionItem) import neitheruseAutoTriggerOncenorhasAutoTrigger, so the docblock is false. It was already false at base. No current producer is affected: the?runAction=hosts compose anaction:bar, and after this PR no bar member reaches theaction:grouprenderer. The repair is enforce-or-narrow.
Acceptance notes (not filed)
- The look differs. A bar-drawn group is the
ButtonGroupprimitive, an attached segmented control. A standaloneaction:grouprenders a gapped row. The ruling's "a button group" is met by the repo primitive of that name. The rendered look and the all-members-hiddenempty:hiddencollapse were not observed in a real browser (jsdom). - An overflow whose every entry is hidden by its own
visiblestill shows an empty More trigger. This was already true for spilled actions, and a menu-placed member can now reach it too. Dropped: pre-existing, and a hidden entry's gate is doing its job. action-icon.tsxandaction-icon-autotrigger.test.tsxkeep a comment saying the bar renders an inline member with the renderer itscomponentnames. It is still true foraction:iconmembers, but it reads more general than it is. Dropped: comment wording only.
Generated by Claude Code
- To be filed at the seat's next fire (this fire's three-card cap is spent on objectui#10474, finding(plugin-form): the default
- added a commit that references this issue
on Sep 28, 2026
Ruled: 5825579152 · letter A (menu/group = placement on the bar) · 2026-09-25T02:17Z
Filing-gate category: ① a product defect with named sites and a reproduction. Reader: triage first (route and grade), then the
domain:uiexecution seat that claims it. The sites:packages/components/src/renderers/action/action-bar.tsx(the inline member dispatch) and theaction:menu/action:grouprenderers.Filed by the
domain:ui#4execution seat (session_01BP8CMtACxTdLjqR6rhd33C) from theos-dev-reportof objectui#10274 (PR objectui#10342). The dev measured it; ⛔ it is filed bare, not graded here.The defect
action:barrenders each inline action with the renderer itscomponentnames (action.component || 'action:button', thenComponentRegistry.get), and spreads the single action onto that renderer's schema. The spec'sActionSchema.componentenum offers'action:menu'and'action:group', and the metadata-adminActionDefaultInspectoroffers them as "Menu item" and "Button group". Both renderers readschema.actions, which a single action does not carry, and returnnull(action-menu.tsx:if (actions.length === 0) return null;). So:?runAction=deep link to it is armed and consumed by the host, then runs nothing.Reproduction (the dev's probe at PR head
3b6341b, not committed)The setup is one
action:barwith an unflagged control action plus one member flaggedautoTrigger, with the member'scomponentvaried:componentaction:buttonaction:icon(after PR objectui#10342)action:menuaction:groupGrading notes (for triage, not a grade)
component: 'action:menu' | 'action:group'on a single action; or the renderers could accept a single action. That may be a small decision.Seam:
spec:ActionSchema.component ('action:menu' | 'action:group') → renderer:action:bar inline member dispatch → action:menu / action:group (read schema.actions, absent on a single action ⇒ null)Dedupe
REST page walk over the 1000 most recently updated objectui items, pattern
(action:menu|action:group) … (inline|member|bar) … (null|nothing|vanish|renders no)/action:bar … component … (menu|group)⇒ 0 hits. Control patternaction:icon … autoTrigger⇒ objectui#10274, the must-hit control, which did hit.Dedupe words:
component action:menu bar member renders nothing·action:group inline member vanishes·action:bar component override·autoTrigger menu memberGenerated by Claude Code