bdtui 0.8.0 → 0.8.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/CHANGELOG.md +189 -173
- package/README.md +117 -114
- package/bin/bdtui.js +35 -35
- package/package.json +48 -48
- package/src/app.js +617 -604
- package/src/bd.js +130 -130
- package/src/keys.js +100 -99
- package/src/state.js +218 -218
- package/src/views/detail.js +231 -230
- package/src/views/list.js +99 -99
- package/src/views/modals.js +269 -255
package/src/views/list.js
CHANGED
|
@@ -1,99 +1,99 @@
|
|
|
1
|
-
import blessed from 'blessed';
|
|
2
|
-
import { state } from '../state.js';
|
|
3
|
-
|
|
4
|
-
const STATUS_SHORT = {
|
|
5
|
-
open: 'open ',
|
|
6
|
-
in_progress: 'in_prog',
|
|
7
|
-
blocked: 'blocked',
|
|
8
|
-
deferred: 'deferrd',
|
|
9
|
-
closed: 'closed ',
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const PRIORITY_COLOR = ['red', 'yellow', 'green', 'cyan', 'gray'];
|
|
13
|
-
const STATUS_COLOR = {
|
|
14
|
-
open: 'white', in_progress: 'cyan', blocked: 'red',
|
|
15
|
-
deferred: 'yellow', closed: 'gray',
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const TYPE_BADGE = {
|
|
19
|
-
epic: '{magenta-fg}E{/}',
|
|
20
|
-
task: '{blue-fg}T{/}',
|
|
21
|
-
chore: '{gray-fg}C{/}',
|
|
22
|
-
bug: '{red-fg}B{/}',
|
|
23
|
-
story: '{cyan-fg}S{/}',
|
|
24
|
-
feature: '{green-fg}F{/}',
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
function t(color, text) {
|
|
28
|
-
return `{${color}-fg}${text}{/}`;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function formatRow(bead, depth = 0, isLast = false) {
|
|
32
|
-
const id = bead.id.padEnd(14);
|
|
33
|
-
const p = `P${bead.priority ?? 2}`;
|
|
34
|
-
// Effective status mirrors how `bd blocked` derives the Blocked tab:
|
|
35
|
-
// an open bead whose blockers aren't all closed reads as "blocked",
|
|
36
|
-
// not "open". The raw `bd list` rows only carry the stored status.
|
|
37
|
-
const stat = (bead.status === 'open' && state.blockedIds.has(bead.id))
|
|
38
|
-
? 'blocked'
|
|
39
|
-
: (bead.status || 'open');
|
|
40
|
-
const s = (STATUS_SHORT[stat] || stat.slice(0, 7)).padEnd(7);
|
|
41
|
-
const badge = TYPE_BADGE[bead.issue_type] ?? t('gray', '?');
|
|
42
|
-
const prefix = depth > 0 ? t('gray', isLast ? ' └ ' : ' ├ ') : ' ';
|
|
43
|
-
const title = bead.title || '';
|
|
44
|
-
|
|
45
|
-
const idCol = t('gray', id);
|
|
46
|
-
const pCol = t(PRIORITY_COLOR[bead.priority ?? 2] ?? 'white', p);
|
|
47
|
-
const sCol = t(STATUS_COLOR[stat] ?? 'white', s);
|
|
48
|
-
|
|
49
|
-
return `${idCol} ${pCol} ${sCol} ${badge}${prefix}${title}`;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function createList(screen) {
|
|
53
|
-
return blessed.list({
|
|
54
|
-
parent: screen,
|
|
55
|
-
top: 1,
|
|
56
|
-
left: 0,
|
|
57
|
-
width: '40%',
|
|
58
|
-
bottom: 1,
|
|
59
|
-
border: { type: 'line' },
|
|
60
|
-
label: ' Beads ',
|
|
61
|
-
tags: true,
|
|
62
|
-
keys: true,
|
|
63
|
-
vi: true,
|
|
64
|
-
mouse: true,
|
|
65
|
-
scrollbar: { ch: ' ', track: { bg: 'black' }, style: { bg: 'cyan' } },
|
|
66
|
-
style: {
|
|
67
|
-
selected: { bg: 'blue', fg: 'white', bold: true },
|
|
68
|
-
border: { fg: 'gray' },
|
|
69
|
-
label: { fg: 'white', bold: true },
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function renderList(list) {
|
|
75
|
-
const total = state.listOrder.length;
|
|
76
|
-
// In paged ("load more") mode only the first visibleCount rows are rendered;
|
|
77
|
-
// everything else renders the full list.
|
|
78
|
-
const shown = state.visibleCount > 0 && state.visibleCount < total
|
|
79
|
-
? state.visibleCount
|
|
80
|
-
: total;
|
|
81
|
-
const ids = state.listOrder.slice(0, shown);
|
|
82
|
-
|
|
83
|
-
const items = ids.map((id) => {
|
|
84
|
-
const b = state.beadsById.get(id);
|
|
85
|
-
const { depth = 0, isLast = false } = state.treeMeta.get(id) ?? {};
|
|
86
|
-
return b ? formatRow(b, depth, isLast) : t('gray', id);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const selIdx = state.selectedId
|
|
90
|
-
? Math.max(0, ids.indexOf(state.selectedId))
|
|
91
|
-
: 0;
|
|
92
|
-
|
|
93
|
-
const label = shown < total
|
|
94
|
-
? ` Beads ${t('gray', `(showing ${shown} of ${total})`)} `
|
|
95
|
-
: ` Beads ${t('gray', `(${total})`)} `;
|
|
96
|
-
list.setLabel(label);
|
|
97
|
-
list.setItems(items);
|
|
98
|
-
if (ids.length > 0) list.select(Math.min(selIdx, ids.length - 1));
|
|
99
|
-
}
|
|
1
|
+
import blessed from 'blessed';
|
|
2
|
+
import { state } from '../state.js';
|
|
3
|
+
|
|
4
|
+
const STATUS_SHORT = {
|
|
5
|
+
open: 'open ',
|
|
6
|
+
in_progress: 'in_prog',
|
|
7
|
+
blocked: 'blocked',
|
|
8
|
+
deferred: 'deferrd',
|
|
9
|
+
closed: 'closed ',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const PRIORITY_COLOR = ['red', 'yellow', 'green', 'cyan', 'gray'];
|
|
13
|
+
const STATUS_COLOR = {
|
|
14
|
+
open: 'white', in_progress: 'cyan', blocked: 'red',
|
|
15
|
+
deferred: 'yellow', closed: 'gray',
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const TYPE_BADGE = {
|
|
19
|
+
epic: '{magenta-fg}E{/}',
|
|
20
|
+
task: '{blue-fg}T{/}',
|
|
21
|
+
chore: '{gray-fg}C{/}',
|
|
22
|
+
bug: '{red-fg}B{/}',
|
|
23
|
+
story: '{cyan-fg}S{/}',
|
|
24
|
+
feature: '{green-fg}F{/}',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function t(color, text) {
|
|
28
|
+
return `{${color}-fg}${text}{/}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function formatRow(bead, depth = 0, isLast = false) {
|
|
32
|
+
const id = bead.id.padEnd(14);
|
|
33
|
+
const p = `P${bead.priority ?? 2}`;
|
|
34
|
+
// Effective status mirrors how `bd blocked` derives the Blocked tab:
|
|
35
|
+
// an open bead whose blockers aren't all closed reads as "blocked",
|
|
36
|
+
// not "open". The raw `bd list` rows only carry the stored status.
|
|
37
|
+
const stat = (bead.status === 'open' && state.blockedIds.has(bead.id))
|
|
38
|
+
? 'blocked'
|
|
39
|
+
: (bead.status || 'open');
|
|
40
|
+
const s = (STATUS_SHORT[stat] || stat.slice(0, 7)).padEnd(7);
|
|
41
|
+
const badge = TYPE_BADGE[bead.issue_type] ?? t('gray', '?');
|
|
42
|
+
const prefix = depth > 0 ? t('gray', isLast ? ' └ ' : ' ├ ') : ' ';
|
|
43
|
+
const title = bead.title || '';
|
|
44
|
+
|
|
45
|
+
const idCol = t('gray', id);
|
|
46
|
+
const pCol = t(PRIORITY_COLOR[bead.priority ?? 2] ?? 'white', p);
|
|
47
|
+
const sCol = t(STATUS_COLOR[stat] ?? 'white', s);
|
|
48
|
+
|
|
49
|
+
return `${idCol} ${pCol} ${sCol} ${badge}${prefix}${title}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function createList(screen) {
|
|
53
|
+
return blessed.list({
|
|
54
|
+
parent: screen,
|
|
55
|
+
top: 1,
|
|
56
|
+
left: 0,
|
|
57
|
+
width: '40%',
|
|
58
|
+
bottom: 1,
|
|
59
|
+
border: { type: 'line' },
|
|
60
|
+
label: ' Beads ',
|
|
61
|
+
tags: true,
|
|
62
|
+
keys: true,
|
|
63
|
+
vi: true,
|
|
64
|
+
mouse: true,
|
|
65
|
+
scrollbar: { ch: ' ', track: { bg: 'black' }, style: { bg: 'cyan' } },
|
|
66
|
+
style: {
|
|
67
|
+
selected: { bg: 'blue', fg: 'white', bold: true },
|
|
68
|
+
border: { fg: 'gray' },
|
|
69
|
+
label: { fg: 'white', bold: true },
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function renderList(list) {
|
|
75
|
+
const total = state.listOrder.length;
|
|
76
|
+
// In paged ("load more") mode only the first visibleCount rows are rendered;
|
|
77
|
+
// everything else renders the full list.
|
|
78
|
+
const shown = state.visibleCount > 0 && state.visibleCount < total
|
|
79
|
+
? state.visibleCount
|
|
80
|
+
: total;
|
|
81
|
+
const ids = state.listOrder.slice(0, shown);
|
|
82
|
+
|
|
83
|
+
const items = ids.map((id) => {
|
|
84
|
+
const b = state.beadsById.get(id);
|
|
85
|
+
const { depth = 0, isLast = false } = state.treeMeta.get(id) ?? {};
|
|
86
|
+
return b ? formatRow(b, depth, isLast) : t('gray', id);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const selIdx = state.selectedId
|
|
90
|
+
? Math.max(0, ids.indexOf(state.selectedId))
|
|
91
|
+
: 0;
|
|
92
|
+
|
|
93
|
+
const label = shown < total
|
|
94
|
+
? ` Beads ${t('gray', `(showing ${shown} of ${total})`)} `
|
|
95
|
+
: ` Beads ${t('gray', `(${total})`)} `;
|
|
96
|
+
list.setLabel(label);
|
|
97
|
+
list.setItems(items);
|
|
98
|
+
if (ids.length > 0) list.select(Math.min(selIdx, ids.length - 1));
|
|
99
|
+
}
|