@adea-ai/ui 0.96.0 → 0.97.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.
Files changed (49) hide show
  1. package/dist/components/composites/about-dialog/about-dialog.d.ts +17 -0
  2. package/dist/components/composites/about-dialog/about-dialog.d.ts.map +1 -0
  3. package/dist/components/composites/about-dialog/about-dialog.js +167 -0
  4. package/dist/components/composites/about-dialog/about-dialog.js.map +1 -0
  5. package/dist/components/composites/about-dialog/index.d.ts +3 -0
  6. package/dist/components/composites/about-dialog/index.d.ts.map +1 -0
  7. package/dist/components/composites/about-dialog/index.js +2 -0
  8. package/dist/components/composites/account-menu/account-menu.d.ts +20 -1
  9. package/dist/components/composites/account-menu/account-menu.d.ts.map +1 -1
  10. package/dist/components/composites/account-menu/account-menu.js +103 -50
  11. package/dist/components/composites/account-menu/account-menu.js.map +1 -1
  12. package/dist/components/composites/account-menu/index.d.ts +1 -1
  13. package/dist/components/composites/account-menu/index.d.ts.map +1 -1
  14. package/dist/components/composites/account-menu/index.js +2 -2
  15. package/dist/components/composites/help-center/help-center.d.ts +19 -0
  16. package/dist/components/composites/help-center/help-center.d.ts.map +1 -0
  17. package/dist/components/composites/help-center/help-center.js +135 -0
  18. package/dist/components/composites/help-center/help-center.js.map +1 -0
  19. package/dist/components/composites/help-center/index.d.ts +3 -0
  20. package/dist/components/composites/help-center/index.d.ts.map +1 -0
  21. package/dist/components/composites/help-center/index.js +2 -0
  22. package/dist/components/composites/update-dialog/update-dialog.d.ts +11 -1
  23. package/dist/components/composites/update-dialog/update-dialog.d.ts.map +1 -1
  24. package/dist/components/composites/update-dialog/update-dialog.js +209 -78
  25. package/dist/components/composites/update-dialog/update-dialog.js.map +1 -1
  26. package/dist/index.d.ts +2 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +4 -2
  29. package/dist/r/about-dialog.json +26 -0
  30. package/dist/r/help-center.json +28 -0
  31. package/dist/r/registry.json +55 -0
  32. package/dist/r/src/components/composites/about-dialog/about-dialog.tsx +161 -0
  33. package/dist/r/src/components/composites/about-dialog/index.ts +2 -0
  34. package/dist/r/src/components/composites/account-menu/account-menu.tsx +76 -13
  35. package/dist/r/src/components/composites/account-menu/index.ts +6 -1
  36. package/dist/r/src/components/composites/help-center/help-center.tsx +104 -0
  37. package/dist/r/src/components/composites/help-center/index.ts +2 -0
  38. package/dist/r/src/components/composites/update-dialog/update-dialog.tsx +200 -27
  39. package/dist/r/update-dialog.json +1 -0
  40. package/package.json +1 -1
  41. package/registry.json +55 -0
  42. package/src/components/composites/about-dialog/about-dialog.tsx +161 -0
  43. package/src/components/composites/about-dialog/index.ts +2 -0
  44. package/src/components/composites/account-menu/account-menu.tsx +76 -13
  45. package/src/components/composites/account-menu/index.ts +6 -1
  46. package/src/components/composites/help-center/help-center.tsx +104 -0
  47. package/src/components/composites/help-center/index.ts +2 -0
  48. package/src/components/composites/update-dialog/update-dialog.tsx +200 -27
  49. package/src/index.ts +2 -0
@@ -2,22 +2,24 @@ import { cn } from "../../../lib/utils.js";
2
2
  import { Badge } from "../../ui/badge/badge.js";
3
3
  import { Button } from "../../ui/button/button.js";
4
4
  import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, createDialogFocusRestoration } from "../../ui/dialog/dialog.js";
