feat(FN-2512): add elapsed timer chip to task cards
- Derive task elapsed time from columnMovedAt with updatedAt/createdAt fallbacks and guard against invalid or future timestamps - Render a clock-based timer chip on in-progress and done cards with accessible labeling and tooltip metadata - Add TaskCard styles for the timer row/chip using design tokens, including mobile-size adjustments - Expand TaskCard tests to cover visibility by column, invalid timestamp suppression, boundary label formatting, and 30s live refresh cadence
This commit is contained in:
@@ -115,6 +115,15 @@ afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
async function waitForFrameContains(lastFrame: () => string | undefined, text: string, timeoutMs = 1200) {
|
||||
const start = Date.now();
|
||||
while (Date.now() - start < timeoutMs) {
|
||||
if ((lastFrame() ?? "").includes(text)) return;
|
||||
await new Promise((r) => setTimeout(r, 20));
|
||||
}
|
||||
throw new Error(`Timed out waiting for frame to include: ${text}`);
|
||||
}
|
||||
|
||||
describe("DashboardApp smoke", () => {
|
||||
it("renders the splash logo and tagline before systemInfo arrives", () => {
|
||||
const controller = newController();
|
||||
@@ -255,6 +264,45 @@ describe("Agents view", () => {
|
||||
expect(lastFrame() ?? "").toContain("Agent Detail");
|
||||
unmount();
|
||||
});
|
||||
|
||||
it("shows run history with readable status labels and opens run logs for the selected run", async () => {
|
||||
const controller = newController();
|
||||
controller.setSystemInfo(makeSystemInfo());
|
||||
|
||||
const agents: AgentItem[] = [
|
||||
{ id: "a1", name: "worker-1", state: "active", role: "executor" },
|
||||
];
|
||||
const detail: AgentDetailItem = {
|
||||
id: "a1",
|
||||
name: "worker-1",
|
||||
state: "active",
|
||||
role: "executor",
|
||||
capabilities: ["executor"],
|
||||
recentRuns: [
|
||||
{
|
||||
id: "run-1",
|
||||
startedAt: new Date().toISOString(),
|
||||
endedAt: new Date().toISOString(),
|
||||
status: "completed",
|
||||
stdoutExcerpt: "plan generated",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
controller.setInteractiveData(makeInteractiveData({ agents, detail }));
|
||||
controller.setMode("interactive");
|
||||
controller.setInteractiveView("agents");
|
||||
|
||||
const { lastFrame, stdin, unmount } = render(renderDashboardAppNode(controller));
|
||||
await waitForFrameContains(lastFrame, "Run history (latest first):");
|
||||
await waitForFrameContains(lastFrame, "Completed");
|
||||
|
||||
stdin.write("\r");
|
||||
await waitForFrameContains(lastFrame, "Run logs (1)");
|
||||
await waitForFrameContains(lastFrame, "plan generated");
|
||||
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Settings view", () => {
|
||||
|
||||
Reference in New Issue
Block a user