feat: restructure sidebar with stats bar, activity feed, and grouped nav
Dashboard-first layout with Resolve/Build/Insights groups. AI split: FlowPilot (Resolve) + Flow Assist (Build). Stats bar: Resolved/Active/In Session daily counters. Activity feed: active sessions with CW ticket #, recent completions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,17 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { LayoutGrid, Network, Wrench, Clock, FileOutput, BarChart3, Settings, PanelLeftClose, PanelLeftOpen, MessageSquareText, BotMessageSquare, BookOpen, Lightbulb, Code2, Library } from 'lucide-react'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import {
|
||||
LayoutGrid, Network, Wrench, Clock, FileOutput, BarChart3,
|
||||
Settings, PanelLeftClose, PanelLeftOpen, MessageSquareText,
|
||||
BookOpen, Lightbulb, Code2, Library, Brain, WandSparkles,
|
||||
} from 'lucide-react'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useUserPreferencesStore } from '@/store/userPreferencesStore'
|
||||
import { usePinnedFlowsStore } from '@/store/pinnedFlowsStore'
|
||||
import { PinnedFlowsSection } from '@/components/sidebar/PinnedFlowsSection'
|
||||
import { sidebarApi } from '@/api'
|
||||
import type { SidebarStatsResponse } from '@/api/sidebar'
|
||||
import { SidebarStatsBar } from '@/components/sidebar/SidebarStatsBar'
|
||||
import { SidebarActivityFeed } from '@/components/sidebar/SidebarActivityFeed'
|
||||
import { NavItem } from './NavItem'
|
||||
import { sessionsApi, treesApi } from '@/api'
|
||||
|
||||
// Semantic icon colors — each nav item gets a unique color for visual landmarks
|
||||
const NAV_COLORS = {
|
||||
@@ -14,7 +20,8 @@ const NAV_COLORS = {
|
||||
editor: '#f59e0b', // amber-500
|
||||
sessions: '#34d399', // emerald-400
|
||||
exports: '#60a5fa', // blue-400
|
||||
ai: '#e879f9', // fuchsia-400
|
||||
flowPilot: '#e879f9', // fuchsia-400
|
||||
flowAssist:'#f472b6', // pink-400
|
||||
stepLib: '#fb923c', // orange-400
|
||||
scripts: '#2dd4bf', // teal-400
|
||||
kb: '#fb7185', // rose-400
|
||||
@@ -26,40 +33,14 @@ const NAV_COLORS = {
|
||||
export function Sidebar() {
|
||||
const sidebarCollapsed = useUserPreferencesStore(s => s.sidebarCollapsed)
|
||||
const toggleSidebar = useUserPreferencesStore(s => s.toggleSidebar)
|
||||
const location = useLocation()
|
||||
|
||||
const pinnedItems = usePinnedFlowsStore((s) => s.items)
|
||||
const loadPinned = usePinnedFlowsStore((s) => s.load)
|
||||
const unpinFlow = usePinnedFlowsStore((s) => s.unpin)
|
||||
const [stats, setStats] = useState<SidebarStatsResponse | null>(null)
|
||||
|
||||
const [activeSessionCount, setActiveSessionCount] = useState(0)
|
||||
const [treeCounts, setTreeCounts] = useState({ total: 0, troubleshooting: 0, procedural: 0, maintenance: 0 })
|
||||
|
||||
// Load pinned flows on mount
|
||||
// Fetch sidebar stats — refreshes on navigation
|
||||
useEffect(() => {
|
||||
loadPinned()
|
||||
}, [loadPinned])
|
||||
|
||||
// Fetch sidebar data on mount
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const [activeSessions, allTrees] = await Promise.all([
|
||||
sessionsApi.list({ completed: false, size: 50 }).catch(() => []),
|
||||
treesApi.list({ sort_by: 'name' }).catch(() => []),
|
||||
])
|
||||
setActiveSessionCount(activeSessions.length)
|
||||
|
||||
const total = allTrees.length
|
||||
const troubleshooting = allTrees.filter(t => t.tree_type === 'troubleshooting').length
|
||||
const procedural = allTrees.filter(t => t.tree_type === 'procedural').length
|
||||
const maintenance = allTrees.filter(t => t.tree_type === 'maintenance').length
|
||||
setTreeCounts({ total, troubleshooting, procedural, maintenance })
|
||||
} catch {
|
||||
// Silently handle errors
|
||||
}
|
||||
}
|
||||
fetchData()
|
||||
}, [])
|
||||
sidebarApi.getStats().then(setStats).catch(() => {})
|
||||
}, [location.pathname])
|
||||
|
||||
const handleSidebarWheel = (e: React.WheelEvent<HTMLElement>) => {
|
||||
const sidebar = e.currentTarget
|
||||
@@ -93,14 +74,15 @@ export function Sidebar() {
|
||||
{/* Collapsed: icon-only nav */}
|
||||
<div className="flex flex-col items-center px-1.5 py-3 space-y-1">
|
||||
<NavItem href="/" icon={LayoutGrid} label="Dashboard" iconColor={NAV_COLORS.dashboard} collapsed />
|
||||
<NavItem href="/sessions" icon={Clock} label="Sessions" badge={stats?.active_count || undefined} iconColor={NAV_COLORS.sessions} collapsed />
|
||||
<NavItem href="/trees" icon={Network} label="All Flows" matchPaths={['/trees', '/flows']} iconColor={NAV_COLORS.flows} collapsed />
|
||||
<NavItem href="/my-trees" icon={Wrench} label="Flow Editor" iconColor={NAV_COLORS.editor} collapsed />
|
||||
<NavItem href="/sessions" icon={Clock} label="Sessions" badge={activeSessionCount || undefined} iconColor={NAV_COLORS.sessions} collapsed />
|
||||
<NavItem href="/shares" icon={FileOutput} label="Exports" iconColor={NAV_COLORS.exports} collapsed />
|
||||
<NavItem href="/assistant" icon={BotMessageSquare} label="AI Assistant" iconColor={NAV_COLORS.ai} collapsed />
|
||||
<NavItem href="/step-library" icon={Library} label="Step Library" iconColor={NAV_COLORS.stepLib} collapsed />
|
||||
<NavItem href="/assistant" icon={Brain} label="FlowPilot" iconColor={NAV_COLORS.flowPilot} collapsed />
|
||||
<NavItem href="/scripts" icon={Code2} label="Script Library" iconColor={NAV_COLORS.scripts} collapsed />
|
||||
<NavItem href="/my-trees" icon={Wrench} label="Flow Editor" iconColor={NAV_COLORS.editor} collapsed />
|
||||
<NavItem href="/flow-assist" icon={WandSparkles} label="Flow Assist" iconColor={NAV_COLORS.flowAssist} collapsed />
|
||||
<NavItem href="/step-library" icon={Library} label="Step Library" iconColor={NAV_COLORS.stepLib} collapsed />
|
||||
<NavItem href="/kb-accelerator" icon={Lightbulb} label="KB Accelerator" iconColor={NAV_COLORS.kb} collapsed />
|
||||
<NavItem href="/shares" icon={FileOutput} label="Exports" iconColor={NAV_COLORS.exports} collapsed />
|
||||
<NavItem href="/analytics" icon={BarChart3} label="Analytics" iconColor={NAV_COLORS.analytics} collapsed />
|
||||
<NavItem href="/guides" icon={BookOpen} label="User Guides" iconColor={NAV_COLORS.guides} collapsed />
|
||||
<NavItem href="/feedback" icon={MessageSquareText} label="Feedback" iconColor={NAV_COLORS.feedback} collapsed />
|
||||
@@ -108,34 +90,62 @@ export function Sidebar() {
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{/* Pinned Flows */}
|
||||
<PinnedFlowsSection flows={pinnedItems} onUnpin={unpinFlow} />
|
||||
{/* Stats Bar */}
|
||||
<SidebarStatsBar
|
||||
resolved={stats?.resolved_today ?? 0}
|
||||
active={stats?.active_count ?? 0}
|
||||
sessionMinutes={stats?.total_session_minutes_today ?? 0}
|
||||
/>
|
||||
|
||||
{/* Activity Feed */}
|
||||
<SidebarActivityFeed
|
||||
activeSessions={stats?.active_sessions ?? []}
|
||||
recentCompletions={stats?.recent_completions ?? []}
|
||||
totalActive={stats?.active_count ?? 0}
|
||||
/>
|
||||
|
||||
<div style={{ borderBottom: '1px solid var(--glass-border)' }} />
|
||||
|
||||
{/* Primary Navigation */}
|
||||
{/* Navigation */}
|
||||
<div className="px-3 py-2 space-y-0.5">
|
||||
{/* Dashboard (standalone) */}
|
||||
<NavItem href="/" icon={LayoutGrid} label="Dashboard" iconColor={NAV_COLORS.dashboard} />
|
||||
|
||||
{/* Resolve */}
|
||||
<div className="font-label text-[0.5625rem] uppercase tracking-[0.12em] text-[#5a6170] px-3 pt-3 pb-1">
|
||||
Resolve
|
||||
</div>
|
||||
<NavItem href="/sessions" icon={Clock} label="Sessions" badge={stats?.active_count || undefined} iconColor={NAV_COLORS.sessions} />
|
||||
<NavItem
|
||||
href="/trees"
|
||||
icon={Network}
|
||||
label="All Flows"
|
||||
badge={treeCounts.total || undefined}
|
||||
badge={stats?.tree_counts.total || undefined}
|
||||
iconColor={NAV_COLORS.flows}
|
||||
matchPaths={['/trees', '/flows']}
|
||||
children={[
|
||||
{ href: '/trees?type=troubleshooting', label: 'Troubleshooting', count: treeCounts.troubleshooting || undefined },
|
||||
{ href: '/trees?type=procedural', label: 'Projects', count: treeCounts.procedural || undefined },
|
||||
{ href: '/trees?type=maintenance', label: 'Maintenance', count: treeCounts.maintenance || undefined },
|
||||
{ href: '/trees?type=troubleshooting', label: 'Troubleshooting', count: stats?.tree_counts.troubleshooting || undefined },
|
||||
{ href: '/trees?type=procedural', label: 'Projects', count: stats?.tree_counts.procedural || undefined },
|
||||
{ href: '/trees?type=maintenance', label: 'Maintenance', count: stats?.tree_counts.maintenance || undefined },
|
||||
]}
|
||||
/>
|
||||
<NavItem href="/my-trees" icon={Wrench} label="Flow Editor" iconColor={NAV_COLORS.editor} />
|
||||
<NavItem href="/sessions" icon={Clock} label="Sessions" badge={activeSessionCount || undefined} iconColor={NAV_COLORS.sessions} />
|
||||
<NavItem href="/shares" icon={FileOutput} label="Exports" iconColor={NAV_COLORS.exports} />
|
||||
<NavItem href="/assistant" icon={BotMessageSquare} label="AI Assistant" iconColor={NAV_COLORS.ai} />
|
||||
<NavItem href="/step-library" icon={Library} label="Step Library" iconColor={NAV_COLORS.stepLib} />
|
||||
<NavItem href="/assistant" icon={Brain} label="FlowPilot" iconColor={NAV_COLORS.flowPilot} />
|
||||
<NavItem href="/scripts" icon={Code2} label="Script Library" iconColor={NAV_COLORS.scripts} />
|
||||
|
||||
{/* Build */}
|
||||
<div className="font-label text-[0.5625rem] uppercase tracking-[0.12em] text-[#5a6170] px-3 pt-3 pb-1">
|
||||
Build
|
||||
</div>
|
||||
<NavItem href="/my-trees" icon={Wrench} label="Flow Editor" iconColor={NAV_COLORS.editor} />
|
||||
<NavItem href="/flow-assist" icon={WandSparkles} label="Flow Assist" iconColor={NAV_COLORS.flowAssist} />
|
||||
<NavItem href="/step-library" icon={Library} label="Step Library" iconColor={NAV_COLORS.stepLib} />
|
||||
<NavItem href="/kb-accelerator" icon={Lightbulb} label="KB Accelerator" iconColor={NAV_COLORS.kb} />
|
||||
|
||||
{/* Insights */}
|
||||
<div className="font-label text-[0.5625rem] uppercase tracking-[0.12em] text-[#5a6170] px-3 pt-3 pb-1">
|
||||
Insights
|
||||
</div>
|
||||
<NavItem href="/shares" icon={FileOutput} label="Exports" iconColor={NAV_COLORS.exports} />
|
||||
<NavItem href="/analytics" icon={BarChart3} label="Analytics" iconColor={NAV_COLORS.analytics} />
|
||||
</div>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user