Remove duplicate Update/Close actions from chat toolbars (FlowPilotPage, CockpitPage) — session lifecycle actions now live only in headers. Redesign ViewToggle as a persistent tab bar with bottom-border active indicator and ARIA attributes. Standardize all action naming: Resolve (emerald), Update (blue), Close (rose), Pause (muted). Fix IncidentHeader Resolve from orange to emerald. Delete unused FlowPilotActionBar component (227 lines). Update ConcludeSessionModal copy to use forward-facing action verbs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
71 lines
2.5 KiB
TypeScript
71 lines
2.5 KiB
TypeScript
import { useNavigate } from 'react-router-dom'
|
|
import { MessageSquare, LayoutDashboard } from 'lucide-react'
|
|
import { cn } from '@/lib/utils'
|
|
import { useFeatureFlag } from '@/hooks/useFeatureFlag'
|
|
import { useUserPreferencesStore } from '@/store/userPreferencesStore'
|
|
|
|
type FlowPilotView = 'flowpilot' | 'cockpit'
|
|
|
|
const VIEW_OPTIONS: { key: FlowPilotView; label: string; icon: typeof MessageSquare }[] = [
|
|
{ key: 'flowpilot', label: 'FlowPilot', icon: MessageSquare },
|
|
{ key: 'cockpit', label: 'Cockpit', icon: LayoutDashboard },
|
|
]
|
|
|
|
interface ViewToggleProps {
|
|
/** Which view is currently active — drives highlight state */
|
|
currentView: FlowPilotView
|
|
/** Session ID for navigation (session pages only). Omit for preference-only mode (dashboard). */
|
|
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')
|
|
const setPreferredView = useUserPreferencesStore(s => s.setPreferredFlowPilotView)
|
|
|
|
if (!hasCockpit) return null
|
|
|
|
const handleSwitch = (view: FlowPilotView) => {
|
|
if (view === currentView) return
|
|
setPreferredView(view)
|
|
if (sessionId) {
|
|
const path = view === 'cockpit'
|
|
? `/cockpit/${sessionId}`
|
|
: `/assistant/${sessionId}`
|
|
navigate(path)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="flex items-center border-b border-border px-3 shrink-0" role="tablist">
|
|
{VIEW_OPTIONS.map(({ key, label, icon: Icon }) => (
|
|
<button
|
|
key={key}
|
|
role="tab"
|
|
aria-selected={currentView === key}
|
|
aria-current={currentView === key ? 'page' : undefined}
|
|
onClick={() => handleSwitch(key)}
|
|
className={cn(
|
|
'flex items-center gap-1.5 px-3 py-2 text-xs font-medium border-b-2 -mb-px',
|
|
'transition-[color,border-color] duration-150',
|
|
'active:opacity-80',
|
|
currentView === key
|
|
? 'text-foreground border-primary'
|
|
: 'text-muted-foreground hover:text-foreground border-transparent'
|
|
)}
|
|
>
|
|
<Icon size={14} />
|
|
{label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|