@unbrained/pm-web 2026.9.18 → 2026.9.23

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 (126) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +6 -4
  3. package/dist/app.d.ts +10 -0
  4. package/dist/app.js +19 -9
  5. package/dist/app.js.map +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/routes/admin.js +6 -6
  8. package/dist/routes/admin.js.map +1 -1
  9. package/dist/routes/auth.js +2 -2
  10. package/dist/routes/auth.js.map +1 -1
  11. package/dist/routes/extensions.js +24 -37
  12. package/dist/routes/extensions.js.map +1 -1
  13. package/dist/routes/github.js +169 -107
  14. package/dist/routes/github.js.map +1 -1
  15. package/dist/routes/groups.js +9 -14
  16. package/dist/routes/groups.js.map +1 -1
  17. package/dist/routes/pm.js +532 -1015
  18. package/dist/routes/pm.js.map +1 -1
  19. package/dist/routes/projects.js +10 -6
  20. package/dist/routes/projects.js.map +1 -1
  21. package/dist/routes/route-helpers.d.ts +74 -0
  22. package/dist/routes/route-helpers.js +85 -0
  23. package/dist/routes/route-helpers.js.map +1 -0
  24. package/dist/routes/sharing.js +30 -18
  25. package/dist/routes/sharing.js.map +1 -1
  26. package/dist/server.js +1 -20
  27. package/dist/server.js.map +1 -1
  28. package/dist/services/mutation-event-watcher.js +3 -28
  29. package/dist/services/mutation-event-watcher.js.map +1 -1
  30. package/dist/services/pm-runner.js +3 -1
  31. package/dist/services/pm-runner.js.map +1 -1
  32. package/dist/services/project-watcher.js +14 -38
  33. package/dist/services/project-watcher.js.map +1 -1
  34. package/dist/services/watcher-utils.d.ts +42 -0
  35. package/dist/services/watcher-utils.js +60 -0
  36. package/dist/services/watcher-utils.js.map +1 -0
  37. package/manifest.json +2 -2
  38. package/package.json +17 -6
  39. package/public/src/app.js +22 -52
  40. package/public/src/app.js.map +1 -1
  41. package/public/src/app.ts +18 -75
  42. package/public/src/browser-window.js +29 -0
  43. package/public/src/browser-window.js.map +1 -0
  44. package/public/src/browser-window.ts +56 -0
  45. package/public/src/components/modals.js +1 -1
  46. package/public/src/components/modals.js.map +1 -1
  47. package/public/src/components/modals.ts +1 -1
  48. package/public/src/i18n.js +14 -6
  49. package/public/src/i18n.js.map +1 -1
  50. package/public/src/i18n.ts +16 -6
  51. package/public/src/sw.ts +1 -0
  52. package/public/src/utils.js +58 -0
  53. package/public/src/utils.js.map +1 -1
  54. package/public/src/utils.ts +53 -0
  55. package/public/src/views/admin.js +2 -5
  56. package/public/src/views/admin.js.map +1 -1
  57. package/public/src/views/admin.ts +2 -2
  58. package/public/src/views/auth.js +5 -1
  59. package/public/src/views/auth.js.map +1 -1
  60. package/public/src/views/auth.ts +6 -1
  61. package/public/src/views/calendar.js +1 -2
  62. package/public/src/views/calendar.js.map +1 -1
  63. package/public/src/views/calendar.ts +1 -2
  64. package/public/src/views/config.js +14 -21
  65. package/public/src/views/config.js.map +1 -1
  66. package/public/src/views/config.ts +14 -19
  67. package/public/src/views/context.js +11 -12
  68. package/public/src/views/context.js.map +1 -1
  69. package/public/src/views/context.ts +13 -12
  70. package/public/src/views/create.js +3 -11
  71. package/public/src/views/create.js.map +1 -1
  72. package/public/src/views/create.ts +3 -3
  73. package/public/src/views/export.js +2 -3
  74. package/public/src/views/export.js.map +1 -1
  75. package/public/src/views/export.ts +2 -3
  76. package/public/src/views/github.js +33 -47
  77. package/public/src/views/github.js.map +1 -1
  78. package/public/src/views/github.ts +35 -28
  79. package/public/src/views/graph-canvas.js +92 -99
  80. package/public/src/views/graph-canvas.js.map +1 -1
  81. package/public/src/views/graph-canvas.ts +94 -93
  82. package/public/src/views/graph.js +88 -73
  83. package/public/src/views/graph.js.map +1 -1
  84. package/public/src/views/graph.ts +97 -63
  85. package/public/src/views/groups.js +2 -5
  86. package/public/src/views/groups.js.map +1 -1
  87. package/public/src/views/groups.ts +2 -2
  88. package/public/src/views/guide.js +11 -10
  89. package/public/src/views/guide.js.map +1 -1
  90. package/public/src/views/guide.ts +12 -10
  91. package/public/src/views/items.js +100 -130
  92. package/public/src/views/items.js.map +1 -1
  93. package/public/src/views/items.ts +99 -117
  94. package/public/src/views/normalize.js +2 -9
  95. package/public/src/views/normalize.js.map +1 -1
  96. package/public/src/views/normalize.ts +2 -9
  97. package/public/src/views/packages.js +7 -4
  98. package/public/src/views/packages.js.map +1 -1
  99. package/public/src/views/packages.ts +8 -4
  100. package/public/src/views/plan-execution.js.map +1 -1
  101. package/public/src/views/plan-execution.ts +5 -15
  102. package/public/src/views/plan.js +2 -1
  103. package/public/src/views/plan.js.map +1 -1
  104. package/public/src/views/plan.ts +6 -17
  105. package/public/src/views/projects.js +5 -6
  106. package/public/src/views/projects.js.map +1 -1
  107. package/public/src/views/projects.ts +5 -6
  108. package/public/src/views/search.js +5 -1
  109. package/public/src/views/search.js.map +1 -1
  110. package/public/src/views/search.ts +7 -1
  111. package/public/src/views/settings.js +30 -55
  112. package/public/src/views/settings.js.map +1 -1
  113. package/public/src/views/settings.ts +23 -17
  114. package/public/src/views/shared.js +2 -5
  115. package/public/src/views/shared.js.map +1 -1
  116. package/public/src/views/shared.ts +2 -5
  117. package/public/src/views/sharing.js +2 -5
  118. package/public/src/views/sharing.js.map +1 -1
  119. package/public/src/views/sharing.ts +2 -2
  120. package/public/src/views/templates.js +9 -16
  121. package/public/src/views/templates.js.map +1 -1
  122. package/public/src/views/templates.ts +9 -14
  123. package/public/src/views/validate.js +2 -9
  124. package/public/src/views/validate.js.map +1 -1
  125. package/public/src/views/validate.ts +2 -9
  126. package/public/sw.js +1 -0
