@sascha384/tic 1.29.0 → 1.30.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 (39) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/commands.d.ts +6 -0
  3. package/dist/commands.js +16 -0
  4. package/dist/commands.js.map +1 -1
  5. package/dist/components/OverlayPanel.d.ts +29 -0
  6. package/dist/components/OverlayPanel.js +120 -0
  7. package/dist/components/OverlayPanel.js.map +1 -0
  8. package/dist/components/Settings.js +28 -30
  9. package/dist/components/Settings.js.map +1 -1
  10. package/dist/components/WorkItemList.js +315 -171
  11. package/dist/components/WorkItemList.js.map +1 -1
  12. package/dist/components/fuzzyMatch.d.ts +1 -0
  13. package/dist/components/fuzzyMatch.js +13 -0
  14. package/dist/components/fuzzyMatch.js.map +1 -1
  15. package/package.json +1 -1
  16. package/dist/components/BulkMenu.d.ts +0 -10
  17. package/dist/components/BulkMenu.js +0 -49
  18. package/dist/components/BulkMenu.js.map +0 -1
  19. package/dist/components/CommandPalette.d.ts +0 -13
  20. package/dist/components/CommandPalette.js +0 -70
  21. package/dist/components/CommandPalette.js.map +0 -1
  22. package/dist/components/DefaultPicker.d.ts +0 -8
  23. package/dist/components/DefaultPicker.js +0 -19
  24. package/dist/components/DefaultPicker.js.map +0 -1
  25. package/dist/components/PriorityPicker.d.ts +0 -6
  26. package/dist/components/PriorityPicker.js +0 -18
  27. package/dist/components/PriorityPicker.js.map +0 -1
  28. package/dist/components/SearchOverlay.d.ts +0 -12
  29. package/dist/components/SearchOverlay.js +0 -64
  30. package/dist/components/SearchOverlay.js.map +0 -1
  31. package/dist/components/StatusPicker.d.ts +0 -7
  32. package/dist/components/StatusPicker.js +0 -16
  33. package/dist/components/StatusPicker.js.map +0 -1
  34. package/dist/components/TemplatePicker.d.ts +0 -8
  35. package/dist/components/TemplatePicker.js +0 -24
  36. package/dist/components/TemplatePicker.js.map +0 -1
  37. package/dist/components/TypePicker.d.ts +0 -7
  38. package/dist/components/TypePicker.js +0 -16
  39. package/dist/components/TypePicker.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useState, useMemo, useEffect, useCallback } from 'react';
3
3
  import { Box, Text, useInput, useApp } from 'ink';
4
4
  import { navigationStore, useNavigationStore, } from '../stores/navigationStore.js';
@@ -14,17 +14,9 @@ import { useBackendDataStore, backendDataStore, } from '../stores/backendDataSto
14
14
  import { useShallow } from 'zustand/shallow';
15
15
  import { SyncQueueStore } from '../sync/queue.js';
16
16
  import { buildTree } from './buildTree.js';
17
- import { SearchOverlay } from './SearchOverlay.js';
18
- import { BulkMenu } from './BulkMenu.js';
19
- import { CommandPalette } from './CommandPalette.js';
20
17
  import { getVisibleCommands, } from '../commands.js';
21
- import { PriorityPicker } from './PriorityPicker.js';
22
- import { TemplatePicker } from './TemplatePicker.js';
23
- import { TypePicker } from './TypePicker.js';
24
- import { StatusPicker } from './StatusPicker.js';
18
+ import { OverlayPanel } from './OverlayPanel.js';
25
19
  import { DetailPanel } from './DetailPanel.js';
26
- import { AutocompleteInput } from './AutocompleteInput.js';
27
- import { MultiAutocompleteInput } from './MultiAutocompleteInput.js';
28
20
  export function getTargetIds(markedIds, cursorItem) {
29
21
  if (markedIds.size > 0) {
30
22
  return [...markedIds];
@@ -88,10 +80,7 @@ export function WorkItemList() {
88
80
  })));
