@tomkapa/tayto 0.8.1 → 0.9.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/README.md +63 -2
- package/dist/{chunk-6ZNCVCAS.js → chunk-7SQR55R2.js} +59 -59
- package/dist/chunk-7SQR55R2.js.map +1 -0
- package/dist/index.js +2786 -1926
- package/dist/index.js.map +1 -1
- package/dist/migrations/006_rename_epic_to_release.sql +1 -0
- package/dist/{tui-APMSKU4E.js → tui-U7ATVUJU.js} +434 -305
- package/dist/tui-U7ATVUJU.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-6ZNCVCAS.js.map +0 -1
- package/dist/tui-APMSKU4E.js.map +0 -1
|
@@ -11,14 +11,14 @@ import {
|
|
|
11
11
|
isNewerVersion,
|
|
12
12
|
isTerminalStatus,
|
|
13
13
|
logger
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-7SQR55R2.js";
|
|
15
15
|
|
|
16
16
|
// src/tui/index.tsx
|
|
17
17
|
import { render } from "ink";
|
|
18
18
|
|
|
19
19
|
// src/tui/components/App.tsx
|
|
20
20
|
import { useReducer, useEffect as useEffect5, useCallback as useCallback2, useMemo as useMemo3, useState as useState8, useRef as useRef5 } from "react";
|
|
21
|
-
import { Box as
|
|
21
|
+
import { Box as Box23, Text as Text23, useInput as useInput7, useApp, useStdout as useStdout4 } from "ink";
|
|
22
22
|
|
|
23
23
|
// src/tui/types.ts
|
|
24
24
|
var ViewType = {
|
|
@@ -30,10 +30,12 @@ var ViewType = {
|
|
|
30
30
|
ProjectCreate: "project-create",
|
|
31
31
|
ProjectEdit: "project-edit",
|
|
32
32
|
DependencyList: "dependency-list",
|
|
33
|
-
|
|
33
|
+
ReleasePicker: "release-picker",
|
|
34
34
|
ProjectLink: "project-link",
|
|
35
|
-
Help: "help"
|
|
35
|
+
Help: "help",
|
|
36
|
+
Settings: "settings"
|
|
36
37
|
};
|
|
38
|
+
var TopTab = { Tasks: "tasks", Settings: "settings" };
|
|
37
39
|
|
|
38
40
|
// src/tui/assets/logo-data.ts
|
|
39
41
|
var PALETTE = {
|
|
@@ -139,7 +141,7 @@ var STATUS_COLOR = {
|
|
|
139
141
|
[TaskStatus.Cancelled]: theme.status.kill
|
|
140
142
|
};
|
|
141
143
|
var TYPE_COLOR = {
|
|
142
|
-
[TaskType.
|
|
144
|
+
[TaskType.Release]: theme.status.modified,
|
|
143
145
|
[TaskType.Story]: theme.status.highlight,
|
|
144
146
|
[TaskType.TechDebt]: theme.status.pending,
|
|
145
147
|
[TaskType.Bug]: theme.status.error
|
|
@@ -152,9 +154,19 @@ var DEP_TYPE_LABEL = {
|
|
|
152
154
|
};
|
|
153
155
|
|
|
154
156
|
// src/tui/state.ts
|
|
157
|
+
function swapAt(arr, i, j) {
|
|
158
|
+
const next = [...arr];
|
|
159
|
+
const a = next[i];
|
|
160
|
+
const b = next[j];
|
|
161
|
+
if (a === void 0 || b === void 0) return arr;
|
|
162
|
+
next[i] = b;
|
|
163
|
+
next[j] = a;
|
|
164
|
+
return next;
|
|
165
|
+
}
|
|
155
166
|
var initialState = {
|
|
156
167
|
activeView: ViewType.TaskList,
|
|
157
168
|
breadcrumbs: [ViewType.TaskList],
|
|
169
|
+
activeTab: TopTab.Tasks,
|
|
158
170
|
tasks: [],
|
|
159
171
|
selectedIndex: 0,
|
|
160
172
|
selectedTask: null,
|
|
@@ -177,13 +189,13 @@ var initialState = {
|
|
|
177
189
|
addDepInput: "",
|
|
178
190
|
focusedPanel: "list",
|
|
179
191
|
detailScrollOffset: 0,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
192
|
+
releases: [],
|
|
193
|
+
releaseSelectedIndex: 0,
|
|
194
|
+
selectedReleaseIds: /* @__PURE__ */ new Set(),
|
|
183
195
|
linkingProject: null,
|
|
184
196
|
editingProject: null,
|
|
185
|
-
|
|
186
|
-
|
|
197
|
+
isReleaseReordering: false,
|
|
198
|
+
releaseReorderSnapshot: null,
|
|
187
199
|
detectedGitRemote: null,
|
|
188
200
|
changelogEntries: null,
|
|
189
201
|
changelogIndex: 0,
|
|
@@ -274,19 +286,9 @@ function appReducer(state, action) {
|
|
|
274
286
|
case "REORDER_MOVE": {
|
|
275
287
|
if (!state.isReordering) return state;
|
|
276
288
|
const idx = state.selectedIndex;
|
|
277
|
-
const tasks = [...state.tasks];
|
|
278
289
|
const swapIdx = action.direction === "up" ? idx - 1 : idx + 1;
|
|
279
|
-
if (swapIdx < 0 || swapIdx >= tasks.length) return state;
|
|
280
|
-
|
|
281
|
-
const swap = tasks[swapIdx];
|
|
282
|
-
if (!current || !swap) return state;
|
|
283
|
-
tasks[idx] = swap;
|
|
284
|
-
tasks[swapIdx] = current;
|
|
285
|
-
return {
|
|
286
|
-
...state,
|
|
287
|
-
tasks,
|
|
288
|
-
selectedIndex: swapIdx
|
|
289
|
-
};
|
|
290
|
+
if (swapIdx < 0 || swapIdx >= state.tasks.length) return state;
|
|
291
|
+
return { ...state, tasks: swapAt(state.tasks, idx, swapIdx), selectedIndex: swapIdx };
|
|
290
292
|
}
|
|
291
293
|
case "EXIT_REORDER": {
|
|
292
294
|
if (!action.save && state.reorderSnapshot) {
|
|
@@ -332,65 +334,62 @@ function appReducer(state, action) {
|
|
|
332
334
|
};
|
|
333
335
|
case "DETAIL_RESET_SCROLL":
|
|
334
336
|
return { ...state, detailScrollOffset: 0 };
|
|
335
|
-
case "
|
|
337
|
+
case "SET_RELEASES":
|
|
336
338
|
return {
|
|
337
339
|
...state,
|
|
338
|
-
|
|
339
|
-
|
|
340
|
+
releases: action.releases,
|
|
341
|
+
releaseSelectedIndex: Math.min(
|
|
342
|
+
state.releaseSelectedIndex,
|
|
343
|
+
Math.max(0, action.releases.length - 1)
|
|
344
|
+
)
|
|
340
345
|
};
|
|
341
|
-
case "
|
|
342
|
-
if (state.
|
|
343
|
-
const maxIdx = Math.max(0, state.
|
|
344
|
-
const newIdx = action.direction === "up" ? Math.max(0, state.
|
|
345
|
-
return { ...state,
|
|
346
|
-
}
|
|
347
|
-
case "
|
|
348
|
-
const next = new Set(state.
|
|
349
|
-
if (next.has(action.
|
|
350
|
-
next.delete(action.
|
|
346
|
+
case "RELEASE_MOVE_CURSOR": {
|
|
347
|
+
if (state.releases.length === 0) return state;
|
|
348
|
+
const maxIdx = Math.max(0, state.releases.length - 1);
|
|
349
|
+
const newIdx = action.direction === "up" ? Math.max(0, state.releaseSelectedIndex - 1) : Math.min(maxIdx, state.releaseSelectedIndex + 1);
|
|
350
|
+
return { ...state, releaseSelectedIndex: newIdx };
|
|
351
|
+
}
|
|
352
|
+
case "TOGGLE_RELEASE": {
|
|
353
|
+
const next = new Set(state.selectedReleaseIds);
|
|
354
|
+
if (next.has(action.releaseId)) {
|
|
355
|
+
next.delete(action.releaseId);
|
|
351
356
|
} else {
|
|
352
|
-
next.add(action.
|
|
357
|
+
next.add(action.releaseId);
|
|
353
358
|
}
|
|
354
|
-
return { ...state,
|
|
359
|
+
return { ...state, selectedReleaseIds: next, selectedIndex: 0 };
|
|
355
360
|
}
|
|
356
|
-
case "
|
|
357
|
-
return { ...state,
|
|
358
|
-
case "
|
|
361
|
+
case "CLEAR_RELEASE_SELECTION":
|
|
362
|
+
return { ...state, selectedReleaseIds: /* @__PURE__ */ new Set(), selectedIndex: 0 };
|
|
363
|
+
case "ENTER_RELEASE_REORDER":
|
|
359
364
|
return {
|
|
360
365
|
...state,
|
|
361
|
-
|
|
362
|
-
|
|
366
|
+
isReleaseReordering: true,
|
|
367
|
+
releaseReorderSnapshot: [...state.releases]
|
|
363
368
|
};
|
|
364
|
-
case "
|
|
365
|
-
if (!state.
|
|
366
|
-
const idx = state.
|
|
367
|
-
const epics = [...state.epics];
|
|
369
|
+
case "RELEASE_REORDER_MOVE": {
|
|
370
|
+
if (!state.isReleaseReordering) return state;
|
|
371
|
+
const idx = state.releaseSelectedIndex;
|
|
368
372
|
const swapIdx = action.direction === "up" ? idx - 1 : idx + 1;
|
|
369
|
-
if (swapIdx < 0 || swapIdx >=
|
|
370
|
-
const current = epics[idx];
|
|
371
|
-
const swap = epics[swapIdx];
|
|
372
|
-
if (!current || !swap) return state;
|
|
373
|
-
epics[idx] = swap;
|
|
374
|
-
epics[swapIdx] = current;
|
|
373
|
+
if (swapIdx < 0 || swapIdx >= state.releases.length) return state;
|
|
375
374
|
return {
|
|
376
375
|
...state,
|
|
377
|
-
|
|
378
|
-
|
|
376
|
+
releases: swapAt(state.releases, idx, swapIdx),
|
|
377
|
+
releaseSelectedIndex: swapIdx
|
|
379
378
|
};
|
|
380
379
|
}
|
|
381
|
-
case "
|
|
382
|
-
if (!action.save && state.
|
|
380
|
+
case "EXIT_RELEASE_REORDER": {
|
|
381
|
+
if (!action.save && state.releaseReorderSnapshot) {
|
|
383
382
|
return {
|
|
384
383
|
...state,
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
384
|
+
isReleaseReordering: false,
|
|
385
|
+
releases: state.releaseReorderSnapshot,
|
|
386
|
+
releaseReorderSnapshot: null
|
|
388
387
|
};
|
|
389
388
|
}
|
|
390
389
|
return {
|
|
391
390
|
...state,
|
|
392
|
-
|
|
393
|
-
|
|
391
|
+
isReleaseReordering: false,
|
|
392
|
+
releaseReorderSnapshot: null
|
|
394
393
|
};
|
|
395
394
|
}
|
|
396
395
|
case "SET_LINKING_PROJECT":
|
|
@@ -413,6 +412,16 @@ function appReducer(state, action) {
|
|
|
413
412
|
return { ...state, changelogDialogOpen: true, changelogIndex: 0 };
|
|
414
413
|
case "CLOSE_CHANGELOG_DIALOG":
|
|
415
414
|
return { ...state, changelogDialogOpen: false };
|
|
415
|
+
case "SWITCH_TAB": {
|
|
416
|
+
const isSettings = action.tab === TopTab.Settings;
|
|
417
|
+
return {
|
|
418
|
+
...state,
|
|
419
|
+
activeTab: action.tab,
|
|
420
|
+
activeView: isSettings ? ViewType.Settings : ViewType.TaskList,
|
|
421
|
+
breadcrumbs: isSettings ? [ViewType.Settings] : [ViewType.TaskList],
|
|
422
|
+
focusedPanel: "list"
|
|
423
|
+
};
|
|
424
|
+
}
|
|
416
425
|
}
|
|
417
426
|
}
|
|
418
427
|
|
|
@@ -510,7 +519,14 @@ function ChangelogTicker({ entries }) {
|
|
|
510
519
|
// src/tui/components/Header.tsx
|
|
511
520
|
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
512
521
|
function getKeyHints(state) {
|
|
513
|
-
const {
|
|
522
|
+
const {
|
|
523
|
+
activeView,
|
|
524
|
+
isSearchActive,
|
|
525
|
+
isReordering,
|
|
526
|
+
isReleaseReordering,
|
|
527
|
+
isAddingDep,
|
|
528
|
+
focusedPanel
|
|
529
|
+
} = state;
|
|
514
530
|
if (state.changelogDialogOpen) {
|
|
515
531
|
return [
|
|
516
532
|
{ key: "\u2191/\u2193", desc: "navigate" },
|
|
@@ -531,7 +547,7 @@ function getKeyHints(state) {
|
|
|
531
547
|
{ key: "esc/\u2190", desc: "cancel" }
|
|
532
548
|
];
|
|
533
549
|
if (isReordering) return [{ key: "\u2191/\u2193", desc: "move" }, ...REORDER_SUFFIX];
|
|
534
|
-
if (
|
|
550
|
+
if (isReleaseReordering) return [{ key: "\u2191/\u2193", desc: "move release" }, ...REORDER_SUFFIX];
|
|
535
551
|
if (isSearchActive) {
|
|
536
552
|
return [
|
|
537
553
|
{ key: "type", desc: "query" },
|
|
@@ -539,7 +555,7 @@ function getKeyHints(state) {
|
|
|
539
555
|
{ key: "esc", desc: "cancel" }
|
|
540
556
|
];
|
|
541
557
|
}
|
|
542
|
-
if (activeView === ViewType.TaskList && focusedPanel === "
|
|
558
|
+
if (activeView === ViewType.TaskList && focusedPanel === "release") {
|
|
543
559
|
return [
|
|
544
560
|
{ key: "j/k", desc: "nav" },
|
|
545
561
|
{ key: "space", desc: "toggle" },
|
|
@@ -562,6 +578,13 @@ function getKeyHints(state) {
|
|
|
562
578
|
{ key: "?", desc: "help" }
|
|
563
579
|
];
|
|
564
580
|
}
|
|
581
|
+
if (activeView === ViewType.Settings) {
|
|
582
|
+
return [
|
|
583
|
+
{ key: "1", desc: "tasks" },
|
|
584
|
+
{ key: "?", desc: "help" },
|
|
585
|
+
{ key: "q", desc: "quit" }
|
|
586
|
+
];
|
|
587
|
+
}
|
|
565
588
|
if (activeView === ViewType.TaskList) {
|
|
566
589
|
return [
|
|
567
590
|
{ key: "enter", desc: "view" },
|
|
@@ -576,6 +599,7 @@ function getKeyHints(state) {
|
|
|
576
599
|
{ key: "f/t", desc: "filter" },
|
|
577
600
|
{ key: "PgDn/Up", desc: "page" },
|
|
578
601
|
{ key: "tab/S-tab", desc: "panel" },
|
|
602
|
+
{ key: "2", desc: "settings" },
|
|
579
603
|
{ key: "?", desc: "help" },
|
|
580
604
|
{ key: "q", desc: "quit" }
|
|
581
605
|
];
|
|
@@ -620,7 +644,7 @@ function getKeyHints(state) {
|
|
|
620
644
|
{ key: "esc", desc: "back" }
|
|
621
645
|
];
|
|
622
646
|
}
|
|
623
|
-
if (activeView === ViewType.
|
|
647
|
+
if (activeView === ViewType.ReleasePicker) {
|
|
624
648
|
return [
|
|
625
649
|
{ key: "j/k", desc: "nav" },
|
|
626
650
|
{ key: "enter", desc: "select" },
|
|
@@ -694,7 +718,8 @@ var VIEW_LABELS = {
|
|
|
694
718
|
"task-create": "create",
|
|
695
719
|
"task-edit": "edit",
|
|
696
720
|
"project-selector": "projects",
|
|
697
|
-
help: "help"
|
|
721
|
+
help: "help",
|
|
722
|
+
settings: "settings"
|
|
698
723
|
};
|
|
699
724
|
function Crumbs({ breadcrumbs }) {
|
|
700
725
|
return /* @__PURE__ */ jsx4(Box4, { flexDirection: "row", gap: 0, width: "100%", children: breadcrumbs.map((crumb, i) => {
|
|
@@ -733,6 +758,11 @@ var COL = {
|
|
|
733
758
|
type: 12,
|
|
734
759
|
status: 14
|
|
735
760
|
};
|
|
761
|
+
var FIXED_WIDTH = 2 + 2 + COL.rank + COL.type + COL.status;
|
|
762
|
+
function padTrunc(s, w) {
|
|
763
|
+
if (s.length >= w) return s.slice(0, w);
|
|
764
|
+
return s.padEnd(w);
|
|
765
|
+
}
|
|
736
766
|
function TaskList({
|
|
737
767
|
tasks,
|
|
738
768
|
selectedIndex,
|
|
@@ -745,8 +775,10 @@ function TaskList({
|
|
|
745
775
|
nonTerminalDependentIds,
|
|
746
776
|
isSelectedBlocked,
|
|
747
777
|
isFocused = true,
|
|
748
|
-
|
|
778
|
+
releaseFilterActive = false,
|
|
779
|
+
width
|
|
749
780
|
}) {
|
|
781
|
+
const maxNameWidth = Math.max(0, width - FIXED_WIDTH);
|
|
750
782
|
const currentPage = Math.floor(selectedIndex / PAGE_SIZE);
|
|
751
783
|
const viewStart = currentPage * PAGE_SIZE;
|
|
752
784
|
const visibleTasks = tasks.slice(viewStart, viewStart + PAGE_SIZE);
|
|
@@ -780,7 +812,7 @@ function TaskList({
|
|
|
780
812
|
" ",
|
|
781
813
|
"REORDER"
|
|
782
814
|
] }),
|
|
783
|
-
|
|
815
|
+
releaseFilterActive && /* @__PURE__ */ jsx6(Text6, { color: theme.titleHighlight, children: " [release]" }),
|
|
784
816
|
filterText && /* @__PURE__ */ jsxs3(Text6, { color: theme.titleFilter, children: [
|
|
785
817
|
" /",
|
|
786
818
|
filterText
|
|
@@ -800,7 +832,7 @@ function TaskList({
|
|
|
800
832
|
] }),
|
|
801
833
|
/* @__PURE__ */ jsx6(Box6, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: tasks.length === 0 ? /* @__PURE__ */ jsx6(Box6, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx6(Text6, { color: theme.fg, children: "No tasks found. Press 'c' to create one." }) }) : visibleTasks.map((task, i) => {
|
|
802
834
|
const actualIndex = viewStart + i;
|
|
803
|
-
const isSelected = actualIndex === selectedIndex;
|
|
835
|
+
const isSelected = actualIndex === selectedIndex && isFocused;
|
|
804
836
|
const isNonTerminalBlocker = nonTerminalBlockerIds.has(task.id);
|
|
805
837
|
const isNonTerminalDependent = nonTerminalDependentIds.has(task.id);
|
|
806
838
|
const rowColor = STATUS_COLOR[task.status] ?? theme.table.fg;
|
|
@@ -808,29 +840,29 @@ function TaskList({
|
|
|
808
840
|
const depMarker = isNonTerminalBlocker ? "\u25B2 " : isNonTerminalDependent ? "\u25BC " : " ";
|
|
809
841
|
if (isSelected) {
|
|
810
842
|
const cursorBg = isReordering ? theme.flash.warn : isSelectedBlocked ? theme.table.blockedCursorBg : theme.table.cursorBg;
|
|
811
|
-
return /* @__PURE__ */
|
|
812
|
-
isReordering ? "~ " : "> ",
|
|
813
|
-
|
|
814
|
-
task.type
|
|
815
|
-
task.status
|
|
816
|
-
task.name
|
|
817
|
-
] }
|
|
843
|
+
return /* @__PURE__ */ jsxs3(Box6, { children: [
|
|
844
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: isReordering ? "~ " : "> " }),
|
|
845
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: padTrunc(rowNum, COL.rank) }),
|
|
846
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: padTrunc(task.type, COL.type) }),
|
|
847
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: padTrunc(task.status, COL.status) }),
|
|
848
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: padTrunc(task.name, maxNameWidth) })
|
|
849
|
+
] }, task.id);
|
|
818
850
|
}
|
|
819
851
|
if (isNonTerminalBlocker || isNonTerminalDependent) {
|
|
820
|
-
return /* @__PURE__ */
|
|
821
|
-
depMarker,
|
|
822
|
-
|
|
823
|
-
task.type
|
|
824
|
-
task.status
|
|
825
|
-
task.name
|
|
826
|
-
] }
|
|
852
|
+
return /* @__PURE__ */ jsxs3(Box6, { children: [
|
|
853
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: theme.table.depHighlightBg, color: theme.table.fg, bold: true, children: depMarker }),
|
|
854
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: theme.table.depHighlightBg, color: theme.table.fg, bold: true, children: padTrunc(rowNum, COL.rank) }),
|
|
855
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: theme.table.depHighlightBg, color: theme.table.fg, bold: true, children: padTrunc(task.type, COL.type) }),
|
|
856
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: theme.table.depHighlightBg, color: theme.table.fg, bold: true, children: padTrunc(task.status, COL.status) }),
|
|
857
|
+
/* @__PURE__ */ jsx6(Text6, { backgroundColor: theme.table.depHighlightBg, color: theme.table.fg, bold: true, children: padTrunc(task.name, maxNameWidth) })
|
|
858
|
+
] }, task.id);
|
|
827
859
|
}
|
|
828
860
|
return /* @__PURE__ */ jsxs3(Box6, { children: [
|
|
829
861
|
/* @__PURE__ */ jsx6(Text6, { children: " " }),
|
|
830
|
-
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: rowNum
|
|
831
|
-
/* @__PURE__ */ jsx6(Text6, { color: TYPE_COLOR[task.type] ?? rowColor, children: task.type
|
|
832
|
-
/* @__PURE__ */ jsx6(Text6, { color: STATUS_COLOR[task.status] ?? rowColor, children: task.status
|
|
833
|
-
/* @__PURE__ */ jsx6(Text6, { color: rowColor, children: task.name })
|
|
862
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: padTrunc(rowNum, COL.rank) }),
|
|
863
|
+
/* @__PURE__ */ jsx6(Text6, { color: TYPE_COLOR[task.type] ?? rowColor, children: padTrunc(task.type, COL.type) }),
|
|
864
|
+
/* @__PURE__ */ jsx6(Text6, { color: STATUS_COLOR[task.status] ?? rowColor, children: padTrunc(task.status, COL.status) }),
|
|
865
|
+
/* @__PURE__ */ jsx6(Text6, { color: rowColor, children: padTrunc(task.name, maxNameWidth) })
|
|
834
866
|
] }, task.id);
|
|
835
867
|
}) }),
|
|
836
868
|
tasks.length > PAGE_SIZE && /* @__PURE__ */ jsx6(Box6, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs3(Text6, { dimColor: true, children: [
|
|
@@ -981,19 +1013,50 @@ function field(label, value) {
|
|
|
981
1013
|
function sectionHeader(title) {
|
|
982
1014
|
return PAD + chalk2.hex(theme.title).bold(`--- ${title} ---`);
|
|
983
1015
|
}
|
|
1016
|
+
function wrapWords(text, maxWidth) {
|
|
1017
|
+
if (maxWidth <= 0 || text.length <= maxWidth) return [text];
|
|
1018
|
+
const words = text.split(" ");
|
|
1019
|
+
const out = [];
|
|
1020
|
+
let line = "";
|
|
1021
|
+
for (const word of words) {
|
|
1022
|
+
if (line.length === 0) {
|
|
1023
|
+
line = word;
|
|
1024
|
+
} else if (line.length + 1 + word.length <= maxWidth) {
|
|
1025
|
+
line += " " + word;
|
|
1026
|
+
} else {
|
|
1027
|
+
out.push(line);
|
|
1028
|
+
line = word;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
if (line.length > 0) out.push(line);
|
|
1032
|
+
return out.length > 0 ? out : [""];
|
|
1033
|
+
}
|
|
1034
|
+
function buildNameLines(name, panelWidth) {
|
|
1035
|
+
const label = "name";
|
|
1036
|
+
const LABEL_PREFIX_LEN = PAD.length + label.length + 2;
|
|
1037
|
+
const valueWidth = Math.max(10, panelWidth - 2 - LABEL_PREFIX_LEN);
|
|
1038
|
+
const indent = " ".repeat(LABEL_PREFIX_LEN);
|
|
1039
|
+
const prefix = PAD + chalk2.hex(theme.yaml.key).bold(label) + chalk2.hex(theme.yaml.colon)(": ");
|
|
1040
|
+
const segments = name.split("\n").flatMap((seg) => wrapWords(seg, valueWidth));
|
|
1041
|
+
return segments.map((seg, i) => (i === 0 ? prefix : indent) + chalk2.hex(theme.titleHighlight).bold(seg));
|
|
1042
|
+
}
|
|
984
1043
|
function markdownLines(content) {
|
|
985
1044
|
const rendered = renderMarkdown(content);
|
|
986
1045
|
if (!rendered) return [];
|
|
987
1046
|
return rendered.split("\n").map((line) => PAD + line);
|
|
988
1047
|
}
|
|
989
|
-
function buildContentLines(task, blockers, dependents, related, duplicates) {
|
|
1048
|
+
function buildContentLines(task, parentTask, panelWidth, blockers, dependents, related, duplicates) {
|
|
990
1049
|
const lines = [];
|
|
991
1050
|
lines.push(field("id", task.id));
|
|
1051
|
+
lines.push(...buildNameLines(task.name, panelWidth));
|
|
992
1052
|
lines.push(field("type", task.type));
|
|
993
1053
|
lines.push(field("status", task.status));
|
|
994
1054
|
lines.push(field("created", new Date(task.createdAt).toLocaleString()));
|
|
995
1055
|
lines.push(field("updated", new Date(task.updatedAt).toLocaleString()));
|
|
996
|
-
if (task.parentId)
|
|
1056
|
+
if (task.parentId) {
|
|
1057
|
+
const parentLabel = parentTask ? parentTask.name : task.parentId;
|
|
1058
|
+
lines.push(field("release", parentLabel));
|
|
1059
|
+
}
|
|
997
1060
|
const hasDeps = blockers.length > 0 || dependents.length > 0 || related.length > 0 || duplicates.length > 0;
|
|
998
1061
|
if (hasDeps) {
|
|
999
1062
|
lines.push(sectionHeader("dependencies"));
|
|
@@ -1038,6 +1101,8 @@ function buildContentLines(task, blockers, dependents, related, duplicates) {
|
|
|
1038
1101
|
var CHROME_LINES = 8;
|
|
1039
1102
|
function TaskDetail({
|
|
1040
1103
|
task,
|
|
1104
|
+
parentTask,
|
|
1105
|
+
panelWidth,
|
|
1041
1106
|
blockers = [],
|
|
1042
1107
|
dependents = [],
|
|
1043
1108
|
related = [],
|
|
@@ -1049,9 +1114,10 @@ function TaskDetail({
|
|
|
1049
1114
|
const allText = `${task.description}
|
|
1050
1115
|
${task.technicalNotes}
|
|
1051
1116
|
${task.additionalRequirements}`;
|
|
1117
|
+
const resolvedWidth = panelWidth ?? (stdout.columns > 0 ? stdout.columns : 120);
|
|
1052
1118
|
const contentLines = useMemo2(
|
|
1053
|
-
() => buildContentLines(task, blockers, dependents, related, duplicates),
|
|
1054
|
-
[task, blockers, dependents, related, duplicates]
|
|
1119
|
+
() => buildContentLines(task, parentTask, resolvedWidth, blockers, dependents, related, duplicates),
|
|
1120
|
+
[task, parentTask, resolvedWidth, blockers, dependents, related, duplicates]
|
|
1055
1121
|
);
|
|
1056
1122
|
const viewportHeight = Math.max(1, (stdout.rows > 0 ? stdout.rows : 24) - CHROME_LINES);
|
|
1057
1123
|
const visibleLines = contentLines.slice(scrollOffset, scrollOffset + viewportHeight);
|
|
@@ -1063,22 +1129,18 @@ ${task.additionalRequirements}`;
|
|
|
1063
1129
|
borderStyle: "bold",
|
|
1064
1130
|
borderColor: isFocused ? theme.borderFocus : theme.border,
|
|
1065
1131
|
children: [
|
|
1066
|
-
/* @__PURE__ */ jsxs5(Box8, { gap: 0, children: [
|
|
1132
|
+
/* @__PURE__ */ jsxs5(Box8, { gap: 0, flexShrink: 0, children: [
|
|
1067
1133
|
/* @__PURE__ */ jsxs5(Text8, { color: theme.title, bold: true, children: [
|
|
1068
1134
|
" ",
|
|
1069
1135
|
"detail"
|
|
1070
1136
|
] }),
|
|
1071
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.fg, children: "(" }),
|
|
1072
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.titleHighlight, bold: true, children: task.name }),
|
|
1073
|
-
/* @__PURE__ */ jsx8(Text8, { color: theme.fg, children: ")" }),
|
|
1074
1137
|
scrollOffset > 0 && /* @__PURE__ */ jsxs5(Text8, { dimColor: true, children: [
|
|
1075
1138
|
" \u2191",
|
|
1076
1139
|
scrollOffset
|
|
1077
1140
|
] })
|
|
1078
1141
|
] }),
|
|
1079
|
-
/* @__PURE__ */ jsx8(Text8, { children: visibleLines.join("\n") }),
|
|
1080
|
-
/* @__PURE__ */ jsx8(Box8, {
|
|
1081
|
-
/* @__PURE__ */ jsx8(Box8, { paddingX: 1, children: /* @__PURE__ */ jsx8(MermaidHint, { content: allText }) })
|
|
1142
|
+
/* @__PURE__ */ jsx8(Box8, { flexDirection: "column", flexGrow: 1, flexShrink: 1, overflow: "hidden", children: /* @__PURE__ */ jsx8(Text8, { children: visibleLines.join("\n") }) }),
|
|
1143
|
+
/* @__PURE__ */ jsx8(Box8, { paddingX: 1, flexShrink: 0, children: /* @__PURE__ */ jsx8(MermaidHint, { content: allText }) })
|
|
1082
1144
|
]
|
|
1083
1145
|
}
|
|
1084
1146
|
);
|
|
@@ -1126,6 +1188,20 @@ function openInEditor(content, filename, options) {
|
|
|
1126
1188
|
// src/tui/components/TaskPicker.tsx
|
|
1127
1189
|
import { useState as useState2 } from "react";
|
|
1128
1190
|
import { Box as Box9, Text as Text9, useInput, useStdout as useStdout2 } from "ink";
|
|
1191
|
+
|
|
1192
|
+
// src/tui/viewport.ts
|
|
1193
|
+
function calcViewStart(cursorIndex, maxVisible) {
|
|
1194
|
+
let viewStart = 0;
|
|
1195
|
+
if (cursorIndex >= viewStart + maxVisible) {
|
|
1196
|
+
viewStart = cursorIndex - maxVisible + 1;
|
|
1197
|
+
}
|
|
1198
|
+
if (cursorIndex < viewStart) {
|
|
1199
|
+
viewStart = cursorIndex;
|
|
1200
|
+
}
|
|
1201
|
+
return viewStart;
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
// src/tui/components/TaskPicker.tsx
|
|
1129
1205
|
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1130
1206
|
var DEP_TYPE_VALUES = Object.values(UIDependencyType);
|
|
1131
1207
|
var DEP_TYPE_COLOR = {
|
|
@@ -1156,13 +1232,7 @@ function TaskPicker({ tasks, excludeIds, initialSelection, onConfirm, onCancel }
|
|
|
1156
1232
|
const q = searchQuery.toLowerCase();
|
|
1157
1233
|
return t.id.toLowerCase().includes(q) || t.name.toLowerCase().includes(q) || t.description.toLowerCase().includes(q);
|
|
1158
1234
|
});
|
|
1159
|
-
|
|
1160
|
-
if (cursorIndex >= viewStart + maxVisible) {
|
|
1161
|
-
viewStart = cursorIndex - maxVisible + 1;
|
|
1162
|
-
}
|
|
1163
|
-
if (cursorIndex < viewStart) {
|
|
1164
|
-
viewStart = cursorIndex;
|
|
1165
|
-
}
|
|
1235
|
+
const viewStart = calcViewStart(cursorIndex, maxVisible);
|
|
1166
1236
|
const visible = available.slice(viewStart, viewStart + maxVisible);
|
|
1167
1237
|
useInput((input, key) => {
|
|
1168
1238
|
if (isSearching) {
|
|
@@ -1993,12 +2063,12 @@ var ROW1 = [
|
|
|
1993
2063
|
];
|
|
1994
2064
|
var ROW2 = [
|
|
1995
2065
|
{
|
|
1996
|
-
title: "
|
|
2066
|
+
title: "RELEASE PANEL",
|
|
1997
2067
|
keys: [
|
|
1998
2068
|
["j/k", "Navigate"],
|
|
1999
2069
|
["space", "Toggle filter"],
|
|
2000
2070
|
["0", "Clear filter"],
|
|
2001
|
-
["\u2190", "Reorder
|
|
2071
|
+
["\u2190", "Reorder releases"]
|
|
2002
2072
|
]
|
|
2003
2073
|
},
|
|
2004
2074
|
{
|
|
@@ -2263,21 +2333,21 @@ function DependencyList({
|
|
|
2263
2333
|
] });
|
|
2264
2334
|
}
|
|
2265
2335
|
|
|
2266
|
-
// src/tui/components/
|
|
2336
|
+
// src/tui/components/ReleasePanel.tsx
|
|
2267
2337
|
import { Box as Box18, Text as Text18 } from "ink";
|
|
2268
2338
|
import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2269
2339
|
var PAGE_SIZE2 = 20;
|
|
2270
|
-
function
|
|
2271
|
-
|
|
2340
|
+
function ReleasePanel({
|
|
2341
|
+
releases,
|
|
2272
2342
|
selectedIndex,
|
|
2273
|
-
|
|
2343
|
+
selectedReleaseIds,
|
|
2274
2344
|
isFocused,
|
|
2275
2345
|
isReordering = false
|
|
2276
2346
|
}) {
|
|
2277
|
-
const filterActive =
|
|
2347
|
+
const filterActive = selectedReleaseIds.size > 0;
|
|
2278
2348
|
const currentPage = Math.floor(selectedIndex / PAGE_SIZE2);
|
|
2279
2349
|
const viewStart = currentPage * PAGE_SIZE2;
|
|
2280
|
-
const
|
|
2350
|
+
const visibleReleases = releases.slice(viewStart, viewStart + PAGE_SIZE2);
|
|
2281
2351
|
return /* @__PURE__ */ jsxs15(
|
|
2282
2352
|
Box18,
|
|
2283
2353
|
{
|
|
@@ -2289,11 +2359,11 @@ function EpicPanel({
|
|
|
2289
2359
|
/* @__PURE__ */ jsxs15(Box18, { children: [
|
|
2290
2360
|
/* @__PURE__ */ jsxs15(Text18, { color: theme.title, bold: true, children: [
|
|
2291
2361
|
" ",
|
|
2292
|
-
"
|
|
2362
|
+
"releases"
|
|
2293
2363
|
] }),
|
|
2294
2364
|
/* @__PURE__ */ jsxs15(Text18, { color: theme.titleCounter, bold: true, children: [
|
|
2295
2365
|
"[",
|
|
2296
|
-
|
|
2366
|
+
releases.length,
|
|
2297
2367
|
"]"
|
|
2298
2368
|
] }),
|
|
2299
2369
|
isReordering && /* @__PURE__ */ jsxs15(Text18, { color: theme.flash.warn, bold: true, children: [
|
|
@@ -2302,38 +2372,38 @@ function EpicPanel({
|
|
|
2302
2372
|
] }),
|
|
2303
2373
|
filterActive && /* @__PURE__ */ jsxs15(Text18, { color: theme.titleFilter, children: [
|
|
2304
2374
|
" *",
|
|
2305
|
-
|
|
2375
|
+
selectedReleaseIds.size
|
|
2306
2376
|
] })
|
|
2307
2377
|
] }),
|
|
2308
|
-
/* @__PURE__ */ jsx18(Box18, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children:
|
|
2378
|
+
/* @__PURE__ */ jsx18(Box18, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: releases.length === 0 ? /* @__PURE__ */ jsx18(Box18, { paddingX: 1, children: /* @__PURE__ */ jsx18(Text18, { dimColor: true, children: "No releases" }) }) : visibleReleases.map((release, i) => {
|
|
2309
2379
|
const actualIndex = viewStart + i;
|
|
2310
2380
|
const isSelected = actualIndex === selectedIndex && isFocused;
|
|
2311
|
-
const isChecked =
|
|
2381
|
+
const isChecked = selectedReleaseIds.has(release.id);
|
|
2312
2382
|
const marker = isChecked ? "[x]" : "[ ]";
|
|
2313
|
-
const statusColor = STATUS_COLOR[
|
|
2383
|
+
const statusColor = STATUS_COLOR[release.status] ?? theme.table.fg;
|
|
2314
2384
|
if (isSelected) {
|
|
2315
2385
|
const cursorBg = isReordering ? theme.flash.warn : theme.table.cursorBg;
|
|
2316
2386
|
return /* @__PURE__ */ jsx18(Box18, { children: /* @__PURE__ */ jsxs15(Text18, { backgroundColor: cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
2317
2387
|
isReordering ? "~ " : " ",
|
|
2318
2388
|
marker,
|
|
2319
2389
|
" ",
|
|
2320
|
-
|
|
2321
|
-
] }) },
|
|
2390
|
+
release.name
|
|
2391
|
+
] }) }, release.id);
|
|
2322
2392
|
}
|
|
2323
2393
|
return /* @__PURE__ */ jsx18(Box18, { children: /* @__PURE__ */ jsxs15(Text18, { color: isChecked ? theme.titleHighlight : statusColor, children: [
|
|
2324
2394
|
" ",
|
|
2325
2395
|
marker,
|
|
2326
2396
|
" ",
|
|
2327
|
-
|
|
2328
|
-
] }) },
|
|
2397
|
+
release.name
|
|
2398
|
+
] }) }, release.id);
|
|
2329
2399
|
}) }),
|
|
2330
|
-
|
|
2400
|
+
releases.length > PAGE_SIZE2 && /* @__PURE__ */ jsx18(Box18, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs15(Text18, { dimColor: true, children: [
|
|
2331
2401
|
"[",
|
|
2332
2402
|
viewStart + 1,
|
|
2333
2403
|
"-",
|
|
2334
|
-
Math.min(viewStart + PAGE_SIZE2,
|
|
2404
|
+
Math.min(viewStart + PAGE_SIZE2, releases.length),
|
|
2335
2405
|
"/",
|
|
2336
|
-
|
|
2406
|
+
releases.length,
|
|
2337
2407
|
"]"
|
|
2338
2408
|
] }) })
|
|
2339
2409
|
]
|
|
@@ -2341,29 +2411,23 @@ function EpicPanel({
|
|
|
2341
2411
|
);
|
|
2342
2412
|
}
|
|
2343
2413
|
|
|
2344
|
-
// src/tui/components/
|
|
2414
|
+
// src/tui/components/ReleasePicker.tsx
|
|
2345
2415
|
import { useState as useState7 } from "react";
|
|
2346
2416
|
import { Box as Box19, Text as Text19, useInput as useInput6, useStdout as useStdout3 } from "ink";
|
|
2347
2417
|
import { Fragment as Fragment6, jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2348
|
-
function
|
|
2418
|
+
function ReleasePicker({ releases, currentReleaseId, onSelect, onCancel }) {
|
|
2349
2419
|
const { stdout } = useStdout3();
|
|
2350
2420
|
const termHeight = stdout.rows > 0 ? stdout.rows : 24;
|
|
2351
2421
|
const maxVisible = Math.max(3, termHeight - 10);
|
|
2352
2422
|
const [searchQuery, setSearchQuery] = useState7("");
|
|
2353
2423
|
const [isSearching, setIsSearching] = useState7(false);
|
|
2354
2424
|
const [cursorIndex, setCursorIndex] = useState7(0);
|
|
2355
|
-
const filtered =
|
|
2425
|
+
const filtered = releases.filter((e) => {
|
|
2356
2426
|
if (!searchQuery.trim()) return true;
|
|
2357
2427
|
const q = searchQuery.toLowerCase();
|
|
2358
2428
|
return e.id.toLowerCase().includes(q) || e.name.toLowerCase().includes(q) || e.description.toLowerCase().includes(q);
|
|
2359
2429
|
});
|
|
2360
|
-
|
|
2361
|
-
if (cursorIndex >= viewStart + maxVisible) {
|
|
2362
|
-
viewStart = cursorIndex - maxVisible + 1;
|
|
2363
|
-
}
|
|
2364
|
-
if (cursorIndex < viewStart) {
|
|
2365
|
-
viewStart = cursorIndex;
|
|
2366
|
-
}
|
|
2430
|
+
const viewStart = calcViewStart(cursorIndex, maxVisible);
|
|
2367
2431
|
const visible = filtered.slice(viewStart, viewStart + maxVisible);
|
|
2368
2432
|
useInput6((input, key) => {
|
|
2369
2433
|
if (isSearching) {
|
|
@@ -2397,9 +2461,9 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
|
2397
2461
|
return;
|
|
2398
2462
|
}
|
|
2399
2463
|
if (key.return) {
|
|
2400
|
-
const
|
|
2401
|
-
if (
|
|
2402
|
-
onSelect(
|
|
2464
|
+
const release = filtered[cursorIndex];
|
|
2465
|
+
if (release) {
|
|
2466
|
+
onSelect(release.id);
|
|
2403
2467
|
}
|
|
2404
2468
|
return;
|
|
2405
2469
|
}
|
|
@@ -2421,12 +2485,12 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
|
2421
2485
|
/* @__PURE__ */ jsxs16(Box19, { gap: 0, children: [
|
|
2422
2486
|
/* @__PURE__ */ jsxs16(Text19, { color: theme.title, bold: true, children: [
|
|
2423
2487
|
" ",
|
|
2424
|
-
"assign to
|
|
2488
|
+
"assign to release"
|
|
2425
2489
|
] }),
|
|
2426
2490
|
/* @__PURE__ */ jsxs16(Text19, { color: theme.titleCounter, bold: true, children: [
|
|
2427
2491
|
" ",
|
|
2428
2492
|
"[",
|
|
2429
|
-
|
|
2493
|
+
releases.length,
|
|
2430
2494
|
"]"
|
|
2431
2495
|
] })
|
|
2432
2496
|
] }),
|
|
@@ -2444,23 +2508,23 @@ function EpicPicker({ epics, currentEpicId, onSelect, onCancel }) {
|
|
|
2444
2508
|
"STATUS".padEnd(14),
|
|
2445
2509
|
"NAME"
|
|
2446
2510
|
] }) }),
|
|
2447
|
-
filtered.length === 0 ? /* @__PURE__ */ jsx19(Box19, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: "No
|
|
2511
|
+
filtered.length === 0 ? /* @__PURE__ */ jsx19(Box19, { paddingX: 2, paddingY: 1, children: /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: "No releases match the filter" }) }) : visible.map((release, i) => {
|
|
2448
2512
|
const actualIndex = viewStart + i;
|
|
2449
2513
|
const isCursor = actualIndex === cursorIndex;
|
|
2450
|
-
const isCurrent =
|
|
2514
|
+
const isCurrent = release.id === currentReleaseId;
|
|
2451
2515
|
const marker = isCurrent ? "* " : " ";
|
|
2452
|
-
const statusColor = STATUS_COLOR[
|
|
2516
|
+
const statusColor = STATUS_COLOR[release.status] ?? theme.table.fg;
|
|
2453
2517
|
return /* @__PURE__ */ jsx19(Box19, { paddingX: 1, children: isCursor ? /* @__PURE__ */ jsxs16(Text19, { backgroundColor: theme.table.cursorBg, color: theme.table.cursorFg, bold: true, children: [
|
|
2454
2518
|
"> ",
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2519
|
+
release.id.padEnd(14),
|
|
2520
|
+
release.status.padEnd(14),
|
|
2521
|
+
release.name
|
|
2458
2522
|
] }) : /* @__PURE__ */ jsxs16(Fragment6, { children: [
|
|
2459
2523
|
/* @__PURE__ */ jsx19(Text19, { color: isCurrent ? theme.titleHighlight : theme.table.fg, children: marker }),
|
|
2460
|
-
/* @__PURE__ */ jsx19(Text19, { color: theme.yaml.value, children:
|
|
2461
|
-
/* @__PURE__ */ jsx19(Text19, { color: statusColor, children:
|
|
2462
|
-
/* @__PURE__ */ jsx19(Text19, { color: isCurrent ? theme.titleHighlight : theme.table.fg, children:
|
|
2463
|
-
] }) },
|
|
2524
|
+
/* @__PURE__ */ jsx19(Text19, { color: theme.yaml.value, children: release.id.padEnd(14) }),
|
|
2525
|
+
/* @__PURE__ */ jsx19(Text19, { color: statusColor, children: release.status.padEnd(14) }),
|
|
2526
|
+
/* @__PURE__ */ jsx19(Text19, { color: isCurrent ? theme.titleHighlight : theme.table.fg, children: release.name })
|
|
2527
|
+
] }) }, release.id);
|
|
2464
2528
|
}),
|
|
2465
2529
|
/* @__PURE__ */ jsx19(Box19, { flexGrow: 1 }),
|
|
2466
2530
|
filtered.length > maxVisible && /* @__PURE__ */ jsx19(Box19, { justifyContent: "flex-end", paddingRight: 1, children: /* @__PURE__ */ jsxs16(Text19, { dimColor: true, children: [
|
|
@@ -2509,6 +2573,39 @@ function ChangelogBanner({ entries, currentIndex }) {
|
|
|
2509
2573
|
);
|
|
2510
2574
|
}
|
|
2511
2575
|
|
|
2576
|
+
// src/tui/components/TabBar.tsx
|
|
2577
|
+
import { Box as Box21, Text as Text21 } from "ink";
|
|
2578
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
2579
|
+
function TabBar({ activeTab }) {
|
|
2580
|
+
const tabs = [
|
|
2581
|
+
{ id: "tasks", label: " Tasks " },
|
|
2582
|
+
{ id: "settings", label: " Settings " }
|
|
2583
|
+
];
|
|
2584
|
+
return /* @__PURE__ */ jsx21(Box21, { flexDirection: "row", gap: 0, width: "100%", children: tabs.map((tab) => {
|
|
2585
|
+
const isActive = tab.id === activeTab;
|
|
2586
|
+
return /* @__PURE__ */ jsx21(
|
|
2587
|
+
Text21,
|
|
2588
|
+
{
|
|
2589
|
+
color: theme.crumb.fg,
|
|
2590
|
+
backgroundColor: isActive ? theme.crumb.activeBg : theme.crumb.bg,
|
|
2591
|
+
bold: isActive,
|
|
2592
|
+
children: tab.label
|
|
2593
|
+
},
|
|
2594
|
+
tab.id
|
|
2595
|
+
);
|
|
2596
|
+
}) });
|
|
2597
|
+
}
|
|
2598
|
+
|
|
2599
|
+
// src/tui/components/SettingsView.tsx
|
|
2600
|
+
import { Box as Box22, Text as Text22 } from "ink";
|
|
2601
|
+
import { jsx as jsx22, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2602
|
+
function SettingsView() {
|
|
2603
|
+
return /* @__PURE__ */ jsxs18(Box22, { flexDirection: "column", flexGrow: 1, borderStyle: "bold", borderColor: theme.border, children: [
|
|
2604
|
+
/* @__PURE__ */ jsx22(Box22, { children: /* @__PURE__ */ jsx22(Text22, { color: theme.title, bold: true, children: " settings" }) }),
|
|
2605
|
+
/* @__PURE__ */ jsx22(Box22, { flexGrow: 1, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx22(Text22, { dimColor: true, children: "No settings available yet" }) })
|
|
2606
|
+
] });
|
|
2607
|
+
}
|
|
2608
|
+
|
|
2512
2609
|
// src/tui/useAutoRefetch.ts
|
|
2513
2610
|
import { useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
2514
2611
|
import { watchFile, unwatchFile } from "fs";
|
|
@@ -2584,7 +2681,7 @@ function writeSeenVersion(cachePath, version) {
|
|
|
2584
2681
|
}
|
|
2585
2682
|
|
|
2586
2683
|
// src/tui/components/App.tsx
|
|
2587
|
-
import { jsx as
|
|
2684
|
+
import { jsx as jsx23, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2588
2685
|
var STATUS_CYCLE = [
|
|
2589
2686
|
TaskStatus.Backlog,
|
|
2590
2687
|
TaskStatus.Todo,
|
|
@@ -2592,7 +2689,7 @@ var STATUS_CYCLE = [
|
|
|
2592
2689
|
TaskStatus.Review,
|
|
2593
2690
|
TaskStatus.Done
|
|
2594
2691
|
];
|
|
2595
|
-
var
|
|
2692
|
+
var RELEASE_PANEL_WIDTH = 48;
|
|
2596
2693
|
function App({ container, initialProject, latestVersion }) {
|
|
2597
2694
|
const { exit } = useApp();
|
|
2598
2695
|
const { stdout } = useStdout4();
|
|
@@ -2608,7 +2705,7 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2608
2705
|
};
|
|
2609
2706
|
}, [stdout]);
|
|
2610
2707
|
const termWidth = stdout.columns > 0 ? stdout.columns : 120;
|
|
2611
|
-
const remaining = Math.max(0, termWidth -
|
|
2708
|
+
const remaining = Math.max(0, termWidth - RELEASE_PANEL_WIDTH - 2);
|
|
2612
2709
|
const taskListWidth = Math.floor(remaining * 0.6);
|
|
2613
2710
|
const taskDetailWidth = remaining - taskListWidth;
|
|
2614
2711
|
const loadProjects = useCallback2(() => {
|
|
@@ -2626,8 +2723,8 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2626
2723
|
if (!activeProject) return;
|
|
2627
2724
|
logger.startSpan("TUI.loadTasks", () => {
|
|
2628
2725
|
const filter = { ...state.filter, level: TaskLevel.Work };
|
|
2629
|
-
if (state.
|
|
2630
|
-
filter.parentIds = [...state.
|
|
2726
|
+
if (state.selectedReleaseIds.size > 0) {
|
|
2727
|
+
filter.parentIds = [...state.selectedReleaseIds];
|
|
2631
2728
|
}
|
|
2632
2729
|
const result = container.taskService.listTasks(activeProject, filter);
|
|
2633
2730
|
if (result.ok) {
|
|
@@ -2638,16 +2735,16 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2638
2735
|
dispatch({ type: "FLASH", message: result.error.message, level: "error" });
|
|
2639
2736
|
}
|
|
2640
2737
|
});
|
|
2641
|
-
}, [container, state.filter, state.activeProject, state.
|
|
2642
|
-
const
|
|
2738
|
+
}, [container, state.filter, state.activeProject, state.selectedReleaseIds]);
|
|
2739
|
+
const loadReleases = useCallback2(() => {
|
|
2643
2740
|
if (!state.activeProject) return;
|
|
2644
2741
|
const result = container.taskService.listTasks(state.activeProject, {
|
|
2645
|
-
level: TaskLevel.
|
|
2742
|
+
level: TaskLevel.Release
|
|
2646
2743
|
});
|
|
2647
2744
|
if (result.ok) {
|
|
2648
|
-
dispatch({ type: "
|
|
2745
|
+
dispatch({ type: "SET_RELEASES", releases: result.value });
|
|
2649
2746
|
} else {
|
|
2650
|
-
logger.error("TUI.
|
|
2747
|
+
logger.error("TUI.loadReleases: failed", result.error);
|
|
2651
2748
|
}
|
|
2652
2749
|
}, [container, state.activeProject]);
|
|
2653
2750
|
const loadDeps = useCallback2(
|
|
@@ -2678,55 +2775,51 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2678
2775
|
dispatch({ type: "SELECT_TASK", task: result.value });
|
|
2679
2776
|
}
|
|
2680
2777
|
loadTasks();
|
|
2681
|
-
|
|
2778
|
+
loadReleases();
|
|
2682
2779
|
} else {
|
|
2683
2780
|
dispatch({ type: "FLASH", message: result.error.message, level: "error" });
|
|
2684
2781
|
}
|
|
2685
2782
|
},
|
|
2686
|
-
[container, state.selectedTask, loadTasks,
|
|
2783
|
+
[container, state.selectedTask, loadTasks, loadReleases]
|
|
2784
|
+
);
|
|
2785
|
+
const saveCurrentReorder = useCallback2(
|
|
2786
|
+
(kind) => {
|
|
2787
|
+
const activeProject = state.activeProject;
|
|
2788
|
+
if (!activeProject) return;
|
|
2789
|
+
const isRelease = kind === "release";
|
|
2790
|
+
const items = isRelease ? state.releases : state.tasks;
|
|
2791
|
+
const idx = isRelease ? state.releaseSelectedIndex : state.selectedIndex;
|
|
2792
|
+
const item = items[idx];
|
|
2793
|
+
if (!item) return;
|
|
2794
|
+
const prev = items[idx - 1];
|
|
2795
|
+
const next = items[idx + 1];
|
|
2796
|
+
const result = prev ? container.taskService.rerankTask({ taskId: item.id, afterId: prev.id }, activeProject) : next ? container.taskService.rerankTask({ taskId: item.id, beforeId: next.id }, activeProject) : container.taskService.rerankTask({ taskId: item.id, position: 1 }, activeProject);
|
|
2797
|
+
dispatch({ type: isRelease ? "EXIT_RELEASE_REORDER" : "EXIT_REORDER", save: result.ok });
|
|
2798
|
+
dispatch({
|
|
2799
|
+
type: "FLASH",
|
|
2800
|
+
message: result.ok ? isRelease ? "Release rank saved" : "Rank saved" : result.error.message,
|
|
2801
|
+
level: result.ok ? "info" : "error"
|
|
2802
|
+
});
|
|
2803
|
+
if (isRelease) loadReleases();
|
|
2804
|
+
else loadTasks();
|
|
2805
|
+
},
|
|
2806
|
+
[
|
|
2807
|
+
container,
|
|
2808
|
+
state.tasks,
|
|
2809
|
+
state.selectedIndex,
|
|
2810
|
+
state.releases,
|
|
2811
|
+
state.releaseSelectedIndex,
|
|
2812
|
+
state.activeProject,
|
|
2813
|
+
loadTasks,
|
|
2814
|
+
loadReleases
|
|
2815
|
+
]
|
|
2687
2816
|
);
|
|
2688
|
-
const saveReorder = useCallback2(() => {
|
|
2689
|
-
const activeProject = state.activeProject;
|
|
2690
|
-
if (!activeProject) return;
|
|
2691
|
-
const tasks = state.tasks;
|
|
2692
|
-
const idx = state.selectedIndex;
|
|
2693
|
-
const task = tasks[idx];
|
|
2694
|
-
if (!task) return;
|
|
2695
|
-
const prev = tasks[idx - 1];
|
|
2696
|
-
const next = tasks[idx + 1];
|
|
2697
|
-
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);
|
|
2698
|
-
dispatch({ type: "EXIT_REORDER", save: result.ok });
|
|
2699
|
-
dispatch({
|
|
2700
|
-
type: "FLASH",
|
|
2701
|
-
message: result.ok ? "Rank saved" : result.error.message,
|
|
2702
|
-
level: result.ok ? "info" : "error"
|
|
2703
|
-
});
|
|
2704
|
-
loadTasks();
|
|
2705
|
-
}, [container, state.tasks, state.selectedIndex, loadTasks]);
|
|
2706
|
-
const saveEpicReorder = useCallback2(() => {
|
|
2707
|
-
const activeProject = state.activeProject;
|
|
2708
|
-
if (!activeProject) return;
|
|
2709
|
-
const epics = state.epics;
|
|
2710
|
-
const idx = state.epicSelectedIndex;
|
|
2711
|
-
const epic = epics[idx];
|
|
2712
|
-
if (!epic) return;
|
|
2713
|
-
const prev = epics[idx - 1];
|
|
2714
|
-
const next = epics[idx + 1];
|
|
2715
|
-
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);
|
|
2716
|
-
dispatch({ type: "EXIT_EPIC_REORDER", save: result.ok });
|
|
2717
|
-
dispatch({
|
|
2718
|
-
type: "FLASH",
|
|
2719
|
-
message: result.ok ? "Epic rank saved" : result.error.message,
|
|
2720
|
-
level: result.ok ? "info" : "error"
|
|
2721
|
-
});
|
|
2722
|
-
loadEpics();
|
|
2723
|
-
}, [container, state.epics, state.epicSelectedIndex, loadEpics]);
|
|
2724
2817
|
const rerankSelectedToEdge = useCallback2(
|
|
2725
2818
|
(kind, edge) => {
|
|
2726
2819
|
const activeProject = state.activeProject;
|
|
2727
2820
|
if (!activeProject) return;
|
|
2728
|
-
const
|
|
2729
|
-
const item =
|
|
2821
|
+
const isRelease = kind === "release";
|
|
2822
|
+
const item = isRelease ? state.releases[state.releaseSelectedIndex] : state.tasks[state.selectedIndex];
|
|
2730
2823
|
if (!item) return;
|
|
2731
2824
|
const result = container.taskService.rerankTask(
|
|
2732
2825
|
{
|
|
@@ -2736,32 +2829,32 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2736
2829
|
activeProject
|
|
2737
2830
|
);
|
|
2738
2831
|
dispatch({
|
|
2739
|
-
type:
|
|
2832
|
+
type: isRelease ? "EXIT_RELEASE_REORDER" : "EXIT_REORDER",
|
|
2740
2833
|
save: result.ok
|
|
2741
2834
|
});
|
|
2742
2835
|
dispatch({
|
|
2743
2836
|
type: "FLASH",
|
|
2744
|
-
message: result.ok ? `${
|
|
2837
|
+
message: result.ok ? `${isRelease ? "Release moved" : "Moved"} to ${edge}` : result.error.message,
|
|
2745
2838
|
level: result.ok ? "info" : "error"
|
|
2746
2839
|
});
|
|
2747
|
-
if (
|
|
2840
|
+
if (isRelease) loadReleases();
|
|
2748
2841
|
else loadTasks();
|
|
2749
2842
|
},
|
|
2750
2843
|
[
|
|
2751
2844
|
container,
|
|
2752
2845
|
state.tasks,
|
|
2753
2846
|
state.selectedIndex,
|
|
2754
|
-
state.
|
|
2755
|
-
state.
|
|
2847
|
+
state.releases,
|
|
2848
|
+
state.releaseSelectedIndex,
|
|
2756
2849
|
loadTasks,
|
|
2757
|
-
|
|
2850
|
+
loadReleases
|
|
2758
2851
|
]
|
|
2759
2852
|
);
|
|
2760
2853
|
const refetchAll = useCallback2(() => {
|
|
2761
2854
|
loadProjects();
|
|
2762
2855
|
loadTasks();
|
|
2763
|
-
|
|
2764
|
-
}, [loadProjects, loadTasks,
|
|
2856
|
+
loadReleases();
|
|
2857
|
+
}, [loadProjects, loadTasks, loadReleases]);
|
|
2765
2858
|
useAutoRefetch(container.dbPath, refetchAll);
|
|
2766
2859
|
useEffect5(() => {
|
|
2767
2860
|
loadProjects();
|
|
@@ -2820,9 +2913,9 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2820
2913
|
useEffect5(() => {
|
|
2821
2914
|
if (state.activeProject) {
|
|
2822
2915
|
loadTasks();
|
|
2823
|
-
|
|
2916
|
+
loadReleases();
|
|
2824
2917
|
}
|
|
2825
|
-
}, [state.activeProject, state.filter, loadTasks,
|
|
2918
|
+
}, [state.activeProject, state.filter, loadTasks, loadReleases]);
|
|
2826
2919
|
useEffect5(() => {
|
|
2827
2920
|
if (state.flash) {
|
|
2828
2921
|
const timer = setTimeout(() => {
|
|
@@ -2860,7 +2953,7 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2860
2953
|
dispatch({ type: "GO_BACK" });
|
|
2861
2954
|
}
|
|
2862
2955
|
loadTasks();
|
|
2863
|
-
|
|
2956
|
+
loadReleases();
|
|
2864
2957
|
} else {
|
|
2865
2958
|
dispatch({ type: "FLASH", message: result.error.message, level: "error" });
|
|
2866
2959
|
dispatch({ type: "CANCEL_DELETE" });
|
|
@@ -2883,7 +2976,7 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2883
2976
|
dispatch({ type: "GO_BACK" });
|
|
2884
2977
|
return;
|
|
2885
2978
|
}
|
|
2886
|
-
if (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit || state.activeView === ViewType.ProjectSelector || state.activeView === ViewType.ProjectCreate || state.activeView === ViewType.ProjectEdit || state.activeView === ViewType.ProjectLink || state.activeView === ViewType.
|
|
2979
|
+
if (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit || state.activeView === ViewType.ProjectSelector || state.activeView === ViewType.ProjectCreate || state.activeView === ViewType.ProjectEdit || state.activeView === ViewType.ProjectLink || state.activeView === ViewType.ReleasePicker) {
|
|
2887
2980
|
return;
|
|
2888
2981
|
}
|
|
2889
2982
|
if (state.activeView === ViewType.DependencyList && state.isAddingDep) {
|
|
@@ -2954,30 +3047,42 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
2954
3047
|
}
|
|
2955
3048
|
return;
|
|
2956
3049
|
}
|
|
2957
|
-
|
|
3050
|
+
const isRootView = state.activeView === ViewType.TaskList || state.activeView === ViewType.Settings;
|
|
3051
|
+
const noModal = !state.changelogEntries && !state.detectedGitRemote && !state.isReordering && !state.isReleaseReordering && !state.isAddingDep;
|
|
3052
|
+
if (noModal && isRootView) {
|
|
3053
|
+
if (input === "1") {
|
|
3054
|
+
dispatch({ type: "SWITCH_TAB", tab: TopTab.Tasks });
|
|
3055
|
+
return;
|
|
3056
|
+
}
|
|
3057
|
+
if (input === "2") {
|
|
3058
|
+
dispatch({ type: "SWITCH_TAB", tab: TopTab.Settings });
|
|
3059
|
+
return;
|
|
3060
|
+
}
|
|
3061
|
+
}
|
|
3062
|
+
if (state.isReleaseReordering) {
|
|
2958
3063
|
if (key.upArrow || input === "k") {
|
|
2959
|
-
dispatch({ type: "
|
|
3064
|
+
dispatch({ type: "RELEASE_REORDER_MOVE", direction: "up" });
|
|
2960
3065
|
return;
|
|
2961
3066
|
}
|
|
2962
3067
|
if (key.downArrow || input === "j") {
|
|
2963
|
-
dispatch({ type: "
|
|
3068
|
+
dispatch({ type: "RELEASE_REORDER_MOVE", direction: "down" });
|
|
2964
3069
|
return;
|
|
2965
3070
|
}
|
|
2966
3071
|
if (input === "t") {
|
|
2967
|
-
rerankSelectedToEdge("
|
|
3072
|
+
rerankSelectedToEdge("release", "top");
|
|
2968
3073
|
return;
|
|
2969
3074
|
}
|
|
2970
3075
|
if (input === "b") {
|
|
2971
|
-
rerankSelectedToEdge("
|
|
3076
|
+
rerankSelectedToEdge("release", "bottom");
|
|
2972
3077
|
return;
|
|
2973
3078
|
}
|
|
2974
3079
|
if (key.rightArrow) {
|
|
2975
|
-
|
|
3080
|
+
saveCurrentReorder("release");
|
|
2976
3081
|
return;
|
|
2977
3082
|
}
|
|
2978
3083
|
if (key.escape || key.leftArrow) {
|
|
2979
|
-
dispatch({ type: "
|
|
2980
|
-
dispatch({ type: "FLASH", message: "
|
|
3084
|
+
dispatch({ type: "EXIT_RELEASE_REORDER", save: false });
|
|
3085
|
+
dispatch({ type: "FLASH", message: "Release reorder cancelled", level: "info" });
|
|
2981
3086
|
return;
|
|
2982
3087
|
}
|
|
2983
3088
|
return;
|
|
@@ -3000,7 +3105,7 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
3000
3105
|
return;
|
|
3001
3106
|
}
|
|
3002
3107
|
if (key.rightArrow) {
|
|
3003
|
-
|
|
3108
|
+
saveCurrentReorder("task");
|
|
3004
3109
|
return;
|
|
3005
3110
|
}
|
|
3006
3111
|
if (key.escape || key.leftArrow) {
|
|
@@ -3010,7 +3115,7 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
3010
3115
|
}
|
|
3011
3116
|
return;
|
|
3012
3117
|
}
|
|
3013
|
-
if (input === "q" && state.activeView === ViewType.TaskList && state.focusedPanel === "list") {
|
|
3118
|
+
if (input === "q" && (state.activeView === ViewType.Settings || state.activeView === ViewType.TaskList && state.focusedPanel === "list")) {
|
|
3014
3119
|
exit();
|
|
3015
3120
|
return;
|
|
3016
3121
|
}
|
|
@@ -3027,36 +3132,45 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
3027
3132
|
return;
|
|
3028
3133
|
}
|
|
3029
3134
|
if (key.tab && state.activeView === ViewType.TaskList) {
|
|
3030
|
-
const panels =
|
|
3135
|
+
const panels = previewItem ? ["release", "list", "detail"] : ["release", "list"];
|
|
3031
3136
|
const curIdx = panels.indexOf(state.focusedPanel);
|
|
3032
3137
|
const delta = key.shift ? -1 : 1;
|
|
3033
3138
|
const nextPanel = panels[(curIdx + delta + panels.length) % panels.length] ?? "list";
|
|
3034
3139
|
dispatch({ type: "SET_PANEL_FOCUS", panel: nextPanel });
|
|
3035
3140
|
return;
|
|
3036
3141
|
}
|
|
3037
|
-
if (state.activeView === ViewType.TaskList && state.focusedPanel === "
|
|
3142
|
+
if (state.activeView === ViewType.TaskList && state.focusedPanel === "release") {
|
|
3038
3143
|
if (key.upArrow || input === "k") {
|
|
3039
|
-
dispatch({ type: "
|
|
3144
|
+
dispatch({ type: "RELEASE_MOVE_CURSOR", direction: "up" });
|
|
3040
3145
|
return;
|
|
3041
3146
|
}
|
|
3042
3147
|
if (key.downArrow || input === "j") {
|
|
3043
|
-
dispatch({ type: "
|
|
3148
|
+
dispatch({ type: "RELEASE_MOVE_CURSOR", direction: "down" });
|
|
3149
|
+
return;
|
|
3150
|
+
}
|
|
3151
|
+
if (input === " ") {
|
|
3152
|
+
const release = state.releases[state.releaseSelectedIndex];
|
|
3153
|
+
if (release) {
|
|
3154
|
+
dispatch({ type: "TOGGLE_RELEASE", releaseId: release.id });
|
|
3155
|
+
}
|
|
3044
3156
|
return;
|
|
3045
3157
|
}
|
|
3046
|
-
if (
|
|
3047
|
-
const
|
|
3048
|
-
if (
|
|
3049
|
-
dispatch({ type: "
|
|
3158
|
+
if (key.return) {
|
|
3159
|
+
const release = state.releases[state.releaseSelectedIndex];
|
|
3160
|
+
if (release) {
|
|
3161
|
+
dispatch({ type: "SELECT_TASK", task: release });
|
|
3162
|
+
loadDeps(release.id);
|
|
3163
|
+
dispatch({ type: "NAVIGATE_TO", view: ViewType.TaskDetail });
|
|
3050
3164
|
}
|
|
3051
3165
|
return;
|
|
3052
3166
|
}
|
|
3053
3167
|
if (input === "0") {
|
|
3054
|
-
dispatch({ type: "
|
|
3168
|
+
dispatch({ type: "CLEAR_RELEASE_SELECTION" });
|
|
3055
3169
|
return;
|
|
3056
3170
|
}
|
|
3057
3171
|
if (key.leftArrow) {
|
|
3058
|
-
if (state.
|
|
3059
|
-
dispatch({ type: "
|
|
3172
|
+
if (state.releases.length > 0) {
|
|
3173
|
+
dispatch({ type: "ENTER_RELEASE_REORDER" });
|
|
3060
3174
|
dispatch({
|
|
3061
3175
|
type: "FLASH",
|
|
3062
3176
|
message: "Reorder: \u2191\u2193 move, t top, b bottom, \u2192 save, \u2190 cancel",
|
|
@@ -3135,7 +3249,7 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
3135
3249
|
const task = state.tasks[state.selectedIndex];
|
|
3136
3250
|
if (task) {
|
|
3137
3251
|
dispatch({ type: "SELECT_TASK", task });
|
|
3138
|
-
dispatch({ type: "NAVIGATE_TO", view: ViewType.
|
|
3252
|
+
dispatch({ type: "NAVIGATE_TO", view: ViewType.ReleasePicker });
|
|
3139
3253
|
}
|
|
3140
3254
|
return;
|
|
3141
3255
|
}
|
|
@@ -3144,14 +3258,14 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
3144
3258
|
if (task && task.parentId) {
|
|
3145
3259
|
const result = container.taskService.updateTask(task.id, { parentId: null });
|
|
3146
3260
|
if (result.ok) {
|
|
3147
|
-
dispatch({ type: "FLASH", message: "Unassigned from
|
|
3261
|
+
dispatch({ type: "FLASH", message: "Unassigned from release", level: "info" });
|
|
3148
3262
|
loadTasks();
|
|
3149
|
-
|
|
3263
|
+
loadReleases();
|
|
3150
3264
|
} else {
|
|
3151
3265
|
dispatch({ type: "FLASH", message: result.error.message, level: "error" });
|
|
3152
3266
|
}
|
|
3153
3267
|
} else if (task) {
|
|
3154
|
-
dispatch({ type: "FLASH", message: "Task has no
|
|
3268
|
+
dispatch({ type: "FLASH", message: "Task has no release", level: "warn" });
|
|
3155
3269
|
}
|
|
3156
3270
|
return;
|
|
3157
3271
|
}
|
|
@@ -3165,10 +3279,10 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
3165
3279
|
return;
|
|
3166
3280
|
}
|
|
3167
3281
|
if (key.leftArrow) {
|
|
3168
|
-
if (state.
|
|
3282
|
+
if (state.selectedReleaseIds.size > 0) {
|
|
3169
3283
|
dispatch({
|
|
3170
3284
|
type: "FLASH",
|
|
3171
|
-
message: "Clear
|
|
3285
|
+
message: "Clear release filter (0) before reordering",
|
|
3172
3286
|
level: "warn"
|
|
3173
3287
|
});
|
|
3174
3288
|
return;
|
|
@@ -3216,7 +3330,7 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
3216
3330
|
return;
|
|
3217
3331
|
}
|
|
3218
3332
|
}
|
|
3219
|
-
if (state.activeView === ViewType.TaskList && state.focusedPanel === "detail" &&
|
|
3333
|
+
if (state.activeView === ViewType.TaskList && state.focusedPanel === "detail" && previewItem) {
|
|
3220
3334
|
if (key.upArrow || input === "k") {
|
|
3221
3335
|
dispatch({ type: "DETAIL_SCROLL", direction: "up" });
|
|
3222
3336
|
return;
|
|
@@ -3226,22 +3340,22 @@ function App({ container, initialProject, latestVersion }) {
|
|
|
3226
3340
|
return;
|
|
3227
3341
|
}
|
|
3228
3342
|
if (input === "e") {
|
|
3229
|
-
dispatch({ type: "SELECT_TASK", task:
|
|
3343
|
+
dispatch({ type: "SELECT_TASK", task: previewItem });
|
|
3230
3344
|
dispatch({ type: "NAVIGATE_TO", view: ViewType.TaskEdit });
|
|
3231
3345
|
return;
|
|
3232
3346
|
}
|
|
3233
3347
|
if (input === "d") {
|
|
3234
|
-
dispatch({ type: "CONFIRM_DELETE", task:
|
|
3348
|
+
dispatch({ type: "CONFIRM_DELETE", task: previewItem });
|
|
3235
3349
|
return;
|
|
3236
3350
|
}
|
|
3237
3351
|
if (input === "s") {
|
|
3238
|
-
cycleStatus(
|
|
3352
|
+
cycleStatus(previewItem);
|
|
3239
3353
|
return;
|
|
3240
3354
|
}
|
|
3241
3355
|
if (input === "m") {
|
|
3242
|
-
const allText = `${
|
|
3243
|
-
${
|
|
3244
|
-
${
|
|
3356
|
+
const allText = `${previewItem.description}
|
|
3357
|
+
${previewItem.technicalNotes}
|
|
3358
|
+
${previewItem.additionalRequirements}`;
|
|
3245
3359
|
const count = openAllMermaidDiagrams(allText);
|
|
3246
3360
|
if (count > 0) {
|
|
3247
3361
|
dispatch({
|
|
@@ -3253,8 +3367,8 @@ ${previewTask.additionalRequirements}`;
|
|
|
3253
3367
|
return;
|
|
3254
3368
|
}
|
|
3255
3369
|
if (input === "D") {
|
|
3256
|
-
dispatch({ type: "SELECT_TASK", task:
|
|
3257
|
-
loadDeps(
|
|
3370
|
+
dispatch({ type: "SELECT_TASK", task: previewItem });
|
|
3371
|
+
loadDeps(previewItem.id);
|
|
3258
3372
|
dispatch({ type: "NAVIGATE_TO", view: ViewType.DependencyList });
|
|
3259
3373
|
return;
|
|
3260
3374
|
}
|
|
@@ -3387,7 +3501,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3387
3501
|
loadDeps(taskId);
|
|
3388
3502
|
dispatch({ type: "GO_BACK" });
|
|
3389
3503
|
loadTasks();
|
|
3390
|
-
|
|
3504
|
+
loadReleases();
|
|
3391
3505
|
} else {
|
|
3392
3506
|
if (!state.activeProject) return;
|
|
3393
3507
|
const result = container.taskService.createTask(data, state.activeProject);
|
|
@@ -3395,7 +3509,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3395
3509
|
dispatch({ type: "FLASH", message: "Task created", level: "info" });
|
|
3396
3510
|
dispatch({ type: "GO_BACK" });
|
|
3397
3511
|
loadTasks();
|
|
3398
|
-
|
|
3512
|
+
loadReleases();
|
|
3399
3513
|
} else {
|
|
3400
3514
|
dispatch({ type: "FLASH", message: result.error.message, level: "error" });
|
|
3401
3515
|
}
|
|
@@ -3408,31 +3522,31 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3408
3522
|
state.activeProject,
|
|
3409
3523
|
loadTasks,
|
|
3410
3524
|
loadDeps,
|
|
3411
|
-
|
|
3525
|
+
loadReleases
|
|
3412
3526
|
]
|
|
3413
3527
|
);
|
|
3414
3528
|
const handleFormCancel = useCallback2(() => {
|
|
3415
3529
|
dispatch({ type: "GO_BACK" });
|
|
3416
3530
|
}, []);
|
|
3417
|
-
const
|
|
3418
|
-
(
|
|
3531
|
+
const handleReleasePickerSelect = useCallback2(
|
|
3532
|
+
(releaseId) => {
|
|
3419
3533
|
if (!state.selectedTask) return;
|
|
3420
3534
|
const result = container.taskService.updateTask(state.selectedTask.id, {
|
|
3421
|
-
parentId:
|
|
3535
|
+
parentId: releaseId
|
|
3422
3536
|
});
|
|
3423
3537
|
if (result.ok) {
|
|
3424
|
-
const msg =
|
|
3538
|
+
const msg = releaseId ? `Assigned to ${releaseId}` : "Unassigned from release";
|
|
3425
3539
|
dispatch({ type: "FLASH", message: msg, level: "info" });
|
|
3426
3540
|
loadTasks();
|
|
3427
|
-
|
|
3541
|
+
loadReleases();
|
|
3428
3542
|
} else {
|
|
3429
3543
|
dispatch({ type: "FLASH", message: result.error.message, level: "error" });
|
|
3430
3544
|
}
|
|
3431
3545
|
dispatch({ type: "GO_BACK" });
|
|
3432
3546
|
},
|
|
3433
|
-
[container, state.selectedTask, loadTasks,
|
|
3547
|
+
[container, state.selectedTask, loadTasks, loadReleases]
|
|
3434
3548
|
);
|
|
3435
|
-
const
|
|
3549
|
+
const handleReleasePickerCancel = useCallback2(() => {
|
|
3436
3550
|
dispatch({ type: "GO_BACK" });
|
|
3437
3551
|
}, []);
|
|
3438
3552
|
const handleProjectSelect = useCallback2((project) => {
|
|
@@ -3566,7 +3680,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3566
3680
|
const handleProjectCancel = useCallback2(() => {
|
|
3567
3681
|
dispatch({ type: "GO_BACK" });
|
|
3568
3682
|
}, []);
|
|
3569
|
-
const
|
|
3683
|
+
const previewItem = state.focusedPanel === "release" ? state.releases[state.releaseSelectedIndex] ?? null : state.tasks[state.selectedIndex] ?? null;
|
|
3570
3684
|
const initialDepsForEdit = useMemo3(() => {
|
|
3571
3685
|
return [
|
|
3572
3686
|
...state.depBlockers.map((t) => ({ id: t.id, name: t.name, type: DependencyType.Blocks })),
|
|
@@ -3583,29 +3697,39 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3583
3697
|
const result = container.taskService.listTasks(state.activeProject, {});
|
|
3584
3698
|
return result.ok ? result.value : [];
|
|
3585
3699
|
}, [container, state.activeProject, state.tasks]);
|
|
3586
|
-
const
|
|
3700
|
+
const previewItemId = previewItem?.id ?? null;
|
|
3587
3701
|
useEffect5(() => {
|
|
3588
|
-
if (state.activeView === ViewType.TaskList &&
|
|
3589
|
-
loadDeps(
|
|
3590
|
-
}
|
|
3591
|
-
}, [state.activeView,
|
|
3592
|
-
return /* @__PURE__ */
|
|
3593
|
-
/* @__PURE__ */
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3702
|
+
if (state.activeView === ViewType.TaskList && previewItemId) {
|
|
3703
|
+
loadDeps(previewItemId);
|
|
3704
|
+
}
|
|
3705
|
+
}, [state.activeView, previewItemId, loadDeps]);
|
|
3706
|
+
return /* @__PURE__ */ jsxs19(Box23, { flexDirection: "column", height: stdout.rows, children: [
|
|
3707
|
+
/* @__PURE__ */ jsxs19(Box23, { flexShrink: 0, flexDirection: "column", children: [
|
|
3708
|
+
/* @__PURE__ */ jsx23(Header, { state, latestVersion }),
|
|
3709
|
+
/* @__PURE__ */ jsx23(TabBar, { activeTab: state.activeTab })
|
|
3710
|
+
] }),
|
|
3711
|
+
state.activeTab === TopTab.Settings && /* @__PURE__ */ jsx23(SettingsView, {}),
|
|
3712
|
+
state.activeTab === TopTab.Tasks && /* @__PURE__ */ jsxs19(Box23, { flexDirection: "column", flexGrow: 1, overflowY: "hidden", children: [
|
|
3713
|
+
state.confirmDelete && /* @__PURE__ */ jsx23(ConfirmDialog, { task: state.confirmDelete }),
|
|
3714
|
+
!state.confirmDelete && state.changelogEntries && state.changelogDialogOpen && state.activeView === ViewType.TaskList && /* @__PURE__ */ jsx23(
|
|
3715
|
+
ChangelogBanner,
|
|
3716
|
+
{
|
|
3717
|
+
entries: state.changelogEntries,
|
|
3718
|
+
currentIndex: state.changelogIndex
|
|
3719
|
+
}
|
|
3720
|
+
),
|
|
3721
|
+
!state.confirmDelete && !state.changelogDialogOpen && state.activeView === ViewType.TaskList && (state.detectedGitRemote ? /* @__PURE__ */ jsx23(DetectedProjectDialog, { remote: state.detectedGitRemote }) : /* @__PURE__ */ jsxs19(Box23, { flexDirection: "row", flexGrow: 1, children: [
|
|
3722
|
+
/* @__PURE__ */ jsx23(
|
|
3723
|
+
ReleasePanel,
|
|
3600
3724
|
{
|
|
3601
|
-
|
|
3602
|
-
selectedIndex: state.
|
|
3603
|
-
|
|
3604
|
-
isFocused: state.focusedPanel === "
|
|
3605
|
-
isReordering: state.
|
|
3725
|
+
releases: state.releases,
|
|
3726
|
+
selectedIndex: state.releaseSelectedIndex,
|
|
3727
|
+
selectedReleaseIds: state.selectedReleaseIds,
|
|
3728
|
+
isFocused: state.focusedPanel === "release",
|
|
3729
|
+
isReordering: state.isReleaseReordering
|
|
3606
3730
|
}
|
|
3607
3731
|
),
|
|
3608
|
-
/* @__PURE__ */
|
|
3732
|
+
/* @__PURE__ */ jsx23(Box23, { width: taskListWidth, children: /* @__PURE__ */ jsx23(
|
|
3609
3733
|
TaskList,
|
|
3610
3734
|
{
|
|
3611
3735
|
tasks: state.tasks,
|
|
@@ -3623,13 +3747,16 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3623
3747
|
),
|
|
3624
3748
|
isSelectedBlocked: state.depBlockers.some((t) => !isTerminalStatus(t.status)),
|
|
3625
3749
|
isFocused: state.focusedPanel === "list",
|
|
3626
|
-
|
|
3750
|
+
releaseFilterActive: state.selectedReleaseIds.size > 0,
|
|
3751
|
+
width: taskListWidth
|
|
3627
3752
|
}
|
|
3628
3753
|
) }),
|
|
3629
|
-
/* @__PURE__ */
|
|
3754
|
+
/* @__PURE__ */ jsx23(Box23, { width: taskDetailWidth, children: previewItem ? /* @__PURE__ */ jsx23(
|
|
3630
3755
|
TaskDetail,
|
|
3631
3756
|
{
|
|
3632
|
-
task:
|
|
3757
|
+
task: previewItem,
|
|
3758
|
+
parentTask: state.releases.find((r) => r.id === previewItem.parentId) ?? null,
|
|
3759
|
+
panelWidth: taskDetailWidth,
|
|
3633
3760
|
blockers: state.depBlockers,
|
|
3634
3761
|
dependents: state.depDependents,
|
|
3635
3762
|
related: state.depRelated,
|
|
@@ -3637,27 +3764,29 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3637
3764
|
isFocused: state.focusedPanel === "detail",
|
|
3638
3765
|
scrollOffset: state.detailScrollOffset
|
|
3639
3766
|
}
|
|
3640
|
-
) : /* @__PURE__ */
|
|
3641
|
-
|
|
3767
|
+
) : /* @__PURE__ */ jsxs19(
|
|
3768
|
+
Box23,
|
|
3642
3769
|
{
|
|
3643
3770
|
flexDirection: "column",
|
|
3644
3771
|
flexGrow: 1,
|
|
3645
3772
|
borderStyle: "bold",
|
|
3646
3773
|
borderColor: theme.border,
|
|
3647
3774
|
children: [
|
|
3648
|
-
/* @__PURE__ */
|
|
3775
|
+
/* @__PURE__ */ jsx23(Box23, { children: /* @__PURE__ */ jsxs19(Text23, { color: theme.title, bold: true, children: [
|
|
3649
3776
|
" ",
|
|
3650
3777
|
"detail"
|
|
3651
3778
|
] }) }),
|
|
3652
|
-
/* @__PURE__ */
|
|
3779
|
+
/* @__PURE__ */ jsx23(Box23, { flexGrow: 1, justifyContent: "center", alignItems: "center", children: /* @__PURE__ */ jsx23(Text23, { dimColor: true, children: "No task selected" }) })
|
|
3653
3780
|
]
|
|
3654
3781
|
}
|
|
3655
3782
|
) })
|
|
3656
3783
|
] })),
|
|
3657
|
-
!state.confirmDelete && state.activeView === ViewType.TaskDetail && state.selectedTask && /* @__PURE__ */
|
|
3784
|
+
!state.confirmDelete && state.activeView === ViewType.TaskDetail && state.selectedTask && /* @__PURE__ */ jsx23(
|
|
3658
3785
|
TaskDetail,
|
|
3659
3786
|
{
|
|
3660
3787
|
task: state.selectedTask,
|
|
3788
|
+
parentTask: state.releases.find((r) => r.id === state.selectedTask.parentId) ?? null,
|
|
3789
|
+
panelWidth: termWidth,
|
|
3661
3790
|
blockers: state.depBlockers,
|
|
3662
3791
|
dependents: state.depDependents,
|
|
3663
3792
|
related: state.depRelated,
|
|
@@ -3665,7 +3794,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3665
3794
|
scrollOffset: state.detailScrollOffset
|
|
3666
3795
|
}
|
|
3667
3796
|
),
|
|
3668
|
-
!state.confirmDelete && state.activeView === ViewType.DependencyList && state.selectedTask && /* @__PURE__ */
|
|
3797
|
+
!state.confirmDelete && state.activeView === ViewType.DependencyList && state.selectedTask && /* @__PURE__ */ jsx23(
|
|
3669
3798
|
DependencyList,
|
|
3670
3799
|
{
|
|
3671
3800
|
task: state.selectedTask,
|
|
@@ -3678,7 +3807,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3678
3807
|
addDepInput: state.addDepInput
|
|
3679
3808
|
}
|
|
3680
3809
|
),
|
|
3681
|
-
!state.confirmDelete && (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit) && /* @__PURE__ */
|
|
3810
|
+
!state.confirmDelete && (state.activeView === ViewType.TaskCreate || state.activeView === ViewType.TaskEdit) && /* @__PURE__ */ jsx23(
|
|
3682
3811
|
TaskForm,
|
|
3683
3812
|
{
|
|
3684
3813
|
editingTask: state.activeView === ViewType.TaskEdit ? state.selectedTask : null,
|
|
@@ -3688,16 +3817,16 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3688
3817
|
onCancel: handleFormCancel
|
|
3689
3818
|
}
|
|
3690
3819
|
),
|
|
3691
|
-
!state.confirmDelete && state.activeView === ViewType.
|
|
3692
|
-
|
|
3820
|
+
!state.confirmDelete && state.activeView === ViewType.ReleasePicker && state.selectedTask && /* @__PURE__ */ jsx23(
|
|
3821
|
+
ReleasePicker,
|
|
3693
3822
|
{
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
onSelect:
|
|
3697
|
-
onCancel:
|
|
3823
|
+
releases: state.releases,
|
|
3824
|
+
currentReleaseId: state.selectedTask.parentId,
|
|
3825
|
+
onSelect: handleReleasePickerSelect,
|
|
3826
|
+
onCancel: handleReleasePickerCancel
|
|
3698
3827
|
}
|
|
3699
3828
|
),
|
|
3700
|
-
!state.confirmDelete && state.activeView === ViewType.ProjectSelector && /* @__PURE__ */
|
|
3829
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectSelector && /* @__PURE__ */ jsx23(
|
|
3701
3830
|
ProjectSelector,
|
|
3702
3831
|
{
|
|
3703
3832
|
projects: state.projects,
|
|
@@ -3710,7 +3839,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3710
3839
|
onCancel: handleProjectCancel
|
|
3711
3840
|
}
|
|
3712
3841
|
),
|
|
3713
|
-
!state.confirmDelete && state.activeView === ViewType.ProjectCreate && /* @__PURE__ */
|
|
3842
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectCreate && /* @__PURE__ */ jsx23(
|
|
3714
3843
|
ProjectForm,
|
|
3715
3844
|
{
|
|
3716
3845
|
initialGitRemote: state.detectedGitRemote ?? void 0,
|
|
@@ -3718,7 +3847,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3718
3847
|
onCancel: handleProjectFormCancel
|
|
3719
3848
|
}
|
|
3720
3849
|
),
|
|
3721
|
-
!state.confirmDelete && state.activeView === ViewType.ProjectEdit && state.editingProject && /* @__PURE__ */
|
|
3850
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectEdit && state.editingProject && /* @__PURE__ */ jsx23(
|
|
3722
3851
|
ProjectForm,
|
|
3723
3852
|
{
|
|
3724
3853
|
editingProject: state.editingProject,
|
|
@@ -3726,7 +3855,7 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3726
3855
|
onCancel: handleProjectFormCancel
|
|
3727
3856
|
}
|
|
3728
3857
|
),
|
|
3729
|
-
!state.confirmDelete && state.activeView === ViewType.ProjectLink && state.linkingProject && /* @__PURE__ */
|
|
3858
|
+
!state.confirmDelete && state.activeView === ViewType.ProjectLink && state.linkingProject && /* @__PURE__ */ jsx23(
|
|
3730
3859
|
ProjectLinkForm,
|
|
3731
3860
|
{
|
|
3732
3861
|
project: state.linkingProject,
|
|
@@ -3736,18 +3865,18 @@ ${state.selectedTask.additionalRequirements}`;
|
|
|
3736
3865
|
onCancel: handleLinkCancel
|
|
3737
3866
|
}
|
|
3738
3867
|
),
|
|
3739
|
-
!state.confirmDelete && state.activeView === ViewType.Help && /* @__PURE__ */
|
|
3868
|
+
!state.confirmDelete && state.activeView === ViewType.Help && /* @__PURE__ */ jsx23(HelpOverlay, {})
|
|
3740
3869
|
] }),
|
|
3741
|
-
/* @__PURE__ */
|
|
3742
|
-
state.flash && /* @__PURE__ */
|
|
3870
|
+
/* @__PURE__ */ jsx23(Crumbs, { breadcrumbs: state.breadcrumbs }),
|
|
3871
|
+
state.flash && /* @__PURE__ */ jsx23(FlashMessage, { message: state.flash.message, level: state.flash.level })
|
|
3743
3872
|
] });
|
|
3744
3873
|
}
|
|
3745
3874
|
|
|
3746
3875
|
// src/tui/index.tsx
|
|
3747
|
-
import { jsx as
|
|
3876
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
3748
3877
|
async function launchTUI(container, initialProject, latestVersion) {
|
|
3749
3878
|
const instance = render(
|
|
3750
|
-
/* @__PURE__ */
|
|
3879
|
+
/* @__PURE__ */ jsx24(App, { container, initialProject, latestVersion }),
|
|
3751
3880
|
{
|
|
3752
3881
|
exitOnCtrlC: true
|
|
3753
3882
|
}
|
|
@@ -3757,4 +3886,4 @@ async function launchTUI(container, initialProject, latestVersion) {
|
|
|
3757
3886
|
export {
|
|
3758
3887
|
launchTUI
|
|
3759
3888
|
};
|
|
3760
|
-
//# sourceMappingURL=tui-
|
|
3889
|
+
//# sourceMappingURL=tui-U7ATVUJU.js.map
|