signalk-underkeel 0.6.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/package.json +1 -1
- package/public/panel.js +34 -7
- package/public/runtime.js +54 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to signalk-underkeel are documented here.
|
|
4
4
|
|
|
5
|
+
## [0.6.2] - 2026-11-13
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Closing the details panel no longer logs an error in the Signal K server log. The panel
|
|
10
|
+
subscribed to `notifications.navigation.underKeel` itself, and on close Freeboard sent
|
|
11
|
+
Signal K an unsubscribe for that one path, which Signal K refuses (it takes only an
|
|
12
|
+
unsubscribe of everything). The background page, which never closes, now holds that
|
|
13
|
+
subscription and passes the message to the panel.
|
|
14
|
+
|
|
5
15
|
## [0.6.1] - 2026-11-13
|
|
6
16
|
|
|
7
17
|
### Fixed
|
package/package.json
CHANGED
package/public/panel.js
CHANGED
|
@@ -145,19 +145,45 @@ async function refreshRoutes() {
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
/** Reads overlap as the status ones do: only the latest may update the message. */
|
|
149
|
+
let noticeRequest = 0;
|
|
150
|
+
|
|
151
|
+
/** The notification's message, which the background page keeps in the extension state. */
|
|
152
|
+
async function refreshNotice() {
|
|
153
|
+
const id = ++noticeRequest;
|
|
154
|
+
try {
|
|
155
|
+
const { ukcNotice } = await client.state.get(["ukcNotice"], "extension");
|
|
156
|
+
if (id !== noticeRequest) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
text("message", ukcNotice && typeof ukcNotice.message === "string" ? ukcNotice.message : "");
|
|
160
|
+
} catch (err) {
|
|
161
|
+
if (id !== noticeRequest) {
|
|
162
|
+
return;
|
|
153
163
|
}
|
|
154
|
-
|
|
164
|
+
// An old message left on screen could say normal over a warning; the poll reads it again.
|
|
165
|
+
text("message", "Under-keel message unavailable: the chart host did not answer.");
|
|
166
|
+
console.warn("under-keel notice", err);
|
|
167
|
+
}
|
|
155
168
|
}
|
|
169
|
+
|
|
170
|
+
// No Signal K subscription of its own: the host would unsubscribe it path by path when the
|
|
171
|
+
// panel closes, which Signal K refuses and logs as an error. The background page relays it.
|
|
156
172
|
await client.subscribe(["state.changed"], (_name, params) => {
|
|
157
|
-
if (params
|
|
173
|
+
if (!params || params.scope !== "extension") {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (params.keys.includes("routeCheck")) {
|
|
158
177
|
void refreshRoutes();
|
|
159
178
|
}
|
|
179
|
+
if (params.keys.includes("ukcNotice")) {
|
|
180
|
+
void refreshNotice();
|
|
181
|
+
if (!document.hidden) {
|
|
182
|
+
void refreshStatus();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
160
185
|
});
|
|
186
|
+
void refreshNotice();
|
|
161
187
|
// The background runtime answers the button, over an event the host must carry.
|
|
162
188
|
const recheck = document.getElementById("recheck");
|
|
163
189
|
recheck.hidden = !["events.publish", "routes", "background.iframe"].every((c) => client.hasCapability(c));
|
|
@@ -176,6 +202,7 @@ function checkStatusAge() {
|
|
|
176
202
|
function poll() {
|
|
177
203
|
void refreshStatus();
|
|
178
204
|
void refreshRoutes();
|
|
205
|
+
void refreshNotice();
|
|
179
206
|
}
|
|
180
207
|
|
|
181
208
|
// A hidden page polls nothing; back on screen an old status reads unknown until the poll answers.
|
package/public/runtime.js
CHANGED
|
@@ -427,11 +427,64 @@ if (has("routes")) {
|
|
|
427
427
|
}, RECHECK_MS);
|
|
428
428
|
}
|
|
429
429
|
|
|
430
|
+
// ---- the notification, relayed to the details panel ----
|
|
431
|
+
/**
|
|
432
|
+
* The panel opens and closes, and the chart host unsubscribes a closed page's Signal K paths
|
|
433
|
+
* one by one, which Signal K refuses: it only takes an unsubscribe of everything, and logs the
|
|
434
|
+
* rest as errors. So this page, which never closes, holds the notification's subscription and
|
|
435
|
+
* keeps its message in the extension state, where the panel reads it.
|
|
436
|
+
*/
|
|
437
|
+
const NOTICE = "notifications.navigation.underKeel";
|
|
438
|
+
/** A write that fails is tried again this many times, each wait longer by this much. */
|
|
439
|
+
const NOTICE_RETRIES = 5;
|
|
440
|
+
const NOTICE_RETRY_MS = 2000;
|
|
441
|
+
/** The last notice received and not given up on, as JSON; a newer one replaces a retry of an older one. */
|
|
442
|
+
let latestNotice;
|
|
443
|
+
let noticeRetry;
|
|
444
|
+
|
|
445
|
+
function relayNotice(value) {
|
|
446
|
+
const n = value && typeof value === "object" ? value : {};
|
|
447
|
+
const notice = { message: typeof n.message === "string" ? n.message : "", state: n.state };
|
|
448
|
+
const key = JSON.stringify(notice);
|
|
449
|
+
if (key === latestNotice) {
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
latestNotice = key;
|
|
453
|
+
clearTimeout(noticeRetry);
|
|
454
|
+
void writeNotice(notice, key, 0);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Writes the notice to the extension state. A notification is sent only when it changes, so
|
|
459
|
+
* a write that fails is tried again rather than left until the next one.
|
|
460
|
+
*/
|
|
461
|
+
async function writeNotice(notice, key, tries) {
|
|
462
|
+
try {
|
|
463
|
+
await client.state.set({ ukcNotice: notice }, "extension");
|
|
464
|
+
} catch (err) {
|
|
465
|
+
if (key !== latestNotice) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (tries < NOTICE_RETRIES) {
|
|
469
|
+
noticeRetry = setTimeout(() => void writeNotice(notice, key, tries + 1), NOTICE_RETRY_MS * (tries + 1));
|
|
470
|
+
} else {
|
|
471
|
+
// Given up: the same notice, sent again on a reconnect, is written rather than dropped.
|
|
472
|
+
latestNotice = undefined;
|
|
473
|
+
console.warn("under-keel notice", err);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
430
478
|
/** Without the Signal K stream, or when subscribing to it fails, the envelope is polled. */
|
|
431
479
|
let streaming = false;
|
|
432
480
|
if (has("signalk.stream")) {
|
|
433
481
|
try {
|
|
434
|
-
await client.signalk.subscribe(Object.keys(onPath), (ev) => {
|
|
482
|
+
await client.signalk.subscribe([...Object.keys(onPath), NOTICE], (ev) => {
|
|
483
|
+
// A notification is sent only when it changes, so its age says nothing about the plugin.
|
|
484
|
+
if (ev.path === NOTICE) {
|
|
485
|
+
relayNotice(ev.value);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
435
488
|
const left = fresh(ev.path, ev.timestamp, Date.now());
|
|
436
489
|
if (left > 0) {
|
|
437
490
|
onPath[ev.path](ev.value, left);
|