diff --git a/.changeset/fn-7306-task-detail-activity-tab.md b/.changeset/fn-7306-task-detail-activity-tab.md
new file mode 100644
index 0000000000..2bce5a6195
--- /dev/null
+++ b/.changeset/fn-7306-task-detail-activity-tab.md
@@ -0,0 +1,7 @@
+---
+"@runfusion/fusion": patch
+---
+
+summary: Rename the task-detail Chat tab to Activity and make it first.
+category: feature
+dev: Keeps the internal `chat` tab id compatible for existing deep links and plugin callers.
diff --git a/packages/dashboard/app/components/TaskDetailModal.tsx b/packages/dashboard/app/components/TaskDetailModal.tsx
index 64aa27a64c..efc219e77d 100644
--- a/packages/dashboard/app/components/TaskDetailModal.tsx
+++ b/packages/dashboard/app/components/TaskDetailModal.tsx
@@ -194,20 +194,20 @@ function formatDurationCompact(ageMs: number): string {
type TabId = "summary" | "definition" | "chat" | "logs" | "changes" | "review" | "pr" | "comments" | "model" | "workflow" | "documents" | "stats" | "routing" | "retries" | "terminal" | `plugin-${string}`;
/*
-FNXC:TaskDetailSummaryTab 2026-06-27-00:00:
-Done tasks land on Summary instead of Chat so completed work opens on the completion overview. Chat stays the implicit default for every other column, and explicit tab requests continue to win for done tasks.
+FNXC:TaskDetailActivityTab 2026-06-30-00:00:
+The existing task activity/steering surface keeps the stable internal `chat` tab id for deep-link/plugin compatibility, but its top-level user-facing label is Activity. Activity is the implicit default for every task column, including done tasks; Summary remains explicitly available for completed work until a later subtask adds the separate planner-model Chat surface.
-FNXC:TaskDetailSummaryTab 2026-06-27-00:00:
-Only an omitted initial tab is the implicit default. Preserve explicit `initialTab="chat"` requests from plugins and task-detail entrypoints so done tasks can still deep-link directly to Chat.
+FNXC:TaskDetailActivityTab 2026-06-30-00:00:
+Only an omitted initial tab is the implicit default. Preserve explicit `initialTab="chat"` requests from plugins and task-detail entrypoints so existing links continue to open the renamed Activity surface.
*/
-function resolveDefaultTab(initialTab: TabId | undefined, column: ColumnId): TabId {
+function resolveDefaultTab(initialTab: TabId | undefined, _column: ColumnId): TabId {
if (initialTab === "retries") {
return "definition";
}
if (initialTab) {
return initialTab;
}
- return column === "done" ? "summary" : "chat";
+ return "chat";
}
// Lazy-load the terminal so xterm + addons stay out of the main bundle (U11).
@@ -501,8 +501,8 @@ export function TaskDetailContent({
autoMergeEnabled: autoMergeEnabledProp,
onOpenWorkflowEditor,
/**
- * FNXC:TaskDetailTabs 2026-06-17-00:00:
- * FN-6532 makes Chat the default task-detail view when no caller supplies an explicit initial tab.
+ * FNXC:TaskDetailActivityTab 2026-06-30-00:00:
+ * The Activity tab is still addressed as `chat` internally so existing callers and deep links do not break while the label/order changes ahead of the future planner Chat tab.
*/
initialTab,
mobileHeaderMode = "close",
@@ -3136,12 +3136,15 @@ export function TaskDetailContent({
<>
{/*
- FNXC:TaskDetailTabs 2026-06-17-00:00:
- FN-6532 requires Chat to be the first task-detail tab while preserving every explicit tab entrypoint.
-
- FNXC:TaskDetailSummaryTab 2026-06-27-00:00:
- Done tasks expose Summary as the first tab because the implicit Chat default resolves there for completed work; non-done tasks keep Chat first and never render an empty Summary shell.
+ FNXC:TaskDetailActivityTab 2026-06-30-00:00:
+ The existing task activity/steering surface is now labelled Activity and always renders first. Keep the `chat` tab id because a later subtask will add the separate planner-model Chat surface; this rename must not break existing `initialTab="chat"` callers.
*/}
+ setActiveTab("chat")}
+ >
+ {t("taskDetail.tabs.activity", "Activity")}
+
{task.column === "done" && (
)}
- setActiveTab("chat")}
- >
- {t("taskDetail.tabs.chat", "Chat")}
-
setActiveTab("definition")}
diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.attachments-and-tabs.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.attachments-and-tabs.test.tsx
index f0b642a4d9..30fc23f6ad 100644
--- a/packages/dashboard/app/components/__tests__/TaskDetailModal.attachments-and-tabs.test.tsx
+++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.attachments-and-tabs.test.tsx
@@ -19,7 +19,7 @@ import { TaskDetailModal, TaskDetailContent } from "../TaskDetailModal";
/*
FNXC:TaskDetailTabs 2026-06-17-08:20:
-FN-6532 made Chat the default TaskDetailModal tab. Definition-tab regression coverage must prove both the no-`initialTab` Chat landing state and the explicit `initialTab="definition"` Definition surface for prompt, GitHub tracking, and dependency sections.
+FN-7306 labels the stable internal `chat` tab as Activity and keeps it as the default TaskDetailModal tab. Definition-tab regression coverage must prove both the no-`initialTab` Activity landing state and the explicit `initialTab="definition"` Definition surface for prompt, GitHub tracking, and dependency sections.
*/
setupTaskDetailModalHooks();
@@ -439,7 +439,7 @@ describe("TaskDetailModal", () => {
});
describe("tab toggle", () => {
- it("defaults to the Chat tab", () => {
+ it("defaults to the Activity tab", () => {
const { container } = render(
{
/>,
);
- expect(screen.getByText("Definition")).toBeTruthy();
+ expect(screen.getByText("Plan")).toBeTruthy();
expect(screen.getByText("Logs")).toBeTruthy();
- // Activity and Agent Log are subviews inside the Logs tab, not top-level tabs.
- // They should NOT be visible on the default Chat tab.
- expect(screen.queryByText("Activity")).toBeNull();
+ // Logs subview controls should NOT be visible on the default Activity tab.
+ expect(container.querySelector(".log-subview-toggle")).toBeNull();
expect(screen.queryByText("Agent Log")).toBeNull();
// Chat content should be visible by default.
expect(container.querySelector(".detail-section--chat")).toBeTruthy();
@@ -638,8 +637,8 @@ describe("TaskDetailModal", () => {
expect(container.querySelector("[data-testid='agent-log-viewer']")).toBeTruthy();
expect(container.querySelector(".detail-activity")).toBeNull();
- // Switch back to Activity subview within Logs tab
- fireEvent.click(screen.getByText("Activity"));
+ // Switch back to Activity subview within Logs tab.
+ fireEvent.click(container.querySelector(".log-subview-toggle .log-subview-btn")!);
expect(container.querySelector(".detail-activity")).toBeTruthy();
expect(container.querySelector("[data-testid='agent-log-viewer']")).toBeNull();
@@ -649,7 +648,7 @@ describe("TaskDetailModal", () => {
expect(container.querySelector(".detail-activity")).toBeNull();
// Switch back to Definition tab
- fireEvent.click(screen.getByText("Definition"));
+ fireEvent.click(screen.getByText("Plan"));
expect(container.querySelector(".markdown-body")).toBeTruthy();
expect(container.querySelector(".detail-activity")).toBeNull();
@@ -681,7 +680,7 @@ describe("TaskDetailModal", () => {
expect(container.querySelector(".markdown-body")).toBeNull();
// Click Definition tab to go back
- fireEvent.click(screen.getByText("Definition"));
+ fireEvent.click(screen.getByText("Plan"));
// Definition content should reappear
expect(container.querySelector(".markdown-body")).toBeTruthy();
@@ -705,7 +704,7 @@ describe("TaskDetailModal", () => {
/>,
);
- // Default: Chat tab active → enabled should be false
+ // Default: Activity tab active → enabled should be false
const initialCall = mockUseAgentLogs.mock.calls[mockUseAgentLogs.mock.calls.length - 1];
expect(initialCall[1]).toBe(false);
@@ -758,18 +757,17 @@ describe("TaskDetailModal", () => {
);
// For an in-progress task (no workflow steps, no merge commit), the
- // top-level tabs are: Chat, Definition, Logs, Changes, Review, Comments,
+ // top-level tabs are: Activity, Plan, Logs, Changes, Review, Comments,
// Artifacts, Model, Workflow, Stats, Routing.
- const tabTexts = ["Chat", "Definition", "Logs", "Changes", "Review", "Comments", "Artifacts", "Model", "Workflow", "Stats", "Routing"];
+ const tabTexts = ["Activity", "Plan", "Logs", "Changes", "Review", "Comments", "Artifacts", "Model", "Workflow", "Stats", "Routing"];
const tabs = screen.getAllByRole("button").filter((b) =>
tabTexts.includes(b.textContent || "")
);
expect(tabs.map((tab) => tab.textContent)).toEqual(tabTexts);
- expect(tabs[0].textContent).toBe("Chat");
- expect(tabs[1].textContent).toBe("Definition");
+ expect(tabs[0].textContent).toBe("Activity");
+ expect(tabs[1].textContent).toBe("Plan");
expect(tabs[2].textContent).toBe("Logs");
- // Activity and Agent Log are NOT top-level tabs (they are subviews inside Logs)
expect(container.querySelectorAll(".detail-tab").length).toBe(11);
// Workflow tab should always appear even when no workflow steps are configured
expect(screen.getByText("Workflow")).toBeInTheDocument();
@@ -841,7 +839,7 @@ describe("TaskDetailModal", () => {
/>,
);
- fireEvent.click(screen.getByRole("button", { name: "Chat" }));
+ fireEvent.click(screen.getByRole("button", { name: "Activity" }));
const content = container.querySelector(".task-detail-content");
const titleRow = container.querySelector(".detail-title-row");
expect(content).not.toHaveClass("task-detail-content--chat-expanded");
@@ -942,7 +940,7 @@ describe("TaskDetailModal", () => {
/>,
);
- fireEvent.click(screen.getByRole("button", { name: "Chat" }));
+ fireEvent.click(screen.getByRole("button", { name: "Activity" }));
fireEvent.click(screen.getByTestId("task-chat-expand-toggle"));
expect(container.querySelector(".task-detail-content")).toHaveClass("task-detail-content--chat-expanded");
@@ -951,7 +949,7 @@ describe("TaskDetailModal", () => {
expect(screen.queryByTestId("task-chat-expand-toggle")).toBeNull();
});
- it("FN-6532 defaults to Chat first while preserving explicit tab requests", () => {
+ it("FN-6532 defaults to Activity first while preserving explicit tab requests", () => {
const { container, rerender } = render(
{
);
const tabs = Array.from(container.querySelectorAll(".detail-tab"));
- expect(tabs.map((tab) => tab.textContent)).toEqual(expect.arrayContaining(["Chat", "Definition"]));
- expect(tabs[0]).toHaveTextContent("Chat");
- const chatTab = screen.getByRole("button", { name: "Chat" });
- const definitionTab = screen.getByRole("button", { name: "Definition" });
+ expect(tabs.map((tab) => tab.textContent)).toEqual(expect.arrayContaining(["Activity", "Plan"]));
+ expect(tabs[0]).toHaveTextContent("Activity");
+ const chatTab = screen.getByRole("button", { name: "Activity" });
+ const definitionTab = screen.getByRole("button", { name: "Plan" });
expect(chatTab.compareDocumentPosition(definitionTab) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
expect(chatTab).toHaveClass("detail-tab-active");
expect(definitionTab).not.toHaveClass("detail-tab-active");
@@ -988,7 +986,8 @@ describe("TaskDetailModal", () => {
);
expect(screen.getByRole("button", { name: "Logs" })).toHaveClass("detail-tab-active");
- expect(screen.getByRole("button", { name: "Chat" })).not.toHaveClass("detail-tab-active");
+ expect(container.querySelector(".detail-tabs .detail-tab:first-child")).toHaveTextContent("Activity");
+ expect(container.querySelector(".detail-tabs .detail-tab:first-child")).not.toHaveClass("detail-tab-active");
expect(container.querySelector(".detail-section--chat")).toBeNull();
});
@@ -1010,8 +1009,8 @@ describe("TaskDetailModal", () => {
/>,
);
- expect(screen.getByRole("button", { name: "Definition" })).toHaveClass("detail-tab-active");
- expect(screen.getByRole("button", { name: "Chat" })).not.toHaveClass("detail-tab-active");
+ expect(screen.getByRole("button", { name: "Plan" })).toHaveClass("detail-tab-active");
+ expect(screen.getByRole("button", { name: "Activity" })).not.toHaveClass("detail-tab-active");
expect(container.querySelector(".detail-section--chat")).toBeNull();
expect(screen.getByText("Definition body unique text.")).toBeInTheDocument();
expect(screen.getByText("GitHub tracking")).toBeInTheDocument();
@@ -1021,7 +1020,7 @@ describe("TaskDetailModal", () => {
expect(container).toHaveTextContent("FN-200");
});
- it("FN-6347 applies chat modifiers only while the Chat tab is active", () => {
+ it("FN-6347 applies chat modifiers only while the Activity tab is active", () => {
const { container } = render(
{
/>,
);
- fireEvent.click(screen.getByRole("button", { name: "Chat" }));
+ fireEvent.click(screen.getByRole("button", { name: "Activity" }));
expect(container.querySelector(".detail-body--chat")).toBeTruthy();
fireEvent.click(screen.getByLabelText("Edit task"));
@@ -1097,7 +1096,7 @@ describe("TaskDetailModal", () => {
expect(container.querySelector(".detail-body--agent-log")).toBeTruthy();
// Switch back to Definition tab
- fireEvent.click(screen.getByText("Definition"));
+ fireEvent.click(screen.getByText("Plan"));
// modifier class should be removed
expect(container.querySelector(".detail-body--agent-log")).toBeNull();
diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.definition-actions.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.definition-actions.test.tsx
index 72451e72f3..28d787cbef 100644
--- a/packages/dashboard/app/components/__tests__/TaskDetailModal.definition-actions.test.tsx
+++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.definition-actions.test.tsx
@@ -222,10 +222,10 @@ describe("TaskDetailModal", () => {
);
// In-progress tasks show exactly 11 tabs:
- // Chat, Plan, Logs, Changes, Review, Comments, Artifacts, Model, Workflow, Stats, Routing
+ // Activity, Plan, Logs, Changes, Review, Comments, Artifacts, Model, Workflow, Stats, Routing
const tabs = container.querySelectorAll(".detail-tab");
expect(tabs.length).toBe(11);
- expect(tabs[0].textContent).toBe("Chat");
+ expect(tabs[0].textContent).toBe("Activity");
expect(tabs[1].textContent).toBe("Plan");
expect(tabs[2].textContent).toBe("Logs");
expect(tabs[3].textContent).toBe("Changes");
@@ -257,7 +257,7 @@ describe("TaskDetailModal", () => {
// In-progress task with workflow steps: 11 tabs (Review after Changes, Workflow after Model)
const tabs = container.querySelectorAll(".detail-tab");
expect(tabs.length).toBe(11);
- expect(tabs[0].textContent).toBe("Chat");
+ expect(tabs[0].textContent).toBe("Activity");
expect(tabs[1].textContent).toBe("Plan");
expect(tabs[2].textContent).toBe("Logs");
expect(tabs[3].textContent).toBe("Changes");
@@ -287,11 +287,11 @@ describe("TaskDetailModal", () => {
/>,
);
- // Done task with commit SHA: Summary, Chat, Plan, Logs, Changes, Review, Comments, Artifacts, Model, Workflow, Stats, Routing (12 tabs, no Commits)
+ // Done task with commit SHA: Activity, Summary, Plan, Logs, Changes, Review, Comments, Artifacts, Model, Workflow, Stats, Routing (12 tabs, no Commits)
const tabs = container.querySelectorAll(".detail-tab");
expect(tabs.length).toBe(12);
- expect(tabs[0].textContent).toBe("Summary");
- expect(tabs[1].textContent).toBe("Chat");
+ expect(tabs[0].textContent).toBe("Activity");
+ expect(tabs[1].textContent).toBe("Summary");
expect(tabs[2].textContent).toBe("Plan");
expect(tabs[3].textContent).toBe("Logs");
expect(tabs[4].textContent).toBe("Changes");
@@ -327,8 +327,8 @@ describe("TaskDetailModal", () => {
// Done task with workflow steps and commit SHA: 12 tabs including Summary and Review (no Commits)
const tabs = container.querySelectorAll(".detail-tab");
expect(tabs.length).toBe(12);
- expect(tabs[0].textContent).toBe("Summary");
- expect(tabs[1].textContent).toBe("Chat");
+ expect(tabs[0].textContent).toBe("Activity");
+ expect(tabs[1].textContent).toBe("Summary");
expect(tabs[2].textContent).toBe("Plan");
expect(tabs[3].textContent).toBe("Logs");
expect(tabs[4].textContent).toBe("Changes");
@@ -358,9 +358,9 @@ describe("TaskDetailModal", () => {
);
const triageTabs = triageContainer.querySelectorAll(".detail-tab");
- expect(triageTabs.length).toBe(10); // Chat, Plan, Logs, Review, Comments, Artifacts, Model, Workflow, Stats, Routing
+ expect(triageTabs.length).toBe(10); // Activity, Plan, Logs, Review, Comments, Artifacts, Model, Workflow, Stats, Routing
expect(Array.from(triageTabs).map(t => t.textContent)).toEqual([
- "Chat", "Plan", "Logs", "Review", "Comments", "Artifacts", "Model", "Workflow", "Stats", "Routing",
+ "Activity", "Plan", "Logs", "Review", "Comments", "Artifacts", "Model", "Workflow", "Stats", "Routing",
]);
const { container: todoContainer } = render(
@@ -377,9 +377,9 @@ describe("TaskDetailModal", () => {
);
const todoTabs = todoContainer.querySelectorAll(".detail-tab");
- expect(todoTabs.length).toBe(10); // Chat, Plan, Logs, Review, Comments, Artifacts, Model, Workflow, Stats, Routing
+ expect(todoTabs.length).toBe(10); // Activity, Plan, Logs, Review, Comments, Artifacts, Model, Workflow, Stats, Routing
expect(Array.from(todoTabs).map(t => t.textContent)).toEqual([
- "Chat", "Plan", "Logs", "Review", "Comments", "Artifacts", "Model", "Workflow", "Stats", "Routing",
+ "Activity", "Plan", "Logs", "Review", "Comments", "Artifacts", "Model", "Workflow", "Stats", "Routing",
]);
});
diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.github-tracking-header.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.github-tracking-header.test.tsx
index faf7a1692b..5e7f15a5c5 100644
--- a/packages/dashboard/app/components/__tests__/TaskDetailModal.github-tracking-header.test.tsx
+++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.github-tracking-header.test.tsx
@@ -1,6 +1,6 @@
/*
FNXC:TaskDetailTabs 2026-06-17-08:20:
-FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
+FN-7306 labels the stable internal `chat` tab as Activity and keeps it as the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Activity landing state.
*/
import { describe, expect, it } from "vitest";
import { render, screen } from "@testing-library/react";
diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.github-tracking-stale.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.github-tracking-stale.test.tsx
index 18854edca1..2da15fd20a 100644
--- a/packages/dashboard/app/components/__tests__/TaskDetailModal.github-tracking-stale.test.tsx
+++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.github-tracking-stale.test.tsx
@@ -1,6 +1,6 @@
/*
FNXC:TaskDetailTabs 2026-06-17-08:20:
-FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
+FN-7306 labels the stable internal `chat` tab as Activity and keeps it as the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Activity landing state.
*/
import { describe, it, expect, vi } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.inline-editing-and-integrations.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.inline-editing-and-integrations.test.tsx
index 1d47889021..9f9fdf49ae 100644
--- a/packages/dashboard/app/components/__tests__/TaskDetailModal.inline-editing-and-integrations.test.tsx
+++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.inline-editing-and-integrations.test.tsx
@@ -1,6 +1,6 @@
/*
FNXC:TaskDetailTabs 2026-06-17-08:20:
-FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
+FN-7306 labels the stable internal `chat` tab as Activity and keeps it as the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Activity landing state.
*/
import { describe, it, expect, vi } from "vitest";
import { useState } from "react";
@@ -2259,7 +2259,7 @@ describe("TaskDetailModal", () => {
);
// Only standard tabs should be visible (Definition, Logs, etc.)
- expect(screen.getByText("Definition")).toBeDefined();
+ expect(screen.getByText("Plan")).toBeDefined();
expect(screen.getByText("Logs")).toBeDefined();
// Plugin tabs should not exist
expect(screen.queryByText("Plugin A Tab")).toBeNull();
diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.models-progress-workflow.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.models-progress-workflow.test.tsx
index f0a71cb81d..03a36df9d4 100644
--- a/packages/dashboard/app/components/__tests__/TaskDetailModal.models-progress-workflow.test.tsx
+++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.models-progress-workflow.test.tsx
@@ -1,6 +1,6 @@
/*
FNXC:TaskDetailTabs 2026-06-17-08:20:
-FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
+FN-7306 labels the stable internal `chat` tab as Activity and keeps it as the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Activity landing state.
*/
import { describe, it, expect, vi } from "vitest";
import { render, screen, fireEvent, act, waitFor } from "@testing-library/react";
diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx
index ea5ceaf599..790b2eea30 100644
--- a/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx
+++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.rendering.test.tsx
@@ -1,6 +1,6 @@
/*
FNXC:TaskDetailTabs 2026-06-17-08:20:
-FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
+FN-7306 labels the stable internal `chat` tab as Activity and keeps it as the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Activity landing state.
*/
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render, screen, fireEvent, act, waitFor } from "@testing-library/react";
@@ -886,7 +886,7 @@ describe("TaskDetailModal", () => {
expect(container.querySelector(".task-detail-content--embedded")).toBeTruthy();
expect(screen.queryByRole("button", { name: "Close" })).toBeNull();
- expect(screen.getByRole("button", { name: "Definition" })).toBeInTheDocument();
+ expect(screen.getByRole("button", { name: "Plan" })).toBeInTheDocument();
});
it("renders header close control for embedded floating task details", () => {
diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx
index a39723b3ef..1244c22623 100644
--- a/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx
+++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.responsive-and-dependencies.test.tsx
@@ -1,6 +1,6 @@
/*
FNXC:TaskDetailTabs 2026-06-17-08:20:
-FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
+FN-7306 labels the stable internal `chat` tab as Activity and keeps it as the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Activity landing state.
*/
import { describe, it, expect, vi } from "vitest";
import { render, screen, fireEvent, act, waitFor } from "@testing-library/react";
@@ -225,8 +225,8 @@ describe("TaskDetailModal", () => {
expect(container.querySelectorAll(".detail-timestamp-item").length).toBe(2);
const tabs = container.querySelectorAll(".detail-tab");
expect(Array.from(tabs).map((tab) => tab.textContent?.trim())).toEqual([
- "Chat",
- "Definition",
+ "Activity",
+ "Plan",
"Logs",
"Changes",
"Review",
diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.summary-tab.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.summary-tab.test.tsx
index 9559fae944..e6a7798513 100644
--- a/packages/dashboard/app/components/__tests__/TaskDetailModal.summary-tab.test.tsx
+++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.summary-tab.test.tsx
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
-import { render, screen, within } from "@testing-library/react";
+import { fireEvent, render, screen, within } from "@testing-library/react";
import type { Column, ModelPricingOverrides, TaskTokenUsage } from "@fusion/core";
import {
makeTask,
@@ -76,7 +76,7 @@ function doneTask(overrides = {}) {
}
describe("TaskDetailModal Summary tab", () => {
- it("lands done tasks on Summary and renders completion, changed-files, and agent-work sections", () => {
+ it("lands done tasks on Activity first and keeps Summary accessible", () => {
const { container } = render(
{
/>,
);
+ expect(container.querySelector(".detail-tabs")?.firstElementChild?.textContent).toBe("Activity");
+ const activityButton = screen.getByRole("button", { name: "Activity" });
+ expectButtonActive(activityButton);
+ expect(screen.queryByRole("button", { name: "Chat" })).toBeNull();
+ expect(screen.queryByText("Completion summary")).toBeNull();
+ expect(container.querySelector(".detail-section--chat [data-testid='task-chat-tab']")).toBeTruthy();
+
const summaryButton = screen.getByRole("button", { name: "Summary" });
+ fireEvent.click(summaryButton);
expectButtonActive(summaryButton);
expect(screen.getByText("Completion summary")).toBeTruthy();
expect(screen.getByText("summary")).toBeTruthy();
@@ -99,10 +107,9 @@ describe("TaskDetailModal Summary tab", () => {
expect(screen.getByText("Preflight")).toBeTruthy();
expect(screen.getByText("Code Review")).toBeTruthy();
expect(screen.getByText("Agents retried this task 1 time.")).toBeTruthy();
- expect(container.querySelector(".detail-tabs")?.firstElementChild?.textContent).toBe("Summary");
});
- it("honors explicit Chat for done tasks", () => {
+ it("honors explicit initialTab=\"chat\" for done tasks", () => {
render(
{
/>,
);
- expectButtonActive(screen.getByRole("button", { name: "Chat" }));
+ expectButtonActive(screen.getByRole("button", { name: "Activity" }));
expect(screen.queryByText("Completion summary")).toBeNull();
});
@@ -153,7 +160,7 @@ describe("TaskDetailModal Summary tab", () => {
expect(screen.queryByText("Completion summary")).toBeNull();
});
- it("does not render Summary for non-done columns and still defaults to Chat", () => {
+ it("does not render Summary for non-done columns and still defaults to Activity", () => {
for (const column of ["in-progress", "in-review", "todo"] as Column[]) {
const rendered = render(
{
/>,
);
expect(screen.queryByRole("button", { name: "Summary" })).toBeNull();
- expectButtonActive(screen.getByRole("button", { name: "Chat" }));
+ expectButtonActive(screen.getByRole("button", { name: "Activity" }));
rendered.unmount();
}
});
@@ -359,6 +366,7 @@ describe("TaskDetailModal Summary tab", () => {
const full = render(
{
{
retrySummary: { total: 0 },
})}
onClose={noop}
+ initialTab="summary"
onMoveTask={noopMove}
onDeleteTask={noopDelete}
onMergeTask={noopMerge}
@@ -451,8 +461,8 @@ describe("TaskDetailModal Summary tab", () => {
expect(summaryButton.classList.contains("detail-tab")).toBe(true);
});
- it("resolves the done-task Summary default in embedded TaskDetailContent", () => {
- render(
+ it("resolves the done-task Activity default in embedded TaskDetailContent", () => {
+ const { container } = render(
{
/>,
);
- expectButtonActive(screen.getByRole("button", { name: "Summary" }));
- expect(screen.getByText("Completion summary")).toBeTruthy();
+ expectButtonActive(screen.getByRole("button", { name: "Activity" }));
+ expect(container.querySelector(".detail-tabs")?.firstElementChild?.textContent).toBe("Activity");
+ expect(screen.queryByText("Completion summary")).toBeNull();
});
});
diff --git a/packages/dashboard/app/components/__tests__/TaskDetailModal.test.tsx b/packages/dashboard/app/components/__tests__/TaskDetailModal.test.tsx
index f9163f11fa..d21458e498 100644
--- a/packages/dashboard/app/components/__tests__/TaskDetailModal.test.tsx
+++ b/packages/dashboard/app/components/__tests__/TaskDetailModal.test.tsx
@@ -1,6 +1,6 @@
/*
FNXC:TaskDetailTabs 2026-06-17-08:20:
-FN-6532 made Chat the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Chat landing state.
+FN-7306 labels the stable internal `chat` tab as Activity and keeps it as the default TaskDetailModal tab. Tests that assert Definition-only sections must opt into `initialTab="definition"` so they verify the intended surface instead of the Activity landing state.
*/
import { describe, it, expect, vi } from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
@@ -689,7 +689,7 @@ describe("TaskDetailModal in-review stall diagnostics", () => {
await user.click(screen.getByRole("button", { name: "View activity log" }));
expect(screen.getByRole("button", { name: "Logs" })).toHaveClass("detail-tab-active");
- expect(screen.getByRole("button", { name: "Activity" })).toHaveClass("log-subview-btn-active");
+ expect(document.querySelector(".log-subview-toggle .log-subview-btn-active")).toHaveTextContent("Activity");
const highlighted = document.querySelector(".detail-log-entry--stall-highlight .detail-log-action");
expect(highlighted?.textContent).toContain("In-review stall surfaced [merge-blocker]");
});
diff --git a/packages/dashboard/app/hooks/useModalManager.ts b/packages/dashboard/app/hooks/useModalManager.ts
index 00cca48781..3346ef1455 100644
--- a/packages/dashboard/app/hooks/useModalManager.ts
+++ b/packages/dashboard/app/hooks/useModalManager.ts
@@ -5,6 +5,10 @@ import type { SectionId } from "../components/SettingsModal";
import type { ToastType } from "./useToast";
import { removeScopedItem } from "../utils/projectStorage";
+/*
+FNXC:TaskDetailActivityTab 2026-06-30-00:00:
+Keep `chat` as the public initial-tab id for the renamed Activity task-detail tab so existing dashboard callers and deep links remain compatible until the future planner Chat tab ships under its own contract.
+*/
export type DetailTaskTab =
| "summary"
| "chat"
diff --git a/packages/dashboard/app/plugins/types.ts b/packages/dashboard/app/plugins/types.ts
index 20a57b5062..e71102e6d8 100644
--- a/packages/dashboard/app/plugins/types.ts
+++ b/packages/dashboard/app/plugins/types.ts
@@ -11,7 +11,12 @@
import type { ReactNode } from "react";
import type { Task, TaskDetail, WorkflowStep } from "@fusion/core";
-/** Tab identifiers for the task detail modal. Mirrors the dashboard's local enum. */
+/**
+ * Tab identifiers for the task detail modal. Mirrors the dashboard's local enum.
+ *
+ * FNXC:TaskDetailActivityTab 2026-06-30-00:00:
+ * Plugins should continue passing `chat` to open the renamed Activity tab; the id is stable compatibility surface, while the top-level label is no longer Chat.
+ */
export type DetailTaskTab = "summary" | "chat" | "definition" | "logs" | "changes" | "comments" | "model" | "workflow" | "pr" | "retries";
export type PluginToastType = "success" | "error" | "warning" | "info";