@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.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/commands.d.ts +6 -0
- package/dist/commands.js +16 -0
- package/dist/commands.js.map +1 -1
- package/dist/components/OverlayPanel.d.ts +29 -0
- package/dist/components/OverlayPanel.js +120 -0
- package/dist/components/OverlayPanel.js.map +1 -0
- package/dist/components/Settings.js +28 -30
- package/dist/components/Settings.js.map +1 -1
- package/dist/components/WorkItemList.js +315 -171
- package/dist/components/WorkItemList.js.map +1 -1
- package/dist/components/fuzzyMatch.d.ts +1 -0
- package/dist/components/fuzzyMatch.js +13 -0
- package/dist/components/fuzzyMatch.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/BulkMenu.d.ts +0 -10
- package/dist/components/BulkMenu.js +0 -49
- package/dist/components/BulkMenu.js.map +0 -1
- package/dist/components/CommandPalette.d.ts +0 -13
- package/dist/components/CommandPalette.js +0 -70
- package/dist/components/CommandPalette.js.map +0 -1
- package/dist/components/DefaultPicker.d.ts +0 -8
- package/dist/components/DefaultPicker.js +0 -19
- package/dist/components/DefaultPicker.js.map +0 -1
- package/dist/components/PriorityPicker.d.ts +0 -6
- package/dist/components/PriorityPicker.js +0 -18
- package/dist/components/PriorityPicker.js.map +0 -1
- package/dist/components/SearchOverlay.d.ts +0 -12
- package/dist/components/SearchOverlay.js +0 -64
- package/dist/components/SearchOverlay.js.map +0 -1
- package/dist/components/StatusPicker.d.ts +0 -7
- package/dist/components/StatusPicker.js +0 -16
- package/dist/components/StatusPicker.js.map +0 -1
- package/dist/components/TemplatePicker.d.ts +0 -8
- package/dist/components/TemplatePicker.js +0 -24
- package/dist/components/TemplatePicker.js.map +0 -1
- package/dist/components/TypePicker.d.ts +0 -7
- package/dist/components/TypePicker.js +0 -16
- package/dist/components/TypePicker.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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: [
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
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
|
-
|
|
678
|
-
|
|
679
|
-
|
|
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, {
|
|
792
|
+
await backend.cachedUpdateWorkItem(id, {
|
|
793
|
+
parent: newParent,
|
|
794
|
+
});
|
|
682
795
|
await queueWrite('update', id);
|
|
683
796
|
}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
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
|
-
|
|
693
|
-
|
|
694
|
-
|
|
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, {
|
|
821
|
+
await backend.cachedUpdateWorkItem(id, {
|
|
822
|
+
parent: newParent,
|
|
823
|
+
});
|
|
697
824
|
await queueWrite('update', id);
|
|
698
825
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
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.
|
|
712
|
-
await queueWrite('
|
|
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
|
-
?
|
|
717
|
-
: `${targetIds.length} items
|
|
930
|
+
? `Item #${targetIds[0]} deleted`
|
|
931
|
+
: `${targetIds.length} items deleted`);
|
|
718
932
|
})();
|
|
719
|
-
}
|
|
933
|
+
}
|
|
934
|
+
else {
|
|
720
935
|
closeOverlay();
|
|
721
|
-
|
|
722
|
-
|
|
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
|