@sascha384/tic 4.1.0 → 4.3.0

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 (89) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/app.js +4 -2
  3. package/dist/app.js.map +1 -1
  4. package/dist/auth/ado.js +76 -28
  5. package/dist/auth/ado.js.map +1 -1
  6. package/dist/auth/github.js +57 -24
  7. package/dist/auth/github.js.map +1 -1
  8. package/dist/auth/gitlab.js +54 -23
  9. package/dist/auth/gitlab.js.map +1 -1
  10. package/dist/auth/jira.d.ts +8 -0
  11. package/dist/auth/jira.js +24 -0
  12. package/dist/auth/jira.js.map +1 -0
  13. package/dist/backends/ado/api.d.ts +1 -0
  14. package/dist/backends/ado/api.js +66 -16
  15. package/dist/backends/ado/api.js.map +1 -1
  16. package/dist/backends/ado/index.js +4 -1
  17. package/dist/backends/ado/index.js.map +1 -1
  18. package/dist/backends/factory.js +1 -1
  19. package/dist/backends/factory.js.map +1 -1
  20. package/dist/backends/files/index.js +1 -0
  21. package/dist/backends/files/index.js.map +1 -1
  22. package/dist/backends/github/api.js +61 -17
  23. package/dist/backends/github/api.js.map +1 -1
  24. package/dist/backends/github/index.js +1 -0
  25. package/dist/backends/github/index.js.map +1 -1
  26. package/dist/backends/github/mappers.d.ts +1 -1
  27. package/dist/backends/github/mappers.js +1 -1
  28. package/dist/backends/github/mappers.js.map +1 -1
  29. package/dist/backends/gitlab/api.js +22 -8
  30. package/dist/backends/gitlab/api.js.map +1 -1
  31. package/dist/backends/gitlab/index.js +1 -0
  32. package/dist/backends/gitlab/index.js.map +1 -1
  33. package/dist/backends/jira/api.d.ts +9 -0
  34. package/dist/backends/jira/api.js +89 -0
  35. package/dist/backends/jira/api.js.map +1 -0
  36. package/dist/backends/jira/index.d.ts +10 -2
  37. package/dist/backends/jira/index.js +140 -161
  38. package/dist/backends/jira/index.js.map +1 -1
  39. package/dist/backends/jira/mappers.d.ts +8 -2
  40. package/dist/backends/jira/mappers.js +20 -5
  41. package/dist/backends/jira/mappers.js.map +1 -1
  42. package/dist/backends/shared/api-client.d.ts +1 -0
  43. package/dist/backends/shared/api-client.js +18 -3
  44. package/dist/backends/shared/api-client.js.map +1 -1
  45. package/dist/backends/types.d.ts +1 -0
  46. package/dist/backends/types.js.map +1 -1
  47. package/dist/cli/commands/auth.js +34 -2
  48. package/dist/cli/commands/auth.js.map +1 -1
  49. package/dist/cli/commands/item.js +2 -2
  50. package/dist/cli/commands/item.js.map +1 -1
  51. package/dist/components/AuthPrompt.js +36 -4
  52. package/dist/components/AuthPrompt.js.map +1 -1
  53. package/dist/components/ErrorBoundary.d.ts +14 -0
  54. package/dist/components/ErrorBoundary.js +30 -0
  55. package/dist/components/ErrorBoundary.js.map +1 -0
  56. package/dist/components/Settings.js +82 -17
  57. package/dist/components/Settings.js.map +1 -1
  58. package/dist/components/StatusScreen.js +3 -1
  59. package/dist/components/StatusScreen.js.map +1 -1
  60. package/dist/components/WorkItemForm.js +57 -14
  61. package/dist/components/WorkItemForm.js.map +1 -1
  62. package/dist/components/WorkItemList.js +141 -35
  63. package/dist/components/WorkItemList.js.map +1 -1
  64. package/dist/components/getMarkedDistribution.d.ts +6 -0
  65. package/dist/components/getMarkedDistribution.js +17 -0
  66. package/dist/components/getMarkedDistribution.js.map +1 -0
  67. package/dist/editor.js +0 -1
  68. package/dist/editor.js.map +1 -1
  69. package/dist/hooks/useFormValidation.d.ts +20 -0
  70. package/dist/hooks/useFormValidation.js +146 -0
  71. package/dist/hooks/useFormValidation.js.map +1 -0
  72. package/dist/index.js +2 -1
  73. package/dist/index.js.map +1 -1
  74. package/dist/storage/index.js +15 -12
  75. package/dist/storage/index.js.map +1 -1
  76. package/dist/stores/backendDataStore.d.ts +2 -1
  77. package/dist/stores/backendDataStore.js +78 -6
  78. package/dist/stores/backendDataStore.js.map +1 -1
  79. package/dist/stores/recentCommandsStore.js +3 -1
  80. package/dist/stores/recentCommandsStore.js.map +1 -1
  81. package/dist/sync/SyncManager.d.ts +1 -1
  82. package/dist/sync/SyncManager.js +51 -10
  83. package/dist/sync/SyncManager.js.map +1 -1
  84. package/dist/update-checker.js +5 -3
  85. package/dist/update-checker.js.map +1 -1
  86. package/package.json +1 -1
  87. package/dist/backends/jira/acli.d.ts +0 -6
  88. package/dist/backends/jira/acli.js +0 -35
  89. package/dist/backends/jira/acli.js.map +0 -1