5
+ import { ActionButton } from "../action-button/action-button.js";
5
6
  import { Progress } from "../../ui/progress/progress.js";
6
7
  import { formatBytes, formatReleaseDate, plainTextFromMarkdown } from "../../../lib/version-notes.js";
7
- import { createComponent, insert, memo, template } from "solid-js/web";
8
- import { Check, Download, ExternalLink, LoaderCircle, RefreshCw, Sparkles } from "lucide-solid";
8
+ import { createComponent, effect, insert, memo, setAttribute, template } from "solid-js/web";
9
+ import { Check, CircleStop, Download, ExternalLink, LoaderCircle, Monitor, RefreshCw, Sparkles } from "lucide-solid";
9
10
  import { Show, createEffect, createMemo, createSignal, onCleanup, onMount, splitProps } from "solid-js";
10
11
  //#region src/components/composites/update-dialog/update-dialog.tsx
11
- var _tmpl$ = /*#__PURE__*/ template(`<div class="flex items-center gap-3"><span class="flex size-10 items-center justify-center rounded-xl bg-primary text-primary-foreground"></span><div>`);
12
- var _tmpl$2 = /*#__PURE__*/ template(`<section class="rounded-xl border border-primary/35 bg-primary-subtle p-4"aria-label="Available update"><div class="flex flex-wrap items-start justify-between gap-4"><div class="flex flex-col gap-1"><p class="flex items-center gap-2 text-sm font-semibold">Version <!> is ready</p><p class="text-sm text-muted-foreground">The signed installer is verified before <!> restarts.`);
12
+ var _tmpl$ = /*#__PURE__*/ template(`<div class="flex items-center gap-3"><div>`);
13
+ var _tmpl$2 = /*#__PURE__*/ template(`<section class="rounded-xl border border-primary/35 bg-primary-subtle p-4"aria-label="Available update"><div class="flex flex-wrap items-start justify-between gap-4"><div class="flex flex-col gap-1"><p class="flex items-center gap-2 text-sm font-semibold">Version <!> </p><p class="text-sm text-muted-foreground">The signed installer is verified before <!> restarts.`);
13
14
  var _tmpl$3 = /*#__PURE__*/ template(`<section class="grid gap-2"aria-label="Update progress"><p class="text-xs text-muted-foreground"role=status>`);
14
15
  var _tmpl$4 = /*#__PURE__*/ template(`<p class="text-foreground flex items-center gap-2 text-sm"role=status> is up to date.`);
15
16
  var _tmpl$5 = /*#__PURE__*/ template(`<p class="text-foreground flex items-center gap-2 text-sm"role=status>`);
16
17
  var _tmpl$6 = /*#__PURE__*/ template(`<p class="text-foreground rounded-lg border border-destructive/35 bg-destructive-subtle px-3 py-2 text-sm"role=alert>`);
