@crvouga/mockingbird-service-aws-speech 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 CHANGED
@@ -1,6 +1,14 @@
1
1
  # Changelog — @crvouga/mockingbird-service-aws-speech
2
2
 
3
- ## 1.6.0 (2026-09-30)
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
 
@@ -2096,6 +2096,50 @@ function bootAdmin(config) {
2096
2096
  if (render)
2097
2097
  await render();
2098
2098
  }
2099
+ const delay = (ms) => new Promise((resolve) => {
2100
+ window.setTimeout(resolve, ms);
2101
+ });
2102
+ const confirmAction = async (button, pending, done, work) => {
2103
+ if (button.dataset.pending === "1")
2104
+ return;
2105
+ const label = button.textContent ?? "";
2106
+ const width = button.offsetWidth;
2107
+ button.dataset.pending = "1";
2108
+ button.classList.add("pressed");
2109
+ button.setAttribute("aria-busy", "true");
2110
+ button.style.minWidth = `${width}px`;
2111
+ button.textContent = pending;
2112
+ try {
2113
+ await work();
2114
+ button.textContent = done;
2115
+ await delay(1e3);
2116
+ } catch (error) {
2117
+ showError(error);
2118
+ } finally {
2119
+ button.textContent = label;
2120
+ button.style.minWidth = "";
2121
+ button.classList.remove("pressed");
2122
+ button.removeAttribute("aria-busy");
2123
+ delete button.dataset.pending;
2124
+ }
2125
+ };
2126
+ document.addEventListener("click", (event) => {
2127
+ const target = event.target;
2128
+ if (!(target instanceof Element))
2129
+ return;
2130
+ const button = target.closest("button");
2131
+ if (!(button instanceof HTMLButtonElement) || button.dataset.pending === "1")
2132
+ return;
2133
+ button.classList.add("pressed");
2134
+ const token = String(Date.now());
2135
+ button.dataset.press = token;
2136
+ window.setTimeout(() => {
2137
+ if (button.dataset.press !== token || button.dataset.pending === "1")
2138
+ return;
2139
+ button.classList.remove("pressed");
2140
+ delete button.dataset.press;
2141
+ }, 450);
2142
+ });
2099
2143
  el("namespace", HTMLSelectElement).addEventListener("change", () => {
2100
2144
  state.namespace = el("namespace", HTMLSelectElement).value;
2101
2145
  refresh().catch(showError);
@@ -2106,7 +2150,7 @@ function bootAdmin(config) {
2106
2150
  refresh().catch(showError);
2107
2151
  });
2108
2152
  el("refresh", HTMLButtonElement).addEventListener("click", () => {
2109
- refresh().catch(showError);
2153
+ confirmAction(el("refresh", HTMLButtonElement), "Refreshing...", "Updated", () => refresh()).catch(showError);
2110
2154
  });
2111
2155
  el("collections", HTMLElement).addEventListener("click", (event) => {
2112
2156
  const target = event.target;
@@ -2229,10 +2273,10 @@ function bootAdmin(config) {
2229
2273
  }).then(() => renderFaults()).catch(showError);
2230
2274
  });
2231
2275
  el("fault-clear", HTMLButtonElement).addEventListener("click", () => {
2232
- api("DELETE", "/faults").then(() => renderFaults()).catch(showError);
2276
+ confirmAction(el("fault-clear", HTMLButtonElement), "Clearing...", "Cleared", () => api("DELETE", "/faults").then(() => renderFaults())).catch(showError);
2233
2277
  });
2234
2278
  el("journal-clear", HTMLButtonElement).addEventListener("click", () => {
2235
- api("DELETE", "/requests").then(() => renderJournal()).catch(showError);
2279
+ confirmAction(el("journal-clear", HTMLButtonElement), "Clearing...", "Cleared", () => api("DELETE", "/requests").then(() => renderJournal())).catch(showError);
2236
2280
  });