@@ -7,6 +7,7 @@ import { isGitRepo } from '../git.js';
7
7
  import { beginImplementation } from '../implement.js';
8
8
  import { configStore, useConfigStore } from '../stores/configStore.js';
9
9
  import { uiStore, useUIStore, getOverlayTargetIds } from '../stores/uiStore.js';
10
+ import { getMarkedDistribution } from './getMarkedDistribution.js';
10
11
  import { TableLayout } from './TableLayout.js';
11
12
  import { useTerminalSize } from '../hooks/useTerminalSize.js';
12
13
  import { useScrollViewport } from '../hooks/useScrollViewport.js';
@@ -113,7 +114,10 @@ export function WorkItemList() {
113
114
  // Marked count for header display
114
115
  const markedCount = markedIds.size;
115
116
  const refreshData = useCallback(() => {
116
- void backendDataStore.getState().refresh();
117
+ void backendDataStore
118
+ .getState()
119
+ .refresh()
120
+ .catch(() => { });
117
121
  }, []);
118
122
  useEffect(() => {
119
123
  if (!toast)
@@ -128,9 +132,25 @@ export function WorkItemList() {
128
132
  return () => clearTimeout(timer);
129
133
  }, [warning, clearWarning]);
130
134
  useEffect(() => {
131
- if (capabilities.templates && backend) {
132
- void backend.listTemplates().then(setTemplates);
133
- }
135
+ if (!capabilities.templates || !backend)
136
+ return;
137
+ let cancelled = false;
138
+ void backend
139
+ .listTemplates()
140
+ .then((t) => {
141
+ if (!cancelled)
142
+ setTemplates(t);
143
+ })
144
+ .catch((err) => {
145
+ if (cancelled)
146
+ return;
147
+ uiStore
148
+ .getState()
149
+ .setToast(err instanceof Error ? err.message : 'Failed to load templates');
150
+ });
151
+ return () => {
152
+ cancelled = true;
153
+ };
134
154
  }, [backend, capabilities.templates]);
135
155
  // Load default view on startup
136
156
  const defaultViewLoadedRef = useRef(false);
@@ -156,7 +176,11 @@ export function WorkItemList() {
156
176
  itemId,
157
177
  timestamp: new Date().toISOString(),
158
178
  });
159
- syncManager?.pushPending().catch(() => { });
179
+ syncManager?.pushPending().catch((err) => {
180
+ uiStore
181
+ .getState()
182
+ .setToast(err instanceof Error ? err.message : 'Sync failed');
183
+ });
160
184
  }
161
185
  };