17
- var _tmpl$7 = /*#__PURE__*/ template(`<div class="flex flex-col gap-2"><div class="flex items-center gap-2"><h2 id=update-release-notes class="text-sm font-semibold">What changed in this release</h2></div><div class="max-h-52 overflow-y-auto rounded-xl border border-border bg-background/45 p-4 font-mono text-xs leading-5 whitespace-pre-wrap text-muted-foreground"role=region aria-labelledby=update-release-notes tabindex=0>`);
18
- var _tmpl$8 = /*#__PURE__*/ template(`<div class="flex flex-col gap-2"><h2 id=update-changelog class="text-sm font-semibold">Installed changelog</h2><p class="text-xs text-muted-foreground">A plain-text history of the installed release channel.</p><div class="max-h-72 overflow-y-auto rounded-xl border border-border bg-background/45 p-4 font-mono text-xs leading-5 whitespace-pre-wrap text-muted-foreground"role=region aria-labelledby=update-changelog tabindex=0>`);
19
- var _tmpl$9 = /*#__PURE__*/ template(`<div class="flex min-h-0 flex-col gap-5 overflow-y-auto p-6"><section class="rounded-xl border border-border bg-background/45 p-4"aria-label="Version status"><div class="flex flex-wrap items-start justify-between gap-4"><div class="flex flex-col gap-1"><p class="text-2xs font-semibold tracking-widest text-muted-foreground uppercase">Installed version</p><p class="text-xl font-semibold tracking-tight">v</p><p class="text-sm text-muted-foreground">`);
20
- var _tmpl$0 = /*#__PURE__*/ template(`<p class="text-xs text-muted-foreground">Released `);
18
+ var _tmpl$7 = /*#__PURE__*/ template(`<div class="flex flex-col gap-2"><div class="flex items-center gap-2"><h2 id=update-release-notes class="text-sm font-semibold text-primary">What changed in this release</h2></div><div class="max-h-52 overflow-y-auto rounded-xl border border-border bg-background/45 p-4 font-mono text-xs leading-5 whitespace-pre-wrap text-muted-foreground"role=region aria-labelledby=update-release-notes tabindex=0>`);
19
+ var _tmpl$8 = /*#__PURE__*/ template(`<div class="flex flex-col gap-2"><h2 id=update-changelog class="text-sm font-semibold text-primary">Installed changelog</h2><p class="text-xs text-muted-foreground">All versions and updates included with this installation.</p><div class="max-h-72 overflow-y-auto rounded-xl border border-border bg-background/45 p-4 font-mono text-xs leading-5 whitespace-pre-wrap text-muted-foreground"role=region aria-labelledby=update-changelog tabindex=0>`);
20
+ var _tmpl$9 = /*#__PURE__*/ template(`<div class="flex min-h-0 flex-col gap-5 overflow-y-auto p-6"><section class="rounded-xl border border-border bg-background/45 p-4"aria-label="Version status"><div class="flex flex-wrap items-start justify-between gap-4"><div class="flex flex-col gap-1"><p class="text-2xs font-semibold tracking-widest text-muted-foreground uppercase">Installed version</p><p class="text-xl font-semibold tracking-tight text-primary">v</p><p class="text-sm text-muted-foreground">`);
21
+ var _tmpl$0 = /*#__PURE__*/ template(`<img alt class=size-10 aria-hidden=true>`);
22
+ var _tmpl$1 = /*#__PURE__*/ template(`<p class="text-xs text-muted-foreground">Released `);
21
23
  function messageText(value) {
22
24
  if (typeof value !== "string") return void 0;
23
25
  const message = value.trim();
@@ -40,12 +42,14 @@ function errorMessage(caught, fallback) {
40
42
  * happens.
41
43
  */
42
44
  function isBusy(state) {
43
- return state?.phase === "checking" || state?.phase === "downloading" || state?.phase === "installing";
45
+ return state?.phase === "checking" || state?.phase === "downloading" || state?.phase === "installing" || state?.phase === "cancelling";
44
46
  }
45
47
  function UpdateDialog(props) {
46
48
  const [local] = splitProps(props, [
47
49
  "adapter",
48
50
  "appName",
51
+ "appIcon",
52
+ "changelog",
49
53
  "fallbackVersion",
50
54
  "desktopOnlyMessage",
51
55
  "open",
@@ -70,6 +74,7 @@ function UpdateDialog(props) {
70
74
  const [busy, setBusy] = createSignal(false);
71
75
  const [error, setError] = createSignal("");
72
76
  const [checkFailed, setCheckFailed] = createSignal(false);
77
+ const [cancelPending, setCancelPending] = createSignal(false);
73
78
  let lifecycleEpoch = 0;
74
79
  let activeOpenEpoch;
75
80
  let disposed = false;
@@ -141,6 +146,7 @@ function UpdateDialog(props) {
141
146
  */
142
147
  createEffect(() => {
143
148
  if (!open() || !desktop()) {
149
+ setCancelPending(false);
144
150
  if (activeOpenEpoch !== void 0) {
145
151
  activeOpenEpoch = void 0;
146
152
  lifecycleEpoch += 1;
@@ -160,6 +166,7 @@ function UpdateDialog(props) {
160
166
  });
161
167
  setError("");
162
168
  setCheckFailed(false);
169
+ setCancelPending(false);
163
170
  setBusy(true);
164
171
  (async () => {
165
172
  try {
@@ -182,10 +189,19 @@ function UpdateDialog(props) {
182
189
  if (!version || !isCurrent()) return;
183
190
  setBusy(true);
184
191
  setError("");
192
+ setState((current) => current ? {
193
+ ...current,
194
+ phase: "downloading",
195
+ downloadedBytes: 0,
196
+ totalBytes: null
197
+ } : current);
185
198
  try {
186
199
  const next = await local.adapter.install(version);
187
200
  if (!isCurrent()) return;
188
- setState(next);
201
+ setState(cancelPending() && ["downloading", "installing"].includes(next.phase) ? {
202
+ ...next,
203
+ phase: "cancelling"
204
+ } : next);
189
205
  if (next.phase === "failed") setError(errorMessage(next.error, "Update installation failed"));
190
206
  else setCheckFailed(false);
191
207
  } catch (caught) {
@@ -196,12 +212,75 @@ function UpdateDialog(props) {
196
212
  if (isCurrent()) setBusy(false);
197
213
  }
198
214
  };
199
- const changelog = createMemo(() => plainTextFromMarkdown(state()?.changelog ?? ""));
215
+ createEffect(() => {
216
+ const phase = state()?.phase;
217
+ if (!open() || !desktop() || !local.adapter.pollIntervalMs || ![
218
+ "downloading",
219
+ "installing",
220
+ "cancelling"
221
+ ].includes(phase ?? "")) return;
222
+ const epoch = activeOpenEpoch;
223
+ let active = true;
224
+ let requestInFlight = false;
225
+ const timer = window.setInterval(() => {
226
+ if (requestInFlight) return;
227
+ requestInFlight = true;
228
+ (async () => {
229
+ try {
230
+ const next = await local.adapter.getStatus();
231
+ if (!active || disposed || !open() || activeOpenEpoch !== epoch) return;
232
+ setState(cancelPending() && ["downloading", "installing"].includes(next.phase) ? {
233
+ ...next,
234
+ phase: "cancelling"
235
+ } : next);
236
+ if (next.phase === "failed") setError(errorMessage(next.error, "Update installation failed"));
237
+ } catch (caught) {
238
+ if (active && !disposed && activeOpenEpoch === epoch) setError(errorMessage(caught, "Update progress is unavailable"));
239
+ } finally {
240
+ requestInFlight = false;
241
+ }
242
+ })();
243
+ }, Math.max(250, local.adapter.pollIntervalMs));
244
+ onCleanup(() => {
245
+ active = false;
246
+ window.clearInterval(timer);
247
+ });
248
+ });
249
+ const cancel = async () => {
250
+ if (!local.adapter.cancel || cancelPending() || state()?.phase === "cancelling") return;
251
+ const epoch = activeOpenEpoch;
252
+ setError("");
253
+ setCancelPending(true);
254
+ setState((current) => current ? {
255
+ ...current,
256
+ phase: "cancelling"
257
+ } : current);
258
+ try {
259
+ const next = await local.adapter.cancel();
260
+ if (!disposed && open() && activeOpenEpoch === epoch) setState(next);
261
+ } catch (caught) {
262
+ if (!disposed && open() && activeOpenEpoch === epoch) {
263
+ setError(errorMessage(caught, "Could not cancel the update"));
264
+ await loadStatus(() => !disposed && open() && activeOpenEpoch === epoch);
265
+ }
266
+ } finally {
267
+ if (!disposed && open() && activeOpenEpoch === epoch) setCancelPending(false);
268
+ }
269
+ };
270
+ const openRelease = async (url) => {
271
+ try {
272
+ if (local.adapter.openExternal) await local.adapter.openExternal(url);
273
+ else window.open(url, "_blank", "noopener,noreferrer");
274
+ } catch (caught) {
275
+ if (!disposed) setError(errorMessage(caught, "Could not open the release page"));
276
+ }
277
+ };
278
+ const changelog = createMemo(() => plainTextFromMarkdown(state()?.changelog || local.changelog || ""));
200
279
  const notes = () => {
201
280
  const value = state()?.releaseNotes;
202
281
  return value ? plainTextFromMarkdown(value) : "";
203
282
  };
204
- const working = () => busy() || isBusy(state());
283
+ const working = () => busy() || cancelPending() || isBusy(state());
205
284
  const isCurrent = () => state()?.phase === "current" && !error() && !checkFailed() && !working();
206
285
  const triggerLabel = () => {
207
286
  const current = state();
@@ -258,8 +337,18 @@ function UpdateDialog(props) {
258
337
  get ["class"]() {
259
338
  return cn("max-w-3xl", local.class);
260
339
  },
261
- get onOpenAutoFocus() {
262
- return focusRestoration.onOpenAutoFocus;
340
+ onKeyDown: (event) => {
341
+ if (event.key === "Escape" && !event.defaultPrevented) {
342
+ event.preventDefault();
343
+ setOpen(false);
344
+ }
345
+ },
346
+ onOpenAutoFocus: (event) => {
347
+ focusRestoration.onOpenAutoFocus(event);
348
+ if (!event.defaultPrevented && event.currentTarget instanceof HTMLElement) {
349
+ event.preventDefault();
350
+ event.currentTarget.focus({ preventScroll: true });
351
+ }
263
352
  },
264
353
  get onCloseAutoFocus() {
265
354
  return focusRestoration.onCloseAutoFocus;
@@ -267,13 +356,25 @@ function UpdateDialog(props) {
267
356
  get children() {
268
357
  return [
269
358
  createComponent(DialogHeader, { get children() {
270
- var _el$ = _tmpl$(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling;
271
- insert(_el$2, createComponent(Sparkles, {
272
- "class": "size-5",
273
- "aria-hidden": "true"
274
- }));
275
- insert(_el$3, createComponent(DialogTitle, { children: "Version & updates" }), null);
276
- insert(_el$3, createComponent(DialogDescription, { get children() {
359
+ var _el$ = _tmpl$(), _el$2 = _el$.firstChild;
360
+ insert(_el$, createComponent(Show, {
361
+ get when() {
362
+ return local.appIcon;
363
+ },
364
+ get fallback() {
365
+ return createComponent(Monitor, {
366
+ "class": "size-10 text-primary",
367
+ "aria-hidden": "true"
368
+ });
369
+ },
370
+ children: (icon) => (() => {
371
+ var _el$34 = _tmpl$0();
372
+ effect(() => setAttribute(_el$34, "src", icon()));
373
+ return _el$34;
374
+ })()
375
+ }), _el$2);
376
+ insert(_el$2, createComponent(DialogTitle, { children: "Version & updates" }), null);
377
+ insert(_el$2, createComponent(DialogDescription, { get children() {
277
378
  return [
278
379
  "Keep ",
279
380
  memo(() => appName()),
@@ -283,11 +384,11 @@ function UpdateDialog(props) {
283
384
  return _el$;
284
385
  } }),
285
386
  (() => {
286
- var _el$4 = _tmpl$9(), _el$6 = _el$4.firstChild.firstChild, _el$9 = _el$6.firstChild.firstChild.nextSibling;
287
- _el$9.firstChild;
288
- var _el$1 = _el$9.nextSibling;
289
- insert(_el$9, () => state()?.currentVersion || local.fallbackVersion || "0.1.0", null);
290
- insert(_el$1, createComponent(Show, {
387
+ var _el$3 = _tmpl$9(), _el$5 = _el$3.firstChild.firstChild, _el$8 = _el$5.firstChild.firstChild.nextSibling;
388
+ _el$8.firstChild;
389
+ var _el$0 = _el$8.nextSibling;
390
+ insert(_el$8, () => state()?.currentVersion || local.fallbackVersion || "0.1.0", null);
391
+ insert(_el$0, createComponent(Show, {
291
392
  get when() {
292
393
  return isCurrent();
293
394
  },
@@ -297,7 +398,7 @@ function UpdateDialog(props) {
297
398
  return memo(() => state()?.phase === "available")() && state()?.availableVersion;
298
399
  },
299
400
  get fallback() {
300
- return memo(() => !!desktop())() ? "Check the release channel for the latest signed build." : local.desktopOnlyMessage ?? `Open this dialog inside the desktop app to check for updates.`;
401
+ return memo(() => state()?.phase === "unavailable")() ? "No signed package is published for this platform." : memo(() => state()?.phase === "cancelled")() ? "Update cancelled. You can retry when ready." : memo(() => !!desktop())() ? "Check the release channel for the latest signed build." : local.desktopOnlyMessage ?? `Open this dialog inside the desktop app to check for updates.`;
301
402
  },
302
403
  get children() {
303
404
  return `A newer release, v${state()?.availableVersion}, is ready.`;
@@ -306,10 +407,11 @@ function UpdateDialog(props) {
306
407
  },
307
408
  children: "You are running the latest release."
308
409
  }));
309
- insert(_el$6, createComponent(Button, {
410
+ insert(_el$5, createComponent(ActionButton, {
310
411
  type: "button",
311
412
  variant: "outline",
312
413
  size: "sm",
414
+ tooltip: "Check the release channel for the latest signed app version.",
313
415
  get disabled() {
314
416
  return !desktop() || working();
315
417
  },
@@ -331,35 +433,43 @@ function UpdateDialog(props) {
331
433
  }), memo(() => checkFailed() ? "Retry update check" : "Check latest version")];
332
434
  }
333
435
  }), null);
334
- insert(_el$4, createComponent(Show, {
436
+ insert(_el$3, createComponent(Show, {
335
437
  get when() {
336
- return memo(() => state()?.phase === "available")() && state()?.availableVersion;
438
+ return memo(() => !!(state()?.availableVersion && state()?.phase !== "installed"))() && state()?.phase !== "unavailable";
337
439
  },
338
440
  get children() {
339
- var _el$10 = _tmpl$2(), _el$11 = _el$10.firstChild, _el$12 = _el$11.firstChild, _el$13 = _el$12.firstChild, _el$14 = _el$13.firstChild, _el$16 = _el$14.nextSibling;
340
- _el$16.nextSibling;
341
- var _el$17 = _el$13.nextSibling, _el$20 = _el$17.firstChild.nextSibling;
342
- _el$20.nextSibling;
343
- insert(_el$13, createComponent(Sparkles, {
441
+ var _el$1 = _tmpl$2(), _el$10 = _el$1.firstChild, _el$11 = _el$10.firstChild, _el$12 = _el$11.firstChild, _el$13 = _el$12.firstChild, _el$15 = _el$13.nextSibling;
442
+ _el$15.nextSibling;
443
+ var _el$16 = _el$12.nextSibling, _el$19 = _el$16.firstChild.nextSibling;
444
+ _el$19.nextSibling;
445
+ insert(_el$12, createComponent(Sparkles, {
344
446
  "class": "size-4 text-primary",
345
447
  "aria-hidden": "true"
346
- }), _el$14);
347
- insert(_el$13, () => state()?.availableVersion, _el$16);
348
- insert(_el$17, appName, _el$20);
349
- insert(_el$12, createComponent(Show, {
448
+ }), _el$13);
449
+ insert(_el$12, () => state()?.availableVersion, _el$15);
450
+ insert(_el$12, () => [
451
+ "downloading",
452
+ "installing",
453
+ "cancelling"
454
+ ].includes(state()?.phase ?? "") ? "is being prepared" : "is ready", null);
455
+ insert(_el$16, appName, _el$19);
456
+ insert(_el$11, createComponent(Show, {
350
457
  get when() {
351
458
  return formatReleaseDate(state()?.releaseDate ?? null);
352
459
  },
353
460
  children: (released) => (() => {
354
- var _el$35 = _tmpl$0();
461
+ var _el$35 = _tmpl$1();
355
462
  _el$35.firstChild;
356
463
  insert(_el$35, released, null);
357
464
  return _el$35;
358
465
  })()
359
466
  }), null);
360
- insert(_el$11, createComponent(Button, {
467
+ insert(_el$10, createComponent(ActionButton, {
361
468
  type: "button",
362
469
  size: "sm",
470
+ get tooltip() {
471
+ return `Download the signed update and restart ${appName()}.`;
472
+ },
363
473
  get disabled() {
364
474
  return working();
365
475
  },
@@ -381,24 +491,24 @@ function UpdateDialog(props) {
381
491
  }), "Install and restart"];
382
492
  }
383
493
  }), null);
384
- return _el$10;
494
+ return _el$1;
385
495
  }
386
496
  }), null);
387
- insert(_el$4, createComponent(Show, {
497
+ insert(_el$3, createComponent(Show, {
388
498
  get when() {
389
- return state()?.phase === "downloading" || state()?.phase === "installing";
499
+ return state()?.phase === "downloading" || state()?.phase === "installing" || state()?.phase === "cancelling";
390
500
  },
391
501
  get children() {
392
- var _el$21 = _tmpl$3(), _el$22 = _el$21.firstChild;
393
- insert(_el$21, createComponent(Progress, {
502
+ var _el$20 = _tmpl$3(), _el$21 = _el$20.firstChild;
503
+ insert(_el$20, createComponent(Progress, {
394
504
  get value() {
395
505
  return progressValue() ?? void 0;
396
506
  },
397
507
  get ["aria-label"]() {
398
508
  return state()?.phase === "installing" ? "Installing update" : "Downloading update";
399
509
  }
400
- }), _el$22);
401
- insert(_el$22, createComponent(Show, {
510
+ }), _el$21);
511
+ insert(_el$21, createComponent(Show, {
402
512
  get when() {
403
513
  return state()?.phase === "installing";
404
514
  },
@@ -415,34 +525,54 @@ function UpdateDialog(props) {
415
525
  },
416
526
  children: "Applying the update…"
417
527
  }));
418
- return _el$21;
528
+ insert(_el$20, createComponent(Show, {
529
+ get when() {
530
+ return local.adapter.cancel;
531
+ },
532
+ get children() {
533
+ return createComponent(ActionButton, {
534
+ type: "button",
535
+ variant: "outline",
536
+ size: "sm",
537
+ tooltip: "Stop the current update download or installation.",
538
+ get disabled() {
539
+ return cancelPending() || state()?.phase === "cancelling";
540
+ },
541
+ onClick: () => void cancel(),
542
+ get children() {
543
+ return [createComponent(CircleStop, { "aria-hidden": "true" }), memo(() => cancelPending() || state()?.phase === "cancelling" ? "Cancelling…" : "Cancel update")];
544
+ }
545
+ });
546
+ }
547
+ }), null);
548
+ return _el$20;
419
549
  }
420
550
  }), null);
421
- insert(_el$4, createComponent(Show, {
551
+ insert(_el$3, createComponent(Show, {
422
552
  get when() {
423
553
  return isCurrent();
424
554
  },
425
555
  get children() {
426
- var _el$23 = _tmpl$4(), _el$24 = _el$23.firstChild;
427
- insert(_el$23, createComponent(Check, {
556
+ var _el$22 = _tmpl$4(), _el$23 = _el$22.firstChild;
557
+ insert(_el$22, createComponent(Check, {
428
558
  "class": "size-4 text-success",
429
559
  "aria-hidden": "true"
430
- }), _el$24);
431
- insert(_el$23, appName, _el$24);
432
- return _el$23;
560
+ }), _el$23);
561
+ insert(_el$22, appName, _el$23);
562
+ return _el$22;
433
563
  }
434
564
  }), null);
435
- insert(_el$4, createComponent(Show, {
565
+ insert(_el$3, createComponent(Show, {
436
566
  get when() {
437
567
  return state()?.phase === "installed";
438
568
  },
439
569
  get children() {
440
- var _el$25 = _tmpl$5();
441
- insert(_el$25, createComponent(Check, {
570
+ var _el$24 = _tmpl$5();
571
+ insert(_el$24, createComponent(Check, {
442
572
  "class": "size-4 text-success",
443
573
  "aria-hidden": "true"
444
574
  }), null);
445
- insert(_el$25, createComponent(Show, {
575
+ insert(_el$24, createComponent(Show, {
446
576
  get when() {
447
577
  return state()?.restartRequired;
448
578
  },
@@ -455,60 +585,61 @@ function UpdateDialog(props) {
455
585
  ];
456
586
  }
457
587
  }), null);
458
- return _el$25;
588
+ return _el$24;
459
589
  }
460
590
  }), null);
461
- insert(_el$4, createComponent(Show, {
591
+ insert(_el$3, createComponent(Show, {
462
592
  get when() {
463
593
  return error();
464
594
  },
465
595
  get children() {
466
- var _el$26 = _tmpl$6();
467
- insert(_el$26, error);
468
- return _el$26;
596
+ var _el$25 = _tmpl$6();
597
+ insert(_el$25, error);
598
+ return _el$25;
469
599
  }
470
600
  }), null);
471
- insert(_el$4, createComponent(Show, {
601
+ insert(_el$3, createComponent(Show, {
472
602
  get when() {
473
603
  return notes();
474
604
  },
475
605
  get children() {
476
- var _el$27 = _tmpl$7(), _el$28 = _el$27.firstChild;
477
- _el$28.firstChild;
478
- var _el$30 = _el$28.nextSibling;
479
- insert(_el$28, createComponent(Badge, {
606
+ var _el$26 = _tmpl$7(), _el$27 = _el$26.firstChild;
607
+ _el$27.firstChild;
608
+ var _el$29 = _el$27.nextSibling;
609
+ insert(_el$27, createComponent(Badge, {
480
610
  variant: "subtle",
481
611
  size: "sm",
482
612
  get children() {
483
613
  return ["v", memo(() => state()?.availableVersion)];
484
614
  }
485
615
  }), null);
486
- insert(_el$30, notes);
487
- return _el$27;
616
+ insert(_el$29, notes);
617
+ return _el$26;
488
618
  }
489
619
  }), null);
490
- insert(_el$4, createComponent(Show, {
620
+ insert(_el$3, createComponent(Show, {
491
621
  get when() {
492
622
  return changelog();
493
623
  },
494
624
  get children() {
495
- var _el$31 = _tmpl$8(), _el$34 = _el$31.firstChild.nextSibling.nextSibling;
496
- insert(_el$34, changelog);
497
- return _el$31;
625
+ var _el$30 = _tmpl$8(), _el$33 = _el$30.firstChild.nextSibling.nextSibling;
626
+ insert(_el$33, changelog);
627
+ return _el$30;
498
628
  }
499
629
  }), null);
500
- return _el$4;
630
+ return _el$3;
501
631
  })(),
502
632
  createComponent(DialogFooter, { get children() {
503
633
  return [createComponent(Show, {
504
634
  get when() {
505
635
  return state()?.releaseUrl;
506
636
  },
507
- children: (url) => createComponent(Button, {
637
+ children: (url) => createComponent(ActionButton, {
508
638
  type: "button",
509
639
  variant: "ghost",
510
640
  size: "sm",
511
- onClick: () => window.open(url(), "_blank", "noopener,noreferrer"),
641
+ tooltip: "Open the release history in your browser.",
642
+ onClick: () => void openRelease(url()),
512
643
  get children() {
513
644
  return [createComponent(ExternalLink, { "aria-hidden": "true" }), "View releases"];
514
645
  }