2237
2281
  el("route-list", HTMLElement).addEventListener("click", (event) => {
2238
2282
  const target = event.target;
@@ -2347,9 +2391,13 @@ function bootAdmin(config) {
2347
2391
  var clientPrelude = [isRecord2, mountAdminBrand, startAdminBrand, faultPresetList, bootAdmin].map((fn) => fn.toString()).join("\n");
2348
2392
  var adminClientSource = (config) => {
2349
2393
  const payload = JSON.stringify(config).replace(/</g, "\\u003c");
2394
+ const entry = bootAdmin.name;
2395
+ if (!/^[A-Za-z_$][\w$]*$/.test(entry)) {
2396
+ throw new Error("admin client cannot call its boot function");
2397
+ }
2350
2398
  return `<script>
2351
2399
  ${clientPrelude}
2352
- bootAdmin(${payload});
2400
+ ${entry}(${payload});
2353
2401
  </script>`;
2354
2402
  };
2355
2403
 
@@ -2563,9 +2611,24 @@ var renderAdminDocument = (service) => {
2563
2611
  .controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
2564
2612
  label.field { display: flex; flex-direction: column; gap: 2px; font-size: 11px; color: var(--faint); }
2565
2613
  label.field input, label.field select, .controls input[type="password"] {
2566
- background: var(--bg-inset); border: 1px solid var(--line); border-radius: 8px;
2567
- padding: 7px 8px; min-height: 36px;
2568
- }
2614
+ background-color: var(--bg-inset); border: 1px solid var(--line); border-radius: 8px;
2615
+ padding: 7px 8px; min-height: 36px; line-height: 1.2;
2616
+ }
2617
+ /* A native menu ignores min-height, so Preset rendered about half as tall as
2618
+ the text fields in the same form. Paint it like those fields. */
2619
+ label.field select {
2620
+ -webkit-appearance: none; appearance: none;
2621
+ padding-right: 28px;
2622
+ 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");
2623
+ background-repeat: no-repeat; background-position: right 10px center; background-size: 12px 12px;
2624
+ }
2625
+ .stack > .field > input,
2626
+ .stack > .field > select,
2627
+ .stack > .field > textarea,
2628
+ dialog .field > input,
2629
+ dialog .field > select,
2630
+ dialog .field > textarea { width: 100%; }
2631
+ .icon-btn, .btn, .btn-primary, .btn-quiet, .btn-danger, nav.side button { cursor: pointer; }
2569
2632
  .icon-btn, .btn, .btn-primary, .btn-quiet, .btn-danger {
2570
2633
  border-radius: 9px; min-height: 36px; padding: 0 12px; border: 1px solid var(--line);
2571
2634
  background: var(--bg-elev);
@@ -2573,6 +2636,14 @@ var renderAdminDocument = (service) => {
2573
2636
  .btn-primary { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
2574
2637
  .btn-quiet { background: transparent; }
2575
2638
  .btn-danger { color: var(--err); }
2639
+ /* Held after mouseup. Clearing an empty journal changes nothing on screen,
2640
+ so the press itself has to stay visible. */
2641
+ .icon-btn:active, .btn:active, .btn-quiet:active, .btn-danger:active, nav.side button:active,
2642
+ .icon-btn.pressed, .btn.pressed, .btn-quiet.pressed, .btn-danger.pressed, nav.side button.pressed {
2643
+ background: var(--bg-inset); border-color: var(--line-strong); color: var(--ink);
2644
+ }
2645
+ .btn-danger:active, .btn-danger.pressed { background: var(--err-soft); color: var(--err); }
2646
+ .btn-primary:active, .btn-primary.pressed { filter: brightness(0.88); color: var(--accent-ink); }
2576
2647
  /* minmax(0, 1fr): a 1fr column will not shrink below its content, so a long
2577
2648
  record or the full nav row would widen the page past the viewport. */
2578
2649
  .layout {
@@ -2661,8 +2732,16 @@ var renderAdminDocument = (service) => {
2661
2732
  input, select, textarea { font-size: 16px; }
2662
2733
  .brand, .vendor, .controls { width: 100%; }
2663
2734
  label.field, label.field select, label.field input { flex: 1; min-width: 0; }
2664
- .layout { grid-template-columns: minmax(0, 1fr); }
2735
+ /* The layout fills the screen. A single-column grid stretches every auto
2736
+ row, so the tab bar grew with the leftover height and the buttons floated
2737
+ in the middle of it. The bar stays one row; the page below takes the rest. */
2738
+ .layout {
2739
+ grid-template-columns: minmax(0, 1fr);
2740
+ grid-template-rows: auto minmax(0, 1fr);
2741
+ align-content: start;
2742
+ }
2665
2743
  nav.side {
2744
+ align-self: start; height: auto;
2666
2745
  flex-direction: row; align-items: center; overflow-x: auto; min-width: 0;
2667
2746
  border-right: 0; border-bottom: 1px solid var(--line);
2668
2747
  padding: 8px;
@@ -3456,7 +3535,7 @@ var stateAdminRoutes = (routes) => {
3456
3535
  };
3457
3536
 
3458
3537
  // ../core/dist/version.js
3459
- var PACKAGE_VERSION = true ? "1.6.0" : UNRELEASED_VERSION;
3538
+ var PACKAGE_VERSION = true ? "1.6.1" : UNRELEASED_VERSION;
3460
3539
 
3461
3540
  // ../core/dist/signing.js
3462
3541
  var encoder = new TextEncoder();
@@ -5618,4 +5697,4 @@ export {
5618
5697
  accessKeyCredential,
5619
5698
  SpeechAPI
5620
5699
  };
5621
- //# sourceMappingURL=chunk-7C3XFQVJ.js.map
5700
+ //# sourceMappingURL=chunk-BNMCHWY6.js.map