🏠 Root
/
home
/
artorgp
/
www
/
wp-content
/
plugins
/
eli-php-compatibility-scanner
/
assets
/
src
/
js
/
classes
/
Editing: ScanManager.js
/** * ScanManager - Handles the scanning process, batch processing, and scan coordination */ import jQuery from 'jquery'; export class ScanManager { constructor(ajaxClient, optionsManager, targetsManager) { this.ajaxClient = ajaxClient; this.optionsManager = optionsManager; this.targetsManager = targetsManager; this.isScanning = false; this.currentScanId = null; } /** * Initialize scan manager */ init() { this.bindEvents(); } /** * Bind event handlers for scan controls */ bindEvents() { jQuery('#phpcompat-start-scan').on('click', () => { this.startScan(); }); jQuery('#phpcompat-stop-scan').on('click', () => { this.stopScan(); }); } /** * Start the scanning process */ async startScan() { if (this.isScanning) { return; } const $button = jQuery('#phpcompat-start-scan'); const $stopButton = jQuery('#phpcompat-stop-scan'); const $status = jQuery('#phpcompat-scan-status'); // Validate targets if (!this.targetsManager.hasSelectedTargets()) { $status.text('Select at least one target'); return; } // Start scanning this.isScanning = true; $status.text('Running…'); $button.prop('disabled', true); $stopButton.show().prop('disabled', false); try { const selectedTargets = this.targetsManager.getSelectedTargets(); await this.processTargets(selectedTargets); } catch (error) { console.error('Scan failed:', error); $status.text('Scan failed'); } finally { this.isScanning = false; $button.prop('disabled', false); $stopButton.hide(); } } /** * Stop the current scan */ async stopScan() { if (!this.isScanning) { return; } const $button = jQuery('#phpcompat-start-scan'); const $stopButton = jQuery('#phpcompat-stop-scan'); const $status = jQuery('#phpcompat-scan-status'); $stopButton.prop('disabled', true).text('Stopping...'); try { const response = await this.ajaxClient.stopScan(); if (response && response.success) { $button.prop('disabled', false).text('Start Scan'); $stopButton.prop('disabled', false).text('Stop Scan').hide(); $status.html(`✅ ${response.data.message || 'Scan stopped'}`); // Clear scan progress jQuery('.phpcompat-progress').remove(); jQuery('.phpcompat-batch-results').remove(); } } catch (error) { console.error('Failed to stop scan:', error); $stopButton.prop('disabled', false).text('Stop Scan'); $status.html('❌ Failed to stop scan'); } this.isScanning = false; } /** * Process all selected targets */ async processTargets(targets) { let anyFailed = false; for (let i = 0; i < targets.length; i++) { if (!this.isScanning) { break; // Scan was stopped } const target = targets[i]; try { await this.processTarget(target); } catch (error) { console.error(`Failed to process target ${target.name}:`, error); anyFailed = true; } } // Final cleanup if (this.isScanning) { const $status = jQuery('#phpcompat-scan-status'); $status.text(anyFailed ? 'Some scans failed' : 'Done'); } } /** * Process a single target */ async processTarget(target) { const $cb = jQuery(target.element); const $label = $cb.closest('.phpcompat-target-item'); const $status = jQuery('#phpcompat-scan-status'); // Create result container const containerId = `pcp-result-${target.type}-${target.slug.replace(/[^a-z0-9_-]/gi, '_')}`; let $container = jQuery(`#${containerId}`); if (!$container.length) { $container = jQuery('<div/>', { id: containerId, class: 'phpcompat-output main_output', css: { marginTop: '8px' } }); $cb.closest('.phpcompat-target-item').after($container); } else { $container.text(''); } // Show spinner let $flag = $label.find('.phpcompat-flag'); if (!$flag.length) { $flag = jQuery('<span/>', { class: 'phpcompat-flag', css: { marginLeft: '6px' } }).appendTo($label); } $flag.html('<span class="spinner is-active"></span>'); $status.text(`Scanning ${target.name}...`); this.targetsManager.setTargetScanning(target.type, target.slug); // Get progress info const batchSize = this.optionsManager.getBatchSize(); const skipVendor = this.optionsManager.getSkipVendor(); const progressRes = await this.ajaxClient.getProgress( target.type, target.slug, batchSize, skipVendor ); if (progressRes && progressRes.success && progressRes.data) { const progress = progressRes.data; if (progress.total_files > 0) { // Create progress section $container.html(this.createProgressSection(progress)); // Process batches await this.processBatches(progress, $container, $flag, target); } else { $container.html('<div class="phpcompat-progress"><strong>No PHP files found to scan</strong><br>The selected target does not contain any PHP files.</div>'); this.targetsManager.setTargetComplete(target.type, target.slug, 0, 0); } } } /** * Create progress section HTML */ createProgressSection(progress) { return `<div class="phpcompat-progress"> <strong>Scan Progress:</strong> Total files: ${progress.total_files} Estimated batches: ${progress.estimated_batches} <div class="phpcompat-progress-bar"><div class="phpcompat-progress-fill" style="width: 0%"></div></div> <div class="phpcompat-progress-text">Preparing to scan...</div> </div>`; } /** * Process all batches for a target */ async processBatches(progress, $container, $flag, target) { const totalBatches = progress.estimated_batches; const scanId = progress.scan_id; const allResults = []; for (let currentBatch = 1; currentBatch <= totalBatches; currentBatch++) { if (!this.isScanning) { break; // Scan was stopped } // Update progress this.updateProgressBar($container, currentBatch, totalBatches); try { const response = await this.ajaxClient.processBatch(scanId, currentBatch); if (response && response.success) { const batchData = response.data; allResults.push(batchData); // Show progressive results this.showProgressiveResults($container, batchData); } else { throw new Error(response?.data?.message || 'Batch failed'); } } catch (error) { console.error(`Batch ${currentBatch} failed:`, error); $flag.html('❌ <span class="phpcompat-status-count">Batch failed</span>'); $container.html(`Batch ${currentBatch} failed: ${error.message}`); return; } // Small delay between batches if (currentBatch < totalBatches) { await new Promise(resolve => setTimeout(resolve, 100)); } } // All batches complete this.finalizeScan($container, $flag, allResults, progress, target); } /** * Update progress bar */ updateProgressBar($container, currentBatch, totalBatches) { const progressPercent = Math.round((currentBatch - 1) / totalBatches * 100); const $progressFill = $container.find('.phpcompat-progress-fill'); const $progressText = $container.find('.phpcompat-progress-text'); if ($progressFill.length) { $progressFill.css('width', `${progressPercent}%`); } if ($progressText.length) { $progressText.text(`Processing batch ${currentBatch} of ${totalBatches}...`); } } /** * Show progressive results during scanning */ showProgressiveResults($container, batchData) { const batchOutput = `<div class="phpcompat-batch"> <strong>Batch ${batchData.batch_number}:</strong> ${batchData.output && batchData.output.length > 0 ? '<pre class="phpcompat-batch-output"></pre>' : '<em>No issues found in this batch</em>'} </div>`; let $existingResults = $container.find('.phpcompat-batch-results'); if ($existingResults.length === 0) { $container.append('<div class="phpcompat-batch-results"></div>'); $existingResults = $container.find('.phpcompat-batch-results'); } $existingResults.append(batchOutput); // Safely set output content if (batchData.output && batchData.output.length > 0) { $existingResults.find('.phpcompat-batch-output').last().text(batchData.output); } } /** * Finalize scan and show complete results */ finalizeScan($container, $flag, allResults, progress, target) { // Calculate totals const totalErrors = allResults.reduce((sum, batch) => sum + (parseInt(batch.errors, 10) || 0), 0); const totalWarnings = allResults.reduce((sum, batch) => sum + (parseInt(batch.warnings, 10) || 0), 0); const totalIssues = totalErrors + totalWarnings; const phpVersion = this.optionsManager.getPhpVersion(); // Update flag with status if (totalIssues > 0) { let statusText = ''; if (totalErrors > 0 && totalWarnings > 0) { statusText = `${totalIssues} issue${totalIssues > 1 ? 's' : ''} (${totalErrors} error${totalErrors > 1 ? 's' : ''}, ${totalWarnings} warning${totalWarnings > 1 ? 's' : ''}) - PHP ${phpVersion}`; } else if (totalErrors > 0) { statusText = `${totalErrors} error${totalErrors > 1 ? 's' : ''} - PHP ${phpVersion}`; } else { statusText = `${totalWarnings} warning${totalWarnings > 1 ? 's' : ''} - PHP ${phpVersion}`; } if (totalErrors > 0) { $flag.html(`❌ <span class="phpcompat-status-count">${statusText}</span>`); } else { $flag.html(`⚠️ <span class="phpcompat-status-count">${statusText}</span>`); } } else { $flag.html(`✅ <span class="phpcompat-status-count">No issues found - PHP ${phpVersion}</span>`); } // Show final organized results this.showFinalResults($container, allResults, progress, phpVersion); // Update overview tag this.targetsManager.setTargetComplete(target.type, target.slug, totalErrors, totalWarnings); } /** * Show final organized results */ showFinalResults($container, allResults, progress, phpVersion) { // Create the new two-column layout const leftColumnHtml = `<div class="phpcompat-output-left"> <div class="phpcompat-progress"> <strong>Scan Progress:</strong> Total files: ${progress.total_files} Estimated batches: ${progress.estimated_batches} <div class="phpcompat-progress-bar"><div class="phpcompat-progress-fill" style="width: 100%"></div></div> <div class="phpcompat-progress-text">Scan Complete!</div> </div> <div class="phpcompat-summary"> <strong>Scan Complete!</strong> Total files scanned: ${progress.total_files} Batches processed: ${allResults.length} Target PHP version: ${phpVersion} </div> </div>`; // Add batch results in right column let rightColumnHtml = ''; if (allResults.length > 0) { rightColumnHtml = `<div class="phpcompat-output-right"> <div class="phpcompat-batch-results"> <div class="phpcompat-batch-results-toggle"> <span>Batch Results (${allResults.length} batches)</span> <span class="toggle-icon">▼</span> </div> <div class="phpcompat-batch-results-content">`; allResults.forEach((batchData, index) => { rightColumnHtml += `<div class="phpcompat-batch"> <strong>Batch ${batchData.batch_number}:</strong> ${batchData.output && batchData.output.length > 0 ? `<pre class="phpcompat-batch-output" data-batch="${index}"></pre>` : '<em>No issues found in this batch</em>'} </div>`; }); rightColumnHtml += '</div></div></div>'; } // Clear existing results and show final organized results $container.find('.phpcompat-progress').remove(); $container.find('.phpcompat-batch-results').remove(); $container.html(leftColumnHtml + rightColumnHtml); // Populate output content allResults.forEach((batchData, index) => { if (batchData.output && batchData.output.length > 0) { $container.find(`.phpcompat-batch-output[data-batch="${index}"]`).text(batchData.output); } }); // Add toggle functionality const $toggleButton = $container.find('.phpcompat-batch-results-toggle'); $toggleButton.on('click', function (e) { e.preventDefault(); const $batchResults = jQuery(this).closest('.phpcompat-batch-results'); const $toggleIcon = jQuery(this).find('.toggle-icon'); $batchResults.toggleClass('collapsed'); // Update toggle icon if ($batchResults.hasClass('collapsed')) { $toggleIcon.text('▶'); } else { $toggleIcon.text('▼'); } }); // Update progress bar to completion const $progressFillFinal = $container.find('.phpcompat-progress-fill'); if ($progressFillFinal.length) { $progressFillFinal.css('width', '100%'); } } /** * Check if currently scanning */ isCurrentlyScanning() { return this.isScanning; } }
Save
Cancel