Merge pull request #176 from ipnet-mesh/chore/observer-ux-tweaks

Update observer table: SNR/Path headers and value suffix cleanup
This commit is contained in:
JingleManSweep
2026-04-26 14:53:07 +01:00
committed by GitHub
6 changed files with 15 additions and 10 deletions
+1 -1
View File
@@ -144,7 +144,7 @@ open http://localhost:8080
This starts all services: MQTT broker, collector, API, web dashboard, and packet capture. The `observer` profile runs [meshcore-packet-capture](https://github.com/agessaman/meshcore-packet-capture) to observe MeshCore RF traffic and publish decoded packets to MQTT.
> **ARM / Raspberry Pi:** The `observer` service Docker image (`ghcr.io/agessaman/meshcore-packet-capture`) does not currently support ARM architectures. A [PR is open](https://github.com/agessaman/meshcore-packet-capture/pull/13) on the upstream project to add ARM support but has not yet been merged. To run the observer on a Raspberry Pi, do not use the `--profile observer` Docker profile — instead, install [meshcore-packet-capture](https://github.com/agessaman/meshcore-packet-capture) natively on the Pi and configure it to publish to your MQTT broker.
> **ARM / Raspberry Pi:** The `observer` service Docker image (`ghcr.io/agessaman/meshcore-packet-capture`) does not support 32-bit ARM (`armv7l`) architectures. Modern Raspberry Pi models (3, 4, 5) using a 64-bit OS are fully supported. If you are running a 32-bit ARM system, install [meshcore-packet-capture](https://github.com/agessaman/meshcore-packet-capture) natively and configure it to publish to your MQTT broker instead of using the `--profile observer` Docker profile.
## Deployment
+3
View File
@@ -176,6 +176,9 @@ Toast/flash messages after successful operations:
| `received_by` | Received By | Received by field |
| `receivers` | Receivers | Multiple receivers |
| `from` | From | Message sender |
| `hops` | Hops | Number of mesh hops (table header) |
| `observers` | Observers | Observers of an event |
| `snr_db` | SNR (dB) | Signal-to-noise ratio in decibels (table header) |
| `unnamed` | Unnamed | Fallback for unnamed items |
| `unnamed_node` | Unnamed Node | Fallback for unnamed nodes |
@@ -478,16 +478,16 @@ export function observerDetailRow(observers, eventProperties, options = {}) {
<thead>
<tr>
<th>Observer</th>
<th>SNR</th>
${showPath ? html`<th>Path</th>` : nothing}
<th>${t('common.snr_db')}</th>
${showPath ? html`<th>${t('common.hops')}</th>` : nothing}
<th>Received</th>
</tr>
</thead>
<tbody>
${observers.map(o => {
const displayName = o.tag_name || o.name || truncateKey(o.public_key, 12);
const snrDisplay = o.snr != null ? `${Number(o.snr).toFixed(1)} dB` : '\u2014';
const pathDisplay = o.path_len != null ? `${o.path_len} hop${o.path_len !== 1 ? 's' : ''}` : '\u2014';
const snrDisplay = o.snr != null ? `${Number(o.snr).toFixed(1)}` : '\u2014';
const pathDisplay = o.path_len != null ? `${o.path_len}` : '\u2014';
const timeDisplay = formatRelativeTime(o.observed_at);
return html`
<tr>
@@ -133,11 +133,11 @@ ${displayContent}`, container);
${ad.observers && ad.observers.length > 0 ? html`
<div class="observer-detail-card hidden mt-2">
<table class="table table-xs w-full">
<thead><tr><th>Observer</th><th>SNR</th><th>Received</th></tr></thead>
<thead><tr><th>Observer</th><th>${t('common.snr_db')}</th><th>Received</th></tr></thead>
<tbody>
${ad.observers.map(o => {
const dn = o.tag_name || o.name || truncateKey(o.public_key, 12);
const snrD = o.snr != null ? `${Number(o.snr).toFixed(1)} dB` : '\u2014';
const snrD = o.snr != null ? `${Number(o.snr).toFixed(1)}` : '\u2014';
const timeD = formatRelativeTime(o.observed_at);
return html`<tr>
<td>\u{1F4E1} <a href="/nodes/${o.public_key}" class="link link-hover">${dn}</a></td>
@@ -246,12 +246,12 @@ ${displayContent}`, container);
${msg.observers && msg.observers.length > 0 ? html`
<div class="observer-detail-card hidden mt-2">
<table class="table table-xs w-full">
<thead><tr><th>Observer</th><th>SNR</th><th>Path</th><th>Received</th></tr></thead>
<thead><tr><th>Observer</th><th>${t('common.snr_db')}</th><th>${t('common.hops')}</th><th>Received</th></tr></thead>
<tbody>
${msg.observers.map(o => {
const dn = o.tag_name || o.name || truncateKey(o.public_key, 12);
const snrD = o.snr != null ? `${Number(o.snr).toFixed(1)} dB` : '\u2014';
const pathD = o.path_len != null ? `${o.path_len} hop${o.path_len !== 1 ? 's' : ''}` : '\u2014';
const snrD = o.snr != null ? `${Number(o.snr).toFixed(1)}` : '\u2014';
const pathD = o.path_len != null ? `${o.path_len}` : '\u2014';
const timeD = formatRelativeTime(o.observed_at);
return html`<tr>
<td>\u{1F4E1} <a href="/nodes/${o.public_key}" class="link link-hover">${dn}</a></td>
@@ -95,6 +95,8 @@
"received": "Received",
"received_by": "Received By",
"observers": "Observers",
"snr_db": "SNR (dB)",
"hops": "Hops",
"from": "From",
"close": "close",
"unnamed": "Unnamed",