fix(dashboard): never show raw landing/reviewing on task status badges

Share one badge label mapper for board and list so AI-merge pipeline
statuses always display as Merging… instead of engine strings.
This commit is contained in:
gsxdsm
2026-07-15 10:39:57 -07:00
parent 49a459a869
commit e172b13612
4 changed files with 51 additions and 11 deletions

View File

@@ -22,6 +22,7 @@ import { useViewportMode } from "../hooks/useViewportMode";
import { getScopedItem, removeScopedItem, setScopedItem } from "../utils/projectStorage";
import { ALL_WORKFLOWS_BOARD_VIEW_ID } from "../utils/boardWorkflowSelection";
import { getUnifiedTaskProgress, isPlanReviewRunning } from "../utils/taskProgress";
import { getTaskStatusBadgeLabel } from "../utils/taskStatusBadgeLabel";
import { useConfirm } from "../hooks/useConfirm";
import { extractDependencyDeleteConflict, extractLineageDeleteConflict } from "../utils/taskDelete";
import { WorkflowSwitcher } from "./WorkflowSwitcher";
@@ -76,9 +77,12 @@ function isListContextInteractiveTarget(target: EventTarget | null): boolean {
type SortField = "title" | "status" | "column" | "retries";
/*
FNXC:MergeQueue 2026-07-15-10:45:
List status column used to print raw engine statuses (landing/reviewing). Share the board badge mapper so list and card never diverge.
*/
function getTaskStatusLabel(status: string, t: TFunction<"app">): string {
if (status === "merging-fix") return t("listView.statusMergingFix", "Merging fixes…");
return status;
return getTaskStatusBadgeLabel(status, t);
}
type SortDirection = "asc" | "desc";

View File

@@ -42,6 +42,7 @@ import { getTaskAgeStalenessCopy, shouldShowTaskAgeStalenessBadge } from "../uti
import { getUnifiedTaskProgress, isPlanReviewRunning } from "../utils/taskProgress";
import { getPrBadgeModifierClass } from "../utils/prBadgeClass";
import { getActiveRuntimeMs, getEndToEndDurationMs, getTimedDurationMs, getWorkflowRuntimeMs, parseTimestampToMs } from "../utils/taskTiming";
import { getTaskStatusBadgeLabel } from "../utils/taskStatusBadgeLabel";
import { canStartPrFeedbackAddressing, getTaskPrimaryPrInfo } from "../utils/prFeedback";
import type { ToastType } from "../hooks/useToast";
import { useConfirm } from "../hooks/useConfirm";
@@ -295,15 +296,7 @@ const TIME_INDICATOR_COLUMNS = new Set<ColumnId>([
const LIVE_TIME_INDICATOR_POLL_MS = 30_000;
function getTaskStatusLabel(status: string, t: TFunction<"app">): string {
if (status === "merging-fix") return t("tasks.statusMergingFix", "Merging fixes…");
/*
FNXC:MergeQueue 2026-07-15-10:40:
Operators expect a "merging" badge while AI merge owns the pump. Map reviewing/landing to the same Merging… label so the board does not look idle during the long review and land phases.
*/
if (status === "reviewing" || status === "landing" || status === "merging" || status === "merging-pr") {
return t("tasks.statusMerging", "Merging…");
}
return status;
return getTaskStatusBadgeLabel(status, t);
}
function getDoneCompletionMs(task: Task): number | null {

View File

@@ -0,0 +1,23 @@
import { describe, expect, it } from "vitest";
import type { TFunction } from "i18next";
import { getTaskStatusBadgeLabel } from "../taskStatusBadgeLabel";
const t = ((key: string, fallback?: string) => fallback ?? key) as TFunction<"app">;
describe("getTaskStatusBadgeLabel", () => {
it("maps the full AI merge pipeline to Merging…", () => {
for (const status of ["merging", "merging-pr", "reviewing", "landing"]) {
expect(getTaskStatusBadgeLabel(status, t)).toBe("Merging…");
}
});
it("keeps merging-fix distinct", () => {
expect(getTaskStatusBadgeLabel("merging-fix", t)).toBe("Merging fixes…");
});
it("passes through non-merge statuses", () => {
expect(getTaskStatusBadgeLabel("planning", t)).toBe("planning");
expect(getTaskStatusBadgeLabel("failed", t)).toBe("failed");
expect(getTaskStatusBadgeLabel(null, t)).toBe("");
});
});

View File

@@ -0,0 +1,20 @@
/*
FNXC:MergeQueue 2026-07-15-10:45:
AI merge sets task.status to reviewing/landing for most of the live merge window. Board/list badges must never show those raw engine strings; map the full active-merge pipeline to operator-facing Merging… (and Merging fixes… for merging-fix).
*/
import type { TFunction } from "i18next";
import { isActiveMergeStatus } from "../../../core/src/active-merge-status";
export function getTaskStatusBadgeLabel(
status: string | null | undefined,
t: TFunction<"app">,
): string {
if (!status) return "";
if (status === "merging-fix") {
return t("tasks.statusMergingFix", "Merging fixes…");
}
if (isActiveMergeStatus(status)) {
return t("tasks.statusMerging", "Merging…");
}
return status;
}