FN-6532: make Chat the default task detail tab
Chat now opens first in task detail while explicit tab entrypoints continue to work. - Default task detail modal state and open-detail calls to the Chat tab. - Reorder the task detail tab strip so Chat appears before Definition. - Extend modal and tab tests to cover Chat-first defaults and explicit tab preservation. - Add a patch changeset for the published Fusion package. Files changed: .changeset/fn-6532-chat-first-task-detail.md | 5 ++ .../dashboard/app/components/TaskDetailModal.tsx | 24 ++++--- .../app/components/__tests__/AppModals.test.tsx | 2 +- .../TaskDetailModal.attachments-and-tabs.test.tsx | 81 +++++++++++++++++----- .../TaskDetailModal.definition-actions.test.tsx | 77 ++++++++++++++++---- .../app/hooks/__tests__/useModalManager.test.ts | 4 +- packages/dashboard/app/hooks/useModalManager.ts | 13 +++- 7 files changed, 162 insertions(+), 44 deletions(-) Fusion-Task-Id: FN-6532 Fusion-Task-Lineage: 7824f253-2a54-4e2d-af64-ed082ce8fbf9
This commit is contained in:
5
.changeset/fn-6532-chat-first-task-detail.md
Normal file
5
.changeset/fn-6532-chat-first-task-detail.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@runfusion/fusion": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Make Chat the first tab and default active view in the task detail modal while preserving explicit initial tab requests.
|
||||||
@@ -375,7 +375,7 @@ export interface TaskDetailModalProps {
|
|||||||
prAuthAvailable?: boolean;
|
prAuthAvailable?: boolean;
|
||||||
autoMergeEnabled?: boolean;
|
autoMergeEnabled?: boolean;
|
||||||
onOpenWorkflowEditor?: () => void;
|
onOpenWorkflowEditor?: () => void;
|
||||||
/** Open the modal with this tab active instead of "definition" */
|
/** Open the modal with this tab active instead of the default Chat view. */
|
||||||
initialTab?: TabId;
|
initialTab?: TabId;
|
||||||
/** Mobile-only header affordance mode. */
|
/** Mobile-only header affordance mode. */
|
||||||
mobileHeaderMode?: "close" | "back";
|
mobileHeaderMode?: "close" | "back";
|
||||||
@@ -555,7 +555,11 @@ export function TaskDetailContent({
|
|||||||
prAuthAvailable,
|
prAuthAvailable,
|
||||||
autoMergeEnabled: autoMergeEnabledProp,
|
autoMergeEnabled: autoMergeEnabledProp,
|
||||||
onOpenWorkflowEditor,
|
onOpenWorkflowEditor,
|
||||||
initialTab = "definition",
|
/**
|
||||||
|
* FNXC:TaskDetailTabs 2026-06-17-00:00:
|
||||||
|
* FN-6532 makes Chat the default task-detail view when no caller supplies an explicit initial tab.
|
||||||
|
*/
|
||||||
|
initialTab = "chat",
|
||||||
mobileHeaderMode = "close",
|
mobileHeaderMode = "close",
|
||||||
embedded = false,
|
embedded = false,
|
||||||
onRequestClose,
|
onRequestClose,
|
||||||
@@ -3063,18 +3067,22 @@ export function TaskDetailContent({
|
|||||||
{!isEditing && (
|
{!isEditing && (
|
||||||
<>
|
<>
|
||||||
<div className="detail-tabs">
|
<div className="detail-tabs">
|
||||||
<button
|
{/*
|
||||||
className={`detail-tab${activeTab === "definition" ? " detail-tab-active" : ""}`}
|
FNXC:TaskDetailTabs 2026-06-17-00:00:
|
||||||
onClick={() => setActiveTab("definition")}
|
FN-6532 requires Chat to be the first task-detail tab while preserving every explicit tab entrypoint.
|
||||||
>
|
*/}
|
||||||
{t("taskDetail.tabs.definition", "Definition")}
|
|
||||||
</button>
|
|
||||||
<button
|
<button
|
||||||
className={`detail-tab${activeTab === "chat" ? " detail-tab-active" : ""}`}
|
className={`detail-tab${activeTab === "chat" ? " detail-tab-active" : ""}`}
|
||||||
onClick={() => setActiveTab("chat")}
|
onClick={() => setActiveTab("chat")}
|
||||||
>
|
>
|
||||||
{t("taskDetail.tabs.chat", "Chat")}
|
{t("taskDetail.tabs.chat", "Chat")}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className={`detail-tab${activeTab === "definition" ? " detail-tab-active" : ""}`}
|
||||||
|
onClick={() => setActiveTab("definition")}
|
||||||
|
>
|
||||||
|
{t("taskDetail.tabs.definition", "Definition")}
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
className={`detail-tab${activeTab === "logs" ? " detail-tab-active" : ""}`}
|
className={`detail-tab${activeTab === "logs" ? " detail-tab-active" : ""}`}
|
||||||
onClick={() => setActiveTab("logs")}
|
onClick={() => setActiveTab("logs")}
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ describe("AppModals", () => {
|
|||||||
const mockModalManager: ModalManager = {
|
const mockModalManager: ModalManager = {
|
||||||
// State
|
// State
|
||||||
detailTask: null,
|
detailTask: null,
|
||||||
detailTaskInitialTab: "definition",
|
detailTaskInitialTab: "chat",
|
||||||
settingsOpen: false,
|
settingsOpen: false,
|
||||||
settingsInitialSection: undefined,
|
settingsInitialSection: undefined,
|
||||||
githubImportOpen: false,
|
githubImportOpen: false,
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask()}
|
task={makeTask()}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -114,6 +115,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask()}
|
task={makeTask()}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -202,6 +204,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ dependencies: [] })}
|
task={makeTask({ dependencies: [] })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -223,6 +226,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ dependencies: ["FN-001", "FN-002"] })}
|
task={makeTask({ dependencies: ["FN-001", "FN-002"] })}
|
||||||
|
initialTab="definition"
|
||||||
tasks={allTasks}
|
tasks={allTasks}
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
@@ -258,6 +262,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ dependencies: [] })}
|
task={makeTask({ dependencies: [] })}
|
||||||
|
initialTab="definition"
|
||||||
tasks={allTasks}
|
tasks={allTasks}
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
@@ -288,6 +293,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ dependencies: ["FN-001", "FN-002"] })}
|
task={makeTask({ dependencies: ["FN-001", "FN-002"] })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -379,6 +385,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ dependencies: [] })}
|
task={makeTask({ dependencies: [] })}
|
||||||
|
initialTab="definition"
|
||||||
tasks={allTasks}
|
tasks={allTasks}
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
@@ -408,6 +415,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ dependencies: [] })}
|
task={makeTask({ dependencies: [] })}
|
||||||
|
initialTab="definition"
|
||||||
tasks={allTasks}
|
tasks={allTasks}
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
@@ -427,7 +435,7 @@ describe("TaskDetailModal", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("tab toggle", () => {
|
describe("tab toggle", () => {
|
||||||
it("defaults to the Definition tab", () => {
|
it("defaults to the Chat tab", () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ prompt: "# Hello\n\nContent" })}
|
task={makeTask({ prompt: "# Hello\n\nContent" })}
|
||||||
@@ -442,18 +450,19 @@ describe("TaskDetailModal", () => {
|
|||||||
|
|
||||||
expect(screen.getByText("Definition")).toBeTruthy();
|
expect(screen.getByText("Definition")).toBeTruthy();
|
||||||
expect(screen.getByText("Logs")).toBeTruthy();
|
expect(screen.getByText("Logs")).toBeTruthy();
|
||||||
// Activity and Agent Log are subviews inside the Logs tab, not top-level tabs
|
// Activity and Agent Log are subviews inside the Logs tab, not top-level tabs.
|
||||||
// They should NOT be visible on the Definition tab
|
// They should NOT be visible on the default Chat tab.
|
||||||
expect(screen.queryByText("Activity")).toBeNull();
|
expect(screen.queryByText("Activity")).toBeNull();
|
||||||
expect(screen.queryByText("Agent Log")).toBeNull();
|
expect(screen.queryByText("Agent Log")).toBeNull();
|
||||||
// Definition content should be visible
|
// Chat content should be visible by default.
|
||||||
expect(container.querySelector(".markdown-body")).toBeTruthy();
|
expect(container.querySelector(".detail-section--chat")).toBeTruthy();
|
||||||
// Activity section should NOT be visible initially
|
expect(container.querySelector("[data-testid='task-chat-tab']")).toBeTruthy();
|
||||||
|
// Activity section should NOT be visible initially.
|
||||||
expect(container.querySelector(".detail-activity")).toBeNull();
|
expect(container.querySelector(".detail-activity")).toBeNull();
|
||||||
// Agent log viewer should not be visible
|
// Agent log viewer should not be visible.
|
||||||
expect(container.querySelector("[data-testid='agent-log-viewer']")).toBeNull();
|
expect(container.querySelector("[data-testid='agent-log-viewer']")).toBeNull();
|
||||||
|
|
||||||
// After clicking Logs tab, the subview toggle buttons should appear
|
// After clicking Logs tab, the subview toggle buttons should appear.
|
||||||
fireEvent.click(screen.getByText("Logs"));
|
fireEvent.click(screen.getByText("Logs"));
|
||||||
const logSubviewToggle = container.querySelector(".log-subview-toggle");
|
const logSubviewToggle = container.querySelector(".log-subview-toggle");
|
||||||
expect(logSubviewToggle).toBeTruthy();
|
expect(logSubviewToggle).toBeTruthy();
|
||||||
@@ -601,6 +610,7 @@ describe("TaskDetailModal", () => {
|
|||||||
prompt: "# Hello\n\nContent",
|
prompt: "# Hello\n\nContent",
|
||||||
log: [{ timestamp: "2026-01-01T00:00:00Z", action: "Test" }],
|
log: [{ timestamp: "2026-01-01T00:00:00Z", action: "Test" }],
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -691,7 +701,7 @@ describe("TaskDetailModal", () => {
|
|||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Default: Definition tab active → enabled should be false
|
// Default: Chat tab active → enabled should be false
|
||||||
const initialCall = mockUseAgentLogs.mock.calls[mockUseAgentLogs.mock.calls.length - 1];
|
const initialCall = mockUseAgentLogs.mock.calls[mockUseAgentLogs.mock.calls.length - 1];
|
||||||
expect(initialCall[1]).toBe(false);
|
expect(initialCall[1]).toBe(false);
|
||||||
|
|
||||||
@@ -744,15 +754,15 @@ describe("TaskDetailModal", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// For an in-progress task (no workflow steps, no merge commit), the
|
// For an in-progress task (no workflow steps, no merge commit), the
|
||||||
// top-level tabs are: Definition, Chat, Logs, Changes, Review, Comments,
|
// top-level tabs are: Chat, Definition, Logs, Changes, Review, Comments,
|
||||||
// Documents, Model, Workflow, Stats, Routing.
|
// Documents, Model, Workflow, Stats, Routing.
|
||||||
const tabTexts = ["Definition", "Chat", "Logs", "Changes", "Review", "Comments", "Documents", "Model", "Workflow", "Stats", "Routing"];
|
const tabTexts = ["Chat", "Definition", "Logs", "Changes", "Review", "Comments", "Documents", "Model", "Workflow", "Stats", "Routing"];
|
||||||
const tabs = screen.getAllByRole("button").filter((b) =>
|
const tabs = screen.getAllByRole("button").filter((b) =>
|
||||||
tabTexts.includes(b.textContent || "")
|
tabTexts.includes(b.textContent || "")
|
||||||
);
|
);
|
||||||
expect(tabs.map((tab) => tab.textContent)).toEqual(tabTexts);
|
expect(tabs.map((tab) => tab.textContent)).toEqual(tabTexts);
|
||||||
expect(tabs[0].textContent).toBe("Definition");
|
expect(tabs[0].textContent).toBe("Chat");
|
||||||
expect(tabs[1].textContent).toBe("Chat");
|
expect(tabs[1].textContent).toBe("Definition");
|
||||||
expect(tabs[2].textContent).toBe("Logs");
|
expect(tabs[2].textContent).toBe("Logs");
|
||||||
|
|
||||||
// Activity and Agent Log are NOT top-level tabs (they are subviews inside Logs)
|
// Activity and Agent Log are NOT top-level tabs (they are subviews inside Logs)
|
||||||
@@ -937,6 +947,47 @@ describe("TaskDetailModal", () => {
|
|||||||
expect(screen.queryByTestId("task-chat-expand-toggle")).toBeNull();
|
expect(screen.queryByTestId("task-chat-expand-toggle")).toBeNull();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("FN-6532 defaults to Chat first while preserving explicit tab requests", () => {
|
||||||
|
const { container, rerender } = render(
|
||||||
|
<TaskDetailModal
|
||||||
|
task={makeTask({ prompt: "# Hello\n\nContent" })}
|
||||||
|
onClose={noop}
|
||||||
|
onMoveTask={noopMove}
|
||||||
|
onDeleteTask={noopDelete}
|
||||||
|
onMergeTask={noopMerge}
|
||||||
|
onOpenDetail={noopOpenDetail}
|
||||||
|
addToast={noop}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
const tabs = Array.from(container.querySelectorAll<HTMLButtonElement>(".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(chatTab.compareDocumentPosition(definitionTab) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
||||||
|
expect(chatTab).toHaveClass("detail-tab-active");
|
||||||
|
expect(definitionTab).not.toHaveClass("detail-tab-active");
|
||||||
|
expect(container.querySelector(".detail-section--chat [data-testid='task-chat-tab']")).toBeTruthy();
|
||||||
|
|
||||||
|
rerender(
|
||||||
|
<TaskDetailModal
|
||||||
|
task={makeTask({ prompt: "# Hello\n\nContent" })}
|
||||||
|
initialTab="logs"
|
||||||
|
onClose={noop}
|
||||||
|
onMoveTask={noopMove}
|
||||||
|
onDeleteTask={noopDelete}
|
||||||
|
onMergeTask={noopMerge}
|
||||||
|
onOpenDetail={noopOpenDetail}
|
||||||
|
addToast={noop}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
|
||||||
|
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-section--chat")).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it("FN-6347 applies chat modifiers only while the Chat tab is active", () => {
|
it("FN-6347 applies chat modifiers only while the Chat tab is active", () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
@@ -950,10 +1001,6 @@ describe("TaskDetailModal", () => {
|
|||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(container.querySelector(".detail-body--chat")).toBeNull();
|
|
||||||
expect(container.querySelector(".detail-section--chat")).toBeNull();
|
|
||||||
|
|
||||||
fireEvent.click(screen.getByRole("button", { name: "Chat" }));
|
|
||||||
const chatBody = container.querySelector(".detail-body--chat");
|
const chatBody = container.querySelector(".detail-body--chat");
|
||||||
const chatSection = container.querySelector(".detail-section--chat");
|
const chatSection = container.querySelector(".detail-section--chat");
|
||||||
expect(chatBody).toBeTruthy();
|
expect(chatBody).toBeTruthy();
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ prompt: "# Test\n\nSpec content." })}
|
task={makeTask({ prompt: "# Test\n\nSpec content." })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -40,6 +41,7 @@ describe("TaskDetailModal", () => {
|
|||||||
const { container } = render(
|
const { container } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ prompt: "# Test\n\nSpec content." })}
|
task={makeTask({ prompt: "# Test\n\nSpec content." })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -65,6 +67,7 @@ describe("TaskDetailModal", () => {
|
|||||||
const { container } = render(
|
const { container } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ prompt: "# Test Task\n\nTest specification." })}
|
task={makeTask({ prompt: "# Test Task\n\nTest specification." })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -94,6 +97,7 @@ describe("TaskDetailModal", () => {
|
|||||||
const { container } = render(
|
const { container } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-099", prompt: "# Original" })}
|
task={makeTask({ id: "FN-099", prompt: "# Original" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -121,6 +125,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ prompt: "# Test" })}
|
task={makeTask({ prompt: "# Test" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -146,6 +151,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-099", column: "todo", prompt: "# Test" })}
|
task={makeTask({ id: "FN-099", column: "todo", prompt: "# Test" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -173,6 +179,7 @@ describe("TaskDetailModal", () => {
|
|||||||
const { container } = render(
|
const { container } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask()}
|
task={makeTask()}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -183,11 +190,11 @@ describe("TaskDetailModal", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// In-progress tasks show exactly 11 tabs:
|
// In-progress tasks show exactly 11 tabs:
|
||||||
// Definition, Chat, Logs, Changes, Review, Comments, Documents, Model, Workflow, Stats, Routing
|
// Chat, Definition, Logs, Changes, Review, Comments, Documents, Model, Workflow, Stats, Routing
|
||||||
const tabs = container.querySelectorAll(".detail-tab");
|
const tabs = container.querySelectorAll(".detail-tab");
|
||||||
expect(tabs.length).toBe(11);
|
expect(tabs.length).toBe(11);
|
||||||
expect(tabs[0].textContent).toBe("Definition");
|
expect(tabs[0].textContent).toBe("Chat");
|
||||||
expect(tabs[1].textContent).toBe("Chat");
|
expect(tabs[1].textContent).toBe("Definition");
|
||||||
expect(tabs[2].textContent).toBe("Logs");
|
expect(tabs[2].textContent).toBe("Logs");
|
||||||
expect(tabs[3].textContent).toBe("Changes");
|
expect(tabs[3].textContent).toBe("Changes");
|
||||||
expect(tabs[4].textContent).toBe("Review");
|
expect(tabs[4].textContent).toBe("Review");
|
||||||
@@ -205,6 +212,7 @@ describe("TaskDetailModal", () => {
|
|||||||
const { container } = render(
|
const { container } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ enabledWorkflowSteps: ["WS-001"] })}
|
task={makeTask({ enabledWorkflowSteps: ["WS-001"] })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -217,8 +225,8 @@ describe("TaskDetailModal", () => {
|
|||||||
// In-progress task with workflow steps: 11 tabs (Review after Changes, Workflow after Model)
|
// In-progress task with workflow steps: 11 tabs (Review after Changes, Workflow after Model)
|
||||||
const tabs = container.querySelectorAll(".detail-tab");
|
const tabs = container.querySelectorAll(".detail-tab");
|
||||||
expect(tabs.length).toBe(11);
|
expect(tabs.length).toBe(11);
|
||||||
expect(tabs[0].textContent).toBe("Definition");
|
expect(tabs[0].textContent).toBe("Chat");
|
||||||
expect(tabs[1].textContent).toBe("Chat");
|
expect(tabs[1].textContent).toBe("Definition");
|
||||||
expect(tabs[2].textContent).toBe("Logs");
|
expect(tabs[2].textContent).toBe("Logs");
|
||||||
expect(tabs[3].textContent).toBe("Changes");
|
expect(tabs[3].textContent).toBe("Changes");
|
||||||
expect(tabs[4].textContent).toBe("Review");
|
expect(tabs[4].textContent).toBe("Review");
|
||||||
@@ -237,6 +245,7 @@ describe("TaskDetailModal", () => {
|
|||||||
column: "done",
|
column: "done",
|
||||||
mergeDetails: { commitSha: "abc1234567890", filesChanged: 3 },
|
mergeDetails: { commitSha: "abc1234567890", filesChanged: 3 },
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -246,11 +255,11 @@ describe("TaskDetailModal", () => {
|
|||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Done task with commit SHA: Definition, Chat, Logs, Changes, Review, Comments, Documents, Model, Workflow, Stats, Routing (11 tabs, no Commits)
|
// Done task with commit SHA: Chat, Definition, Logs, Changes, Review, Comments, Documents, Model, Workflow, Stats, Routing (11 tabs, no Commits)
|
||||||
const tabs = container.querySelectorAll(".detail-tab");
|
const tabs = container.querySelectorAll(".detail-tab");
|
||||||
expect(tabs.length).toBe(11);
|
expect(tabs.length).toBe(11);
|
||||||
expect(tabs[0].textContent).toBe("Definition");
|
expect(tabs[0].textContent).toBe("Chat");
|
||||||
expect(tabs[1].textContent).toBe("Chat");
|
expect(tabs[1].textContent).toBe("Definition");
|
||||||
expect(tabs[2].textContent).toBe("Logs");
|
expect(tabs[2].textContent).toBe("Logs");
|
||||||
expect(tabs[3].textContent).toBe("Changes");
|
expect(tabs[3].textContent).toBe("Changes");
|
||||||
expect(tabs[4].textContent).toBe("Review");
|
expect(tabs[4].textContent).toBe("Review");
|
||||||
@@ -272,6 +281,7 @@ describe("TaskDetailModal", () => {
|
|||||||
mergeDetails: { commitSha: "abc1234567890", filesChanged: 3 },
|
mergeDetails: { commitSha: "abc1234567890", filesChanged: 3 },
|
||||||
enabledWorkflowSteps: ["WS-001"],
|
enabledWorkflowSteps: ["WS-001"],
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -284,8 +294,8 @@ describe("TaskDetailModal", () => {
|
|||||||
// Done task with workflow steps and commit SHA: 11 tabs including Review (no Commits)
|
// Done task with workflow steps and commit SHA: 11 tabs including Review (no Commits)
|
||||||
const tabs = container.querySelectorAll(".detail-tab");
|
const tabs = container.querySelectorAll(".detail-tab");
|
||||||
expect(tabs.length).toBe(11);
|
expect(tabs.length).toBe(11);
|
||||||
expect(tabs[0].textContent).toBe("Definition");
|
expect(tabs[0].textContent).toBe("Chat");
|
||||||
expect(tabs[1].textContent).toBe("Chat");
|
expect(tabs[1].textContent).toBe("Definition");
|
||||||
expect(tabs[2].textContent).toBe("Logs");
|
expect(tabs[2].textContent).toBe("Logs");
|
||||||
expect(tabs[3].textContent).toBe("Changes");
|
expect(tabs[3].textContent).toBe("Changes");
|
||||||
expect(tabs[4].textContent).toBe("Review");
|
expect(tabs[4].textContent).toBe("Review");
|
||||||
@@ -303,6 +313,7 @@ describe("TaskDetailModal", () => {
|
|||||||
const { container: triageContainer } = render(
|
const { container: triageContainer } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ column: "triage" })}
|
task={makeTask({ column: "triage" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -313,14 +324,15 @@ describe("TaskDetailModal", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const triageTabs = triageContainer.querySelectorAll(".detail-tab");
|
const triageTabs = triageContainer.querySelectorAll(".detail-tab");
|
||||||
expect(triageTabs.length).toBe(10); // Definition, Chat, Logs, Review, Comments, Documents, Model, Workflow, Stats, Routing
|
expect(triageTabs.length).toBe(10); // Chat, Definition, Logs, Review, Comments, Documents, Model, Workflow, Stats, Routing
|
||||||
expect(Array.from(triageTabs).map(t => t.textContent)).toEqual([
|
expect(Array.from(triageTabs).map(t => t.textContent)).toEqual([
|
||||||
"Definition", "Chat", "Logs", "Review", "Comments", "Documents", "Model", "Workflow", "Stats", "Routing",
|
"Chat", "Definition", "Logs", "Review", "Comments", "Documents", "Model", "Workflow", "Stats", "Routing",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const { container: todoContainer } = render(
|
const { container: todoContainer } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ column: "todo" })}
|
task={makeTask({ column: "todo" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -331,9 +343,9 @@ describe("TaskDetailModal", () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const todoTabs = todoContainer.querySelectorAll(".detail-tab");
|
const todoTabs = todoContainer.querySelectorAll(".detail-tab");
|
||||||
expect(todoTabs.length).toBe(10); // Definition, Chat, Logs, Review, Comments, Documents, Model, Workflow, Stats, Routing
|
expect(todoTabs.length).toBe(10); // Chat, Definition, Logs, Review, Comments, Documents, Model, Workflow, Stats, Routing
|
||||||
expect(Array.from(todoTabs).map(t => t.textContent)).toEqual([
|
expect(Array.from(todoTabs).map(t => t.textContent)).toEqual([
|
||||||
"Definition", "Chat", "Logs", "Review", "Comments", "Documents", "Model", "Workflow", "Stats", "Routing",
|
"Chat", "Definition", "Logs", "Review", "Comments", "Documents", "Model", "Workflow", "Stats", "Routing",
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -341,6 +353,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ prompt: "" })}
|
task={makeTask({ prompt: "" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -364,6 +377,7 @@ describe("TaskDetailModal", () => {
|
|||||||
status: "awaiting-approval",
|
status: "awaiting-approval",
|
||||||
prompt: "# Task Spec",
|
prompt: "# Task Spec",
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -385,6 +399,7 @@ describe("TaskDetailModal", () => {
|
|||||||
status: "awaiting-approval",
|
status: "awaiting-approval",
|
||||||
prompt: "# Task Spec",
|
prompt: "# Task Spec",
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -406,6 +421,7 @@ describe("TaskDetailModal", () => {
|
|||||||
status: "planning",
|
status: "planning",
|
||||||
prompt: "# Task Spec",
|
prompt: "# Task Spec",
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -427,6 +443,7 @@ describe("TaskDetailModal", () => {
|
|||||||
status: "awaiting-approval",
|
status: "awaiting-approval",
|
||||||
prompt: "",
|
prompt: "",
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -454,6 +471,7 @@ describe("TaskDetailModal", () => {
|
|||||||
status: "awaiting-approval",
|
status: "awaiting-approval",
|
||||||
prompt: "# Task Spec",
|
prompt: "# Task Spec",
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -489,6 +507,7 @@ describe("TaskDetailModal", () => {
|
|||||||
status: "awaiting-approval",
|
status: "awaiting-approval",
|
||||||
prompt: "# Task Spec",
|
prompt: "# Task Spec",
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -534,6 +553,7 @@ describe("TaskDetailModal", () => {
|
|||||||
status: "awaiting-approval",
|
status: "awaiting-approval",
|
||||||
prompt: "# Task Spec",
|
prompt: "# Task Spec",
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -566,6 +586,7 @@ describe("TaskDetailModal", () => {
|
|||||||
status: "awaiting-approval",
|
status: "awaiting-approval",
|
||||||
prompt: "# Task Spec",
|
prompt: "# Task Spec",
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -600,6 +621,7 @@ describe("TaskDetailModal", () => {
|
|||||||
status: "awaiting-approval",
|
status: "awaiting-approval",
|
||||||
prompt: "# Task Spec",
|
prompt: "# Task Spec",
|
||||||
})}
|
})}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -623,6 +645,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask()}
|
task={makeTask()}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -644,6 +667,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask()}
|
task={makeTask()}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -665,6 +689,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001" })}
|
task={makeTask({ id: "FN-001" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -697,6 +722,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001" })}
|
task={makeTask({ id: "FN-001" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -729,6 +755,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001" })}
|
task={makeTask({ id: "FN-001" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -759,6 +786,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001" })}
|
task={makeTask({ id: "FN-001" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -788,6 +816,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001" })}
|
task={makeTask({ id: "FN-001" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -821,6 +850,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ column })}
|
task={makeTask({ column })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -839,6 +869,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ column: "triage" })}
|
task={makeTask({ column: "triage" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -854,6 +885,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ column: "triage", paused: true })}
|
task={makeTask({ column: "triage", paused: true })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -870,6 +902,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ column: "triage", paused: true })}
|
task={makeTask({ column: "triage", paused: true })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -891,6 +924,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "todo", paused: undefined, userPaused: true })}
|
task={makeTask({ id: "FN-001", column: "todo", paused: undefined, userPaused: true })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -917,6 +951,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ column: "triage", paused: true, assignedAgentId: "agent-1" })}
|
task={makeTask({ column: "triage", paused: true, assignedAgentId: "agent-1" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -946,6 +981,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ column: "triage", paused: true, assignedAgentId: "agent-1", pausedByAgentId: "agent-1" })}
|
task={makeTask({ column: "triage", paused: true, assignedAgentId: "agent-1", pausedByAgentId: "agent-1" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -968,6 +1004,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ column: "triage", paused: false, status: "todo" })}
|
task={makeTask({ column: "triage", paused: false, status: "todo" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -984,6 +1021,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -1007,6 +1045,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -1029,6 +1068,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -1056,6 +1096,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -1079,6 +1120,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -1109,6 +1151,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -1136,6 +1179,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -1168,6 +1212,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -1204,6 +1249,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -1234,6 +1280,7 @@ describe("TaskDetailModal", () => {
|
|||||||
const { container } = render(
|
const { container } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -1267,6 +1314,7 @@ describe("TaskDetailModal", () => {
|
|||||||
render(
|
render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
@@ -1300,6 +1348,7 @@ describe("TaskDetailModal", () => {
|
|||||||
const { container } = render(
|
const { container } = render(
|
||||||
<TaskDetailModal
|
<TaskDetailModal
|
||||||
task={makeTask({ id: "FN-001", column: "done" })}
|
task={makeTask({ id: "FN-001", column: "done" })}
|
||||||
|
initialTab="definition"
|
||||||
onClose={noop}
|
onClose={noop}
|
||||||
onMoveTask={noopMove}
|
onMoveTask={noopMove}
|
||||||
onDeleteTask={noopDelete}
|
onDeleteTask={noopDelete}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ describe("useModalManager", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(result.current.detailTask?.id).toBe("FN-123");
|
expect(result.current.detailTask?.id).toBe("FN-123");
|
||||||
expect(result.current.detailTaskInitialTab).toBe("definition");
|
expect(result.current.detailTaskInitialTab).toBe("chat");
|
||||||
|
|
||||||
act(() => {
|
act(() => {
|
||||||
result.current.openDetailWithChangesTab(task);
|
result.current.openDetailWithChangesTab(task);
|
||||||
@@ -203,7 +203,7 @@ describe("useModalManager", () => {
|
|||||||
expect(result.current.detailTask?.id).toBe("FN-456");
|
expect(result.current.detailTask?.id).toBe("FN-456");
|
||||||
// Should not have prompt field (plain Task)
|
// Should not have prompt field (plain Task)
|
||||||
expect("prompt" in (result.current.detailTask as unknown as Record<string, unknown>)).toBe(false);
|
expect("prompt" in (result.current.detailTask as unknown as Record<string, unknown>)).toBe(false);
|
||||||
expect(result.current.detailTaskInitialTab).toBe("definition");
|
expect(result.current.detailTaskInitialTab).toBe("chat");
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import type { SectionId } from "../components/SettingsModal";
|
|||||||
import type { ToastType } from "./useToast";
|
import type { ToastType } from "./useToast";
|
||||||
|
|
||||||
export type DetailTaskTab =
|
export type DetailTaskTab =
|
||||||
|
| "chat"
|
||||||
| "definition"
|
| "definition"
|
||||||
| "logs"
|
| "logs"
|
||||||
| "changes"
|
| "changes"
|
||||||
@@ -162,7 +163,11 @@ export function useModalManager(options: UseModalManagerOptions): ModalManager {
|
|||||||
const [subtaskResumeSessionId, setSubtaskResumeSessionId] = useState<string | undefined>(undefined);
|
const [subtaskResumeSessionId, setSubtaskResumeSessionId] = useState<string | undefined>(undefined);
|
||||||
// Can be Task (optimistic open) or TaskDetail (full data with prompt)
|
// Can be Task (optimistic open) or TaskDetail (full data with prompt)
|
||||||
const [detailTask, setDetailTask] = useState<(Task | TaskDetail) | null>(null);
|
const [detailTask, setDetailTask] = useState<(Task | TaskDetail) | null>(null);
|
||||||
const [detailTaskInitialTab, setDetailTaskInitialTab] = useState<DetailTaskTab>("definition");
|
/**
|
||||||
|
* FNXC:TaskDetailTabs 2026-06-17-00:00:
|
||||||
|
* FN-6532 makes Chat the default task-detail view whenever a task opens without an explicit tab request.
|
||||||
|
*/
|
||||||
|
const [detailTaskInitialTab, setDetailTaskInitialTab] = useState<DetailTaskTab>("chat");
|
||||||
const [detailTaskOrigin, setDetailTaskOrigin] = useState<DetailTaskOrigin | null>(null);
|
const [detailTaskOrigin, setDetailTaskOrigin] = useState<DetailTaskOrigin | null>(null);
|
||||||
const [groupModalGroupId, setGroupModalGroupId] = useState<string | null>(null);
|
const [groupModalGroupId, setGroupModalGroupId] = useState<string | null>(null);
|
||||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||||
@@ -250,9 +255,13 @@ export function useModalManager(options: UseModalManagerOptions): ModalManager {
|
|||||||
setSubtaskResumeSessionId(undefined);
|
setSubtaskResumeSessionId(undefined);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FNXC:TaskDetailTabs 2026-06-17-00:00:
|
||||||
|
* Open-detail callers that omit initialTab should land on Chat; explicit tab requests preserve caller intent.
|
||||||
|
*/
|
||||||
const openDetailTask = useCallback((
|
const openDetailTask = useCallback((
|
||||||
task: Task | TaskDetail,
|
task: Task | TaskDetail,
|
||||||
initialTab: DetailTaskTab = "definition",
|
initialTab: DetailTaskTab = "chat",
|
||||||
options?: { origin?: DetailTaskOrigin },
|
options?: { origin?: DetailTaskOrigin },
|
||||||
) => {
|
) => {
|
||||||
setDetailTask(task);
|
setDetailTask(task);
|
||||||
|
|||||||
Reference in New Issue
Block a user