refactoring step 2
This commit is contained in:
@ -63,7 +63,7 @@ class VNADashboard {
|
||||
*/
|
||||
async init() {
|
||||
try {
|
||||
console.log('🚀 Initializing VNA Dashboard...');
|
||||
console.log('Initializing VNA Dashboard...');
|
||||
|
||||
// Initialize Lucide icons
|
||||
if (typeof lucide !== 'undefined') {
|
||||
@ -80,7 +80,7 @@ class VNADashboard {
|
||||
await this.websocket.connect();
|
||||
|
||||
this.isInitialized = true;
|
||||
console.log('✅ VNA Dashboard initialized successfully');
|
||||
console.log('VNA Dashboard initialized successfully');
|
||||
|
||||
// Show welcome notification
|
||||
this.notifications.show({
|
||||
@ -90,7 +90,7 @@ class VNADashboard {
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to initialize VNA Dashboard:', error);
|
||||
console.error('Failed to initialize VNA Dashboard:', error);
|
||||
this.notifications.show({
|
||||
type: 'error',
|
||||
title: 'Initialization Failed',
|
||||
@ -148,7 +148,7 @@ class VNADashboard {
|
||||
setupUIHandlers() {
|
||||
// Navigation
|
||||
this.ui.onViewChange((view) => {
|
||||
console.log(`📱 Switched to view: ${view}`);
|
||||
console.log(` Switched to view: ${view}`);
|
||||
if (view === 'settings') {
|
||||
this.settings.refresh();
|
||||
}
|
||||
@ -156,7 +156,7 @@ class VNADashboard {
|
||||
|
||||
// Processor toggles (UI-only visibility)
|
||||
this.ui.onProcessorToggle((processor, enabled) => {
|
||||
console.log(`🔧 Processor ${processor}: ${enabled ? 'enabled' : 'disabled'}`);
|
||||
console.log(` Processor ${processor}: ${enabled ? 'enabled' : 'disabled'}`);
|
||||
this.charts.toggleProcessor(processor, enabled);
|
||||
this.savePreferences();
|
||||
});
|
||||
@ -171,7 +171,7 @@ class VNADashboard {
|
||||
if (data.type === 'system_status') {
|
||||
this.ui.updateSystemStatus(data.data);
|
||||
} else if (data.type === 'processor_history') {
|
||||
console.log('📜 Received processor history:', data);
|
||||
console.log('Received processor history:', data);
|
||||
}
|
||||
// Note: 'error' is handled by WebSocket manager directly
|
||||
}
|
||||
@ -247,7 +247,7 @@ class VNADashboard {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Error applying preferences:', error);
|
||||
console.warn('Error applying preferences:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,7 +263,7 @@ class VNADashboard {
|
||||
};
|
||||
await this.storage.savePreferences(preferences);
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Failed to save preferences:', error);
|
||||
console.warn('Failed to save preferences:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -282,7 +282,7 @@ class VNADashboard {
|
||||
destroy() {
|
||||
if (!this.isInitialized) return;
|
||||
|
||||
console.log('🧹 Cleaning up VNA Dashboard...');
|
||||
console.log('Cleaning up VNA Dashboard...');
|
||||
|
||||
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
|
||||
window.removeEventListener('beforeunload', this.handleBeforeUnload);
|
||||
@ -295,7 +295,7 @@ class VNADashboard {
|
||||
this.notifications.destroy();
|
||||
|
||||
this.isInitialized = false;
|
||||
console.log('✅ VNA Dashboard cleanup complete');
|
||||
console.log('VNA Dashboard cleanup complete');
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,11 +312,11 @@ if (document.readyState === 'loading') {
|
||||
|
||||
// Global error handling
|
||||
window.addEventListener('error', (event) => {
|
||||
console.error('🚨 Global error:', event.error);
|
||||
console.error('Global error:', event.error);
|
||||
});
|
||||
|
||||
window.addEventListener('unhandledrejection', (event) => {
|
||||
console.error('🚨 Unhandled promise rejection:', event.reason);
|
||||
console.error('Unhandled promise rejection:', event.reason);
|
||||
});
|
||||
|
||||
// Development helpers
|
||||
|
||||
@ -63,14 +63,14 @@ export class AcquisitionManager {
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
this.notifications.show({type: 'success', message: result.message});
|
||||
this.notifications.show({type: 'success', title: 'Acquisition Started', message: result.message});
|
||||
await this.updateStatus();
|
||||
} else {
|
||||
this.notifications.show({type: 'error', message: result.error || 'Failed to start acquisition'});
|
||||
this.notifications.show({type: 'error', title: 'Start Failed', message: result.error || 'Failed to start acquisition'});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error starting acquisition:', error);
|
||||
this.notifications.show({type: 'error', message: 'Failed to start acquisition'});
|
||||
this.notifications.show({type: 'error', title: 'Start Failed', message: 'Failed to start acquisition'});
|
||||
} finally {
|
||||
setButtonLoading(this.elements.startBtn, false, originalState);
|
||||
}
|
||||
@ -88,14 +88,14 @@ export class AcquisitionManager {
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
this.notifications.show({type: 'success', message: result.message});
|
||||
this.notifications.show({type: 'success', title: 'Acquisition Stopped', message: result.message});
|
||||
await this.updateStatus();
|
||||
} else {
|
||||
this.notifications.show({type: 'error', message: result.error || 'Failed to stop acquisition'});
|
||||
this.notifications.show({type: 'error', title: 'Stop Failed', message: result.error || 'Failed to stop acquisition'});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error stopping acquisition:', error);
|
||||
this.notifications.show({type: 'error', message: 'Failed to stop acquisition'});
|
||||
this.notifications.show({type: 'error', title: 'Stop Failed', message: 'Failed to stop acquisition'});
|
||||
} finally {
|
||||
setButtonLoading(this.elements.stopBtn, false, originalState);
|
||||
}
|
||||
@ -113,14 +113,14 @@ export class AcquisitionManager {
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
this.notifications.show({type: 'success', message: result.message});
|
||||
this.notifications.show({type: 'success', title: 'Single Sweep', message: result.message});
|
||||
await this.updateStatus();
|
||||
} else {
|
||||
this.notifications.show({type: 'error', message: result.error || 'Failed to trigger single sweep'});
|
||||
this.notifications.show({type: 'error', title: 'Single Sweep Failed', message: result.error || 'Failed to trigger single sweep'});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error triggering single sweep:', error);
|
||||
this.notifications.show({type: 'error', message: 'Failed to trigger single sweep'});
|
||||
this.notifications.show({type: 'error', title: 'Single Sweep Failed', message: 'Failed to trigger single sweep'});
|
||||
} finally {
|
||||
setButtonLoading(this.elements.singleSweepBtn, false, originalState);
|
||||
}
|
||||
|
||||
@ -68,31 +68,31 @@ export class ChartManager {
|
||||
}
|
||||
|
||||
async init() {
|
||||
console.log('📊 Initializing Chart Manager...');
|
||||
console.log('Initializing Chart Manager...');
|
||||
this.chartsGrid = document.getElementById('chartsGrid');
|
||||
this.emptyState = document.getElementById('emptyState');
|
||||
if (!this.chartsGrid || !this.emptyState) throw new Error('Required DOM elements not found');
|
||||
if (typeof Plotly === 'undefined') throw new Error('Plotly.js not loaded');
|
||||
console.log('✅ Chart Manager initialized');
|
||||
console.log('Chart Manager initialized');
|
||||
}
|
||||
|
||||
/** Новый входной формат — прямо payload от WS: processor_result */
|
||||
/** New input format - direct payload from WS: processor_result */
|
||||
addResult(payload) {
|
||||
try {
|
||||
const { processor_id, timestamp, plotly_config, metadata, data } = payload;
|
||||
if (!processor_id) {
|
||||
console.warn('⚠️ Invalid result - missing processor_id:', payload);
|
||||
console.warn('Invalid result - missing processor_id:', payload);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.disabledProcessors.has(processor_id)) {
|
||||
console.log(`⏸️ Skipping disabled processor: ${processor_id}`);
|
||||
console.log(` Skipping disabled processor: ${processor_id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Store only the latest data (no history needed)
|
||||
this.chartData.set(processor_id, {
|
||||
timestamp: new Date((timestamp ?? Date.now()) * 1000), // если приходит epoch seconds
|
||||
timestamp: new Date((timestamp ?? Date.now()) * 1000), // if timestamp is in epoch seconds
|
||||
metadata: metadata || {},
|
||||
data: data || {},
|
||||
plotly_config: plotly_config || { data: [], layout: {} }
|
||||
@ -103,7 +103,7 @@ export class ChartManager {
|
||||
this.updateChart(processor_id, plotly_config || { data: [], layout: {} });
|
||||
this.hideEmptyState();
|
||||
} catch (e) {
|
||||
console.error('❌ Error adding chart result:', e);
|
||||
console.error('Error adding chart result:', e);
|
||||
this.notifications?.show?.({
|
||||
type: 'error', title: 'Chart Error', message: `Failed to update chart`
|
||||
});
|
||||
@ -111,7 +111,7 @@ export class ChartManager {
|
||||
}
|
||||
|
||||
createChart(processorId) {
|
||||
console.log(`📊 Creating chart for processor: ${processorId}`);
|
||||
console.log(` Creating chart for processor: ${processorId}`);
|
||||
const card = this.createChartCard(processorId);
|
||||
this.chartsGrid.appendChild(card);
|
||||
|
||||
@ -144,7 +144,7 @@ export class ChartManager {
|
||||
if (this.isPaused) return;
|
||||
|
||||
const chart = this.charts.get(processorId);
|
||||
if (!chart?.plotContainer) { console.warn(`⚠️ Chart not found for processor: ${processorId}`); return; }
|
||||
if (!chart?.plotContainer) { console.warn(` Chart not found for processor: ${processorId}`); return; }
|
||||
|
||||
try {
|
||||
const start = performance.now();
|
||||
@ -172,7 +172,7 @@ export class ChartManager {
|
||||
this.updatePerformanceStats(dt);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`❌ Error updating chart ${processorId}:`, e);
|
||||
console.error(` Error updating chart ${processorId}:`, e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,7 +187,7 @@ export class ChartManager {
|
||||
while (this.updateQueue.size > 0 && !this.isPaused) {
|
||||
const [id, fn] = this.updateQueue.entries().next().value;
|
||||
this.updateQueue.delete(id);
|
||||
try { await fn(); } catch (e) { console.error(`❌ Error in queued update for ${id}:`, e); }
|
||||
try { await fn(); } catch (e) { console.error(` Error in queued update for ${id}:`, e); }
|
||||
await new Promise(r => setTimeout(r, 0));
|
||||
}
|
||||
this.isUpdating = false;
|
||||
@ -297,11 +297,11 @@ export class ChartManager {
|
||||
JSON.stringify(uiParameters) !== JSON.stringify(chart.lastUiParameters);
|
||||
|
||||
if (!parametersChanged) {
|
||||
console.log(`⚪ No parameter changes for ${processorId}, skipping settings update`);
|
||||
console.log(` No parameter changes for ${processorId}, skipping settings update`);
|
||||
return; // No need to update if parameters haven't changed
|
||||
}
|
||||
|
||||
console.log(`🔄 Updating settings for ${processorId}:`, {
|
||||
console.log(` Updating settings for ${processorId}:`, {
|
||||
old: chart.lastUiParameters,
|
||||
new: uiParameters
|
||||
});
|
||||
@ -341,7 +341,7 @@ export class ChartManager {
|
||||
uiParameters.forEach(param => {
|
||||
const settingKey = `${processorId}_${param.name}`;
|
||||
this.lastSettingValues[settingKey] = param.value;
|
||||
console.log(`💾 Initialized setting value: ${settingKey} = ${param.value}`);
|
||||
console.log(` Initialized setting value: ${settingKey} = ${param.value}`);
|
||||
});
|
||||
}
|
||||
|
||||
@ -396,7 +396,7 @@ export class ChartManager {
|
||||
value = value === 'true';
|
||||
}
|
||||
|
||||
console.log(`🔧 Chart setting changed: ${processorId}.${paramName} = ${value}`);
|
||||
console.log(` Chart setting changed: ${processorId}.${paramName} = ${value}`);
|
||||
|
||||
// Store the current setting value to prevent loops
|
||||
if (!this.lastSettingValues) this.lastSettingValues = {};
|
||||
@ -410,7 +410,7 @@ export class ChartManager {
|
||||
|
||||
// Check if this is the same value we just set to prevent feedback loop
|
||||
if (lastValue === value) {
|
||||
console.log(`🔄 Skipping duplicate setting: ${settingKey} = ${value} (was ${this.lastSettingValues[settingKey]})`);
|
||||
console.log(` Skipping duplicate setting: ${settingKey} = ${value} (was ${this.lastSettingValues[settingKey]})`);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -425,13 +425,13 @@ export class ChartManager {
|
||||
}
|
||||
|
||||
this.settingDebounceTimers[debounceKey] = setTimeout(() => {
|
||||
console.log(`📤 Sending setting update: ${processorId}.${paramName} = ${value}`);
|
||||
console.log(` Sending setting update: ${processorId}.${paramName} = ${value}`);
|
||||
// Send update via WebSocket
|
||||
const websocket = window.vnaDashboard?.websocket;
|
||||
if (websocket && websocket.recalculate) {
|
||||
websocket.recalculate(processorId, { [paramName]: value });
|
||||
} else {
|
||||
console.warn('⚠️ WebSocket not available for settings update');
|
||||
console.warn('WebSocket not available for settings update');
|
||||
}
|
||||
delete this.settingDebounceTimers[debounceKey];
|
||||
}, 300); // 300ms delay to prevent rapid updates
|
||||
@ -445,17 +445,17 @@ export class ChartManager {
|
||||
const paramName = button.dataset.param;
|
||||
|
||||
if (!paramName) {
|
||||
console.warn('⚠️ Button missing param data:', button);
|
||||
console.warn('Button missing param data:', button);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent multiple clicks while processing
|
||||
if (button.disabled) {
|
||||
console.log('🔘 Button already processing, ignoring click');
|
||||
console.log('Button already processing, ignoring click');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`🔘 Button clicked: ${processorId}.${paramName}`);
|
||||
console.log(` Button clicked: ${processorId}.${paramName}`);
|
||||
|
||||
// Temporarily disable button and show feedback
|
||||
const originalText = button.textContent;
|
||||
@ -465,10 +465,10 @@ export class ChartManager {
|
||||
// Send button action via WebSocket (set to true to trigger action) - only once
|
||||
const websocket = window.vnaDashboard?.websocket;
|
||||
if (websocket && websocket.recalculate) {
|
||||
console.log(`📤 Sending button action: ${processorId}.${paramName} = true`);
|
||||
console.log(` Sending button action: ${processorId}.${paramName} = true`);
|
||||
websocket.recalculate(processorId, { [paramName]: true });
|
||||
} else {
|
||||
console.warn('⚠️ WebSocket not available for button action');
|
||||
console.warn('WebSocket not available for button action');
|
||||
}
|
||||
|
||||
// Re-enable button after a short delay
|
||||
@ -543,7 +543,7 @@ export class ChartManager {
|
||||
message: `Downloaded ${formatProcessorName(id)} plot and data`
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('❌ Chart download failed:', e);
|
||||
console.error('Chart download failed:', e);
|
||||
this.notifications?.show?.({
|
||||
type: 'error',
|
||||
title: 'Download Failed',
|
||||
@ -620,7 +620,7 @@ export class ChartManager {
|
||||
|
||||
return rawData;
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Error extracting processor raw data:', error);
|
||||
console.warn('Error extracting processor raw data:', error);
|
||||
return { error: 'Failed to extract raw data' };
|
||||
}
|
||||
}
|
||||
@ -681,8 +681,8 @@ export class ChartManager {
|
||||
this.performanceStats.avgUpdateTime = total / this.performanceStats.updatesProcessed;
|
||||
}
|
||||
|
||||
pause() { this.isPaused = true; console.log('⏸️ Chart updates paused'); }
|
||||
resume() { this.isPaused = false; console.log('▶️ Chart updates resumed'); if (this.updateQueue.size) this.processUpdateQueue(); }
|
||||
pause() { this.isPaused = true; console.log('Chart updates paused'); }
|
||||
resume() { this.isPaused = false; console.log('Chart updates resumed'); if (this.updateQueue.size) this.processUpdateQueue(); }
|
||||
|
||||
|
||||
/**
|
||||
@ -706,7 +706,7 @@ export class ChartManager {
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ Could not extract Plotly data for ${processorId}:`, error);
|
||||
console.warn(` Could not extract Plotly data for ${processorId}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -760,7 +760,7 @@ export class ChartManager {
|
||||
|
||||
return { data, layout };
|
||||
} catch (error) {
|
||||
console.warn(`⚠️ Could not extract safe Plotly data for ${processorId}:`, error);
|
||||
console.warn(` Could not extract safe Plotly data for ${processorId}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -790,11 +790,11 @@ export class ChartManager {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
console.log('🧹 Cleaning up Chart Manager...');
|
||||
console.log('Cleaning up Chart Manager...');
|
||||
this.clearAll();
|
||||
this.updateQueue.clear();
|
||||
this.isUpdating = false;
|
||||
this.isPaused = true;
|
||||
console.log('✅ Chart Manager cleanup complete');
|
||||
console.log('Chart Manager cleanup complete');
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ export class NotificationManager {
|
||||
document.body.appendChild(this.container);
|
||||
}
|
||||
|
||||
console.log('📢 Notification Manager initialized');
|
||||
console.log('Notification Manager initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,7 +68,7 @@ export class NotificationManager {
|
||||
show(options) {
|
||||
// Validate options
|
||||
if (!options || typeof options !== 'object') {
|
||||
console.warn('⚠️ Invalid notification options:', options);
|
||||
console.warn('Invalid notification options:', options);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ export class NotificationManager {
|
||||
|
||||
// Don't show notification if both title and message are empty
|
||||
if (!title && !message) {
|
||||
console.warn('⚠️ Skipping notification with empty title and message');
|
||||
console.warn('Skipping notification with empty title and message');
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ export class NotificationManager {
|
||||
const lastShown = this.recentNotifications.get(notificationKey);
|
||||
|
||||
if (lastShown && (now - lastShown) < 2000) {
|
||||
console.log('🔄 Skipping duplicate notification:', notificationKey);
|
||||
console.log('Skipping duplicate notification:', notificationKey);
|
||||
return null; // Skip duplicate notification
|
||||
}
|
||||
|
||||
@ -169,7 +169,7 @@ export class NotificationManager {
|
||||
lucide.createIcons({ attrs: { 'stroke-width': 1.5 } });
|
||||
}
|
||||
|
||||
console.log(`📢 Showing ${notification.type} notification:`, notification.title);
|
||||
console.log(` Showing ${notification.type} notification:`, notification.title);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -249,7 +249,7 @@ export class NotificationManager {
|
||||
try {
|
||||
actionConfig.handler(notification);
|
||||
} catch (error) {
|
||||
console.error('❌ Error in notification action handler:', error);
|
||||
console.error('Error in notification action handler:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -285,7 +285,7 @@ export class NotificationManager {
|
||||
const notification = this.notifications.get(id);
|
||||
if (!notification) return;
|
||||
|
||||
console.log(`📢 Dismissing notification: ${id}`);
|
||||
console.log(` Dismissing notification: ${id}`);
|
||||
|
||||
// Clear timer
|
||||
if (notification.timer) {
|
||||
@ -312,7 +312,7 @@ export class NotificationManager {
|
||||
* Dismiss all notifications
|
||||
*/
|
||||
dismissAll() {
|
||||
console.log('📢 Dismissing all notifications');
|
||||
console.log('Dismissing all notifications');
|
||||
|
||||
for (const id of this.notifications.keys()) {
|
||||
this.dismiss(id);
|
||||
@ -323,7 +323,7 @@ export class NotificationManager {
|
||||
* Dismiss notifications by type
|
||||
*/
|
||||
dismissByType(type) {
|
||||
console.log(`📢 Dismissing all ${type} notifications`);
|
||||
console.log(` Dismissing all ${type} notifications`);
|
||||
|
||||
for (const notification of this.notifications.values()) {
|
||||
if (notification.type === type) {
|
||||
@ -487,7 +487,7 @@ export class NotificationManager {
|
||||
* Cleanup
|
||||
*/
|
||||
destroy() {
|
||||
console.log('🧹 Cleaning up Notification Manager...');
|
||||
console.log('Cleaning up Notification Manager...');
|
||||
|
||||
this.dismissAll();
|
||||
|
||||
@ -495,6 +495,6 @@ export class NotificationManager {
|
||||
this.container.parentNode.removeChild(this.container);
|
||||
}
|
||||
|
||||
console.log('✅ Notification Manager cleanup complete');
|
||||
console.log('Notification Manager cleanup complete');
|
||||
}
|
||||
}
|
||||
@ -71,9 +71,9 @@ export class SettingsManager {
|
||||
await this._loadInitialData();
|
||||
|
||||
this.isInitialized = true;
|
||||
console.log('✅ Settings Manager initialized');
|
||||
console.log('Settings Manager initialized');
|
||||
} catch (err) {
|
||||
console.error('❌ Settings Manager init failed:', err);
|
||||
console.error('Settings Manager init failed:', err);
|
||||
this._notify('error', 'Settings Error', 'Failed to initialize settings');
|
||||
}
|
||||
}
|
||||
@ -83,7 +83,7 @@ export class SettingsManager {
|
||||
this._resetCalibrationCaptureState();
|
||||
this._detachEvents();
|
||||
this.isInitialized = false;
|
||||
console.log('🧹 Settings Manager destroyed');
|
||||
console.log('Settings Manager destroyed');
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
@ -287,7 +287,7 @@ export class SettingsManager {
|
||||
calibrations.forEach(c => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = c.name;
|
||||
opt.textContent = `${c.name} ${c.is_complete ? '✓' : '⚠'}`;
|
||||
opt.textContent = `${c.name} ${c.is_complete ? '✔' : '?'}`;
|
||||
dd.appendChild(opt);
|
||||
});
|
||||
|
||||
@ -392,7 +392,7 @@ export class SettingsManager {
|
||||
btn.title = 'Standard is currently being captured';
|
||||
} else if (isCompleted) {
|
||||
btn.classList.add('btn--success');
|
||||
btn.innerHTML = `<i data-lucide="check"></i> ${std.toUpperCase()} ✓`;
|
||||
btn.innerHTML = `<i data-lucide="check"></i> ${std.toUpperCase()}`;
|
||||
btn.disabled = false;
|
||||
btn.title = 'Click to recapture this standard';
|
||||
} else if (isMissing) {
|
||||
@ -435,7 +435,7 @@ export class SettingsManager {
|
||||
// Reset reference state
|
||||
this.availableReferences = [];
|
||||
this.currentReference = null;
|
||||
console.log('🔄 Calibration and reference UI reset after preset change');
|
||||
console.log('Calibration and reference UI reset after preset change');
|
||||
}
|
||||
|
||||
/* ----------------------------- Event Handlers (UI) ----------------------------- */
|
||||
@ -470,10 +470,10 @@ export class SettingsManager {
|
||||
|
||||
this._notify('success', 'Preset Set', result.message);
|
||||
|
||||
// Сброс UI калибровки
|
||||
// Reset calibration UI
|
||||
this._resetCalibrationStateForPresetChange();
|
||||
|
||||
// Обновить статус
|
||||
// Update status
|
||||
await this._loadStatus();
|
||||
} catch (e) {
|
||||
console.error('Set preset failed:', e);
|
||||
@ -521,7 +521,7 @@ export class SettingsManager {
|
||||
this.debouncer.debounce(key, () =>
|
||||
this.reqGuard.runExclusive(key, async () => {
|
||||
try {
|
||||
// Отметим стандарт как «занят»
|
||||
// Mark standard as busy
|
||||
this.disabledStandards.add(standard);
|
||||
|
||||
const btn = document.querySelector(`[data-standard="${standard}"]`);
|
||||
@ -695,13 +695,13 @@ export class SettingsManager {
|
||||
const modal = this.elements.plotsModal;
|
||||
if (!modal) return;
|
||||
|
||||
// Запомним пакет
|
||||
// Store data package
|
||||
this.currentPlotsData = plotsData;
|
||||
|
||||
// Рендер карточек/графиков
|
||||
// Render cards/plots
|
||||
this._renderCalibrationPlots(plotsData.individual_plots, plotsData.preset);
|
||||
|
||||
// Заголовок
|
||||
// Header
|
||||
const title = modal.querySelector('.modal__title');
|
||||
if (title) {
|
||||
title.innerHTML = `
|
||||
@ -711,10 +711,10 @@ export class SettingsManager {
|
||||
if (typeof lucide !== 'undefined') lucide.createIcons();
|
||||
}
|
||||
|
||||
// Кнопки закрытия/скачивания
|
||||
// Close/download buttons
|
||||
this._setupModalCloseHandlers(modal);
|
||||
|
||||
// Показ
|
||||
// Display
|
||||
modal.classList.add('modal--active');
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ export class StorageManager {
|
||||
debug: 'debug_info'
|
||||
};
|
||||
|
||||
console.log(`💾 Storage Manager initialized (${this.isAvailable ? 'available' : 'not available'})`);
|
||||
console.log(` Storage Manager initialized (${this.isAvailable ? 'available' : 'not available'})`);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -29,7 +29,7 @@ export class StorageManager {
|
||||
localStorage.removeItem(test);
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.warn('⚠️ localStorage not available:', e.message);
|
||||
console.warn('localStorage not available:', e.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -46,7 +46,7 @@ export class StorageManager {
|
||||
*/
|
||||
async save(key, data) {
|
||||
if (!this.isAvailable) {
|
||||
console.warn('⚠️ Storage not available, cannot save:', key);
|
||||
console.warn('Storage not available, cannot save:', key);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -58,24 +58,24 @@ export class StorageManager {
|
||||
});
|
||||
|
||||
localStorage.setItem(this.getKey(key), serialized);
|
||||
console.log(`💾 Saved to storage: ${key}`);
|
||||
console.log(` Saved to storage: ${key}`);
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to save to storage:', error);
|
||||
console.error('Failed to save to storage:', error);
|
||||
|
||||
// Handle quota exceeded error
|
||||
if (error.name === 'QuotaExceededError') {
|
||||
console.log('🧹 Storage quota exceeded, cleaning up...');
|
||||
console.log('Storage quota exceeded, cleaning up...');
|
||||
this.cleanup();
|
||||
|
||||
// Try again after cleanup
|
||||
try {
|
||||
localStorage.setItem(this.getKey(key), serialized);
|
||||
console.log(`💾 Saved to storage after cleanup: ${key}`);
|
||||
console.log(` Saved to storage after cleanup: ${key}`);
|
||||
return true;
|
||||
} catch (retryError) {
|
||||
console.error('❌ Still failed after cleanup:', retryError);
|
||||
console.error('Still failed after cleanup:', retryError);
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,7 +88,7 @@ export class StorageManager {
|
||||
*/
|
||||
async load(key) {
|
||||
if (!this.isAvailable) {
|
||||
console.warn('⚠️ Storage not available, cannot load:', key);
|
||||
console.warn('Storage not available, cannot load:', key);
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -102,16 +102,16 @@ export class StorageManager {
|
||||
|
||||
// Validate structure
|
||||
if (!parsed.data || !parsed.timestamp) {
|
||||
console.warn('⚠️ Invalid storage data format:', key);
|
||||
console.warn('Invalid storage data format:', key);
|
||||
this.remove(key); // Clean up invalid data
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log(`💾 Loaded from storage: ${key} (${new Date(parsed.timestamp).toLocaleString()})`);
|
||||
console.log(` Loaded from storage: ${key} (${new Date(parsed.timestamp).toLocaleString()})`);
|
||||
return parsed.data;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to load from storage:', error);
|
||||
console.error('Failed to load from storage:', error);
|
||||
this.remove(key); // Clean up corrupted data
|
||||
return null;
|
||||
}
|
||||
@ -125,10 +125,10 @@ export class StorageManager {
|
||||
|
||||
try {
|
||||
localStorage.removeItem(this.getKey(key));
|
||||
console.log(`🗑️ Removed from storage: ${key}`);
|
||||
console.log(` Removed from storage: ${key}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to remove from storage:', error);
|
||||
console.error('Failed to remove from storage:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -142,7 +142,7 @@ export class StorageManager {
|
||||
try {
|
||||
return localStorage.getItem(this.getKey(key)) !== null;
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to check storage existence:', error);
|
||||
console.error('Failed to check storage existence:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -215,7 +215,7 @@ export class StorageManager {
|
||||
|
||||
if (data && data.expiresAt) {
|
||||
if (Date.now() > data.expiresAt) {
|
||||
console.log('🕒 Session data expired, removing...');
|
||||
console.log('Session data expired, removing...');
|
||||
await this.remove(this.keys.session);
|
||||
return null;
|
||||
}
|
||||
@ -278,7 +278,7 @@ export class StorageManager {
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to calculate storage stats:', error);
|
||||
console.error('Failed to calculate storage stats:', error);
|
||||
return { available: false, error: error.message };
|
||||
}
|
||||
}
|
||||
@ -310,7 +310,7 @@ export class StorageManager {
|
||||
async cleanup() {
|
||||
if (!this.isAvailable) return;
|
||||
|
||||
console.log('🧹 Cleaning up storage...');
|
||||
console.log('Cleaning up storage...');
|
||||
|
||||
try {
|
||||
const keysToRemove = [];
|
||||
@ -339,13 +339,13 @@ export class StorageManager {
|
||||
// Remove identified keys
|
||||
keysToRemove.forEach(key => {
|
||||
localStorage.removeItem(key);
|
||||
console.log(`🗑️ Cleaned up: ${key}`);
|
||||
console.log(` Cleaned up: ${key}`);
|
||||
});
|
||||
|
||||
console.log(`🧹 Cleanup complete. Removed ${keysToRemove.length} items.`);
|
||||
console.log(` Cleanup complete. Removed ${keysToRemove.length} items.`);
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Cleanup failed:', error);
|
||||
console.error('Cleanup failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@ -355,7 +355,7 @@ export class StorageManager {
|
||||
async clearAll() {
|
||||
if (!this.isAvailable) return false;
|
||||
|
||||
console.log('🗑️ Clearing all storage data...');
|
||||
console.log('Clearing all storage data...');
|
||||
|
||||
try {
|
||||
const keysToRemove = [];
|
||||
@ -373,11 +373,11 @@ export class StorageManager {
|
||||
localStorage.removeItem(key);
|
||||
});
|
||||
|
||||
console.log(`🗑️ Cleared ${keysToRemove.length} items from storage`);
|
||||
console.log(` Cleared ${keysToRemove.length} items from storage`);
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to clear storage:', error);
|
||||
console.error('Failed to clear storage:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -405,11 +405,11 @@ export class StorageManager {
|
||||
}
|
||||
}
|
||||
|
||||
console.log('📤 Exported storage data');
|
||||
console.log('Exported storage data');
|
||||
return exportData;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to export data:', error);
|
||||
console.error('Failed to export data:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -431,11 +431,11 @@ export class StorageManager {
|
||||
localStorage.setItem(fullKey, JSON.stringify(value));
|
||||
}
|
||||
|
||||
console.log(`📥 Imported ${Object.keys(importData.data).length} items`);
|
||||
console.log(` Imported ${Object.keys(importData.data).length} items`);
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to import data:', error);
|
||||
console.error('Failed to import data:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -444,10 +444,10 @@ export class StorageManager {
|
||||
* Cleanup on destroy
|
||||
*/
|
||||
destroy() {
|
||||
console.log('🧹 Storage Manager cleanup...');
|
||||
console.log('Storage Manager cleanup...');
|
||||
// Perform any necessary cleanup
|
||||
// For now, just run a cleanup to free up space
|
||||
this.cleanup();
|
||||
console.log('✅ Storage Manager cleanup complete');
|
||||
console.log('Storage Manager cleanup complete');
|
||||
}
|
||||
}
|
||||
@ -38,7 +38,7 @@ export class UIManager {
|
||||
* Initialize UI Manager
|
||||
*/
|
||||
async init() {
|
||||
console.log('🎨 Initializing UI Manager...');
|
||||
console.log('Initializing UI Manager...');
|
||||
|
||||
// Get DOM elements
|
||||
this.findElements();
|
||||
@ -59,7 +59,7 @@ export class UIManager {
|
||||
this.websocket.on('processor_result', (payload) => this.onProcessorResult(payload));
|
||||
}
|
||||
|
||||
console.log('✅ UI Manager initialized');
|
||||
console.log('UI Manager initialized');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -263,12 +263,12 @@ export class UIManager {
|
||||
}
|
||||
|
||||
handleResize() {
|
||||
console.log('📱 Window resized');
|
||||
console.log('Window resized');
|
||||
// Charts handle their own resize
|
||||
}
|
||||
|
||||
// System status and theme methods simplified
|
||||
updateSystemStatus(statusData) { console.log('📊 System status:', statusData); }
|
||||
updateSystemStatus(statusData) { console.log('System status:', statusData); }
|
||||
setTheme(theme) { document.documentElement.setAttribute('data-theme', theme); }
|
||||
getCurrentTheme() { return document.documentElement.getAttribute('data-theme') || 'dark'; }
|
||||
|
||||
@ -280,7 +280,7 @@ export class UIManager {
|
||||
if (this.eventHandlers[eventType]) {
|
||||
this.eventHandlers[eventType].forEach(handler => {
|
||||
try { handler(...args); }
|
||||
catch (error) { console.error(`❌ Error in ${eventType} handler:`, error); }
|
||||
catch (error) { console.error(` Error in ${eventType} handler:`, error); }
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -294,7 +294,7 @@ export class UIManager {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
console.log('🧹 Cleaning up UI Manager...');
|
||||
console.log('Cleaning up UI Manager...');
|
||||
|
||||
// Clear event handlers
|
||||
Object.keys(this.eventHandlers).forEach(key => {
|
||||
@ -304,6 +304,6 @@ export class UIManager {
|
||||
// Clear processors
|
||||
this.processors.clear();
|
||||
|
||||
console.log('✅ UI Manager cleanup complete');
|
||||
console.log('UI Manager cleanup complete');
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,47 +120,21 @@ export class ButtonState {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set button to loading state with animation
|
||||
* Set button to disabled state during request
|
||||
* @param {HTMLElement} button - Button element
|
||||
* @param {boolean} loading - Whether to set loading state
|
||||
* @param {boolean} loading - Whether to disable button
|
||||
* @param {Object} originalState - Original button state to restore
|
||||
*/
|
||||
export function setButtonLoading(button, loading, originalState = {}) {
|
||||
if (!button) return;
|
||||
if (!button) return originalState;
|
||||
|
||||
if (loading) {
|
||||
// Save original state if not provided
|
||||
if (!originalState.text) {
|
||||
originalState.text = button.textContent;
|
||||
originalState.icon = button.querySelector('i')?.getAttribute('data-lucide');
|
||||
if (!originalState.disabled) {
|
||||
originalState.disabled = button.disabled;
|
||||
}
|
||||
|
||||
button.disabled = true;
|
||||
button.classList.add('loading');
|
||||
|
||||
const icon = button.querySelector('i');
|
||||
if (icon) {
|
||||
icon.setAttribute('data-lucide', 'loader-2');
|
||||
icon.style.animation = 'spin 1s linear infinite';
|
||||
}
|
||||
|
||||
if (window.lucide) {
|
||||
window.lucide.createIcons();
|
||||
}
|
||||
} else {
|
||||
button.disabled = false;
|
||||
button.classList.remove('loading');
|
||||
|
||||
const icon = button.querySelector('i');
|
||||
if (icon) {
|
||||
icon.style.animation = '';
|
||||
if (originalState.icon) {
|
||||
icon.setAttribute('data-lucide', originalState.icon);
|
||||
if (window.lucide) {
|
||||
window.lucide.createIcons();
|
||||
}
|
||||
}
|
||||
}
|
||||
button.disabled = originalState.disabled || false;
|
||||
}
|
||||
|
||||
return originalState;
|
||||
|
||||
@ -33,7 +33,7 @@ export class WebSocketManager {
|
||||
|
||||
async connect() {
|
||||
if (this.isConnected || this.isConnecting) {
|
||||
console.log('🔌 WebSocket already connected/connecting');
|
||||
console.log('WebSocket already connected/connecting');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ export class WebSocketManager {
|
||||
this.isConnecting = true;
|
||||
this.emit('connecting');
|
||||
|
||||
console.log(`🔌 Connecting to WebSocket: ${this.config.url}`);
|
||||
console.log(` Connecting to WebSocket: ${this.config.url}`);
|
||||
|
||||
this.ws = new WebSocket(this.config.url);
|
||||
this.setupWebSocketEvents();
|
||||
@ -49,7 +49,7 @@ export class WebSocketManager {
|
||||
await this.waitForConnection(5000);
|
||||
} catch (error) {
|
||||
this.isConnecting = false;
|
||||
console.error('❌ WebSocket connection failed:', error);
|
||||
console.error('WebSocket connection failed:', error);
|
||||
this.handleConnectionError(error);
|
||||
throw error;
|
||||
}
|
||||
@ -85,7 +85,7 @@ export class WebSocketManager {
|
||||
if (!this.ws) return;
|
||||
|
||||
this.ws.onopen = (event) => {
|
||||
console.log('✅ WebSocket connected');
|
||||
console.log('WebSocket connected');
|
||||
this.isConnected = true;
|
||||
this.isConnecting = false;
|
||||
this.reconnectAttempts = 0;
|
||||
@ -106,7 +106,7 @@ export class WebSocketManager {
|
||||
try {
|
||||
this.handleMessage(event.data);
|
||||
} catch (error) {
|
||||
console.error('❌ Error processing WebSocket message:', error);
|
||||
console.error('Error processing WebSocket message:', error);
|
||||
this.notifications?.show?.({
|
||||
type: 'error',
|
||||
title: 'Message Error',
|
||||
@ -116,12 +116,12 @@ export class WebSocketManager {
|
||||
};
|
||||
|
||||
this.ws.onerror = (error) => {
|
||||
console.error('❌ WebSocket error:', error);
|
||||
console.error('WebSocket error:', error);
|
||||
this.handleConnectionError(error);
|
||||
};
|
||||
|
||||
this.ws.onclose = (event) => {
|
||||
console.log('🔌 WebSocket closed:', event.code, event.reason);
|
||||
console.log('WebSocket closed:', event.code, event.reason);
|
||||
this.handleDisconnection(event);
|
||||
};
|
||||
}
|
||||
@ -134,7 +134,7 @@ export class WebSocketManager {
|
||||
|
||||
try {
|
||||
if (typeof data !== 'string') {
|
||||
console.warn('⚠️ Received non-text message, ignoring');
|
||||
console.warn('Received non-text message, ignoring');
|
||||
return;
|
||||
}
|
||||
if (data === 'ping') { this.handlePing(); return; }
|
||||
@ -144,7 +144,7 @@ export class WebSocketManager {
|
||||
try {
|
||||
payload = JSON.parse(data);
|
||||
} catch (jsonError) {
|
||||
console.error('❌ Invalid JSON format:', data);
|
||||
console.error('Invalid JSON format:', data);
|
||||
console.error('JSON parse error:', jsonError);
|
||||
this.notifications?.show?.({
|
||||
type: 'error',
|
||||
@ -154,7 +154,7 @@ export class WebSocketManager {
|
||||
return;
|
||||
}
|
||||
|
||||
// Публичное событие «data» — для всего, плюс более точечные:
|
||||
// Public "data" event for everything, plus more specific ones:
|
||||
this.emit('data', payload);
|
||||
|
||||
switch (payload.type) {
|
||||
@ -165,8 +165,8 @@ export class WebSocketManager {
|
||||
this.emit('processor_history', payload);
|
||||
break;
|
||||
case 'error':
|
||||
console.error('🔴 Server error:', payload);
|
||||
console.error('🔴 Error details:', {
|
||||
console.error('Server error:', payload);
|
||||
console.error('Error details:', {
|
||||
message: payload.message,
|
||||
code: payload.code,
|
||||
details: payload.details,
|
||||
@ -180,11 +180,11 @@ export class WebSocketManager {
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.warn('⚠️ Unknown payload type:', payload.type);
|
||||
console.warn('Unknown payload type:', payload.type);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('❌ Failed to parse WebSocket JSON:', e);
|
||||
console.log('📝 Raw message:', data);
|
||||
console.error('Failed to parse WebSocket JSON:', e);
|
||||
console.log('Raw message:', data);
|
||||
this.notifications?.show?.({
|
||||
type: 'error',
|
||||
title: 'Message Processing Error',
|
||||
@ -205,7 +205,7 @@ export class WebSocketManager {
|
||||
}
|
||||
handlePong() {
|
||||
if (this.lastPing) {
|
||||
console.log(`🏓 WebSocket latency: ${Date.now() - this.lastPing}ms`);
|
||||
console.log(` WebSocket latency: ${Date.now() - this.lastPing}ms`);
|
||||
this.lastPing = null;
|
||||
}
|
||||
}
|
||||
@ -251,7 +251,7 @@ export class WebSocketManager {
|
||||
scheduleReconnect() {
|
||||
if (this.reconnectTimer) return;
|
||||
const delay = Math.min(this.config.reconnectInterval * Math.pow(2, this.reconnectAttempts), 30000);
|
||||
console.log(`🔄 Scheduling reconnect in ${delay}ms (attempt ${this.reconnectAttempts + 1})`);
|
||||
console.log(` Scheduling reconnect in ${delay}ms (attempt ${this.reconnectAttempts + 1})`);
|
||||
this.reconnectTimer = setTimeout(() => {
|
||||
this.reconnectTimer = null;
|
||||
this.reconnect();
|
||||
@ -260,7 +260,7 @@ export class WebSocketManager {
|
||||
|
||||
async reconnect() {
|
||||
if (this.reconnectAttempts >= this.config.maxReconnectAttempts) {
|
||||
console.error('❌ Max reconnection attempts reached');
|
||||
console.error('Max reconnection attempts reached');
|
||||
this.notifications?.show?.({
|
||||
type: 'error',
|
||||
title: 'Connection Failed',
|
||||
@ -271,16 +271,16 @@ export class WebSocketManager {
|
||||
this.reconnectAttempts++;
|
||||
if (this.ws) { this.ws.close(); this.ws = null; }
|
||||
try { await this.connect(); }
|
||||
catch (error) { console.error(`❌ Reconnection attempt ${this.reconnectAttempts} failed:`, error); this.scheduleReconnect(); }
|
||||
catch (error) { console.error(` Reconnection attempt ${this.reconnectAttempts} failed:`, error); this.scheduleReconnect(); }
|
||||
}
|
||||
|
||||
send(data) {
|
||||
if (!this.isConnected || !this.ws) {
|
||||
if (this.messageQueue.length < this.maxQueueSize) {
|
||||
this.messageQueue.push(data);
|
||||
console.log('📤 Message queued (not connected)');
|
||||
console.log('Message queued (not connected)');
|
||||
} else {
|
||||
console.warn('⚠️ Message queue full, dropping message');
|
||||
console.warn('Message queue full, dropping message');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -289,22 +289,22 @@ export class WebSocketManager {
|
||||
this.ws.send(msg);
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error('❌ Failed to send message:', e);
|
||||
console.error('Failed to send message:', e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
processPendingMessages() {
|
||||
if (this.messageQueue.length === 0) return;
|
||||
console.log(`📤 Processing ${this.messageQueue.length} queued messages`);
|
||||
console.log(` Processing ${this.messageQueue.length} queued messages`);
|
||||
const messages = [...this.messageQueue];
|
||||
this.messageQueue = [];
|
||||
messages.forEach(m => this.send(m));
|
||||
}
|
||||
|
||||
// === ПУБЛИЧНОЕ API ДЛЯ СОВМЕСТИМОСТИ С БЭКЕНДОМ ===
|
||||
// === PUBLIC API FOR BACKEND COMPATIBILITY ===
|
||||
|
||||
/** Запросить пересчёт с обновлением конфигурации (СУЩЕСТВУЕТ НА БЭКЕНДЕ) */
|
||||
/** Request recalculation with config update (EXISTS ON BACKEND) */
|
||||
recalculate(processorId, configUpdates = undefined) {
|
||||
return this.send({
|
||||
type: 'recalculate',
|
||||
@ -313,7 +313,7 @@ export class WebSocketManager {
|
||||
});
|
||||
}
|
||||
|
||||
/** Получить историю результатов процессора (СУЩЕСТВУЕТ НА БЭКЕНДЕ) */
|
||||
/** Get processor results history (EXISTS ON BACKEND) */
|
||||
getHistory(processorId, limit = 10) {
|
||||
return this.send({
|
||||
type: 'get_history',
|
||||
@ -336,12 +336,12 @@ export class WebSocketManager {
|
||||
emit(event, data) {
|
||||
if (!this.eventListeners.has(event)) return;
|
||||
this.eventListeners.get(event).forEach(cb => {
|
||||
try { cb(data); } catch (e) { console.error(`❌ Error in event listener for ${event}:`, e); }
|
||||
try { cb(data); } catch (e) { console.error(` Error in event listener for ${event}:`, e); }
|
||||
});
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
console.log('🔌 Disconnecting WebSocket');
|
||||
console.log('Disconnecting WebSocket');
|
||||
if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; }
|
||||
if (this.pingTimer) { clearInterval(this.pingTimer); this.pingTimer = null; }
|
||||
if (this.ws) { this.ws.close(1000, 'Manual disconnect'); this.ws = null; }
|
||||
|
||||
Reference in New Issue
Block a user