feat(FN-2497): merge fusion/fn-2497

This commit is contained in:
gsxdsm
2026-04-25 11:10:51 -07:00
parent b19b0005ef
commit 904ed2fbdc
6 changed files with 120 additions and 1 deletions

View File

@@ -393,6 +393,20 @@
white-space: nowrap;
}
.list-title-content {
display: inline-flex;
align-items: center;
gap: var(--space-xs);
min-width: 0;
max-width: 100%;
}
.list-title-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.list-cell-date {
font-size: 12px;
color: var(--text-muted);
@@ -476,6 +490,23 @@
color: var(--triage);
}
.list-execution-mode-badge {
display: inline-flex;
align-items: center;
padding: 2px 8px;
border-radius: var(--radius-pill);
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.4px;
line-height: 1;
}
.list-execution-mode-badge--fast {
background: color-mix(in srgb, var(--color-warning) 20%, transparent);
color: var(--color-warning);
}
/* Progress bar */
.list-cell-progress {
min-width: 100px;

View File

@@ -856,6 +856,9 @@ export function ListView({
<div className="list-card-row">
<span className="list-card-id">{task.id}</span>
{task.executionMode === "fast" && (
<span className="list-execution-mode-badge list-execution-mode-badge--fast">Fast</span>
)}
<span className="list-card-spacer" />
{isStuckState ? (
<span className="list-status-badge stuck">Stuck</span>
@@ -1035,7 +1038,12 @@ export function ListView({
)}
{visibleColumns.has("title") && (
<td className="list-cell list-cell-title">
{task.title || task.description}
<div className="list-title-content">
{task.executionMode === "fast" && (
<span className="list-execution-mode-badge list-execution-mode-badge--fast">Fast</span>
)}
<span className="list-title-text">{task.title || task.description}</span>
</div>
</td>
)}
{visibleColumns.has("status") && (

View File

@@ -222,6 +222,22 @@
color: var(--color-error-dark);
}
.card-execution-mode-badge {
display: inline-flex;
align-items: center;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.4px;
padding: 2px 8px;
border-radius: var(--radius-pill);
}
.card-execution-mode-badge--fast {
background: color-mix(in srgb, var(--color-warning) 20%, transparent);
color: var(--color-warning);
}
.card.failed {
border-left: 3px solid var(--color-error-dark);
}

View File

@@ -260,6 +260,7 @@ function areTaskCardPropsEqual(previous: TaskCardProps, next: TaskCardProps): bo
previousTask.createdAt === nextTask.createdAt &&
previousTask.status === nextTask.status &&
previousTask.priority === nextTask.priority &&
previousTask.executionMode === nextTask.executionMode &&
previousTask.paused === nextTask.paused &&
previousTask.error === nextTask.error &&
previousTask.size === nextTask.size &&
@@ -902,6 +903,9 @@ function TaskCardComponent({
{normalizedPriority}
</span>
)}
{task.executionMode === "fast" && (
<span className="card-execution-mode-badge card-execution-mode-badge--fast">Fast</span>
)}
{task.missionId && (
<span
className="card-mission-badge"

View File

@@ -122,6 +122,21 @@ describe("ListView", () => {
expect(screen.getByText("Second Task")).toBeDefined();
});
it("shows fast indicator in desktop rows only for fast-mode tasks", () => {
const tasks = [
createMockTask({ id: "FN-001", title: "Fast Task", executionMode: "fast" }),
createMockTask({ id: "FN-002", title: "Standard Task", executionMode: "standard" }),
];
const { container } = renderListView({ tasks });
const fastRow = container.querySelector('tr[data-id="FN-001"]') as HTMLElement;
const standardRow = container.querySelector('tr[data-id="FN-002"]') as HTMLElement;
expect(fastRow.querySelector(".list-execution-mode-badge")?.textContent).toBe("Fast");
expect(standardRow.querySelector(".list-execution-mode-badge")).toBeNull();
});
it("shows empty state when no tasks", () => {
renderListView({ tasks: [] });
expect(screen.getByText("No tasks yet")).toBeDefined();
@@ -2252,6 +2267,23 @@ describe("ListView - Bulk Selection", () => {
expect(within(card as HTMLElement).getByText("executing")).toBeInTheDocument();
});
it("shows fast indicator in mobile cards only for fast-mode tasks", () => {
mockMobileViewport();
const { container } = renderListView({
tasks: [
createMockTask({ id: "FN-001", title: "Fast mobile", executionMode: "fast", status: "pending" }),
createMockTask({ id: "FN-002", title: "Standard mobile", executionMode: "standard", status: "pending" }),
],
});
const fastCard = container.querySelector('.list-card[data-id="FN-001"]') as HTMLElement;
const standardCard = container.querySelector('.list-card[data-id="FN-002"]') as HTMLElement;
expect(fastCard.querySelector(".list-execution-mode-badge")?.textContent).toBe("Fast");
expect(standardCard.querySelector(".list-execution-mode-badge")).toBeNull();
});
it("shows unified progress bar for executing mobile cards with steps and workflow checks", () => {
mockMobileViewport();

View File

@@ -82,6 +82,34 @@ describe("TaskCard", () => {
expect(container.querySelector(".card-status-badge")).toBeNull();
});
it("renders fast-mode indicator only when executionMode is fast", () => {
const { container, rerender } = render(
<TaskCard task={makeTask({ executionMode: "fast" })} onOpenDetail={noop} addToast={noop} />,
);
expect(container.querySelector(".card-execution-mode-badge")?.textContent).toBe("Fast");
rerender(
<TaskCard task={makeTask({ executionMode: "standard" })} onOpenDetail={noop} addToast={noop} />,
);
expect(container.querySelector(".card-execution-mode-badge")).toBeNull();
});
it("updates fast-mode indicator when executionMode changes", () => {
const { container, rerender } = render(
<TaskCard task={makeTask({ executionMode: "standard" })} onOpenDetail={noop} addToast={noop} />,
);
expect(container.querySelector(".card-execution-mode-badge")).toBeNull();
rerender(
<TaskCard task={makeTask({ executionMode: "fast" })} onOpenDetail={noop} addToast={noop} />,
);
expect(container.querySelector(".card-execution-mode-badge")?.textContent).toBe("Fast");
});
it("renders unified progress counts for task steps + workflow checks", () => {
render(
<TaskCard