Repository navigation
fix(plugin-kanban): a lane that refuses the dragged card says why - #27133
Merged
Merged
Conversation
A lane the drop gate closes was dimmed and aria-disabled with no reason attached. It now carries the reason as its title and as the text its aria-describedby names, on the flat lane and on every swimlane cell. ObjectKanban answers with the message of each blocking state_machine rule that refuses the move; a host with no reason gets the new kanban.dropBlocked sentence in all ten packs. Claude-Session: https://claude.ai/code/session_01JQwxbZzYH3oXtLp9fbSkzn Co-Authored-By: Claude <noreply@anthropic.com>
Contributor
Author
席位核对ACCEPT · 席位意见:拖动卡片时,被状态机规则拒绝的列现在用规则自己的提示语说明原因(悬停提示加读屏描述),只在被拒绝时出现;规则没写提示语时用新的通用句子。
|
This was referenced Oct 28, 2026
8 of 9 tasks
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.
Requested by Warren · project thread
Fixes #27099
维护者速读
title(鼠标悬停提示)和aria-describedby(读屏)里说明原因;泳道布局的格子同样。message,即服务端拒收同一移动时给出的那句话。ui/packages/plugin-kanban/src/ObjectKanban.tsx的dropBlockedReason,再看KanbanImpl.tsx的dropBlockedReasonFor与两处车道属性。pnpm --dir ui exec vitest run packages/plugin-kanban/src/ObjectKanban.dropBlockedReason-27099.test.tsx packages/plugin-kanban/src/__tests__/dropBlockedReason-27099.test.tsx,预期 8 个测试全绿。Clause-②: no
Metadata-protocol: none
What changes
KanbanImpl.tsx.KanbanBoardPropsgains an optionaldropBlockedReason(fromColumnId, toColumnId)besidecanDropCard. While a card is dragged, a lane the gate closes now carries the reason as itstitleand as the text of a visually hidden span itsaria-describedbynames. The swimlane layout's cells, which draw the same three blocked attributes on their own, carry it the same way (one id per row and column). An open lane, and every lane outside a drag, carries neither. When the host gives no reason, the lane uses the new pack sentencekanban.dropBlocked("A card in {{from}} cannot be moved to {{to}}.") with the two column titles.ObjectKanban.tsx. Supplies the reason: themessageof each blockingstate_machinerule on the grouped field that refuses the move. Each rule is asked alone through the gate's own read (stateMachineNextValues), so a rule the gate ignores (warning-only, inactive, insert-only, or silent on the card's value) is never named, and no second copy of the gate's predicate exists. Several closing rules join their messages; a blank message falls through to the board sentence.stateMachineNextValuesand@object-ui/coreare untouched.KanbanBoardCore.tsx. Threads the new prop, as it doescanDropCard.@object-ui/i18n.kanban.dropBlockedin all ten packs.@object-ui/plugin-kanbanand@object-ui/i18n, patch.Why
The card's Expected: a blocked lane exposes the reason the drop is refused, worded from the rule that blocks it, through a title and
aria-describedbyon the existing lane element, with no new widget. Measured onorigin/mainbefore the change: the only supplier of the gate isObjectKanban'scanDropCard, and the only thing it reads is the blockingstate_machinerule on thegroupByfield. A required field never closes a lane (it prompts after the drop), and a missing update grant makes the cards not movable, so no lane is dimmed for either. The card's "transition, required field or permission" therefore reduces to the state-machine rule, whosemessagethe spec requires.Tests
ObjectKanban.dropBlockedReason-27099.test.tsx(new, beside the drop-gate test): the closed lane'stitleand accessible description are the rule's message; CONTROL, an open lane and every lane before the drag explain nothing; the reason leaves with the drag; two closing rules are joined while a rule silent on the from-state and a warning-only rule are not named; a blank message falls back to the board sentence.__tests__/dropBlockedReason-27099.test.tsx(new, realDndContext, pointer pick-up): every swimlane row's closed cell carries the reason and the open column's cells do not; the fallback is read from the zh pack under a zh provider (the two packs are first shown to differ); a host'sdropBlockedReasonwins over the fallback.Acceptance notes
/metaserves. The server's refusal of the same move resolves the message againstobjects.OBJECT._validations.RULE.messagein the caller's language, buttranslateObjectin@objectstack/spec(the served object's translation) does not touchvalidations[].message, and nothing inui/reads that key. Under a translated locale the lane therefore shows the authored text while the refusal toast would show the translated one. Reported to the seat as a finding; not changed here.Verification
All runs at head
18f0af77(the branch withorigin/main6817bf1emerged), except the two ablations, which ran on the pre-merge commit6dc7501fcarrying the same feature diff.New and neighbouring tests
pnpm --dir ui exec vitest run --maxWorkers=2over the two new files andObjectKanban.stateMachineDropGate-25933.test.tsx: Test Files 3 passed (3), Tests 14 passed (14).Ablations (each restored, blob equal to HEAD and `git diff HEAD` empty, through `scripts/ablation-replace.mjs`)
titleandaria-describedbylines:ObjectKanban.dropBlockedReason-27099.test.tsx4 failed, 1 passed (the CONTROL).titleandaria-describedbylines:__tests__/dropBlockedReason-27099.test.tsx1 failed (the swimlane case), 2 passed.Package suites and type-check
pnpm --dir ui exec vitest run --maxWorkers=2 packages/plugin-kanban/ packages/i18n/: Test Files 171 passed (171), Tests 1910 passed, 13 skipped.pnpm --filter @object-ui/plugin-kanban --filter @object-ui/i18n run type-check: exit 0 for both.Derived gates
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 34 commands; all 34 ran and exited 0 (exit captured before any pipe), pluspnpm check:changeset-fixedandpnpm --dir ui run check:new-line-citationsoutside the derivation, both exit 0.--ranreconciliation: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Families CI runs beyond the derivation (lint, type-check lanes, the full UI shards) are left to this PR's check-runs.Human Minimum
packages/specholds no runtime logic.pnpm lintpasses. (No formatter ran;pnpm lintis CI's run.)main, one pull request.packages/spectouched: its generated artifacts are regenerated and committed. (Not touched.)content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.Generated by Claude Code