feat(FN-1323): unify list and board agent-active styling

- Apply consistent agent-active state styling across ListView and BoardView
- Add .agent-active CSS class to unify visual indicator styling
- Update ListView component to use unified active state classes
- Add ListView test coverage for agent-active state rendering
This commit is contained in:
gsxdsm
2026-04-09 10:10:25 -07:00
parent 1c6c3d1700
commit 8a6b4b8c94
3 changed files with 77 additions and 15 deletions

View File

@@ -832,7 +832,7 @@ export function ListView({
return (
<div
key={task.id}
className={`list-card${isSelectionMode ? " list-card--selectable" : ""}`}
className={`list-card${isAgentActive ? " agent-active" : ""}${isSelectionMode ? " list-card--selectable" : ""}`}
onClick={() => handleRowClick(task)}
data-id={task.id}
>
@@ -858,7 +858,7 @@ export function ListView({
{isStuckState ? (
<span className="list-status-badge stuck">Stuck</span>
) : hasStatus ? (
<span className={`list-status-badge${isFailed ? " failed" : ""}${isAgentActive ? " pulsing" : ""}`}>
<span className={`list-status-badge list-status-badge--${task.column}${isFailed ? " failed" : ""}${isAgentActive ? " pulsing" : ""}`}>
{task.status}
</span>
) : null}
@@ -1044,7 +1044,7 @@ export function ListView({
</span>
) : task.status ? (
<span
className={`list-status-badge${isFailed ? " failed" : ""}${
className={`list-status-badge list-status-badge--${task.column}${isFailed ? " failed" : ""}${
isAgentActive ? " pulsing" : ""
}`}
>

View File

@@ -2249,5 +2249,41 @@ describe("ListView - Bulk Selection", () => {
expect(screen.getByText("2 selected")).toBeInTheDocument();
expect(screen.getByText("Bulk Edit Models:")).toBeInTheDocument();
});
it("applies agent-active class to mobile cards when task is in-progress and not paused/failed", () => {
mockMobileViewport();
const { container } = renderListView({
tasks: [
createMockTask({
id: "FN-001",
status: "executing",
column: "in-progress",
}),
],
globalPaused: false,
});
const card = container.querySelector('.list-card[data-id="FN-001"]');
expect(card?.className).toContain("agent-active");
});
it("does not apply agent-active class to mobile cards when globalPaused is true", () => {
mockMobileViewport();
const { container } = renderListView({
tasks: [
createMockTask({
id: "FN-001",
status: "executing",
column: "in-progress",
}),
],
globalPaused: true,
});
const card = container.querySelector('.list-card[data-id="FN-001"]');
expect(card?.className).not.toContain("agent-active");
});
});
});

View File

@@ -7693,18 +7693,11 @@ body {
}
.list-row.agent-active {
border-left: 3px solid var(--in-progress);
animation: list-agent-glow 2.5s ease-in-out infinite;
}
@keyframes list-agent-glow {
0%,
100% {
background: rgba(var(--in-progress-rgb), 0.05);
}
50% {
background: rgba(var(--in-progress-rgb), 0.12);
}
border-color: var(--in-progress);
box-shadow:
0 0 8px rgba(var(--in-progress-rgb), 0.4),
0 0 20px rgba(var(--in-progress-rgb), 0.15);
animation: agent-glow 2.5s ease-in-out infinite;
}
/* Table cells */
@@ -7769,6 +7762,31 @@ body {
animation: pulse 1.5s ease-in-out infinite;
}
.list-status-badge--triage {
background: var(--status-triage-bg);
color: var(--triage);
}
.list-status-badge--todo {
background: var(--status-todo-bg);
color: var(--todo);
}
.list-status-badge--in-progress {
background: var(--status-in-progress-bg);
color: var(--in-progress);
}
.list-status-badge--in-review {
background: var(--status-in-review-bg);
color: var(--in-review);
}
.list-status-badge--done {
background: var(--status-done-bg);
color: var(--done);
}
.list-status-badge--archived {
background: var(--status-archived-bg);
color: var(--text-muted, #8b949e);
}
.list-column-badge {
display: inline-flex;
align-items: center;
@@ -8063,6 +8081,14 @@ body {
transform: scale(0.99);
}
.list-card.agent-active {
border-color: var(--in-progress);
box-shadow:
0 0 8px rgba(var(--in-progress-rgb), 0.4),
0 0 20px rgba(var(--in-progress-rgb), 0.15);
animation: agent-glow 2.5s ease-in-out infinite;
}
.list-card-row {
display: flex;
align-items: center;