feat: FlowPilot migration — Phase 1-9 + Phase 9 bug fixes + QA fixture harness #147

Merged
chihlasm merged 85 commits from feat/flowpilot-migration into main 2026-04-25 06:02:14 +00:00
7 changed files with 33 additions and 14 deletions
Showing only changes of commit f3c3ee5b57 - Show all commits

View File

@@ -48,7 +48,7 @@ export function ActiveFlowPilotSessions({ hideHeader = false }: { hideHeader?: b
{sessions.map((session) => (
<button
key={session.id}
onClick={() => navigate(session.session_type === 'chat' ? `/assistant/${session.id}` : `/pilot/${session.id}`)}
onClick={() => navigate(`/pilot/${session.id}`)}
className="card-interactive p-4 text-left"
>
<div className="flex items-start justify-between gap-2 mb-2">

View File

@@ -52,7 +52,7 @@ export function RecentFlowPilotSessions({ hideHeader = false }: { hideHeader?: b
return (
<button
key={session.id}
onClick={() => navigate(session.session_type === 'chat' ? `/assistant/${session.id}` : `/pilot/${session.id}`)}
onClick={() => navigate(`/pilot/${session.id}`)}
className="flex w-full items-center gap-3 px-5 py-3 text-left hover:bg-[rgba(255,255,255,0.02)] transition-colors"
style={{
borderBottom: i < sessions.length - 1 ? '1px solid var(--color-border-default)' : undefined,

View File

@@ -52,7 +52,7 @@ export function StartSessionInput() {
if (completedUploadIds.length > 0) {
state.uploadIds = completedUploadIds
}
navigate('/assistant', { state })
navigate('/pilot', { state })
}
const handleKeyDown = (e: React.KeyboardEvent) => {
@@ -63,7 +63,7 @@ export function StartSessionInput() {
}
const handleSuggestionClick = (suggestion: string) => {
navigate('/assistant', { state: { prefill: suggestion } })
navigate('/pilot', { state: { prefill: suggestion } })
}
// ── File handling ──────────────────────────────

View File

@@ -18,9 +18,12 @@ const STATUS_CONFIG = {
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 = isChat ? `/assistant/${session.id}` : `/pilot/${session.id}`
const linkTo = `/pilot/${session.id}`
const displayTitle = isChat
? (session.title || session.problem_summary || 'Untitled chat')
: (session.problem_summary || 'Untitled session')

View File

@@ -42,7 +42,7 @@ const PAGES: PaletteItem[] = [
{ id: 'page-dashboard', group: 'pages', title: 'Dashboard', path: '/', icon: 'page' },
{ id: 'page-flows', group: 'pages', title: 'All Flows', subtitle: 'Browse your flow library', path: '/trees', icon: 'page' },
{ id: 'page-sessions', group: 'pages', title: 'Sessions', subtitle: 'View session history', path: '/sessions', icon: 'page' },
{ id: 'page-assistant', group: 'pages', title: 'AI Assistant', subtitle: 'FlowPilot chat', path: '/assistant', icon: 'page' },
{ id: 'page-flowpilot', group: 'pages', title: 'FlowPilot', subtitle: 'AI troubleshooting', path: '/pilot', icon: 'page' },
{ id: 'page-scripts', group: 'pages', title: 'Script Generator', subtitle: 'Generate PowerShell scripts', path: '/scripts', icon: 'page' },
{ id: 'page-analytics', group: 'pages', title: 'Analytics', subtitle: 'Team usage & metrics', path: '/analytics', icon: 'page' },
{ id: 'page-settings', group: 'pages', title: 'Settings', subtitle: 'Account & preferences', path: '/account', icon: 'page' },
@@ -177,7 +177,7 @@ export function CommandPalette({ open, onClose }: CommandPaletteProps) {
group: 'flowpilot',
title: 'Troubleshoot with FlowPilot',
subtitle: trimmed,
path: '/assistant',
path: '/pilot',
icon: 'sparkles',
}

View File

@@ -9,7 +9,7 @@ const PREFETCH_MAP: Record<string, () => Promise<unknown>> = {
'/shares': () => import('@/pages/MySharesPage'),
'/analytics': () => import('@/pages/TeamAnalyticsPage'),
'/analytics/me': () => import('@/pages/MyAnalyticsPage'),
'/assistant': () => import('@/pages/AssistantChatPage'),
'/pilot': () => import('@/pages/AssistantChatPage'),
'/step-library': () => import('@/pages/StepLibraryPage'),
'/guides': () => import('@/pages/GuidesHubPage'),
'/feedback': () => import('@/pages/FeedbackPage'),

View File

@@ -1,4 +1,4 @@
import { createBrowserRouter } from 'react-router-dom'
import { createBrowserRouter, Navigate, useParams } from 'react-router-dom'
import * as Sentry from '@sentry/react'
import { Suspense } from 'react'
import { AppLayout, ProtectedRoute } from '@/components/layout'
@@ -49,7 +49,10 @@ const ScriptLibraryPage = lazyWithRetry(() => import('@/pages/ScriptLibraryPage'
const ScriptManagePage = lazyWithRetry(() => import('@/pages/ScriptManagePage'))
const AssistantChatPage = lazyWithRetry(() => import('@/pages/AssistantChatPage'))
const FlowAssistPage = lazyWithRetry(() => import('@/pages/FlowAssistPage'))
const FlowPilotSessionPage = lazyWithRetry(() => import('@/pages/FlowPilotSessionPage'))
// FlowPilotSessionPage (the old guided-mode surface) was removed from active
// routing in Phase 1 of the FlowPilot migration. The file is retained on disk
// for reference but not mounted — the unified chat-primary surface now serves
// /pilot. Delete the file when nothing in the tree references it anymore.
const EscalationQueuePage = lazyWithRetry(() => import('@/pages/EscalationQueuePage'))
const ReviewQueuePage = lazyWithRetry(() => import('@/pages/ReviewQueuePage'))
const FlowPilotAnalyticsPage = lazyWithRetry(() => import('@/pages/FlowPilotAnalyticsPage'))
@@ -98,6 +101,16 @@ function page(Component: React.LazyExoticComponent<React.ComponentType>) {
)
}
/**
* Permanent 301-style redirect from /assistant/:sessionId to /pilot/:sessionId.
* Used by the Phase 1 route-rename; paired with a bare-path redirect to /pilot.
* SPA redirects replace history so the legacy URL does not linger in back-nav.
*/
function AssistantSessionRedirect() {
const { sessionId } = useParams<{ sessionId: string }>()
return <Navigate to={sessionId ? `/pilot/${sessionId}` : '/pilot'} replace />
}
export const router = sentryCreateBrowserRouter([
{
path: '/landing',
@@ -202,11 +215,14 @@ export const router = sentryCreateBrowserRouter([
{ path: 'network-diagrams/new', element: page(DiagramEditorPage) },
{ path: 'network-diagrams/:id', element: page(DiagramEditorPage) },
{ path: 'kb-accelerator', element: page(KBAcceleratorPage) },
{ path: 'assistant', element: page(AssistantChatPage) },
{ path: 'assistant/:sessionId', element: page(AssistantChatPage) },
// Phase 1 — FlowPilot migration. The unified chat-primary surface lives at
// /pilot; /assistant permanently redirects. FlowPilotSessionPage (old
// guided surface) is no longer mounted.
{ path: 'pilot', element: page(AssistantChatPage) },
{ path: 'pilot/:sessionId', element: page(AssistantChatPage) },
{ path: 'assistant', element: <Navigate to="/pilot" replace /> },
{ path: 'assistant/:sessionId', element: <AssistantSessionRedirect /> },
{ path: 'flow-assist', element: page(FlowAssistPage) },
{ path: 'pilot', element: page(FlowPilotSessionPage) },
{ path: 'pilot/:sessionId', element: page(FlowPilotSessionPage) },
{ path: 'escalations', element: page(EscalationQueuePage) },
{ path: 'queue', element: page(SessionQueuePage) },
{ path: 'review-queue', element: page(ReviewQueuePage) },