From 3790f68134cd244da2b30f3d8ee3fbfae17745a2 Mon Sep 17 00:00:00 2001 From: spencrmartin Date: Mon, 15 Dec 2025 10:43:48 -0500 Subject: [PATCH] Transform ticker into Matrix notification system - Extended TickerItem interface with priority, actionable, notification, and invitation types - Added Matrix-specific notification functions: - addSessionInvitation() - for session invites - addMessageNotification() - for new messages - addSessionJoined/Left() - for user activity - addConnectionStatus() - for Matrix connection state - addSessionWaiting() - for sessions awaiting participants - Updated default items to show Matrix notifications instead of system stats - Added demo notification system in AppLayout with realistic Matrix scenarios - Focused route notifications on Matrix-related sections only - Creates authentic collaborative workspace notification experience --- .../src/components/Layout/AppLayout.tsx | 67 +++++++-------- .../src/components/NotificationTicker.tsx | 86 +++++++++++++++++-- 2 files changed, 112 insertions(+), 41 deletions(-) diff --git a/ui/desktop/src/components/Layout/AppLayout.tsx b/ui/desktop/src/components/Layout/AppLayout.tsx index 81c47aec6d..1bbd3b7e54 100644 --- a/ui/desktop/src/components/Layout/AppLayout.tsx +++ b/ui/desktop/src/components/Layout/AppLayout.tsx @@ -328,9 +328,34 @@ const AppLayoutContent: React.FC = ({ setIsGoosehintsModalOpen } return () => window.removeEventListener('open-sidecar-localhost', handler); }, [sidecar]); - // Add ticker updates based on navigation changes and system events + // Add Matrix-related notifications and demo content + useEffect(() => { + // Simulate Matrix notifications for demo purposes + const demoNotifications = [ + () => ticker.addSessionInvitation('project-gamma', 'david'), + () => ticker.addMessageNotification('eve', 'design-team', 2), + () => ticker.addSessionJoined('frank', 'standup-meeting'), + () => ticker.addSessionWaiting('code-review-session', 3), + () => ticker.addConnectionStatus('connected'), + ]; + + // Add initial demo notification + setTimeout(() => { + const randomNotification = demoNotifications[Math.floor(Math.random() * demoNotifications.length)]; + randomNotification(); + }, 2000); + + // Add periodic demo notifications + const interval = setInterval(() => { + const randomNotification = demoNotifications[Math.floor(Math.random() * demoNotifications.length)]; + randomNotification(); + }, 15000); // Every 15 seconds + + return () => clearInterval(interval); + }, []); // Removed ticker from dependencies + + // Add route change notifications useEffect(() => { - // Update ticker when route changes const routeNames: Record = { '/': 'hub', '/pair': 'chat', @@ -344,41 +369,15 @@ const AppLayoutContent: React.FC = ({ setIsGoosehintsModalOpen } }; const currentRoute = routeNames[location.pathname] || 'unknown'; - ticker.addItem({ - text: `section: ${currentRoute}`, - type: 'info' - }); - }, [location.pathname]); // Removed ticker from dependencies - - // Add ticker updates for sidecar changes - useEffect(() => { - if (sidecar?.activeViews.length) { + + // Only add route notifications for Matrix-related sections + if (currentRoute === 'sessions' || currentRoute === 'peers' || currentRoute === 'channels') { ticker.addItem({ - text: `sidecars active: ${sidecar.activeViews.length}`, - type: 'success' + text: `navigated to ${currentRoute}`, + type: 'info' }); } - }, [sidecar?.activeViews.length]); // Removed ticker from dependencies - - // Add periodic system status updates - useEffect(() => { - const interval = setInterval(() => { - const memoryUsage = Math.floor(Math.random() * 30) + 40; // Mock memory usage 40-70% - const activeConnections = Math.floor(Math.random() * 5) + 1; // Mock 1-6 connections - - ticker.addItem({ - text: `mem: ${memoryUsage}%`, - type: memoryUsage > 60 ? 'warning' : 'info' - }); - - ticker.addItem({ - text: `connections: ${activeConnections}`, - type: 'neutral' - }); - }, 30000); // Update every 30 seconds - - return () => clearInterval(interval); - }, []); // Removed ticker from dependencies + }, [location.pathname]); // Removed ticker from dependencies // Determine layout direction based on navigation position (only for push mode) const isHorizontalNav = navigationPosition === 'top' || navigationPosition === 'bottom'; diff --git a/ui/desktop/src/components/NotificationTicker.tsx b/ui/desktop/src/components/NotificationTicker.tsx index f4825f33d6..298eb99fc2 100644 --- a/ui/desktop/src/components/NotificationTicker.tsx +++ b/ui/desktop/src/components/NotificationTicker.tsx @@ -4,8 +4,10 @@ import { cn } from '../utils'; interface TickerItem { id: string; text: string; - type?: 'info' | 'warning' | 'error' | 'success' | 'neutral'; + type?: 'info' | 'warning' | 'error' | 'success' | 'neutral' | 'notification' | 'invitation'; timestamp?: Date; + priority?: 'low' | 'medium' | 'high'; + actionable?: boolean; } interface NotificationTickerProps { @@ -16,12 +18,12 @@ interface NotificationTickerProps { } const defaultItems: TickerItem[] = [ - { id: '1', text: 'goose ai agent online', type: 'success' }, - { id: '2', text: 'system status: operational', type: 'info' }, - { id: '3', text: 'extensions loaded: 12', type: 'info' }, - { id: '4', text: 'last sync: 2 min ago', type: 'neutral' }, - { id: '5', text: 'memory usage: 45%', type: 'info' }, - { id: '6', text: 'active sessions: 3', type: 'success' }, + { id: '1', text: 'matrix: connected', type: 'success', priority: 'high' }, + { id: '2', text: 'session invitation from alice: project-alpha', type: 'invitation', priority: 'high', actionable: true }, + { id: '3', text: 'new message from bob in dev-team', type: 'notification', priority: 'medium', actionable: true }, + { id: '4', text: 'charlie joined project-beta', type: 'success', priority: 'low' }, + { id: '5', text: 'session waiting: code-review (2 participants)', type: 'invitation', priority: 'high', actionable: true }, + { id: '6', text: '3 new messages from team in general', type: 'notification', priority: 'medium', actionable: true }, ]; export const NotificationTicker: React.FC = ({ @@ -212,12 +214,82 @@ export const useNotificationTicker = () => { }); }, [addItem]); + // Matrix-specific notification functions + const addSessionInvitation = useCallback((sessionName: string, inviterName: string) => { + addItem({ + text: `session invitation from ${inviterName.toLowerCase()}: ${sessionName.toLowerCase()}`, + type: 'invitation', + priority: 'high', + actionable: true, + }); + }, [addItem]); + + const addMessageNotification = useCallback((senderName: string, sessionName: string, messageCount: number = 1) => { + const messageText = messageCount === 1 + ? `new message from ${senderName.toLowerCase()} in ${sessionName.toLowerCase()}` + : `${messageCount} new messages from ${senderName.toLowerCase()} in ${sessionName.toLowerCase()}`; + + addItem({ + text: messageText, + type: 'notification', + priority: 'medium', + actionable: true, + }); + }, [addItem]); + + const addSessionJoined = useCallback((userName: string, sessionName: string) => { + addItem({ + text: `${userName.toLowerCase()} joined ${sessionName.toLowerCase()}`, + type: 'success', + priority: 'low', + }); + }, [addItem]); + + const addSessionLeft = useCallback((userName: string, sessionName: string) => { + addItem({ + text: `${userName.toLowerCase()} left ${sessionName.toLowerCase()}`, + type: 'neutral', + priority: 'low', + }); + }, [addItem]); + + const addConnectionStatus = useCallback((status: 'connected' | 'disconnected' | 'reconnecting') => { + const statusMessages = { + connected: { text: 'matrix: connected', type: 'success' as const }, + disconnected: { text: 'matrix: disconnected', type: 'error' as const }, + reconnecting: { text: 'matrix: reconnecting...', type: 'warning' as const }, + }; + + const { text, type } = statusMessages[status]; + addItem({ + text, + type, + priority: 'high', + }); + }, [addItem]); + + const addSessionWaiting = useCallback((sessionName: string, participantCount: number) => { + addItem({ + text: `session waiting: ${sessionName.toLowerCase()} (${participantCount} participants)`, + type: 'invitation', + priority: 'high', + actionable: true, + }); + }, [addItem]); + return { items, addItem, removeItem, clearItems, updateSystemStatus, + // Matrix-specific functions + addSessionInvitation, + addMessageNotification, + addSessionJoined, + addSessionLeft, + addConnectionStatus, + addSessionWaiting, }; };