From 9d39e51f566825599b388fd04b8af323134cbd1f Mon Sep 17 00:00:00 2001 From: beeman Date: Thu, 5 Mar 2026 11:00:44 +0700 Subject: [PATCH] fix: prevent Live Feed sidebar from sliding in on page navigation (#181) Only apply the slide-in-right animation when the user actively re-expands the panel, not on initial mount. Also remove dead duplicate files src/live-feed.tsx and src/page.tsx. --- src/components/layout/live-feed.tsx | 5 +- src/live-feed.tsx | 161 --------------------------- src/page.tsx | 166 ---------------------------- 3 files changed, 3 insertions(+), 329 deletions(-) delete mode 100644 src/live-feed.tsx delete mode 100644 src/page.tsx diff --git a/src/components/layout/live-feed.tsx b/src/components/layout/live-feed.tsx index dae3c77..f64420b 100644 --- a/src/components/layout/live-feed.tsx +++ b/src/components/layout/live-feed.tsx @@ -7,6 +7,7 @@ export function LiveFeed() { const { logs, sessions, activities, connection, dashboardMode, toggleLiveFeed } = useMissionControl() const isLocal = dashboardMode === 'local' const [expanded, setExpanded] = useState(true) + const [hasCollapsed, setHasCollapsed] = useState(false) // Combine logs, activities, and (in local mode) session events into a unified feed const sessionItems = isLocal @@ -70,7 +71,7 @@ export function LiveFeed() { } return ( -
+
{/* Header */}
@@ -80,7 +81,7 @@ export function LiveFeed() {
- {/* Mini indicators */} -
- {feedItems.slice(0, 5).map((item) => ( -
- ))} -
-
- ) - } - - return ( -
- {/* Header */} -
-
-
- Live Feed - {feedItems.length} -
-
- - -
-
- - {/* Feed items */} -
- {feedItems.length === 0 ? ( -
- No activity yet -
- ) : ( -
- {feedItems.map((item) => ( - - ))} -
- )} -
- - {/* Active sessions mini-list */} -
-
Active Sessions
-
- {sessions.filter(s => s.active).slice(0, 4).map(session => ( -
-
- {session.key || session.id} - {session.model?.split('/').pop()?.slice(0, 8)} -
- ))} - {sessions.filter(s => s.active).length === 0 && ( -
No active sessions
- )} -
-
-
- ) -} - -function FeedItem({ item }: { item: { id: string; type: string; level: string; message: string; source: string; timestamp: number } }) { - const levelIndicator = item.level === 'error' - ? 'bg-red-500' - : item.level === 'warn' - ? 'bg-amber-500' - : item.level === 'debug' - ? 'bg-gray-500' - : 'bg-blue-500/50' - - const timeStr = formatRelativeTime(item.timestamp) - - return ( -
-
-
-
-

- {item.message.length > 120 ? item.message.slice(0, 120) + '...' : item.message} -

-
- {item.source} - ยท - {timeStr} -
-
-
-
- ) -} - -function formatRelativeTime(ts: number): string { - const diff = Date.now() - ts - if (diff < 60_000) return 'now' - if (diff < 3_600_000) return `${Math.floor(diff / 60_000)}m` - if (diff < 86_400_000) return `${Math.floor(diff / 3_600_000)}h` - return `${Math.floor(diff / 86_400_000)}d` -} diff --git a/src/page.tsx b/src/page.tsx deleted file mode 100644 index 872d32c..0000000 --- a/src/page.tsx +++ /dev/null @@ -1,166 +0,0 @@ -'use client' - -import { useEffect, useState } from 'react' -import { NavRail } from '@/components/layout/nav-rail' -import { HeaderBar } from '@/components/layout/header-bar' -import { LiveFeed } from '@/components/layout/live-feed' -import { Dashboard } from '@/components/dashboard/dashboard' -import { AgentSpawnPanel } from '@/components/panels/agent-spawn-panel' -import { LogViewerPanel } from '@/components/panels/log-viewer-panel' -import { CronManagementPanel } from '@/components/panels/cron-management-panel' -import { MemoryBrowserPanel } from '@/components/panels/memory-browser-panel' -import { TokenDashboardPanel } from '@/components/panels/token-dashboard-panel' -import { SessionDetailsPanel } from '@/components/panels/session-details-panel' -import { TaskBoardPanel } from '@/components/panels/task-board-panel' -import { ActivityFeedPanel } from '@/components/panels/activity-feed-panel' -import { AgentSquadPanelPhase3 } from '@/components/panels/agent-squad-panel-phase3' -import { StandupPanel } from '@/components/panels/standup-panel' -import { OrchestrationBar } from '@/components/panels/orchestration-bar' -import { NotificationsPanel } from '@/components/panels/notifications-panel' -import { UserManagementPanel } from '@/components/panels/user-management-panel' -import { AuditTrailPanel } from '@/components/panels/audit-trail-panel' -import { AgentHistoryPanel } from '@/components/panels/agent-history-panel' -import { WebhookPanel } from '@/components/panels/webhook-panel' -import { SettingsPanel } from '@/components/panels/settings-panel' -import { GatewayConfigPanel } from '@/components/panels/gateway-config-panel' -import { IntegrationsPanel } from '@/components/panels/integrations-panel' -import { AlertRulesPanel } from '@/components/panels/alert-rules-panel' -import { MultiGatewayPanel } from '@/components/panels/multi-gateway-panel' -import { ChatPanel } from '@/components/chat/chat-panel' -import { useWebSocket } from '@/lib/websocket' -import { useServerEvents } from '@/lib/use-server-events' -import { useMissionControl } from '@/store' - -export default function Home() { - const { connect } = useWebSocket() - const { activeTab, setCurrentUser, liveFeedOpen, toggleLiveFeed } = useMissionControl() - - // Connect to SSE for real-time local DB events (tasks, agents, chat, etc.) - useServerEvents() - const [isClient, setIsClient] = useState(false) - - useEffect(() => { - setIsClient(true) - - // Fetch current user - fetch('/api/auth/me') - .then(res => res.ok ? res.json() : null) - .then(data => { if (data?.user) setCurrentUser(data.user) }) - .catch(() => {}) - - // Auto-connect to gateway on mount - const wsToken = process.env.NEXT_PUBLIC_GATEWAY_TOKEN || process.env.NEXT_PUBLIC_WS_TOKEN || '' - const gatewayPort = process.env.NEXT_PUBLIC_GATEWAY_PORT || '18789' - const gatewayHost = window.location.hostname - const wsUrl = `ws://${gatewayHost}:${gatewayPort}` - connect(wsUrl, wsToken) - }, [connect, setCurrentUser]) - - if (!isClient) { - return ( -
-
-
- MC -
-
-
- Loading Mission Control... -
-
-
- ) - } - - return ( -
- {/* Left: Icon rail navigation (hidden on mobile, shown as bottom bar instead) */} - - - {/* Center: Header + Content */} -
- -
- -
-
- - {/* Right: Live feed (hidden on mobile) */} - {liveFeedOpen && ( -
- -
- )} - - {/* Floating button to reopen LiveFeed when closed */} - {!liveFeedOpen && ( - - )} - - {/* Chat panel overlay */} - -
- ) -} - -function ContentRouter({ tab }: { tab: string }) { - switch (tab) { - case 'overview': - return - case 'tasks': - return - case 'agents': - return ( - <> - - - - ) - case 'activity': - return - case 'notifications': - return - case 'standup': - return - case 'spawn': - return - case 'sessions': - return - case 'logs': - return - case 'cron': - return - case 'memory': - return - case 'tokens': - return - case 'users': - return - case 'history': - return - case 'audit': - return - case 'webhooks': - return - case 'alerts': - return - case 'gateways': - return - case 'gateway-config': - return - case 'integrations': - return - case 'settings': - return - default: - return - } -}