Spaces:
Running
Running
| import React, { useEffect, useCallback } from "react"; | |
| import { useAgentGraph } from "@/context/AgentGraphContext"; | |
| import { useNavigation } from "@/context/NavigationContext"; | |
| import { Breadcrumb } from "./Breadcrumb"; | |
| import { DashboardView } from "../features/workspace/DashboardView"; | |
| import { TraceKnowledgeGraphView } from "../features/traces/TraceKnowledgeGraphView"; | |
| import { TracesView } from "../features/traces/TracesView"; | |
| import { KnowledgeGraphVisualizer } from "../features/traces/KnowledgeGraphVisualizer"; | |
| import { AdvancedProcessingView } from "../features/processing/AdvancedProcessingView"; | |
| import { TraceEditor } from "../features/traces/TraceEditor"; | |
| import { TemporalGraphVisualizer } from "../features/traces/TemporalGraphVisualizer"; | |
| import { GraphComparisonView } from "../features/comparison/GraphComparisonView"; | |
| import { FloatingActionWidget } from "../shared/FloatingActionWidget"; | |
| import ExampleTraceBrowserView from "@/components/features/traces/ExampleTraceBrowserView"; | |
| import { ConnectionsView } from "../features/connections/ConnectionsView"; | |
| import { UploadView } from "../features/upload/UploadView"; | |
| import { Button } from "@/components/ui/button"; | |
| import { ArrowLeft } from "lucide-react"; | |
| interface MainWorkspaceProps { | |
| isSidebarCollapsed: boolean; | |
| onToggleSidebar?: () => void; | |
| } | |
| export function MainWorkspace({ | |
| isSidebarCollapsed: _isSidebarCollapsed, | |
| onToggleSidebar: _onToggleSidebar, | |
| }: MainWorkspaceProps) { | |
| const { state, actions } = useAgentGraph(); | |
| const navigation = useNavigation(); | |
| const { activeView } = state; | |
| // FloatingActionWidget now handles its own contextual actions | |
| // Function to handle back navigation using breadcrumbs | |
| const handleBackNavigation = useCallback(() => { | |
| const breadcrumbs = navigation.state.breadcrumbs; | |
| if (breadcrumbs.length > 1) { | |
| // Navigate to the second-to-last breadcrumb item | |
| const previousBreadcrumb = breadcrumbs[breadcrumbs.length - 2]; | |
| if (previousBreadcrumb?.path) { | |
| switch (previousBreadcrumb.path) { | |
| case "welcome": | |
| actions.setActiveView("welcome"); | |
| break; | |
| case "traces": | |
| actions.setActiveView("traces"); | |
| break; | |
| case "trace-kg": | |
| actions.setActiveView("trace-kg"); | |
| break; | |
| case "kg-visualizer": | |
| actions.setActiveView("kg-visualizer"); | |
| break; | |
| case "advanced-processing": | |
| actions.setActiveView("advanced-processing"); | |
| break; | |
| case "trace-editor": | |
| actions.setActiveView("trace-editor"); | |
| break; | |
| case "temporal-visualizer": | |
| actions.setActiveView("temporal-visualizer"); | |
| break; | |
| case "connections": | |
| actions.setActiveView("connections"); | |
| break; | |
| case "upload": | |
| actions.setActiveView("upload"); | |
| break; | |
| case "graph-comparison": | |
| actions.setActiveView("graph-comparison"); | |
| break; | |
| case "example-traces": | |
| actions.setActiveView("example-traces"); | |
| break; | |
| default: | |
| actions.setActiveView("welcome"); | |
| } | |
| } else { | |
| actions.setActiveView("welcome"); | |
| } | |
| } else { | |
| // If no previous breadcrumb, go to dashboard | |
| actions.setActiveView("welcome"); | |
| } | |
| }, [navigation.state.breadcrumbs, actions]); | |
| // Generate breadcrumbs based on current state | |
| const generateBreadcrumbs = useCallback(() => { | |
| const breadcrumbs: Array<{ label: string; path: string; active: boolean }> = | |
| []; | |
| // Always show Dashboard breadcrumb | |
| if (activeView === "welcome") { | |
| breadcrumbs.push({ | |
| label: "Dashboard", | |
| path: "welcome", | |
| active: true, | |
| }); | |
| } else { | |
| breadcrumbs.push({ | |
| label: "Dashboard", | |
| path: "welcome", | |
| active: false, | |
| }); | |
| } | |
| if (activeView === "traces") { | |
| breadcrumbs.push({ | |
| label: "My Traces", | |
| path: "traces", | |
| active: true, | |
| }); | |
| } | |
| if (activeView === "trace-kg" && state.selectedTrace) { | |
| breadcrumbs.push({ | |
| label: "My Traces", | |
| path: "traces", | |
| active: false, | |
| }); | |
| breadcrumbs.push({ | |
| label: state.selectedTrace.filename, | |
| path: "trace-kg", | |
| active: true, | |
| }); | |
| } | |
| if ( | |
| activeView === "kg-visualizer" && | |
| state.selectedTrace && | |
| state.selectedKnowledgeGraph | |
| ) { | |
| breadcrumbs.push({ | |
| label: "My Traces", | |
| path: "traces", | |
| active: false, | |
| }); | |
| breadcrumbs.push({ | |
| label: state.selectedTrace.filename, | |
| path: "trace-kg", | |
| active: false, | |
| }); | |
| breadcrumbs.push({ | |
| label: "Agent Graph Visualization", | |
| path: "kg-visualizer", | |
| active: true, | |
| }); | |
| } | |
| if ( | |
| activeView === "advanced-processing" && | |
| state.selectedTrace && | |
| state.selectedKnowledgeGraph | |
| ) { | |
| breadcrumbs.push({ | |
| label: "My Traces", | |
| path: "traces", | |
| active: false, | |
| }); | |
| breadcrumbs.push({ | |
| label: state.selectedTrace.filename, | |
| path: "trace-kg", | |
| active: false, | |
| }); | |
| breadcrumbs.push({ | |
| label: "Agent Graph Visualization", | |
| path: "kg-visualizer", | |
| active: false, | |
| }); | |
| breadcrumbs.push({ | |
| label: "Advanced Processing", | |
| path: "advanced-processing", | |
| active: true, | |
| }); | |
| } | |
| if (activeView === "trace-editor" && state.selectedTrace) { | |
| breadcrumbs.push({ | |
| label: "My Traces", | |
| path: "traces", | |
| active: false, | |
| }); | |
| breadcrumbs.push({ | |
| label: state.selectedTrace.filename, | |
| path: "trace-kg", | |
| active: false, | |
| }); | |
| breadcrumbs.push({ | |
| label: "Edit Trace", | |
| path: "trace-editor", | |
| active: true, | |
| }); | |
| } | |
| if (activeView === "temporal-visualizer" && state.selectedTemporalData) { | |
| breadcrumbs.push({ | |
| label: "My Traces", | |
| path: "traces", | |
| active: false, | |
| }); | |
| breadcrumbs.push({ | |
| label: state.selectedTemporalData.trace_title, | |
| path: "trace-kg", | |
| active: false, | |
| }); | |
| breadcrumbs.push({ | |
| label: "Temporal Visualization", | |
| path: "temporal-visualizer", | |
| active: true, | |
| }); | |
| } | |
| if (activeView === "graph-comparison") { | |
| breadcrumbs.push({ | |
| label: "Graph Comparison", | |
| path: "graph-comparison", | |
| active: true, | |
| }); | |
| } | |
| if (activeView === "example-traces") { | |
| breadcrumbs.push({ | |
| label: "Gallery", | |
| path: "example-traces", | |
| active: true, | |
| }); | |
| } | |
| if (activeView === "connections") { | |
| breadcrumbs.push({ | |
| label: "Connections", | |
| path: "connections", | |
| active: true, | |
| }); | |
| } | |
| if (activeView === "upload") { | |
| breadcrumbs.push({ | |
| label: "Upload Trace", | |
| path: "upload", | |
| active: true, | |
| }); | |
| } | |
| return breadcrumbs; | |
| }, [ | |
| activeView, | |
| state.selectedTrace, | |
| state.selectedKnowledgeGraph, | |
| state.selectedTemporalData, | |
| ]); | |
| // Update navigation context when state changes | |
| useEffect(() => { | |
| const breadcrumbs = generateBreadcrumbs(); | |
| navigation.actions.setBreadcrumbs(breadcrumbs); | |
| }, [generateBreadcrumbs, navigation.actions]); | |
| const renderView = () => { | |
| switch (activeView) { | |
| case "welcome": | |
| return <DashboardView />; | |
| case "traces": | |
| return <TracesView />; | |
| case "trace-kg": | |
| return state.selectedTrace ? ( | |
| <TraceKnowledgeGraphView | |
| trace={state.selectedTrace} | |
| knowledgeGraphs={state.knowledgeGraphs.filter( | |
| (kg) => kg.filename === state.selectedTrace?.filename | |
| )} | |
| /> | |
| ) : ( | |
| <DashboardView /> | |
| ); | |
| case "kg-visualizer": | |
| return state.selectedKnowledgeGraph ? ( | |
| <KnowledgeGraphVisualizer | |
| knowledgeGraph={state.selectedKnowledgeGraph} | |
| /> | |
| ) : ( | |
| <DashboardView /> | |
| ); | |
| case "advanced-processing": | |
| return state.selectedKnowledgeGraph ? ( | |
| <AdvancedProcessingView | |
| knowledgeGraph={state.selectedKnowledgeGraph} | |
| onBack={() => actions.setActiveView("trace-kg")} | |
| /> | |
| ) : ( | |
| <DashboardView /> | |
| ); | |
| case "trace-editor": | |
| return state.selectedTrace ? ( | |
| <TraceEditor | |
| trace={state.selectedTrace} | |
| onBack={() => actions.setActiveView("trace-kg")} | |
| /> | |
| ) : ( | |
| <DashboardView /> | |
| ); | |
| case "temporal-visualizer": | |
| return state.selectedTemporalData ? ( | |
| <TemporalGraphVisualizer | |
| temporalData={state.selectedTemporalData} | |
| onBack={() => actions.setActiveView("trace-kg")} | |
| /> | |
| ) : ( | |
| <DashboardView /> | |
| ); | |
| case "graph-comparison": | |
| return <GraphComparisonView />; | |
| case "example-traces": | |
| return <ExampleTraceBrowserView />; | |
| case "connections": | |
| return <ConnectionsView />; | |
| case "upload": | |
| return <UploadView />; | |
| default: | |
| return <DashboardView />; | |
| } | |
| }; | |
| // Special layout for temporal visualizer - full screen with sidebar | |
| if (activeView === "temporal-visualizer") { | |
| return ( | |
| <div className="fixed inset-0 bg-background z-50 flex flex-col"> | |
| {/* Global Floating Action Widget for temporal view */} | |
| <FloatingActionWidget /> | |
| {/* Breadcrumb Navigation */} | |
| <div className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60"> | |
| <div className="flex items-center justify-between px-6 py-3"> | |
| <div className="flex items-center gap-3"> | |
| {navigation.state.breadcrumbs.length > 1 && ( | |
| <Button | |
| variant="ghost" | |
| size="sm" | |
| onClick={handleBackNavigation} | |
| className="h-8 w-8 p-0 hover:bg-muted/50 rounded-md" | |
| title="Go back" | |
| > | |
| <ArrowLeft className="h-4 w-4" /> | |
| </Button> | |
| )} | |
| <Breadcrumb /> | |
| </div> | |
| </div> | |
| </div> | |
| {/* Main content with sidebar */} | |
| <div className="flex w-full flex-1 min-h-0"> | |
| <div className="flex-1 overflow-hidden">{renderView()}</div> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <div className="flex-1 flex flex-col min-h-0"> | |
| {/* Global Floating Action Widget */} | |
| <FloatingActionWidget /> | |
| {/* Breadcrumb Navigation - Only show when needed */} | |
| {navigation.state.breadcrumbs.length > 0 ? ( | |
| <div className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 flex-shrink-0"> | |
| <div className="flex items-center justify-between px-6 py-2"> | |
| <div className="flex items-center gap-3"> | |
| {navigation.state.breadcrumbs.length > 1 && ( | |
| <Button | |
| variant="ghost" | |
| size="sm" | |
| onClick={handleBackNavigation} | |
| className="h-8 w-8 p-0 hover:bg-muted/50 rounded-md" | |
| title="Go back" | |
| > | |
| <ArrowLeft className="h-4 w-4" /> | |
| </Button> | |
| )} | |
| <Breadcrumb /> | |
| </div> | |
| </div> | |
| </div> | |
| ) : ( | |
| <div className="border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 flex-shrink-0"> | |
| <div className="flex items-center px-6 py-2"> | |
| {/* Empty div to maintain layout when no breadcrumbs */} | |
| </div> | |
| </div> | |
| )} | |
| {/* Main Content */} | |
| <div className="flex-1 flex flex-col min-h-0">{renderView()}</div> | |
| </div> | |
| ); | |
| } | |