Repository navigation
feat(plugin-list, plugin-chatbot): the list view and the chatbot pick with the shared Select (objectui#11865, slice p) - #12025
Merged
objectstack-fleet[bot] merged 4 commits intoOct 9, 2026
Conversation
… with the shared Select (objectui#11865, slice p) ListView's "Color by field" and its rows-per-page fallback selector, and ChatbotEnhanced's model picker, were browser-native select elements. Each is now the shared Select through a module-private picker: items carry option indexes, so the "None" option (value '') needs no empty SelectItem, and a value outside the options shows as itself. Each pick writes what the native control wrote. Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU Co-authored-by: Claude <noreply@anthropic.com>
…ove objectui#11984's readers (objectui#11865, slice p) New pins for ListView's "Color by field" and rows-per-page selector and for ChatbotEnhanced's model picker: each is the primitive, writes what the native control wrote (literals read on base), shows an outside value as itself, and opens and selects from the keyboard. objectui#11984's field-read pin read ListView's own "Color by field" through native-select readers. The wide Row color position now reads the listbox, and the stored-config rows read the trigger and the listbox; a new row pins that a rule on an unreadable field outside the columns never becomes the picker's outside item. The existing page-size and model-picker tests read the shared Select. Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU Co-authored-by: Claude <noreply@anthropic.com>
… pickers (objectui#11865, slice p) Also types the new pin's grid spy props instead of `any`. Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU Co-authored-by: Claude <noreply@anthropic.com>
…bjectui#11865, slice p) The reverse leg read the name row and the read-only row green on the native control, by design; the pin's direction note now names both. Claude-Session: https://claude.ai/code/session_01MgfduSkFrfM3eorB3UGfAU Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
objectstack-fleet
Bot
deleted the
claude/issue-11865-listview-chatbot-select
branch
October 9, 2026 04:43
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.
Part of #11865
Clause-②: no
Slice p of claim
6073419396(domain:uiseat 2, accountos-bill, sessionsession_01MgfduSkFrfM3eorB3UGfAU): the native selects left in the list view and the chatbot now use the shared RadixSelectfrom@object-ui/components, the control the rest of the console picks with. It follows the card's landed slices (objectui#11976 through objectui#12021): items carry option indexes, so an option whose value is''needs no emptySelectItem, and a stored value outside the options shows as its own item. Each picker is module-private; nothing new is exported.packages/plugin-list/src/ListView.tsxListOptionPickerplugins-views, eagerpackages/plugin-list/src/ListView.tsxListOptionPickerplugins-views, eagerpackages/plugin-chatbot/src/ChatbotEnhanced.tsxModelPickerplugin-chatbot, eagerCount first. On base
2063f7a96the census matched 3 lines inListView.tsxand 1 inChatbotEnhanced.tsx; the real elements are 2 and 1. The thirdListView.tsxline sat in the multi-line JSX comment above the rows-per-page selector ("Rendering a second native select here produced a duplicate control"). That comment now says "a second selector", so the census stops counting it. On head, each file matches the census once more, in prose: the new picker's docblock says the control "used to be a browser-native select", in the same words as the twin's docblock.What stays the same
Every option writes what the native control wrote. A scratch probe on base
2063f7a96fired achangeevent for every option of each native control and recorded the write. Each pin compares against those readings as JSON text:undefined, and a picked field keeps the config's colours.onPageSizeChange, and the next fetch's$top, over three paginations: a declared 25, none declared, and a declared 7.onModelChange, over three selections: none (the first model is in force), an offered model, and a model none of the options carries.Re-picking the current option writes nothing, as a browser's native select did. The probe's synthetic
changefired for the current option too, so the re-pick rows pin the primitive.Accessible names:
aria-labelitsmodellabel gives it (pinned, with a label override).htmlFor, the "Rows per page" text is a span, neither had anaria-label, and the probe read an empty name. So none is kept, and none is added, as slice m did for the twin.Keys: Enter opens each picker and Enter on an option selects it; pinned on all three. In the chatbot this happens inside the composer's form, and the draft is not sent (pinned).
Read-only: the list's two surfaces have no read-only state. The chatbot's
readOnlytranscript has no composer, so no picker, as before (pinned). Itsdisabledprop did not disable the native select on base and does not disable the picker now: unchanged, and noted below.One display change
A value none of a picker's options carries now shows as itself. On base, the native select showed its first option instead:
ghostoutside the list's columns read "None", while the popover's Clear button said a rule was set;All three are pinned, and picking the outside item writes nothing.
"Color by field" now matches its twin,
ViewSettingsPopover'sColorFieldPicker(objectui#12019), whose header asks the two to stay in step: the same outside item and the same "None" handling.ViewSettingsPopover.tsxis not edited.objectui#11984's field-read pin, carried in
ListView.fieldListRead-11984.test.tsxreadListView's own "Color by field" through native-select readers. They now read the sharedSelect:pickerLabels(); the nativeselectLabels()helper is removed;toHaveValue;offeredRowColorConfig), so a field the caller may not read never reaches that item.Every enumerated position still asserts the same field set. The ablations ran through objectstack
scripts/ablation-replace.mjsin wrap mode. Each printed "ok mutation landed", then "ok restored: blob == HEAD" withgit diff HEADempty.ListView.tsx2063f7a9616f8fa0c5allFieldsdropscanReadField(object columns)offeredRowColorConfigdropscanReadField6c4bf4ff1)allFieldsablation: the base 11 stay red, the wide Row color position and the View settings one among them. Both stored-config row-colour rows join them, red at the listbox read, which offered "Secret Note" and "Secret Status". On base the stored-config row stayed green: its native reader never readallFields. Their full-read legs cannot turn red under this ablation, by construction: with full read,canReadFieldanswers true.offeredRowColorConfigablation: both stored-config row-colour rows turn red, and the trigger readssecret_note. That is the outside item naming a withheld field, the exact hazard the added row pins.ListView.tsxchanged after the heads named.Reverse leg (both sources put on their base blobs and checked by hash, trap-restored to HEAD, blob checked): the five touched test files read "Tests 54 failed | 255 passed (309)".
ListView.sharedSelect-11865: 34 of 34 red.ChatbotEnhanced.modelPicker-11865: 13 red, 2 green. The green rows are the name row and the read-only row, which keep a behaviour.ListView.test: 3 red (the page-size readers), 145 green.ListView.fieldListRead-11984: 3 red (the Row color position and both stored-config row-colour rows), 18 green.ChatbotEnhanced.test: 1 red (the model-picker test), 90 green.First-load bytes
apps/console,CI=true pnpm exec vite build, under the verify lock, in this worktree: at base2063f7a96before any edit, and at head4a02099e4.eagerGzipByteseagerRawBytes2063f7a964a02099e4plugin-chatbot(+153 gzip / +335 raw:ModelPicker) andplugins-views(+18 / +222:ListOptionPicker; the twin already brings the sharedSelectinto that chunk). The rest is minifier churn:index-8,studioScope-2,ViewVariantInspector-1,src-1.pnpm check:eager-closureon the head build prints "Console eager closure is 3161.7 KB gzipped across 289 of 2474 chunks (budget: 3204.6 KB, headroom: 42.8 KB)", with the chunk membership green.scripts/check-eager-closure-budget.mjsis untouched.Evidence (head
4a02099e4)pnpm exec vitest run --maxWorkers=2 packages/plugin-list/ packages/plugin-chatbot/ packages/core/src/utils/__tests__/column-identity.ratchet.test.ts scripts/__tests__/one-authority-per-exported-name-6273.test.ts, at the repo root under the lock, reads "Test Files 185 passed (185)" and "Tests 1992 passed (1992)", with VERDICT command-exit 0.pnpm --workspace-concurrency=2 --filter '@object-ui/plugin-list^...' --filter '@object-ui/plugin-chatbot^...' run build: 13 of 47 projects, exit 0):pnpm --filter @object-ui/plugin-list type-checkexits 0;pnpm --filter @object-ui/plugin-chatbot type-checkexits 0;tsc --noEmit && tsc -p tsconfig.test.json, and--listFilesOnlylists all five touched test files.pnpm exec eslint --format jsonon the 7 touched source and test files reads 0 errors. Warnings per file equal the base blob's:ListView.tsx187,ChatbotEnhanced.tsx10,ListView.test.tsx26. The others, both new pins included, read 0.node scripts/check-changeset-presence.mjsexits 0: "7 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)".node scripts/check-changeset-no-major.mjsexits 0.pnpm check:new-line-citationsexits 0: "0 new citation(s)".pnpm check:control-bytesexits 0, and a control-byte grep over the changed files finds nothing.Not on it
packages/components/src/ui/**,packages/i18n/**,StudioDesignSurface.tsx(slice o),ViewSettingsPopover.tsxandscripts/check-eager-closure-budget.mjs.useAgents.Acceptance notes
AiChatPage.tsx, the comment besidemodels=says the chatbot "renders the footer" native select. It is now the sharedSelect. That is wording only, in a file outside this slice. Carrier: the next PR that touchesAiChatPage.tsx.disabledprop disables the composer's textarea and submit, but not the model picker, on base and on head. This slice keeps that. Carrier: none.elements/prompt-input.tsxalready exportsPromptInputSelectwrappers around the sharedSelect, and nothing calls them. This slice uses the sharedSelectdirectly, as triage directs. Carrier: none.Generated by Claude Code