MUL-5258: feat(issues): show agent-working indicator in Table view (#5875)

* feat(issues): show agent-working indicator in Table view

Reuse the self-contained IssueAgentActivityIndicator (already in List and
Board views) in the Table view's Issue column, rendered right after the
identifier and before the title — matching the List view placement so the
'agent working' cue sits in the same spot across all three views. The
indicator returns null when no agent is active, so inactive rows are
unchanged.

MUL-5258

Co-authored-by: multica-agent <github@multica.ai>

* test(issues): cover Table agent-working badge insertion

The previous stub returned null with no assertion, so deleting the badge
insertion in table-view.tsx would still pass every test here. Render a
marker carrying the issue id and assert the Table cell mounts it for the
row's issue, positioned between the identifier and the title (identifier →
activity → title, matching List/Board). Verified the new test fails when the
insertion is removed.

MUL-5258

Co-authored-by: multica-agent <github@multica.ai>

---------

Co-authored-by: Bohan-J <bohan@devv.ai>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
Bohan Jiang
2026-07-24 15:02:33 +08:00
committed by GitHub
parent 581d9527ba
commit 2aafa41a5f
2 changed files with 38 additions and 0 deletions

View File

@@ -7,6 +7,19 @@ import { describe, expect, it, vi } from "vitest";
import { useState } from "react";
import type { Issue } from "@multica/core/types";
// InlineTitle renders the self-contained agent-activity badge, which fetches
// the workspace agent-task snapshot via React Query. Stub it (same pattern as
// inbox-list-item.test.tsx) instead of standing up query/workspace providers,
// but render a marker carrying the issue id so a test can assert the badge is
// wired into the cell with the row's issue — otherwise the badge insertion in
// table-view.tsx could be deleted and every test here would still pass.
vi.mock("./issue-agent-activity-indicator", () => ({
IssueAgentActivityIndicator: ({ issueId }: { issueId: string }) => (
<span data-testid="issue-agent-activity" data-issue-id={issueId} />
),
}));
import { InlineTitle } from "./table-view";
import type { IssueTableDisplayRow } from "./table-view-model";
@@ -192,4 +205,27 @@ describe("InlineTitle", () => {
fireEvent.keyDown(screen.getByRole("textbox"), { key: "Escape" });
expect(screen.getByRole("button", { name: "Remote title" })).toBeTruthy();
});
it("renders the agent-activity badge for the row's issue, between the identifier and the title", () => {
render(<Harness title="Original" />);
const identifier = screen.getByText("MUL-1");
const badge = screen.getByTestId("issue-agent-activity");
const titleButton = screen.getByRole("button", { name: "Original" });
// Wired to THIS row's issue — deleting the badge insertion in
// table-view.tsx would drop the marker and fail this test, so the core
// product change is actually covered.
expect(badge.getAttribute("data-issue-id")).toBe("issue-1");
// Same reading order as List/Board: identifier → activity → title.
expect(
identifier.compareDocumentPosition(badge) &
Node.DOCUMENT_POSITION_FOLLOWING,
).toBeTruthy();
expect(
badge.compareDocumentPosition(titleButton) &
Node.DOCUMENT_POSITION_FOLLOWING,
).toBeTruthy();
});
});

View File

@@ -136,6 +136,7 @@ import {
} from "./table-view-model";
import type { ChildProgress } from "./list-row";
import { InfiniteScrollSentinel } from "./infinite-scroll-sentinel";
import { IssueAgentActivityIndicator } from "./issue-agent-activity-indicator";
const SELECT_COLUMN_ID = "__select";
const ADD_COLUMN_ID = "__add";
@@ -666,6 +667,7 @@ export function InlineTitle({
<span className="w-16 shrink-0 text-xs text-muted-foreground">
{row.issue.identifier}
</span>
<IssueAgentActivityIndicator issueId={row.issue.id} />
{editing ? (
<Input
autoFocus