De tweede indeling gebouwd, en er ging meer weg dan erbij kwam
Vijf widgets op de bovenste rij, de certificaatkeuze in een dialoog achter een puntjesmenu, het activiteitenlog vol breed, en het instelkader dichtgeklapt met twee kopieerknoppen. Uitgeleverd als 0.0.17. De zelfcontrole uit 0.0.16 heeft daarmee eindelijk een plek om te verschijnen. Wat opvalt is wat er verdween. Twee mechanismen bestonden alleen omdat er kaders naast elkaar stonden: het meerekken van de tegels met de hoogte van hun buur, en het samen groeien en krimpen van log en certificaatkader. Dat tweede was de hele inhoud van 0.0.13. Vijf gelijke widgets en een vol breed log hebben geen buur, dus beide zijn weg, samen met .col-5 en .col-7. De harde eis staat in de code en niet alleen in het plan: de foutmelding "geen certificaat in gebruik" heeft de knop die de dialoog opent. Een verse installatie heeft geen certificaat en de pagina is de enige plek waar je er een kiest; dat achter een menu verstoppen zou de klem van 0.0.3 in een andere vorm zijn. Twee dingen onderweg bijgestuurd. Het menu werd drie punten in plaats van een hamburger, op aanwijzing van de gebruiker, want dat is wat umbrelOS bij zijn eigen apps toont. En het ontwerp beweerde dat de certificaatlijst een lijst was, terwijl die op 20-08 al een dropdown geworden is; dat is rechtgezet in 4a2 en de dropdown is ongewijzigd meeverhuisd. Niet geverifieerd: niets hiervan is in een browser gezien, op geen enkele schermbreedte. Dat staat als taak met de gebruiker als eigenaar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -107,7 +107,7 @@ body {
|
||||
hebben 1,8rem ruimte binnenin en een radius van 28 pixels; met 1rem ertussen
|
||||
is de ruimte tússen twee kaders kleiner dan de ruimte erbinnen, en dan gaan ze
|
||||
aan elkaar plakken. De maat hoort eerder groter dan de binnenruimte te zijn
|
||||
dan kleiner. Zelfde waarde in .stat-grid hieronder, anders valt de rij tegels
|
||||
dan kleiner. Zelfde waarde in .row1 hieronder, anders valt de rij widgets
|
||||
uit de toon met de rij eronder. */
|
||||
gap: 1.5rem;
|
||||
/* stretch en niet start: twee kaders naast elkaar horen even hoog te zijn, en
|
||||
@@ -118,16 +118,14 @@ body {
|
||||
}
|
||||
.grid > * { min-width: 0; }
|
||||
.grid > .card { display: flex; flex-direction: column; }
|
||||
.col-5 { grid-column: span 5; }
|
||||
.col-7 { grid-column: span 7; }
|
||||
/* 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
|
||||
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; }
|
||||
.grid .card { margin-bottom: 0; }
|
||||
|
||||
/* Onder deze breedte is naast elkaar geen winst meer maar gedrang. */
|
||||
@media (max-width: 1100px) {
|
||||
.col-5, .col-7 { grid-column: 1 / -1; }
|
||||
}
|
||||
|
||||
/* ── Typografie ─────────────────────────────────────────────────────────── */
|
||||
.t-h1 { font-size: 2rem; font-weight: 700; letter-spacing: -0.025em; line-height: 1.15; }
|
||||
.t-h3 { font-size: 1.1rem; font-weight: 600; letter-spacing: -0.01em; line-height: 1.3; }
|
||||
@@ -183,23 +181,35 @@ body {
|
||||
[data-theme="light"] .card { box-shadow: 0 1px 3px rgba(0,0,0,0.05), 0 6px 24px rgba(0,0,0,0.04); }
|
||||
.card-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 1.1rem; }
|
||||
|
||||
/* Drie kolommen, en de reactietijd neemt er twee. Er stonden drie tegels van
|
||||
gelijke breedte; de derde was de resterende geldigheid van het certificaat, en
|
||||
die is er op 20-08-2026 uit omdat de kaart eronder hetzelfde zegt met een datum
|
||||
erbij. De ruimte gaat naar de sparkline, want dat is het enige hier dat
|
||||
daadwerkelijk breedte nodig heeft. */
|
||||
.stat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.5rem; }
|
||||
.stat-wide { grid-column: span 2; }
|
||||
/* ── 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.
|
||||
|
||||
/* De drie tegels staan naast een kader met drie lijstregels en zijn van zichzelf
|
||||
lager, wat een gat rechtsboven oplevert. Ze zetten hun getal dus onderaan, zodat
|
||||
de drie getallen onderling op één lijn staan én op de laatste regel van het kader
|
||||
ernaast. In de gestapelde weergave doet dit niets, want daar is geen buur om je
|
||||
aan te meten. */
|
||||
@media (min-width: 1101px) {
|
||||
.stat-grid .card { display: flex; flex-direction: column; }
|
||||
.stat-grid .stat-body { margin-top: auto; }
|
||||
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.
|
||||
|
||||
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. */
|
||||
.row1 {
|
||||
grid-column: 1 / -1;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 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); } }
|
||||
@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. */
|
||||
.row1 .card { display: flex; flex-direction: column; }
|
||||
.row1 .stat-body { margin-top: auto; }
|
||||
|
||||
/* De twee clientlijsten naast elkaar zodra er ruimte is; het zijn twee losse
|
||||
lijsten en geen vervolg op elkaar, dus onder elkaar is verspilde breedte. */
|
||||
@@ -211,6 +221,15 @@ body {
|
||||
.clients { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr)); gap: 1.2rem 2.4rem; }
|
||||
.stat-val { font-size: 1.9rem; font-weight: 700; letter-spacing: -0.025em; font-variant-numeric: tabular-nums; line-height: 1.1; }
|
||||
.stat-val.unknown { color: var(--text-ter); font-size: 1.5rem; }
|
||||
/* Twee widgets tonen een woord in plaats van een getal, en op 1,9rem loopt
|
||||
"Wrong certificate" over drie regels. Kleiner, en met een afbreekpunt, want
|
||||
afkappen met puntjes zou hier de betekenis wegnemen. */
|
||||
.stat-val.text { font-size: 1.3rem; line-height: 1.25; overflow-wrap: anywhere; }
|
||||
/* Rood is voor het geval waar je iets aan moet doen. Bewust niet voor "off": geen
|
||||
certificaat gekozen is de normale begintoestand van een verse installatie, en
|
||||
daar staat de melding bovenaan al voor. */
|
||||
.stat-val.bad { color: var(--neg); }
|
||||
.stat-sub.mono { font-family: var(--font-mono); overflow-wrap: anywhere; }
|
||||
/* Even hoog als de sparkline hieronder, en met dezelfde bovenmarge. Anders staat
|
||||
het getal van "Backend response" hoger dan de andere twee, want daar hangt een
|
||||
grafiekje onder in plaats van een regel tekst. */
|
||||
@@ -317,24 +336,20 @@ body {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.9;
|
||||
/* flex-basis 0 en niet auto, en dát is de hele hoogtekwestie van 20-08-2026.
|
||||
Met basis auto telt de inhoud van dit blok mee voor de natuurlijke hoogte van
|
||||
zijn kader, en dan duwt een log met tien regels de rij hoger dan het
|
||||
certificaatkader ernaast nodig heeft. Het gevolg zag je aan de andere kant:
|
||||
leegte onder de knop "Use this certificate", die precies verdween als je het
|
||||
uploadblok uitklapte.
|
||||
/* Sinds 27-08-2026 neemt dit blok gewoon zijn eigen hoogte. Hier stond
|
||||
flex: 1 1 0, en dat was de oplossing voor een probleem dat niet meer bestaat:
|
||||
het log stond naast het certificaatkader en die twee moesten samen groeien en
|
||||
krimpen, anders viel er leegte onder de knop "Use this certificate" zodra je
|
||||
het uploadblok uitklapte. Dat was de hele inhoud van 0.0.13.
|
||||
|
||||
Met basis 0 draagt dit blok niets bij aan die natuurlijke hoogte. Het
|
||||
certificaatkader bepaalt de rij, dit blok groeit ernaartoe, en uitklappen laat
|
||||
dus beide kaders meegroeien. Wat er niet in past, scrolt hier, en dat is waar
|
||||
een log voor gemaakt is.
|
||||
|
||||
Geen max-height meer: de rij is nu begrensd door het kader ernaast, dus een
|
||||
eigen plafond zou alleen weer leegte onderaan opleveren. */
|
||||
flex: 1 1 0;
|
||||
/* De bodem voor het geval het certificaatkader ooit korter is dan dit, zoals
|
||||
wanneer er geen enkel certificaat gevonden is. Er passen vier regels in. */
|
||||
De certificaatkeuze zit nu in een dialoog en dit kader is vol breed, dus er is
|
||||
geen buur meer om je aan te meten. Wat overblijft is een plafond, want een
|
||||
etmaal aan regels zou anders één lange pagina worden; daarboven scrolt het
|
||||
blok zelf, en dat is waar een log voor gemaakt is. */
|
||||
flex: 0 0 auto;
|
||||
/* Er passen vier regels in; dat is de bodem voor een leeg of net gestart log. */
|
||||
min-height: 110px;
|
||||
max-height: 60vh;
|
||||
overflow: auto;
|
||||
overscroll-behavior: contain;
|
||||
scrollbar-width: thin;
|
||||
@@ -385,6 +400,103 @@ body {
|
||||
/* ── Grafieken ──────────────────────────────────────────────────────────── */
|
||||
.spark { width: 100%; height: 34px; display: block; margin-top: 0.5rem; overflow: visible; }
|
||||
|
||||
/* ── Het menu rechtsboven ───────────────────────────────────────────────── */
|
||||
.menu { position: relative; flex-shrink: 0; }
|
||||
/* Het driehoekje van summary weg, in twee vormen: WebKit heeft zijn eigen
|
||||
pseudo-element en de rest gaat via list-style. */
|
||||
/* Alleen het driehoekje weg en de cursor; de maatvoering staat hieronder bij
|
||||
.menu-button, want twee regels die allebei padding zetten laten de meest
|
||||
specifieke winnen en dat is deze. */
|
||||
.menu > summary { list-style: none; cursor: pointer; }
|
||||
.menu > summary::-webkit-details-marker { display: none; }
|
||||
.menu > summary::marker { content: ''; }
|
||||
/* Flink, want drie punten op de gewone knopgrootte van 0,75rem zijn nauwelijks
|
||||
te zien en al helemaal niet te raken. De letterafstand zet ze uit elkaar,
|
||||
anders plakken ze in de meeste letterfamilies aan elkaar. De vaste hoogte en
|
||||
line-height houden de knop even hoog als hij met tekst erin zou zijn. */
|
||||
.menu-button {
|
||||
font-size: 1.4rem;
|
||||
line-height: 1;
|
||||
letter-spacing: 0.08em;
|
||||
padding: 0.3rem 0.7rem 0.5rem;
|
||||
min-height: 2rem;
|
||||
}
|
||||
.menu-panel {
|
||||
position: absolute; right: 0; top: calc(100% + 0.4rem);
|
||||
z-index: 20; min-width: 15rem;
|
||||
background: var(--bg-elevated);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 0.35rem;
|
||||
box-shadow: 0 8px 30px rgba(0,0,0,0.18);
|
||||
}
|
||||
.menu-item {
|
||||
display: flex; align-items: center; justify-content: space-between; gap: 1.2rem;
|
||||
width: 100%; text-align: left;
|
||||
font-family: inherit; font-size: 0.82rem; color: var(--text-primary);
|
||||
background: transparent; border: 0; border-radius: var(--radius-sm);
|
||||
padding: 0.55rem 0.65rem; cursor: pointer;
|
||||
}
|
||||
.menu-item:hover { background: var(--neutral-bg); }
|
||||
.menu-meta { font-size: 0.75rem; color: var(--text-sec); }
|
||||
|
||||
/* ── De dialoog ─────────────────────────────────────────────────────────── */
|
||||
/* Breder dan het kader waar deze inhoud uit komt, en dat mag: een dialoog leent
|
||||
geen hoogte van een buur, dus de keuzelijst en het uploadblok kunnen hier
|
||||
gewoon staan zonder dat er elders leegte ontstaat. */
|
||||
.sheet {
|
||||
/* Alleen van belang in de terugvalroute zonder showModal; zie de HTML. */
|
||||
grid-column: 1 / -1;
|
||||
width: min(46rem, calc(100vw - 2rem));
|
||||
max-height: min(44rem, calc(100vh - 4rem));
|
||||
padding: 0;
|
||||
color: var(--text-primary);
|
||||
background: var(--bg-elevated);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius-lg);
|
||||
overflow: hidden;
|
||||
}
|
||||
.sheet::backdrop { background: rgba(0,0,0,0.55); }
|
||||
.sheet-head {
|
||||
display: flex; align-items: center; justify-content: space-between; gap: 1rem;
|
||||
padding: 1.3rem 1.5rem; border-bottom: 1px solid var(--border);
|
||||
}
|
||||
/* Alleen dit deel scrollt, zodat de sluitknop in beeld blijft bij twintig
|
||||
certificaten. */
|
||||
.sheet-body {
|
||||
padding: 0.4rem 1.5rem 1.5rem;
|
||||
overflow: auto;
|
||||
max-height: calc(min(44rem, 100vh - 4rem) - 5rem);
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: var(--scrollbar) transparent;
|
||||
}
|
||||
|
||||
/* De knop in de foutmelding "geen certificaat in gebruik". Op een eigen regel,
|
||||
want in de melding staat een zin die je eerst leest. */
|
||||
.alert-action { margin-top: 0.7rem; }
|
||||
|
||||
/* ── Het instelkader ────────────────────────────────────────────────────── */
|
||||
.setup > summary { list-style: none; cursor: pointer; display: flex; align-items: baseline; gap: 0.8rem; flex-wrap: wrap; }
|
||||
.setup > summary::-webkit-details-marker { display: none; }
|
||||
.setup > summary::marker { content: ''; }
|
||||
/* Een chevron die meedraait, want zonder het driehoekje van de browser is er
|
||||
verder niets dat zegt dat dit open kan. */
|
||||
.setup > summary::after {
|
||||
content: ''; margin-left: auto; width: 0.5rem; height: 0.5rem;
|
||||
border-right: 2px solid var(--text-sec); border-bottom: 2px solid var(--text-sec);
|
||||
transform: rotate(45deg); transition: transform 0.2s var(--ease-out);
|
||||
}
|
||||
.setup[open] > summary::after { transform: rotate(-135deg); }
|
||||
.setup-form { min-width: 0; }
|
||||
.setup-value {
|
||||
display: flex; align-items: center; gap: 0.7rem; flex-wrap: wrap;
|
||||
margin: 0.45rem 0 0.55rem;
|
||||
}
|
||||
/* De wallets onder de vorm die ze vragen. Naam en vindplaats op één regel, want
|
||||
het gaat om het herkennen van je eigen wallet en niet om een handleiding. */
|
||||
.setup-wallets { font-size: 0.75rem; line-height: 1.7; color: var(--text-sec); }
|
||||
.setup-wallets strong { color: var(--text-primary); font-weight: 600; }
|
||||
|
||||
.hidden { display: none !important; }
|
||||
|
||||
/* Onder deze breedte past een regel niet meer naast zijn label. Alles wat op een
|
||||
@@ -413,14 +525,9 @@ body {
|
||||
.log-event { width: auto; }
|
||||
.log-detail { flex-basis: 100%; }
|
||||
|
||||
/* Op één kolom staat er geen kader meer naast om de hoogte van te lenen, dus
|
||||
hier neemt het log wél zijn eigen hoogte. Met een plafond, want anders wordt
|
||||
een etmaal aan regels één lange pagina; daarboven scrolt het blok zelf. */
|
||||
.log { flex: 0 0 auto; min-height: 0; max-height: 60vh; }
|
||||
|
||||
/* De tegels op elkaar, en dan neemt de reactietijd geen twee kolommen meer. */
|
||||
.stat-grid { grid-template-columns: 1fr; }
|
||||
.stat-wide { grid-column: auto; }
|
||||
/* Het plafond blijft, de bodem niet: op een telefoon is 110 pixels aan lege
|
||||
loghoogte zonde van het scherm. */
|
||||
.log { min-height: 0; }
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
@@ -456,9 +563,41 @@ body {
|
||||
tests/test_server_start_zonder_certificaat.py houdt ze gelijk. -->
|
||||
<p class="t-body-sm">Your own node from anywhere, without waiting for Tor <span class="head-version">v${APP_VERSION}</span></p>
|
||||
</div>
|
||||
<button class="btn" id="theme-toggle" type="button" title="Switch between light and dark">
|
||||
<span id="theme-label">Light</span>
|
||||
</button>
|
||||
<!-- Het menu rechtsboven. Hier stond een losse knop voor licht en donker; die
|
||||
is er op verzoek van de gebruiker (27-08-2026) in gegaan, samen met het
|
||||
certificaatbeheer. Wat hier staat is wat je zelden aanraakt, en de kop
|
||||
houdt daardoor niets meer dan het merk en de tagline.
|
||||
|
||||
Met details/summary en niet met eigen JavaScript, want dan werkt openen
|
||||
en sluiten met het toetsenbord zonder dat wij daar iets voor doen. Wat er
|
||||
wél bij moet is sluiten op Escape en bij een klik ernaast; dat staat in
|
||||
het script, want dat kent details van zichzelf niet. -->
|
||||
<details class="menu" id="menu">
|
||||
<!-- Drie punten en geen hamburger, op aanwijzing van de gebruiker
|
||||
(27-08-2026): dat is wat umbrelOS bij zijn eigen apps toont, en een
|
||||
pagina die in dat dashboard hangt hoort daar niet van af te wijken.
|
||||
|
||||
Als tekst en niet als SVG, want dan schaalt hij mee met de lettergrootte
|
||||
van de gebruiker. Middelste punten (U+00B7) en geen gewone punten: die
|
||||
staan op de basislijn en zakken dus naar de onderrand van de knop,
|
||||
terwijl deze vanzelf op halve hoogte staan. Hetzelfde teken dat elders
|
||||
op deze pagina de velden in een keuzeregel scheidt. -->
|
||||
<summary class="btn menu-button" title="Settings" aria-label="Settings">···</summary>
|
||||
<div class="menu-panel">
|
||||
<button class="menu-item" id="menu-certs" type="button">
|
||||
<span>Certificates</span>
|
||||
<span class="menu-meta" id="menu-certs-meta"></span>
|
||||
</button>
|
||||
<!-- De regel toont de huidige stand en niet de handeling. De losse knop
|
||||
hiervoor deed het andersom, met "Light" terwijl de pagina donker was.
|
||||
Als knop klopte dat, want dat was waar je heen ging; als menuregel
|
||||
leest het als een bewering over hoe het nú staat, en dan is het fout. -->
|
||||
<button class="menu-item" id="menu-theme" type="button">
|
||||
<span>Appearance</span>
|
||||
<span class="menu-meta" id="theme-label">Dark</span>
|
||||
</button>
|
||||
</div>
|
||||
</details>
|
||||
</header>
|
||||
|
||||
<!-- Meldingen. Alle drie standaard verborgen; het script bepaalt welke past. -->
|
||||
@@ -499,6 +638,13 @@ body {
|
||||
<span>
|
||||
<span class="alert-title">No certificate in use, so TLS is not running</span>
|
||||
<span class="alert-body" id="alert-nocert-body"></span>
|
||||
<!-- Deze knop is geen extraatje maar de eis die de nieuwe indeling zelf
|
||||
oproept. De certificaatkeuze zit sinds 27-08-2026 achter het menu, en
|
||||
dit is precies de toestand waarin een gebruiker die keuze móet kunnen
|
||||
vinden: een verse installatie heeft er nog geen. Dat is de klem van
|
||||
0.0.3 in een andere vorm, en die komt niet terug. Het menu is de weg
|
||||
terug voor later, deze knop is de weg erheen nu. Zie PLAN.md 4a2. -->
|
||||
<button class="btn alert-action" id="alert-nocert-open" type="button">Choose a certificate</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -510,38 +656,34 @@ body {
|
||||
schermen stapelt hij precies zo. -->
|
||||
<div class="grid">
|
||||
|
||||
<section class="card col-5">
|
||||
<div class="card-head">
|
||||
<h2 class="t-h3">Electrum server</h2>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">Address</div>
|
||||
<div class="list-item-sub">Chosen in the umbrelOS settings, not in this app</div>
|
||||
</div>
|
||||
<div class="list-item-val mono" id="backend-address">${APP_ELECTRS_NODE_IP}:${APP_ELECTRS_NODE_PORT}</div>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">Implementation</div>
|
||||
<div class="list-item-sub">Recognised by address; shown as unknown if it has moved</div>
|
||||
<!-- Vijf widgets, alle vijf 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.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
antwoordt. -->
|
||||
<div class="row1">
|
||||
<div class="card">
|
||||
<div class="card-head">
|
||||
<h2 class="t-h3">Electrum server</h2>
|
||||
</div>
|
||||
<div class="list-item-val unknown" id="backend-name">unknown</div>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">Last checked</div>
|
||||
<div class="list-item-sub">Written by the proxy itself, not measured by this page</div>
|
||||
<div class="stat-body">
|
||||
<div class="stat-val text unknown" id="backend-name">unknown</div>
|
||||
<!-- 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". -->
|
||||
<div class="stat-sub mono" id="backend-address">${APP_ELECTRS_NODE_IP}:${APP_ELECTRS_NODE_PORT}</div>
|
||||
</div>
|
||||
<div class="list-item-val unknown" id="backend-checked">unknown</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- De drie getallen die zeggen of het goed gaat. Precies zo opgebouwd als elk
|
||||
ander kader op deze pagina: een card-head met een titel erin, dan de inhoud.
|
||||
Ze hadden eerst een eigen kleine grijze kop in kapitalen, en dat maakte ze
|
||||
een apart soort ding zonder dat daar een reden voor was. -->
|
||||
<div class="stat-grid col-7">
|
||||
<div class="card">
|
||||
<div class="card-head">
|
||||
<h2 class="t-h3">Block height</h2>
|
||||
@@ -551,13 +693,8 @@ body {
|
||||
<div class="stat-sub" id="stat-height-sub"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Twee kolommen breed. Hiernaast stond een derde tegel met het aantal dagen
|
||||
dat het certificaat nog geldig is, en die is er op verzoek van de
|
||||
gebruiker uit (20-08-2026): de kaart Certificate hieronder zegt hetzelfde
|
||||
en noemt de datum erbij, en bij minder dan dertig dagen staat er een
|
||||
melding bovenaan de pagina. De vrijgekomen ruimte gaat hierheen, want de
|
||||
sparkline is het enige op deze rij dat er iets mee doet. -->
|
||||
<div class="card stat-wide">
|
||||
|
||||
<div class="card">
|
||||
<div class="card-head">
|
||||
<h2 class="t-h3">Backend response</h2>
|
||||
</div>
|
||||
@@ -566,30 +703,78 @@ body {
|
||||
<svg class="spark" id="spark" viewBox="0 0 100 34" preserveAspectRatio="none" aria-hidden="true"></svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Het certificaat als getal en niet als kaart. Kiezen, uploaden en de
|
||||
details zitten sinds 27-08-2026 in de dialoog achter het menu; wat hier
|
||||
staat is wat je in één oogopslag wilt weten. Het aantal dagen tot
|
||||
vernieuwing stond hier eerder als tegel en is er op 20-08-2026 uit
|
||||
gegaan omdat de kaart eronder hetzelfde zei. Die kaart is er nu niet
|
||||
meer, dus het getal komt terug. -->
|
||||
<div class="card">
|
||||
<div class="card-head">
|
||||
<h2 class="t-h3">Certificate</h2>
|
||||
</div>
|
||||
<div class="stat-body">
|
||||
<div class="stat-val unknown" id="cert-days">unknown</div>
|
||||
<div class="stat-sub mono" id="cert-domain">unknown</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- De zelfcontrole, gebouwd in 0.0.16. Dit is de enige widget die over deze
|
||||
app zelf gaat en niet over iets waar hij naar kijkt.
|
||||
|
||||
Let op het woord dat hier NIET staat: "reachable". De agent verbindt van
|
||||
container naar container, dus een router die de poort niet meer
|
||||
doorstuurt leest hier als in orde. Wat er gemeten is, is de voordeur zelf
|
||||
en niet de weg ernaartoe; de onderregel zegt dat er ook bij. -->
|
||||
<div class="card">
|
||||
<div class="card-head">
|
||||
<h2 class="t-h3">Gateway</h2>
|
||||
</div>
|
||||
<div class="stat-body">
|
||||
<div class="stat-val text unknown" id="self-state">unknown</div>
|
||||
<div class="stat-sub" id="self-sub"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="card col-5">
|
||||
<div class="card-head">
|
||||
<h2 class="t-h3">Certificate</h2>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">In use</div>
|
||||
<div class="list-item-sub" id="cert-source">source unknown</div>
|
||||
<!-- De dialoog met alles wat met certificaten te maken heeft: de huidige, de
|
||||
keuze, en het uploaden. Te openen uit het menu rechtsboven en uit de
|
||||
foutmelding bovenaan.
|
||||
|
||||
Met het dialog-element en niet met een eigen overlay: focus, Escape en het
|
||||
afschermen van de pagina erachter zitten erin.
|
||||
|
||||
Hij staat binnen het raster en dat maakt in de praktijk niets uit: dicht is
|
||||
een dialog display:none, en open via showModal() staat hij in de top layer,
|
||||
dus in geen van beide gevallen is hij een rastercel. Alleen de terugvalroute
|
||||
voor een browser zonder showModal zet hem gewoon in de stroom, en daarvoor
|
||||
staat er in .sheet een grid-column op de volle breedte. -->
|
||||
<dialog id="cert-dialog" class="sheet">
|
||||
<form method="dialog" class="sheet-head">
|
||||
<h2 class="t-h3">Certificates</h2>
|
||||
<button class="btn" value="close" aria-label="Close">Close</button>
|
||||
</form>
|
||||
|
||||
<div class="sheet-body">
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">In use</div>
|
||||
<div class="list-item-sub" id="cert-source">source unknown</div>
|
||||
</div>
|
||||
<div class="list-item-val mono unknown" id="cert-dialog-domain">unknown</div>
|
||||
</div>
|
||||
<div class="list-item-val mono unknown" id="cert-domain">unknown</div>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<div><div class="list-item-title">Valid until</div></div>
|
||||
<div class="list-item-val unknown" id="cert-until">unknown</div>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">Last reload</div>
|
||||
<div class="list-item-sub">A renewal is reloaded, so open connections stay up</div>
|
||||
<div class="list-item">
|
||||
<div><div class="list-item-title">Valid until</div></div>
|
||||
<div class="list-item-val unknown" id="cert-until">unknown</div>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<div>
|
||||
<div class="list-item-title">Last reload</div>
|
||||
<div class="list-item-sub">A renewal is reloaded, so open connections stay up</div>
|
||||
</div>
|
||||
<div class="list-item-val unknown" id="cert-reload">unknown</div>
|
||||
</div>
|
||||
<div class="list-item-val unknown" id="cert-reload">unknown</div>
|
||||
</div>
|
||||
|
||||
<!-- Ingeklapt, want dit is voor wie geen reverse proxy heeft en dat is de
|
||||
uitzondering. Dichtgeklapt kost het één regel, en dat was de opdracht:
|
||||
@@ -597,11 +782,9 @@ body {
|
||||
komt uit de hostnaam in het certificaat zelf, en dat is ook precies
|
||||
waarom er geen padtrucs mogelijk zijn.
|
||||
|
||||
Hier en niet onder de keuzeknop, op verzoek van de gebruiker
|
||||
(20-08-2026). Twee redenen: het spaart een horizontale lijn uit, want de
|
||||
rij hierboven trekt er al een, en het is de logische volgorde. Wat je
|
||||
uploadt komt in de keuzelijst hieronder terecht, dus eerst toevoegen en
|
||||
dan kiezen. -->
|
||||
Boven de keuzelijst en niet eronder, op verzoek van de gebruiker
|
||||
(20-08-2026): wat je uploadt komt in die lijst terecht, dus eerst
|
||||
toevoegen en dan kiezen. -->
|
||||
<details class="upload">
|
||||
<summary>Upload your own certificate</summary>
|
||||
<p class="t-caption" style="margin: 0.5rem 0 0.8rem;">
|
||||
@@ -629,11 +812,10 @@ body {
|
||||
<span class="t-label">Choose a certificate</span>
|
||||
<span class="t-caption" id="cert-count"></span>
|
||||
</div>
|
||||
<!-- Eén regel, om twee redenen. Het scheelt hoogte, en dit kader bepaalt de
|
||||
hoogte van de rij. En de oude tekst noemde Nginx Proxy Manager als bron,
|
||||
terwijl die mount nog uitgecommentarieerd staat in de compose omdat het
|
||||
pad niet geverifieerd is; wat er stond kon dus niet waar zijn. Waar een
|
||||
certificaat vandaan komt staat toch al in de optie zelf. -->
|
||||
<!-- Eén regel. De oude tekst noemde Nginx Proxy Manager als bron, terwijl die
|
||||
mount nog uitgecommentarieerd staat in de compose omdat het pad niet
|
||||
geverifieerd is; wat er stond kon dus niet waar zijn. Waar een certificaat
|
||||
vandaan komt staat toch al in de optie zelf. -->
|
||||
<p class="t-caption" style="margin-bottom: 0.6rem;">
|
||||
Pick the one matching the name your wallet connects to.
|
||||
</p>
|
||||
@@ -642,17 +824,20 @@ body {
|
||||
<button class="btn btn-solid" id="cert-apply" type="button" disabled>Use this certificate</button>
|
||||
<span class="t-caption" id="cert-apply-note"></span>
|
||||
</div>
|
||||
</section>
|
||||
</div><!-- /sheet-body -->
|
||||
</dialog>
|
||||
|
||||
<!-- Voorstel, nog niet besloten. De agent stelt de regels samen uit de
|
||||
stream-access-log van nginx. Bewust zonder client-IP en zonder bronpoort:
|
||||
dat is precies het soort gegeven dat deze app dichtzet, en het is niet
|
||||
nodig om te zien of het werkt.
|
||||
|
||||
Staat rechts en is het brede kader van de twee: logregels zijn monospace en
|
||||
hebben breedte nodig, en zo valt de kolomgrens samen met die van de rij
|
||||
erboven in plaats van ertegenin. -->
|
||||
<section class="card col-7">
|
||||
Over de volle breedte sinds 27-08-2026. Het stond naast het
|
||||
certificaatkader, en die twee moesten daarvoor samen groeien en krimpen;
|
||||
dat was de hele inhoud van 0.0.13. Nu de certificaatkeuze in een dialoog
|
||||
zit, is er geen buur meer en vervalt die koppeling. Logregels zijn
|
||||
monospace en hadden de breedte toch al het hardst nodig. -->
|
||||
<section class="card col-full">
|
||||
<div class="card-head">
|
||||
<h2 class="t-h3">Activity log</h2>
|
||||
</div>
|
||||
@@ -668,35 +853,57 @@ body {
|
||||
kopieerknop zat eerst in een eigen kader erboven; dat was hetzelfde kader
|
||||
twee keer, dus het is hierin opgegaan. -->
|
||||
<section class="card col-full">
|
||||
<div class="card-head">
|
||||
<h2 class="t-h3">Setting up your wallet</h2>
|
||||
</div>
|
||||
<!-- Dichtgeklapt, op verzoek van de gebruiker (27-08-2026). Dit kader heb je
|
||||
één keer nodig en daarna nooit meer, en open nam het het onderste derde
|
||||
deel van de pagina.
|
||||
|
||||
<!-- Hier stond het verbindingsadres nog een keer groot, met een kopieerknop.
|
||||
Weg op verzoek van de gebruiker (19-08-2026), en zonder verlies: datzelfde
|
||||
adres staat hieronder bij elke client, in de vorm die díe client wil, en
|
||||
daar zit de kopieerknop ook. -->
|
||||
<p class="t-caption" style="margin: 0 0 1.4rem;">
|
||||
Use <strong>SSL</strong> as the connection type. If you connect from outside your own network, your
|
||||
router may forward a different external port to this one.
|
||||
</p>
|
||||
Er staan nu twee kopieerknoppen in plaats van één per wallet. Dat draait
|
||||
een besluit van 19-08-2026 terug, en dat is opgeschreven in PLAN.md 4a2
|
||||
zodat het niet per ongeluk hersteld wordt: er zijn feitelijk maar twee
|
||||
vormen van hetzelfde adres, dus tien knoppen waren negen keer dezelfde
|
||||
handeling.
|
||||
|
||||
<div class="clients">
|
||||
<div>
|
||||
<div class="t-label" style="margin-bottom: 0.4rem;">Paste as one line</div>
|
||||
<div id="clients-oneline"></div>
|
||||
Wat daarbij niet verloren mocht gaan is wélke wallet welke vorm wil. De
|
||||
wallets staan daarom onder de vorm die ze vragen en niet als één lijst
|
||||
ernaast; zonder die groepering staat er wel een adres, maar niet meer
|
||||
waar het bij hoort. -->
|
||||
<details class="setup" id="setup">
|
||||
<summary class="setup-summary">
|
||||
<span class="t-h3">Setting up your wallet</span>
|
||||
<span class="t-caption">The address to paste, per wallet</span>
|
||||
</summary>
|
||||
|
||||
<p class="t-caption" style="margin: 1rem 0 1.2rem;">
|
||||
Use <strong>SSL</strong> as the connection type. If you connect from outside your own network, your
|
||||
router may forward a different external port to this one.
|
||||
</p>
|
||||
|
||||
<div class="clients">
|
||||
<div class="setup-form">
|
||||
<div class="t-label">Paste as one line</div>
|
||||
<div class="setup-value">
|
||||
<span class="list-item-val mono unknown" id="oneline-value">unknown</span>
|
||||
<button class="btn" id="oneline-copy" type="button">Copy</button>
|
||||
</div>
|
||||
<div class="setup-wallets" id="oneline-wallets"></div>
|
||||
</div>
|
||||
<div class="setup-form">
|
||||
<div class="t-label">Host and port separately, with SSL turned on</div>
|
||||
<div class="setup-value">
|
||||
<span class="list-item-val mono unknown" id="split-value">unknown</span>
|
||||
<span class="t-caption" id="split-port"></span>
|
||||
<button class="btn" id="split-copy" type="button">Copy</button>
|
||||
</div>
|
||||
<div class="setup-wallets" id="split-wallets"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="t-label" style="margin-bottom: 0.4rem;">Host and port separately, with SSL turned on</div>
|
||||
<div id="clients-split"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="t-caption" style="margin-top: 1.2rem;">
|
||||
Wasabi and Samourai use their own backend and do not speak the Electrum protocol. Specter Desktop
|
||||
talks to Bitcoin Core directly. Hardware wallets connect through one of the apps above rather than
|
||||
on their own.
|
||||
</p>
|
||||
<p class="t-caption" style="margin-top: 1.2rem;">
|
||||
Wasabi and Samourai use their own backend and do not speak the Electrum protocol. Specter Desktop
|
||||
talks to Bitcoin Core directly. Hardware wallets connect through one of the apps above rather than
|
||||
on their own.
|
||||
</p>
|
||||
</details>
|
||||
</section>
|
||||
|
||||
</div><!-- /grid -->
|
||||
@@ -749,15 +956,55 @@ body {
|
||||
|
||||
function applyTheme(theme) {
|
||||
root.setAttribute('data-theme', theme);
|
||||
document.getElementById('theme-label').textContent = theme === 'dark' ? 'Light' : 'Dark';
|
||||
// De huidige stand en niet waar je heen gaat. Als losse knop stond hier het
|
||||
// omgekeerde, en dáár klopte dat: een knop belooft wat er gebeurt als je hem
|
||||
// indrukt. Een menuregel met een waarde erachter leest als een bewering over
|
||||
// hoe het nu staat, en dan is dezelfde tekst ineens fout.
|
||||
document.getElementById('theme-label').textContent = theme === 'dark' ? 'Dark' : 'Light';
|
||||
}
|
||||
|
||||
document.getElementById('theme-toggle').addEventListener('click', function () {
|
||||
document.getElementById('menu-theme').addEventListener('click', function () {
|
||||
var next = root.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
|
||||
applyTheme(next);
|
||||
try { localStorage.setItem('eg-theme', next); } catch (e) { /* privémodus; niet erg */ }
|
||||
});
|
||||
|
||||
// ── Het menu ────────────────────────────────────────────────────────────
|
||||
// details opent en sluit zichzelf, ook met het toetsenbord. Wat het niet doet
|
||||
// is sluiten bij een klik ernaast of op Escape, en dat is bij een menu wel de
|
||||
// verwachting. Vandaar deze twee, en niet meer dan deze twee.
|
||||
var menu = el('menu');
|
||||
|
||||
function closeMenu() { menu.removeAttribute('open'); }
|
||||
|
||||
document.addEventListener('click', function (e) {
|
||||
if (menu.hasAttribute('open') && !menu.contains(e.target)) { closeMenu(); }
|
||||
});
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape' && menu.hasAttribute('open')) { closeMenu(); }
|
||||
});
|
||||
|
||||
// ── De certificaatdialoog ───────────────────────────────────────────────
|
||||
// Twee wegen erheen, en dat is met opzet. Het menu is de weg voor wie later
|
||||
// iets wil wijzigen; de knop in de foutmelding is de weg voor wie nog nooit een
|
||||
// certificaat gekozen heeft, en dat is de enige toestand waarin deze pagina
|
||||
// écht iets van je vraagt. Zie PLAN.md 4a2.
|
||||
var sheet = el('cert-dialog');
|
||||
|
||||
function openSheet() {
|
||||
closeMenu();
|
||||
if (typeof sheet.showModal === 'function') {
|
||||
sheet.showModal();
|
||||
} else {
|
||||
// Zonder showModal geen overlay en geen focusval, maar wel een zichtbare
|
||||
// dialoog. Beter dan een knop die niets doet.
|
||||
sheet.setAttribute('open', '');
|
||||
}
|
||||
}
|
||||
|
||||
el('menu-certs').addEventListener('click', openSheet);
|
||||
el('alert-nocert-open').addEventListener('click', openSheet);
|
||||
|
||||
// ── Hulpjes ─────────────────────────────────────────────────────────────
|
||||
function el(id) { return document.getElementById(id); }
|
||||
|
||||
@@ -812,7 +1059,7 @@ body {
|
||||
var backend = s.backend || {};
|
||||
var cert = s.certificate || {};
|
||||
|
||||
drawClients(tls.domain, tls.port);
|
||||
drawSetup(tls.domain, tls.port);
|
||||
|
||||
// Blokhoogte
|
||||
if (typeof backend.height === 'number') {
|
||||
@@ -826,14 +1073,29 @@ body {
|
||||
}
|
||||
drawSpark(s.history || []);
|
||||
|
||||
// Certificaat
|
||||
// Certificaat. Het aantal dagen tot vernieuwing staat sinds 27-08-2026 weer
|
||||
// als widget op de pagina; het stond er tot 20-08-2026 als tegel en ging er
|
||||
// toen uit omdat de kaart eronder hetzelfde zei. Die kaart is nu een dialoog,
|
||||
// dus de dubbeling is weg en het getal hoort weer op de pagina.
|
||||
var daysLeft = null;
|
||||
// daysLeft stuurt alleen nog de melding bovenaan; de tegel die dit getal
|
||||
// toonde is eruit. De kaart hieronder noemt de datum, en dat is wat je wilt
|
||||
// weten als je hier komt kijken.
|
||||
var days = el('cert-days');
|
||||
days.classList.remove('bad', 'text');
|
||||
if (cert.not_after) {
|
||||
daysLeft = Math.floor((cert.not_after - nowSec) / 86400);
|
||||
put('cert-until', whenLocal(cert.not_after));
|
||||
if (daysLeft < 0) {
|
||||
put('cert-days', 'expired');
|
||||
days.classList.add('bad', 'text');
|
||||
} else {
|
||||
put('cert-days', daysLeft + (daysLeft === 1 ? ' day' : ' days'));
|
||||
}
|
||||
} else if (!cert.selected) {
|
||||
// Niet 'unknown': er is niets onbekends aan: er is er geen. De melding
|
||||
// bovenaan zegt wat je eraan doet, dus hier volstaat het woord.
|
||||
put('cert-days', 'none');
|
||||
days.classList.add('text');
|
||||
} else {
|
||||
put('cert-days', null);
|
||||
}
|
||||
// Geen actief certificaat betekent geen TLS, en dat is het ergste wat deze
|
||||
// app kan overkomen. Dus geen subtiele grijze tekst maar de foutmelding
|
||||
@@ -848,15 +1110,23 @@ body {
|
||||
el('cert-source').textContent = cert.source
|
||||
? 'from ' + cert.source + (cert.reason ? ' · ' + cert.reason : '')
|
||||
: (cert.reason || 'source unknown');
|
||||
// Twee keer dezelfde naam: als onderregel van de widget en in de dialoog. Dat
|
||||
// is geen dubbeling maar twee plekken die elkaar niet zien; wie de dialoog
|
||||
// opent, hoort er niet voor terug te hoeven bladeren.
|
||||
put('cert-domain', tls.domain);
|
||||
put('cert-dialog-domain', tls.domain);
|
||||
put('cert-reload', whenLocal(cert.last_reload));
|
||||
el('menu-certs-meta').textContent = cert.selected ? (tls.domain || 'in use') : 'none in use';
|
||||
renderCertAlert(daysLeft);
|
||||
drawCertChoices(s.certificates, cert.selected, nowSec);
|
||||
|
||||
// Backend
|
||||
// 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",
|
||||
// en een widget met drie onderteksten is geen widget meer.
|
||||
put('backend-name', backend.name);
|
||||
if (backend.address) { put('backend-address', backend.address); }
|
||||
put('backend-checked', age !== null ? agoText(age) : null);
|
||||
|
||||
drawSelfCheck(tls.self_check);
|
||||
|
||||
// Hier stond een badge met "answered 7 seconds ago". Die is eruit op verzoek
|
||||
// van de gebruiker (20-08-2026), en met reden: de rij "Last checked" eronder
|
||||
@@ -901,6 +1171,54 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
// ── De zelfcontrole ─────────────────────────────────────────────────────
|
||||
// Gebouwd in de agent in 0.0.16, hier getoond sinds de tweede indeling.
|
||||
//
|
||||
// Let op het woord dat hier niet staat: "reachable". De agent verbindt van
|
||||
// container naar container, dus dit zegt niets over de poortmapping naar de
|
||||
// host of over de doorstuurregel in de router. "Answering" met daaronder "from
|
||||
// inside the app" is wat er gemeten is; alles wat verder gaat, zou de tegel
|
||||
// laten liegen op precies het punt waar iemand hem gelooft.
|
||||
var SELF = {
|
||||
ok: { label: 'Answering', bad: false },
|
||||
failed: { label: 'Not answering', bad: true },
|
||||
'wrong-certificate': { label: 'Wrong certificate', bad: true },
|
||||
// Geen certificaat is de normale begintoestand van een verse installatie en
|
||||
// dus niet rood; de melding bovenaan zegt al wat eraan te doen is.
|
||||
off: { label: 'Off', bad: false },
|
||||
pending: { label: 'Checking', bad: false }
|
||||
};
|
||||
|
||||
function drawSelfCheck(self) {
|
||||
var node = el('self-state');
|
||||
var sub = el('self-sub');
|
||||
var kind = self && self.state ? SELF[self.state] : null;
|
||||
|
||||
if (!kind) {
|
||||
put('self-state', null);
|
||||
node.classList.remove('bad');
|
||||
// Dit is de toestand op een installatie met een oudere agent. Zwijgen zou
|
||||
// hier als "in orde" lezen.
|
||||
sub.textContent = self ? 'Reported as ' + self.state : 'The agent has not reported this yet.';
|
||||
return;
|
||||
}
|
||||
|
||||
put('self-state', kind.label);
|
||||
node.classList.toggle('bad', kind.bad);
|
||||
|
||||
if (self.state === 'ok') {
|
||||
sub.textContent = 'answered in ' + self.ms + ' ms, from inside the app';
|
||||
} else if (self.state === 'off') {
|
||||
sub.textContent = 'no certificate selected, so nothing is listening';
|
||||
} else if (self.state === 'wrong-certificate') {
|
||||
sub.textContent = 'not the certificate you selected; a reload may have failed';
|
||||
} else if (self.state === 'pending') {
|
||||
sub.textContent = 'measuring again after the certificate change';
|
||||
} else {
|
||||
sub.textContent = self.error ? String(self.error) : 'no reason given';
|
||||
}
|
||||
}
|
||||
|
||||
// ── Certificaatkeuze ────────────────────────────────────────────────────
|
||||
// De lus schrijft in status.json wat hij in de drie gemounte mappen gevonden
|
||||
// heeft. De keuze gaat er met een PUT naartoe; de lus leest dat bestand en
|
||||
@@ -1082,74 +1400,56 @@ body {
|
||||
});
|
||||
});
|
||||
|
||||
// ── Clientregels ────────────────────────────────────────────────────────
|
||||
// Zonder domein en poort krijgt elke rij hetzelfde onbekend-veld als de rest
|
||||
// van de pagina. Een half ingevulde regel die iemand toch kopieert, is erger
|
||||
// dan een lege.
|
||||
function drawClients(domain, port) {
|
||||
fill('clients-oneline', CLIENTS_ONELINE, function () {
|
||||
return (domain && port) ? domain + ':' + port + ':s' : null;
|
||||
});
|
||||
fill('clients-split', CLIENTS_SPLIT, function () {
|
||||
return domain ? domain : null;
|
||||
}, port ? 'port ' + port : null);
|
||||
// ── Het instelkader ─────────────────────────────────────────────────────
|
||||
// Twee vormen van hetzelfde adres, dus twee kopieerknoppen (27-08-2026). Hier
|
||||
// stond een kopieerknop per wallet, tien in totaal, en dat waren negen keer
|
||||
// dezelfde handeling. Dat draait een besluit van 19-08-2026 terug; PLAN.md 4a2
|
||||
// zegt waarom, zodat het niet per ongeluk hersteld wordt.
|
||||
//
|
||||
// De wallets blijven wél onder de vorm staan die ze vragen. Dat is de
|
||||
// voorwaarde bij die vereenvoudiging: welke wallet welk formaat wil, is precies
|
||||
// wat dit kader te vertellen heeft, en één lijst naast twee losse knoppen
|
||||
// gooit dat weg.
|
||||
//
|
||||
// Zonder domein en poort blijft de waarde op 'unknown' staan, net als elders op
|
||||
// de pagina. Een half ingevuld adres dat iemand toch kopieert is erger dan een
|
||||
// leeg veld, dus de kopieerknop staat dan uit.
|
||||
var oneLineValue = null;
|
||||
var splitValue = null;
|
||||
|
||||
function drawSetup(domain, port) {
|
||||
oneLineValue = (domain && port) ? domain + ':' + port + ':s' : null;
|
||||
splitValue = domain || null;
|
||||
put('oneline-value', oneLineValue);
|
||||
put('split-value', splitValue);
|
||||
el('split-port').textContent = port ? 'port ' + port : '';
|
||||
el('oneline-copy').disabled = !oneLineValue;
|
||||
el('split-copy').disabled = !splitValue;
|
||||
}
|
||||
|
||||
function fill(containerId, clients, valueFor, extra) {
|
||||
var box = el(containerId);
|
||||
// Eén keer getekend, want deze lijst verandert nooit; hij komt uit
|
||||
// Referenties/Clients.md. De vindplaats staat erbij en dat is bewust: het gaat
|
||||
// erom je eigen wallet te herkennen, en dan is "waar zit die instelling" de
|
||||
// volgende vraag.
|
||||
function walletList(id, clients) {
|
||||
var box = el(id);
|
||||
box.innerHTML = '';
|
||||
for (var i = 0; i < clients.length; i++) {
|
||||
var value = valueFor();
|
||||
var row = document.createElement('div');
|
||||
row.className = 'list-item';
|
||||
|
||||
var left = document.createElement('div');
|
||||
var title = document.createElement('div');
|
||||
title.className = 'list-item-title';
|
||||
title.textContent = clients[i].name;
|
||||
var sub = document.createElement('div');
|
||||
sub.className = 'list-item-sub';
|
||||
sub.textContent = clients[i].where;
|
||||
left.appendChild(title);
|
||||
left.appendChild(sub);
|
||||
|
||||
var right = document.createElement('div');
|
||||
right.style.display = 'flex';
|
||||
right.style.alignItems = 'center';
|
||||
right.style.gap = '0.6rem';
|
||||
|
||||
var val = document.createElement('span');
|
||||
val.className = 'list-item-val mono' + (value ? '' : ' unknown');
|
||||
val.textContent = value ? value : 'unknown';
|
||||
right.appendChild(val);
|
||||
|
||||
if (extra) {
|
||||
var note = document.createElement('span');
|
||||
note.className = 'list-item-meta t-caption';
|
||||
note.textContent = extra;
|
||||
right.appendChild(note);
|
||||
}
|
||||
|
||||
if (value) {
|
||||
right.appendChild(copyButton(value));
|
||||
}
|
||||
|
||||
row.appendChild(left);
|
||||
row.appendChild(right);
|
||||
var name = document.createElement('strong');
|
||||
name.textContent = clients[i].name;
|
||||
row.appendChild(name);
|
||||
row.appendChild(document.createTextNode(' · ' + clients[i].where));
|
||||
box.appendChild(row);
|
||||
}
|
||||
}
|
||||
|
||||
function copyButton(value) {
|
||||
var b = document.createElement('button');
|
||||
b.type = 'button';
|
||||
b.className = 'btn';
|
||||
b.textContent = 'Copy';
|
||||
b.addEventListener('click', function () {
|
||||
copy(value, b);
|
||||
});
|
||||
return b;
|
||||
}
|
||||
el('oneline-copy').addEventListener('click', function () {
|
||||
if (oneLineValue) { copy(oneLineValue, el('oneline-copy')); }
|
||||
});
|
||||
el('split-copy').addEventListener('click', function () {
|
||||
if (splitValue) { copy(splitValue, el('split-copy')); }
|
||||
});
|
||||
|
||||
// ── Grafiekjes ──────────────────────────────────────────────────────────
|
||||
function drawSpark(history) {
|
||||
@@ -1327,7 +1627,10 @@ body {
|
||||
});
|
||||
}
|
||||
|
||||
drawClients(null, null);
|
||||
walletList('oneline-wallets', CLIENTS_ONELINE);
|
||||
walletList('split-wallets', CLIENTS_SPLIT);
|
||||
drawSetup(null, null);
|
||||
drawSelfCheck(null);
|
||||
drawActivity(null);
|
||||
drawCertChoices(null, null, Math.floor(Date.now() / 1000));
|
||||
load();
|
||||
|
||||
@@ -9,7 +9,7 @@ manifestVersion: 1
|
||||
id: whatsnext-electrum-gate
|
||||
category: bitcoin
|
||||
name: Electrum Gate
|
||||
version: "0.0.16"
|
||||
version: "0.0.17"
|
||||
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
|
||||
@@ -56,28 +56,31 @@ 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 app now checks its own front door. Until this release it watched whether your Electrum server was
|
||||
answering, but never whether the gateway itself was, which is the one thing it exists to do.
|
||||
The dashboard has been rebuilt around five small tiles: your Electrum server, block height, response
|
||||
time, your certificate, and whether the gateway itself is answering. That last one is the check added
|
||||
in the previous release, which until now had nowhere to show.
|
||||
|
||||
|
||||
Every few minutes it opens a connection to its own TLS port, completes the handshake, and compares the
|
||||
certificate it gets back with the one you picked. That last part catches something nothing else did: a
|
||||
certificate change that nginx never actually applied, which looks fine from the outside and fails at
|
||||
your wallet.
|
||||
Choosing and uploading certificates moved into a dialog behind the menu at the top right, together with
|
||||
the light and dark setting. Nothing is harder to find: when no certificate is in use, the message at the
|
||||
top of the page still takes you straight there, and that message is what a fresh install shows.
|
||||
|
||||
|
||||
For now the result appears as a line in the activity log when it changes. A tile on the dashboard
|
||||
follows in a later release. The check runs every few minutes rather than every minute, and its own
|
||||
connections are kept out of the activity log, so the log stays about your wallets.
|
||||
|
||||
|
||||
What it does not tell you: whether your gateway can be reached from outside. This check runs inside the
|
||||
app, so a router that stopped forwarding the port still reads as fine here.
|
||||
The activity log now runs the full width of the page. "Setting up your wallet" starts collapsed and is
|
||||
much shorter. There are only two forms of the same address, so there are two copy buttons instead of one
|
||||
per wallet, with the wallets listed under the form each of them asks for.
|
||||
|
||||
|
||||
Earlier releases:
|
||||
|
||||
|
||||
0.0.16 taught the app to check its own front door: it connects to its own TLS port, completes the
|
||||
handshake, and compares the certificate it gets back with the one you picked. That catches a
|
||||
certificate change that never actually took effect, which looks fine from the outside and fails at your
|
||||
wallet. It does not tell you whether your gateway can be reached from outside; the check runs inside the
|
||||
app.
|
||||
|
||||
|
||||
0.0.15 moved the app store this app comes from to a new address, and pointed every link in this listing
|
||||
there. If you added the store at its old address, remove it in umbrelOS and add the new one.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user