Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6662adf0b8 | |||
| b18d16add1 |
@@ -303,6 +303,9 @@ Settings → Pair iOS app: scan the QR code, or tap "Copy pairing code" and past
|
||||
it into the app's "Enter manually". Self-signed certificates are pinned during
|
||||
pairing.
|
||||
|
||||
The iOS app is currently in beta testing. For an invite, email
|
||||
[engineroom@redetzke.aero](mailto:engineroom@redetzke.aero).
|
||||
|
||||
## Development
|
||||
|
||||
On macOS (or any non-Linux system), `make dev` starts the app on
|
||||
|
||||
@@ -173,28 +173,32 @@ fieldset { border: 0; margin: 0; padding: 0; min-width: 0; display: flex; flex-d
|
||||
.kv dt { color: var(--ink-2); }
|
||||
.kv dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
|
||||
|
||||
/* health: public addresses, then one tile per check */
|
||||
/* health: public addresses on the left, one row per check on the right */
|
||||
.hcbody { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 12px; margin-top: 16px; }
|
||||
.hchead { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
|
||||
.hchead > span { font-size: 13px; color: var(--ink-2); }
|
||||
.hchead > span.bad { color: var(--bad-ink); font-weight: 500; }
|
||||
.hcaddrs { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 12px; margin-top: 16px; }
|
||||
.hcaddr { background: var(--ground); border-radius: 10px; padding: 14px 16px; min-width: 0; }
|
||||
.hcaddrs { display: flex; flex-direction: column; gap: 12px; }
|
||||
.hcaddr { flex: 1; display: flex; flex-direction: column; justify-content: center; background: var(--ground); border-radius: 10px; padding: 14px 18px; min-width: 0; }
|
||||
.hcaddr .l { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--ink-2); }
|
||||
.hcaddr .v { margin-top: 4px; font-size: 15px; font-weight: 500; overflow-wrap: anywhere; }
|
||||
.hcaddr .v.mono { font-size: 20px; }
|
||||
.hcaddr .v.mono { font-size: 22px; }
|
||||
.hcaddr .n { font-family: var(--sans); font-size: 12px; font-weight: 400; color: var(--ink-2); }
|
||||
.hcaddr.bad { background: #fdf6f5; box-shadow: inset 0 0 0 1px #e6b3b0; }
|
||||
.hcaddr.bad .v { color: var(--bad-ink); }
|
||||
.hctiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 12px; margin-top: 12px; }
|
||||
.hctile { border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
|
||||
.hctile .l { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--ink-2); }
|
||||
.hctile .l > span:first-child { flex: 1; min-width: 0; }
|
||||
.hctile .s { font-size: 15px; font-weight: 500; }
|
||||
.hctile .r { font-size: 11.5px; color: var(--ink-3); overflow-wrap: anywhere; }
|
||||
.hctile .p { font-size: 12.5px; color: var(--bad-ink); overflow-wrap: anywhere; }
|
||||
.hctile.bad { border-color: #e6b3b0; background: #fdf6f5; }
|
||||
.hctile.bad .s { color: var(--bad-ink); }
|
||||
@media (max-width: 640px) { .hctiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
|
||||
.hclist { border: 1px solid var(--line); border-radius: 10px; min-width: 0; }
|
||||
.hcrow { display: grid; grid-template-columns: 8px minmax(0, 190px) minmax(0, 1fr); gap: 2px 14px; align-items: baseline; padding: 11px 16px; border-top: 1px solid var(--line-2); }
|
||||
.hcrow:first-child { border-top: 0; }
|
||||
.hcrow > .dot { align-self: center; }
|
||||
.hcrow .l { font-size: 13px; color: var(--ink-2); }
|
||||
.hcrow .v { display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; min-width: 0; }
|
||||
.hcrow .s { font-weight: 500; }
|
||||
.hcrow .r { font-size: 12px; color: var(--ink-3); overflow-wrap: anywhere; }
|
||||
.hcrow .p { grid-column: 2 / -1; font-size: 12.5px; color: var(--bad-ink); overflow-wrap: anywhere; }
|
||||
.hcrow.bad { background: #fdf6f5; }
|
||||
.hcrow.bad .s { color: var(--bad-ink); }
|
||||
@media (max-width: 1000px) { .hcbody { grid-template-columns: minmax(0, 1fr); } }
|
||||
@media (max-width: 640px) { .hcrow { grid-template-columns: 8px minmax(0, 1fr); } .hcrow .v { grid-column: 2; } }
|
||||
|
||||
/* activity */
|
||||
.ev { display: flex; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--line-2); font-size: 13px; }
|
||||
|
||||
@@ -1511,9 +1511,9 @@
|
||||
const DNS_PRESETS = [['Quad9', '9.9.9.9, 149.112.112.112']];
|
||||
|
||||
// healthParts turns the server's checks into the Health card: the public
|
||||
// address per IP family (from its uplink and public address checks), then
|
||||
// one tile per other check with a plain-word status, the raw setting and,
|
||||
// when it fails, what is wrong.
|
||||
// address per IP family (from its uplink and public address checks) and,
|
||||
// beside them, one row per other check with a plain-word status, the raw
|
||||
// setting and, when it fails, what is wrong.
|
||||
function healthParts(checks) {
|
||||
const by = Object.fromEntries(checks.map((c) => [c.name, c]));
|
||||
const addrs = [];
|
||||
@@ -1563,14 +1563,14 @@
|
||||
return h('section', { class: 'card', 'aria-labelledby': 'hc' },
|
||||
h('div', { class: 'hchead' }, h('h2', { id: 'hc' }, 'Health'),
|
||||
h('span', { class: hp.failing ? 'bad' : null }, hp.failing ? hp.failing + ' of ' + hp.total + ' checks failing' : 'All ' + hp.total + ' checks pass')),
|
||||
h('div', { class: 'hcbody' },
|
||||
hp.addrs.length ? h('div', { class: 'hcaddrs' }, hp.addrs.map((a) => h('div', { class: a.ok ? 'hcaddr' : 'hcaddr bad' },
|
||||
h('div', { class: 'l' }, dot(a.ok), a.label),
|
||||
h('div', { class: a.mono ? 'v mono' : 'v' }, a.value, a.note ? h('span', { class: 'n' }, ' ' + a.note) : null)))) : null,
|
||||
h('div', { class: 'hctiles' }, hp.tiles.map((t) => h('div', { class: t.ok ? 'hctile' : 'hctile bad', title: t.title || null },
|
||||
h('div', { class: 'l' }, h('span', null, t.label), dot(t.ok)),
|
||||
h('div', { class: 's' }, t.status),
|
||||
t.raw ? h('div', { class: 'r mono' }, t.raw) : null,
|
||||
t.problem ? h('div', { class: 'p' }, t.problem) : null))));
|
||||
h('div', { class: 'hclist' }, hp.tiles.map((t) => h('div', { class: t.ok ? 'hcrow' : 'hcrow bad', title: t.title || null },
|
||||
dot(t.ok), h('span', { class: 'l' }, t.label),
|
||||
h('span', { class: 'v' }, h('span', { class: 's' }, t.status), t.raw ? h('span', { class: 'r mono' }, t.raw) : null),
|
||||
t.problem ? h('div', { class: 'p' }, t.problem) : null)))));
|
||||
}
|
||||
|
||||
async function viewServer(wrap) {
|
||||
|
||||
Reference in New Issue
Block a user