fix(task-board): name lanes after the board's columns, not Studio's - #6771
Merged
Conversation
A board mirrored from a tracker was still being read through Studio's own vocabulary in three places, and each one misled in its own way: - A status no column accounts for got OUR translation. A stranded `triage` card rendered as "Backlog" beside the tracker's real Backlog — a second column, identical in appearance, that nobody could act on because it does not exist over there. `laneHeader` gives an off-board lane neither our name nor our icon: it is labelled by its raw status and carries an "off board" badge that says why it is on screen. - Dropping onto a lane's own droppable was validated against Studio's `STATUSES`, which on a mirrored board matches no column at all — so dragging a card into an empty Jira column resolved to null and the card sprang back. Validated against the board's columns now. Off-board lanes are deliberately not drop targets: a card can leave one, never be filed into one, and the "new task here" button is gone for the same reason. - "Move to" and the status dropdown offered the canonical lanes whoever's board it was, so on a mirrored board every entry named a column the server rejects. `moveTargets` takes the board's columns. `laneLabel` is now module-private. Naming a lane requires knowing whether the board even HAS a column for it, and every caller that skipped that question is the bug above; `laneHeader` is the way in. `STATUSES` goes with it — it had become a second copy of `CANONICAL_COLUMN_KEYS` with no reader but a test.
decocms Bot
pushed a commit
that referenced
this pull request
Aug 31, 2026
PR: #6771 fix(task-board): name lanes after the board's columns, not Studio's Bump type: patch - decocms (apps/api/package.json): 4.305.2 -> 4.305.3 - @decocms/native (apps/native/package.json): 4.305.2 -> 4.305.3 Deploy-Scope: web
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.
Follow-up to the mirrored-board series. On a board whose columns come from a
tracker, three surfaces were still speaking Studio's vocabulary. Each one
misled differently.
A stranded card was masquerading as a column
The board draws a lane for any status no column accounts for (#6727), so a card
can't go invisible. But that lane was labelled with our translation — a
triagecard on a mirrored board rendered as "Backlog", sitting next to thetracker's own Backlog column. Two identical-looking columns, one of which does
not exist over there and nobody can act on.
laneHeader(status, t, columns)now answers naming and appearance together,because they're the same question: a column the board owns is drawn with its
own name and, if it's one of ours, our icon. A status off the board gets
neither — it's labelled by its raw key and carries an
off boardbadge with atooltip saying why it's on screen. The "new task here" button is gone for it
too: a card created in a non-column would be stranded the moment it existed.
laneLabelis now module-private. Naming a lane requires knowing whether theboard even has a column for it, and every caller that skipped that question
is the bug above.
You couldn't drag a card into an empty column
A lane's droppable was validated against Studio's
STATUSES, which on amirrored board matches no column at all — so dropping onto an empty column
resolved to null and the card sprang back. Only dropping onto an existing card
worked, which made it look like an intermittent bug rather than a rule.
Extracted as
dropLane, validated against the board's columns, with the twoways of being over a lane (its droppable, or a card in it) gated by one rule.
That closes the mirror-image hole too: hovering a card in an off-board lane
used to resolve to that lane, so the drop appeared to work until the list
refetched and the server's rejection showed.
"Move to" was a list of ways to fail
The bulk menu and the task's status dropdown offered the canonical lanes
whoever's board it was. On a mirrored board every entry named a column the
server rejects.
moveTargetstakes the board's columns now;useBoardColumnsreads them off the same cached list without opening the board's SSE streams.
STATUSESis deleted — it had become a second copy ofCANONICAL_COLUMN_KEYSwith no reader but a test.
Verification
Against a local board with five mirrored columns and one Studio-native card
stranded off it:
status with the
off boardbadge and no new-task button.persisted (verified in Postgres). That run predates the
dropLaneextraction; the extraction itself is covered by unit tests, and the wiring
is four lines.
Unit tests cover
dropLane(4),laneHeader(3),moveTargetson a mirroredboard, and
laneVisibility's newunplaced.bun run check,lint,fmt,and
knipare clean.Still open
no stable column id, so the key is the name.
board_column_orgnull.in_reviewroles are settable but read by nothing yet.Summary by cubic
Fixes the task board so lanes, drag targets, and the move menu follow the board's own columns instead of Studio's canonical statuses. On boards mirrored from a tracker, canonical names matched no real column, so stranded cards looked like phantom columns, drops into empty columns failed, and "Move to" listed statuses the server rejects.
Bug Fixes
Refactors
laneHeaderreplaces the publiclaneLabel, which is now module-private; naming a lane requires knowing whether the board has a column for it.dropLanehandles both ways of being over a lane — its droppable or a card in it — with one rule.STATUSESis deleted;moveTargetsanduseBoardColumnsread columns from the same cached query as the board.Written for commit 582599a. Summary will update on new commits.