From 0e3e20c990673198fef4ab0ff08c32b94d59f543 Mon Sep 17 00:00:00 2001 From: Paul Holstein <44263169+holstein13@users.noreply.github.com> Date: Sat, 21 Feb 2026 16:46:32 -0500 Subject: [PATCH] feat(report): add 'report' tab type and openSessionReport store action Co-Authored-By: Claude Opus 4.6 --- .../components/layout/SortableTab.tsx | 3 ++- src/renderer/store/slices/tabSlice.ts | 22 +++++++++++++++++++ src/renderer/types/tabs.ts | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/layout/SortableTab.tsx b/src/renderer/components/layout/SortableTab.tsx index 1a9758c4..72fd3013 100644 --- a/src/renderer/components/layout/SortableTab.tsx +++ b/src/renderer/components/layout/SortableTab.tsx @@ -8,7 +8,7 @@ import { useCallback, useState } from 'react'; import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; import { useStore } from '@renderer/store'; -import { Bell, FileText, LayoutDashboard, Pin, Search, Settings, X } from 'lucide-react'; +import { Activity, Bell, FileText, LayoutDashboard, Pin, Search, Settings, X } from 'lucide-react'; import { useShallow } from 'zustand/react/shallow'; import type { Tab } from '@renderer/types/tabs'; @@ -30,6 +30,7 @@ const TAB_ICONS = { notifications: Bell, settings: Settings, session: FileText, + report: Activity, } as const; export const SortableTab = ({ diff --git a/src/renderer/store/slices/tabSlice.ts b/src/renderer/store/slices/tabSlice.ts index f0d4f3af..1735c03e 100644 --- a/src/renderer/store/slices/tabSlice.ts +++ b/src/renderer/store/slices/tabSlice.ts @@ -46,6 +46,7 @@ export interface TabSlice { closeTab: (tabId: string) => void; setActiveTab: (tabId: string) => void; openDashboard: () => void; + openSessionReport: (sourceTabId: string) => void; getActiveTab: () => Tab | null; isSessionOpen: (sessionId: string) => boolean; enqueueTabNavigation: (tabId: string, request: TabNavigationRequest) => void; @@ -380,6 +381,27 @@ export const createTabSlice: StateCreator = (set, ge set(syncFromLayout(newLayout)); }, + // Open a session report tab based on a source session tab + openSessionReport: (sourceTabId: string) => { + const state = get(); + const allTabs = getAllTabs(state.paneLayout); + const sourceTab = allTabs.find((t) => t.id === sourceTabId); + if (sourceTab?.type !== 'session') return; + + const tabData = state.tabSessionData[sourceTabId]; + const firstMsg = tabData?.sessionDetail?.session.firstMessage; + const label = firstMsg + ? `Report: ${firstMsg.slice(0, 30)}${firstMsg.length > 30 ? '…' : ''}` + : 'Session Report'; + + state.openTab({ + type: 'report', + label, + projectId: sourceTab.projectId, + sessionId: sourceTab.sessionId, + }); + }, + // Get the currently active tab (from the focused pane) getActiveTab: () => { const state = get(); diff --git a/src/renderer/types/tabs.ts b/src/renderer/types/tabs.ts index 4e60603e..434b2ff9 100644 --- a/src/renderer/types/tabs.ts +++ b/src/renderer/types/tabs.ts @@ -76,7 +76,7 @@ export interface Tab { id: string; /** Type of content displayed in this tab */ - type: 'session' | 'dashboard' | 'notifications' | 'settings'; + type: 'session' | 'dashboard' | 'notifications' | 'settings' | 'report'; /** Session ID (required when type === 'session') */ sessionId?: string;