Gate 0.0.28: de blokhoogte was niet van deze app

Op verzoek van de gebruiker. Dit is een TLS-voordeur op een Electrum-server;
wat de keten doet staat in elke wallet die hij al heeft. Vier widgets over,
alle vier over deze gateway.

De leeftijd van de meting stond onder de blokhoogte en was daarmee de laatste
plek waar de pagina zei hoe oud zijn gegevens zijn: de voetregel en de badge
die hetzelfde zeiden zijn in augustus weggehaald met precies dat argument. Die
regel staat nu onder de reactietijd, na de sparkline zodat de vier onderregels
op een lijn blijven.

De rij is een raster van vier met breekpunten op 1100 en 560 pixels; vier
deelt door twee, dus de stap die bepaalde welke widget alleen kwam te staan is
vervallen. In de agent is de hoogte uit het antwoord gehaald maar het verzoek
niet: daar wordt de reactietijd uit gemeten.

Alle tests groen: 22 + 43 + 39 + 54 + 28 + 115 + 65 goed, 0 fout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Harmen
2026-09-04 09:43:11 +02:00
co-authored by Claude Opus 5
parent 5ee21b10e7
commit dbec428e62
7 changed files with 134 additions and 80 deletions
+8 -5
View File
@@ -630,10 +630,16 @@ def apply_certificate(cert):
# --- De backend bevragen ----------------------------------------------------
def probe_backend():
"""Blokhoogte en reactietijd van de Electrum-server.
"""Reactietijd van de Electrum-server, en of hij antwoordt.
Eén verzoek over een verse verbinding. Het Electrum-protocol is
JSON-RPC met een regeleinde eraan, dus dit is een socket en niets meer.
De methode is nog steeds headers.subscribe: het is het goedkoopste
verzoek waar een geldig antwoord op komt. De blokhoogte die erin staat
wordt sinds 0.0.28 niet meer overgenomen, want het is niet aan deze app
om die te tonen. Wat we van het antwoord gebruiken is dat het er is en
dat het te ontleden valt.
"""
result = {"address": ELECTRUM_HOST + ":" + str(ELECTRUM_PORT), "reachable": False}
result["name"] = BACKEND_NAMES.get(ELECTRUM_HOST)
@@ -662,12 +668,9 @@ def probe_backend():
break
elapsed = (time.monotonic() - start) * 1000.0
line = b"".join(chunks).split(b"\n", 1)[0]
answer = json.loads(line.decode("utf-8"))
height = (answer.get("result") or {}).get("height")
json.loads(line.decode("utf-8"))
result["reachable"] = True
result["response_ms"] = int(round(elapsed))
if isinstance(height, int):
result["height"] = height
except Exception as e: # noqa: BLE001 - elke fout betekent hetzelfde voor
# de pagina: de backend antwoordde niet.
result["error"] = str(e)
+57 -59
View File
@@ -250,7 +250,7 @@ body {
.grid > .card { display: flex; flex-direction: column; }
/* Hier stonden ook .col-5 en .col-7, met een mediaregel die ze onder 1100px vol
breed maakte. Sinds de tweede indeling (27-08-2026) is er geen rij meer die in
tweeën valt: de bovenste rij heeft zijn eigen raster van vijf, en het log en het
tweeën valt: de bovenste rij heeft zijn eigen raster van vier, en het log en het
instelkader zijn allebei vol breed. Weggehaald in plaats van laten staan, want
ongebruikte klassen nodigen uit tot een indeling die er niet meer is. */
.col-full { grid-column: 1 / -1; }
@@ -336,32 +336,32 @@ body {
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.1rem; }
/* ── De bovenste rij ────────────────────────────────────────────────────────
Vijf gelijke widgets (27-08-2026). Hier stond een raster van drie tegels waarvan
de reactietijd er twee nam, naast een kader met lijstregels; dat vroeg twee
kunstjes die nu weg zijn, namelijk meerekken met de hoogte van de buur en een
dubbele kolom voor de sparkline.
Vier gelijke widgets (27-08-2026, sinds 0.0.28 vier in plaats van vijf). Hier
stond een raster van drie tegels waarvan de reactietijd er twee nam, naast een
kader met lijstregels; dat vroeg twee kunstjes die nu weg zijn, namelijk
meerekken met de hoogte van de buur en een dubbele kolom voor de sparkline.
Een eigen raster en geen deling van de twaalf kolommen hierboven, want vijf
past daar niet in. Dat is nieuw op deze pagina: elke andere rij viel in tweeën.
Een eigen raster en geen deling van de twaalf kolommen hierboven. Met vier zou
dat kunnen (drie kolommen elk), maar de rij houdt zijn eigen breekpunten: de
twaalf kolommen breken bij andere breedtes dan waar een widget te smal wordt.
Wat er bij het versmallen gebeurt, is daarom expliciet en niet aan auto-fit
overgelaten. Met vijf items levert elke stap een ongelijke laatste rij op, en
dan wil je zelf bepalen wélke widget alleen komt te staan. Dat is steeds de
laatste, de zelfcontrole, en die is als enige begrijpelijk zonder buur. */
Wat er bij het versmallen gebeurt, is expliciet en niet aan auto-fit
overgelaten. Vier deelt door twee, dus elke stap levert nu volle rijen op; met
vijf stond hier een derde stap om te bepalen wélke widget alleen kwam te staan.
Die is vervallen. */
.row1 {
grid-column: 1 / -1;
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-template-columns: repeat(4, 1fr);
gap: 1.5rem;
}
/* Onder deze breedte wordt een widget van een vijfde te smal voor "Wrong
certificate" of een blokhoogte met scheidingstekens. Drie plus twee. */
@media (max-width: 1400px) { .row1 { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 900px) { .row1 { grid-template-columns: repeat(2, 1fr); } }
/* Onder deze breedte wordt een widget van een kwart te smal voor "Wrong
certificate". Twee plus twee, en dus geen losse widget onderaan. */
@media (max-width: 1100px) { .row1 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .row1 { grid-template-columns: 1fr; } }
/* De widgets zetten hun waarde onderaan, zodat de vijf getallen op één lijn
staan ook als de ene titel over twee regels valt en de andere niet.
/* De widgets zetten hun waarde onderaan, zodat de getallen op één lijn staan ook
als de ene titel over twee regels valt en de andere niet.
De min-height is er op verzoek van de gebruiker (27-08-2026): zonder die maat
bepaalt de hoogste widget de rij, en dat leverde vijf krappe blokjes op waarin
@@ -382,14 +382,15 @@ body {
op 20-08-2026 op zijn telefoon zag. Met min(420px, 100%) mag de track krimpen
tot de schermbreedte. */
.clients { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr)); gap: 1.2rem 2.4rem; }
/* Eén maat voor alle vijf de widgets (27-08-2026). Hier stonden er drie: 1,9rem
voor een getal, 1,5rem voor "unknown" en 1,3rem voor een woord. Op de rij naast
elkaar viel dat op, en terecht: "964 307" oogde groter dan "Fulcrum" ernaast,
terwijl het even belangrijk is.
/* Eén maat voor alle widgets (27-08-2026). Hier stonden er drie: 1,9rem voor een
getal, 1,5rem voor "unknown" en 1,3rem voor een woord. Op de rij naast elkaar
viel dat op, en terecht: "964 307" oogde groter dan "Fulcrum" ernaast, terwijl
het even belangrijk is.
1,55rem is de maat waarop allebei werkt. Groter en "Wrong certificate" loopt op
een vijfde van de breedte over drie regels; kleiner en een blokhoogte verliest
het gewicht dat hem het eerste maakt waar je naar kijkt. */
1,55rem is de maat waarop een getal en een woord allebei werken. Groter en
"Wrong certificate" loopt op een kwart van de breedte over drie regels; kleiner
en "7 ms" verliest het gewicht dat een waarde het eerste maakt waar je naar
kijkt. */
.stat-val { font-size: 1.55rem; font-weight: 700; letter-spacing: -0.025em; font-variant-numeric: tabular-nums; line-height: 1.2; }
/* Alleen de kleur, geen eigen maat meer: onbekend is een andere toestand van
dezelfde waarde en hoort niet ook nog van formaat te verschillen. */
@@ -933,15 +934,16 @@ body {
schermen stapelt hij precies zo. -->
<div class="grid">
<!-- Vijf widgets, alle vijf hetzelfde soort ding: een titel, één waarde, en
<!-- Vier widgets, alle vier hetzelfde soort ding: een titel, één waarde, en
hooguit één onderregel. Opgegeven door de gebruiker op 27-08-2026 en
uitgeschreven in PLAN.md 4a2.
uitgeschreven in PLAN.md 4a2. Het waren er vijf tot 0.0.28; de blokhoogte
is eruit omdat het niet aan deze app is om die te tonen.
Hier stonden een kader met drie lijstregels voor de Electrum-server en
daarnaast twee tegels. Dat vroeg twee kunstjes die nu vervallen: de tegels
moesten meerekken met de hoogte van het kader ernaast, en de reactietijd
nam twee kolommen om de sparkline ruimte te geven. Vijf gelijke widgets
hebben geen buur om zich aan te meten.
nam twee kolommen om de sparkline ruimte te geven. Gelijke widgets hebben
geen buur om zich aan te meten.
De volgorde is die van het lezen: eerst waar je verkeer heen gaat, dan of
dat werkt, dan het certificaat, en als laatste of onze eigen voordeur
@@ -956,16 +958,25 @@ body {
<!-- Het adres als onderregel en niet als eigen lijstregel. De twee andere
regels die hier stonden zijn weg: "Chosen in the umbrelOS settings"
was uitleg bij een instelling die je hier toch niet wijzigt, en "Last
checked" staat al onder de blokhoogte als "as of ... ago". -->
checked" staat als "as of ... ago" onder de reactietijd. -->
<div class="stat-sub mono" id="backend-address">${APP_ELECTRS_NODE_IP}:${APP_ELECTRS_NODE_PORT}</div>
</div>
</div>
<!-- Reactietijd vóór blokhoogte, omgedraaid op verzoek van de gebruiker
(27-08-2026). Hij staat daarmee naast de Electrum-server waar hij over
gaat, en de blokhoogte schuift naar het midden van de rij. Let op: dit is
de leesvolgorde in de HTML en dus ook de stapelvolgorde op een smal
scherm; er staat nergens een order in de CSS die daarvan afwijkt. -->
<!-- Reactietijd staat naast de Electrum-server waar hij over gaat. Let op:
dit is de leesvolgorde in de HTML en dus ook de stapelvolgorde op een
smal scherm; er staat nergens een order in de CSS die daarvan afwijkt.
De onderregel met de leeftijd van de meting hoorde tot 0.0.28 bij de
blokhoogte. Die widget is er op verzoek van de gebruiker uit (04-09-2026:
het is niet aan deze app om de blokhoogte te tonen), en de leeftijd
verhuisde mee naar hier. Het is dezelfde meting uit dezelfde ronde, en
zonder deze regel staat er nergens op de pagina meer hoe oud de
gegevens zijn.
Hij staat ná de sparkline en niet ervoor, want de onderregels van de vier
widgets horen op één lijn te staan. Ervoor zou de waarde van déze widget
nog eens de hoogte van de sparkline hoger komen dan de andere drie. -->
<div class="card">
<div class="card-head">
<h2 class="t-h3">Backend response</h2>
@@ -973,16 +984,7 @@ body {
<div class="stat-body">
<div class="stat-val unknown" id="stat-latency">unknown</div>
<svg class="spark" id="spark" viewBox="0 0 100 34" preserveAspectRatio="none" aria-hidden="true"></svg>
</div>
</div>
<div class="card">
<div class="card-head">
<h2 class="t-h3">Block height</h2>
</div>
<div class="stat-body">
<div class="stat-val unknown" id="stat-height">unknown</div>
<div class="stat-sub" id="stat-height-sub"></div>
<div class="stat-sub" id="stat-latency-sub"></div>
</div>
</div>
@@ -1275,8 +1277,8 @@ body {
<!-- Hier stond een voetregel met "Last reading ... ago" en het versienummer. Die
is er op verzoek van de gebruiker uit (19-08-2026): de leeftijd van de
gegevens staat al in de badge bij de Electrum-server en onder de blokhoogte,
en het versienummer is ook in umbrelOS zelf te zien. -->
gegevens staat al onder de reactietijd, en het versienummer is ook in
umbrelOS zelf te zien. -->
</div>
@@ -1403,9 +1405,9 @@ body {
function show(id, on) { el(id).classList.toggle('hidden', !on); }
function num(n) {
return String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ' ');
}
// Hier stond num(), dat een getal met spaties per duizend afbrak. De
// blokhoogte was de enige waarde die groot genoeg was om dat te vragen, en die
// widget is er sinds 0.0.28 uit.
function whenLocal(unix) {
if (!unix) { return null; }
@@ -1427,7 +1429,7 @@ body {
// Hoe oud de gegevens zijn, hangt niet meer aan een melding of een badge. Dat
// is twee keer op verzoek van de gebruiker weggehaald: de melding bovenaan op
// 19-08-2026, de badge bij de Electrum-server op 20-08-2026. Wat het zegt staat
// nog op de plek waar het thuishoort, namelijk onder de blokhoogte als
// nog op de plek waar het thuishoort, namelijk onder de reactietijd als
// "as of ... ago" en in de rij "Last checked".
//
// De leeftijd zelf blijft dus in gebruik, alleen niet meer als aparte
@@ -1440,15 +1442,11 @@ body {
drawSetup(tls.domain, tls.port);
// Blokhoogte
if (typeof backend.height === 'number') {
put('stat-height', num(backend.height));
el('stat-height-sub').textContent = age !== null ? 'as of ' + agoText(age) : '';
}
// Reactietijd
// Reactietijd. De onderregel met de leeftijd van de meting stond tot 0.0.28
// onder de blokhoogte; die widget is eruit en de regel staat nu hier.
if (typeof backend.response_ms === 'number') {
put('stat-latency', backend.response_ms, ' ms');
el('stat-latency-sub').textContent = age !== null ? 'as of ' + agoText(age) : '';
}
drawSpark(s.history || []);
@@ -1499,7 +1497,7 @@ body {
drawCertChoices(s.certificates, cert.selected, nowSec);
// Backend. "Last checked" stond hier als derde lijstregel en is er op
// 27-08-2026 uit: hetzelfde staat onder de blokhoogte als "as of ... ago",
// 27-08-2026 uit: hetzelfde staat onder de reactietijd als "as of ... ago",
// en een widget met drie onderteksten is geen widget meer.
put('backend-name', backend.name);
if (backend.address) { put('backend-address', backend.address); }
+20 -15
View File
@@ -9,7 +9,7 @@ manifestVersion: 1
id: whatsnext-electrum-gate
category: bitcoin
name: Electrum Gate
version: "0.0.27"
version: "0.0.28"
tagline: Your own node from anywhere, without waiting for Tor
description: >-
The privacy win is already yours: you run the Electrum server. A public one gets asked for
@@ -42,9 +42,9 @@ description: >-
it, they already reach the Electrum server directly.
The dashboard hands you the exact line each of those wallets asks for, and shows block
height, certificate expiry and whether your Electrum server is answering. Electrs, Fulcrum
and ElectrumX all work, switchable in the umbrelOS settings.
The dashboard hands you the exact line each of those wallets asks for, and shows how long
your certificate is still good for and whether your Electrum server is answering. Electrs,
Fulcrum and ElectrumX all work, switchable in the umbrelOS settings.
What it does not do: hide that the traffic exists. Your domain is public in the certificate
@@ -56,6 +56,16 @@ description: >-
# staan. In 0.0.9 stond er daardoor drie keer "Earlier releases" en twee keer
# dezelfde 0.0.4-regel. De toets let er nu op.
releaseNotes: >-
The block height tile is gone. This app is a front door for your Electrum server; what the chain is
doing is not its news to report, and every wallet and block explorer you own already tells you. Four
tiles are left, all of them about this gateway: which server your traffic goes to, whether it answers
and how fast, how long your certificate is still good for, and whether the front door itself is up.
How old the readings are now sits under the response time, where it used to sit under the height.
Everything in 0.0.27:
Fixes the Status card reading "Not answering" for five minutes after every restart or update, with
a connection error underneath, while the gateway itself was working fine the whole time. The check
runs from inside the app and it ran before the part it checks had started, so the very first
@@ -82,20 +92,15 @@ releaseNotes: >-
changed.
Everything in 0.0.24, released the day before:
The menu has a new "About this app" item: what the app is for, what it asks of you, and what the
Status card does and does not prove. That last one was the reason for this release. The card used to
read "Answering" with "answered in 7 ms, from inside the app" underneath, which was unclear in both
halves. It now says "Running", with the measurement below it, and the caveat has moved to where there
is room to state it properly: the check runs inside the app, so a router that no longer forwards the
port still reads as Running here.
Earlier releases:
0.0.24 added an "About this app" item to the menu, and changed the Status card from "Answering" with
"answered in 7 ms, from inside the app" underneath to "Running" with the measurement below it. The
caveat moved into that dialog, where there is room to state it: the check runs inside the app, so a
router that no longer forwards the port still reads as Running here.
0.0.23 fixed a page that could go blank or show stale values once another app from the same store was
installed. The page reached its helper by a short name that a second app happened to use as well, so
roughly half of its requests ended up at the wrong one.