89
81
  const { setCursor, toggleExpanded, toggleMarked, clearMarked, clampCursor, removeDeletedItem, } = listViewStore.getState();
90
82
  // Local state for inputs and templates
91
- const [parentInput, setParentInput] = useState('');
92
83
  const [allSearchItems, setAllSearchItems] = useState([]);
93
- const [assigneeInput, setAssigneeInput] = useState('');
94
- const [labelsInput, setLabelsInput] = useState('');
95
84
  const [templates, setTemplates] = useState([]);
96
85
  const [showFullDescription, setShowFullDescription] = useState(false);
97
86
  const [descriptionScrollOffset, setDescriptionScrollOffset] = useState(0);
@@ -229,16 +218,6 @@ export function WorkItemList() {
229
218
  chromeLines,
230
219
  linesPerItem: 1,
231
220
  });
232
- // Block 1: Overlay escape handlers for inline inputs
233
- useInput((_input, key) => {
234
- if (key.escape) {
235
- closeOverlay();
236
- }
237
- }, {
238
- isActive: activeOverlay?.type === 'parent-input' ||
239
- activeOverlay?.type === 'assignee-input' ||
240
- activeOverlay?.type === 'labels-input',
241
- });
242
221
  // Block 1.5: Description scroll handler — active when full description is shown
