updated view and added calibration deletion
This commit is contained in:
@ -621,3 +621,33 @@ async def delete_reference(reference_name: str, preset_filename: str | None = No
|
|||||||
logger.error("Failed to delete reference", name=reference_name, error=repr(exc))
|
logger.error("Failed to delete reference", name=reference_name, error=repr(exc))
|
||||||
raise HTTPException(status_code=500, detail=str(exc))
|
raise HTTPException(status_code=500, detail=str(exc))
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete("/calibration/{calibration_name}")
|
||||||
|
async def delete_calibration(calibration_name: str, preset_filename: str | None = None) -> dict[str, Any]:
|
||||||
|
"""Delete a calibration set."""
|
||||||
|
try:
|
||||||
|
settings_manager = singletons.settings_manager
|
||||||
|
|
||||||
|
if preset_filename:
|
||||||
|
preset = next(
|
||||||
|
(p for p in settings_manager.get_available_presets() if p.filename == preset_filename),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
if not preset:
|
||||||
|
raise HTTPException(status_code=404, detail=f"Preset '{preset_filename}' not found")
|
||||||
|
else:
|
||||||
|
preset = settings_manager.get_current_preset()
|
||||||
|
if not preset:
|
||||||
|
raise HTTPException(status_code=400, detail="No current preset set and no preset_filename provided")
|
||||||
|
|
||||||
|
settings_manager.delete_calibration(preset, calibration_name)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"message": f"Calibration '{calibration_name}' deleted"
|
||||||
|
}
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as exc: # noqa: BLE001
|
||||||
|
logger.error("Failed to delete calibration", name=calibration_name, error=repr(exc))
|
||||||
|
raise HTTPException(status_code=500, detail=str(exc))
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
config_inputs/s21_start100_stop8800_points1000_bw1khz.bin
|
config_inputs/s11_start100_stop8800_points1000_bw1khz.bin
|
||||||
1
vna_system/calibration/current_calibration
Symbolic link
1
vna_system/calibration/current_calibration
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
s11_start100_stop8800_points1000_bw1khz/еуыеуые
|
||||||
@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"preset": {
|
|
||||||
"filename": "s11_start100_stop8800_points1000_bw1khz.bin",
|
|
||||||
"mode": "s11",
|
|
||||||
"start_freq": 100000000.0,
|
|
||||||
"stop_freq": 8800000000.0,
|
|
||||||
"points": 1000,
|
|
||||||
"bandwidth": 1000.0
|
|
||||||
},
|
|
||||||
"calibration_name": "яыф",
|
|
||||||
"standards": [
|
|
||||||
"open",
|
|
||||||
"load",
|
|
||||||
"short"
|
|
||||||
],
|
|
||||||
"created_timestamp": "2025-09-26T17:20:00.022650",
|
|
||||||
"is_complete": true
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"preset": {
|
|
||||||
"filename": "s11_start100_stop8800_points1000_bw1khz.bin",
|
|
||||||
"mode": "s11",
|
|
||||||
"start_freq": 100000000.0,
|
|
||||||
"stop_freq": 8800000000.0,
|
|
||||||
"points": 1000,
|
|
||||||
"bandwidth": 1000.0
|
|
||||||
},
|
|
||||||
"calibration_name": "яыф",
|
|
||||||
"standard": "load",
|
|
||||||
"sweep_number": 12,
|
|
||||||
"sweep_timestamp": 1758896376.33808,
|
|
||||||
"created_timestamp": "2025-09-26T17:20:00.020322",
|
|
||||||
"total_points": 1000
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"preset": {
|
|
||||||
"filename": "s11_start100_stop8800_points1000_bw1khz.bin",
|
|
||||||
"mode": "s11",
|
|
||||||
"start_freq": 100000000.0,
|
|
||||||
"stop_freq": 8800000000.0,
|
|
||||||
"points": 1000,
|
|
||||||
"bandwidth": 1000.0
|
|
||||||
},
|
|
||||||
"calibration_name": "яыф",
|
|
||||||
"standard": "open",
|
|
||||||
"sweep_number": 17,
|
|
||||||
"sweep_timestamp": 1758896395.4880857,
|
|
||||||
"created_timestamp": "2025-09-26T17:20:00.016886",
|
|
||||||
"total_points": 1000
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"preset": {
|
|
||||||
"filename": "s11_start100_stop8800_points1000_bw1khz.bin",
|
|
||||||
"mode": "s11",
|
|
||||||
"start_freq": 100000000.0,
|
|
||||||
"stop_freq": 8800000000.0,
|
|
||||||
"points": 1000,
|
|
||||||
"bandwidth": 1000.0
|
|
||||||
},
|
|
||||||
"calibration_name": "яыф",
|
|
||||||
"standard": "short",
|
|
||||||
"sweep_number": 13,
|
|
||||||
"sweep_timestamp": 1758896378.4093437,
|
|
||||||
"created_timestamp": "2025-09-26T17:20:00.022500",
|
|
||||||
"total_points": 1000
|
|
||||||
}
|
|
||||||
@ -2,9 +2,9 @@
|
|||||||
"open_air": true,
|
"open_air": true,
|
||||||
"axis": "abs",
|
"axis": "abs",
|
||||||
"data_limitation": "ph_only_1",
|
"data_limitation": "ph_only_1",
|
||||||
"cut": 1.291,
|
"cut": 2.0,
|
||||||
"max": 1.0,
|
"max": 5.0,
|
||||||
"gain": 0.9,
|
"gain": 2.2,
|
||||||
"start_freq": 100.0,
|
"start_freq": 100.0,
|
||||||
"stop_freq": 8800.0,
|
"stop_freq": 8800.0,
|
||||||
"clear_history": false,
|
"clear_history": false,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"y_min": -80,
|
"y_min": -80,
|
||||||
"y_max": 40,
|
"y_max": 40,
|
||||||
"show_phase": true
|
"show_phase": false
|
||||||
}
|
}
|
||||||
@ -183,6 +183,10 @@ class BScanProcessor(BaseProcessor):
|
|||||||
latest_history = self._sweep_history[-1]
|
latest_history = self._sweep_history[-1]
|
||||||
reference_data = latest_history.get("reference_data")
|
reference_data = latest_history.get("reference_data")
|
||||||
|
|
||||||
|
if reference_data is None:
|
||||||
|
logger.warning(f"Open air substraction cannot be done: reference_data is None")
|
||||||
|
self._config["open_air"] = False
|
||||||
|
|
||||||
if self._config["open_air"] and reference_data is not None:
|
if self._config["open_air"] and reference_data is not None:
|
||||||
reference_complex = self._get_complex_s11(reference_data)
|
reference_complex = self._get_complex_s11(reference_data)
|
||||||
if reference_complex is not None and reference_complex.size:
|
if reference_complex is not None and reference_complex.size:
|
||||||
|
|||||||
@ -188,6 +188,10 @@ class VNASettingsManager:
|
|||||||
raise ValueError("No current preset available")
|
raise ValueError("No current preset available")
|
||||||
return self.reference_manager.delete_reference(reference_name, current_preset)
|
return self.reference_manager.delete_reference(reference_name, current_preset)
|
||||||
|
|
||||||
|
def delete_calibration(self, preset: ConfigPreset, calibration_name: str) -> None:
|
||||||
|
"""Delete a saved calibration for the given preset."""
|
||||||
|
self.calibration_manager.delete_calibration(preset, calibration_name)
|
||||||
|
|
||||||
# ------------------------------------------------------------------ #
|
# ------------------------------------------------------------------ #
|
||||||
# Acquisition integration
|
# Acquisition integration
|
||||||
# ------------------------------------------------------------------ #
|
# ------------------------------------------------------------------ #
|
||||||
|
|||||||
@ -74,15 +74,6 @@ else
|
|||||||
log_warning "Consider creating a virtual environment: python3 -m venv venv"
|
log_warning "Consider creating a virtual environment: python3 -m venv venv"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check configuration files
|
|
||||||
if [ ! -f "vna_system/api/api_config.json" ]; then
|
|
||||||
log_warning "API config not found. Using defaults."
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f "vna_system/core/processing/config.json" ]; then
|
|
||||||
log_warning "Processing config not found. Some processors may not work."
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Start the server
|
# Start the server
|
||||||
log_info "Starting VNA System API server..."
|
log_info "Starting VNA System API server..."
|
||||||
log_info "Press Ctrl+C to stop the server"
|
log_info "Press Ctrl+C to stop the server"
|
||||||
|
|||||||
@ -518,61 +518,40 @@
|
|||||||
margin-top: var(--space-3);
|
margin-top: var(--space-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Current Reference Info */
|
/* Reference details */
|
||||||
.current-reference-info {
|
|
||||||
margin-top: var(--space-4);
|
|
||||||
padding-top: var(--space-4);
|
|
||||||
border-top: 1px solid var(--color-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.reference-info-card {
|
|
||||||
background: var(--color-gray-800);
|
|
||||||
border: 1px solid var(--color-gray-600);
|
|
||||||
border-radius: var(--radius-lg);
|
|
||||||
padding: var(--space-4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.reference-info-card h5 {
|
|
||||||
margin: 0 0 var(--space-3) 0;
|
|
||||||
font-size: var(--text-sm);
|
|
||||||
font-weight: var(--weight-semibold);
|
|
||||||
color: var(--color-gray-300);
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.05em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reference-details {
|
.reference-details {
|
||||||
|
margin-top: var(--space-3);
|
||||||
|
padding: var(--space-3);
|
||||||
|
border-radius: var(--radius-md);
|
||||||
|
border: 1px solid var(--border-primary);
|
||||||
|
background: var(--bg-surface);
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--space-2);
|
gap: var(--space-2);
|
||||||
background: var(--color-gray-900);
|
|
||||||
padding: var(--space-3);
|
|
||||||
border-radius: var(--radius-md);
|
|
||||||
border: 1px solid var(--color-gray-700);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.reference-name {
|
.reference-details__row {
|
||||||
font-size: var(--text-base);
|
display: flex;
|
||||||
font-weight: var(--weight-semibold);
|
gap: var(--space-2);
|
||||||
color: var(--color-white);
|
font-size: var(--font-size-sm);
|
||||||
|
align-items: baseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reference-timestamp {
|
.reference-details__label {
|
||||||
font-size: var(--text-sm);
|
min-width: 90px;
|
||||||
color: var(--color-gray-300);
|
color: var(--text-secondary);
|
||||||
font-family: var(--font-mono);
|
font-weight: var(--font-weight-medium);
|
||||||
}
|
}
|
||||||
|
|
||||||
.reference-description {
|
.reference-details__value {
|
||||||
margin: 0;
|
color: var(--text-primary);
|
||||||
font-size: var(--text-sm);
|
flex: 1 1 auto;
|
||||||
color: var(--color-gray-400);
|
word-break: break-word;
|
||||||
font-style: italic;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.reference-description:empty::before {
|
.reference-details__row--description {
|
||||||
content: "Описание не указано";
|
align-items: flex-start;
|
||||||
opacity: 0.7;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Responsive adjustments */
|
/* Responsive adjustments */
|
||||||
|
|||||||
@ -121,17 +121,21 @@ export class AcquisitionManager {
|
|||||||
async updateStatus() {
|
async updateStatus() {
|
||||||
try {
|
try {
|
||||||
const status = await apiGet(API.ACQUISITION.STATUS);
|
const status = await apiGet(API.ACQUISITION.STATUS);
|
||||||
|
const normalized = { ...status, connected: true };
|
||||||
|
|
||||||
this.currentStatus = status;
|
this.currentStatus = normalized;
|
||||||
this.updateUI(status);
|
this.updateUI(normalized);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error getting acquisition status:', error);
|
console.error('Error getting acquisition status:', error);
|
||||||
this.updateUI({
|
const fallback = {
|
||||||
running: false,
|
running: false,
|
||||||
paused: false,
|
paused: false,
|
||||||
continuous_mode: true,
|
continuous_mode: true,
|
||||||
sweep_count: 0
|
sweep_count: 0,
|
||||||
});
|
connected: false
|
||||||
|
};
|
||||||
|
this.currentStatus = fallback;
|
||||||
|
this.updateUI(fallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,6 +180,20 @@ export class AcquisitionManager {
|
|||||||
this.elements.singleSweepBtn.disabled = false;
|
this.elements.singleSweepBtn.disabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const systemStatusEl = document.getElementById('systemStatus');
|
||||||
|
if (systemStatusEl) {
|
||||||
|
if (status.connected === false) {
|
||||||
|
systemStatusEl.textContent = 'Не подключено';
|
||||||
|
} else {
|
||||||
|
const mode = status.continuous_mode ? 'Непрерывный' : 'Одиночный';
|
||||||
|
let suffix = ' (остановлен)';
|
||||||
|
if (status.running) {
|
||||||
|
suffix = status.paused ? ' (пауза)' : ' (запущен)';
|
||||||
|
}
|
||||||
|
systemStatusEl.textContent = `Режим: ${mode}${suffix}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update sweep count in header if available
|
// Update sweep count in header if available
|
||||||
const sweepCountEl = document.getElementById('sweepCount');
|
const sweepCountEl = document.getElementById('sweepCount');
|
||||||
if (sweepCountEl) {
|
if (sweepCountEl) {
|
||||||
|
|||||||
@ -75,6 +75,7 @@ export const API = {
|
|||||||
CALIBRATION_START: `${API_BASE}/settings/calibration/start`,
|
CALIBRATION_START: `${API_BASE}/settings/calibration/start`,
|
||||||
CALIBRATION_SAVE: `${API_BASE}/settings/calibration/save`,
|
CALIBRATION_SAVE: `${API_BASE}/settings/calibration/save`,
|
||||||
CALIBRATION_SET: `${API_BASE}/settings/calibration/set`,
|
CALIBRATION_SET: `${API_BASE}/settings/calibration/set`,
|
||||||
|
CALIBRATION_DELETE: (name) => `${API_BASE}/settings/calibration/${encodeURIComponent(name)}`,
|
||||||
CALIBRATION_ADD_STANDARD: `${API_BASE}/settings/calibration/add-standard`,
|
CALIBRATION_ADD_STANDARD: `${API_BASE}/settings/calibration/add-standard`,
|
||||||
CALIBRATION_STANDARDS_PLOTS: (name) => `${API_BASE}/settings/calibration/${encodeURIComponent(name)}/standards-plots`,
|
CALIBRATION_STANDARDS_PLOTS: (name) => `${API_BASE}/settings/calibration/${encodeURIComponent(name)}/standards-plots`,
|
||||||
|
|
||||||
|
|||||||
@ -76,6 +76,7 @@ export class SettingsManager {
|
|||||||
calibrationDropdown: document.getElementById('calibrationDropdown'),
|
calibrationDropdown: document.getElementById('calibrationDropdown'),
|
||||||
setCalibrationBtn: document.getElementById('setCalibrationBtn'),
|
setCalibrationBtn: document.getElementById('setCalibrationBtn'),
|
||||||
viewPlotsBtn: document.getElementById('viewPlotsBtn'),
|
viewPlotsBtn: document.getElementById('viewPlotsBtn'),
|
||||||
|
deleteCalibrationBtn: document.getElementById('deleteCalibrationBtn'),
|
||||||
viewCurrentPlotsBtn: document.getElementById('viewCurrentPlotsBtn'),
|
viewCurrentPlotsBtn: document.getElementById('viewCurrentPlotsBtn'),
|
||||||
|
|
||||||
// Modal
|
// Modal
|
||||||
@ -91,6 +92,7 @@ export class SettingsManager {
|
|||||||
setReferenceBtn: document.getElementById('setReferenceBtn'),
|
setReferenceBtn: document.getElementById('setReferenceBtn'),
|
||||||
clearReferenceBtn: document.getElementById('clearReferenceBtn'),
|
clearReferenceBtn: document.getElementById('clearReferenceBtn'),
|
||||||
deleteReferenceBtn: document.getElementById('deleteReferenceBtn'),
|
deleteReferenceBtn: document.getElementById('deleteReferenceBtn'),
|
||||||
|
previewReferenceBtn: document.getElementById('previewReferenceBtn'),
|
||||||
currentReferenceInfo: document.getElementById('currentReferenceInfo'),
|
currentReferenceInfo: document.getElementById('currentReferenceInfo'),
|
||||||
currentReferenceName: document.getElementById('currentReferenceName'),
|
currentReferenceName: document.getElementById('currentReferenceName'),
|
||||||
currentReferenceTimestamp: document.getElementById('currentReferenceTimestamp'),
|
currentReferenceTimestamp: document.getElementById('currentReferenceTimestamp'),
|
||||||
@ -99,6 +101,7 @@ export class SettingsManager {
|
|||||||
// Status
|
// Status
|
||||||
presetCount: document.getElementById('presetCount'),
|
presetCount: document.getElementById('presetCount'),
|
||||||
calibrationCount: document.getElementById('calibrationCount'),
|
calibrationCount: document.getElementById('calibrationCount'),
|
||||||
|
referenceCount: document.getElementById('referenceCount'),
|
||||||
systemStatus: document.getElementById('systemStatus')
|
systemStatus: document.getElementById('systemStatus')
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -158,7 +161,7 @@ export class SettingsManager {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Status load failed:', e);
|
console.error('Status load failed:', e);
|
||||||
if (this.elements.systemStatus) {
|
if (this.elements.systemStatus) {
|
||||||
this.elements.systemStatus.textContent = 'Ошибка';
|
this.elements.systemStatus.textContent = 'Не подключено';
|
||||||
}
|
}
|
||||||
this.notify(ERROR, 'Ошибка статуса', 'Не удалось получить текущее состояние системы');
|
this.notify(ERROR, 'Ошибка статуса', 'Не удалось получить текущее состояние системы');
|
||||||
return null;
|
return null;
|
||||||
@ -191,7 +194,7 @@ export class SettingsManager {
|
|||||||
await this.calibrationManager.loadWorkingCalibration();
|
await this.calibrationManager.loadWorkingCalibration();
|
||||||
|
|
||||||
if (!status && this.elements.systemStatus) {
|
if (!status && this.elements.systemStatus) {
|
||||||
this.elements.systemStatus.textContent = 'Готово';
|
this.elements.systemStatus.textContent = 'Не подключено';
|
||||||
}
|
}
|
||||||
|
|
||||||
const effectiveStatus = {
|
const effectiveStatus = {
|
||||||
@ -206,6 +209,9 @@ export class SettingsManager {
|
|||||||
if (this.elements.calibrationCount) {
|
if (this.elements.calibrationCount) {
|
||||||
this.elements.calibrationCount.textContent = effectiveStatus.available_calibrations ?? '-';
|
this.elements.calibrationCount.textContent = effectiveStatus.available_calibrations ?? '-';
|
||||||
}
|
}
|
||||||
|
if (this.elements.referenceCount) {
|
||||||
|
this.elements.referenceCount.textContent = '-';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateHeaderSummary(effectiveStatus);
|
this.updateHeaderSummary(effectiveStatus);
|
||||||
@ -227,10 +233,10 @@ export class SettingsManager {
|
|||||||
if (this.elements.calibrationCount) {
|
if (this.elements.calibrationCount) {
|
||||||
this.elements.calibrationCount.textContent = status?.available_calibrations ?? '-';
|
this.elements.calibrationCount.textContent = status?.available_calibrations ?? '-';
|
||||||
}
|
}
|
||||||
if (this.elements.systemStatus) {
|
if (this.elements.referenceCount) {
|
||||||
this.elements.systemStatus.textContent = 'Готово';
|
const count = this.referenceManager?.availableReferences?.length;
|
||||||
|
this.elements.referenceCount.textContent = typeof count === 'number' ? count : '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateHeaderSummary(status);
|
this.updateHeaderSummary(status);
|
||||||
this.updateReferenceSummary(this.referenceManager.getCurrentReference());
|
this.updateReferenceSummary(this.referenceManager.getCurrentReference());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import { Debouncer, RequestGuard, ButtonState } from '../utils.js';
|
import { Debouncer, RequestGuard, ButtonState } from '../utils.js';
|
||||||
import { renderIcons } from '../icons.js';
|
import { renderIcons } from '../icons.js';
|
||||||
import { apiGet, apiPost, buildUrl } from '../api-client.js';
|
import { apiGet, apiPost, apiDelete, buildUrl } from '../api-client.js';
|
||||||
import { API, TIMING, CALIBRATION_STANDARDS, NOTIFICATION_TYPES } from '../constants.js';
|
import { API, TIMING, CALIBRATION_STANDARDS, NOTIFICATION_TYPES } from '../constants.js';
|
||||||
|
|
||||||
const { SUCCESS, ERROR, INFO } = NOTIFICATION_TYPES;
|
const { SUCCESS, ERROR, INFO } = NOTIFICATION_TYPES;
|
||||||
@ -25,6 +25,7 @@ export class CalibrationManager {
|
|||||||
this.handleSaveCalibration = this.handleSaveCalibration.bind(this);
|
this.handleSaveCalibration = this.handleSaveCalibration.bind(this);
|
||||||
this.handleSetCalibration = this.handleSetCalibration.bind(this);
|
this.handleSetCalibration = this.handleSetCalibration.bind(this);
|
||||||
this.handleCalibrationChange = this.handleCalibrationChange.bind(this);
|
this.handleCalibrationChange = this.handleCalibrationChange.bind(this);
|
||||||
|
this.handleDeleteCalibration = this.handleDeleteCalibration.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
init(elements) {
|
init(elements) {
|
||||||
@ -33,6 +34,7 @@ export class CalibrationManager {
|
|||||||
this.elements.saveCalibrationBtn?.addEventListener('click', this.handleSaveCalibration);
|
this.elements.saveCalibrationBtn?.addEventListener('click', this.handleSaveCalibration);
|
||||||
this.elements.calibrationDropdown?.addEventListener('change', this.handleCalibrationChange);
|
this.elements.calibrationDropdown?.addEventListener('change', this.handleCalibrationChange);
|
||||||
this.elements.setCalibrationBtn?.addEventListener('click', this.handleSetCalibration);
|
this.elements.setCalibrationBtn?.addEventListener('click', this.handleSetCalibration);
|
||||||
|
this.elements.deleteCalibrationBtn?.addEventListener('click', this.handleDeleteCalibration);
|
||||||
|
|
||||||
this.elements.calibrationNameInput?.addEventListener('input', () => {
|
this.elements.calibrationNameInput?.addEventListener('input', () => {
|
||||||
const hasName = this.elements.calibrationNameInput.value.trim().length > 0;
|
const hasName = this.elements.calibrationNameInput.value.trim().length > 0;
|
||||||
@ -46,6 +48,7 @@ export class CalibrationManager {
|
|||||||
this.elements.saveCalibrationBtn?.removeEventListener('click', this.handleSaveCalibration);
|
this.elements.saveCalibrationBtn?.removeEventListener('click', this.handleSaveCalibration);
|
||||||
this.elements.calibrationDropdown?.removeEventListener('change', this.handleCalibrationChange);
|
this.elements.calibrationDropdown?.removeEventListener('change', this.handleCalibrationChange);
|
||||||
this.elements.setCalibrationBtn?.removeEventListener('click', this.handleSetCalibration);
|
this.elements.setCalibrationBtn?.removeEventListener('click', this.handleSetCalibration);
|
||||||
|
this.elements.deleteCalibrationBtn?.removeEventListener('click', this.handleDeleteCalibration);
|
||||||
this.resetCaptureState();
|
this.resetCaptureState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,6 +94,9 @@ export class CalibrationManager {
|
|||||||
dd.disabled = true;
|
dd.disabled = true;
|
||||||
this.elements.setCalibrationBtn.disabled = true;
|
this.elements.setCalibrationBtn.disabled = true;
|
||||||
this.elements.viewPlotsBtn.disabled = true;
|
this.elements.viewPlotsBtn.disabled = true;
|
||||||
|
if (this.elements.deleteCalibrationBtn) {
|
||||||
|
this.elements.deleteCalibrationBtn.disabled = true;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,6 +111,9 @@ export class CalibrationManager {
|
|||||||
dd.disabled = false;
|
dd.disabled = false;
|
||||||
this.elements.setCalibrationBtn.disabled = true;
|
this.elements.setCalibrationBtn.disabled = true;
|
||||||
this.elements.viewPlotsBtn.disabled = true;
|
this.elements.viewPlotsBtn.disabled = true;
|
||||||
|
if (this.elements.deleteCalibrationBtn) {
|
||||||
|
this.elements.deleteCalibrationBtn.disabled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateWorking(working) {
|
updateWorking(working) {
|
||||||
@ -195,6 +204,9 @@ export class CalibrationManager {
|
|||||||
const v = this.elements.calibrationDropdown.value;
|
const v = this.elements.calibrationDropdown.value;
|
||||||
this.elements.setCalibrationBtn.disabled = !v;
|
this.elements.setCalibrationBtn.disabled = !v;
|
||||||
this.elements.viewPlotsBtn.disabled = !v;
|
this.elements.viewPlotsBtn.disabled = !v;
|
||||||
|
if (this.elements.deleteCalibrationBtn) {
|
||||||
|
this.elements.deleteCalibrationBtn.disabled = !v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleStartCalibration() {
|
async handleStartCalibration() {
|
||||||
@ -233,6 +245,7 @@ export class CalibrationManager {
|
|||||||
|
|
||||||
const btn = document.querySelector(`[data-standard="${standard}"]`);
|
const btn = document.querySelector(`[data-standard="${standard}"]`);
|
||||||
ButtonState.set(btn, { state: 'loading', icon: 'upload', text: 'Снятие...' });
|
ButtonState.set(btn, { state: 'loading', icon: 'upload', text: 'Снятие...' });
|
||||||
|
this.toggleStandardButtons(true);
|
||||||
|
|
||||||
this.notify(INFO, 'Снятие стандарта', `Снимается стандарт ${standard.toUpperCase()}...`);
|
this.notify(INFO, 'Снятие стандарта', `Снимается стандарт ${standard.toUpperCase()}...`);
|
||||||
|
|
||||||
@ -246,11 +259,29 @@ export class CalibrationManager {
|
|||||||
console.error('Capture standard failed:', e);
|
console.error('Capture standard failed:', e);
|
||||||
this.notify(ERROR, 'Ошибка калибровки', 'Не удалось снять стандарт калибровки');
|
this.notify(ERROR, 'Ошибка калибровки', 'Не удалось снять стандарт калибровки');
|
||||||
this.resetCaptureState(standard);
|
this.resetCaptureState(standard);
|
||||||
|
} finally {
|
||||||
|
this.toggleStandardButtons(false);
|
||||||
}
|
}
|
||||||
}), TIMING.DEBOUNCE_CALIBRATION
|
}), TIMING.DEBOUNCE_CALIBRATION
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleStandardButtons(disabled) {
|
||||||
|
const buttons = this.elements.calibrationStandards?.querySelectorAll('.calibration-standard-btn');
|
||||||
|
if (!buttons) return;
|
||||||
|
buttons.forEach(btn => {
|
||||||
|
if (disabled) {
|
||||||
|
btn.dataset.prevDisabled = btn.disabled ? '1' : '0';
|
||||||
|
btn.disabled = true;
|
||||||
|
} else {
|
||||||
|
if (btn.dataset.prevDisabled !== undefined) {
|
||||||
|
btn.disabled = btn.dataset.prevDisabled === '1';
|
||||||
|
delete btn.dataset.prevDisabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async handleSaveCalibration() {
|
async handleSaveCalibration() {
|
||||||
const name = this.elements.calibrationNameInput.value.trim();
|
const name = this.elements.calibrationNameInput.value.trim();
|
||||||
if (!name) return;
|
if (!name) return;
|
||||||
@ -312,6 +343,48 @@ export class CalibrationManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async handleDeleteCalibration() {
|
||||||
|
const name = this.elements.calibrationDropdown.value;
|
||||||
|
if (!name || !this.currentPreset) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!confirm(`Удалить калибровку «${name}»? Это действие необратимо.`)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.debouncer.debounce('delete-calibration', () =>
|
||||||
|
this.reqGuard.runExclusive('delete-calibration', async () => {
|
||||||
|
try {
|
||||||
|
if (this.elements.deleteCalibrationBtn) {
|
||||||
|
ButtonState.set(this.elements.deleteCalibrationBtn, { state: 'loading', icon: 'loader', text: 'Удаление...' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = buildUrl(API.SETTINGS.CALIBRATION_DELETE(name), {
|
||||||
|
preset_filename: this.currentPreset.filename
|
||||||
|
});
|
||||||
|
const result = await apiDelete(url);
|
||||||
|
|
||||||
|
this.notify(SUCCESS, 'Калибровка удалена', result.message);
|
||||||
|
|
||||||
|
await this.loadCalibrations();
|
||||||
|
await this.loadWorkingCalibration();
|
||||||
|
|
||||||
|
if (this.onCalibrationSet) {
|
||||||
|
await this.onCalibrationSet();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Delete calibration failed:', e);
|
||||||
|
this.notify(ERROR, 'Ошибка калибровки', 'Не удалось удалить калибровку');
|
||||||
|
} finally {
|
||||||
|
if (this.elements.deleteCalibrationBtn) {
|
||||||
|
ButtonState.set(this.elements.deleteCalibrationBtn, { state: 'normal', icon: 'trash-2', text: 'Удалить' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}), TIMING.DEBOUNCE_CALIBRATION
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
updateStatus(status) {
|
updateStatus(status) {
|
||||||
if (status.current_calibration) {
|
if (status.current_calibration) {
|
||||||
this.currentCalibration = status.current_calibration;
|
this.currentCalibration = status.current_calibration;
|
||||||
|
|||||||
@ -68,14 +68,57 @@ export class PresetManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formatDisplay(p) {
|
formatDisplay(p) {
|
||||||
let s = `${p.filename} (${p.mode})`;
|
if (!p) return '';
|
||||||
if (p.start_freq && p.stop_freq) {
|
|
||||||
const startMHz = (p.start_freq / 1e6).toFixed(0);
|
const parts = [];
|
||||||
const stopMHz = (p.stop_freq / 1e6).toFixed(0);
|
if (p.mode) {
|
||||||
s += ` - ${startMHz}-${stopMHz}MHz`;
|
parts.push(p.mode.toUpperCase());
|
||||||
}
|
}
|
||||||
if (p.points) s += `, ${p.points}pts`;
|
|
||||||
return s;
|
const start = this.formatFrequency(p.start_freq);
|
||||||
|
const stop = this.formatFrequency(p.stop_freq);
|
||||||
|
if (start && stop) {
|
||||||
|
parts.push(`${start} – ${stop}`);
|
||||||
|
} else if (start || stop) {
|
||||||
|
parts.push(start || stop);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.points) {
|
||||||
|
parts.push(`${p.points} точек`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bandwidth = this.formatFrequency(p.bandwidth);
|
||||||
|
if (bandwidth) {
|
||||||
|
parts.push(`ПП ${bandwidth}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parts.length && p.filename) {
|
||||||
|
return p.filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.join(' • ');
|
||||||
|
}
|
||||||
|
|
||||||
|
formatFrequency(value) {
|
||||||
|
if (value === null || value === undefined) return null;
|
||||||
|
const numeric = Number(value);
|
||||||
|
if (!Number.isFinite(numeric) || numeric <= 0) return null;
|
||||||
|
|
||||||
|
const units = [
|
||||||
|
{ divider: 1e9, suffix: 'ГГц' },
|
||||||
|
{ divider: 1e6, suffix: 'МГц' },
|
||||||
|
{ divider: 1e3, suffix: 'кГц' },
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const unit of units) {
|
||||||
|
if (numeric >= unit.divider) {
|
||||||
|
const scaled = numeric / unit.divider;
|
||||||
|
const formatted = scaled >= 10 ? scaled.toFixed(0) : scaled.toFixed(2);
|
||||||
|
return `${formatted} ${unit.suffix}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${numeric.toFixed(0)} Гц`;
|
||||||
}
|
}
|
||||||
|
|
||||||
handlePresetChange() {
|
handlePresetChange() {
|
||||||
@ -114,7 +157,7 @@ export class PresetManager {
|
|||||||
updateStatus(status) {
|
updateStatus(status) {
|
||||||
if (status.current_preset) {
|
if (status.current_preset) {
|
||||||
this.currentPreset = status.current_preset;
|
this.currentPreset = status.current_preset;
|
||||||
this.elements.currentPreset.textContent = status.current_preset.filename;
|
this.elements.currentPreset.textContent = this.formatDisplay(status.current_preset);
|
||||||
} else {
|
} else {
|
||||||
this.currentPreset = null;
|
this.currentPreset = null;
|
||||||
this.elements.currentPreset.textContent = 'Нет';
|
this.elements.currentPreset.textContent = 'Нет';
|
||||||
@ -129,7 +172,7 @@ export class PresetManager {
|
|||||||
setCurrentPresetDirect(preset) {
|
setCurrentPresetDirect(preset) {
|
||||||
this.currentPreset = preset;
|
this.currentPreset = preset;
|
||||||
if (this.elements.currentPreset) {
|
if (this.elements.currentPreset) {
|
||||||
this.elements.currentPreset.textContent = preset ? preset.filename : 'Нет';
|
this.elements.currentPreset.textContent = preset ? this.formatDisplay(preset) : 'Нет';
|
||||||
}
|
}
|
||||||
this.syncSelectedPreset();
|
this.syncSelectedPreset();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { Debouncer, RequestGuard, ButtonState } from '../utils.js';
|
|||||||
import { apiGet, apiPost, apiDelete, buildUrl } from '../api-client.js';
|
import { apiGet, apiPost, apiDelete, buildUrl } from '../api-client.js';
|
||||||
import { API, TIMING, NOTIFICATION_TYPES } from '../constants.js';
|
import { API, TIMING, NOTIFICATION_TYPES } from '../constants.js';
|
||||||
|
|
||||||
const { SUCCESS, ERROR, WARNING } = NOTIFICATION_TYPES;
|
const { SUCCESS, ERROR, WARNING, INFO } = NOTIFICATION_TYPES;
|
||||||
|
|
||||||
export class ReferenceManager {
|
export class ReferenceManager {
|
||||||
constructor(notifications) {
|
constructor(notifications) {
|
||||||
@ -25,6 +25,7 @@ export class ReferenceManager {
|
|||||||
this.handleSetReference = this.handleSetReference.bind(this);
|
this.handleSetReference = this.handleSetReference.bind(this);
|
||||||
this.handleClearReference = this.handleClearReference.bind(this);
|
this.handleClearReference = this.handleClearReference.bind(this);
|
||||||
this.handleDeleteReference = this.handleDeleteReference.bind(this);
|
this.handleDeleteReference = this.handleDeleteReference.bind(this);
|
||||||
|
this.handlePreviewReference = this.handlePreviewReference.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
init(elements) {
|
init(elements) {
|
||||||
@ -34,6 +35,7 @@ export class ReferenceManager {
|
|||||||
this.elements.setReferenceBtn?.addEventListener('click', this.handleSetReference);
|
this.elements.setReferenceBtn?.addEventListener('click', this.handleSetReference);
|
||||||
this.elements.clearReferenceBtn?.addEventListener('click', this.handleClearReference);
|
this.elements.clearReferenceBtn?.addEventListener('click', this.handleClearReference);
|
||||||
this.elements.deleteReferenceBtn?.addEventListener('click', this.handleDeleteReference);
|
this.elements.deleteReferenceBtn?.addEventListener('click', this.handleDeleteReference);
|
||||||
|
this.elements.previewReferenceBtn?.addEventListener('click', this.handlePreviewReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
@ -42,6 +44,13 @@ export class ReferenceManager {
|
|||||||
this.elements.setReferenceBtn?.removeEventListener('click', this.handleSetReference);
|
this.elements.setReferenceBtn?.removeEventListener('click', this.handleSetReference);
|
||||||
this.elements.clearReferenceBtn?.removeEventListener('click', this.handleClearReference);
|
this.elements.clearReferenceBtn?.removeEventListener('click', this.handleClearReference);
|
||||||
this.elements.deleteReferenceBtn?.removeEventListener('click', this.handleDeleteReference);
|
this.elements.deleteReferenceBtn?.removeEventListener('click', this.handleDeleteReference);
|
||||||
|
this.elements.previewReferenceBtn?.removeEventListener('click', this.handlePreviewReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateReferenceCount(count) {
|
||||||
|
if (this.elements.referenceCount) {
|
||||||
|
this.elements.referenceCount.textContent = typeof count === 'number' ? count : '-';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async setCurrentPreset(preset) {
|
async setCurrentPreset(preset) {
|
||||||
@ -65,6 +74,7 @@ export class ReferenceManager {
|
|||||||
preset_filename: this.currentPreset.filename
|
preset_filename: this.currentPreset.filename
|
||||||
});
|
});
|
||||||
this.availableReferences = await apiGet(referencesUrl);
|
this.availableReferences = await apiGet(referencesUrl);
|
||||||
|
this.updateReferenceCount(this.availableReferences.length);
|
||||||
|
|
||||||
const currentUrl = buildUrl(API.SETTINGS.REFERENCE_CURRENT, {
|
const currentUrl = buildUrl(API.SETTINGS.REFERENCE_CURRENT, {
|
||||||
preset_filename: this.currentPreset.filename
|
preset_filename: this.currentPreset.filename
|
||||||
@ -77,6 +87,7 @@ export class ReferenceManager {
|
|||||||
console.error('Failed to load references:', error);
|
console.error('Failed to load references:', error);
|
||||||
this.renderDropdown([]);
|
this.renderDropdown([]);
|
||||||
this.updateInfo(null);
|
this.updateInfo(null);
|
||||||
|
this.updateReferenceCount(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,6 +103,7 @@ export class ReferenceManager {
|
|||||||
const setBtn = this.elements.setReferenceBtn;
|
const setBtn = this.elements.setReferenceBtn;
|
||||||
const deleteBtn = this.elements.deleteReferenceBtn;
|
const deleteBtn = this.elements.deleteReferenceBtn;
|
||||||
const clearBtn = this.elements.clearReferenceBtn;
|
const clearBtn = this.elements.clearReferenceBtn;
|
||||||
|
const previewBtn = this.elements.previewReferenceBtn;
|
||||||
|
|
||||||
if (references.length === 0) {
|
if (references.length === 0) {
|
||||||
this.elements.referenceDropdown.innerHTML = '<option value="">Эталоны отсутствуют</option>';
|
this.elements.referenceDropdown.innerHTML = '<option value="">Эталоны отсутствуют</option>';
|
||||||
@ -99,6 +111,7 @@ export class ReferenceManager {
|
|||||||
if (setBtn) setBtn.disabled = true;
|
if (setBtn) setBtn.disabled = true;
|
||||||
if (clearBtn) clearBtn.disabled = true;
|
if (clearBtn) clearBtn.disabled = true;
|
||||||
if (deleteBtn) deleteBtn.disabled = true;
|
if (deleteBtn) deleteBtn.disabled = true;
|
||||||
|
if (previewBtn) previewBtn.disabled = true;
|
||||||
} else {
|
} else {
|
||||||
this.elements.referenceDropdown.innerHTML = '<option value="">Выберите эталон...</option>';
|
this.elements.referenceDropdown.innerHTML = '<option value="">Выберите эталон...</option>';
|
||||||
|
|
||||||
@ -117,6 +130,7 @@ export class ReferenceManager {
|
|||||||
|
|
||||||
if (setBtn) setBtn.disabled = false;
|
if (setBtn) setBtn.disabled = false;
|
||||||
if (deleteBtn) deleteBtn.disabled = false;
|
if (deleteBtn) deleteBtn.disabled = false;
|
||||||
|
if (previewBtn) previewBtn.disabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateButtons();
|
this.updateButtons();
|
||||||
@ -132,10 +146,12 @@ export class ReferenceManager {
|
|||||||
const setBtn = this.elements.setReferenceBtn;
|
const setBtn = this.elements.setReferenceBtn;
|
||||||
const deleteBtn = this.elements.deleteReferenceBtn;
|
const deleteBtn = this.elements.deleteReferenceBtn;
|
||||||
const clearBtn = this.elements.clearReferenceBtn;
|
const clearBtn = this.elements.clearReferenceBtn;
|
||||||
|
const previewBtn = this.elements.previewReferenceBtn;
|
||||||
|
|
||||||
if (setBtn) setBtn.disabled = !hasSelection;
|
if (setBtn) setBtn.disabled = !hasSelection;
|
||||||
if (deleteBtn) deleteBtn.disabled = !hasSelection;
|
if (deleteBtn) deleteBtn.disabled = !hasSelection;
|
||||||
if (clearBtn) clearBtn.disabled = !hasCurrent;
|
if (clearBtn) clearBtn.disabled = !hasCurrent;
|
||||||
|
if (previewBtn) previewBtn.disabled = !(hasSelection || hasCurrent);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateInfo(reference) {
|
updateInfo(reference) {
|
||||||
@ -148,11 +164,15 @@ export class ReferenceManager {
|
|||||||
|
|
||||||
if (!reference) {
|
if (!reference) {
|
||||||
this.elements.currentReferenceInfo.style.display = 'none';
|
this.elements.currentReferenceInfo.style.display = 'none';
|
||||||
|
if (this.elements.currentReferenceName) this.elements.currentReferenceName.textContent = '—';
|
||||||
|
if (this.elements.currentReferenceTimestamp) this.elements.currentReferenceTimestamp.textContent = '—';
|
||||||
|
if (this.elements.currentReferenceDescription) this.elements.currentReferenceDescription.textContent = '—';
|
||||||
this.onReferenceUpdated?.(null);
|
this.onReferenceUpdated?.(null);
|
||||||
|
this.updateButtons();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.elements.currentReferenceInfo.style.display = 'block';
|
this.elements.currentReferenceInfo.style.display = 'flex';
|
||||||
|
|
||||||
if (this.elements.currentReferenceName) {
|
if (this.elements.currentReferenceName) {
|
||||||
this.elements.currentReferenceName.textContent = reference.name;
|
this.elements.currentReferenceName.textContent = reference.name;
|
||||||
@ -166,10 +186,11 @@ export class ReferenceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.elements.currentReferenceDescription) {
|
if (this.elements.currentReferenceDescription) {
|
||||||
this.elements.currentReferenceDescription.textContent = reference.description || '';
|
this.elements.currentReferenceDescription.textContent = reference.description || '—';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onReferenceUpdated?.(reference);
|
this.onReferenceUpdated?.(reference);
|
||||||
|
this.updateButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleCreateReference() {
|
async handleCreateReference() {
|
||||||
@ -208,6 +229,51 @@ export class ReferenceManager {
|
|||||||
this.updateButtons();
|
this.updateButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async handlePreviewReference() {
|
||||||
|
const dropdown = this.elements.referenceDropdown;
|
||||||
|
const selectedName = dropdown?.value ?? '';
|
||||||
|
const targetName = selectedName || this.currentReference?.name;
|
||||||
|
if (!targetName) {
|
||||||
|
this.notify(WARNING, 'Нет данных', 'Не выбран ни один эталон для просмотра');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.debouncer.debounce('preview-reference', () =>
|
||||||
|
this.reqGuard.runExclusive('preview-reference', async () => {
|
||||||
|
try {
|
||||||
|
const url = buildUrl(API.SETTINGS.REFERENCE_ITEM(targetName), {
|
||||||
|
preset_filename: this.currentPreset?.filename
|
||||||
|
});
|
||||||
|
const details = await apiGet(url);
|
||||||
|
|
||||||
|
const timestamp = details?.timestamp
|
||||||
|
? new Date(details.timestamp).toLocaleString()
|
||||||
|
: '—';
|
||||||
|
const description = details?.description ? details.description : '—';
|
||||||
|
|
||||||
|
const lines = [
|
||||||
|
`Имя: ${details?.name ?? targetName}`,
|
||||||
|
`Дата: ${timestamp}`,
|
||||||
|
`Описание: ${description}`
|
||||||
|
];
|
||||||
|
|
||||||
|
if (details?.metadata && Object.keys(details.metadata).length) {
|
||||||
|
const metaPairs = Object.entries(details.metadata)
|
||||||
|
.map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
|
||||||
|
.join('; ');
|
||||||
|
lines.push(`Метаданные: ${metaPairs}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = lines.join(' • ');
|
||||||
|
this.notify(INFO, 'Просмотр эталона', message);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Preview reference failed:', error);
|
||||||
|
this.notify(ERROR, 'Ошибка эталона', 'Не удалось загрузить данные эталона');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async handleSetReference() {
|
async handleSetReference() {
|
||||||
const referenceName = this.elements.referenceDropdown.value;
|
const referenceName = this.elements.referenceDropdown.value;
|
||||||
if (!referenceName) return;
|
if (!referenceName) return;
|
||||||
@ -263,7 +329,7 @@ export class ReferenceManager {
|
|||||||
const referenceName = this.elements.referenceDropdown.value;
|
const referenceName = this.elements.referenceDropdown.value;
|
||||||
if (!referenceName) return;
|
if (!referenceName) return;
|
||||||
|
|
||||||
if (!confirm(`Are you sure you want to delete reference "${referenceName}"? This action cannot be undone.`)) {
|
if (!confirm(`Удалить эталон «${referenceName}»? Это действие необратимо.`)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,6 +358,7 @@ export class ReferenceManager {
|
|||||||
this.currentReference = null;
|
this.currentReference = null;
|
||||||
this.renderDropdown([]);
|
this.renderDropdown([]);
|
||||||
this.updateInfo(null);
|
this.updateInfo(null);
|
||||||
|
this.updateReferenceCount(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
notify(type, title, message) {
|
notify(type, title, message) {
|
||||||
|
|||||||
@ -246,6 +246,10 @@
|
|||||||
<span data-icon="bar-chart-3"></span>
|
<span data-icon="bar-chart-3"></span>
|
||||||
Показать графики
|
Показать графики
|
||||||
</button>
|
</button>
|
||||||
|
<button class="btn btn--secondary" id="deleteCalibrationBtn" disabled>
|
||||||
|
<span data-icon="trash-2"></span>
|
||||||
|
Удалить
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -291,6 +295,20 @@
|
|||||||
Удалить
|
Удалить
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="reference-details" id="currentReferenceInfo" style="display: none;">
|
||||||
|
<div class="reference-details__row">
|
||||||
|
<span class="reference-details__label">Имя:</span>
|
||||||
|
<span class="reference-details__value" id="currentReferenceName">—</span>
|
||||||
|
</div>
|
||||||
|
<div class="reference-details__row">
|
||||||
|
<span class="reference-details__label">Дата:</span>
|
||||||
|
<span class="reference-details__value" id="currentReferenceTimestamp">—</span>
|
||||||
|
</div>
|
||||||
|
<div class="reference-details__row reference-details__row--description">
|
||||||
|
<span class="reference-details__label">Описание:</span>
|
||||||
|
<span class="reference-details__value" id="currentReferenceDescription">—</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -304,21 +322,17 @@
|
|||||||
<span class="status-label">Получено свипов:</span>
|
<span class="status-label">Получено свипов:</span>
|
||||||
<span class="status-value" id="sweepCount">-</span>
|
<span class="status-value" id="sweepCount">-</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="status-item">
|
|
||||||
<span class="status-label">Обработано точек:</span>
|
|
||||||
<span class="status-value" id="pointCount">-</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-item">
|
|
||||||
<span class="status-label">Активные процессоры:</span>
|
|
||||||
<span class="status-value" id="processorCount">-</span>
|
|
||||||
</div>
|
|
||||||
<div class="status-item">
|
<div class="status-item">
|
||||||
<span class="status-label">Калибровок сохранено:</span>
|
<span class="status-label">Калибровок сохранено:</span>
|
||||||
<span class="status-value" id="calibrationCount">-</span>
|
<span class="status-value" id="calibrationCount">-</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="status-item">
|
||||||
|
<span class="status-label">Эталонов сохранено:</span>
|
||||||
|
<span class="status-value" id="referenceCount">-</span>
|
||||||
|
</div>
|
||||||
<div class="status-item">
|
<div class="status-item">
|
||||||
<span class="status-label">Статус системы:</span>
|
<span class="status-label">Статус системы:</span>
|
||||||
<span class="status-value" id="systemStatus">Проверка...</span>
|
<span class="status-value" id="systemStatus">Режим: —</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user