Repository navigation
feat(app-shell,plugin-kanban): a card on a kanban view leaf's Studio canvas selects the board's card in a 看板卡片 section (objectui#12725, part) - #12900
Merged
objectstack-fleet[bot] merged 8 commits intoOct 17, 2026
Conversation
…s selects the board's card in the view's properties (objectui#12725, part)
On an object leaf whose list view renders as a kanban board, a card click
on the Studio canvas selects "the card": the pillar's one selection gains a
{ kind: 'card' } member, so the slot switches to 属性, Esc and an empty
canvas click clear it, and the status line names it. The click and the
pointer press are taken in the capture phase, so the record does not open
and no drag starts; a control inside a card keeps its job.
The channel is a Studio-internal StudioCanvasCardSelectionContext beside the
published props; StudioCanvasPreviewProps and index.ts are unchanged.
ObjectListViewInspector gains a 看板卡片 section on a kanban view. Each
control writes one spec-declared key: kanban.columns, kanban.titleField,
navigation.mode and kanban.groupByField. No colour control.
SortableCard carries one additive data-kanban-card attribute with the
card's record id, so the canvas can tell which card a click landed on and
outline it.
Claude-Session: https://claude.ai/code/session_01HRnFN6Rtqk2WxPiK6qBhwq
Co-authored-by: Claude <noreply@anthropic.com>
…ction (objectui#12725, part) Through the mounted surface with the real board: a card click switches the slot to 属性, outlines the card and names it on the status line, and neither opens the record nor lets the press reach the card; Esc and an empty-canvas click clear it. Each of the four controls writes exactly its spec key and the saved body parses as ListViewSchema; a view with no kanban block is born by the group-by field. Controls: a grid leaf has no section, the board outside Studio opens a record and takes the press, a canvas registered over the default gets no channel. Claude-Session: https://claude.ai/code/session_01HRnFN6Rtqk2WxPiK6qBhwq Co-authored-by: Claude <noreply@anthropic.com>
… on the Studio canvas (objectui#12725, part) Claude-Session: https://claude.ai/code/session_01HRnFN6Rtqk2WxPiK6qBhwq Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HRnFN6Rtqk2WxPiK6qBhwq Co-authored-by: Claude <noreply@anthropic.com>
objectui#12888 split SortableCard into a list item wrapping a role=button control; data-kanban-card moves to the control, which holds the ref, the listeners and the click and key handlers. Claude-Session: https://claude.ai/code/session_01HRnFN6Rtqk2WxPiK6qBhwq Co-authored-by: Claude <noreply@anthropic.com>
…n the Studio canvas (objectui#12725, part) objectui#12888 made a focused card open on Enter and on Space's release, as a click does. On the Studio canvas the keys now do what the click does there: KanbanCardSelect takes keydown Enter and keyup Space in the capture phase on the card element itself and selects the card, and holds Space's press so the board does not scroll and the board's own handler does not run. A key on a control inside a card stays that control's. Outside Studio nothing changes. Pins: Enter selects, Space selects on release, a key on a control inside a card is not taken, and the CONTROL that Enter opens the record outside Studio. The fixture card follows the board's new list item and button nesting. Claude-Session: https://claude.ai/code/session_01HRnFN6Rtqk2WxPiK6qBhwq Co-authored-by: Claude <noreply@anthropic.com>
…ndlers on the Studio canvas (objectui#12725, part) Claude-Session: https://claude.ai/code/session_01HRnFN6Rtqk2WxPiK6qBhwq Co-authored-by: Claude <noreply@anthropic.com>
…(objectui#12725, part) Claude-Session: https://claude.ai/code/session_01HRnFN6Rtqk2WxPiK6qBhwq 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
|
Contributor
Author
席位核对 — ACCEPT · objectui#12725 phase 4 · head
|
Contributor
Author
Landing · head
|
objectstack-fleet
Bot
deleted the
claude/issue-12725-kanban-card-panel
branch
October 17, 2026 15:50
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 #12725
Clause-②: no
This lands the release's remainder item 1: a kanban view leaf's card. Still on #12725: item 3's 草稿 chip and 来源 line, which need the copilot's draft provenance per field, and items 4 and 5 (change card v2, the 变更 badge counting the copilot's drafts), which need objectstack-ai/cloud#2924's payload.
What changed
On an
objectleaf whose list view renders as a kanban board (type: 'kanban'), a click on a card in the Studio canvas selects "the card":The click is taken in the capture phase, so the record does not open. The pointer press on a card is taken there too, so the board's drag sensor never starts a move on the Studio canvas. Enter, and Space on its release, on a focused card select it the same way (see objectui#12888 below). A button or link drawn inside a card keeps its click and its keys. Esc, or a click on empty canvas, clears the selection, and the slot keeps the view's properties. Outside Studio the board is unchanged: a click opens the record and a drag moves the card.
studio-canvas-preview.tsx: a Studio-internalStudioCanvasCardSelectionContextbeside the published props, in the pattern of phase 3'sStudioCanvasColumnSelectionContext. The default object canvas wraps the grid in one moredisplay: contentselement (KanbanCardSelect) that reads it.StudioCanvasPreviewPropsandindex.tsare unchanged, and a canvas registered over the default sees no channel.StudioDesignSurface.tsx: the card is a member of the pillar's one keyed selection,{ kind: 'card', id: RECORD_ID }, beside phase 3's{ kind: 'column' }, not a second, parallel state. SoshowProps, Esc and the empty-canvas click are the existing seam. The channel is provided only while the panel holds a kanban view of the open leaf.ObjectListViewInspector.tsx: the 看板卡片 section, shown only when the view'stypeiskanban, first in the panel, writing through the inspector's existing draft path.metadata-admin/i18n.ts: 17 en and zh rows. No@object-ui/i18nkey.How a card is identified, and plugin-kanban
SortableCardgains ONE additive attribute,data-kanban-cardset to the card's record id; nothing else inplugin-kanbanchanges, so objectui#12838'saria-labelwork in the same file stays clear. objectui#12888 (merged into this branch) split the card into arole="listitem"wrapping arole="button"control that holds the ref, the drag listeners, the click and the new Enter and Space handlers; the attribute sits on that control, soclosest('[data-kanban-card]')and the outline rule each resolve to exactly one element per card. Because #12888 opens a focused card on Enter and on Space's release, the canvas takes those keys in the capture phase too, only on the card element itself (#12888's own guard): Enter and Space's release select the card, Space's press is held so the board does not scroll, and neither reaches the card's handlers. Outside Studio the keys open the record, as #12888 made them. Measured why the existing DOM was not enough:role="listitem"alone does find a card (the board draws no other list item), but the outline has to name the clicked card, andaria-labelis the card's title, which is record text that two cards can share (and a translated or derived title besides). A style rule keyed on it would outline every card of that title. The record id names exactly one card.The outline is a style rule scoped to the wrapper, as phase 3's column outline is: the board owns its cards and redraws them, so no class can be put on a card from outside.
The four controls
Each writes one key the spec declares, and only that key (
@objectstack/spec18.0.0-next.3, unchanged from next.2 for these keys):kanban.columnsKanbanConfigSchema.columns: "Fields to show on cards"kanban.titleField; 记录名称 removes the keyKanbanConfigSchema.titleField: "Omit to fall back to the record display name (ADR-0079 resolver chain)"navigation.mode; 默认 removes the key (and an emptynavigationblock with it)NavigationConfigSchema.modeoverNavigationModeSchema: page, drawer, modal, split, popover, new_window, nonekanban.groupByFieldKanbanConfigSchema.groupByField"Field to group columns by", checked bygroupByFieldCheck, which refuses only a padded name; every field of the object is offeredKanbanConfigSchemais a strict object that requiresgroupByFieldandcolumns. So on a kanban view with nokanbanblock, the title and the card fields are disabled with a note until a group-by field is picked, and picking it writes{ groupByField, columns: [] }; on an emptykanban.columnsthe board shows the view's first columns, as before. No colour control (rowColorhas no reader inplugin-kanban), and nosummarizeFieldcontrol (the StudioRailProps artboard draws none); an existingsummarizeFieldis kept as written.Live, before and after
e2e/live/ci/start-backend.sh(published@objectstack/*@18.0.0-next.3, showcase2c9bf9430a11), console frommain26323c4(before) and this branch9591cd2(after), Chromium, light, zh-CN, 1280 and 1010 px. Leaf: 界面 › 数据模型 › 任务看板(看板视图), the showcase's ownboardkanban view ofshowcase_task.Deviations
task.view.tsboard,project.view.tsby_status), but noobjectnav entry of the showcase lands on one, so there is no kanban view leaf to open (phase 3 measured the same). The live reading adds one entry in the browser,{ type: 'object', objectName: 'showcase_task', viewName: 'board' }, identically for before and after. The README beside the screenshots lists every stub.plugin-kanbanis touched by the one attribute above, as ruling 3 allows when the existing DOM cannot identify a card.Acceptance notes
after-1280-card-enter.png).mainand on this branch alike (before-1010-open.png).Screenshots
Evidence branch
claude/issue-12725d-evidence, commits1f37ce5(the click reading) andd2eac2e(the Enter reading), underdocs/design/findings/12725d/(18 PNGs, the DOM readings as JSON, the driver and a README):main), 1280: https://github.com/objectstack-ai/objectui/blob/1f37ce51ae5ebe171a21af2b7e7285e546b1dfba/docs/design/findings/12725d/before-1280-card-click.png?raw=truemain), 1010: https://github.com/objectstack-ai/objectui/blob/1f37ce51ae5ebe171a21af2b7e7285e546b1dfba/docs/design/findings/12725d/before-1010-card-click.png?raw=true9bce2a9, after objectui#12888), 1280: https://github.com/objectstack-ai/objectui/blob/d2eac2eba3d030eab80827a980b0adb28d8426af/docs/design/findings/12725d/after-1280-card-enter.png?raw=trueTest evidence (head
9bce2a9; the suites ran on14078da, and9bce2a9changes only the changeset's prose)StudioDesignSurface.kanbanCardSelection-12725.test.tsx, 16 tests through the mounted surface with the realStudioObjectRecordsCanvasand the real kanban board: the card click (slot 属性, section selected, outline, status line, no record opened, the press never reaches the card); Enter on a focused card selects it; Space selects on its release, and neither half reaches the card's own handlers; a control inside a card keeps its click and its keys; Esc; empty canvas; each control writes exactly its key and the saved body parses asListViewSchema; a view with nokanbanblock. Controls: a grid leaf has no section; the board outside Studio opens the record on a click and on Enter, and takes the press; a canvas registered over the default gets no channel.StudioDesignSurface*,studioCanvas*/studio-canvas-previewandObjectListViewInspector*test: 97 files, 671 tests passed.packages/plugin-kanban/(objectui#12888's tests included): 75 files, 506 tests passed. Phase 3'sleafColumnSelection-12725is in the family run, unchanged and green.type-checkfor@object-ui/app-shelland@object-ui/plugin-kanban: exit 0.buildfor both: exit 0.eslint(normal mode) on the changed files: 0 errors, and the diff adds noeslint-disabledirective; the new warnings arereact-refresh/only-export-componentson the new exports, the rule already firing in both files.check:i18n-keys,check:i18n-drift,check:i18n-designer-parity,check:new-line-citations(0 new),check:test-path-roots,check-changeset-presence: all exit 0.ablation-replace.mjsin wrap mode (each restore proven with an emptygit diff HEAD): the card select off, the click's stopPropagation off, the press capture off, the outline naming another card, the control exemption off,data-kanban-cardremoved, the channel not provided, Esc off, empty-canvas clear off,showPropsoff, the section on every view, the section not marked selected, each of the four writes broken, the record-name option keeping the title, a born block withoutcolumns, the title not held for the block; after objectui#12888, Enter not taken, Space's release not taken, Space's press not held, the own-key guard widened to anything inside a card, the key path not stopped, and the attribute removed again: each turned at least one test red. Not pinned, by measurement: the channel's kanban gate (no cards exist on a non-kanban canvas to tell it apart).Generated by Claude Code