162
186
  const pushUpdateUndo = (targetIds, label) => {
@@ -245,9 +269,16 @@ export function WorkItemList() {
245
269
  if (activeOverlay?.type !== 'command-bar' || !backend)
246
270
  return;
247
271
  let cancelled = false;
248
- void backend.listWorkItems().then((items) => {
272
+ void backend
273
+ .listWorkItems()
274
+ .then((items) => {
249
275
  if (!cancelled)
250
276
  setAllSearchItems(items);
277
+ })
278
+ .catch((err) => {
279
+ uiStore
280
+ .getState()
281
+ .setToast(err instanceof Error ? err.message : 'Failed to load items');
251
282
  });
252
283
  return () => {
253
284
  cancelled = true;
@@ -282,6 +313,7 @@ export function WorkItemList() {
282
313
  chromeLines,
283
314
  linesPerItem: 1,
284
315
  });
316
+ const markedDistribution = useMemo(() => getMarkedDistribution(markedIds, treeItems.map((t) => t.item), viewport.start, viewport.end), [markedIds, treeItems, viewport.start, viewport.end]);
285
317
  // Block 1.5: Description scroll handler — active when full description is shown
286
318
  useInput((_input, key) => {
287
319
  if (_input === ' ' || key.escape) {
@@ -456,14 +488,21 @@ export function WorkItemList() {
456
488
  refreshData();
457
489
  setToast(`Undid ${entry.label}`);
458
490
  }
459
- })();
491
+ })().catch((err) => {
492
+ uiStore
493
+ .getState()
494
+ .setToast(err instanceof Error ? err.message : 'Undo failed');
495
+ });
460
496
  }
461
497
  if (input === 'o' && treeItems.length > 0 && backend) {
462
498
  void (async () => {
463
499
  const itemId = treeItems[cursor].item.id;
464
500
  await backend.openItem(itemId);
465
- void backendDataStore.getState().reloadItem(itemId);
466
- })();
501
+ void backendDataStore
502
+ .getState()
503
+ .reloadItem(itemId)
504
+ .catch(() => { });
505
+ })().catch(() => { });
467
506
  }
468
507
  if (input === 'b' && gitAvailable && treeItems.length > 0) {
469
508
  const item = treeItems[cursor].item;
@@ -485,7 +524,10 @@ export function WorkItemList() {
485
524
  process.stdin.setRawMode?.(true);
486
525
  setWarning(e instanceof Error ? e.message : 'Failed to start implementation');
487
526
  }
488
- void backendDataStore.getState().reloadItem(item.id);
527
+ void backendDataStore
528
+ .getState()
529
+ .reloadItem(item.id)
530
+ .catch(() => { });
489
531
  }
