Files
mongoose/tutorials/device-dashboard/events/dashboard.html
T
2026-05-18 18:07:22 +01:00

131 lines
6.3 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Array Dashboard</title>
<script src="https://mongoose.ws/resources/dashboard.js"></script>
<script>
Dashboard.init({
debug: true,
data: { event: { index: 0, message: 'hi' } },
});
let pageStart = 0;
let loading = false;
async function readEvent(index) {
await Dashboard.call('set', { event: { index } });
const ev = await Dashboard.call('get', 'event');
return ev && typeof ev == 'object' ? ev : { index, message: `my ev ${index}` };
}
function setLoading(value) {
loading = value;
document.querySelectorAll('[data-page-button]').forEach(btn => btn.disabled = value);
}
async function loadRows(start) {
if (loading) return;
const count = Number(document.querySelector('#page-size').value) || 10;
const tbody = document.querySelector('#events tbody');
const status = document.querySelector('#table-status');
pageStart = Math.max(0, start);
tbody.replaceChildren();
status.textContent = `Loading ${pageStart}..${pageStart + count - 1}`;
setLoading(true);
try {
for (let i = pageStart; i < pageStart + count; i++) {
const tr = document.createElement('tr');
const tdIndex = document.createElement('td');
const tdMessage = document.createElement('td');
tdIndex.textContent = i;
tdMessage.textContent = 'Loading...';
tr.append(tdIndex, tdMessage);
tbody.appendChild(tr);
const ev = await readEvent(i);
tdIndex.textContent = ev.index;
tdMessage.textContent = ev.message;
}
status.textContent = `Showing ${pageStart}..${pageStart + count - 1}`;
} catch (err) {
status.textContent = `Error: ${err && err.message ? err.message : err}`;
} finally {
setLoading(false);
}
}
// Show dashboard only when all device data is reported
Dashboard.on('ready', () => {
document.body.style.visibility = 'visible';
loadRows(0);
});
</script>
<style>
* { box-sizing: border-box; }
html, body { height: 100%; }
body { margin: 0; background:#f8fafc; font:500 14px/1.35 Arial,sans-serif; }
code {white-space: nowrap; background: #ddd; border-radius: 4px; padding: 1px 4px;}
.field { display: flex; flex-direction: row; justify-content: space-between; align-items: center; gap: 0.75rem; }
.field-label { font-size: 0.75rem; font-weight: 700; text-transform: uppercase; color: #94a3b8; flex-shrink: 0; white-space: nowrap; min-width: 3rem; }
.field-input { flex: 1; min-width: 0; padding: 0.45rem 0.75rem; font-size: 0.88rem; font-family: inherit; color: #334155; border: 1px solid #e2e8f0; border-radius: 0.55rem; outline: none; transition: border-color 0.15s ease; }
.field-input.edited { border-color: #00500040 !important; background: #00ff0020; }
.field-input.error { border-color: #50000040; background: #ff000020; }
.field-input::placeholder { color: #cbd5e1; }
.field-input:hover { border-color: #cbd5e1; }
.field-input:focus { border-color: #7dd3fc; }
.field-input:disabled, .field-input.disabled { color: #cbd5e1; border-color: #e2e8f0; cursor: not-allowed; pointer-events: none; }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; height: 2rem; padding: 0.3rem 1rem; font-size: 0.85rem; font-family: inherit; font-weight: 600; border-radius: 0.5rem; border: 1px solid transparent; cursor: pointer; transition: all 0.15s ease; white-space: nowrap; }
.btn-secondary { color: #64748b; background: #ffffff; border-color: #e2e8f0; box-shadow: 0 1px 2px rgba(148, 163, 184, 0.1); }
.btn-secondary:hover { background: #f1f5f9; border-color: #cbd5e1; color: #475569; }
.btn-primary { color: #ffffff; background: linear-gradient(160deg, #38bdf8, #0ea5e9); border-color: #0284c7; box-shadow: 0 1px 3px rgba(14, 165, 233, 0.3), 0 4px 10px rgba(14, 165, 233, 0.15); }
.btn-primary:hover { background: linear-gradient(160deg, #0ea5e9, #0284c7); box-shadow: 0 1px 3px rgba(14, 165, 233, 0.4), 0 6px 14px rgba(14, 165, 233, 0.2); }
.btn-primary:active, .btn-secondary:active { transform: translateY(0); }
.btn:disabled, .btn.disabled { opacity: 0.45; cursor: not-allowed; pointer-events: none; box-shadow: none; transform: none; }
.toolbar { display: flex; align-items: center; flex-wrap: wrap; gap: 0.75rem; margin: 1.25rem 0; }
.table-wrap { max-width: 44rem; overflow: auto; border: 1px solid #e2e8f0; border-radius: 0.5rem; background: #fff; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 0.65rem 0.85rem; border-bottom: 1px solid #e2e8f0; text-align: left; }
th { font-size: 0.75rem; text-transform: uppercase; color: #64748b; background: #f1f5f9; }
td:first-child { width: 7rem; color: #334155; font-variant-numeric: tabular-nums; }
tr:last-child td { border-bottom: 0; }
#table-status { min-width: 12rem; color: #64748b; }
</style>
</head>
<body style="visibility: hidden;">
<main id="main" style="margin: 2rem; color: #64748b;">
<h1>Array read/write</h1>
<div class="toolbar">
<button class="btn btn-secondary" data-page-button onclick="loadRows(pageStart - Number(document.querySelector('#page-size').value || 10))">Prev</button>
<button class="btn btn-secondary" data-page-button onclick="loadRows(pageStart + Number(document.querySelector('#page-size').value || 10))">Next</button>
<div class="field" style="width: 9rem;">
Rows
<input id="page-size" class="field-input" type="text" value="10" />
</div>
<button class="btn btn-primary" data-page-button onclick="loadRows(pageStart)">Reload</button>
<span id="table-status"></span>
</div>
<div class="table-wrap">
<table id="events">
<thead>
<tr>
<th>Index</th>
<th>Message</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</main>
</body>
</html>