Files
ssd_health/files/dashboard/index.php

190 lines
6.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
// Function to fetch SSD information from the API
function fetchSSDData() {
$url = 'http://172.17.0.1:5000/drives';
$options = [
'http' => [
'header' => "Content-type: application/json\r\n",
'method' => 'GET',
],
];
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) {
die('Error Fetching data');
}
return json_decode($result, true); // Decode JSON as an associative array
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>SSD Health Dashboard</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<button onclick="window.location.reload();" class="title-button"><h2>SSD Health Dashboard</h2></button><br>
This is a historical list of every disk ever scanned by this device.<p>
For a live dashboard, please visit <a href=/>home</a>.
</div>
<div class="container">
Search for disk:<br>
<input id="search" type="text" placeholder="Search by ID, model, serial…" /><p>
<?php
$ssdData = fetchSSDData();
echo '<table class="ssd-list" style="border-collapse:collapse;width:100%;">';
echo '<thead>
<tr>
<th data-sort="id">Disk ID</th>
<th data-sort="model">Model String</th>
<th data-sort="serial">Serial Number</th>
<th data-sort="gb_written">GB Written</th>
<th data-sort="capacity">Disk Capacity</th>
<th data-sort="flavor">Disk Flavor</th>
<th data-sort="smart">SMART Result</th>
</tr>
</thead>';
echo '<tbody id="ssd-body">';
foreach ($ssdData as $ssd) {
// Escape the values so the page stays safe
$id = htmlspecialchars($ssd['id']);
$model = htmlspecialchars($ssd['model']);
$serial = htmlspecialchars($ssd['serial']);
$gbw = htmlspecialchars($ssd['gb_written']);
$cap = htmlspecialchars($ssd['capacity']);
$flavor = htmlspecialchars($ssd['flavor']);
$smart = htmlspecialchars($ssd['smart']);
echo "<tr>
<td>{$id}</td>
<td>{$model}</td>
<td>{$serial}</td>
<td>{$gbw}</td>
<td>{$cap}</td>
<td>{$flavor}</td>
<td>{$smart}</td>
</tr>";
}
echo '</tbody></table>';
?>
</div>
</body>
<script>
document.addEventListener('DOMContentLoaded', () => {
const searchInput = document.getElementById('search');
const tbody = document.getElementById('ssd-body');
const rows = Array.from(tbody.rows); // snapshot of rows
// Optional: a simple debounce so we don't react on every keystroke
const debounce = (fn, delay) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
};
const filterRows = debounce(() => {
const query = searchInput.value.trim().toLowerCase();
rows.forEach(row => {
// Grab all cells in this row as a single string
const rowText = Array.from(row.cells)
.map(cell => cell.textContent)
.join(' ')
.toLowerCase();
row.style.display = rowText.includes(query) ? '' : 'none';
});
}, 200); // 200ms debounce
searchInput.addEventListener('input', filterRows);
});
</script>
<script>
document.addEventListener('DOMContentLoaded', () => {
/* ----- Search filter ----- */
const searchInput = document.getElementById('search');
const tbody = document.getElementById('ssd-body');
const rowsSnapshot = Array.from(tbody.rows); // keep a static snapshot
const debounce = (fn, delay) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
};
const filterRows = debounce(() => {
const q = searchInput.value.trim().toLowerCase();
rowsSnapshot.forEach(r => {
const rowText = Array.from(r.cells)
.map(c => c.textContent.trim().toLowerCase())
.join(' ');
r.style.display = rowText.includes(q) ? '' : 'none';
});
}, 200);
searchInput.addEventListener('input', filterRows);
/* ----- Table sorting ----- */
const table = document.querySelector('.ssd-list');
const headerCells = table.querySelectorAll('th[data-sort]');
const bodyRows = Array.from(tbody.rows);
headerCells.forEach((th, index) => {
th.classList.add('sortable'); // gives the arrow styling
th.style.cursor = 'pointer';
th.addEventListener('click', () => {
const currentSort = th.dataset.currentSort || 'none';
const ascending = currentSort !== 'asc';
// reset other headers
headerCells.forEach(h => {
h.dataset.currentSort = 'none';
h.classList.remove('asc', 'desc');
});
// set current header state
th.dataset.currentSort = ascending ? 'asc' : 'desc';
th.classList.toggle('asc', ascending);
th.classList.toggle('desc', !ascending);
// sort
bodyRows.sort((a, b) => {
const aText = a.cells[index].textContent.trim();
const bText = b.cells[index].textContent.trim();
// try numeric comparison
const aNum = parseFloat(aText.replace(/,/g, ''));
const bNum = parseFloat(bText.replace(/,/g, ''));
if (!isNaN(aNum) && !isNaN(bNum)) {
return ascending ? aNum - bNum : bNum - aNum;
}
// fallback to localeCompare (caseinsensitive)
return ascending
? aText.localeCompare(bText, undefined, { sensitivity: 'base' })
: bText.localeCompare(aText, undefined, { sensitivity: 'base' });
});
// reattach sorted rows
bodyRows.forEach(r => tbody.appendChild(r));
});
});
});
</script>
</html>