@sascha384/tic 1.28.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/HelpScreen.js +2 -1
- package/dist/components/HelpScreen.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 +322 -172
- 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 === '/') {
|
|
@@ -393,9 +344,15 @@ export function WorkItemList() {
|
|
|
393
344
|
}
|
|
394
345
|
refreshData();
|
|
395
346
|
}
|
|
396
|
-
if (input === '
|
|
347
|
+
if (input === 'S') {
|
|
397
348
|
navigate('status');
|
|
398
349
|
}
|
|
350
|
+
if (input === 's' && treeItems.length > 0) {
|
|
351
|
+
const targetIds = getTargetIds(markedIds, treeItems[cursor]?.item);
|
|
352
|
+
if (targetIds.length > 0) {
|
|
353
|
+
openOverlay({ type: 'status-picker', targetIds });
|
|
354
|
+
}
|
|
355
|
+
}
|
|
399
356
|
if (input === 'v') {
|
|
400
357
|
void configStore
|
|
401
358
|
.getState()
|
|
@@ -409,14 +366,6 @@ export function WorkItemList() {
|
|
|
409
366
|
const targetIds = getTargetIds(markedIds, treeItems[cursor]?.item);
|
|
410
367
|
if (targetIds.length > 0) {
|
|
411
368
|
openOverlay({ type: 'parent-input', targetIds });
|
|
412
|
-
// For single item, prefill current parent
|
|
413
|
-
if (targetIds.length === 1) {
|
|
414
|
-
const item = treeItems.find((t) => t.item.id === targetIds[0]);
|
|
415
|
-
setParentInput(item?.item.parent ?? '');
|
|
416
|
-
}
|
|
417
|
-
else {
|
|
418
|
-
setParentInput('');
|
|
419
|
-
}
|
|
420
369
|
}
|
|
421
370
|
}
|
|
422
371
|
if (key.tab && capabilities.customTypes && types.length > 0) {
|
|
@@ -455,14 +404,12 @@ export function WorkItemList() {
|
|
|
455
404
|
const targetIds = getTargetIds(markedIds, treeItems[cursor]?.item);
|
|
456
405
|
if (targetIds.length > 0) {
|
|
457
406
|
openOverlay({ type: 'assignee-input', targetIds });
|
|
458
|
-
setAssigneeInput('');
|
|
459
407
|
}
|
|
460
408
|
}
|
|
461
409
|
if (input === 'l' && capabilities.fields.labels && treeItems.length > 0) {
|
|
462
410
|
const targetIds = getTargetIds(markedIds, treeItems[cursor]?.item);
|
|
463
411
|
if (targetIds.length > 0) {
|
|
464
412
|
openOverlay({ type: 'labels-input', targetIds });
|
|
465
|
-
setLabelsInput('');
|
|
466
413
|
}
|
|
467
414
|
}
|
|
468
415
|
if (input === 't' && capabilities.customTypes && treeItems.length > 0) {
|
|
@@ -583,7 +530,6 @@ export function WorkItemList() {
|
|
|
583
530
|
const targetIds = getTargetIds(markedIds, treeItems[cursor]?.item);
|
|
584
531
|
if (targetIds.length > 0) {
|
|
585
532
|
openOverlay({ type: 'assignee-input', targetIds });
|
|
586
|
-
setAssigneeInput('');
|
|
587
533
|
}
|
|
588
534
|
}
|
|
589
535
|
break;
|
|
@@ -592,7 +538,6 @@ export function WorkItemList() {
|
|
|
592
538
|
const targetIds = getTargetIds(markedIds, treeItems[cursor]?.item);
|
|
593
539
|
if (targetIds.length > 0) {
|
|
594
540
|
openOverlay({ type: 'labels-input', targetIds });
|
|
595
|
-
setLabelsInput('');
|
|
596
541
|
}
|
|
597
542
|
}
|
|
598
543
|
break;
|
|
@@ -634,7 +579,6 @@ export function WorkItemList() {
|
|
|
634
579
|
break;
|
|
635
580
|
case 'parent':
|
|
636
581
|
openOverlay({ type: 'parent-input', targetIds });
|
|
637
|
-
setParentInput('');
|
|
638
582
|
break;
|
|
639
583
|
case 'type':
|
|
640
584
|
openOverlay({ type: 'type-picker', targetIds });
|
|
@@ -644,11 +588,9 @@ export function WorkItemList() {
|
|
|
644
588
|
break;
|
|
645
589
|
case 'assignee':
|
|
646
590
|
openOverlay({ type: 'assignee-input', targetIds });
|
|
647
|
-
setAssigneeInput('');
|
|
648
591
|
break;
|
|
649
592
|
case 'labels':
|
|
650
593
|
openOverlay({ type: 'labels-input', targetIds });
|
|
651
|
-
setLabelsInput('');
|
|
652
594
|
break;
|
|
653
595
|
case 'delete':
|
|
654
596
|
openOverlay({ type: 'delete-confirm', targetIds });
|
|
@@ -662,128 +604,336 @@ export function WorkItemList() {
|
|
|
662
604
|
const positionText = treeItems.length > viewport.maxVisible
|
|
663
605
|
? `${cursor + 1}/${treeItems.length}`
|
|
664
606
|
: '';
|
|
665
|
-
return (_jsxs(Box, { flexDirection: "column", children: [
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
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) => {
|
|
670
686
|
closeOverlay();
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
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 {
|
|
674
791
|
for (const id of targetIds) {
|
|
675
|
-
await backend.cachedUpdateWorkItem(id, {
|
|
792
|
+
await backend.cachedUpdateWorkItem(id, {
|
|
793
|
+
parent: newParent,
|
|
794
|
+
});
|
|
676
795
|
await queueWrite('update', id);
|
|
677
796
|
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
}
|
|
683
|
-
}, onCancel: () => closeOverlay() })), activeOverlay?.type === 'type-picker' && (_jsx(TypePicker, { types: types, onSelect: (type) => {
|
|
684
|
-
const targetIds = getOverlayTargetIds();
|
|
797
|
+
clearWarning();
|
|
798
|
+
}
|
|
799
|
+
catch (e) {
|
|
800
|
+
setWarning(e instanceof Error ? e.message : 'Invalid parent');
|
|
801
|
+
}
|
|
685
802
|
closeOverlay();
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
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 {
|
|
689
820
|
for (const id of targetIds) {
|
|
690
|
-
await backend.cachedUpdateWorkItem(id, {
|
|
821
|
+
await backend.cachedUpdateWorkItem(id, {
|
|
822
|
+
parent: newParent,
|
|
823
|
+
});
|
|
691
824
|
await queueWrite('update', id);
|
|
692
825
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
}
|
|
698
|
-
}, onCancel: () => closeOverlay() })), activeOverlay?.type === 'priority-picker' && (_jsx(PriorityPicker, { onSelect: (priority) => {
|
|
699
|
-
const targetIds = getOverlayTargetIds();
|
|
826
|
+
clearWarning();
|
|
827
|
+
}
|
|
828
|
+
catch (e) {
|
|
829
|
+
setWarning(e instanceof Error ? e.message : 'Invalid parent');
|
|
830
|
+
}
|
|
700
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;
|
|
701
916
|
if (!backend)
|
|
702
917
|
return;
|
|
703
918
|
void (async () => {
|
|
704
919
|
for (const id of targetIds) {
|
|
705
|
-
await backend.
|
|
706
|
-
await queueWrite('
|
|
920
|
+
await backend.cachedDeleteWorkItem(id);
|
|
921
|
+
await queueWrite('delete', id);
|
|
922
|
+
}
|
|
923
|
+
closeOverlay();
|
|
924
|
+
for (const id of targetIds) {
|
|
925
|
+
removeDeletedItem(id);
|
|
707
926
|
}
|
|
927
|
+
setCursor(Math.max(0, cursor - 1));
|
|
708
928
|
refreshData();
|
|
709
929
|
setToast(targetIds.length === 1
|
|
710
|
-
?
|
|
711
|
-
: `${targetIds.length} items
|
|
930
|
+
? `Item #${targetIds[0]} deleted`
|
|
931
|
+
: `${targetIds.length} items deleted`);
|
|
712
932
|
})();
|
|
713
|
-
}
|
|
933
|
+
}
|
|
934
|
+
else {
|
|
714
935
|
closeOverlay();
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
selectWorkItem(null);
|
|
718
|
-
navigate('form');
|
|
719
|
-
}, 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: () => {
|
|
720
|
-
const targetIds = getOverlayTargetIds();
|
|
721
|
-
if (!backend)
|
|
722
|
-
return;
|
|
723
|
-
void (async () => {
|
|
724
|
-
const raw = parentInput.trim();
|
|
725
|
-
const newParent = raw === ''
|
|
726
|
-
? null
|
|
727
|
-
: raw.includes(' - ')
|
|
728
|
-
? raw.split(' - ')[0].trim()
|
|
729
|
-
: raw;
|
|
730
|
-
try {
|
|
731
|
-
for (const id of targetIds) {
|
|
732
|
-
await backend.cachedUpdateWorkItem(id, {
|
|
733
|
-
parent: newParent,
|
|
734
|
-
});
|
|
735
|
-
await queueWrite('update', id);
|
|
736
|
-
}
|
|
737
|
-
clearWarning();
|
|
738
|
-
}
|
|
739
|
-
catch (e) {
|
|
740
|
-
setWarning(e instanceof Error ? e.message : 'Invalid parent');
|
|
741
|
-
}
|
|
742
|
-
closeOverlay();
|
|
743
|
-
setParentInput('');
|
|
744
|
-
refreshData();
|
|
745
|
-
setToast(targetIds.length === 1
|
|
746
|
-
? 'Parent updated'
|
|
747
|
-
: `${targetIds.length} items updated`);
|
|
748
|
-
})();
|
|
749
|
-
} })] })) : 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: () => {
|
|
750
|
-
const targetIds = getOverlayTargetIds();
|
|
751
|
-
closeOverlay();
|
|
752
|
-
if (!backend)
|
|
753
|
-
return;
|
|
754
|
-
void (async () => {
|
|
755
|
-
const assignee = assigneeInput.trim();
|
|
756
|
-
for (const id of targetIds) {
|
|
757
|
-
await backend.cachedUpdateWorkItem(id, { assignee });
|
|
758
|
-
await queueWrite('update', id);
|
|
759
|
-
}
|
|
760
|
-
setAssigneeInput('');
|
|
761
|
-
refreshData();
|
|
762
|
-
setToast(targetIds.length === 1
|
|
763
|
-
? 'Assignee updated'
|
|
764
|
-
: `${targetIds.length} items updated`);
|
|
765
|
-
})();
|
|
766
|
-
} })] })) : 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: () => {
|
|
767
|
-
const targetIds = getOverlayTargetIds();
|
|
768
|
-
closeOverlay();
|
|
769
|
-
if (!backend)
|
|
770
|
-
return;
|
|
771
|
-
void (async () => {
|
|
772
|
-
const labels = labelsInput
|
|
773
|
-
.split(',')
|
|
774
|
-
.map((l) => l.trim())
|
|
775
|
-
.filter(Boolean);
|
|
776
|
-
for (const id of targetIds) {
|
|
777
|
-
await backend.cachedUpdateWorkItem(id, { labels });
|
|
778
|
-
await queueWrite('update', id);
|
|
779
|
-
}
|
|
780
|
-
setLabelsInput('');
|
|
781
|
-
refreshData();
|
|
782
|
-
setToast(targetIds.length === 1
|
|
783
|
-
? 'Labels updated'
|
|
784
|
-
: `${targetIds.length} items updated`);
|
|
785
|
-
})();
|
|
786
|
-
} })] })) : 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 -
|
|
787
|
-
(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"] }) }))] }));
|
|
788
938
|
}
|
|
789
939
|
//# sourceMappingURL=WorkItemList.js.map
|