← back to YOLO Progress Viewer

detailed-viewer.html

607 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>🔍 Detailed Scraper Monitor | Real-Time Loading</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Cascadia Code', 'Fira Code', monospace;
            background: #0a0e27;
            color: #00ff41;
            min-height: 100vh;
            overflow-x: hidden;
        }

        .matrix-bg {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: linear-gradient(0deg, transparent 24%, rgba(0, 255, 65, 0.02) 25%, rgba(0, 255, 65, 0.02) 26%, transparent 27%, transparent 74%, rgba(0, 255, 65, 0.02) 75%, rgba(0, 255, 65, 0.02) 76%, transparent 77%, transparent);
            background-size: 50px 50px;
            z-index: -1;
        }

        .container {
            max-width: 1600px;
            margin: 0 auto;
            padding: 20px;
            position: relative;
        }

        .header {
            background: rgba(0, 20, 40, 0.9);
            border: 2px solid #00ff41;
            border-radius: 10px;
            padding: 20px;
            margin-bottom: 30px;
            box-shadow: 0 0 20px rgba(0, 255, 65, 0.3);
        }

        .title {
            font-size: 2.5rem;
            text-align: center;
            text-shadow: 0 0 10px #00ff41;
            margin-bottom: 10px;
        }

        .subtitle {
            text-align: center;
            color: #00cc33;
            font-size: 1.1rem;
        }

        .main-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-bottom: 30px;
        }

        @media (max-width: 1200px) {
            .main-grid {
                grid-template-columns: 1fr;
            }
        }

        .panel {
            background: rgba(0, 20, 40, 0.9);
            border: 1px solid #00ff41;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 0 15px rgba(0, 255, 65, 0.2);
        }

        .panel-title {
            font-size: 1.3rem;
            margin-bottom: 15px;
            color: #00ff41;
            border-bottom: 1px solid #00ff41;
            padding-bottom: 10px;
        }

        .function-list {
            max-height: 400px;
            overflow-y: auto;
            font-size: 0.9rem;
        }

        .function-item {
            padding: 8px;
            margin-bottom: 5px;
            background: rgba(0, 255, 65, 0.05);
            border-left: 3px solid transparent;
            transition: all 0.3s ease;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .function-item.loading {
            border-left-color: #ffaa00;
            background: rgba(255, 170, 0, 0.1);
            animation: pulse 1s infinite;
        }

        .function-item.success {
            border-left-color: #00ff41;
            background: rgba(0, 255, 65, 0.1);
        }

        .function-item.error {
            border-left-color: #ff0040;
            background: rgba(255, 0, 64, 0.1);
        }

        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.6; }
        }

        .function-name {
            font-weight: bold;
        }

        .function-status {
            font-size: 0.8rem;
            padding: 2px 8px;
            border-radius: 12px;
            background: rgba(0, 0, 0, 0.3);
        }

        .scraper-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
            gap: 15px;
        }

        .scraper-card {
            background: rgba(0, 30, 50, 0.9);
            border: 1px solid #00ff41;
            border-radius: 6px;
            padding: 15px;
            transition: all 0.3s ease;
        }

        .scraper-card:hover {
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(0, 255, 65, 0.3);
        }

        .scraper-name {
            font-weight: bold;
            color: #00ff41;
            margin-bottom: 8px;
            font-size: 0.95rem;
        }

        .scraper-info {
            font-size: 0.8rem;
            color: #00cc33;
            line-height: 1.4;
        }

        .scraper-status {
            display: inline-block;
            padding: 2px 6px;
            border-radius: 4px;
            font-size: 0.75rem;
            margin-top: 5px;
        }

        .status-active {
            background: rgba(0, 255, 65, 0.2);
            color: #00ff41;
        }

        .status-pending {
            background: rgba(255, 170, 0, 0.2);
            color: #ffaa00;
        }

        .status-error {
            background: rgba(255, 0, 64, 0.2);
            color: #ff0040;
        }

        .console-log {
            background: #000;
            border: 1px solid #00ff41;
            border-radius: 6px;
            padding: 15px;
            height: 300px;
            overflow-y: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.85rem;
            margin-bottom: 20px;
        }

        .log-entry {
            margin-bottom: 5px;
            padding: 3px 0;
            border-bottom: 1px solid rgba(0, 255, 65, 0.1);
        }

        .log-time {
            color: #666;
            margin-right: 10px;
        }

        .log-message {
            color: #00ff41;
        }

        .log-error {
            color: #ff0040;
        }

        .log-warning {
            color: #ffaa00;
        }

        .stats-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 15px;
            margin-bottom: 30px;
        }

        .stat-card {
            background: rgba(0, 40, 80, 0.9);
            border: 1px solid #00ff41;
            border-radius: 8px;
            padding: 15px;
            text-align: center;
        }

        .stat-value {
            font-size: 2rem;
            font-weight: bold;
            color: #00ff41;
            text-shadow: 0 0 10px rgba(0, 255, 65, 0.5);
        }

        .stat-label {
            font-size: 0.9rem;
            color: #00cc33;
            margin-top: 5px;
        }

        .progress-bar {
            background: rgba(0, 0, 0, 0.5);
            border: 1px solid #00ff41;
            border-radius: 20px;
            height: 30px;
            overflow: hidden;
            margin-bottom: 20px;
            position: relative;
        }

        .progress-fill {
            background: linear-gradient(90deg, #00ff41, #00cc33);
            height: 100%;
            transition: width 0.5s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            color: #000;
            font-weight: bold;
        }

        .file-tree {
            background: rgba(0, 0, 0, 0.5);
            border: 1px solid #00ff41;
            border-radius: 6px;
            padding: 15px;
            max-height: 500px;
            overflow-y: auto;
        }

        .tree-item {
            padding: 3px 0;
            padding-left: 20px;
            cursor: pointer;
            transition: background 0.2s;
        }

        .tree-item:hover {
            background: rgba(0, 255, 65, 0.1);
        }

        .tree-folder {
            font-weight: bold;
            color: #ffaa00;
        }

        .tree-file {
            color: #00ff41;
        }

        .tree-file.md {
            color: #00ccff;
        }

        .tree-file.ts {
            color: #ff00ff;
        }

        .tree-file.js {
            color: #ffff00;
        }

        ::-webkit-scrollbar {
            width: 10px;
            height: 10px;
        }

        ::-webkit-scrollbar-track {
            background: rgba(0, 0, 0, 0.3);
        }

        ::-webkit-scrollbar-thumb {
            background: #00ff41;
            border-radius: 5px;
        }

        ::-webkit-scrollbar-thumb:hover {
            background: #00cc33;
        }
    </style>
</head>
<body>
    <div class="matrix-bg"></div>
    
    <div class="container">
        <div class="header">
            <h1 class="title">🔍 Detailed Scraper Monitor</h1>
            <p class="subtitle">Real-Time Function Loading & MD Scraper File Tracking</p>
        </div>

        <div class="stats-grid">
            <div class="stat-card">
                <div class="stat-value" id="totalScrapers">0</div>
                <div class="stat-label">Total Scrapers</div>
            </div>
            <div class="stat-card">
                <div class="stat-value" id="loadedFunctions">0</div>
                <div class="stat-label">Functions Loaded</div>
            </div>
            <div class="stat-card">
                <div class="stat-value" id="activeProcesses">0</div>
                <div class="stat-label">Active Processes</div>
            </div>
            <div class="stat-card">
                <div class="stat-value" id="mdFiles">0</div>
                <div class="stat-label">MD Files</div>
            </div>
        </div>

        <div class="progress-bar">
            <div class="progress-fill" id="mainProgress" style="width: 0%">
                <span id="progressText">0%</span>
            </div>
        </div>

        <div class="main-grid">
            <div class="panel">
                <h2 class="panel-title">📂 Scraper Files</h2>
                <div class="file-tree" id="fileTree">
                    <div class="tree-item tree-folder">📁 /lib/scrapers/</div>
                    <div id="scraperFileList"></div>
                    <div class="tree-item tree-folder" style="margin-top: 10px;">📁 /docs/</div>
                    <div id="mdFileList"></div>
                </div>
            </div>

            <div class="panel">
                <h2 class="panel-title">⚡ Function Loading Status</h2>
                <div class="function-list" id="functionList">
                    <!-- Functions will be populated here -->
                </div>
            </div>
        </div>

        <div class="panel">
            <h2 class="panel-title">📊 Console Output</h2>
            <div class="console-log" id="consoleLog">
                <!-- Console logs will appear here -->
            </div>
        </div>

        <div class="panel">
            <h2 class="panel-title">🤖 Active Scrapers</h2>
            <div class="scraper-grid" id="scraperGrid">
                <!-- Scraper cards will be populated here -->
            </div>
        </div>
    </div>

    <script>
        // Mock data for demonstration - replace with real WebSocket connection
        const scraperFiles = [
            '1838-wallcoverings-new-sku-scraper.ts',
            'aesthetics-wall-new-sku-scraper.ts',
            'ananbo-new-sku-scraper.ts',
            'andrew-martin-new-sku-scraper.ts',
            'arbor-wood-new-sku-scraper.ts',
            'arc-com-digital-solutions-new-sku-scraper.ts',
            'arte-new-sku-scraper.ts',
            'aux-abris-new-sku-scraper.ts',
            'belarte-studio-new-sku-scraper.ts',
            'bradbury-bradbury-new-sku-scraper.ts',
            'brunschwig-new-sku-scraper.ts',
            'carnegie-fabrics-new-sku-scraper.ts',
            'chivasso-new-sku-scraper.ts',
            'cole-and-son-new-sku-scraper.ts',
            'colefax-and-fowler-new-sku-scraper.ts'
        ];

        const mdFiles = [
            'SCRAPER-GUIDE.md',
            'VENDOR-CONFIG.md',
            'API-DOCUMENTATION.md',
            'TROUBLESHOOTING.md',
            'RATE-LIMIT-FIX.md'
        ];

        const functions = [
            { name: 'initializePlaywright()', status: 'loading', time: '2025-12-09 02:05:01' },
            { name: 'loadVendorConfig()', status: 'success', time: '2025-12-09 02:05:02' },
            { name: 'extractProductInfo()', status: 'loading', time: '2025-12-09 02:05:03' },
            { name: 'testVendor()', status: 'loading', time: '2025-12-09 02:05:04' },
            { name: 'scanAllVendors()', status: 'loading', time: '2025-12-09 02:05:05' },
            { name: 'deployAgents()', status: 'pending', time: '2025-12-09 02:05:06' },
            { name: 'sendProgressReport()', status: 'pending', time: '2025-12-09 02:05:07' },
            { name: 'startYoloMode()', status: 'success', time: '2025-12-09 02:05:08' }
        ];

        let logIndex = 0;
        let progressValue = 0;

        function initializeFileTree() {
            // Populate scraper files
            const scraperList = document.getElementById('scraperFileList');
            scraperFiles.forEach((file, index) => {
                setTimeout(() => {
                    const div = document.createElement('div');
                    div.className = 'tree-item tree-file ts';
                    div.innerHTML = `&nbsp;&nbsp;📄 ${file}`;
                    scraperList.appendChild(div);
                    updateStats();
                    addLog(`Loaded scraper: ${file}`, 'info');
                }, index * 100);
            });

            // Populate MD files
            const mdList = document.getElementById('mdFileList');
            mdFiles.forEach((file, index) => {
                setTimeout(() => {
                    const div = document.createElement('div');
                    div.className = 'tree-item tree-file md';
                    div.innerHTML = `&nbsp;&nbsp;📝 ${file}`;
                    mdList.appendChild(div);
                    updateStats();
                    addLog(`Loaded documentation: ${file}`, 'info');
                }, (index + scraperFiles.length) * 100);
            });
        }

        function initializeFunctions() {
            const functionList = document.getElementById('functionList');
            functions.forEach((func, index) => {
                setTimeout(() => {
                    const div = document.createElement('div');
                    div.className = `function-item ${func.status}`;
                    div.innerHTML = `
                        <span class="function-name">${func.name}</span>
                        <span class="function-status">${func.status.toUpperCase()}</span>
                    `;
                    functionList.appendChild(div);
                    
                    // Simulate loading completion
                    if (func.status === 'loading') {
                        setTimeout(() => {
                            div.classList.remove('loading');
                            div.classList.add('success');
                            div.querySelector('.function-status').textContent = 'SUCCESS';
                            addLog(`✅ ${func.name} loaded successfully`, 'success');
                            updateProgress();
                        }, 2000 + Math.random() * 3000);
                    }
                }, index * 300);
            });
        }

        function initializeScrapers() {
            const scraperGrid = document.getElementById('scraperGrid');
            const activeScrapers = scraperFiles.slice(0, 8);
            
            activeScrapers.forEach((scraper, index) => {
                setTimeout(() => {
                    const vendorName = scraper.replace('-new-sku-scraper.ts', '');
                    const card = document.createElement('div');
                    card.className = 'scraper-card';
                    card.innerHTML = `
                        <div class="scraper-name">${vendorName}</div>
                        <div class="scraper-info">
                            Status: <span class="scraper-status status-active">ACTIVE</span><br>
                            Products: ${Math.floor(Math.random() * 50)}<br>
                            Last Run: ${new Date().toLocaleTimeString()}
                        </div>
                    `;
                    scraperGrid.appendChild(card);
                    addLog(`🤖 Activated scraper: ${vendorName}`, 'info');
                }, index * 500);
            });
        }

        function updateStats() {
            document.getElementById('totalScrapers').textContent = 
                document.querySelectorAll('.tree-file.ts').length;
            document.getElementById('loadedFunctions').textContent = 
                document.querySelectorAll('.function-item.success').length;
            document.getElementById('activeProcesses').textContent = 
                document.querySelectorAll('.scraper-status.status-active').length;
            document.getElementById('mdFiles').textContent = 
                document.querySelectorAll('.tree-file.md').length;
        }

        function updateProgress() {
            progressValue = Math.min(progressValue + 10, 100);
            document.getElementById('mainProgress').style.width = progressValue + '%';
            document.getElementById('progressText').textContent = progressValue + '%';
        }

        function addLog(message, type = 'info') {
            const consoleLog = document.getElementById('consoleLog');
            const entry = document.createElement('div');
            entry.className = 'log-entry';
            
            const time = new Date().toLocaleTimeString();
            let messageClass = 'log-message';
            if (type === 'error') messageClass = 'log-error';
            if (type === 'warning') messageClass = 'log-warning';
            
            entry.innerHTML = `
                <span class="log-time">[${time}]</span>
                <span class="${messageClass}">${message}</span>
            `;
            
            consoleLog.appendChild(entry);
            consoleLog.scrollTop = consoleLog.scrollHeight;
        }

        // Real-time WebSocket connection for actual deployment
        function connectToServer() {
            const ws = new WebSocket('ws://45.61.58.125:3040');
            
            ws.onmessage = function(event) {
                const data = JSON.parse(event.data);
                // Update UI with real data
                if (data.type === 'function_load') {
                    addLog(`Loading function: ${data.function}`, 'info');
                }
                if (data.type === 'scraper_status') {
                    addLog(`Scraper ${data.vendor}: ${data.status}`, data.success ? 'success' : 'error');
                }
            };
        }

        // Initialize everything
        document.addEventListener('DOMContentLoaded', () => {
            addLog('🚀 System initializing...', 'info');
            initializeFileTree();
            initializeFunctions();
            initializeScrapers();
            
            // Simulate real-time updates
            setInterval(() => {
                const randomLog = [
                    'Checking vendor API...',
                    'Loading Playwright browser...',
                    'Extracting product data...',
                    'Saving to database...',
                    'Updating cache...'
                ];
                addLog(randomLog[Math.floor(Math.random() * randomLog.length)], 'info');
                updateStats();
            }, 5000);
            
            // Try to connect to real server
            try {
                connectToServer();
            } catch (e) {
                addLog('Running in demo mode (no server connection)', 'warning');
            }
        });
    </script>
</body>
</html>