All checks were successful
Mirror to GitHub / mirror (push) Successful in 3s
Collapses the pre-existing dual-surface setup (AssistantChatPage at /assistant, FlowPilotSessionPage at /pilot) into a single chat-primary surface per architectural claim #1 of FLOWPILOT-MIGRATION.md. Router changes (frontend/src/router.tsx): - /pilot and /pilot/:sessionId now render AssistantChatPage. - /assistant redirects permanently to /pilot via <Navigate replace>. - /assistant/:sessionId redirects to /pilot/:sessionId preserving the ID via an AssistantSessionRedirect helper that reads the param. - FlowPilotSessionPage is no longer imported or mounted. Per the beta-history-disposable decision, the file stays on disk for reference but is unreachable; delete once nothing else in the tree imports it. Dispatcher de-branching — previously these sites routed by session_type (chat -> /assistant, otherwise -> /pilot). All now unconditionally go to /pilot/:id since session_type is no longer used for frontend routing: - components/dashboard/ActiveFlowPilotSessions.tsx - components/dashboard/RecentFlowPilotSessions.tsx - components/flowpilot/AISessionListItem.tsx (keeps isChat for icon selection, but linkTo is unconditional) User-facing label + navigation updates: - components/layout/CommandPalette.tsx: "AI Assistant" palette entry becomes "FlowPilot" pointing to /pilot; the sparkles quick-action also routes to /pilot. - components/dashboard/StartSessionInput.tsx: both navigate() call sites now go to /pilot instead of /assistant. - lib/routePrefetch.ts: prefetch entry for AssistantChatPage keyed to /pilot (the real surface) rather than /assistant (now redirect-only). Preserved intentionally (not user-facing routes): - Backend /assistant/retention API path and the assistantChatApi module name — those are internal API and module identifiers, not SPA routes. - src/components/assistant/* and src/types/assistant-chat — TypeScript module paths, not routes. - Sidebar.tsx — no top-level AI entry existed to rename; /pilot is already in the History group's matchPaths. Whether FlowPilot deserves its own rail entry is a future UX decision, not Phase 1 scope. - FlowPilotAnalyticsPage at /analytics/flowpilot — analytics for the unified product, not guided-only, per the agreed Q16 interpretation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
78 lines
3.1 KiB
TypeScript
78 lines
3.1 KiB
TypeScript
import { Link } from 'react-router-dom'
|
|
import { Clock, CheckCircle2, ArrowUpRight, AlertCircle, Pause, Route, MessageCircle } from 'lucide-react'
|
|
import { cn } from '@/lib/utils'
|
|
import type { AISessionSummary } from '@/types/ai-session'
|
|
|
|
interface AISessionListItemProps {
|
|
session: AISessionSummary
|
|
}
|
|
|
|
const STATUS_CONFIG = {
|
|
active: { icon: Clock, color: 'text-primary', label: 'Active' },
|
|
paused: { icon: Pause, color: 'text-warning', label: 'Paused' },
|
|
resolved: { icon: CheckCircle2, color: 'text-success', label: 'Resolved' },
|
|
escalated: { icon: ArrowUpRight, color: 'text-warning', label: 'Escalated' },
|
|
abandoned: { icon: AlertCircle, color: 'text-text-muted', label: 'Abandoned' },
|
|
} as const
|
|
|
|
export function AISessionListItem({ session }: AISessionListItemProps) {
|
|
const config = STATUS_CONFIG[session.status as keyof typeof STATUS_CONFIG] ?? STATUS_CONFIG.active
|
|
const StatusIcon = config.icon
|
|
// Both chat and guided sessions now land on the unified /pilot surface.
|
|
// session_type is preserved on the DB row for data compatibility but is
|
|
// no longer used for frontend route selection (Phase 1 FlowPilot migration).
|
|
const isChat = session.session_type === 'chat'
|
|
const TypeIcon = isChat ? MessageCircle : Route
|
|
const linkTo = `/pilot/${session.id}`
|
|
const displayTitle = isChat
|
|
? (session.title || session.problem_summary || 'Untitled chat')
|
|
: (session.problem_summary || 'Untitled session')
|
|
|
|
return (
|
|
<Link
|
|
to={linkTo}
|
|
className="card-interactive block p-4 transition-all"
|
|
>
|
|
<div className="flex items-start justify-between gap-3">
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2">
|
|
<span className={cn(
|
|
'flex items-center justify-center w-5 h-5 rounded',
|
|
isChat ? 'text-violet-400' : 'text-primary'
|
|
)}>
|
|
<TypeIcon size={14} />
|
|
</span>
|
|
<p className="text-sm font-medium text-foreground truncate">
|
|
{displayTitle}
|
|
</p>
|
|
</div>
|
|
<div className="mt-1.5 flex items-center gap-3 flex-wrap">
|
|
{session.problem_domain && (
|
|
<span className="font-sans text-xs rounded-md bg-accent-dim px-2 py-0.5 text-[0.625rem] uppercase tracking-wider text-primary">
|
|
{session.problem_domain}
|
|
</span>
|
|
)}
|
|
<span className={cn('flex items-center gap-1 text-xs', config.color)}>
|
|
<StatusIcon size={12} />
|
|
{config.label}
|
|
</span>
|
|
<span className="text-xs text-muted-foreground">
|
|
{session.step_count} {isChat ? 'messages' : 'steps'}
|
|
</span>
|
|
<span className="text-xs text-text-muted">
|
|
{new Date(session.created_at).toLocaleDateString(undefined, {
|
|
month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit',
|
|
})}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
{session.session_rating && (
|
|
<span className="font-sans text-xs text-xs text-warning">
|
|
{'★'.repeat(session.session_rating)}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</Link>
|
|
)
|
|
}
|