@crvouga/mockingbird-service-caretalk 1.6.0 → 1.6.1
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 +9 -1
- package/dist/{chunk-VBOYORPS.js → chunk-3SMS2XHQ.js} +89 -10
- package/dist/chunk-3SMS2XHQ.js.map +7 -0
- package/dist/{chunk-5H2PMMOJ.js → chunk-Q4NZIWTX.js} +2 -2
- package/dist/cli.js +2 -2
- package/dist/index.js +1 -1
- package/dist/server.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-VBOYORPS.js.map +0 -7
- /package/dist/{chunk-5H2PMMOJ.js.map → chunk-Q4NZIWTX.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-caretalk
|
|
2
2
|
|
|
3
|
-
## 1.6.
|
|
3
|
+
## 1.6.1 (2026-09-30)
|
|
4
|
+
|
|
5
|
+
### Fixes and improvements
|
|
6
|
+
|
|
7
|
+
- keep admin buttons pressed until the action finishes ([0aabfcb](https://github.com/crvouga/mockingbird/commit/0aabfcb5f392aa51e193f9c3f817d5877d92bc6a))
|
|
8
|
+
- size admin select fields like the text inputs beside them ([0fb3ef2](https://github.com/crvouga/mockingbird/commit/0fb3ef2ddbf43376c93a2ae6d87c6c9bf890dafc))
|
|
9
|
+
- keep admin section tabs wired when boot is renamed ([4eda25e](https://github.com/crvouga/mockingbird/commit/4eda25eacd59da048d196f7cc8369d7a02b47bfc))
|
|
10
|
+
|
|
11
|
+
## 1.6.0 (2026-09-29)
|
|
4
12
|
|
|
5
13
|
### Features
|
|
6
14
|
|
|
@@ -2286,6 +2286,50 @@ function bootAdmin(config) {
|
|
|
2286
2286
|
if (render)
|
|
2287
2287
|
await render();
|
|
2288
2288
|
}
|
|
2289
|
+
const delay = (ms) => new Promise((resolve) => {
|
|
2290
|
+
window.setTimeout(resolve, ms);
|
|
2291
|
+
});
|
|
2292
|
+
const confirmAction = async (button, pending, done, work) => {
|
|
2293
|
+
if (button.dataset.pending === "1")
|
|
2294
|
+
return;
|
|
2295
|
+
const label = button.textContent ?? "";
|
|
2296
|
+
const width = button.offsetWidth;
|
|
2297
|
+
button.dataset.pending = "1";
|
|
2298
|
+
button.classList.add("pressed");
|
|
2299
|
+
button.setAttribute("aria-busy", "true");
|
|
2300
|
+
button.style.minWidth = `${width}px`;
|
|
2301
|
+
button.textContent = pending;
|
|
2302
|
+
try {
|
|
2303
|
+
await work();
|
|
2304
|
+
button.textContent = done;
|
|
2305
|
+
await delay(1e3);
|
|
2306
|
+
} catch (error) {
|
|
2307
|
+
showError(error);
|
|
2308
|
+
} finally {
|
|
2309
|
+
button.textContent = label;
|
|
2310
|
+
button.style.minWidth = "";
|
|
2311
|
+
button.classList.remove("pressed");
|
|
2312
|
+
button.removeAttribute("aria-busy");
|
|
2313
|
+
delete button.dataset.pending;
|
|
2314
|
+
}
|
|
2315
|
+
};
|
|
2316
|
+
document.addEventListener("click", (event) => {
|
|
2317
|
+
const target = event.target;
|
|
2318
|
+
if (!(target instanceof Element))
|
|
2319
|
+
return;
|
|
2320
|
+
const button = target.closest("button");
|
|
2321
|
+
if (!(button instanceof HTMLButtonElement) || button.dataset.pending === "1")
|
|
2322
|
+
return;
|
|
2323
|
+
button.classList.add("pressed");
|
|
2324
|
+
const token = String(Date.now());
|
|
2325
|
+
button.dataset.press = token;
|
|
2326
|
+
window.setTimeout(() => {
|
|
2327
|
+
if (button.dataset.press !== token || button.dataset.pending === "1")
|
|
2328
|
+
return;
|
|
2329
|
+
button.classList.remove("pressed");
|
|
2330
|
+
delete button.dataset.press;
|
|
2331
|
+
}, 450);
|
|
2332
|
+
});
|
|
2289
2333
|
el("namespace", HTMLSelectElement).addEventListener("change", () => {
|
|
2290
2334
|
state.namespace = el("namespace", HTMLSelectElement).value;
|
|
2291
2335
|
refresh().catch(showError);
|
|
@@ -2296,7 +2340,7 @@ function bootAdmin(config) {
|
|
|
2296
2340
|
refresh().catch(showError);
|
|
2297
2341
|
});
|
|
2298
2342
|
el("refresh", HTMLButtonElement).addEventListener("click", () => {
|
|
2299
|
-
refresh().catch(showError);
|
|
2343
|
+
confirmAction(el("refresh", HTMLButtonElement), "Refreshing...", "Updated", () => refresh()).catch(showError);
|
|
2300
2344
|
});
|
|
2301
2345
|
el("collections", HTMLElement).addEventListener("click", (event) => {
|
|
2302
2346
|
const target = event.target;
|
|
@@ -2419,10 +2463,10 @@ function bootAdmin(config) {
|
|
|
2419
2463
|
}).then(() => renderFaults()).catch(showError);
|
|
2420
2464
|
});
|
|
2421
2465
|
el("fault-clear", HTMLButtonElement).addEventListener("click", () => {
|
|
2422
|
-
api("DELETE", "/faults").then(() => renderFaults()).catch(showError);
|
|
2466
|
+
confirmAction(el("fault-clear", HTMLButtonElement), "Clearing...", "Cleared", () => api("DELETE", "/faults").then(() => renderFaults())).catch(showError);
|
|
2423
2467
|
});
|
|
2424
2468
|
el("journal-clear", HTMLButtonElement).addEventListener("click", () => {
|
|
2425
|
-
api("DELETE", "/requests").then(() => renderJournal()).catch(showError);
|
|
2469
|
+
confirmAction(el("journal-clear", HTMLButtonElement), "Clearing...", "Cleared", () => api("DELETE", "/requests").then(() => renderJournal())).catch(showError);
|
|
2426
2470
|
});
|
|
2427
2471
|
el("route-list", HTMLElement).addEventListener("click", (event) => {
|
|
2428
2472
|
const target = event.target;
|
|
@@ -2537,9 +2581,13 @@ function bootAdmin(config) {
|
|
|
2537
2581
|
var clientPrelude = [isRecord2, mountAdminBrand, startAdminBrand, faultPresetList, bootAdmin].map((fn) => fn.toString()).join("\n");
|
|
2538
2582
|
var adminClientSource = (config) => {
|
|
2539
2583
|
const payload = JSON.stringify(config).replace(/</g, "\\u003c");
|
|
2584
|
+
const entry = bootAdmin.name;
|
|
2585
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(entry)) {
|
|
2586
|
+
throw new Error("admin client cannot call its boot function");
|
|
2587
|
+
}
|
|
2540
2588
|
return `<script>
|
|
2541
2589
|
${clientPrelude}
|
|
2542
|
-
|
|
2590
|
+
${entry}(${payload});
|
|
2543
2591
|
</script>`;
|
|
2544
2592
|
};
|
|
2545
2593
|
|
|
@@ -2753,9 +2801,24 @@ var renderAdminDocument = (service) => {
|
|
|
2753
2801
|
.controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
|
2754
2802
|
label.field { display: flex; flex-direction: column; gap: 2px; font-size: 11px; color: var(--faint); }
|
|
2755
2803
|
label.field input, label.field select, .controls input[type="password"] {
|
|
2756
|
-
background: var(--bg-inset); border: 1px solid var(--line); border-radius: 8px;
|
|
2757
|
-
padding: 7px 8px; min-height: 36px;
|
|
2758
|
-
}
|
|
2804
|
+
background-color: var(--bg-inset); border: 1px solid var(--line); border-radius: 8px;
|
|
2805
|
+
padding: 7px 8px; min-height: 36px; line-height: 1.2;
|
|
2806
|
+
}
|
|
2807
|
+
/* A native menu ignores min-height, so Preset rendered about half as tall as
|
|
2808
|
+
the text fields in the same form. Paint it like those fields. */
|
|
2809
|
+
label.field select {
|
|
2810
|
+
-webkit-appearance: none; appearance: none;
|
|
2811
|
+
padding-right: 28px;
|
|
2812
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='none' stroke='%2371717a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M2.5 4.5 6 8l3.5-3.5'/%3E%3C/svg%3E");
|
|
2813
|
+
background-repeat: no-repeat; background-position: right 10px center; background-size: 12px 12px;
|
|
2814
|
+
}
|
|
2815
|
+
.stack > .field > input,
|
|
2816
|
+
.stack > .field > select,
|
|
2817
|
+
.stack > .field > textarea,
|
|
2818
|
+
dialog .field > input,
|
|
2819
|
+
dialog .field > select,
|
|
2820
|
+
dialog .field > textarea { width: 100%; }
|
|
2821
|
+
.icon-btn, .btn, .btn-primary, .btn-quiet, .btn-danger, nav.side button { cursor: pointer; }
|
|
2759
2822
|
.icon-btn, .btn, .btn-primary, .btn-quiet, .btn-danger {
|
|
2760
2823
|
border-radius: 9px; min-height: 36px; padding: 0 12px; border: 1px solid var(--line);
|
|
2761
2824
|
background: var(--bg-elev);
|
|
@@ -2763,6 +2826,14 @@ var renderAdminDocument = (service) => {
|
|
|
2763
2826
|
.btn-primary { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
|
|
2764
2827
|
.btn-quiet { background: transparent; }
|
|
2765
2828
|
.btn-danger { color: var(--err); }
|
|
2829
|
+
/* Held after mouseup. Clearing an empty journal changes nothing on screen,
|
|
2830
|
+
so the press itself has to stay visible. */
|
|
2831
|
+
.icon-btn:active, .btn:active, .btn-quiet:active, .btn-danger:active, nav.side button:active,
|
|
2832
|
+
.icon-btn.pressed, .btn.pressed, .btn-quiet.pressed, .btn-danger.pressed, nav.side button.pressed {
|
|
2833
|
+
background: var(--bg-inset); border-color: var(--line-strong); color: var(--ink);
|
|
2834
|
+
}
|
|
2835
|
+
.btn-danger:active, .btn-danger.pressed { background: var(--err-soft); color: var(--err); }
|
|
2836
|
+
.btn-primary:active, .btn-primary.pressed { filter: brightness(0.88); color: var(--accent-ink); }
|
|
2766
2837
|
/* minmax(0, 1fr): a 1fr column will not shrink below its content, so a long
|
|
2767
2838
|
record or the full nav row would widen the page past the viewport. */
|
|
2768
2839
|
.layout {
|
|
@@ -2851,8 +2922,16 @@ var renderAdminDocument = (service) => {
|
|
|
2851
2922
|
input, select, textarea { font-size: 16px; }
|
|
2852
2923
|
.brand, .vendor, .controls { width: 100%; }
|
|
2853
2924
|
label.field, label.field select, label.field input { flex: 1; min-width: 0; }
|
|
2854
|
-
|
|
2925
|
+
/* The layout fills the screen. A single-column grid stretches every auto
|
|
2926
|
+
row, so the tab bar grew with the leftover height and the buttons floated
|
|
2927
|
+
in the middle of it. The bar stays one row; the page below takes the rest. */
|
|
2928
|
+
.layout {
|
|
2929
|
+
grid-template-columns: minmax(0, 1fr);
|
|
2930
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
2931
|
+
align-content: start;
|
|
2932
|
+
}
|
|
2855
2933
|
nav.side {
|
|
2934
|
+
align-self: start; height: auto;
|
|
2856
2935
|
flex-direction: row; align-items: center; overflow-x: auto; min-width: 0;
|
|
2857
2936
|
border-right: 0; border-bottom: 1px solid var(--line);
|
|
2858
2937
|
padding: 8px;
|
|
@@ -3730,7 +3809,7 @@ var stateAdminRoutes = (routes) => {
|
|
|
3730
3809
|
};
|
|
3731
3810
|
|
|
3732
3811
|
// ../core/dist/version.js
|
|
3733
|
-
var PACKAGE_VERSION = true ? "1.6.
|
|
3812
|
+
var PACKAGE_VERSION = true ? "1.6.1" : UNRELEASED_VERSION;
|
|
3734
3813
|
|
|
3735
3814
|
// ../core/dist/signing.js
|
|
3736
3815
|
var encoder = new TextEncoder();
|
|
@@ -5306,4 +5385,4 @@ export {
|
|
|
5306
5385
|
normalizeDate,
|
|
5307
5386
|
CareTalkAPI
|
|
5308
5387
|
};
|
|
5309
|
-
//# sourceMappingURL=chunk-
|
|
5388
|
+
//# sourceMappingURL=chunk-3SMS2XHQ.js.map
|