From 63db9549b9e7b2beea4e999296561ad77e90c131 Mon Sep 17 00:00:00 2001 From: Maxim Vershinin Date: Wed, 30 Sep 2026 19:27:16 +0400 Subject: [PATCH 1/3] feat(frontend): drive selection added --- static/css/style.css | 26 +++++++++- static/js/main.js | 108 ++++++++++++++++++++++++++++++++++++++- templates/benchmark.html | 39 +++++++++++--- 3 files changed, 164 insertions(+), 9 deletions(-) diff --git a/static/css/style.css b/static/css/style.css index 9ac3dd9..43426f3 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -16,7 +16,31 @@ font-size: 0.9rem; } -/* Drive cards styling */ +/* Drive selector cards */ +.drive-selector-card { + transition: all 0.2s ease; +} + +.drive-selector-card .btn-check:checked + .btn { + background-color: #e7f1ff; + border-color: #0d6efd; + box-shadow: 0 0 0 0.2rem rgba(13, 110, 253, 0.25); +} + +.drive-selector-card .btn { + border-radius: 0.5rem; + padding: 1rem; +} + +.drive-selector-card .btn:hover { + background-color: #f8f9fa; +} + +.drive-selector-card .btn-check:checked + .btn:hover { + background-color: #e7f1ff; +} + +/* General drive cards */ .drive-card { transition: all 0.3s ease; height: 100%; diff --git a/static/js/main.js b/static/js/main.js index 00cdbab..f88e68f 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -3,6 +3,9 @@ * Handles HTMX events and dynamic content rendering */ +// Global state +let selectedDrive = null; + // Render drives after HTMX loads them function renderDrives(data) { const container = document.getElementById('drives-content'); @@ -45,16 +48,117 @@ function renderDrives(data) { }); } +// Render drive selector for benchmark tab (available drives only) +function renderDriveSelector(data) { + const container = document.getElementById('drive-cards'); + if (!container) return; + + container.innerHTML = ''; + + if (!data.drives || data.drives.length === 0) { + container.innerHTML = '

No drives found.

'; + return; + } + + // Filter to show only available drives + const availableDrives = data.drives.filter(drive => !drive.mounted); + + if (availableDrives.length === 0) { + container.innerHTML = '
No available drives. All drives are mounted.
'; + return; + } + + availableDrives.forEach(drive => { + const col = document.createElement('div'); + col.className = 'col-md-4 mb-3'; + + const cardWrapper = document.createElement('div'); + cardWrapper.className = 'drive-selector-card'; + cardWrapper.dataset.drivePath = drive.path; + + // Radio input (hidden) + const radio = document.createElement('input'); + radio.type = 'radio'; + radio.name = 'selected_drive'; + radio.value = drive.path; + radio.id = `drive-${drive.name}`; + radio.className = 'btn-check'; + radio.setAttribute('autocomplete', 'off'); + + // Label as card + const label = document.createElement('label'); + label.htmlFor = `drive-${drive.name}`; + label.className = 'btn btn-outline-primary w-100 text-start'; + label.innerHTML = ` +
+
+
${drive.name}
+ ${drive.size} ${drive.model || ''} +
+
+ Available +
+
+ ${drive.serial ? `SN: ${drive.serial}` : ''} + `; + + cardWrapper.appendChild(radio); + cardWrapper.appendChild(label); + col.appendChild(cardWrapper); + container.appendChild(col); + + // Add click handler to show selected drive info + radio.addEventListener('change', function() { + if (this.checked) { + selectDrive(drive); + } + }); + }); +} + +// Handle drive selection +function selectDrive(drive) { + selectedDrive = drive; + console.log('Selected drive:', drive); + + // Update UI to show selection + const infoDiv = document.getElementById('selected-drive-info'); + if (infoDiv) { + infoDiv.innerHTML = ` +
+ Selected: ${drive.name} (${drive.path}) +
${drive.size} - ${drive.model || 'Unknown model'} +
+ `; + } + + // Enable benchmark configuration section + const configDiv = document.getElementById('benchmark-config'); + if (configDiv) { + configDiv.classList.remove('opacity-50'); + configDiv.querySelector('.card-body').innerHTML = ` +

Drive ${drive.name} selected. Configure benchmark parameters below.

+ + `; + } +} + // Listen for HTMX events document.addEventListener('htmx:afterRequest', function(evt) { + // Render drives in home page if (evt.detail.target.id === 'drives-content') { renderDrives(JSON.parse(evt.detail.xhr.response)); } + + // Render drive selector in benchmark page + if (evt.detail.target.id === 'drive-cards') { + renderDriveSelector(JSON.parse(evt.detail.xhr.response)); + } }); -// Optional: Listen for HTMX load event as fallback +// Listen for HTMX load event as fallback document.addEventListener('htmx:load', function(evt) { - if (evt.target.id === 'drives-content') { + if (evt.target.id === 'drive-cards') { // HTMX will load the content via hx-get // The afterRequest event will handle rendering } diff --git a/templates/benchmark.html b/templates/benchmark.html index 92b1047..2f6d600 100644 --- a/templates/benchmark.html +++ b/templates/benchmark.html @@ -8,16 +8,43 @@

Benchmark

Configure and run disk benchmarks.

- -
+ +
+
+
Select Drive to Benchmark
+
-
Select Drive
-

Choose a drive to benchmark from the list below.

+

Choose an available drive from the list below.

- -
+ +
+
+ + +
+ + +
+
+
+ + +
+
+
Benchmark Configuration
+
+
+

Select a drive above to configure benchmark parameters.

+{% endblock %} + +{% block extra_js %} + {% endblock %} \ No newline at end of file -- 2.52.0 From c40940a4307a67e49cc55f3b9aa5e743102d4463 Mon Sep 17 00:00:00 2001 From: bot Date: Thu, 1 Oct 2026 23:07:45 +0400 Subject: [PATCH 2/3] fix(frontend): add Clear Selection button for undoing drive selection Fixes issue #1: Users can now deselect a previously chosen drive --- templates/benchmark.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/templates/benchmark.html b/templates/benchmark.html index 2f6d600..55a80da 100644 --- a/templates/benchmark.html +++ b/templates/benchmark.html @@ -29,6 +29,11 @@
+ -- 2.52.0 From 028c68251a83b58d2b6ebeadab071b8b8ddf7bd4 Mon Sep 17 00:00:00 2001 From: bot Date: Thu, 1 Oct 2026 23:10:37 +0400 Subject: [PATCH 3/3] fix(frontend): add clearDriveSelection() function for undoing drive selection - Add clearDriveSelection() to reset UI state and uncheck radio buttons - Show clear selection button when drive is selected - Fixes issue #1: undo disk selection --- static/js/main.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/static/js/main.js b/static/js/main.js index f88e68f..83f65dd 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -132,6 +132,12 @@ function selectDrive(drive) { `; } + // Show clear selection button + const clearContainer = document.getElementById('clear-selection-container'); + if (clearContainer) { + clearContainer.style.display = 'block'; + } + // Enable benchmark configuration section const configDiv = document.getElementById('benchmark-config'); if (configDiv) { @@ -143,6 +149,44 @@ function selectDrive(drive) { } } +// Handle drive deselection (clear selection) +function clearDriveSelection() { + selectedDrive = null; + console.log('Cleared drive selection'); + + // Clear selected drive info + const infoDiv = document.getElementById('selected-drive-info'); + if (infoDiv) { + infoDiv.innerHTML = ''; + } + + // Hide clear selection button + const clearContainer = document.getElementById('clear-selection-container'); + if (clearContainer) { + clearContainer.style.display = 'none'; + } + + // Disable benchmark configuration section + const configDiv = document.getElementById('benchmark-config'); + if (configDiv) { + configDiv.classList.add('opacity-50'); + configDiv.querySelector('.card-body').innerHTML = ` +

Select a drive above to configure benchmark parameters.

+ `; + } + + // Uncheck all radio buttons + const radios = document.querySelectorAll('input[name="selected_drive"]'); + radios.forEach(radio => { radio.checked = false; }); +} + +// Listen for clear selection button click +document.addEventListener('click', function(evt) { + if (evt.target.id === 'clear-selection-btn' || evt.target.closest('#clear-selection-btn')) { + clearDriveSelection(); + } +}); + // Listen for HTMX events document.addEventListener('htmx:afterRequest', function(evt) { // Render drives in home page -- 2.52.0