@@ -3,7 +3,7 @@
3
3
  // ═══════════════════════════════════════════════════════════════
4
4
  import { state } from '../state.js';
5
5
  import { api } from '../api.js';
6
- import { escHtml, statusBadge, priorityDot, typeIcon } from '../utils.js';
6
+ import { escHtml, statusBadge, priorityDot, typeIcon, relTime, fmtDate, setFormValue, resetButton } from '../utils.js';
7
7
  import { showModal, hideModal, createModal, confirmDialog } from '../components/modals.js';
8
8
  import { toast } from '../components/toast.js';
9
9
  import { getTypes, getStatuses, TYPE_ICONS, PRIORITY_LABELS } from '../constants.js';
@@ -12,12 +12,18 @@ import { loadItemsBadge } from './projects.js';
12
12
  import { renderLocalGraph, destroyLocalGraph } from './graph.js';
13
13
  import { EMPTY_FILTERS, filtersToQueryString, filtersFromSearchParams, hasActiveFilters } from '../filters.js';
14
14
  import type { Item } from '../types.js';
15
+
16
+ /** Store the fetched item list outside the async loader. */
17
+ function rememberItems(items: Item[]): void {
18
+ state.items = items;
19
+ }
15
20
  import type {
16
21
  CloseManyResponse,
17
22
  CommentsResponse,
18
23
  DepsResponse,
19
24
  FilesResponse,
20
25
  HistoryResponse,
26
+ DepRow,
21
27
  ItemResponse,
22
28
  LearningsResponse,
23
29
  ListResponse,
@@ -43,6 +49,58 @@ interface BulkClosePayload {
43
49
  reason: string;
44
50
  }
45
51
 
52
+ // ─── Shared item-action helpers ───────────────────────────────
53
+
54
+ /** Toasts a standardized error message extracted from a caught error value. */
55
+ function toastError(err: unknown): void {
56
+ toast(err instanceof Error ? err.message : String(err), 'error');
57
+ }
58
+
59
+ /** Performs a POST item action (start, pause, release) and refreshes the
60
+ * view, optionally reopening the detail modal and refreshing the badge. */
61
+ async function postItemAction(endpoint: string, itemId: string, successMsg: string, withBadge: boolean): Promise<void> {
62
+ try {
63
+ await api('POST', `/projects/${state.currentProject!.id}/pm/${endpoint}/${itemId}`, {});
64
+ toast(successMsg, 'success');
65
+ openItemDetail(itemId);
66
+ if (state.currentView === 'items') fetchAndRenderItems();
67
+ if (withBadge) loadItemsBadge();
68
+ } catch (err: unknown) { toastError(err); }
69
+ }
70
+
71
+ /** Refreshes the items view after a successful item action, optionally
72
+ * reopening the detail modal or hiding it first, and refreshing the badge. */
73
+ function refreshAfterItemAction(opts: { toastMsg: string; reopenDetail?: string; hideDetail?: boolean; withBadge?: boolean }): void {
74
+ toast(opts.toastMsg, 'success');
75
+ if (opts.hideDetail) hideModal('item-detail-modal');
76
+ if (opts.reopenDetail) openItemDetail(opts.reopenDetail);
77
+ if (state.currentView === 'items') fetchAndRenderItems();
78
+ if (opts.withBadge) loadItemsBadge();
79
+ }
80
+
81
+ /** Renders the "no items match" preview placeholder and disables the apply
82
+ * button. */
83
+ function renderNoMatchPreview(previewEl: HTMLElement, applyBtn: HTMLButtonElement | null): void {
84
+ previewEl.innerHTML = `<div style="color:var(--text-muted);font-size:13px;padding:10px 0">No items match the filter criteria.</div>`;
85
+ if (applyBtn) applyBtn.disabled = true;
86
+ }
87
+
88
+ /** Toasts the result of a bulk operation, noting failures when present. */
89
+ function toastBulkResult(action: string, count: string | number, failed: number): void {
90
+ if (failed > 0) {
91
+ toast(`${action} ${count} item${count !== 1 ? 's' : ''} (${failed} failed)`, 'info');
92
+ } else {
93
+ toast(`${action} ${count} item${count !== 1 ? 's' : ''}`, 'success');
94
+ }
95
+ }
96
+
97
+ /** Renders a preview list of matched items with their changes, capped at 8
98
+ * entries with an overflow note. */
99
+ function renderMatchedPreview(matched: ItemPlan[], displayCount: number): string {
100
+ return `${matched.slice(0, 8).map((it) => `<div style="color:var(--text-secondary);font-size:12px">· ${escHtml(it.id)}${it.changes?.length ? ` — ${escHtml(it.changes.map((c) => `${c.field}: ${String(c.before)} → ${String(c.after)}`).join(', '))}` : ''}</div>`).join('')}
101
+ ${displayCount > 8 ? `<div style="color:var(--text-muted);font-size:12px;margin-top:4px">… and ${displayCount - 8} more</div>` : ''}`;
102
+ }
103
+
46
104
  /**
47
105
  * Mirrors the current item filters into the page URL query string when the
48
106
  * items view is active, using history.replaceState so the filtered view is
@@ -71,18 +129,7 @@ export function loadFiltersFromUrl(): void {
71
129
  }
72
130
  }
73
131
 
74
- type RawDependency = {
75
- targetId?: string;
76
- id?: string;
77
- rel?: string;
78
- relationship?: string;
79
- kind?: string;
80
- type?: string;
81
- target?: string;
82
- targetTitle?: string;
83
- title?: string;
84
- [key: string]: unknown;
85
- };
132
+ type RawDependency = DepRow;
86
133
 
87
134
  const DEP_REL_OPTIONS = [
88
135
  { value: 'blocked_by', label: 'Blocked by / depends on' },
@@ -292,15 +339,13 @@ export async function previewBulkUpdate(): Promise<void> {
292
339
  const updateDesc = updateParts.map(p=>`<strong>${escHtml(p)}</strong>`).join(', ');
293
340
 
294
341
  if (count === 0 && matched.length === 0) {
295
- previewEl.innerHTML = `<div style="color:var(--text-muted);font-size:13px;padding:10px 0">No items match the filter criteria.</div>`;
296
- if (applyBtn) applyBtn.disabled = true;
342
+ renderNoMatchPreview(previewEl, applyBtn);
297
343
  } else {
298
344
  const displayCount = count || matched.length;
299
345
  previewEl.innerHTML = `
300
346
  <div style="background:rgba(99,102,241,0.08);border:1px solid rgba(99,102,241,0.25);border-radius:var(--radius);padding:10px 14px;font-size:13px">
301
347
  <div style="margin-bottom:8px">Will update <strong>${displayCount}</strong> item${displayCount!==1?'s':''}: ${updateDesc}</div>
302
- ${matched.slice(0,8).map((it)=>`<div style="color:var(--text-secondary);font-size:12px">· ${escHtml(it.id)}${it.changes?.length ? ` — ${escHtml(it.changes.map((c) => `${c.field}: ${String(c.before)} → ${String(c.after)}`).join(', '))}` : ''}</div>`).join('')}
303
- ${displayCount > 8 ? `<div style="color:var(--text-muted);font-size:12px;margin-top:4px">… and ${displayCount - 8} more</div>` : ''}
348
+ ${renderMatchedPreview(matched, displayCount)}
304
349
  </div>`;
305
350
  if (applyBtn) applyBtn.disabled = false;
306
351
  // Store payload for apply (without dryRun)
@@ -331,16 +376,12 @@ export async function applyBulkUpdate(): Promise<void> {
331
376
  const data = await api<UpdateManyResponse>('POST', `/projects/${pid}/pm/update-many`, payload);
332
377
  const updated = data.updated_count ?? 'some';
333
378
  const failed = data.failed_count ?? 0;
334
- if (failed > 0) {
335
- toast(`Updated ${updated} item${updated!==1?'s':''} (${failed} failed)`, 'info');
336
- } else {
337
- toast(`Updated ${updated} item${updated!==1?'s':''}`, 'success');
338
- }
379
+ toastBulkResult('Updated', updated, failed);
339
380
  hideModal('bulk-update-modal');
340
381
  if (state.currentView === 'items') fetchAndRenderItems();
341
382
  loadItemsBadge();
342
383
  } catch(err: unknown) {
343
- toast(err instanceof Error ? err.message : String(err), 'error');
384
+ toastError(err);
344
385
  if (applyBtn) { applyBtn.disabled = false; applyBtn.textContent = 'Apply Update'; }
345
386
  }
346
387
  }
@@ -452,15 +493,13 @@ export async function previewBulkClose(): Promise<void> {
452
493
  const applyBtn = document.getElementById('bc-apply-btn') as HTMLButtonElement | null;
453
494
  if (previewEl) {
454
495
  if (count === 0 && matched.length === 0) {
455
- previewEl.innerHTML = `<div style="color:var(--text-muted);font-size:13px;padding:10px 0">No items match the filter criteria.</div>`;
456
- if (applyBtn) applyBtn.disabled = true;
496
+ renderNoMatchPreview(previewEl, applyBtn);
457
497
  } else {
458
498
  const displayCount = count || matched.length;
459
499
  previewEl.innerHTML = `
460
500
  <div style="background:rgba(248,113,113,0.08);border:1px solid rgba(248,113,113,0.25);border-radius:var(--radius);padding:10px 14px;font-size:13px">
461
501
  <div style="margin-bottom:8px">Will <strong>${targetStatus}</strong> <strong>${displayCount}</strong> item${displayCount!==1?'s':''}. Reason: <em>${escHtml(reason)}</em></div>
462
- ${matched.slice(0,8).map((it)=>`<div style="color:var(--text-secondary);font-size:12px">· ${escHtml(it.id)}${it.changes?.length ? ` — ${escHtml(it.changes.map((c) => `${c.field}: ${String(c.before)} → ${String(c.after)}`).join(', '))}` : ''}</div>`).join('')}
463
- ${displayCount > 8 ? `<div style="color:var(--text-muted);font-size:12px;margin-top:4px">… and ${displayCount - 8} more</div>` : ''}
502
+ ${renderMatchedPreview(matched, displayCount)}
464
503
  </div>`;
465
504
  if (applyBtn) {
466
505
  applyBtn.disabled = false;
@@ -503,16 +542,12 @@ export async function applyBulkClose(): Promise<void> {
503
542
  const data = await api<CloseManyResponse>('POST', `/projects/${pid}/pm/close-many`, payload);
504
543
  const closed = data.closed_count ?? 'some';
505
544
  const failed = data.failed_count ?? 0;
506
- if (failed > 0) {
507
- toast(`Closed ${closed} item${closed!==1?'s':''} (${failed} failed)`, 'info');
508
- } else {
509
- toast(`Closed ${closed} item${closed!==1?'s':''}`, 'success');
510
- }
545
+ toastBulkResult('Closed', closed, failed);
511
546
  hideModal('bulk-close-modal');
512
547
  if (state.currentView === 'items') fetchAndRenderItems();
513
548
  loadItemsBadge();
514
549
  } catch(err: unknown) {
515
- toast(err instanceof Error ? err.message : String(err), 'error');
550
+ toastError(err);
516
551
  if (applyBtn) { applyBtn.disabled = false; applyBtn.textContent = 'Close Items'; }
517
552
  }
518
553
  }
@@ -561,7 +596,7 @@ export async function renderItemsView(): Promise<void> {
561
596
  </select>
562
597
  <select class="filter-select" id="filter-priority" onchange="window.__app.applyItemFilters()">
563
598
  <option value="">All Priorities</option>
564
- ${[0,1,2,3,4].map(p=>`<option value="${p}"${state.itemFilters.priority==String(p)?' selected':''}>P${p}: ${PRIORITY_LABELS[p]}</option>`).join('')}
599
+ ${[0,1,2,3,4].map(p=>`<option value="${p}"${state.itemFilters.priority===String(p)?' selected':''}>P${p}: ${PRIORITY_LABELS[p]}</option>`).join('')}
565
600
  </select>
566
601
  <input class="filter-select" id="filter-sprint" type="text" placeholder="Sprint…" value="${escHtml(state.itemFilters.sprint)}" oninput="window.__app.applyItemFilters()" style="width:100px">
567
602
  <input class="filter-select" id="filter-release" type="text" placeholder="Release…" value="${escHtml(state.itemFilters.release)}" oninput="window.__app.applyItemFilters()" style="width:100px">
@@ -604,7 +639,7 @@ export async function fetchAndRenderItems(): Promise<void> {
604
639
  if (tag) {
605
640
  items = items.filter((i) => (i.tags || []).some((t) => t.toLowerCase() === tag));
606
641
  }
607
- state.items = items;
642
+ rememberItems(items);
608
643
  const sub = document.getElementById('items-subtitle');
609
644
  if (sub) sub.textContent = `${state.items.length} item${state.items.length!==1?'s':''}`;
610
645
  renderItemsList();
@@ -884,7 +919,7 @@ export async function openItemDetail(itemId: string): Promise<void> {
884
919
  <div class="form-group">
885
920
  <label class="form-label">Priority</label>
886
921
  <select class="form-select" id="edit-priority">
887
- ${[0,1,2,3,4].map(p=>`<option value="${p}"${item.priority==p?' selected':''}>P${p}: ${PRIORITY_LABELS[p]}</option>`).join('')}
922
+ ${[0,1,2,3,4].map(p=>`<option value="${p}"${item.priority===p?' selected':''}>P${p}: ${PRIORITY_LABELS[p]}</option>`).join('')}
888
923
  </select>
889
924
  </div>
890
925
  </div>
@@ -1067,28 +1102,6 @@ export async function openItemDetail(itemId: string): Promise<void> {
1067
1102
  }
1068
1103
  }
1069
1104
 
1070
- /**
1071
- * Formats a timestamp as a human-readable relative age string (just now,
1072
- * Nm/Nh/Nd ago) for recent times, or a localized date for anything older than
1073
- * a week. Returns an empty string when the timestamp is missing.
1074
- */
1075
- function relTime(ts: string | undefined | null): string {
1076
- if (!ts) return '';
1077
- const d = new Date(ts);
1078
- const diff = Date.now() - d.getTime();
1079
- const s = Math.floor(diff/1000);
1080
- if (s < 60) return 'just now';
1081
- if (s < 3600) return `${Math.floor(s/60)}m ago`;
1082
- if (s < 86400) return `${Math.floor(s/3600)}h ago`;
1083
- if (s < 604800) return `${Math.floor(s/86400)}d ago`;
1084
- return d.toLocaleDateString();
1085
- }
1086
-
1087
- function fmtDate(ts: string | undefined | null): string {
1088
- if (!ts) return '';
1089
- return new Date(ts).toLocaleDateString('en-US', { year:'numeric', month:'short', day:'numeric' });
1090
- }
1091
-
1092
1105
  /**
1093
1106
  * Switches the item detail modal to the selected tab: toggles the active class
1094
1107
  * on the tabs, shows the target tab panel while hiding the others, tears down
@@ -1135,7 +1148,7 @@ export async function addComment(itemId: string): Promise<void> {
1135
1148
  toast('Comment added','success');
1136
1149
  el.value = '';
1137
1150
  openItemDetail(itemId);
1138
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1151
+ } catch(err: unknown) { toastError(err); }
1139
1152
  }
1140
1153
 
1141
1154
  /**
@@ -1151,7 +1164,7 @@ export async function addNote(itemId: string): Promise<void> {
1151
1164
  await api('POST',`/projects/${state.currentProject!.id}/pm/notes/${itemId}`,{text});
1152
1165
  toast('Note added','success');
1153
1166
  el.value = '';
1154
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1167
+ } catch(err: unknown) { toastError(err); }
1155
1168
  }
1156
1169
 
1157
1170
  /**
@@ -1168,7 +1181,7 @@ export async function appendItem(itemId: string): Promise<void> {
1168
1181
  await api('POST',`/projects/${state.currentProject!.id}/pm/append/${itemId}`,{text});
1169
1182
  toast('Appended','success');
1170
1183
  el.value = '';
1171
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1184
+ } catch(err: unknown) { toastError(err); }
1172
1185
  }
1173
1186
 
1174
1187
  /**
@@ -1217,11 +1230,8 @@ export async function updateItem(itemId: string): Promise<void> {
1217
1230
  if (acceptanceCriteria) payload.acceptanceCriteria = acceptanceCriteria;
1218
1231
  if (blockedReason) payload.blockedReason = blockedReason;
1219
1232
  await api('PATCH',`/projects/${state.currentProject!.id}/pm/update/${itemId}`,payload);
1220
- toast('Item updated','success');
1221
- openItemDetail(itemId);
1222
- if (state.currentView==='items') fetchAndRenderItems();
1223
- loadItemsBadge();
1224
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1233
+ refreshAfterItemAction({ toastMsg: 'Item updated', reopenDetail: itemId, withBadge: true });
1234
+ } catch(err: unknown) { toastError(err); }
1225
1235
  }
1226
1236
 
1227
1237
  /**
@@ -1241,11 +1251,8 @@ export async function closeItem(itemId: string, targetStatus: string): Promise<v
1241
1251
  } else {
1242
1252
  await api('POST',`/projects/${state.currentProject!.id}/pm/close/${itemId}`,{reason});
1243
1253
  }
1244
- toast(`Item ${targetStatus}`,'success');
1245
- hideModal('item-detail-modal');
1246
- if (state.currentView==='items') fetchAndRenderItems();
1247
- loadItemsBadge();
1248
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1254
+ refreshAfterItemAction({ toastMsg: `Item ${targetStatus}`, hideDetail: true, withBadge: true });
1255
+ } catch(err: unknown) { toastError(err); }
1249
1256
  }
1250
1257
 
1251
1258
  /**
@@ -1256,11 +1263,8 @@ export function confirmDeleteItem(itemId: string): void {
1256
1263
  confirmDialog('Delete Item?', 'This action cannot be undone. The item and all its data will be permanently removed.', async () => {
1257
1264
  try {
1258
1265
  await api('DELETE',`/projects/${state.currentProject!.id}/pm/delete/${itemId}`);
1259
- toast('Item deleted','success');
1260
- hideModal('item-detail-modal');
1261
- if (state.currentView==='items') fetchAndRenderItems();
1262
- loadItemsBadge();
1263
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1266
+ refreshAfterItemAction({ toastMsg: 'Item deleted', hideDetail: true, withBadge: true });
1267
+ } catch(err: unknown) { toastError(err); }
1264
1268
  }, true);
1265
1269
  }
1266
1270
 
@@ -1281,7 +1285,7 @@ export async function claimItem(itemId: string): Promise<void> {
1281
1285
  toast('Item claimed','success');
1282
1286
  openItemDetail(itemId);
1283
1287
  if (state.currentView==='items') fetchAndRenderItems();
1284
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); if (row) row.style.opacity = ''; }
1288
+ } catch(err: unknown) { toastError(err); if (row) row.style.opacity = ''; }
1285
1289
  }
1286
1290
 
1287
1291
  /**
@@ -1289,12 +1293,7 @@ export async function claimItem(itemId: string): Promise<void> {
1289
1293
  * reopens the detail and refreshes the items list.
1290
1294
  */
1291
1295
  export async function releaseItem(itemId: string): Promise<void> {
1292
- try {
1293
- await api('POST',`/projects/${state.currentProject!.id}/pm/release/${itemId}`,{});
1294
- toast('Item released','success');
1295
- openItemDetail(itemId);
1296
- if (state.currentView==='items') fetchAndRenderItems();
1297
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1296
+ await postItemAction('release', itemId, 'Item released', false);
1298
1297
  }
1299
1298
 
1300
1299
  /**
@@ -1302,13 +1301,7 @@ export async function releaseItem(itemId: string): Promise<void> {
1302
1301
  * then reopens the detail and refreshes the items list and project badge.
1303
1302
  */
1304
1303
  export async function startItem(itemId: string): Promise<void> {
1305
- try {
1306
- await api('POST',`/projects/${state.currentProject!.id}/pm/start-task/${itemId}`,{});
1307
- toast('Item started','success');
1308
- openItemDetail(itemId);
1309
- if (state.currentView==='items') fetchAndRenderItems();
1310
- loadItemsBadge();
1311
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1304
+ await postItemAction('start-task', itemId, 'Item started', true);
1312
1305
  }
1313
1306
 
1314
1307
  /**
@@ -1316,13 +1309,7 @@ export async function startItem(itemId: string): Promise<void> {
1316
1309
  * detail and refreshes the items list and project badge.
1317
1310
  */
1318
1311
  export async function pauseItem(itemId: string): Promise<void> {
1319
- try {
1320
- await api('POST',`/projects/${state.currentProject!.id}/pm/pause-task/${itemId}`,{});
1321
- toast('Item paused','success');
1322
- openItemDetail(itemId);
1323
- if (state.currentView==='items') fetchAndRenderItems();
1324
- loadItemsBadge();
1325
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1312
+ await postItemAction('pause-task', itemId, 'Item paused', true);
1326
1313
  }
1327
1314
 
1328
1315
  // ═══════════════════════════════════════════════════════════════
@@ -1348,7 +1335,7 @@ export async function addDep(itemId: string): Promise<void> {
1348
1335
  await api('POST',`/projects/${state.currentProject!.id}/pm/deps/${itemId}`,{targetId,rel});
1349
1336
  toast('Dependency added','success');
1350
1337
  openItemDetail(itemId);
1351
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1338
+ } catch(err: unknown) { toastError(err); }
1352
1339
  }
1353
1340
 
1354
1341
  /**
@@ -1367,7 +1354,7 @@ export async function removeDep(itemId: string, targetId: string, relation: stri
1367
1354
  await api('DELETE', `/projects/${state.currentProject!.id}/pm/deps/${itemId}`, { targetId, rel });
1368
1355
  toast('Dependency removed','success');
1369
1356
  openItemDetail(itemId);
1370
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1357
+ } catch(err: unknown) { toastError(err); }
1371
1358
  },
1372
1359
  true
1373
1360
  );
@@ -1386,7 +1373,7 @@ export async function addLearning(itemId: string): Promise<void> {
1386
1373
  await api('POST',`/projects/${state.currentProject!.id}/pm/learnings/${itemId}`,{text});
1387
1374
  toast('Learning recorded','success');
1388
1375
  openItemDetail(itemId);
1389
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1376
+ } catch(err: unknown) { toastError(err); }
1390
1377
  }
1391
1378
 
1392
1379
  /**
@@ -1404,7 +1391,7 @@ export async function addTest(itemId: string): Promise<void> {
1404
1391
  await api('POST',`/projects/${state.currentProject!.id}/pm/tests/${itemId}`,{command,description});
1405
1392
  toast('Test added','success');
1406
1393
  openItemDetail(itemId);
1407
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1394
+ } catch(err: unknown) { toastError(err); }
1408
1395
  }
1409
1396
 
1410
1397
  /**
@@ -1419,7 +1406,7 @@ export async function addFileLink(itemId: string): Promise<void> {
1419
1406
  await api('POST',`/projects/${state.currentProject!.id}/pm/files/${itemId}`,{path:filePath});
1420
1407
  toast('File linked','success');
1421
1408
  openItemDetail(itemId);
1422
- } catch(err: unknown) { toast(err instanceof Error ? err.message : String(err),'error'); }
1409
+ } catch(err: unknown) { toastError(err); }
1423
1410
  }
1424
1411
 
1425
1412
  // ═══════════════════════════════════════════════════════════════
@@ -1437,27 +1424,22 @@ export function useItemAsTemplate(item: Record<string, unknown>): void {
1437
1424
  showView('create');
1438
1425
  // Give the create view time to render, then fill fields
1439
1426
  setTimeout(() => {
1440
- const setVal = (id: string, val: string | undefined) => {
1441
- if (!val) return;
1442
- const el = document.getElementById(id) as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | null;
1443
- if (el) el.value = val;
1444
- };
1445
1427
  // Pre-fill create form from item fields (title gets "Copy of …" prefix)
1446
1428
  const origTitle = String(item['title'] || '');
1447
- setVal('ci-title', origTitle ? `Copy of ${origTitle}` : '');
1448
- setVal('ci-type', String(item['type'] || ''));
1449
- setVal('ci-priority', String(item['priority'] || ''));
1429
+ setFormValue('ci-title', origTitle ? `Copy of ${origTitle}` : '');
1430
+ setFormValue('ci-type', String(item['type'] || ''));
1431
+ setFormValue('ci-priority', String(item['priority'] || ''));
1450
1432
  const tags = Array.isArray(item['tags']) ? (item['tags'] as string[]).join(', ') : String(item['tags'] || '');
1451
- setVal('ci-tags', tags);
1452
- setVal('ci-desc', String(item['description'] || ''));
1453
- setVal('ci-sprint', String(item['sprint'] || ''));
1454
- setVal('ci-release', String(item['release'] || ''));
1455
- setVal('ci-assignee', String(item['assignee'] || ''));
1433
+ setFormValue('ci-tags', tags);
1434
+ setFormValue('ci-desc', String(item['description'] || ''));
1435
+ setFormValue('ci-sprint', String(item['sprint'] || ''));
1436
+ setFormValue('ci-release', String(item['release'] || ''));
1437
+ setFormValue('ci-assignee', String(item['assignee'] || ''));
1456
1438
  if (item['acceptance_criteria'] || item['acceptanceCriteria']) {
1457
- setVal('ci-acceptance-criteria', String(item['acceptance_criteria'] || item['acceptanceCriteria'] || ''));
1439
+ setFormValue('ci-acceptance-criteria', String(item['acceptance_criteria'] || item['acceptanceCriteria'] || ''));
1458
1440
  }
1459
1441
  if (item['body']) {
1460
- setVal('ci-body', String(item['body']));
1442
+ setFormValue('ci-body', String(item['body']));
1461
1443
  }
1462
1444
  document.getElementById('ci-title')?.focus();
1463
1445
  // Select all title text so user can immediately replace or refine
@@ -3,7 +3,7 @@
3
3
  // ═══════════════════════════════════════════════════════════════
4
4
  import { state } from '../state.js';
5
5
  import { api } from '../api.js';
6
- import { escHtml } from '../utils.js';
6
+ import { escHtml, issueRow } from '../utils.js';
7
7
  import { toast } from '../components/toast.js';
8
8
  /** Renders a dry-run preview of lifecycle metadata normalization for the current project, listing each suggested change with an item link and an apply button that only advises using the CLI. */
9
9
  export async function renderNormalizeView() {
@@ -35,14 +35,7 @@ export async function renderNormalizeView() {
35
35
  <div class="card">
36
36
  <div class="card-header"><div class="card-title">Suggested Changes (${items.length})</div></div>
37
37
  <div class="card-body">
38
- ${items.map((i) => `
39
- <div style="display:flex;gap:8px;align-items:flex-start;padding:8px 0;border-bottom:1px solid var(--border)">
40
- <span style="color:var(--priority-3);flex-shrink:0">⚡</span>
41
- <div style="flex:1">
42
- <div style="font-size:13px">${escHtml(i.message || i.description || JSON.stringify(i))}</div>
43
- ${i.id ? `<div style="font-size:11px;color:var(--text-muted);margin-top:2px"><a href="#" onclick="window.__app.openItemDetail('${escHtml(i.id)}');return false" style="color:var(--accent)">${escHtml(i.id)}</a></div>` : ''}
44
- </div>
45
- </div>`).join('')}
38
+ ${items.map((i) => issueRow('⚡', 'var(--priority-3)', i.message || i.description || JSON.stringify(i), i.id)).join('')}
46
39
  </div>
47
40
  </div>
48
41
  <div style="margin-top:12px;display:flex;gap:8px">
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.js","sourceRoot":"","sources":["normalize.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,iBAAiB;AACjB,kEAAkE;AAClE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAG/C,kMAAkM;AAClM,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE;QAAE,OAAO;IAChB,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QAAC,EAAE,CAAC,SAAS,GAAG,wFAAwF,CAAC;QAAC,OAAO;IAAC,CAAC;IAC/I,EAAE,CAAC,SAAS,GAAG;;oHAEmG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC;;;2GAG3C,CAAC;IAC1G,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAoB,MAAM,EAAE,aAAa,KAAK,CAAC,cAAc,CAAC,EAAE,eAAe,CAAC,CAAC;QACvG,MAAM,IAAI,GAAkB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC;QACpE,MAAM,KAAK,GAAsB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;QAClE,MAAM,GAAG,GAAG,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,SAAS,GAAG,mKAAmK,CAAC;QACtL,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,GAAG,CAAC,SAAS,GAAG;;gFAE0D,KAAK,CAAC,MAAM;;cAE9E,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;;;;gDAIiB,OAAO,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;oBACpF,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,wHAAwH,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,gDAAgD,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE;;qBAEzN,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;;;;;eAMhB,CAAC;QACZ,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,SAAS,GAAG,yHAAyH,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC;QACtM,CAAC;IACH,CAAC;IAAC,OAAM,GAAY,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,IAAI,GAAG;YAAE,GAAG,CAAC,SAAS,GAAG,iEAAiE,OAAO,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC;IACpK,CAAC;AACH,CAAC;AAED,wIAAwI;AACxI,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC,KAAK,CAAC,cAAc;QAAE,OAAO;IAClC,KAAK,CAAC,wEAAwE,EAAE,MAAM,CAAC,CAAC;AAC1F,CAAC"}
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["normalize.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,iBAAiB;AACjB,kEAAkE;AAClE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAG/C,kMAAkM;AAClM,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;IACxD,IAAI,CAAC,EAAE;QAAE,OAAO;IAChB,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;QAAC,EAAE,CAAC,SAAS,GAAG,wFAAwF,CAAC;QAAC,OAAO;IAAC,CAAC;IAC/I,EAAE,CAAC,SAAS,GAAG;;oHAEmG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC;;;2GAG3C,CAAC;IAC1G,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAoB,MAAM,EAAE,aAAa,KAAK,CAAC,cAAc,CAAC,EAAE,eAAe,CAAC,CAAC;QACvG,MAAM,IAAI,GAAkB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC;QACpE,MAAM,KAAK,GAAsB,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;QAClE,MAAM,GAAG,GAAG,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,SAAS,GAAG,mKAAmK,CAAC;QACtL,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpD,GAAG,CAAC,SAAS,GAAG;;gFAE0D,KAAK,CAAC,MAAM;;cAE9E,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,mBAAmB,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;;;;;eAMnH,CAAC;QACZ,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,SAAS,GAAG,yHAAyH,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC;QACtM,CAAC;IACH,CAAC;IAAC,OAAM,GAAY,EAAE,CAAC;QACrB,MAAM,GAAG,GAAG,QAAQ,CAAC,cAAc,CAAC,mBAAmB,CAAC,CAAC;QACzD,IAAI,GAAG;YAAE,GAAG,CAAC,SAAS,GAAG,iEAAiE,OAAO,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC;IACpK,CAAC;AACH,CAAC;AAED,wIAAwI;AACxI,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC,KAAK,CAAC,cAAc;QAAE,OAAO;IAClC,KAAK,CAAC,wEAAwE,EAAE,MAAM,CAAC,CAAC;AAC1F,CAAC"}
@@ -3,7 +3,7 @@
3
3
  // ═══════════════════════════════════════════════════════════════
4
4
  import { state } from '../state.js';
5
5
  import { api } from '../api.js';
6
- import { escHtml } from '../utils.js';
6
+ import { escHtml, issueRow } from '../utils.js';
7
7
  import { toast } from '../components/toast.js';
8
8
  import type { NormalizeChange, NormalizePlan, NormalizeResponse } from '../api-types.js';
9
9
 
@@ -31,14 +31,7 @@ export async function renderNormalizeView(): Promise<void> {
31
31
  <div class="card">
32
32
  <div class="card-header"><div class="card-title">Suggested Changes (${items.length})</div></div>
33
33
  <div class="card-body">
34
- ${items.map((i) => `
35
- <div style="display:flex;gap:8px;align-items:flex-start;padding:8px 0;border-bottom:1px solid var(--border)">
36
- <span style="color:var(--priority-3);flex-shrink:0">⚡</span>
37
- <div style="flex:1">
38
- <div style="font-size:13px">${escHtml(i.message || i.description || JSON.stringify(i))}</div>
39
- ${i.id ? `<div style="font-size:11px;color:var(--text-muted);margin-top:2px"><a href="#" onclick="window.__app.openItemDetail('${escHtml(i.id)}');return false" style="color:var(--accent)">${escHtml(i.id)}</a></div>` : ''}
40
- </div>
41
- </div>`).join('')}
34
+ ${items.map((i) => issueRow('⚡', 'var(--priority-3)', i.message || i.description || JSON.stringify(i), i.id)).join('')}
42
35
  </div>
43
36
  </div>
44
37
  <div style="margin-top:12px;display:flex;gap:8px">
@@ -210,6 +210,11 @@ function wirePackageActions(root) {
210
210
  void handlePackageAction(name, action, btn);
211
211
  });
212
212
  }
213
+ /** Restore a package-action button outside the async handler. */
214
+ function restorePackageButton(button, label) {
215
+ button.disabled = false;
216
+ button.textContent = label;
217
+ }
213
218
  /**
214
219
  * Performs a package action against the extensions route for the current
215
220
  * project. Disables and marks the clicked button while in flight, confirms
@@ -236,8 +241,7 @@ async function handlePackageAction(name, action, btn) {
236
241
  try {
237
242
  if (action === 'uninstall') {
238
243
  if (!window.confirm(t('packages.confirmUninstall', { name }))) {
239
- btn.disabled = false;
240
- btn.textContent = original;
244
+ restorePackageButton(btn, original);
241
245
  return;
242
246
  }
243
247
  }
@@ -250,8 +254,7 @@ async function handlePackageAction(name, action, btn) {
250
254
  catch (err) {
251
255
  const msg = err instanceof Error ? err.message : String(err);
252
256
  toast(t('packages.actionFailed', { action: actionLabel[action] ?? action, error: msg }), 'error');
253
- btn.disabled = false;
254
- btn.textContent = original;
257
+ restorePackageButton(btn, original);
255
258
  }
256
259
  }
257
260
  // Wire the delegated action handler once the view container exists.
@@ -1 +1 @@
1
- {"version":3,"file":"packages.js","sourceRoot":"","sources":["packages.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"packages.js","sourceRoot":"","sources":["packages.ts"],"names":[],"mappings":"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"}
@@ -246,6 +246,12 @@ function wirePackageActions(root: HTMLElement): void {
246
246
  });
247
247
  }
248
248
 
249
+ /** Restore a package-action button outside the async handler. */
250
+ function restorePackageButton(button: HTMLButtonElement, label: string): void {
251
+ button.disabled = false;
252
+ button.textContent = label;
253
+ }
254
+
249
255
  /**
250
256
  * Performs a package action against the extensions route for the current
251
257
  * project. Disables and marks the clicked button while in flight, confirms
@@ -271,8 +277,7 @@ async function handlePackageAction(name: string, action: string, btn: HTMLButton
271
277
  try {
272
278
  if (action === 'uninstall') {
273
279
  if (!window.confirm(t('packages.confirmUninstall', { name }))) {
274
- btn.disabled = false;
275
- btn.textContent = original;
280
+ restorePackageButton(btn, original);
276
281
  return;
277
282
  }
278
283
  }
@@ -284,8 +289,7 @@ async function handlePackageAction(name: string, action: string, btn: HTMLButton
284
289
  } catch (err: unknown) {
285
290
  const msg = err instanceof Error ? err.message : String(err);
286
291
  toast(t('packages.actionFailed', { action: actionLabel[action] ?? action, error: msg }), 'error');
287
- btn.disabled = false;
288
- btn.textContent = original;
292
+ restorePackageButton(btn, original);
289
293
  }
290
294
  }
291
295