#!/usr/bin/env python3 import os # Read the existing file with open('frontend/admin/components/AiLogsTile.vue', 'r') as f: content = f.read() # Find where the file is truncated if 'case \'success\': return \'green' in content and not 'case \'warning\': return \'orange\'' in content: # The file is truncated at the getLogColor function # Let's find the exact position and complete it lines = content.split('\n') # Find the line with getLogColor for i, line in enumerate(lines): if 'const getLogColor = (type: AiLogEntry[\'type\']) => {' in line: start_idx = i # Find where this function ends (look for the next function or end of file) for j in range(i+1, len(lines)): if lines[j].strip().startswith('const ') or lines[j].strip().startswith('//'): # Found next function or comment end_idx = j break else: end_idx = len(lines) # Replace the incomplete function with complete version new_function = '''const getLogColor = (type: AiLogEntry['type']) => { switch (type) { case 'info': return 'blue' case 'success': return 'green' case 'warning': return 'orange' case 'error': return 'red' case 'gold': return 'amber' default: return 'grey' } } const getLogIcon = (type: AiLogEntry['type']) => { switch (type) { case 'info': return 'mdi-information' case 'success': return 'mdi-check-circle' case 'warning': return 'mdi-alert' case 'error': return 'mdi-alert-circle' case 'gold': return 'mdi-star' default: return 'mdi-help-circle' } } const getRobotColor = (robotName: string) => { const robot = robots.value.find(r => r.name === robotName) return robot?.statusColor || 'grey' } const getStatusColor = (status: string) => { switch (status.toLowerCase()) { case 'running': return 'success' case 'idle': return 'warning' case 'error': return 'error' case 'paused': return 'grey' default: return 'grey' } } const formatTime = (timestamp: Date) => { const now = new Date() const diff = now.getTime() - timestamp.getTime() if (diff < 60000) return 'Just now' if (diff < 3600000) return `${Math.floor(diff / 60000)}m ago` if (diff < 86400000) return `${Math.floor(diff / 3600000)}h ago` return timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) } // Data fetching and polling const fetchLogs = async () => { if (isRefreshing.value) return isRefreshing.value = true try { // Simulate API call await new Promise(resolve => setTimeout(resolve, 500)) // Add new mock log const newLog = generateMockLog() logs.value.push(newLog) // Keep only last 50 logs if (logs.value.length > 50) { logs.value = logs.value.slice(-50) } // Mark old logs as not new setTimeout(() => { logs.value.forEach(log => { if (log.isNew && Date.now() - log.timestamp.getTime() > 5000) { log.isNew = false } }) }, 5000) // Update connection status randomly if (Math.random() > 0.95) { connectionStatus.value = 'disconnected' } else if (Math.random() > 0.98) { connectionStatus.value = 'error' } else { connectionStatus.value = 'connected' } } catch (error) { console.error('Failed to fetch AI logs:', error) connectionStatus.value = 'error' } finally { isRefreshing.value = false isLoading.value = false } } const forceRefresh = () => { fetchLogs() } const toggleAutoScroll = () => { autoScroll.value = !autoScroll.value } const clearLogs = () => { logs.value = [] } const scrollToBottom = () => { if (logContainer.value && autoScroll.value) { nextTick(() => { logContainer.value!.scrollTop = logContainer.value!.scrollHeight }) } } // Polling management let pollInterval: number | null = null const startPolling = () => { if (pollInterval) clearInterval(pollInterval) pollInterval = setInterval(() => { fetchLogs() scrollToBottom() }, pollingInterval.value) as unknown as number } const stopPolling = () => { if (pollInterval) { clearInterval(pollInterval) pollInterval = null } } // Lifecycle hooks onMounted(() => { // Initial load fetchLogs() // Start polling startPolling() // Generate initial logs for (let i = 0; i < 10; i++) { const log = generateMockLog() log.timestamp = new Date(Date.now() - (10 - i) * 60000) // Staggered times log.isNew = false logs.value.push(log) } isLoading.value = false }) onUnmounted(() => { stopPolling() })''' # Replace the lines new_lines = lines[:start_idx] + new_function.split('\n') content = '\n'.join(new_lines) break # Write the complete file with open('frontend/admin/components/AiLogsTile.vue', 'w') as f: f.write(content) print("File completed successfully")