83 lines
2.7 KiB
HTML
83 lines
2.7 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Valkey/Redis Cache Visualization</title>
|
|
<style>
|
|
body { font-family: sans-serif; background: #f8fafc; margin: 0; padding: 2em; }
|
|
h1 { color: #2563eb; }
|
|
table { border-collapse: collapse; width: 100%; background: #fff; }
|
|
th, td { border: 1px solid #e5e7eb; padding: 0.5em 1em; }
|
|
th { background: #f1f5f9; }
|
|
tr:nth-child(even) { background: #f9fafb; }
|
|
.json { font-family: monospace; font-size: 0.95em; white-space: pre; }
|
|
.expand { cursor: pointer; color: #2563eb; text-decoration: underline; }
|
|
.search { margin-bottom: 1em; padding: 0.5em; width: 300px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>Valkey/Redis Cache Visualization</h1>
|
|
<input class="search" type="text" id="search" placeholder="Search by key or value..." />
|
|
<table id="cacheTable">
|
|
<thead>
|
|
<tr><th>Key</th><th>Value</th></tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
<script>
|
|
let cacheKeys = [];
|
|
let cacheDetails = {};
|
|
const tbody = document.querySelector('#cacheTable tbody');
|
|
|
|
function renderTable(keys) {
|
|
tbody.innerHTML = '';
|
|
for (const { key } of keys) {
|
|
const tr = document.createElement('tr');
|
|
const tdKey = document.createElement('td');
|
|
tdKey.textContent = key;
|
|
const tdValue = document.createElement('td');
|
|
tdValue.textContent = '[click to load]';
|
|
tdValue.className = 'expand';
|
|
tdValue.onclick = async () => {
|
|
tdValue.textContent = 'Loading...';
|
|
if (!cacheDetails[key]) {
|
|
try {
|
|
const res = await fetch(`http://localhost:3006/api/cache/${encodeURIComponent(key)}`);
|
|
const data = await res.json();
|
|
cacheDetails[key] = data.value;
|
|
} catch (err) {
|
|
tdValue.textContent = 'Error loading value';
|
|
return;
|
|
}
|
|
}
|
|
tdValue.innerHTML = `<div class='json'>${JSON.stringify(cacheDetails[key], null, 2)}</div>`;
|
|
};
|
|
tr.appendChild(tdKey);
|
|
tr.appendChild(tdValue);
|
|
tbody.appendChild(tr);
|
|
}
|
|
}
|
|
|
|
// Fetch cache keys from API
|
|
async function loadKeys() {
|
|
try {
|
|
const res = await fetch('http://localhost:3006/api/cache/keys');
|
|
cacheKeys = await res.json();
|
|
renderTable(cacheKeys);
|
|
} catch (err) {
|
|
tbody.innerHTML = `<tr><td colspan='2' style='color:#b91c1c'>Failed to load cache keys: ${err}</td></tr>`;
|
|
}
|
|
}
|
|
|
|
// Search functionality
|
|
document.getElementById('search').addEventListener('input', function() {
|
|
const q = this.value.toLowerCase();
|
|
renderTable(cacheKeys.filter(({key}) => key.toLowerCase().includes(q)));
|
|
});
|
|
|
|
// Initial load
|
|
loadKeys();
|
|
</script>
|
|
</body>
|
|
</html>
|