From a19df338aded8e812225f6a331cc07f9bbb751c5 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Sat, 27 Jun 2026 12:15:42 -0700 Subject: [PATCH] FN-7131: add done-task summary tab Done task details now open to a read-only Summary tab before Chat. - Add TaskSummaryTab with completion summary markdown, landed-file stats, completed steps, workflow results, and retry context. - Default done-task detail entrypoints to Summary while preserving explicit tab selections and plugin tab typing. - Style and localize the Summary tab, document it, and add dashboard coverage for defaulting and tab content. - Add a minor changeset for the published CLI package. Files changed: .changeset/fn-7131-summary-tab.md | 7 + docs/dashboard-guide.md | 1 + packages/dashboard/app/App.tsx | 2 +- .../dashboard/app/components/TaskDetailModal.css | 181 +++++++++++++++++ .../dashboard/app/components/TaskDetailModal.tsx | 63 ++++-- .../dashboard/app/components/TaskSummaryTab.tsx | 160 +++++++++++++++ .../TaskDetailModal.definition-actions.test.tsx | 56 +++--- .../__tests__/TaskDetailModal.summary-tab.test.tsx | 222 +++++++++++++++++++++ .../dashboard/app/components/dashboard/types.ts | 2 +- .../app/hooks/__tests__/useModalManager.test.ts | 10 +- .../dashboard/app/hooks/useMainPanelTaskDetail.ts | 9 +- packages/dashboard/app/hooks/useModalManager.ts | 12 +- packages/dashboard/app/plugins/types.ts | 2 +- packages/i18n/locales/en/app.json | 16 ++ 14 files changed, 687 insertions(+), 56 deletions(-) Fusion-Task-Id: FN-7131 Fusion-Task-Lineage: e8ca4ade-9904-4705-a151-d9e55f67b398 Co-authored-by: Fusion (runfusion.ai) --- .changeset/fn-7131-summary-tab.md | 7 + docs/dashboard-guide.md | 1 + packages/dashboard/app/App.tsx | 2 +- .../app/components/TaskDetailModal.css | 181 ++++++++++++++ .../app/components/TaskDetailModal.tsx | 63 +++-- .../app/components/TaskSummaryTab.tsx | 160 +++++++++++++ ...askDetailModal.definition-actions.test.tsx | 56 ++--- .../TaskDetailModal.summary-tab.test.tsx | 222 ++++++++++++++++++ .../app/components/dashboard/types.ts | 2 +- .../hooks/__tests__/useModalManager.test.ts | 10 +- .../app/hooks/useMainPanelTaskDetail.ts | 9 +- .../dashboard/app/hooks/useModalManager.ts | 12 +- packages/dashboard/app/plugins/types.ts | 2 +- packages/i18n/locales/en/app.json | 16 ++ 14 files changed, 687 insertions(+), 56 deletions(-) create mode 100644 .changeset/fn-7131-summary-tab.md create mode 100644 packages/dashboard/app/components/TaskSummaryTab.tsx create mode 100644 packages/dashboard/app/components/__tests__/TaskDetailModal.summary-tab.test.tsx diff --git a/.changeset/fn-7131-summary-tab.md b/.changeset/fn-7131-summary-tab.md new file mode 100644 index 0000000000..1d7374d6cf --- /dev/null +++ b/.changeset/fn-7131-summary-tab.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": minor +--- + +summary: Done tasks now open on a new Summary tab showing what changed and what the agents did. +category: feature +dev: Adds the "summary" TabId + TaskSummaryTab to TaskDetailModal; done tasks resolve the implicit Chat default to Summary while explicit tab entrypoints are honored. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index d6edaa02b4..b441ee682e 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -966,6 +966,7 @@ For related global/project configuration behavior, see [Settings reference](./se Inspect task definition, logs, review feedback, comments, artifacts, workflow outcomes, model overrides, and task routing from a single modal. - Editable tasks with descriptions show **Summarize as title** beside the read-mode title; it asks AI to generate a concise title from the description and saves it without opening the edit form. +- The **Summary** tab appears first for `done` tasks and is their default landing tab. It shows the recorded completion summary, changed-file/merge stats when available, completed steps, workflow results, and retry counts from the already-loaded task detail; non-`done` tasks still open on **Chat** by default. - The **Chat** tab includes an expand/collapse control that lets the transcript and composer fill the task-detail modal, then restores the normal header, tabs, and action footer when collapsed. - Task-detail Chat messages are persisted as user comments/steering guidance and surfaced to every relevant agent lane: live executor sessions receive steering injection, while planner, reviewer (spec/plan/code), and merger agents (standard and clean-room AI merge/review) receive the latest user comments in their next prompt/pass. - The priority chip in task metadata is an inline picker: you can change priority directly without entering full edit mode. diff --git a/packages/dashboard/app/App.tsx b/packages/dashboard/app/App.tsx index 51f8f45a84..efc906fe88 100644 --- a/packages/dashboard/app/App.tsx +++ b/packages/dashboard/app/App.tsx @@ -787,7 +787,7 @@ function AppInner() { FNXC:TaskDetailBack 2026-06-25-00:00: Browser and Android Back must close the currently viewed full-panel task detail before leaving the prior dashboard view. The history entry owns an idempotent revert callback that clears stale snapshot state for board/list origins or restores the previous task snapshot for nested task-detail links, and explicit Back-to-board consumes that same entry without pushing a contradictory view entry during popstate. */ - const openTaskDetailInMainPanel = useCallback((task: Task | TaskDetail, initialTab: DetailTaskTab = "chat") => { + const openTaskDetailInMainPanel = useCallback((task: Task | TaskDetail, initialTab?: DetailTaskTab) => { const previousView = taskView; const previousDetailTask = mainPanelDetailTask; const previousDetailTab = mainPanelDetailInitialTab; diff --git a/packages/dashboard/app/components/TaskDetailModal.css b/packages/dashboard/app/components/TaskDetailModal.css index 799c189d49..38cd414c80 100644 --- a/packages/dashboard/app/components/TaskDetailModal.css +++ b/packages/dashboard/app/components/TaskDetailModal.css @@ -1555,6 +1555,187 @@ The footer Actions/Move dropdown buttons sit at the BOTTOM of the embedded panel margin-bottom: 0; } +/* +FNXC:TaskDetailSummaryTab 2026-06-27-00:00: +The done-task Summary tab is a scrollable overview composed from existing detail data. Reuse detail-section/markdown conventions and tokenized spacing/colors so the new landing tab preserves modal hierarchy across desktop and mobile. +*/ +.detail-section--summary { + overflow-y: auto; +} + +.task-summary-tab { + display: flex; + flex-direction: column; + gap: var(--space-lg); +} + +.task-summary-section { + display: flex; + flex-direction: column; + gap: var(--space-sm); + padding: var(--space-lg); + background: var(--card); + border: var(--btn-border-width) solid var(--border); + border-radius: var(--radius-lg); +} + +.task-summary-section h4, +.task-summary-section h5 { + margin: 0; +} + +.task-summary-section h5 { + color: var(--text-muted); + font-size: calc(var(--space-sm) + var(--space-xs) * 0.75); + font-weight: 600; +} + +.task-summary-markdown { + color: var(--text); +} + +.task-summary-empty { + margin: 0; + color: var(--text-muted); + font-size: calc(var(--space-sm) + var(--space-xs) * 0.75); +} + +.task-summary-stats { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(calc(var(--space-2xl) * 3), 1fr)); + gap: var(--space-sm); + margin: 0; +} + +.task-summary-stats > div { + display: flex; + flex-direction: column; + gap: var(--space-xs); + min-width: 0; + padding: var(--space-sm); + background: var(--surface); + border: var(--btn-border-width) solid var(--border); + border-radius: var(--radius-md); +} + +.task-summary-stats dt { + color: var(--text-muted); + font-size: calc(var(--space-sm) + var(--space-xs) * 0.5); + text-transform: uppercase; + letter-spacing: calc(var(--btn-border-width) * 0.5); +} + +.task-summary-stats dd { + margin: 0; + color: var(--text); + font-family: var(--font-mono); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.task-summary-diff-add { + color: var(--color-success); +} + +.task-summary-diff-del { + color: var(--color-error); +} + +.task-summary-file-list, +.task-summary-work-list { + display: flex; + flex-direction: column; + gap: var(--space-xs); + margin: 0; + padding: 0; + list-style: none; +} + +.task-summary-file-list li, +.task-summary-work-list li { + min-width: 0; + padding: var(--space-sm); + background: var(--surface); + border: var(--btn-border-width) solid var(--border); + border-radius: var(--radius-md); + color: var(--text); +} + +.task-summary-file-list li { + font-family: var(--font-mono); + font-size: calc(var(--space-sm) + var(--space-xs) * 0.75); + overflow-wrap: anywhere; +} + +.task-summary-subsection { + display: flex; + flex-direction: column; + gap: var(--space-sm); +} + +.task-summary-work-list li { + display: flex; + align-items: center; + gap: var(--space-sm); +} + +.task-summary-status { + flex-shrink: 0; + padding: var(--space-xs) var(--space-sm); + border-radius: var(--radius-full); + background: var(--surface-muted); + color: var(--text-muted); + font-size: calc(var(--space-sm) + var(--space-xs) * 0.5); + font-weight: 600; + text-transform: capitalize; +} + +.task-summary-status--done, +.task-summary-status--passed { + background: color-mix(in srgb, var(--color-success) 16%, transparent); + color: var(--color-success); +} + +.task-summary-status--skipped, +.task-summary-status--advisory_failure, +.task-summary-status--pending { + background: color-mix(in srgb, var(--color-warning) 16%, transparent); + color: var(--color-warning); +} + +.task-summary-status--failed { + background: color-mix(in srgb, var(--color-error) 16%, transparent); + color: var(--color-error); +} + +.task-summary-retries { + margin: 0; + color: var(--text-muted); +} + +@media (max-width: 768px) { + .detail-section--summary { + padding-inline: var(--space-sm); + } + + .task-summary-tab { + gap: var(--space-md); + } + + .task-summary-section { + padding: var(--space-md); + } + + .task-summary-stats { + grid-template-columns: 1fr; + } + + .task-summary-work-list li { + align-items: flex-start; + } +} + /* Spec tab layout - allows SpecEditor to fill available vertical space */ .detail-section--spec { display: flex; diff --git a/packages/dashboard/app/components/TaskDetailModal.tsx b/packages/dashboard/app/components/TaskDetailModal.tsx index 452e7f91cc..d4dd3d6a9c 100644 --- a/packages/dashboard/app/components/TaskDetailModal.tsx +++ b/packages/dashboard/app/components/TaskDetailModal.tsx @@ -37,6 +37,7 @@ import { TaskChatTab } from "./TaskChatTab"; import { TaskReviewTab } from "./TaskReviewTab"; import { MergeDetails } from "./MergeDetails"; import { TaskChangesTab } from "./TaskChangesTab"; +import { TaskSummaryTab } from "./TaskSummaryTab"; import { WorkspaceWorktreesSummary, isWorkspaceTask } from "./WorkspaceWorktreesSummary"; import { TaskForm, type PendingImage } from "./TaskForm"; import { useNodes } from "../hooks/useNodes"; @@ -189,7 +190,24 @@ function formatDurationCompact(ageMs: number): string { return `${minutes}m`; } -type TabId = "definition" | "chat" | "logs" | "changes" | "review" | "pr" | "comments" | "model" | "workflow" | "documents" | "stats" | "routing" | "retries" | "terminal" | `plugin-${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: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. +*/ +function resolveDefaultTab(initialTab: TabId | undefined, column: ColumnId): TabId { + if (initialTab === "retries") { + return "definition"; + } + if (initialTab) { + return initialTab; + } + return column === "done" ? "summary" : "chat"; +} // Lazy-load the terminal so xterm + addons stay out of the main bundle (U11). const LazySessionTerminal = lazy(() => @@ -278,7 +296,7 @@ export interface TaskDetailModalProps { prAuthAvailable?: boolean; autoMergeEnabled?: boolean; onOpenWorkflowEditor?: () => void; - /** Open the modal with this tab active instead of the default Chat view. */ + /** Open the modal with this tab active instead of the default done-aware landing view. */ initialTab?: TabId; /** Mobile-only header affordance mode. */ mobileHeaderMode?: "close" | "back"; @@ -476,7 +494,7 @@ export function TaskDetailContent({ * 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", + initialTab, mobileHeaderMode = "close", embedded = false, onRequestClose, @@ -486,7 +504,7 @@ export function TaskDetailContent({ }: TaskDetailContentProps) { const { t } = useTranslation("app"); const columnLabel = useColumnLabel(); - const [activeTab, setActiveTab] = useState(initialTab === "retries" ? "definition" : initialTab); + const [activeTab, setActiveTab] = useState(() => resolveDefaultTab(initialTab, task.column)); const [chatExpanded, setChatExpanded] = useState(false); // ── CLI agent session (U11) ──────────────────────────────────────────────── @@ -613,11 +631,11 @@ export function TaskDetailContent({ // Sync activeTab when the caller changes initialTab (e.g. opening a different tab) useEffect(() => { - setActiveTab(initialTab === "retries" ? "definition" : initialTab); + setActiveTab(resolveDefaultTab(initialTab, task.column)); if (initialTab === "retries") { setRetriesExpanded(true); } - }, [initialTab]); + }, [initialTab, task.column]); useEffect(() => { if (activeTab === "pr" && task.column !== "in-review") { @@ -625,6 +643,12 @@ export function TaskDetailContent({ } }, [activeTab, task.column]); + useEffect(() => { + if (activeTab === "summary" && task.column !== "done") { + setActiveTab("definition"); + } + }, [activeTab, task.column]); + // Reset description expanded state when task changes useEffect(() => { setDescriptionExpanded(false); @@ -3050,7 +3074,18 @@ 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. */} + {task.column === "done" && ( + + )}