243
222
  useInput((_input, key) => {
244
223
  if (_input === ' ' || key.escape) {
@@ -254,34 +233,6 @@ export function WorkItemList() {
254
233
  setDescriptionScrollOffset((o) => Math.min(maxScroll, o + 1));
255
234
  }
256
235
  }, { isActive: showFullDescription && activeOverlay === null });
257
- // Block 2: Delete confirmation handler
258
- useInput((input) => {
259
- if (activeOverlay?.type !== 'delete-confirm')
260
- return;
261
- if (input === 'y' || input === 'Y') {
262
- const targetIds = activeOverlay.targetIds;
263
- if (!backend)
264
- return;
265
- void (async () => {
266
- for (const id of targetIds) {
267
- await backend.cachedDeleteWorkItem(id);
268
- await queueWrite('delete', id);
269
- }
270
- closeOverlay();
271
- for (const id of targetIds) {
272
- removeDeletedItem(id);
273
- }
274
- setCursor(Math.max(0, cursor - 1));
275
- refreshData();
276
- setToast(targetIds.length === 1
277
- ? `Item #${targetIds[0]} deleted`
278
- : `${targetIds.length} items deleted`);
279
- })();
280
- }
281
- else {
282
- closeOverlay();
283
- }
284
- }, { isActive: activeOverlay?.type === 'delete-confirm' });
285
236
  // Block 3: Main input handler — only active when no overlay is open
286
237
  useInput((input, key) => {
287
238
  if (input === '/') {
@@ -415,14 +366,6 @@ export function WorkItemList() {
415
366
  const targetIds = getTargetIds(markedIds, treeItems[cursor]?.item);
416
367
  if (targetIds.length > 0) {
417
368
  openOverlay({ type: 'parent-input', targetIds });
418
- // For single item, prefill current parent
419
- if (targetIds.length === 1) {
420
- const item = treeItems.find((t) => t.item.id === targetIds[0]);
421
- setParentInput(item?.item.parent ?? '');
422
- }
423
- else {
424
- setParentInput('');
425
- }
426
369
  }
427
370
  }
428
371
  if (key.tab && capabilities.customTypes && types.length > 0) {
@@ -461,14 +404,12 @@ export function WorkItemList() {
461
404
  const targetIds = getTargetIds(markedIds, treeItems[cursor]?.item);
462
405
  if (targetIds.length > 0) {
463
406
  openOverlay({ type: 'assignee-input', targetIds });
464
- setAssigneeInput('');
465
407
  }
466
408
  }
467
409
  if (input === 'l' && capabilities.fields.labels && treeItems.length > 0) {
468
410
  const targetIds = getTargetIds(markedIds, treeItems[cursor]?.item);
469
411
  if (targetIds.length > 0) {
470
412
  openOverlay({ type: 'labels-input', targetIds });
471
- setLabelsInput('');
472
413
  }
473
414
  }
474
415
  if (input === 't' && capabilities.customTypes && treeItems.length > 0) {
@@ -589,7 +530,6 @@ export function WorkItemList() {
589
530
  const targetIds = getTargetIds(markedIds, treeItems[cursor]?.item);
590
531
  if (targetIds.length > 0) {
591
532
  openOverlay({ type: 'assignee-input', targetIds });
592
- setAssigneeInput('');
593
533
  }
594
534
  }
595
535
  break;
@@ -598,7 +538,6 @@ export function WorkItemList() {
598
538
  const targetIds = getTargetIds(markedIds, treeItems[cursor]?.item);
599
539
  if (targetIds.length > 0) {
600
540
  openOverlay({ type: 'labels-input', targetIds });
601
- setLabelsInput('');
602
541
  }
603
542
  }
604
543
  break;
@@ -640,7 +579,6 @@ export function WorkItemList() {
640
579
  break;
641
580
  case 'parent':
642
581
  openOverlay({ type: 'parent-input', targetIds });
643
- setParentInput('');
644
582
  break;
645
583
  case 'type':
646
584
  openOverlay({ type: 'type-picker', targetIds });
@@ -650,11 +588,9 @@ export function WorkItemList() {
650
588
  break;
651
589
  case 'assignee':
652
590
  openOverlay({ type: 'assignee-input', targetIds });
653
- setAssigneeInput('');
654
591
  break;
655
592
  case 'labels':
656
593
  openOverlay({ type: 'labels-input', targetIds });
657
- setLabelsInput('');
658
594
  break;
659
595
  case 'delete':
660
596
  openOverlay({ type: 'delete-confirm', targetIds });
@@ -668,128 +604,336 @@ export function WorkItemList() {
668
604
  const positionText = treeItems.length > viewport.maxVisible
669
605
  ? `${cursor + 1}/${treeItems.length}`
670
606
  : '';
671
- return (_jsxs(Box, { flexDirection: "column", children: [activeOverlay?.type === 'search' && (_jsx(SearchOverlay, { items: allSearchItems, currentIteration: iteration, onSelect: handleSearchSelect, onCancel: handleSearchCancel })), activeOverlay?.type !== 'search' && (_jsxs(_Fragment, { children: [activeOverlay?.type === 'bulk-menu' && (_jsx(BulkMenu, { itemCount: markedIds.size > 0 ? markedIds.size : 1, capabilities: capabilities, onSelect: (action) => {
672
- closeOverlay();
673
- handleBulkAction(action);
674
- }, onCancel: () => closeOverlay() })), activeOverlay?.type === 'command-palette' && (_jsx(CommandPalette, { commands: paletteCommands, onSelect: handleCommandSelect, onCancel: () => closeOverlay() })), activeOverlay?.type === 'status-picker' && (_jsx(StatusPicker, { statuses: statuses, onSelect: (status) => {
675
- const targetIds = getOverlayTargetIds();
607
+ 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: ` (${items.length} items)` }), markedCount > 0 && (_jsx(Text, { color: "magenta", children: ` ● ${markedCount} marked` }))] }) }), _jsx(TableLayout, { treeItems: visibleTreeItems, cursor: viewport.visibleCursor, capabilities: capabilities, collapsedIds: collapsedIds, markedIds: markedIds, terminalWidth: terminalWidth }), 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(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 === 'search' ? ((() => {
608
+ const searchItems = allSearchItems.map((item) => ({
609
+ id: item.id,
610
+ label: `#${item.id} ${item.title}`,
611
+ value: item.id,
612
+ hint: item.type,
613
+ category: item.iteration === iteration
614
+ ? 'Current iteration'
615
+ : (item.iteration ?? 'No iteration'),
616
+ }));
617
+ return (_jsx(OverlayPanel, { title: "Search", items: searchItems, placeholder: "Type to search...", onSelect: (selected) => {
618
+ const item = allSearchItems.find((i) => i.id === selected.value);
619
+ if (item)
620
+ handleSearchSelect(item);
621
+ }, onCancel: handleSearchCancel }));
622
+ })()) : activeOverlay?.type === 'bulk-menu' ? ((() => {
623
+ const bulkItems = [];
624
+ bulkItems.push({
625
+ id: 'status',
626
+ label: 'Set status...',
627
+ value: 'status',
628
+ hint: 's',
629
+ });
630
+ if (capabilities.iterations) {
631
+ bulkItems.push({
632
+ id: 'iteration',
633
+ label: 'Set iteration...',
634
+ value: 'iteration',
635
+ hint: 'i',
636
+ });
637
+ }
638
+ if (capabilities.fields.parent) {
639
+ bulkItems.push({
640
+ id: 'parent',
641
+ label: 'Set parent...',
642
+ value: 'parent',
643
+ hint: 'p',
644
+ });
645
+ }
646
+ if (capabilities.customTypes) {
647
+ bulkItems.push({
648
+ id: 'type',
649
+ label: 'Set type...',
650
+ value: 'type',
651
+ hint: 't',
652
+ });
653
+ }
654
+ if (capabilities.fields.priority) {
655
+ bulkItems.push({
656
+ id: 'priority',
657
+ label: 'Set priority...',
658
+ value: 'priority',
659
+ hint: 'P',
660
+ });
661
+ }
662
+ if (capabilities.fields.assignee) {
663
+ bulkItems.push({
664
+ id: 'assignee',
665
+ label: 'Set assignee...',
666
+ value: 'assignee',
667
+ hint: 'a',
668
+ });
669
+ }
670
+ if (capabilities.fields.labels) {
671
+ bulkItems.push({
672
+ id: 'labels',
673
+ label: 'Set labels...',
674
+ value: 'labels',
675
+ hint: 'l',
676
+ });
677
+ }
678
+ bulkItems.push({
679
+ id: 'delete',
680
+ label: 'Delete',
681
+ value: 'delete',
682
+ hint: 'd',
683
+ });
684
+ const count = markedIds.size > 0 ? markedIds.size : 1;
685
+ return (_jsx(OverlayPanel, { title: `Bulk Actions (${count} ${count === 1 ? 'item' : 'items'})`, items: bulkItems, onSelect: (item) => {
676
686
  closeOverlay();
677
- if (!backend)
678
- return;
679
- void (async () => {
687
+ handleBulkAction(item.value);
688
+ }, onCancel: () => closeOverlay() }));
689
+ })()) : activeOverlay?.type === 'command-palette' ? (_jsx(OverlayPanel, { title: "Commands", items: paletteCommands.map((cmd) => ({
690
+ id: cmd.id,
691
+ label: cmd.label,
692
+ value: cmd.id,
693
+ hint: cmd.shortcut,
694
+ category: cmd.category,
695
+ })), placeholder: "Type a command...", onSelect: (item) => {
696
+ const cmd = paletteCommands.find((c) => c.id === item.value);
697
+ if (cmd)
698
+ handleCommandSelect(cmd);
699
+ }, onCancel: () => closeOverlay() })) : activeOverlay?.type === 'status-picker' ? (_jsx(OverlayPanel, { title: "Set Status", items: statuses.map((s) => ({ id: s, label: s, value: s })), onSelect: (item) => {
700
+ const targetIds = getOverlayTargetIds();
701
+ closeOverlay();
702
+ if (!backend)
703
+ return;
704
+ void (async () => {
705
+ for (const id of targetIds) {
706
+ await backend.cachedUpdateWorkItem(id, {
707
+ status: item.value,
708
+ });
709
+ await queueWrite('update', id);
710
+ }
711
+ refreshData();
712
+ setToast(targetIds.length === 1
713
+ ? 'Status updated'
714
+ : `${targetIds.length} items updated`);
715
+ })();
716
+ }, onCancel: () => closeOverlay() })) : activeOverlay?.type === 'type-picker' ? (_jsx(OverlayPanel, { title: "Set Type", items: types.map((t) => ({
717
+ id: t,
718
+ label: t.charAt(0).toUpperCase() + t.slice(1),
719
+ value: t,
720
+ })), onSelect: (item) => {
721
+ const targetIds = getOverlayTargetIds();
722
+ closeOverlay();
723
+ if (!backend)
724
+ return;
725
+ void (async () => {
726
+ for (const id of targetIds) {
727
+ await backend.cachedUpdateWorkItem(id, {
728
+ type: item.value,
729
+ });
730
+ await queueWrite('update', id);
731
+ }
732
+ refreshData();
733
+ setToast(targetIds.length === 1
734
+ ? 'Type updated'
735
+ : `${targetIds.length} items updated`);
736
+ })();
737
+ }, onCancel: () => closeOverlay() })) : activeOverlay?.type === 'priority-picker' ? (_jsx(OverlayPanel, { title: "Set Priority", items: [
738
+ { id: 'critical', label: 'Critical', value: 'critical' },
739
+ { id: 'high', label: 'High', value: 'high' },
740
+ { id: 'medium', label: 'Medium', value: 'medium' },
741
+ { id: 'low', label: 'Low', value: 'low' },
742
+ ], onSelect: (item) => {
743
+ const targetIds = getOverlayTargetIds();
744
+ closeOverlay();
745
+ if (!backend)
746
+ return;
747
+ const priority = item.value;
748
+ void (async () => {
749
+ for (const id of targetIds) {
750
+ await backend.cachedUpdateWorkItem(id, { priority });
751
+ await queueWrite('update', id);
752
+ }
753
+ refreshData();
754
+ setToast(targetIds.length === 1
755
+ ? 'Priority updated'
756
+ : `${targetIds.length} items updated`);
757
+ })();
758
+ }, onCancel: () => closeOverlay() })) : activeOverlay?.type === 'template-picker' ? (_jsx(OverlayPanel, { title: "Select Template", items: [
759
+ { id: '__none__', label: 'No template', value: '__none__' },
760
+ ...templates.map((t) => ({
761
+ id: t.slug,
762
+ label: t.name,
763
+ value: t.slug,
764
+ })),
765
+ ], onSelect: (item) => {
766
+ closeOverlay();
767
+ setFormMode('item');
768
+ if (item.value === '__none__') {
769
+ setActiveTemplate(null);
770
+ }
771
+ else {
772
+ const template = templates.find((t) => t.slug === item.value);
773
+ setActiveTemplate(template ?? null);
774
+ }
775
+ selectWorkItem(null);
776
+ navigate('form');
777
+ }, onCancel: () => closeOverlay() })) : activeOverlay?.type === 'parent-input' ? (_jsx(OverlayPanel, { title: `Set Parent (${activeOverlay.targetIds.length} item${activeOverlay.targetIds.length > 1 ? 's' : ''})`, items: parentSuggestions.map((s) => ({
778
+ id: s,
779
+ label: s,
780
+ value: s,
781
+ })), allowFreeform: true, onSelect: (item) => {
782
+ const targetIds = getOverlayTargetIds();
783
+ if (!backend)
784
+ return;
785
+ void (async () => {
786
+ const raw = item.value.trim();
787
+ const newParent = raw.includes(' - ')
788
+ ? raw.split(' - ')[0].trim()
789
+ : raw;
790
+ try {
680
791
  for (const id of targetIds) {
681
- await backend.cachedUpdateWorkItem(id, { status });
792
+ await backend.cachedUpdateWorkItem(id, {
793
+ parent: newParent,
794
+ });
682
795
  await queueWrite('update', id);
683
796
  }
684
- refreshData();
685
- setToast(targetIds.length === 1
686
- ? 'Status updated'
687
- : `${targetIds.length} items updated`);
688
- })();
689
- }, onCancel: () => closeOverlay() })), activeOverlay?.type === 'type-picker' && (_jsx(TypePicker, { types: types, onSelect: (type) => {
690
- const targetIds = getOverlayTargetIds();
797
+ clearWarning();
798
+ }
799
+ catch (e) {
800
+ setWarning(e instanceof Error ? e.message : 'Invalid parent');
801
+ }
691
802
  closeOverlay();
692
- if (!backend)
693
- return;
694
- void (async () => {
803
+ refreshData();
804
+ setToast(targetIds.length === 1
805
+ ? 'Parent updated'
806
+ : `${targetIds.length} items updated`);
807
+ })();
808
+ }, onSubmitFreeform: (text) => {
809
+ const targetIds = getOverlayTargetIds();
810
+ if (!backend)
811
+ return;
812
+ void (async () => {
813
+ const raw = text.trim();
814
+ const newParent = raw === ''
815
+ ? null
816
+ : raw.includes(' - ')
817
+ ? raw.split(' - ')[0].trim()
818
+ : raw;
819
+ try {
695
820
  for (const id of targetIds) {
696
- await backend.cachedUpdateWorkItem(id, { type });
821
+ await backend.cachedUpdateWorkItem(id, {
822
+ parent: newParent,
823
+ });
697
824
  await queueWrite('update', id);
698
825
  }
699
- refreshData();
700
- setToast(targetIds.length === 1
701
- ? 'Type updated'
702
- : `${targetIds.length} items updated`);
703
- })();
704
- }, onCancel: () => closeOverlay() })), activeOverlay?.type === 'priority-picker' && (_jsx(PriorityPicker, { onSelect: (priority) => {
705
- const targetIds = getOverlayTargetIds();
826
+ clearWarning();
827
+ }
828
+ catch (e) {
829
+ setWarning(e instanceof Error ? e.message : 'Invalid parent');
830
+ }
706
831
  closeOverlay();
832
+ refreshData();
833
+ setToast(targetIds.length === 1
834
+ ? 'Parent updated'
835
+ : `${targetIds.length} items updated`);
836
+ })();
837
+ }, 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) => {
838
+ const targetIds = getOverlayTargetIds();
839
+ closeOverlay();
840
+ if (!backend)
841
+ return;
842
+ void (async () => {
843
+ for (const id of targetIds) {
844
+ await backend.cachedUpdateWorkItem(id, {
845
+ assignee: item.value.trim(),
846
+ });
847
+ await queueWrite('update', id);
848
+ }
849
+ refreshData();
850
+ setToast(targetIds.length === 1
851
+ ? 'Assignee updated'
852
+ : `${targetIds.length} items updated`);
853
+ })();
854
+ }, onSubmitFreeform: (text) => {
855
+ const targetIds = getOverlayTargetIds();
856
+ closeOverlay();
857
+ if (!backend)
858
+ return;
859
+ void (async () => {
860
+ for (const id of targetIds) {
861
+ await backend.cachedUpdateWorkItem(id, {
862
+ assignee: text.trim(),
863
+ });
864
+ await queueWrite('update', id);
865
+ }
866
+ refreshData();
867
+ setToast(targetIds.length === 1
868
+ ? 'Assignee updated'
869
+ : `${targetIds.length} items updated`);
870
+ })();
871
+ }, 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) => ({
872
+ id: l,
873
+ label: l,
874
+ value: l,
875
+ })), multiSelect: true, allowFreeform: true, onSelect: () => { }, onConfirm: (selected) => {
876
+ const targetIds = getOverlayTargetIds();
877
+ closeOverlay();
878
+ if (!backend)
879
+ return;
880
+ void (async () => {
881
+ const labels = selected.map((i) => i.value);
882
+ for (const id of targetIds) {
883
+ await backend.cachedUpdateWorkItem(id, { labels });
884
+ await queueWrite('update', id);
885
+ }
886
+ refreshData();
887
+ setToast(targetIds.length === 1
888
+ ? 'Labels updated'
889
+ : `${targetIds.length} items updated`);
890
+ })();
891
+ }, onSubmitFreeform: (text) => {
892
+ const targetIds = getOverlayTargetIds();
893
+ closeOverlay();
894
+ if (!backend)
895
+ return;
896
+ void (async () => {
897
+ const labels = text
898
+ .split(',')
899
+ .map((l) => l.trim())
900
+ .filter(Boolean);
901
+ for (const id of targetIds) {
902
+ await backend.cachedUpdateWorkItem(id, { labels });
903
+ await queueWrite('update', id);
904
+ }
905
+ refreshData();
906
+ setToast(targetIds.length === 1
907
+ ? 'Labels updated'
908
+ : `${targetIds.length} items updated`);
909
+ })();
910
+ }, onCancel: () => closeOverlay(), placeholder: "Type to filter labels..." })) : activeOverlay?.type === 'delete-confirm' ? (_jsx(OverlayPanel, { title: `Delete ${activeOverlay.targetIds.length} item${activeOverlay.targetIds.length > 1 ? 's' : ''}?`, items: [
911
+ { id: 'yes', label: 'Yes, delete', value: 'yes' },
912
+ { id: 'no', label: 'Cancel', value: 'no' },
913
+ ], onSelect: (item) => {
914
+ if (item.value === 'yes') {
915
+ const targetIds = activeOverlay.targetIds;
707
916
  if (!backend)
708
917
  return;
709
918
  void (async () => {
710
919
  for (const id of targetIds) {
711
- await backend.cachedUpdateWorkItem(id, { priority });
712
- await queueWrite('update', id);
920
+ await backend.cachedDeleteWorkItem(id);
921
+ await queueWrite('delete', id);
922
+ }
923
+ closeOverlay();
924
+ for (const id of targetIds) {
925
+ removeDeletedItem(id);
713
926
  }
927
+ setCursor(Math.max(0, cursor - 1));
714
928
  refreshData();
715
929
  setToast(targetIds.length === 1
716
- ? 'Priority updated'
717
- : `${targetIds.length} items updated`);
930
+ ? `Item #${targetIds[0]} deleted`
931
+ : `${targetIds.length} items deleted`);
718
932
  })();
719
- }, onCancel: () => closeOverlay() })), activeOverlay?.type === 'template-picker' && (_jsx(TemplatePicker, { templates: templates, onSelect: (template) => {
933
+ }
934
+ else {
720
935
  closeOverlay();
721
- setFormMode('item');
722
- setActiveTemplate(template);
723
- selectWorkItem(null);
724
- navigate('form');
725
- }, onCancel: () => closeOverlay() })), _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: ` (${items.length} items)` }), markedCount > 0 && (_jsx(Text, { color: "magenta", children: ` ● ${markedCount} marked` }))] }) }), _jsx(TableLayout, { treeItems: visibleTreeItems, cursor: viewport.visibleCursor, capabilities: capabilities, collapsedIds: collapsedIds, markedIds: markedIds, terminalWidth: terminalWidth }), 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(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 === 'parent-input' ? (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "cyan", children: ["Set parent for ", activeOverlay.targetIds.length, " item", activeOverlay.targetIds.length > 1 ? 's' : '', " (empty to clear):"] }), _jsx(AutocompleteInput, { value: parentInput, onChange: setParentInput, focus: true, suggestions: parentSuggestions, onSubmit: () => {
726
- const targetIds = getOverlayTargetIds();
727
- if (!backend)
728
- return;
729
- void (async () => {
730
- const raw = parentInput.trim();
731
- const newParent = raw === ''
732
- ? null
733
- : raw.includes(' - ')
734
- ? raw.split(' - ')[0].trim()
735
- : raw;
736
- try {
737
- for (const id of targetIds) {
738
- await backend.cachedUpdateWorkItem(id, {
739
- parent: newParent,
740
- });
741
- await queueWrite('update', id);
742
- }
743
- clearWarning();
744
- }
745
- catch (e) {
746
- setWarning(e instanceof Error ? e.message : 'Invalid parent');
747
- }
748
- closeOverlay();
749
- setParentInput('');
750
- refreshData();
751
- setToast(targetIds.length === 1
752
- ? 'Parent updated'
753
- : `${targetIds.length} items updated`);
754
- })();
755
- } })] })) : activeOverlay?.type === 'assignee-input' ? (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "cyan", children: ["Set assignee for ", activeOverlay.targetIds.length, " item", activeOverlay.targetIds.length > 1 ? 's' : '', ":"] }), _jsx(AutocompleteInput, { value: assigneeInput, onChange: setAssigneeInput, focus: true, suggestions: assignees, onSubmit: () => {
756
- const targetIds = getOverlayTargetIds();
757
- closeOverlay();
758
- if (!backend)
759
- return;
760
- void (async () => {
761
- const assignee = assigneeInput.trim();
762
- for (const id of targetIds) {
763
- await backend.cachedUpdateWorkItem(id, { assignee });
764
- await queueWrite('update', id);
765
- }
766
- setAssigneeInput('');
767
- refreshData();
768
- setToast(targetIds.length === 1
769
- ? 'Assignee updated'
770
- : `${targetIds.length} items updated`);
771
- })();
772
- } })] })) : activeOverlay?.type === 'labels-input' ? (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "cyan", children: ["Set labels for ", activeOverlay.targetIds.length, " item", activeOverlay.targetIds.length > 1 ? 's' : '', ' ', "(comma-separated):"] }), _jsx(MultiAutocompleteInput, { value: labelsInput, onChange: setLabelsInput, focus: true, suggestions: labelSuggestions, onSubmit: () => {
773
- const targetIds = getOverlayTargetIds();
774
- closeOverlay();
775
- if (!backend)
776
- return;
777
- void (async () => {
778
- const labels = labelsInput
779
- .split(',')
780
- .map((l) => l.trim())
781
- .filter(Boolean);
782
- for (const id of targetIds) {
783
- await backend.cachedUpdateWorkItem(id, { labels });
784
- await queueWrite('update', id);
785
- }
786
- setLabelsInput('');
787
- refreshData();
788
- setToast(targetIds.length === 1
789
- ? 'Labels updated'
790
- : `${targetIds.length} items updated`);
791
- })();
792
- } })] })) : activeOverlay?.type === 'delete-confirm' ? (_jsxs(Text, { color: "red", children: ["Delete ", activeOverlay.targetIds.length, " item", activeOverlay.targetIds.length > 1 ? 's' : '', "? (y/n)"] })) : toast ? (_jsxs(Box, { children: [_jsx(Text, { color: "green", children: toast.message }), positionText && _jsxs(Text, { dimColor: true, children: [" ", positionText] })] })) : (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: buildHelpText(terminalWidth -
793
- (positionText ? positionText.length + 2 : 0)) }), positionText && _jsxs(Text, { dimColor: true, children: [" ", positionText] })] })) }), warning && (_jsx(Box, { children: _jsxs(Text, { color: "yellow", children: ["\u26A0 ", warning] }) })), updateInfo?.updateAvailable && activeOverlay === null && (_jsx(Box, { children: _jsxs(Text, { color: "yellow", children: ["Update available: ", updateInfo.current, " \u2192 ", updateInfo.latest, ' ', "Press , to update in Settings"] }) }))] }))] }));
936
+ }
937
+ }, onCancel: () => closeOverlay() })) : toast ? (_jsxs(Box, { children: [_jsx(Text, { color: "green", children: toast.message }), positionText && _jsxs(Text, { dimColor: true, children: [" ", positionText] })] })) : (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: buildHelpText(terminalWidth - (positionText ? positionText.length + 2 : 0)) }), positionText && _jsxs(Text, { dimColor: true, children: [" ", positionText] })] })) }), warning && (_jsx(Box, { children: _jsxs(Text, { color: "yellow", children: ["\u26A0 ", warning] }) })), updateInfo?.updateAvailable && activeOverlay === null && (_jsx(Box, { children: _jsxs(Text, { color: "yellow", children: ["Update available: ", updateInfo.current, " \u2192 ", updateInfo.latest, " Press , to update in Settings"] }) }))] }));
794
938
  }
795
939
  //# sourceMappingURL=WorkItemList.js.map