@tomkapa/tayto 0.3.2 → 0.4.1
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/README.md +190 -111
- package/dist/{chunk-STYT4TGJ.js → chunk-74Q55TOV.js} +41 -2
- package/dist/chunk-74Q55TOV.js.map +1 -0
- package/dist/index.js +162 -80
- package/dist/index.js.map +1 -1
- package/dist/migrations/005_project_git_remote.sql +5 -0
- package/dist/{tui-JEP3F4JS.js → tui-IXZGQMWN.js} +308 -143
- package/dist/tui-IXZGQMWN.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-STYT4TGJ.js.map +0 -1
- package/dist/tui-JEP3F4JS.js.map +0 -1
|
@@ -5,16 +5,17 @@ import {
|
|
|
5
5
|
TaskStatus,
|
|
6
6
|
TaskType,
|
|
7
7
|
UIDependencyType,
|
|
8
|
+
detectGitRemote,
|
|
8
9
|
isTerminalStatus,
|
|
9
10
|
logger
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-74Q55TOV.js";
|
|
11
12
|
|
|
12
13
|
// src/tui/index.tsx
|
|
13
14
|
import { render } from "ink";
|
|
14
15
|
|
|
15
16
|
// src/tui/components/App.tsx
|
|
16
|
-
import { useReducer, useEffect as useEffect2, useCallback as useCallback2, useMemo as useMemo2, useState as
|
|
17
|
-
import { Box as
|
|
17
|
+
import { useReducer, useEffect as useEffect2, useCallback as useCallback2, useMemo as useMemo2, useState as useState7 } from "react";
|
|
18
|
+
import { Box as Box17, Text as Text17, useInput as useInput7, useApp, useStdout as useStdout4 } from "ink";
|
|
18
19
|
|
|
19
20
|
// src/tui/types.ts
|
|
20
21
|
var ViewType = {
|
|
@@ -26,6 +27,7 @@ var ViewType = {
|
|
|
26
27
|
ProjectCreate: "project-create",
|
|
27
28
|
DependencyList: "dependency-list",
|
|
28
29
|
EpicPicker: "epic-picker",
|
|
30
|
+
ProjectLink: "project-link",
|
|
29
31
|
Help: "help"
|
|
30
32
|
};
|
|
31
33
|
|
|
@@ -192,6 +194,7 @@ var initialState = {
|
|
|
192
194
|
epics: [],
|
|
193
195
|
epicSelectedIndex: 0,
|
|
194
196
|
selectedEpicIds: /* @__PURE__ */ new Set(),
|
|
197
|
+
linkingProject: null,
|
|
195
198
|
isEpicReordering: false,
|
|
196
199
|
epicReorderSnapshot: null
|
|
197
200
|
};
|
|
@@ -214,6 +217,7 @@ function appReducer(state, action) {
|
|
|
214
217
|
confirmDelete: null,
|
|
215
218
|
isSearchActive: false,
|
|
216
219
|
formData: null,
|
|
220
|
+
linkingProject: null,
|
|
217
221
|
focusedPanel: "list"
|
|
218
222
|
};
|
|
219
223
|
}
|
|
@@ -396,6 +400,8 @@ function appReducer(state, action) {
|
|
|
396
400
|
epicReorderSnapshot: null
|
|
397
401
|
};
|
|
398
402
|
}
|
|
403
|
+
case "SET_LINKING_PROJECT":
|
|
404
|
+
return { ...state, linkingProject: action.project };
|
|
399
405
|
}
|
|
400
406
|
}
|
|
401
407
|
|
|
@@ -1314,6 +1320,7 @@ function ProjectSelector({
|
|
|
1314
1320
|
onSelect,
|
|
1315
1321
|
onCreate,
|
|
1316
1322
|
onSetDefault,
|
|
1323
|
+
onLink,
|
|
1317
1324
|
onCancel
|
|
1318
1325
|
}) {
|
|
1319
1326
|
const [selectedIndex, setSelectedIndex] = useState3(() => {
|
|
@@ -1344,6 +1351,13 @@ function ProjectSelector({
|
|
|
1344
1351
|
}
|
|
1345
1352
|
return;
|
|
1346
1353
|
}
|
|
1354
|
+
if (input === "l") {
|
|
1355
|
+
const project = projects[selectedIndex];
|
|
1356
|
+
if (project) {
|
|
1357
|
+
onLink(project);
|
|
1358
|
+
}
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
1347
1361
|
if (key.upArrow || input === "k") {
|
|
1348
1362
|
setSelectedIndex((i) => Math.max(0, i - 1));
|
|
1349
1363
|
}
|
|
@@ -1365,6 +1379,7 @@ function ProjectSelector({
|
|
|
1365
1379
|
] }),
|
|
1366
1380
|
/* @__PURE__ */ jsxs7(Box9, { paddingX: 1, children: [
|
|
1367
1381
|
/* @__PURE__ */ jsx9(Text9, { color: theme.table.headerFg, bold: true, children: " NAME".padEnd(30) }),
|
|
1382
|
+
/* @__PURE__ */ jsx9(Text9, { color: theme.table.headerFg, bold: true, children: "GIT REMOTE".padEnd(40) }),
|
|
1368
1383
|
/* @__PURE__ */ jsx9(Text9, { color: theme.table.headerFg, bold: true, children: "DESCRIPTION" })
|
|
1369
1384
|
] }),
|
|
1370
1385
|
projects.length === 0 ? /* @__PURE__ */ jsx9(Box9, { paddingX: 1, paddingY: 1, children: /* @__PURE__ */ jsx9(Text9, { color: theme.fg, children: "No projects. Press 'c' to create one." }) }) : projects.map((project, i) => {
|
|
@@ -1373,11 +1388,13 @@ function ProjectSelector({
|
|
|
1373
1388
|
const activeMarker = isActive ? "*" : " ";
|
|
1374
1389
|
const defaultMarker = project.isDefault ? "D" : " ";
|
|
1375
1390
|
const marker = `${activeMarker}${defaultMarker}`;
|
|
1391
|
+
const remoteDisplay = (project.gitRemote ?? "").slice(0, 38).padEnd(40);
|
|
1376
1392
|
if (isSelected) {
|
|
1377
1393
|
return /* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsxs7(Text9, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
1378
1394
|
marker,
|
|
1379
1395
|
" ",
|
|
1380
1396
|
project.name.padEnd(27),
|
|
1397
|
+
remoteDisplay,
|
|
1381
1398
|
project.description
|
|
1382
1399
|
] }) }, project.id);
|
|
1383
1400
|
}
|
|
@@ -1387,11 +1404,12 @@ function ProjectSelector({
|
|
|
1387
1404
|
" ",
|
|
1388
1405
|
project.name.padEnd(27)
|
|
1389
1406
|
] }),
|
|
1407
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: remoteDisplay }),
|
|
1390
1408
|
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: project.description })
|
|
1391
1409
|
] }, project.id);
|
|
1392
1410
|
}),
|
|
1393
1411
|
/* @__PURE__ */ jsx9(Box9, { flexGrow: 1 }),
|
|
1394
|
-
/* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "enter: select | d: set default | c: create | esc: back" }) })
|
|
1412
|
+
/* @__PURE__ */ jsx9(Box9, { paddingX: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "enter: select | d: set default | l: link git | c: create | esc: back" }) })
|
|
1395
1413
|
] });
|
|
1396
1414
|
}
|
|
1397
1415
|
|
|
@@ -1490,9 +1508,86 @@ function ProjectForm({ onSave, onCancel }) {
|
|
|
1490
1508
|
] });
|
|
1491
1509
|
}
|
|
1492
1510
|
|
|
1493
|
-
// src/tui/components/
|
|
1494
|
-
import {
|
|
1511
|
+
// src/tui/components/ProjectLinkForm.tsx
|
|
1512
|
+
import { useState as useState5 } from "react";
|
|
1513
|
+
import { Box as Box11, Text as Text11, useInput as useInput5 } from "ink";
|
|
1495
1514
|
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1515
|
+
function ProjectLinkForm({ project, onSave, onUnlink, onDetect, onCancel }) {
|
|
1516
|
+
const [remoteUrl, setRemoteUrl] = useState5(project.gitRemote ?? "");
|
|
1517
|
+
useInput5((input, key) => {
|
|
1518
|
+
if (key.escape) {
|
|
1519
|
+
onCancel();
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1522
|
+
if (input === "s" && key.ctrl) {
|
|
1523
|
+
const trimmed = remoteUrl.trim();
|
|
1524
|
+
if (trimmed) {
|
|
1525
|
+
onSave(trimmed);
|
|
1526
|
+
}
|
|
1527
|
+
return;
|
|
1528
|
+
}
|
|
1529
|
+
if (input === "d" && key.ctrl) {
|
|
1530
|
+
const detected = onDetect();
|
|
1531
|
+
if (detected) {
|
|
1532
|
+
setRemoteUrl(detected);
|
|
1533
|
+
}
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
if (input === "u" && key.ctrl) {
|
|
1537
|
+
if (project.gitRemote) {
|
|
1538
|
+
onUnlink();
|
|
1539
|
+
}
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
if (key.backspace || key.delete) {
|
|
1543
|
+
setRemoteUrl((v) => v.slice(0, -1));
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1546
|
+
if (input && !key.ctrl && !key.meta) {
|
|
1547
|
+
setRemoteUrl((v) => v + input);
|
|
1548
|
+
}
|
|
1549
|
+
});
|
|
1550
|
+
return /* @__PURE__ */ jsxs9(Box11, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
|
|
1551
|
+
/* @__PURE__ */ jsxs9(Box11, { gap: 0, children: [
|
|
1552
|
+
/* @__PURE__ */ jsxs9(Text11, { color: theme.title, bold: true, children: [
|
|
1553
|
+
" ",
|
|
1554
|
+
"link git remote"
|
|
1555
|
+
] }),
|
|
1556
|
+
/* @__PURE__ */ jsxs9(Text11, { color: theme.titleCounter, bold: true, children: [
|
|
1557
|
+
" ",
|
|
1558
|
+
"[",
|
|
1559
|
+
project.name,
|
|
1560
|
+
"]"
|
|
1561
|
+
] })
|
|
1562
|
+
] }),
|
|
1563
|
+
/* @__PURE__ */ jsxs9(Box11, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [
|
|
1564
|
+
/* @__PURE__ */ jsxs9(Box11, { gap: 1, children: [
|
|
1565
|
+
/* @__PURE__ */ jsx11(Text11, { color: theme.dialog.label, bold: true, children: "Current:" }),
|
|
1566
|
+
/* @__PURE__ */ jsx11(
|
|
1567
|
+
Text11,
|
|
1568
|
+
{
|
|
1569
|
+
color: project.gitRemote ? theme.yaml.value : theme.table.fg,
|
|
1570
|
+
dimColor: !project.gitRemote,
|
|
1571
|
+
children: project.gitRemote ?? "(none)"
|
|
1572
|
+
}
|
|
1573
|
+
)
|
|
1574
|
+
] }),
|
|
1575
|
+
/* @__PURE__ */ jsxs9(Box11, { gap: 1, marginTop: 1, children: [
|
|
1576
|
+
/* @__PURE__ */ jsx11(Text11, { color: theme.dialog.label, bold: true, children: "Remote URL: " }),
|
|
1577
|
+
/* @__PURE__ */ jsxs9(Text11, { color: theme.yaml.value, children: [
|
|
1578
|
+
remoteUrl,
|
|
1579
|
+
/* @__PURE__ */ jsx11(Text11, { color: theme.titleHighlight, children: "_" })
|
|
1580
|
+
] })
|
|
1581
|
+
] })
|
|
1582
|
+
] }),
|
|
1583
|
+
/* @__PURE__ */ jsx11(Box11, { flexGrow: 1 }),
|
|
1584
|
+
/* @__PURE__ */ jsx11(Box11, { paddingX: 1, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "ctrl+s: save | ctrl+d: detect from cwd | ctrl+u: unlink | esc: cancel" }) })
|
|
1585
|
+
] });
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
// src/tui/components/HelpOverlay.tsx
|
|
1589
|
+
import { Box as Box12, Text as Text12 } from "ink";
|
|
1590
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1496
1591
|
var SECTIONS = [
|
|
1497
1592
|
{
|
|
1498
1593
|
title: "NAVIGATION",
|
|
@@ -1554,8 +1649,8 @@ var SECTIONS = [
|
|
|
1554
1649
|
}
|
|
1555
1650
|
];
|
|
1556
1651
|
function HelpOverlay() {
|
|
1557
|
-
return /* @__PURE__ */
|
|
1558
|
-
|
|
1652
|
+
return /* @__PURE__ */ jsxs10(
|
|
1653
|
+
Box12,
|
|
1559
1654
|
{
|
|
1560
1655
|
flexDirection: "column",
|
|
1561
1656
|
borderStyle: "bold",
|
|
@@ -1563,35 +1658,35 @@ function HelpOverlay() {
|
|
|
1563
1658
|
paddingX: 2,
|
|
1564
1659
|
paddingY: 1,
|
|
1565
1660
|
children: [
|
|
1566
|
-
/* @__PURE__ */
|
|
1661
|
+
/* @__PURE__ */ jsxs10(Text12, { color: theme.title, bold: true, children: [
|
|
1567
1662
|
" ",
|
|
1568
1663
|
"Help"
|
|
1569
1664
|
] }),
|
|
1570
|
-
/* @__PURE__ */
|
|
1571
|
-
/* @__PURE__ */
|
|
1572
|
-
/* @__PURE__ */
|
|
1573
|
-
section.keys.map(([key, desc]) => /* @__PURE__ */
|
|
1574
|
-
/* @__PURE__ */
|
|
1665
|
+
/* @__PURE__ */ jsx12(Text12, { children: " " }),
|
|
1666
|
+
/* @__PURE__ */ jsx12(Box12, { flexDirection: "row", gap: 4, children: SECTIONS.map((section) => /* @__PURE__ */ jsxs10(Box12, { flexDirection: "column", children: [
|
|
1667
|
+
/* @__PURE__ */ jsx12(Text12, { color: theme.table.headerFg, bold: true, children: section.title }),
|
|
1668
|
+
section.keys.map(([key, desc]) => /* @__PURE__ */ jsxs10(Box12, { gap: 1, children: [
|
|
1669
|
+
/* @__PURE__ */ jsxs10(Text12, { color: theme.menu.key, bold: true, children: [
|
|
1575
1670
|
"<",
|
|
1576
1671
|
(key ?? "").padEnd(5),
|
|
1577
1672
|
">"
|
|
1578
1673
|
] }),
|
|
1579
|
-
/* @__PURE__ */
|
|
1674
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: desc })
|
|
1580
1675
|
] }, key))
|
|
1581
1676
|
] }, section.title)) }),
|
|
1582
|
-
/* @__PURE__ */
|
|
1583
|
-
/* @__PURE__ */
|
|
1677
|
+
/* @__PURE__ */ jsx12(Text12, { children: " " }),
|
|
1678
|
+
/* @__PURE__ */ jsx12(Text12, { dimColor: true, children: "Press any key to close" })
|
|
1584
1679
|
]
|
|
1585
1680
|
}
|
|
1586
1681
|
);
|
|
1587
1682
|
}
|
|
1588
1683
|
|
|
1589
1684
|
// src/tui/components/ConfirmDialog.tsx
|
|
1590
|
-
import { Box as
|
|
1591
|
-
import { jsx as
|
|
1685
|
+
import { Box as Box13, Text as Text13 } from "ink";
|
|
1686
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1592
1687
|
function ConfirmDialog({ task }) {
|
|
1593
|
-
return /* @__PURE__ */
|
|
1594
|
-
|
|
1688
|
+
return /* @__PURE__ */ jsxs11(
|
|
1689
|
+
Box13,
|
|
1595
1690
|
{
|
|
1596
1691
|
flexDirection: "column",
|
|
1597
1692
|
borderStyle: "bold",
|
|
@@ -1600,17 +1695,17 @@ function ConfirmDialog({ task }) {
|
|
|
1600
1695
|
paddingY: 1,
|
|
1601
1696
|
alignSelf: "center",
|
|
1602
1697
|
children: [
|
|
1603
|
-
/* @__PURE__ */
|
|
1604
|
-
/* @__PURE__ */
|
|
1605
|
-
/* @__PURE__ */
|
|
1698
|
+
/* @__PURE__ */ jsx13(Text13, { color: theme.dialog.label, bold: true, children: "<Delete>" }),
|
|
1699
|
+
/* @__PURE__ */ jsx13(Text13, { children: " " }),
|
|
1700
|
+
/* @__PURE__ */ jsxs11(Text13, { color: theme.dialog.fg, children: [
|
|
1606
1701
|
'Delete task "',
|
|
1607
1702
|
task.name,
|
|
1608
1703
|
'"?'
|
|
1609
1704
|
] }),
|
|
1610
|
-
/* @__PURE__ */
|
|
1611
|
-
/* @__PURE__ */
|
|
1612
|
-
/* @__PURE__ */
|
|
1613
|
-
|
|
1705
|
+
/* @__PURE__ */ jsx13(Text13, { children: " " }),
|
|
1706
|
+
/* @__PURE__ */ jsxs11(Box13, { gap: 3, children: [
|
|
1707
|
+
/* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsx13(
|
|
1708
|
+
Text13,
|
|
1614
1709
|
{
|
|
1615
1710
|
backgroundColor: theme.dialog.buttonFocusBg,
|
|
1616
1711
|
color: theme.dialog.buttonFocusFg,
|
|
@@ -1618,7 +1713,7 @@ function ConfirmDialog({ task }) {
|
|
|
1618
1713
|
children: " y: OK "
|
|
1619
1714
|
}
|
|
1620
1715
|
) }),
|
|
1621
|
-
/* @__PURE__ */
|
|
1716
|
+
/* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsx13(Text13, { backgroundColor: theme.dialog.buttonBg, color: theme.dialog.buttonFg, children: " n: Cancel " }) })
|
|
1622
1717
|
] })
|
|
1623
1718
|
]
|
|
1624
1719
|
}
|
|
@@ -1626,8 +1721,8 @@ function ConfirmDialog({ task }) {
|
|
|
1626
1721
|
}
|
|
1627
1722
|
|
|
1628
1723
|
// src/tui/components/DependencyList.tsx
|
|
1629
|
-
import { Box as
|
|
1630
|
-
import { Fragment as Fragment2, jsx as
|
|
1724
|
+
import { Box as Box14, Text as Text14 } from "ink";
|
|
1725
|
+
import { Fragment as Fragment2, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1631
1726
|
function TaskRow({
|
|
1632
1727
|
task,
|
|
1633
1728
|
globalIndex,
|
|
@@ -1635,16 +1730,16 @@ function TaskRow({
|
|
|
1635
1730
|
}) {
|
|
1636
1731
|
const isSelected = globalIndex === selectedIndex;
|
|
1637
1732
|
const statusColor = STATUS_COLOR[task.status] ?? theme.table.fg;
|
|
1638
|
-
return /* @__PURE__ */
|
|
1733
|
+
return /* @__PURE__ */ jsx14(Box14, { children: isSelected ? /* @__PURE__ */ jsxs12(Text14, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
1639
1734
|
"> ",
|
|
1640
1735
|
task.id.padEnd(12),
|
|
1641
1736
|
task.status.padEnd(14),
|
|
1642
1737
|
task.name
|
|
1643
|
-
] }) : /* @__PURE__ */
|
|
1644
|
-
/* @__PURE__ */
|
|
1645
|
-
/* @__PURE__ */
|
|
1646
|
-
/* @__PURE__ */
|
|
1647
|
-
/* @__PURE__ */
|
|
1738
|
+
] }) : /* @__PURE__ */ jsxs12(Fragment2, { children: [
|
|
1739
|
+
/* @__PURE__ */ jsx14(Text14, { children: " " }),
|
|
1740
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.yaml.value, children: task.id.padEnd(12) }),
|
|
1741
|
+
/* @__PURE__ */ jsx14(Text14, { color: statusColor, children: task.status.padEnd(14) }),
|
|
1742
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.table.fg, children: task.name })
|
|
1648
1743
|
] }) }, task.id);
|
|
1649
1744
|
}
|
|
1650
1745
|
function DependencyList({
|
|
@@ -1665,23 +1760,23 @@ function DependencyList({
|
|
|
1665
1760
|
const relatedOffset = offset;
|
|
1666
1761
|
offset += related.length;
|
|
1667
1762
|
const duplicatesOffset = offset;
|
|
1668
|
-
return /* @__PURE__ */
|
|
1669
|
-
/* @__PURE__ */
|
|
1670
|
-
/* @__PURE__ */
|
|
1763
|
+
return /* @__PURE__ */ jsxs12(Box14, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.borderFocus, children: [
|
|
1764
|
+
/* @__PURE__ */ jsxs12(Box14, { gap: 0, children: [
|
|
1765
|
+
/* @__PURE__ */ jsxs12(Text14, { color: theme.title, bold: true, children: [
|
|
1671
1766
|
" ",
|
|
1672
1767
|
"dependencies"
|
|
1673
1768
|
] }),
|
|
1674
|
-
/* @__PURE__ */
|
|
1675
|
-
/* @__PURE__ */
|
|
1676
|
-
/* @__PURE__ */
|
|
1769
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.fg, children: "(" }),
|
|
1770
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.titleHighlight, bold: true, children: task.name }),
|
|
1771
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.fg, children: ")" })
|
|
1677
1772
|
] }),
|
|
1678
|
-
/* @__PURE__ */
|
|
1679
|
-
/* @__PURE__ */
|
|
1773
|
+
/* @__PURE__ */ jsxs12(Box14, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
1774
|
+
/* @__PURE__ */ jsxs12(Text14, { color: theme.table.headerFg, bold: true, children: [
|
|
1680
1775
|
"BLOCKED BY (",
|
|
1681
1776
|
blockers.length,
|
|
1682
1777
|
")"
|
|
1683
1778
|
] }),
|
|
1684
|
-
blockers.length === 0 ? /* @__PURE__ */
|
|
1779
|
+
blockers.length === 0 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " No blockers" }) : blockers.map((t, i) => /* @__PURE__ */ jsx14(
|
|
1685
1780
|
TaskRow,
|
|
1686
1781
|
{
|
|
1687
1782
|
task: t,
|
|
@@ -1691,13 +1786,13 @@ function DependencyList({
|
|
|
1691
1786
|
t.id
|
|
1692
1787
|
))
|
|
1693
1788
|
] }),
|
|
1694
|
-
/* @__PURE__ */
|
|
1695
|
-
/* @__PURE__ */
|
|
1789
|
+
/* @__PURE__ */ jsxs12(Box14, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
1790
|
+
/* @__PURE__ */ jsxs12(Text14, { color: theme.table.headerFg, bold: true, children: [
|
|
1696
1791
|
"BLOCKS (",
|
|
1697
1792
|
dependents.length,
|
|
1698
1793
|
")"
|
|
1699
1794
|
] }),
|
|
1700
|
-
dependents.length === 0 ? /* @__PURE__ */
|
|
1795
|
+
dependents.length === 0 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " No dependents" }) : dependents.map((t, i) => /* @__PURE__ */ jsx14(
|
|
1701
1796
|
TaskRow,
|
|
1702
1797
|
{
|
|
1703
1798
|
task: t,
|
|
@@ -1707,13 +1802,13 @@ function DependencyList({
|
|
|
1707
1802
|
t.id
|
|
1708
1803
|
))
|
|
1709
1804
|
] }),
|
|
1710
|
-
/* @__PURE__ */
|
|
1711
|
-
/* @__PURE__ */
|
|
1805
|
+
/* @__PURE__ */ jsxs12(Box14, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
1806
|
+
/* @__PURE__ */ jsxs12(Text14, { color: theme.table.headerFg, bold: true, children: [
|
|
1712
1807
|
"RELATES TO (",
|
|
1713
1808
|
related.length,
|
|
1714
1809
|
")"
|
|
1715
1810
|
] }),
|
|
1716
|
-
related.length === 0 ? /* @__PURE__ */
|
|
1811
|
+
related.length === 0 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " No related tasks" }) : related.map((t, i) => /* @__PURE__ */ jsx14(
|
|
1717
1812
|
TaskRow,
|
|
1718
1813
|
{
|
|
1719
1814
|
task: t,
|
|
@@ -1723,13 +1818,13 @@ function DependencyList({
|
|
|
1723
1818
|
t.id
|
|
1724
1819
|
))
|
|
1725
1820
|
] }),
|
|
1726
|
-
/* @__PURE__ */
|
|
1727
|
-
/* @__PURE__ */
|
|
1821
|
+
/* @__PURE__ */ jsxs12(Box14, { flexDirection: "column", paddingX: 1, paddingTop: 1, children: [
|
|
1822
|
+
/* @__PURE__ */ jsxs12(Text14, { color: theme.table.headerFg, bold: true, children: [
|
|
1728
1823
|
"DUPLICATES (",
|
|
1729
1824
|
duplicates.length,
|
|
1730
1825
|
")"
|
|
1731
1826
|
] }),
|
|
1732
|
-
duplicates.length === 0 ? /* @__PURE__ */
|
|
1827
|
+
duplicates.length === 0 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " No duplicate tasks" }) : duplicates.map((t, i) => /* @__PURE__ */ jsx14(
|
|
1733
1828
|
TaskRow,
|
|
1734
1829
|
{
|
|
1735
1830
|
task: t,
|
|
@@ -1739,19 +1834,19 @@ function DependencyList({
|
|
|
1739
1834
|
t.id
|
|
1740
1835
|
))
|
|
1741
1836
|
] }),
|
|
1742
|
-
/* @__PURE__ */
|
|
1743
|
-
isAddingDep && /* @__PURE__ */
|
|
1744
|
-
/* @__PURE__ */
|
|
1745
|
-
/* @__PURE__ */
|
|
1746
|
-
/* @__PURE__ */
|
|
1837
|
+
/* @__PURE__ */ jsx14(Box14, { flexGrow: 1 }),
|
|
1838
|
+
isAddingDep && /* @__PURE__ */ jsxs12(Box14, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
|
|
1839
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.prompt, children: "depends on (id or id:type): " }),
|
|
1840
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.prompt, children: addDepInput }),
|
|
1841
|
+
/* @__PURE__ */ jsx14(Text14, { color: theme.promptSuggest, children: "_" })
|
|
1747
1842
|
] }),
|
|
1748
|
-
/* @__PURE__ */
|
|
1843
|
+
/* @__PURE__ */ jsx14(Box14, { paddingX: 1, children: /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "a: add dep (id or id:relates-to) | x: remove selected | enter: go to task | esc: back" }) })
|
|
1749
1844
|
] });
|
|
1750
1845
|
}
|
|
1751
1846
|
|
|
1752
1847
|
// src/tui/components/EpicPanel.tsx
|
|
1753
|
-
import { Box as
|
|
1754
|
-
import { jsx as
|
|
1848
|
+
import { Box as Box15, Text as Text15 } from "ink";
|
|
1849
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1755
1850
|
var PAGE_SIZE2 = 20;
|
|
1756
1851
|
function EpicPanel({
|
|
1757
1852
|
epics,
|
|
@@ -1764,34 +1859,34 @@ function EpicPanel({
|
|
|
1764
1859
|
const currentPage = Math.floor(selectedIndex / PAGE_SIZE2);
|
|
1765
1860
|
const viewStart = currentPage * PAGE_SIZE2;
|
|
1766
1861
|
const visibleEpics = epics.slice(viewStart, viewStart + PAGE_SIZE2);
|
|
1767
|
-
return /* @__PURE__ */
|
|
1768
|
-
|
|
1862
|
+
return /* @__PURE__ */ jsxs13(
|
|
1863
|
+
Box15,
|
|
1769
1864
|
{
|
|
1770
1865
|
flexDirection: "column",
|
|
1771
1866
|
width: 48,
|
|
1772
1867
|
borderStyle: "bold",
|
|
1773
1868
|
borderColor: isFocused ? theme.borderFocus : theme.border,
|
|
1774
1869
|
children: [
|
|
1775
|
-
/* @__PURE__ */
|
|
1776
|
-
/* @__PURE__ */
|
|
1870
|
+
/* @__PURE__ */ jsxs13(Box15, { children: [
|
|
1871
|
+
/* @__PURE__ */ jsxs13(Text15, { color: theme.title, bold: true, children: [
|
|
1777
1872
|
" ",
|
|
1778
1873
|
"epics"
|
|
1779
1874
|
] }),
|
|
1780
|
-
/* @__PURE__ */
|
|
1875
|
+
/* @__PURE__ */ jsxs13(Text15, { color: theme.titleCounter, bold: true, children: [
|
|
1781
1876
|
"[",
|
|
1782
1877
|
epics.length,
|
|
1783
1878
|
"]"
|
|
1784
1879
|
] }),
|
|
1785
|
-
isReordering && /* @__PURE__ */
|
|
1880
|
+
isReordering && /* @__PURE__ */ jsxs13(Text15, { color: theme.flash.warn, bold: true, children: [
|
|
1786
1881
|
" ",
|
|
1787
1882
|
"REORDER"
|
|
1788
1883
|
] }),
|
|
1789
|
-
filterActive && /* @__PURE__ */
|
|
1884
|
+
filterActive && /* @__PURE__ */ jsxs13(Text15, { color: theme.titleFilter, children: [
|
|
1790
1885
|
" *",
|
|
1791
1886
|
selectedEpicIds.size
|
|
1792
1887
|
] })
|
|
1793
1888
|
] }),
|
|
1794
|
-
/* @__PURE__ */
|
|
1889
|
+
/* @__PURE__ */ jsx15(Box15, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: epics.length === 0 ? /* @__PURE__ */ jsx15(Box15, { paddingX: 1, children: /* @__PURE__ */ jsx15(Text15, { dimColor: true, children: "No epics" }) }) : visibleEpics.map((epic, i) => {
|
|
1795
1890
|
const actualIndex = viewStart + i;
|
|
1796
1891
|
const isSelected = actualIndex === selectedIndex && isFocused;
|
|
1797
1892
|
const isChecked = selectedEpicIds.has(epic.id);
|
|
@@ -1799,21 +1894,21 @@ function EpicPanel({
|
|
|
1799
1894
|
const statusColor = STATUS_COLOR[epic.status] ?? theme.table.fg;
|
|
1800
1895
|
if (isSelected) {
|
|
1801
1896
|
const cursorBg = isReordering ? theme.flash.warn : theme.table.cursorBg;
|
|
1802
|
-
return /* @__PURE__ */
|
|
1897
|
+
return /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsxs13(Text15, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
1803
1898
|
isReordering ? "~ " : " ",
|
|
1804
1899
|
marker,
|
|
1805
1900
|
" ",
|
|
1806
1901
|
epic.name
|
|
1807
1902
|
] }) }, epic.id);
|
|
1808
1903
|
}
|
|
1809
|
-
return /* @__PURE__ */
|
|
1904
|
+
return /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsxs13(Text15, { color: isChecked ? theme.titleHighlight : statusColor, children: [
|
|
1810
1905
|
" ",
|
|
1811
1906
|
marker,
|
|
1812
1907
|
" ",
|
|
1813
1908
|
epic.name
|
|
1814
1909
|
] }) }, epic.id);
|
|
1815
1910
|
}) }),
|
|
1816
|
-
epics.length > PAGE_SIZE2 && /* @__PURE__ */
|
|
1911
|
+
epics.length > PAGE_SIZE2 && /* @__PURE__ */ jsx15(Box15, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs13(Text15, { dimColor: true, children: [
|
|
1817
1912
|
"[",
|
|
1818
1913
|
viewStart + 1,
|
|
1819
1914
|
"-",
|
|
@@ -1828,16 +1923,16 @@ function EpicPanel({
|
|
|
1828
1923
|
}
|
|
1829
1924
|
|
|
1830
1925
|
// src/tui/components/EpicPicker.tsx
|
|
1831
|
-
import { useState as
|
|
1832
|
-
import { Box as
|
|
1833
|
-
import { Fragment as Fragment3, jsx as
|
|
1926
|
+
import { useState as useState6 } from "react";
|
|
1927
|
+
import { Box as Box16, Text as Text16, useInput as useInput6, useStdout as useStdout3 } from "ink";
|
|
1928
|
+
import { Fragment as Fragment3, jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1834
1929
|
function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
1835
1930
|
const { stdout } = useStdout3();
|
|
1836
1931
|
const termHeight = stdout.rows > 0 ? stdout.rows : 24;
|
|
1837
1932
|
const maxVisible = Math.max(3, termHeight - 10);
|
|
1838
|
-
const [searchQuery, setSearchQuery] =
|
|
1839
|
-
const [isSearching, setIsSearching] =
|
|
1840
|
-
const [cursorIndex, setCursorIndex] =
|
|
1933
|
+
const [searchQuery, setSearchQuery] = useState6("");
|
|
1934
|
+
const [isSearching, setIsSearching] = useState6(false);
|
|
1935
|
+
const [cursorIndex, setCursorIndex] = useState6(0);
|
|
1841
1936
|
const filtered = epics.filter((e) => {
|
|
1842
1937
|
if (!searchQuery.trim()) return true;
|
|
1843
1938
|
const q = searchQuery.toLowerCase();
|
|
@@ -1851,7 +1946,7 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
|
1851
1946
|
viewStart = cursorIndex;
|
|
1852
1947
|
}
|
|
1853
1948
|
const visible = filtered.slice(viewStart, viewStart + maxVisible);
|
|
1854
|
-
|
|
1949
|
+
useInput6((input, key) => {
|
|
1855
1950
|
if (isSearching) {
|
|
1856
1951
|
if (key.escape) {
|
|
1857
1952
|
setIsSearching(false);
|
|
@@ -1903,53 +1998,53 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
|
1903
1998
|
return;
|
|
1904
1999
|
}
|
|
1905
2000
|
});
|
|
1906
|
-
return /* @__PURE__ */
|
|
1907
|
-
/* @__PURE__ */
|
|
1908
|
-
/* @__PURE__ */
|
|
2001
|
+
return /* @__PURE__ */ jsxs14(Box16, { flexDirection: "column", borderStyle: "bold", borderColor: theme.borderFocus, flexGrow: 1, children: [
|
|
2002
|
+
/* @__PURE__ */ jsxs14(Box16, { gap: 0, children: [
|
|
2003
|
+
/* @__PURE__ */ jsxs14(Text16, { color: theme.title, bold: true, children: [
|
|
1909
2004
|
" ",
|
|
1910
2005
|
"assign to epic"
|
|
1911
2006
|
] }),
|
|
1912
|
-
/* @__PURE__ */
|
|
2007
|
+
/* @__PURE__ */ jsxs14(Text16, { color: theme.titleCounter, bold: true, children: [
|
|
1913
2008
|
" ",
|
|
1914
2009
|
"[",
|
|
1915
2010
|
epics.length,
|
|
1916
2011
|
"]"
|
|
1917
2012
|
] })
|
|
1918
2013
|
] }),
|
|
1919
|
-
isSearching ? /* @__PURE__ */
|
|
1920
|
-
/* @__PURE__ */
|
|
1921
|
-
/* @__PURE__ */
|
|
1922
|
-
/* @__PURE__ */
|
|
1923
|
-
] }) : searchQuery ? /* @__PURE__ */
|
|
2014
|
+
isSearching ? /* @__PURE__ */ jsxs14(Box16, { borderStyle: "round", borderColor: theme.prompt, paddingX: 1, children: [
|
|
2015
|
+
/* @__PURE__ */ jsx16(Text16, { color: theme.prompt, children: "/" }),
|
|
2016
|
+
/* @__PURE__ */ jsx16(Text16, { color: theme.prompt, children: searchQuery }),
|
|
2017
|
+
/* @__PURE__ */ jsx16(Text16, { color: theme.promptSuggest, children: "_" })
|
|
2018
|
+
] }) : searchQuery ? /* @__PURE__ */ jsx16(Box16, { paddingX: 1, children: /* @__PURE__ */ jsxs14(Text16, { color: theme.titleFilter, children: [
|
|
1924
2019
|
"/",
|
|
1925
2020
|
searchQuery
|
|
1926
2021
|
] }) }) : null,
|
|
1927
|
-
/* @__PURE__ */
|
|
2022
|
+
/* @__PURE__ */ jsx16(Box16, { paddingX: 1, children: /* @__PURE__ */ jsxs14(Text16, { color: theme.table.headerFg, bold: true, children: [
|
|
1928
2023
|
" ",
|
|
1929
2024
|
"ID".padEnd(14),
|
|
1930
2025
|
"STATUS".padEnd(14),
|
|
1931
2026
|
"NAME"
|
|
1932
2027
|
] }) }),
|
|
1933
|
-
filtered.length === 0 ? /* @__PURE__ */
|
|
2028
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx16(Box16, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "No epics match the filter" }) }) : visible.map((epic, i) => {
|
|
1934
2029
|
const actualIndex = viewStart + i;
|
|
1935
2030
|
const isCursor = actualIndex === cursorIndex;
|
|
1936
2031
|
const isCurrent = epic.id === currentEpicId;
|
|
1937
2032
|
const marker = isCurrent ? "* " : " ";
|
|
1938
2033
|
const statusColor = STATUS_COLOR[epic.status] ?? theme.table.fg;
|
|
1939
|
-
return /* @__PURE__ */
|
|
2034
|
+
return /* @__PURE__ */ jsx16(Box16, { paddingX: 1, children: isCursor ? /* @__PURE__ */ jsxs14(Text16, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
1940
2035
|
"> ",
|
|
1941
2036
|
epic.id.padEnd(14),
|
|
1942
2037
|
epic.status.padEnd(14),
|
|
1943
2038
|
epic.name
|
|
1944
|
-
] }) : /* @__PURE__ */
|
|
1945
|
-
/* @__PURE__ */
|
|
1946
|
-
/* @__PURE__ */
|
|
1947
|
-
/* @__PURE__ */
|
|
1948
|
-
/* @__PURE__ */
|
|
2039
|
+
] }) : /* @__PURE__ */ jsxs14(Fragment3, { children: [
|
|
2040
|
+
/* @__PURE__ */ jsx16(Text16, { color: isCurrent ? theme.titleHighlight : theme.table.fg, children: marker }),
|
|
2041
|
+
/* @__PURE__ */ jsx16(Text16, { color: theme.yaml.value, children: epic.id.padEnd(14) }),
|
|
2042
|
+
/* @__PURE__ */ jsx16(Text16, { color: statusColor, children: epic.status.padEnd(14) }),
|
|
2043
|
+
/* @__PURE__ */ jsx16(Text16, { color: isCurrent ? theme.titleHighlight : theme.table.fg, children: epic.name })
|
|
1949
2044
|
] }) }, epic.id);
|
|
1950
2045
|
}),
|
|
1951
|
-
/* @__PURE__ */
|
|
1952
|
-
filtered.length > maxVisible && /* @__PURE__ */
|
|
2046
|
+
/* @__PURE__ */ jsx16(Box16, { flexGrow: 1 }),
|
|
2047
|
+
filtered.length > maxVisible && /* @__PURE__ */ jsx16(Box16, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs14(Text16, { dimColor: true, children: [
|
|
1953
2048
|
"[",
|
|
1954
2049
|
viewStart + 1,
|
|
1955
2050
|
"-",
|
|
@@ -1958,7 +2053,7 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
|
1958
2053
|
filtered.length,
|
|
1959
2054
|
"]"
|
|
1960
2055
|
] }) }),
|
|
1961
|
-
/* @__PURE__ */
|
|
2056
|
+
/* @__PURE__ */ jsx16(Box16, { paddingX: 1, children: /* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "enter: assign | x: unassign | /: search | esc: cancel" }) })
|
|
1962
2057
|
] });
|
|
1963
2058
|
}
|
|
1964
2059
|
|
|
@@ -1998,7 +2093,7 @@ function useAutoRefetch(dbPath, onRefetch) {
|
|
|
1998
2093
|
}
|
|
1999
2094
|
|
|
2000
2095
|
// src/tui/components/App.tsx
|
|
2001
|
-
import { jsx as
|
|
2096
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2002
2097
|
var STATUS_CYCLE = [
|
|
2003
2098
|
TaskStatus.Backlog,
|
|
2004
2099
|
TaskStatus.Todo,
|
|
@@ -2011,7 +2106,7 @@ function App({ container, initialProject }) {
|
|
|
2011
2106
|
const { exit } = useApp();
|
|
2012
2107
|
const { stdout } = useStdout4();
|
|
2013
2108
|
const [state, dispatch] = useReducer(appReducer, initialState);
|
|
2014
|
-
const [, setResizeTick] =
|
|
2109
|
+
const [, setResizeTick] = useState7(0);
|
|
2015
2110
|
useEffect2(() => {
|
|
2016
2111
|
const onResize = () => {
|
|
2017
2112
|
setResizeTick((n) => n + 1);
|
|
@@ -2036,15 +2131,14 @@ function App({ container, initialProject }) {
|
|
|
2036
2131
|
}
|
|
2037
2132
|
}, [container]);
|
|
2038
2133
|
const loadTasks = useCallback2(() => {
|
|
2134
|
+
const activeProject = state.activeProject;
|
|
2135
|
+
if (!activeProject) return;
|
|
2039
2136
|
logger.startSpan("TUI.loadTasks", () => {
|
|
2040
2137
|
const filter = { ...state.filter, level: TaskLevel.Work };
|
|
2041
|
-
if (state.activeProject) {
|
|
2042
|
-
filter.projectId = state.activeProject.id;
|
|
2043
|
-
}
|
|
2044
2138
|
if (state.selectedEpicIds.size > 0) {
|
|
2045
2139
|
filter.parentIds = [...state.selectedEpicIds];
|
|
2046
2140
|
}
|
|
2047
|
-
const result = container.taskService.listTasks(filter);
|
|
2141
|
+
const result = container.taskService.listTasks(activeProject, filter);
|
|
2048
2142
|
if (result.ok) {
|
|
2049
2143
|
logger.info(`TUI.loadTasks: loaded ${result.value.length} tasks`);
|
|
2050
2144
|
dispatch({ type: "SET_TASKS", tasks: result.value });
|
|
@@ -2056,8 +2150,7 @@ function App({ container, initialProject }) {
|
|
|
2056
2150
|
}, [container, state.filter, state.activeProject, state.selectedEpicIds]);
|
|
2057
2151
|
const loadEpics = useCallback2(() => {
|
|
2058
2152
|
if (!state.activeProject) return;
|
|
2059
|
-
const result = container.taskService.listTasks({
|
|
2060
|
-
projectId: state.activeProject.id,
|
|
2153
|
+
const result = container.taskService.listTasks(state.activeProject, {
|
|
2061
2154
|
level: TaskLevel.Epic
|
|
2062
2155
|
});
|
|
2063
2156
|
if (result.ok) {
|
|
@@ -2102,13 +2195,15 @@ function App({ container, initialProject }) {
|
|
|
2102
2195
|
[container, state.selectedTask, loadTasks, loadEpics]
|
|
2103
2196
|
);
|
|
2104
2197
|
const saveReorder = useCallback2(() => {
|
|
2198
|
+
const activeProject = state.activeProject;
|
|
2199
|
+
if (!activeProject) return;
|
|
2105
2200
|
const tasks = state.tasks;
|
|
2106
2201
|
const idx = state.selectedIndex;
|
|
2107
2202
|
const task = tasks[idx];
|
|
2108
2203
|
if (!task) return;
|
|
2109
2204
|
const prev = tasks[idx - 1];
|
|
2110
2205
|
const next = tasks[idx + 1];
|
|
2111
|
-
const result = prev ? container.taskService.rerankTask({ taskId: task.id, afterId: prev.id }) : next ? container.taskService.rerankTask({ taskId: task.id, beforeId: next.id }) : container.taskService.rerankTask({ taskId: task.id, position: 1 });
|
|
2206
|
+
const result = prev ? container.taskService.rerankTask({ taskId: task.id, afterId: prev.id }, activeProject) : next ? container.taskService.rerankTask({ taskId: task.id, beforeId: next.id }, activeProject) : container.taskService.rerankTask({ taskId: task.id, position: 1 }, activeProject);
|
|
2112
2207
|
dispatch({ type: "EXIT_REORDER", save: result.ok });
|
|
2113
2208
|
dispatch({
|
|
2114
2209
|
type: "FLASH",
|
|
@@ -2118,13 +2213,15 @@ function App({ container, initialProject }) {
|
|
|
2118
2213
|
loadTasks();
|
|
2119
2214
|
}, [container, state.tasks, state.selectedIndex, loadTasks]);
|
|
2120
2215
|
const saveEpicReorder = useCallback2(() => {
|
|
2216
|
+
const activeProject = state.activeProject;
|
|
2217
|
+
if (!activeProject) return;
|
|
2121
2218
|
const epics = state.epics;
|
|
2122
2219
|
const idx = state.epicSelectedIndex;
|
|
2123
2220
|
const epic = epics[idx];
|
|
2124
2221
|
if (!epic) return;
|
|
2125
2222
|
const prev = epics[idx - 1];
|
|
2126
2223
|
const next = epics[idx + 1];
|
|
2127
|
-
const result = prev ? container.taskService.rerankTask({ taskId: epic.id, afterId: prev.id }) : next ? container.taskService.rerankTask({ taskId: epic.id, beforeId: next.id }) : container.taskService.rerankTask({ taskId: epic.id, position: 1 });
|
|
2224
|
+
const result = prev ? container.taskService.rerankTask({ taskId: epic.id, afterId: prev.id }, activeProject) : next ? container.taskService.rerankTask({ taskId: epic.id, beforeId: next.id }, activeProject) : container.taskService.rerankTask({ taskId: epic.id, position: 1 }, activeProject);
|
|
2128
2225
|
dispatch({ type: "EXIT_EPIC_REORDER", save: result.ok });
|
|
2129
2226
|
dispatch({
|
|
2130
2227
|
type: "FLASH",
|
|
@@ -2135,13 +2232,18 @@ function App({ container, initialProject }) {
|
|
|
2135
2232
|
}, [container, state.epics, state.epicSelectedIndex, loadEpics]);
|
|
2136
2233
|
const rerankSelectedToEdge = useCallback2(
|
|
2137
2234
|
(kind, edge) => {
|
|
2235
|
+
const activeProject = state.activeProject;
|
|
2236
|
+
if (!activeProject) return;
|
|
2138
2237
|
const isEpic = kind === "epic";
|
|
2139
2238
|
const item = isEpic ? state.epics[state.epicSelectedIndex] : state.tasks[state.selectedIndex];
|
|
2140
2239
|
if (!item) return;
|
|
2141
|
-
const result = container.taskService.rerankTask(
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2240
|
+
const result = container.taskService.rerankTask(
|
|
2241
|
+
{
|
|
2242
|
+
taskId: item.id,
|
|
2243
|
+
...edge === "top" ? { top: true } : { bottom: true }
|
|
2244
|
+
},
|
|
2245
|
+
activeProject
|
|
2246
|
+
);
|
|
2145
2247
|
dispatch({
|
|
2146
2248
|
type: isEpic ? "EXIT_EPIC_REORDER" : "EXIT_REORDER",
|
|
2147
2249
|
save: result.ok
|
|
@@ -2207,7 +2309,7 @@ function App({ container, initialProject }) {
|
|
|
2207
2309
|
}
|
|
2208
2310
|
return void 0;
|
|
2209
2311
|
}, [state.flash]);
|
|
2210
|
-
|
|
2312
|
+
useInput7((input, key) => {
|
|
2211
2313
|
if (state.confirmDelete) {
|
|
2212
2314
|
if (input === "y") {
|
|
2213
2315
|
const result = container.taskService.deleteTask(state.confirmDelete.id);
|
|
@@ -2232,7 +2334,7 @@ function App({ container, initialProject }) {
|
|
|
2232
2334
|
dispatch({ type: "GO_BACK" });
|
|
2233
2335
|
return;
|
|
2234
2336
|
}
|
|
2235
|
-
if (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit || state.activeView === ViewType.ProjectSelector || state.activeView === ViewType.ProjectCreate || state.activeView === ViewType.EpicPicker) {
|
|
2337
|
+
if (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit || state.activeView === ViewType.ProjectSelector || state.activeView === ViewType.ProjectCreate || state.activeView === ViewType.ProjectLink || state.activeView === ViewType.EpicPicker) {
|
|
2236
2338
|
return;
|
|
2237
2339
|
}
|
|
2238
2340
|
if (state.activeView === ViewType.DependencyList && state.isAddingDep) {
|
|
@@ -2733,7 +2835,8 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2733
2835
|
loadTasks();
|
|
2734
2836
|
loadEpics();
|
|
2735
2837
|
} else {
|
|
2736
|
-
|
|
2838
|
+
if (!state.activeProject) return;
|
|
2839
|
+
const result = container.taskService.createTask(data, state.activeProject);
|
|
2737
2840
|
if (result.ok) {
|
|
2738
2841
|
dispatch({ type: "FLASH", message: "Task created", level: "info" });
|
|
2739
2842
|
dispatch({ type: "GO_BACK" });
|
|
@@ -2833,6 +2936,57 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2833
2936
|
const handleProjectFormCancel = useCallback2(() => {
|
|
2834
2937
|
dispatch({ type: "GO_BACK" });
|
|
2835
2938
|
}, []);
|
|
2939
|
+
const handleProjectLink = useCallback2((project) => {
|
|
2940
|
+
dispatch({ type: "SET_LINKING_PROJECT", project });
|
|
2941
|
+
dispatch({ type: "NAVIGATE_TO", view: ViewType.ProjectLink });
|
|
2942
|
+
}, []);
|
|
2943
|
+
const handleLinkSave = useCallback2(
|
|
2944
|
+
(remote) => {
|
|
2945
|
+
if (!state.linkingProject) return;
|
|
2946
|
+
const result = container.projectService.linkGitRemote(state.linkingProject.id, remote);
|
|
2947
|
+
if (result.ok) {
|
|
2948
|
+
logger.info(
|
|
2949
|
+
`TUI.linkGitRemote: linked project=${state.linkingProject.id} remote=${result.value.gitRemote}`
|
|
2950
|
+
);
|
|
2951
|
+
dispatch({
|
|
2952
|
+
type: "FLASH",
|
|
2953
|
+
message: `Linked to: ${result.value.gitRemote}`,
|
|
2954
|
+
level: "info"
|
|
2955
|
+
});
|
|
2956
|
+
dispatch({ type: "GO_BACK" });
|
|
2957
|
+
loadProjects();
|
|
2958
|
+
} else {
|
|
2959
|
+
logger.error("TUI.linkGitRemote: failed", result.error);
|
|
2960
|
+
dispatch({ type: "FLASH", message: result.error.message, level: "error" });
|
|
2961
|
+
}
|
|
2962
|
+
},
|
|
2963
|
+
[container, state.linkingProject, loadProjects]
|
|
2964
|
+
);
|
|
2965
|
+
const handleLinkUnlink = useCallback2(() => {
|
|
2966
|
+
if (!state.linkingProject) return;
|
|
2967
|
+
const result = container.projectService.unlinkGitRemote(state.linkingProject.id);
|
|
2968
|
+
if (result.ok) {
|
|
2969
|
+
logger.info(`TUI.unlinkGitRemote: unlinked project=${state.linkingProject.id}`);
|
|
2970
|
+
dispatch({ type: "FLASH", message: "Git remote unlinked", level: "info" });
|
|
2971
|
+
dispatch({ type: "GO_BACK" });
|
|
2972
|
+
loadProjects();
|
|
2973
|
+
} else {
|
|
2974
|
+
logger.error("TUI.unlinkGitRemote: failed", result.error);
|
|
2975
|
+
dispatch({ type: "FLASH", message: result.error.message, level: "error" });
|
|
2976
|
+
}
|
|
2977
|
+
}, [container, state.linkingProject, loadProjects]);
|
|
2978
|
+
const handleLinkDetect = useCallback2(() => {
|
|
2979
|
+
const result = detectGitRemote();
|
|
2980
|
+
if (result.ok && result.value) {
|
|
2981
|
+
dispatch({ type: "FLASH", message: `Detected: ${result.value}`, level: "info" });
|
|
2982
|
+
return result.value;
|
|
2983
|
+
}
|
|
2984
|
+
dispatch({ type: "FLASH", message: "No git remote detected in cwd", level: "warn" });
|
|
2985
|
+
return null;
|
|
2986
|
+
}, []);
|
|
2987
|
+
const handleLinkCancel = useCallback2(() => {
|
|
2988
|
+
dispatch({ type: "GO_BACK" });
|
|
2989
|
+
}, []);
|
|
2836
2990
|
const handleProjectCancel = useCallback2(() => {
|
|
2837
2991
|
dispatch({ type: "GO_BACK" });
|
|
2838
2992
|
}, []);
|
|
@@ -2850,7 +3004,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2850
3004
|
}, [state.depBlockers, state.depRelated, state.depDuplicates]);
|
|
2851
3005
|
const allProjectTasks = useMemo2(() => {
|
|
2852
3006
|
if (!state.activeProject) return [];
|
|
2853
|
-
const result = container.taskService.listTasks(
|
|
3007
|
+
const result = container.taskService.listTasks(state.activeProject, {});
|
|
2854
3008
|
return result.ok ? result.value : [];
|
|
2855
3009
|
}, [container, state.activeProject, state.tasks]);
|
|
2856
3010
|
const previewTaskId = previewTask?.id ?? null;
|
|
@@ -2859,12 +3013,12 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2859
3013
|
loadDeps(previewTaskId);
|
|
2860
3014
|
}
|
|
2861
3015
|
}, [state.activeView, previewTaskId, loadDeps]);
|
|
2862
|
-
return /* @__PURE__ */
|
|
2863
|
-
/* @__PURE__ */
|
|
2864
|
-
/* @__PURE__ */
|
|
2865
|
-
state.confirmDelete && /* @__PURE__ */
|
|
2866
|
-
!state.confirmDelete && state.activeView === ViewType.TaskList && /* @__PURE__ */
|
|
2867
|
-
/* @__PURE__ */
|
|
3016
|
+
return /* @__PURE__ */ jsxs15(Box17, { flexDirection: "column", height: stdout.rows, children: [
|
|
3017
|
+
/* @__PURE__ */ jsx17(Header, { state }),
|
|
3018
|
+
/* @__PURE__ */ jsxs15(Box17, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: [
|
|
3019
|
+
state.confirmDelete && /* @__PURE__ */ jsx17(ConfirmDialog, { task: state.confirmDelete }),
|
|
3020
|
+
!state.confirmDelete && state.activeView === ViewType.TaskList && /* @__PURE__ */ jsxs15(Box17, { flexDirection: "row", flexGrow: 1, children: [
|
|
3021
|
+
/* @__PURE__ */ jsx17(
|
|
2868
3022
|
EpicPanel,
|
|
2869
3023
|
{
|
|
2870
3024
|
epics: state.epics,
|
|
@@ -2874,7 +3028,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2874
3028
|
isReordering: state.isEpicReordering
|
|
2875
3029
|
}
|
|
2876
3030
|
),
|
|
2877
|
-
/* @__PURE__ */
|
|
3031
|
+
/* @__PURE__ */ jsx17(Box17, { width: taskListWidth, children: /* @__PURE__ */ jsx17(
|
|
2878
3032
|
TaskList,
|
|
2879
3033
|
{
|
|
2880
3034
|
tasks: state.tasks,
|
|
@@ -2895,7 +3049,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2895
3049
|
epicFilterActive: state.selectedEpicIds.size > 0
|
|
2896
3050
|
}
|
|
2897
3051
|
) }),
|
|
2898
|
-
/* @__PURE__ */
|
|
3052
|
+
/* @__PURE__ */ jsx17(Box17, { width: taskDetailWidth, children: previewTask ? /* @__PURE__ */ jsx17(
|
|
2899
3053
|
TaskDetail,
|
|
2900
3054
|
{
|
|
2901
3055
|
task: previewTask,
|
|
@@ -2906,24 +3060,24 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2906
3060
|
isFocused: state.focusedPanel === "detail",
|
|
2907
3061
|
scrollOffset: state.detailScrollOffset
|
|
2908
3062
|
}
|
|
2909
|
-
) : /* @__PURE__ */
|
|
2910
|
-
|
|
3063
|
+
) : /* @__PURE__ */ jsxs15(
|
|
3064
|
+
Box17,
|
|
2911
3065
|
{
|
|
2912
3066
|
flexDirection: "column",
|
|
2913
3067
|
flexGrow: 1,
|
|
2914
3068
|
borderStyle: "bold",
|
|
2915
3069
|
borderColor: theme.border,
|
|
2916
3070
|
children: [
|
|
2917
|
-
/* @__PURE__ */
|
|
3071
|
+
/* @__PURE__ */ jsx17(Box17, { children: /* @__PURE__ */ jsxs15(Text17, { color: theme.title, bold: true, children: [
|
|
2918
3072
|
" ",
|
|
2919
3073
|
"detail"
|
|
2920
3074
|
] }) }),
|
|
2921
|
-
/* @__PURE__ */
|
|
3075
|
+
/* @__PURE__ */ jsx17(Box17, { flexGrow: 1, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: "No task selected" }) })
|
|
2922
3076
|
]
|
|
2923
3077
|
}
|
|
2924
3078
|
) })
|
|
2925
3079
|
] }),
|
|
2926
|
-
!state.confirmDelete && state.activeView === ViewType.TaskDetail && state.selectedTask && /* @__PURE__ */
|
|
3080
|
+
!state.confirmDelete && state.activeView === ViewType.TaskDetail && state.selectedTask && /* @__PURE__ */ jsx17(
|
|
2927
3081
|
TaskDetail,
|
|
2928
3082
|
{
|
|
2929
3083
|
task: state.selectedTask,
|
|
@@ -2934,7 +3088,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2934
3088
|
scrollOffset: state.detailScrollOffset
|
|
2935
3089
|
}
|
|
2936
3090
|
),
|
|
2937
|
-
!state.confirmDelete && state.activeView === ViewType.DependencyList && state.selectedTask && /* @__PURE__ */
|
|
3091
|
+
!state.confirmDelete && state.activeView === ViewType.DependencyList && state.selectedTask && /* @__PURE__ */ jsx17(
|
|
2938
3092
|
DependencyList,
|
|
2939
3093
|
{
|
|
2940
3094
|
task: state.selectedTask,
|
|
@@ -2947,7 +3101,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2947
3101
|
addDepInput: state.addDepInput
|
|
2948
3102
|
}
|
|
2949
3103
|
),
|
|
2950
|
-
!state.confirmDelete && (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit) && /* @__PURE__ */
|
|
3104
|
+
!state.confirmDelete && (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit) && /* @__PURE__ */ jsx17(
|
|
2951
3105
|
TaskForm,
|
|
2952
3106
|
{
|
|
2953
3107
|
editingTask: state.activeView === ViewType.TaskEdit ? state.selectedTask : null,
|
|
@@ -2957,7 +3111,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2957
3111
|
onCancel: handleFormCancel
|
|
2958
3112
|
}
|
|
2959
3113
|
),
|
|
2960
|
-
!state.confirmDelete && state.activeView === ViewType.EpicPicker && state.selectedTask && /* @__PURE__ */
|
|
3114
|
+
!state.confirmDelete && state.activeView === ViewType.EpicPicker && state.selectedTask && /* @__PURE__ */ jsx17(
|
|
2961
3115
|
EpicPicker,
|
|
2962
3116
|
{
|
|
2963
3117
|
epics: state.epics,
|
|
@@ -2966,7 +3120,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2966
3120
|
onCancel: handleEpicPickerCancel
|
|
2967
3121
|
}
|
|
2968
3122
|
),
|
|
2969
|
-
!state.confirmDelete && state.activeView === ViewType.ProjectSelector && /* @__PURE__ */
|
|
3123
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectSelector && /* @__PURE__ */ jsx17(
|
|
2970
3124
|
ProjectSelector,
|
|
2971
3125
|
{
|
|
2972
3126
|
projects: state.projects,
|
|
@@ -2974,21 +3128,32 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
2974
3128
|
onSelect: handleProjectSelect,
|
|
2975
3129
|
onCreate: handleProjectCreate,
|
|
2976
3130
|
onSetDefault: handleSetDefault,
|
|
3131
|
+
onLink: handleProjectLink,
|
|
2977
3132
|
onCancel: handleProjectCancel
|
|
2978
3133
|
}
|
|
2979
3134
|
),
|
|
2980
|
-
!state.confirmDelete && state.activeView === ViewType.ProjectCreate && /* @__PURE__ */
|
|
2981
|
-
!state.confirmDelete && state.activeView === ViewType.
|
|
3135
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectCreate && /* @__PURE__ */ jsx17(ProjectForm, { onSave: handleProjectFormSave, onCancel: handleProjectFormCancel }),
|
|
3136
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectLink && state.linkingProject && /* @__PURE__ */ jsx17(
|
|
3137
|
+
ProjectLinkForm,
|
|
3138
|
+
{
|
|
3139
|
+
project: state.linkingProject,
|
|
3140
|
+
onSave: handleLinkSave,
|
|
3141
|
+
onUnlink: handleLinkUnlink,
|
|
3142
|
+
onDetect: handleLinkDetect,
|
|
3143
|
+
onCancel: handleLinkCancel
|
|
3144
|
+
}
|
|
3145
|
+
),
|
|
3146
|
+
!state.confirmDelete && state.activeView === ViewType.Help && /* @__PURE__ */ jsx17(HelpOverlay, {})
|
|
2982
3147
|
] }),
|
|
2983
|
-
/* @__PURE__ */
|
|
2984
|
-
state.flash && /* @__PURE__ */
|
|
3148
|
+
/* @__PURE__ */ jsx17(Crumbs, { breadcrumbs: state.breadcrumbs }),
|
|
3149
|
+
state.flash && /* @__PURE__ */ jsx17(FlashMessage, { message: state.flash.message, level: state.flash.level })
|
|
2985
3150
|
] });
|
|
2986
3151
|
}
|
|
2987
3152
|
|
|
2988
3153
|
// src/tui/index.tsx
|
|
2989
|
-
import { jsx as
|
|
3154
|
+
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
2990
3155
|
async function launchTUI(container, initialProject) {
|
|
2991
|
-
const instance = render(/* @__PURE__ */
|
|
3156
|
+
const instance = render(/* @__PURE__ */ jsx18(App, { container, initialProject }), {
|
|
2992
3157
|
exitOnCtrlC: true
|
|
2993
3158
|
});
|
|
2994
3159
|
await instance.waitUntilExit();
|
|
@@ -2996,4 +3161,4 @@ async function launchTUI(container, initialProject) {
|
|
|
2996
3161
|
export {
|
|
2997
3162
|
launchTUI
|
|
2998
3163
|
};
|
|
2999
|
-
//# sourceMappingURL=tui-
|
|
3164
|
+
//# sourceMappingURL=tui-IXZGQMWN.js.map
|