feat(pilot): unify AI troubleshooting surface at /pilot, redirect /assistant (Phase 1)
All checks were successful
Mirror to GitHub / mirror (push) Successful in 3s
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>
This commit is contained in:
@@ -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">
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 ──────────────────────────────
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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',
|
||||
}
|
||||
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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) },
|
||||
|
||||
Reference in New Issue
Block a user