diff --git a/frontend/src/components/assistant/ConcludeSessionModal.tsx b/frontend/src/components/assistant/ConcludeSessionModal.tsx index 82f97c36..a1d10b34 100644 --- a/frontend/src/components/assistant/ConcludeSessionModal.tsx +++ b/frontend/src/components/assistant/ConcludeSessionModal.tsx @@ -33,8 +33,8 @@ interface ConcludeSessionModalProps { const OUTCOMES: { value: ConclusionOutcome; label: string; description: string; icon: typeof CheckCircle2; color: string; bg: string; border: string }[] = [ { value: 'resolved', - label: 'Resolved', - description: 'Issue has been fixed or answered', + label: 'Resolve', + description: 'Mark the issue as fixed', icon: CheckCircle2, color: 'text-emerald-400', bg: 'bg-emerald-400/10', @@ -43,7 +43,7 @@ const OUTCOMES: { value: ConclusionOutcome; label: string; description: string; { value: 'escalated', label: 'Escalate', - description: 'Needs to be handed off or escalated', + description: 'Hand off to another engineer or team', icon: ArrowUpRight, color: 'text-amber-400', bg: 'bg-amber-400/10', @@ -51,8 +51,8 @@ const OUTCOMES: { value: ConclusionOutcome; label: string; description: string; }, { value: 'paused', - label: 'Paused', - description: 'Continuing later — saving progress', + label: 'Pause', + description: 'Save progress and come back later', icon: Pause, color: 'text-blue-400', bg: 'bg-blue-400/10', @@ -155,7 +155,7 @@ export function ConcludeSessionModal({ setSummary('') } } catch { - setError('Failed to conclude session. Please try again.') + setError('Failed to close case. Please try again.') setGenerating(false) } } @@ -296,7 +296,7 @@ export function ConcludeSessionModal({ {step === 'select-outcome' && (

- How did this session end? + What would you like to do?

{OUTCOMES.map(o => { const Icon = o.icon @@ -526,12 +526,12 @@ export function ConcludeSessionModal({ {generating ? ( <> - Generating... + Closing... ) : ( <> - Generate Summary + Close & Generate )} diff --git a/frontend/src/components/assistant/IncidentHeader.tsx b/frontend/src/components/assistant/IncidentHeader.tsx index 0bf67a2c..880977a1 100644 --- a/frontend/src/components/assistant/IncidentHeader.tsx +++ b/frontend/src/components/assistant/IncidentHeader.tsx @@ -1,5 +1,5 @@ import { useState, useRef, useEffect } from 'react' -import { Pencil, X, Check, ExternalLink, Pause, XCircle, Link2, MoreHorizontal, FileText } from 'lucide-react' +import { Pencil, X, Check, CheckCircle2, ExternalLink, Pause, XCircle, Link2, MoreHorizontal, FileText } from 'lucide-react' import { cn } from '@/lib/utils' import { toast } from '@/lib/toast' import type { TriageMeta } from '@/types/ai-session' @@ -12,8 +12,6 @@ interface IncidentHeaderProps { onStatusUpdate?: () => void onPause?: () => void onClose?: () => void - /** Extra elements rendered in the action group (e.g. ViewToggle) */ - extraActions?: React.ReactNode } interface EditPopoverProps { @@ -129,14 +127,14 @@ function OverflowMenu({ onPause, onClose }: { onPause?: () => void; onClose?: () {open && ( <>
setOpen(false)} /> -
+
{onPause && ( )} )}
@@ -170,7 +168,6 @@ export function IncidentHeader({ onStatusUpdate, onPause, onClose, - extraActions, }: IncidentHeaderProps) { return (
@@ -212,21 +209,21 @@ export function IncidentHeader({ )} {onStatusUpdate && ( )} - {extraActions}
) diff --git a/frontend/src/components/assistant/ViewToggle.tsx b/frontend/src/components/assistant/ViewToggle.tsx index fc88bfb6..1b5e0b8c 100644 --- a/frontend/src/components/assistant/ViewToggle.tsx +++ b/frontend/src/components/assistant/ViewToggle.tsx @@ -18,6 +18,13 @@ interface ViewToggleProps { sessionId?: string } +/** + * Persistent tab bar for switching between FlowPilot (chat) and Cockpit (triage) views. + * Renders as a horizontal tab strip with an active bottom-border indicator. + * + * NOTE: If the tab bar proves too tall or prominent in certain layouts, + * consider pivoting to a compact segmented control (Option A from the critique). + */ export function ViewToggle({ currentView, sessionId }: ViewToggleProps) { const navigate = useNavigate() const hasCockpit = useFeatureFlag('flowpilot_cockpit') @@ -37,19 +44,24 @@ export function ViewToggle({ currentView, sessionId }: ViewToggleProps) { } return ( -
+
{VIEW_OPTIONS.map(({ key, label, icon: Icon }) => ( ))} diff --git a/frontend/src/components/flowpilot/FlowPilotActionBar.tsx b/frontend/src/components/flowpilot/FlowPilotActionBar.tsx deleted file mode 100644 index df72f812..00000000 --- a/frontend/src/components/flowpilot/FlowPilotActionBar.tsx +++ /dev/null @@ -1,227 +0,0 @@ -import { useState } from 'react' -import { CheckCircle2, ArrowUpRight, Pause, X, FileText } from 'lucide-react' -import { EscalateModal } from './EscalateModal' -import { StatusUpdateModal } from './StatusUpdateModal' -import type { - ResolveSessionRequest, - EscalateSessionRequest, - SessionDocumentation, - StatusUpdateAudience, - StatusUpdateLength, - StatusUpdateContext, - StatusUpdateResponse, -} from '@/types/ai-session' - -interface FlowPilotActionBarProps { - canResolve: boolean - canEscalate: boolean - isProcessing: boolean - hasPsaTicket?: boolean - sessionId?: string - canShareUpdate?: boolean - onResolve: (data: ResolveSessionRequest) => Promise - onEscalate: (data: EscalateSessionRequest) => Promise - onPause?: () => Promise - onAbandon?: () => Promise - onGenerateStatusUpdate?: (audience: StatusUpdateAudience, length: StatusUpdateLength, context: StatusUpdateContext) => Promise -} - -export function FlowPilotActionBar({ - canResolve, - canEscalate, - isProcessing, - hasPsaTicket = false, - sessionId, - canShareUpdate = false, - onResolve, - onEscalate, - onPause, - onAbandon, - onGenerateStatusUpdate, -}: FlowPilotActionBarProps) { - const [showResolve, setShowResolve] = useState(false) - const [showEscalate, setShowEscalate] = useState(false) - const [showAbandon, setShowAbandon] = useState(false) - const [showStatusUpdate, setShowStatusUpdate] = useState(false) - const [resolutionSummary, setResolutionSummary] = useState('') - const [submitting, setSubmitting] = useState(false) - - const handleResolve = async () => { - if (!resolutionSummary.trim() || resolutionSummary.length < 5) return - setSubmitting(true) - try { - await onResolve({ resolution_summary: resolutionSummary }) - setShowResolve(false) - } finally { - setSubmitting(false) - } - } - - const handlePause = async () => { - if (onPause) { - setSubmitting(true) - try { - await onPause() - } finally { - setSubmitting(false) - } - } - } - - const handleAbandon = async () => { - if (onAbandon) { - setSubmitting(true) - try { - await onAbandon() - setShowAbandon(false) - } finally { - setSubmitting(false) - } - } - } - - return ( - <> - {/* Bottom bar — fixed to viewport bottom, single row on all screen sizes */} -
- {/* Primary actions */} - - - {canShareUpdate && onGenerateStatusUpdate && ( - - )} - - {/* Spacer */} -
- - {/* Secondary actions — right side */} - {onPause && ( - - )} - {onAbandon && ( - - )} -
- - {/* Resolve modal */} - {showResolve && ( -
-
-

Resolve Session

-

Summarize what fixed the issue. This will be included in the auto-generated documentation.

-