490
532
  if (input === 'S') {
491
533
  navigate('status');
@@ -512,7 +554,8 @@ export function WorkItemList() {
512
554
  if (input === 'v') {
513
555
  void configStore
514
556
  .getState()
515
- .update({ showDetailPanel: !showDetailPanel });
557
+ .update({ showDetailPanel: !showDetailPanel })
558
+ .catch(() => { });
516
559
  }
517
560
  if (input === ' ' && showDetailPanel && hasDescription) {
518
561
  setShowFullDescription(true);
@@ -532,8 +575,13 @@ export function WorkItemList() {
532
575
  clearWarning();
533
576
  }
534
577
  if (input === 'r' && syncManager) {
535
- void syncManager.sync().then(() => {
578
+ void syncManager
579
+ .sync()
580
+ .then(() => {
536
581
  refreshData();
582
+ })
583
+ .catch(() => {
584
+ // Errors recorded in syncStatus by SyncManager
537
585
  });
538
586
  }
539
587
  if (input === 'm' && treeItems.length > 0) {
@@ -820,8 +868,11 @@ export function WorkItemList() {
820
868
  void (async () => {
821
869
  const itemId = treeItems[cursor].item.id;
822
870
  await backend.openItem(itemId);
823
- void backendDataStore.getState().reloadItem(itemId);
824
- })();
871
+ void backendDataStore
872
+ .getState()
873
+ .reloadItem(itemId)
874
+ .catch(() => { });
875
+ })().catch(() => { });
825
876
  }
826
877
  break;
827
878
  case 'branch':
@@ -844,12 +895,20 @@ export function WorkItemList() {
844
895
  process.stdin.setRawMode?.(true);
845
896
  setWarning(e instanceof Error ? e.message : 'Failed to start implementation');
846
897
  }
847
- void backendDataStore.getState().reloadItem(item.id);
898
+ void backendDataStore
899
+ .getState()
900
+ .reloadItem(item.id)
901
+ .catch(() => { });
848
902
  }
849
903
  break;
850
904
  case 'sync':
851
905
  if (syncManager) {
852
- void syncManager.sync().then(() => refreshData());
906
+ void syncManager
907
+ .sync()
908
+ .then(() => refreshData())
909
+ .catch(() => {
910
+ // Errors recorded in syncStatus by SyncManager
911
+ });
853
912
  }
854
913
  break;
855
914
  case 'iterations':
@@ -979,7 +1038,7 @@ export function WorkItemList() {
979
1038
  const positionText = treeItems.length > viewport.maxVisible
980
1039
  ? `${cursor + 1}/${treeItems.length}`
981
1040
  : '';
982
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { wrap: "truncate", children: [_jsxs(Text, { bold: true, color: "cyan", children: [typeLabel, " \u2014 ", iteration] }), _jsx(Text, { dimColor: true, children: ` (${filterCount > 0 ? `${items.length}/${unfilteredCount}` : items.length} item${unfilteredCount === 1 ? '' : 's'})` }), markedCount > 0 && (_jsx(Text, { color: "magenta", children: ` ● ${markedCount} marked` })), filterCount > 0 && (_jsx(Text, { color: "yellow", children: ` [${filterCount} filter${filterCount === 1 ? '' : 's'}${activeViewName ? `: ${activeViewName}` : ''}]` }))] }) }), _jsx(TableLayout, { treeItems: visibleTreeItems, cursor: viewport.visibleCursor, capabilities: capabilities, collapsedIds: collapsedIds, markedIds: markedIds, terminalWidth: terminalWidth, sortStack: sortStack }), treeItems.length === 0 && !loading && initError && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "red", children: "Failed to connect to backend:" }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "red", children: initError }) }), _jsx(Text, { dimColor: true, children: "Press , for settings or q to quit." })] })), treeItems.length === 0 && !loading && !initError && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["No ", activeType ?? 'item', "s in this iteration. Press c to create, / to search all."] }) })), loading && treeItems.length === 0 && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Loading..." }) })), showDetailPanel && treeItems.length > 0 && treeItems[cursor] && (_jsx(Box, { marginTop: 1, children: _jsx(DetailPanel, { item: treeItems[cursor].item, terminalWidth: terminalWidth, showFullDescription: showFullDescription, descriptionScrollOffset: descriptionScrollOffset, maxDescriptionHeight: maxDescriptionHeight }) })), _jsx(Box, { marginTop: 1, children: showFullDescription ? (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "\u2191\u2193 scroll space/esc close" }), positionText && _jsxs(Text, { dimColor: true, children: [" ", positionText] })] })) : activeOverlay?.type === 'command-bar' ? (_jsx(OverlayPanel, { title: "Commands", items: commandBarItems, placeholder: "Type to search...", externalFilter: true, onQueryChange: setCommandBarQuery, onSelect: (item) => {
1041
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { wrap: "truncate", children: [_jsxs(Text, { bold: true, color: "cyan", children: [typeLabel, " \u2014 ", iteration] }), _jsx(Text, { dimColor: true, children: ` (${filterCount > 0 ? `${items.length}/${unfilteredCount}` : items.length} item${unfilteredCount === 1 ? '' : 's'})` }), markedCount > 0 && (_jsxs(Text, { color: "magenta", children: [` ● ${markedCount}`, markedDistribution.above > 0 && ` ↑${markedDistribution.above}`, markedDistribution.below > 0 && ` ↓${markedDistribution.below}`] })), filterCount > 0 && (_jsx(Text, { color: "yellow", children: ` [${filterCount} filter${filterCount === 1 ? '' : 's'}${activeViewName ? `: ${activeViewName}` : ''}]` }))] }) }), _jsx(TableLayout, { treeItems: visibleTreeItems, cursor: viewport.visibleCursor, capabilities: capabilities, collapsedIds: collapsedIds, markedIds: markedIds, terminalWidth: terminalWidth, sortStack: sortStack }), treeItems.length === 0 && !loading && initError && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "red", children: "Failed to connect to backend:" }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: "red", children: initError }) }), _jsx(Text, { dimColor: true, children: "Press , for settings or q to quit." })] })), treeItems.length === 0 && !loading && !initError && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["No ", activeType ?? 'item', "s in this iteration. Press c to create, / to search all."] }) })), loading && treeItems.length === 0 && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Loading..." }) })), showDetailPanel && treeItems.length > 0 && treeItems[cursor] && (_jsx(Box, { marginTop: 1, children: _jsx(DetailPanel, { item: treeItems[cursor].item, terminalWidth: terminalWidth, showFullDescription: showFullDescription, descriptionScrollOffset: descriptionScrollOffset, maxDescriptionHeight: maxDescriptionHeight }) })), _jsx(Box, { marginTop: 1, children: showFullDescription ? (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: "\u2191\u2193 scroll space/esc close" }), positionText && _jsxs(Text, { dimColor: true, children: [" ", positionText] })] })) : activeOverlay?.type === 'command-bar' ? (_jsx(OverlayPanel, { title: "Commands", items: commandBarItems, placeholder: "Type to search...", externalFilter: true, onQueryChange: setCommandBarQuery, onSelect: (item) => {
983
1042
  if (item.kind === 'issue') {
984
1043
  const workItem = allSearchItems.find((i) => i.id === item.value);
985
1044
  if (workItem)
@@ -1079,7 +1138,11 @@ export function WorkItemList() {
1079
1138
  setToast(targetIds.length === 1
1080
1139
  ? 'Status updated — press u to undo'
1081
1140
  : `${targetIds.length} items updated — press u to undo`);
1082
- })();
1141
+ })().catch((err) => {
1142
+ uiStore
1143
+ .getState()
1144
+ .setToast(err instanceof Error ? err.message : 'Update failed');
1145
+ });
1083
1146
  }, onCancel: () => closeOverlay() })) : activeOverlay?.type === 'type-picker' ? (_jsx(OverlayPanel, { title: "Set Type", items: types.map((t) => ({
1084
1147
  id: t,
1085
1148
  label: t.charAt(0).toUpperCase() + t.slice(1),
@@ -1103,7 +1166,11 @@ export function WorkItemList() {
1103
1166
  setToast(targetIds.length === 1
1104
1167
  ? 'Type updated — press u to undo'
1105
1168
  : `${targetIds.length} items updated — press u to undo`);
1106
- })();
1169
+ })().catch((err) => {
1170
+ uiStore
1171
+ .getState()
1172
+ .setToast(err instanceof Error ? err.message : 'Update failed');
1173
+ });
1107
1174
  }, onCancel: () => closeOverlay() })) : activeOverlay?.type === 'priority-picker' ? (_jsx(OverlayPanel, { title: "Set Priority", items: [
1108
1175
  { id: 'critical', label: 'Critical', value: 'critical' },
1109
1176
  { id: 'high', label: 'High', value: 'high' },
@@ -1127,7 +1194,11 @@ export function WorkItemList() {
1127
1194
  setToast(targetIds.length === 1
1128
1195
  ? 'Priority updated — press u to undo'
1129
1196
  : `${targetIds.length} items updated — press u to undo`);
1130
- })();
1197
+ })().catch((err) => {
1198
+ uiStore
1199
+ .getState()
1200
+ .setToast(err instanceof Error ? err.message : 'Update failed');
1201
+ });
1131
1202
  }, onCancel: () => closeOverlay() })) : activeOverlay?.type === 'template-picker' ? (_jsx(OverlayPanel, { title: "Select Template", items: [
1132
1203
  { id: '__none__', label: 'No template', value: '__none__' },
1133
1204
  ...templates.map((t) => ({
@@ -1180,7 +1251,7 @@ export function WorkItemList() {
1180
1251
  setToast(targetIds.length === 1
1181
1252
  ? 'Parent updated — press u to undo'
1182
1253
  : `${targetIds.length} items updated — press u to undo`);
1183
- })();
1254
+ })().catch(() => { });
1184
1255
  }, onSubmitFreeform: (text) => {
1185
1256
  const targetIds = getOverlayTargetIds();
1186
1257
  if (!backend)
@@ -1212,7 +1283,7 @@ export function WorkItemList() {
1212
1283
  setToast(targetIds.length === 1
1213
1284
  ? 'Parent updated — press u to undo'
1214
1285
  : `${targetIds.length} items updated — press u to undo`);
1215
- })();
1286
+ })().catch(() => { });
1216
1287
  }, onCancel: () => closeOverlay(), placeholder: "Type parent ID or title...", emptyMessage: "Type a parent ID (empty to clear)" })) : activeOverlay?.type === 'assignee-input' ? (_jsx(OverlayPanel, { title: `Set Assignee (${activeOverlay.targetIds.length} item${activeOverlay.targetIds.length > 1 ? 's' : ''})`, items: assignees.map((a) => ({ id: a, label: a, value: a })), allowFreeform: true, onSelect: (item) => {
1217
1288
  const targetIds = getOverlayTargetIds();
1218
1289
  closeOverlay();
@@ -1232,7 +1303,11 @@ export function WorkItemList() {
1232
1303
  setToast(targetIds.length === 1
1233
1304
  ? 'Assignee updated — press u to undo'
1234
1305
  : `${targetIds.length} items updated — press u to undo`);
1235
- })();
1306
+ })().catch((err) => {
1307
+ uiStore
1308
+ .getState()
1309
+ .setToast(err instanceof Error ? err.message : 'Update failed');
1310
+ });
1236
1311
  }, onSubmitFreeform: (text) => {
1237
1312
  const targetIds = getOverlayTargetIds();
1238
1313
  closeOverlay();
@@ -1252,7 +1327,11 @@ export function WorkItemList() {
1252
1327
  setToast(targetIds.length === 1
1253
1328
  ? 'Assignee updated — press u to undo'
1254
1329
  : `${targetIds.length} items updated — press u to undo`);
1255
- })();
1330
+ })().catch((err) => {
1331
+ uiStore
1332
+ .getState()
1333
+ .setToast(err instanceof Error ? err.message : 'Update failed');
1334
+ });
1256
1335
  }, onCancel: () => closeOverlay(), placeholder: "Type assignee name..." })) : activeOverlay?.type === 'labels-input' ? (_jsx(OverlayPanel, { title: `Set Labels (${activeOverlay.targetIds.length} item${activeOverlay.targetIds.length > 1 ? 's' : ''})`, items: labelSuggestions.map((l) => ({
1257
1336
  id: l,
1258
1337
  label: l,
@@ -1275,7 +1354,11 @@ export function WorkItemList() {
1275
1354
  setToast(targetIds.length === 1
1276
1355
  ? 'Labels updated — press u to undo'
1277
1356
  : `${targetIds.length} items updated — press u to undo`);
1278
- })();
1357
+ })().catch((err) => {
1358
+ uiStore
1359
+ .getState()
1360
+ .setToast(err instanceof Error ? err.message : 'Update failed');
1361
+ });
1279
1362
  }, onSubmitFreeform: (text) => {
1280
1363
  const targetIds = getOverlayTargetIds();
1281
1364
  closeOverlay();
@@ -1297,7 +1380,11 @@ export function WorkItemList() {
1297
1380
  setToast(targetIds.length === 1
1298
1381
  ? 'Labels updated — press u to undo'
1299
1382
  : `${targetIds.length} items updated — press u to undo`);
1300
- })();
1383
+ })().catch((err) => {
1384
+ uiStore
1385
+ .getState()
1386
+ .setToast(err instanceof Error ? err.message : 'Update failed');
1387
+ });
1301
1388
  }, onCancel: () => closeOverlay(), placeholder: "Type to filter labels..." })) : activeOverlay?.type === 'sort-picker' ? (_jsx(OverlayPanel, { title: "Order by", items: sortPickerItems, onSelect: (item) => {
1302
1389
  closeOverlay();
1303
1390
  if (item.value === '__clear__') {
@@ -1360,9 +1447,12 @@ export function WorkItemList() {
1360
1447
  ...(sortStack.length > 0 ? { sort: [...sortStack] } : {}),
1361
1448
  };
1362
1449
  const existing = savedViews.filter((v) => v.name !== lastViewName);
1363
- void configStore.getState().update({
1450
+ void configStore
1451
+ .getState()
1452
+ .update({
1364
1453
  views: [...existing, newView],
1365
- });
1454
+ })
1455
+ .catch(() => { });
1366
1456
  filterStore.setState({
1367
1457
  activeViewName: lastViewName,
1368
1458
  });
@@ -1388,11 +1478,17 @@ export function WorkItemList() {
1388
1478
  }, onAction: (item) => {
1389
1479
  if (item.value === '__no-filters__' ||
1390
1480
  item.value === defaultView) {
1391
- void configStore.getState().update({ defaultView: undefined });
1481
+ void configStore
1482
+ .getState()
1483
+ .update({ defaultView: undefined })
1484
+ .catch(() => { });
1392
1485
  setToast('Default view cleared');
1393
1486
  }
1394
1487
  else {
1395
- void configStore.getState().update({ defaultView: item.value });
1488
+ void configStore
1489
+ .getState()
1490
+ .update({ defaultView: item.value })
1491
+ .catch(() => { });
1396
1492
  setToast(`View "${item.value}" set as default`);
1397
1493
  }
1398
1494
  }, onCancel: () => closeOverlay(), footer: "\u2191\u2193 navigate enter load tab set default esc cancel" })) : activeOverlay?.type === 'save-view-input' ? (_jsx(OverlayPanel, { title: "Save View", items: [], allowFreeform: true, onSelect: () => { }, onSubmitFreeform: (name) => {
@@ -1406,20 +1502,26 @@ export function WorkItemList() {
1406
1502
  ...(sortStack.length > 0 ? { sort: [...sortStack] } : {}),
1407
1503
  };
1408
1504
  const existing = savedViews.filter((v) => v.name !== name.trim());
1409
- void configStore.getState().update({
1505
+ void configStore
1506
+ .getState()
1507
+ .update({
1410
1508
  views: [...existing, newView],
1411
- });
1509
+ })
1510
+ .catch(() => { });
1412
1511
  filterStore.setState({ activeViewName: name.trim() });
1413
1512
  closeOverlay();
1414
1513
  setToast(`View "${name.trim()}" saved`);
1415
1514
  }, onCancel: () => closeOverlay(), placeholder: "Enter view name...", emptyMessage: "Type a name and press enter" })) : activeOverlay?.type === 'delete-view-picker' ? (_jsx(OverlayPanel, { title: "Delete View", items: viewPickerItems.filter((i) => i.id !== '__no-filters__'), onSelect: (item) => {
1416
1515
  const remaining = savedViews.filter((v) => v.name !== item.value);
1417
- void configStore.getState().update({
1516
+ void configStore
1517
+ .getState()
1518
+ .update({
1418
1519
  views: remaining,
1419
1520
  ...(defaultView === item.value
1420
1521
  ? { defaultView: undefined }
1421
1522
  : {}),
1422
- });
1523
+ })
1524
+ .catch(() => { });
1423
1525
  if (activeViewName === item.value) {
1424
1526
  filterStore.setState({ activeViewName: null });
1425
1527
  }
@@ -1474,7 +1576,11 @@ export function WorkItemList() {
1474
1576
  setToast(targetIds.length === 1
1475
1577
  ? `Item #${targetIds[0]} deleted${softDelete ? ' — press u to undo' : ''}`
1476
1578
  : `${targetIds.length} items deleted${softDelete ? ' — press u to undo' : ''}`);
1477
- })();
1579
+ })().catch((err) => {
1580
+ uiStore
1581
+ .getState()
1582
+ .setToast(err instanceof Error ? err.message : 'Delete failed');
1583
+ });
1478
1584
  }
1479
1585
  else {
1480
1586
  closeOverlay();