Files
resolutionflow/frontend/src/components/assistant/ViewToggle.tsx
chihlasm 165e402284 fix: deduplicate actions, promote ViewToggle tab bar, standardize naming
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>
2026-04-04 04:40:06 +00:00

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>
)
}