fix(dashboard): one queued badge family — map raw 'queued', fold queued-to-plan into the status badge

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-07-31 20:33:34 -07:00
parent 577dcb6c0c
commit 7e4e892fce
3 changed files with 32 additions and 16 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: One queued badge family — scheduler-queued cards read "Queued", and Queued to plan is the same badge as Planning.
category: fix
dev: Raw status "queued" no longer renders the lowercase engine token; the standalone queued-to-plan pill is removed and folds into the main status badge span (same classes/tooltip, testid preserved), so a card can never show two queued labels.

View File

@@ -3392,7 +3392,15 @@ function TaskCardComponent({
? t("tasks.needsInput", "Needs input") ? t("tasks.needsInput", "Needs input")
: isTransientPlannerActive : isTransientPlannerActive
? t("tasks.statusPlanning", "Planning") ? t("tasks.statusPlanning", "Planning")
: getTaskStatusLabel(visualStatus ?? "", t, showOptionalGateBadge ? undefined : getRunningWorkflowStepLabel(task), { idle: !isAgentActive, overlapBlockedBy: task.overlapBlockedBy ?? null }); /*
FNXC:TaskStatusBadge 2026-08-01-03:20 (operator: ONE queued badge family, no dupes):
Queued-to-plan renders through THIS badge now — same span, same family as Planning —
instead of the standalone `queued-to-plan` pill it used to be (removed below). One card,
one badge; the muted modifier class and testid survive on this span.
*/
: showQueuedToPlanBadge
? t("tasks.queuedToPlan", "Queued to plan")
: getTaskStatusLabel(visualStatus ?? "", t, showOptionalGateBadge ? undefined : getRunningWorkflowStepLabel(task), { idle: !isAgentActive, overlapBlockedBy: task.overlapBlockedBy ?? null });
const hasCardMetaBadges = showPriorityBadge const hasCardMetaBadges = showPriorityBadge
|| task.executionMode === "fast" || task.executionMode === "fast"
// FNXC:PlannerOversight 2026-07-04-00:00: the oversight badge is opt-in // FNXC:PlannerOversight 2026-07-04-00:00: the oversight badge is opt-in
@@ -3536,9 +3544,9 @@ function TaskCardComponent({
: pausedByAgent ? t("tasks.pausedByAgent", "paused by agent") : t("tasks.paused", "paused")} : pausedByAgent ? t("tasks.pausedByAgent", "paused by agent") : t("tasks.paused", "paused")}
</span> </span>
)} )}
{showStatusBadge && ( {(showStatusBadge || showQueuedToPlanBadge) && (
<span <span
className={`card-status-badge card-status-badge--${task.column}${isAwaitingApproval ? " awaiting-approval" : ""}${isPlanReviewReplanCapApproval ? " awaiting-approval--plan-review-replan-cap" : ""}${isAwaitingInput ? " awaiting-input" : ""}${isAgentActive ? " pulsing" : ""}${isFailed ? " failed" : ""}${isStuck ? " stuck" : ""}`} className={`card-status-badge card-status-badge--${task.column}${showQueuedToPlanBadge ? " queued-to-plan" : ""}${isAwaitingApproval ? " awaiting-approval" : ""}${isPlanReviewReplanCapApproval ? " awaiting-approval--plan-review-replan-cap" : ""}${isAwaitingInput ? " awaiting-input" : ""}${isAgentActive ? " pulsing" : ""}${isFailed ? " failed" : ""}${isStuck ? " stuck" : ""}`}
title={ title={
isPlanReviewReplanCapApproval isPlanReviewReplanCapApproval
? t( ? t(
@@ -3560,6 +3568,11 @@ function TaskCardComponent({
idle Revising card explains itself. Gated on !isAgentActive so a genuinely idle Revising card explains itself. Gated on !isAgentActive so a genuinely
running revise cycle keeps no misleading "waiting" text. running revise cycle keeps no misleading "waiting" text.
*/ */
: showQueuedToPlanBadge
? t(
"tasks.queuedToPlanTitle",
"Waiting for a planning slot — planning starts when an agent slot frees up",
)
: task.status === "needs-replan" && !isAgentActive : task.status === "needs-replan" && !isAgentActive
? t( ? t(
"tasks.needsReplanQueuedTitle", "tasks.needsReplanQueuedTitle",
@@ -3568,7 +3581,7 @@ function TaskCardComponent({
: undefined : undefined
} }
aria-label={isTransientPlannerActive ? t("tasks.statusPlanning", "Planning") : undefined} aria-label={isTransientPlannerActive ? t("tasks.statusPlanning", "Planning") : undefined}
data-testid={isAwaitingApproval ? `card-awaiting-approval-${task.id}` : undefined} data-testid={isAwaitingApproval ? `card-awaiting-approval-${task.id}` : showQueuedToPlanBadge ? `card-queued-to-plan-${task.id}` : undefined}
data-awaiting-approval-reason={isAwaitingApproval ? (task.awaitingApprovalReason ?? "manual") : undefined} data-awaiting-approval-reason={isAwaitingApproval ? (task.awaitingApprovalReason ?? "manual") : undefined}
> >
{statusBadgeLabel} {statusBadgeLabel}
@@ -3624,18 +3637,6 @@ function TaskCardComponent({
find. Names the surviving dimension only. Worktrees can also be the binding gate, but only when find. Names the surviving dimension only. Worktrees can also be the binding gate, but only when
the operator has worktree limiting on, so it is not stated unconditionally here. the operator has worktree limiting on, so it is not stated unconditionally here.
*/} */}
{showQueuedToPlanBadge && (
<span
className="card-status-badge card-status-badge--todo queued-to-plan"
data-testid={`card-queued-to-plan-${task.id}`}
title={t(
"tasks.queuedToPlanTitle",
"Waiting for a planning slot — planning starts when an agent slot frees up",
)}
>
{t("tasks.queuedToPlan", "Queued to plan")}
</span>
)}
{hasInReviewStall && stallCopy && ( {hasInReviewStall && stallCopy && (
<span <span
className={`card-status-badge card-status-badge--in-review in-review-stall in-review-stall--${stallCopy.code}`} className={`card-status-badge card-status-badge--in-review in-review-stall in-review-stall--${stallCopy.code}`}

View File

@@ -74,6 +74,14 @@ export function getTaskStatusBadgeLabel(
return t("tasks.statusQueuedBehind", "Queued behind {{taskId}}", { taskId: context.overlapBlockedBy }); return t("tasks.statusQueuedBehind", "Queued behind {{taskId}}", { taskId: context.overlapBlockedBy });
} }
/* /*
FNXC:TaskStatusBadge 2026-08-01-03:20 (operator: one queued family, like the planning badge):
Raw "queued" (scheduler capacity/dependency marker) previously fell through to the verbatim
lowercase engine token. Map it so every queued state reads as the same badge family.
*/
if (status === "queued") {
return t("tasks.statusQueued", "Queued");
}
/*
FNXC:TaskStatusBadge 2026-07-26-14:05: FNXC:TaskStatusBadge 2026-07-26-14:05:
"planning" is an engine token, not operator copy, and it was only ever hidden because U12's "planning" is an engine token, not operator copy, and it was only ever hidden because U12's
workflow-step override happened to cover the same cards. Now that the Plan Review gate has its own workflow-step override happened to cover the same cards. Now that the Plan Review gate has its own