@crvouga/mockingbird-service-paddle 0.3.0 → 0.3.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-YFGZYQKB.js → chunk-KVA6Z6FB.js} +2 -2
- package/dist/{chunk-2LDOLWZ5.js → chunk-LW2XNBX2.js} +89 -10
- package/dist/chunk-LW2XNBX2.js.map +7 -0
- 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-2LDOLWZ5.js.map +0 -7
- /package/dist/{chunk-YFGZYQKB.js.map → chunk-KVA6Z6FB.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# Changelog — @crvouga/mockingbird-service-paddle
|
|
2
2
|
|
|
3
|
-
## 0.3.
|
|
3
|
+
## 0.3.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
|
+
## 0.3.0 (2026-09-29)
|
|
4
12
|
|
|
5
13
|
### Features
|
|
6
14
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createRuntime
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LW2XNBX2.js";
|
|
4
4
|
|
|
5
5
|
// ../../adapters/node/dist/cli.js
|
|
6
6
|
import { readFile } from "node:fs/promises";
|
|
@@ -370,4 +370,4 @@ export {
|
|
|
370
370
|
createServer2 as createServer,
|
|
371
371
|
serveTarget
|
|
372
372
|
};
|
|
373
|
-
//# sourceMappingURL=chunk-
|
|
373
|
+
//# sourceMappingURL=chunk-KVA6Z6FB.js.map
|
|
@@ -2283,6 +2283,50 @@ function bootAdmin(config) {
|
|
|
2283
2283
|
if (render)
|
|
2284
2284
|
await render();
|
|
2285
2285
|
}
|
|
2286
|
+
const delay = (ms) => new Promise((resolve) => {
|
|
2287
|
+
window.setTimeout(resolve, ms);
|
|
2288
|
+
});
|
|
2289
|
+
const confirmAction = async (button, pending, done, work) => {
|
|
2290
|
+
if (button.dataset.pending === "1")
|
|
2291
|
+
return;
|
|
2292
|
+
const label = button.textContent ?? "";
|
|
2293
|
+
const width = button.offsetWidth;
|
|
2294
|
+
button.dataset.pending = "1";
|
|
2295
|
+
button.classList.add("pressed");
|
|
2296
|
+
button.setAttribute("aria-busy", "true");
|
|
2297
|
+
button.style.minWidth = `${width}px`;
|
|
2298
|
+
button.textContent = pending;
|
|
2299
|
+
try {
|
|
2300
|
+
await work();
|
|
2301
|
+
button.textContent = done;
|
|
2302
|
+
await delay(1e3);
|
|
2303
|
+
} catch (error) {
|
|
2304
|
+
showError(error);
|
|
2305
|
+
} finally {
|
|
2306
|
+
button.textContent = label;
|
|
2307
|
+
button.style.minWidth = "";
|
|
2308
|
+
button.classList.remove("pressed");
|
|
2309
|
+
button.removeAttribute("aria-busy");
|
|
2310
|
+
delete button.dataset.pending;
|
|
2311
|
+
}
|
|
2312
|
+
};
|
|
2313
|
+
document.addEventListener("click", (event) => {
|
|
2314
|
+
const target = event.target;
|
|
2315
|
+
if (!(target instanceof Element))
|
|
2316
|
+
return;
|
|
2317
|
+
const button = target.closest("button");
|
|
2318
|
+
if (!(button instanceof HTMLButtonElement) || button.dataset.pending === "1")
|
|
2319
|
+
return;
|
|
2320
|
+
button.classList.add("pressed");
|
|
2321
|
+
const token = String(Date.now());
|
|
2322
|
+
button.dataset.press = token;
|
|
2323
|
+
window.setTimeout(() => {
|
|
2324
|
+
if (button.dataset.press !== token || button.dataset.pending === "1")
|
|
2325
|
+
return;
|
|
2326
|
+
button.classList.remove("pressed");
|
|
2327
|
+
delete button.dataset.press;
|
|
2328
|
+
}, 450);
|
|
2329
|
+
});
|
|
2286
2330
|
el("namespace", HTMLSelectElement).addEventListener("change", () => {
|
|
2287
2331
|
state.namespace = el("namespace", HTMLSelectElement).value;
|
|
2288
2332
|
refresh().catch(showError);
|
|
@@ -2293,7 +2337,7 @@ function bootAdmin(config) {
|
|
|
2293
2337
|
refresh().catch(showError);
|
|
2294
2338
|
});
|
|
2295
2339
|
el("refresh", HTMLButtonElement).addEventListener("click", () => {
|
|
2296
|
-
refresh().catch(showError);
|
|
2340
|
+
confirmAction(el("refresh", HTMLButtonElement), "Refreshing...", "Updated", () => refresh()).catch(showError);
|
|
2297
2341
|
});
|
|
2298
2342
|
el("collections", HTMLElement).addEventListener("click", (event) => {
|
|
2299
2343
|
const target = event.target;
|
|
@@ -2416,10 +2460,10 @@ function bootAdmin(config) {
|
|
|
2416
2460
|
}).then(() => renderFaults()).catch(showError);
|
|
2417
2461
|
});
|
|
2418
2462
|
el("fault-clear", HTMLButtonElement).addEventListener("click", () => {
|
|
2419
|
-
api("DELETE", "/faults").then(() => renderFaults()).catch(showError);
|
|
2463
|
+
confirmAction(el("fault-clear", HTMLButtonElement), "Clearing...", "Cleared", () => api("DELETE", "/faults").then(() => renderFaults())).catch(showError);
|
|
2420
2464
|
});
|
|
2421
2465
|
el("journal-clear", HTMLButtonElement).addEventListener("click", () => {
|
|
2422
|
-
api("DELETE", "/requests").then(() => renderJournal()).catch(showError);
|
|
2466
|
+
confirmAction(el("journal-clear", HTMLButtonElement), "Clearing...", "Cleared", () => api("DELETE", "/requests").then(() => renderJournal())).catch(showError);
|
|
2423
2467
|
});
|
|
2424
2468
|
el("route-list", HTMLElement).addEventListener("click", (event) => {
|
|
2425
2469
|
const target = event.target;
|
|
@@ -2534,9 +2578,13 @@ function bootAdmin(config) {
|
|
|
2534
2578
|
var clientPrelude = [isRecord2, mountAdminBrand, startAdminBrand, faultPresetList, bootAdmin].map((fn) => fn.toString()).join("\n");
|
|
2535
2579
|
var adminClientSource = (config) => {
|
|
2536
2580
|
const payload = JSON.stringify(config).replace(/</g, "\\u003c");
|
|
2581
|
+
const entry = bootAdmin.name;
|
|
2582
|
+
if (!/^[A-Za-z_$][\w$]*$/.test(entry)) {
|
|
2583
|
+
throw new Error("admin client cannot call its boot function");
|
|
2584
|
+
}
|
|
2537
2585
|
return `<script>
|
|
2538
2586
|
${clientPrelude}
|
|
2539
|
-
|
|
2587
|
+
${entry}(${payload});
|
|
2540
2588
|
</script>`;
|
|
2541
2589
|
};
|
|
2542
2590
|
|
|
@@ -2750,9 +2798,24 @@ var renderAdminDocument = (service) => {
|
|
|
2750
2798
|
.controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
|
|
2751
2799
|
label.field { display: flex; flex-direction: column; gap: 2px; font-size: 11px; color: var(--faint); }
|
|
2752
2800
|
label.field input, label.field select, .controls input[type="password"] {
|
|
2753
|
-
background: var(--bg-inset); border: 1px solid var(--line); border-radius: 8px;
|
|
2754
|
-
padding: 7px 8px; min-height: 36px;
|
|
2755
|
-
}
|
|
2801
|
+
background-color: var(--bg-inset); border: 1px solid var(--line); border-radius: 8px;
|
|
2802
|
+
padding: 7px 8px; min-height: 36px; line-height: 1.2;
|
|
2803
|
+
}
|
|
2804
|
+
/* A native menu ignores min-height, so Preset rendered about half as tall as
|
|
2805
|
+
the text fields in the same form. Paint it like those fields. */
|
|
2806
|
+
label.field select {
|
|
2807
|
+
-webkit-appearance: none; appearance: none;
|
|
2808
|
+
padding-right: 28px;
|
|
2809
|
+
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");
|
|
2810
|
+
background-repeat: no-repeat; background-position: right 10px center; background-size: 12px 12px;
|
|
2811
|
+
}
|
|
2812
|
+
.stack > .field > input,
|
|
2813
|
+
.stack > .field > select,
|
|
2814
|
+
.stack > .field > textarea,
|
|
2815
|
+
dialog .field > input,
|
|
2816
|
+
dialog .field > select,
|
|
2817
|
+
dialog .field > textarea { width: 100%; }
|
|
2818
|
+
.icon-btn, .btn, .btn-primary, .btn-quiet, .btn-danger, nav.side button { cursor: pointer; }
|
|
2756
2819
|
.icon-btn, .btn, .btn-primary, .btn-quiet, .btn-danger {
|
|
2757
2820
|
border-radius: 9px; min-height: 36px; padding: 0 12px; border: 1px solid var(--line);
|
|
2758
2821
|
background: var(--bg-elev);
|
|
@@ -2760,6 +2823,14 @@ var renderAdminDocument = (service) => {
|
|
|
2760
2823
|
.btn-primary { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
|
|
2761
2824
|
.btn-quiet { background: transparent; }
|
|
2762
2825
|
.btn-danger { color: var(--err); }
|
|
2826
|
+
/* Held after mouseup. Clearing an empty journal changes nothing on screen,
|
|
2827
|
+
so the press itself has to stay visible. */
|
|
2828
|
+
.icon-btn:active, .btn:active, .btn-quiet:active, .btn-danger:active, nav.side button:active,
|
|
2829
|
+
.icon-btn.pressed, .btn.pressed, .btn-quiet.pressed, .btn-danger.pressed, nav.side button.pressed {
|
|
2830
|
+
background: var(--bg-inset); border-color: var(--line-strong); color: var(--ink);
|
|
2831
|
+
}
|
|
2832
|
+
.btn-danger:active, .btn-danger.pressed { background: var(--err-soft); color: var(--err); }
|
|
2833
|
+
.btn-primary:active, .btn-primary.pressed { filter: brightness(0.88); color: var(--accent-ink); }
|
|
2763
2834
|
/* minmax(0, 1fr): a 1fr column will not shrink below its content, so a long
|
|
2764
2835
|
record or the full nav row would widen the page past the viewport. */
|
|
2765
2836
|
.layout {
|
|
@@ -2848,8 +2919,16 @@ var renderAdminDocument = (service) => {
|
|
|
2848
2919
|
input, select, textarea { font-size: 16px; }
|
|
2849
2920
|
.brand, .vendor, .controls { width: 100%; }
|
|
2850
2921
|
label.field, label.field select, label.field input { flex: 1; min-width: 0; }
|
|
2851
|
-
|
|
2922
|
+
/* The layout fills the screen. A single-column grid stretches every auto
|
|
2923
|
+
row, so the tab bar grew with the leftover height and the buttons floated
|
|
2924
|
+
in the middle of it. The bar stays one row; the page below takes the rest. */
|
|
2925
|
+
.layout {
|
|
2926
|
+
grid-template-columns: minmax(0, 1fr);
|
|
2927
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
2928
|
+
align-content: start;
|
|
2929
|
+
}
|
|
2852
2930
|
nav.side {
|
|
2931
|
+
align-self: start; height: auto;
|
|
2853
2932
|
flex-direction: row; align-items: center; overflow-x: auto; min-width: 0;
|
|
2854
2933
|
border-right: 0; border-bottom: 1px solid var(--line);
|
|
2855
2934
|
padding: 8px;
|
|
@@ -3717,7 +3796,7 @@ var stateAdminRoutes = (routes) => {
|
|
|
3717
3796
|
};
|
|
3718
3797
|
|
|
3719
3798
|
// ../core/dist/version.js
|
|
3720
|
-
var PACKAGE_VERSION = true ? "0.3.
|
|
3799
|
+
var PACKAGE_VERSION = true ? "0.3.1" : UNRELEASED_VERSION;
|
|
3721
3800
|
|
|
3722
3801
|
// ../core/dist/signing.js
|
|
3723
3802
|
var encoder = new TextEncoder();
|
|
@@ -7436,4 +7515,4 @@ export {
|
|
|
7436
7515
|
AUTH_TOKEN_TTL_MS,
|
|
7437
7516
|
PaddleAPI
|
|
7438
7517
|
};
|
|
7439
|
-
//# sourceMappingURL=chunk-
|
|
7518
|
+
//# sourceMappingURL=chunk-LW2XNBX2.js.map
|