AFTER — #1527 (Move Forward + Change Status) and #1528 (Assign + assignee) designed together.
Both land in the same hero/action region of TaskDetailPane.tsx, so they get one
design-system section (§IR) and one mount point: a StaffActionBar band
directly under the hero card. The hero action row itself is untouched — that is how state 1
stays byte-for-byte today's pane.
No new colour: everything below is §2/§3 tokens already in the system.
1Ordinary client — internal_role: null
Nothing is added. No staff bar, no Move Forward, no Change Status, no Assign, and
no assignee name anywhere — the payload does not carry assigned_to_name at all
for this viewer, so the name is absent from the HTTP response, not merely hidden in the DOM
(spec decision 7). Identical to the BEFORE capture.
#1527Spec✦ Feature
Ticket panel: Move Forward and a role-correct Change Status control
RARequested by Redmine Admin
Updated 2 hours ago
✳
✎ Edit
⏸ Pause
GET …/tasks/1527 → { status_id: 8, allowed_statuses: [] }
no can_move_forward · no can_assign · no assigned_to_name key
At a glance
- Reference
- #1527
- Stage
- Spec
- Type
- Feature
2Developer, assigned to this ticket
One control, not two. The server sends allowed_statuses already narrowed
to what this viewer may set — for a developer that is exactly [next_status], so
length < 2 ⇒ Change Status is not rendered and Move Forward is the only door. A
one-option dropdown would be a menu offering a choice that does not exist, three clicks for what
the button does in one. The label names the target stage, from
next_status_id + next_status_name.
#1527Spec✦ Feature
Ticket panel: Move Forward and a role-correct Change Status control
RARequested by Redmine Admin
✳
✎ Edit
⏸ Pause
⚙ Staff controls
→ Move to Design
You are assigned to this ticket.
can_move_forward: true · next_status_id: 15 ("Design")
allowed_statuses: [ {id:15, name:"Design"} ] → 1 option ⇒ no dropdown
At a glance
- Reference
- #1527
- Stage
- Spec
- Assigned to
- GWGuillaume W.
3Developer, not assigned — disabled + tooltip
The button is present and keyboard-focusable: aria-disabled="true"
with the click handler short-circuited, never a bare disabled (which drops it out of
the tab order, so the explanation becomes unreachable exactly for the people who need it most).
The tooltip is the aria-describedby target, shown on hover and on
:focus-visible. Below: the same button focused by keyboard, with the second reason
shape — nothing left to advance to.
#1531In development
Backend: the progression rule and the move-forward route
RARequested by Redmine Admin
✳⏸ Pause
⚙ Staff controls
Only the developer assigned to this ticket can move it forward.
→ Move to QA
⚙ Staff controls — variant: no next stage (ticket is Shipped)
This ticket is at the end of the pipeline.
→ Move forward
focus-visible ring — the tooltip opens on keyboard focus too
can_move_forward: false, next_status_id: 10 → “not assigned to you”
can_move_forward: false, next_status_id: null → “end of the pipeline”
allowed_statuses: [] in both cases ⇒ no Change Status control
At a glance
- Stage
- In development
- Assigned to
- ALAlice L.
4CTO / platform admin — full set, backward included, plus Assign
Three controls on one row, in decreasing frequency of use:
Move Forward (primary — the one verb used twenty times a day) → Change Status
(the correction path, forward and backward) → Assign. The Change Status menu lists
allowed_statuses verbatim: the frontend holds no status order, so it cannot decide
what “forward” means and does not try. Backlog is absent because the server never puts it there.
#1527Spec✦ Feature
Ticket panel: Move Forward and a role-correct Change Status control
RARequested by Redmine Admin
✳✎ Edit⏸ Pause
⚙ Staff controls
→ Move to Design
SpecChange status▾
GWAssigned to Guillaume W.▾
Assign menu open — GET /projects/9/developers. “Unassigned” is an
explicit first option, separated by a hairline from the people.
Change Status menu (same anatomy as the existing TransitionControl,
§TB.6): each target is a TaskStatusPill, selecting one opens the inline
confirm step before the mutation fires. Backward targets are listed in the server's order,
unmarked — a “backward” badge would need a status order in src/.
can_move_forward: true · can_assign: true · next_status_id: 15
allowed_statuses: 7, 15, 9, 10, 11, 12, 13, 14 → ≥ 2 options ⇒ dropdown renders
At a glance
- Reference
- #1527
- Stage
- Spec
- Assigned to
- GWGuillaume W.
5Backlog ticket, viewed by a CTO — the credit gate holds
No status control renders for anyone, including CTO and admin. Not a disabled
Move Forward with an explanation — absent. Submit stays the only way out of the backlog,
and the pane must not suggest a second door exists. The Assign control survives: assigning
changes no status and costs no credit, so a CTO can line the work up before the client pays.
#1528Backlog✦ Feature
Ticket panel: Assign to Developer and assignee visibility
Complexity 4/10
➤ Submit to the team
✳
✎ Edit
⏸ Pause
⚙ Staff controls
—Unassigned▾
No developer is configured for this project.
Empty-state variant of the Assign control: GET …/developers legitimately
returned []. The trigger is aria-disabled (focusable, described by
the note), never an empty menu that opens onto nothing.
Filing is free — nothing starts until you submit this ticket.
status_id: 16 → Move Forward and Change Status are not rendered
can_move_forward: false · next_status_id: null · allowed_statuses: []
can_assign: true — assignment is not a status change
At a glance
- Stage
- Backlog
- Assigned to
- Unassigned
6Server refusals — inline, never blanking the pane
Every error is a role="alert" paragraph inside the staff bar, under
the control that produced it. The ticket, its description and its criteria stay on screen; the
status pill never showed an unconfirmed stage, because the controls are pessimistic by design —
there is no optimistic state to roll back. Each failure still invalidates the board and detail
queries, so a pane made stale by someone else converges on the next paint.
⚙ Staff controls
→ Move to QA
In developmentChange status▾
⚠ 403 — You're not allowed to make that change. The ticket has been refreshed.
⚠ 409 — Couldn't move this task. (the existing invalid-transition message, reused verbatim)
MDAssigned to Marc D.▾
⚠ 422 — Marc D. has no Redmine account linked yet. An admin can add one in the admin dashboard.
⚠ upstream — Couldn't change the assignee.