@ondrej-svec/hog 1.9.3 → 1.11.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/dist/cli.js +1014 -832
- package/dist/cli.js.map +1 -1
- package/dist/fetch-worker.js +35 -26
- package/dist/fetch-worker.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -740,10 +740,11 @@ function fetchProjectEnrichment(repo, projectNumber) {
|
|
|
740
740
|
const [owner] = repo.split("/");
|
|
741
741
|
if (!owner) return /* @__PURE__ */ new Map();
|
|
742
742
|
const query = `
|
|
743
|
-
query($owner: String!, $projectNumber: Int
|
|
743
|
+
query($owner: String!, $projectNumber: Int!, $cursor: String) {
|
|
744
744
|
organization(login: $owner) {
|
|
745
745
|
projectV2(number: $projectNumber) {
|
|
746
|
-
items(first: 100) {
|
|
746
|
+
items(first: 100, after: $cursor) {
|
|
747
|
+
pageInfo { hasNextPage endCursor }
|
|
747
748
|
nodes {
|
|
748
749
|
content {
|
|
749
750
|
... on Issue {
|
|
@@ -769,33 +770,41 @@ function fetchProjectEnrichment(repo, projectNumber) {
|
|
|
769
770
|
}
|
|
770
771
|
`;
|
|
771
772
|
try {
|
|
772
|
-
const result = runGhJson([
|
|
773
|
-
"api",
|
|
774
|
-
"graphql",
|
|
775
|
-
"-f",
|
|
776
|
-
`query=${query}`,
|
|
777
|
-
"-F",
|
|
778
|
-
`owner=${owner}`,
|
|
779
|
-
"-F",
|
|
780
|
-
`projectNumber=${String(projectNumber)}`
|
|
781
|
-
]);
|
|
782
|
-
const items = result?.data?.organization?.projectV2?.items?.nodes ?? [];
|
|
783
773
|
const enrichMap = /* @__PURE__ */ new Map();
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
const
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
|
|
774
|
+
let cursor = null;
|
|
775
|
+
do {
|
|
776
|
+
const args = [
|
|
777
|
+
"api",
|
|
778
|
+
"graphql",
|
|
779
|
+
"-f",
|
|
780
|
+
`query=${query}`,
|
|
781
|
+
"-F",
|
|
782
|
+
`owner=${owner}`,
|
|
783
|
+
"-F",
|
|
784
|
+
`projectNumber=${String(projectNumber)}`
|
|
785
|
+
];
|
|
786
|
+
if (cursor) args.push("-f", `cursor=${cursor}`);
|
|
787
|
+
const result = runGhJson(args);
|
|
788
|
+
const page = result?.data?.organization?.projectV2?.items;
|
|
789
|
+
const nodes = page?.nodes ?? [];
|
|
790
|
+
for (const item of nodes) {
|
|
791
|
+
if (!item?.content?.number) continue;
|
|
792
|
+
const enrichment = {};
|
|
793
|
+
const fieldValues = item.fieldValues?.nodes ?? [];
|
|
794
|
+
for (const fv of fieldValues) {
|
|
795
|
+
if (!fv) continue;
|
|
796
|
+
if ("date" in fv && fv.date && DATE_FIELD_NAME_RE2.test(fv.field?.name ?? "")) {
|
|
797
|
+
enrichment.targetDate = fv.date;
|
|
798
|
+
}
|
|
799
|
+
if ("name" in fv && fv.field?.name === "Status" && fv.name) {
|
|
800
|
+
enrichment.projectStatus = fv.name;
|
|
801
|
+
}
|
|
795
802
|
}
|
|
803
|
+
enrichMap.set(item.content.number, enrichment);
|
|
796
804
|
}
|
|
797
|
-
|
|
798
|
-
|
|
805
|
+
if (!page?.pageInfo?.hasNextPage) break;
|
|
806
|
+
cursor = page.pageInfo.endCursor ?? null;
|
|
807
|
+
} while (cursor);
|
|
799
808
|
return enrichMap;
|
|
800
809
|
} catch {
|
|
801
810
|
return /* @__PURE__ */ new Map();
|
|
@@ -1630,7 +1639,7 @@ ${dueLine}` : dueLine;
|
|
|
1630
1639
|
const output = await createIssueAsync(repo, title, effectiveBody, labels);
|
|
1631
1640
|
const match = output.match(/\/(\d+)$/);
|
|
1632
1641
|
const issueNumber = match?.[1] ? parseInt(match[1], 10) : 0;
|
|
1633
|
-
const
|
|
1642
|
+
const shortName2 = repoConfig?.shortName ?? repo;
|
|
1634
1643
|
if (issueNumber > 0 && dueDate && repoConfig?.dueDateFieldId) {
|
|
1635
1644
|
const dueDateConfig = {
|
|
1636
1645
|
projectNumber: repoConfig.projectNumber,
|
|
@@ -1639,7 +1648,7 @@ ${dueLine}` : dueLine;
|
|
|
1639
1648
|
updateProjectItemDateAsync(repo, issueNumber, dueDateConfig, dueDate).catch(() => {
|
|
1640
1649
|
});
|
|
1641
1650
|
}
|
|
1642
|
-
t.resolve(`Created ${
|
|
1651
|
+
t.resolve(`Created ${shortName2}#${issueNumber}`);
|
|
1643
1652
|
refresh();
|
|
1644
1653
|
onOverlayDone();
|
|
1645
1654
|
return issueNumber > 0 ? { repo, issueNumber } : null;
|
|
@@ -1999,7 +2008,13 @@ function useKeyboard({
|
|
|
1999
2008
|
selectedRepoStatusOptionsLength,
|
|
2000
2009
|
actions,
|
|
2001
2010
|
onSearchEscape,
|
|
2002
|
-
|
|
2011
|
+
panelFocus,
|
|
2012
|
+
reposNav,
|
|
2013
|
+
statusesNav,
|
|
2014
|
+
activityNav,
|
|
2015
|
+
onRepoEnter,
|
|
2016
|
+
onStatusEnter,
|
|
2017
|
+
onActivityEnter
|
|
2003
2018
|
}) {
|
|
2004
2019
|
const {
|
|
2005
2020
|
exit,
|
|
@@ -2035,19 +2050,41 @@ function useKeyboard({
|
|
|
2035
2050
|
}
|
|
2036
2051
|
if (ui.canNavigate) {
|
|
2037
2052
|
if (input2 === "j" || key.downArrow) {
|
|
2038
|
-
|
|
2053
|
+
switch (panelFocus.activePanelId) {
|
|
2054
|
+
case 1:
|
|
2055
|
+
reposNav.moveDown();
|
|
2056
|
+
break;
|
|
2057
|
+
case 2:
|
|
2058
|
+
statusesNav.moveDown();
|
|
2059
|
+
break;
|
|
2060
|
+
case 3:
|
|
2061
|
+
nav.moveDown();
|
|
2062
|
+
break;
|
|
2063
|
+
case 4:
|
|
2064
|
+
activityNav.moveDown();
|
|
2065
|
+
break;
|
|
2066
|
+
default:
|
|
2067
|
+
break;
|
|
2068
|
+
}
|
|
2039
2069
|
return;
|
|
2040
2070
|
}
|
|
2041
2071
|
if (input2 === "k" || key.upArrow) {
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2072
|
+
switch (panelFocus.activePanelId) {
|
|
2073
|
+
case 1:
|
|
2074
|
+
reposNav.moveUp();
|
|
2075
|
+
break;
|
|
2076
|
+
case 2:
|
|
2077
|
+
statusesNav.moveUp();
|
|
2078
|
+
break;
|
|
2079
|
+
case 3:
|
|
2080
|
+
nav.moveUp();
|
|
2081
|
+
break;
|
|
2082
|
+
case 4:
|
|
2083
|
+
activityNav.moveUp();
|
|
2084
|
+
break;
|
|
2085
|
+
default:
|
|
2086
|
+
break;
|
|
2049
2087
|
}
|
|
2050
|
-
key.shift ? tabNav.prev() : tabNav.next();
|
|
2051
2088
|
return;
|
|
2052
2089
|
}
|
|
2053
2090
|
}
|
|
@@ -2077,8 +2114,8 @@ function useKeyboard({
|
|
|
2077
2114
|
if (input2 === "r" && handleErrorAction("retry")) return;
|
|
2078
2115
|
if (ui.canAct) {
|
|
2079
2116
|
const digit = parseInt(input2, 10);
|
|
2080
|
-
if (!Number.isNaN(digit) && digit >=
|
|
2081
|
-
|
|
2117
|
+
if (!Number.isNaN(digit) && digit >= 0 && digit <= 4) {
|
|
2118
|
+
panelFocus.focusPanel(digit);
|
|
2082
2119
|
return;
|
|
2083
2120
|
}
|
|
2084
2121
|
if (input2 === "/") {
|
|
@@ -2095,7 +2132,7 @@ function useKeyboard({
|
|
|
2095
2132
|
refresh();
|
|
2096
2133
|
return;
|
|
2097
2134
|
}
|
|
2098
|
-
if (input2 === "
|
|
2135
|
+
if (input2 === "o") {
|
|
2099
2136
|
handleSlack();
|
|
2100
2137
|
return;
|
|
2101
2138
|
}
|
|
@@ -2178,7 +2215,22 @@ function useKeyboard({
|
|
|
2178
2215
|
return;
|
|
2179
2216
|
}
|
|
2180
2217
|
if (key.return) {
|
|
2181
|
-
|
|
2218
|
+
switch (panelFocus.activePanelId) {
|
|
2219
|
+
case 1:
|
|
2220
|
+
onRepoEnter();
|
|
2221
|
+
break;
|
|
2222
|
+
case 2:
|
|
2223
|
+
onStatusEnter();
|
|
2224
|
+
break;
|
|
2225
|
+
case 3:
|
|
2226
|
+
handleOpen();
|
|
2227
|
+
break;
|
|
2228
|
+
case 4:
|
|
2229
|
+
onActivityEnter();
|
|
2230
|
+
break;
|
|
2231
|
+
default:
|
|
2232
|
+
break;
|
|
2233
|
+
}
|
|
2182
2234
|
return;
|
|
2183
2235
|
}
|
|
2184
2236
|
}
|
|
@@ -2186,7 +2238,13 @@ function useKeyboard({
|
|
|
2186
2238
|
[
|
|
2187
2239
|
ui,
|
|
2188
2240
|
nav,
|
|
2189
|
-
|
|
2241
|
+
panelFocus,
|
|
2242
|
+
reposNav,
|
|
2243
|
+
statusesNav,
|
|
2244
|
+
activityNav,
|
|
2245
|
+
onRepoEnter,
|
|
2246
|
+
onStatusEnter,
|
|
2247
|
+
onActivityEnter,
|
|
2190
2248
|
exit,
|
|
2191
2249
|
refresh,
|
|
2192
2250
|
handleSlack,
|
|
@@ -2492,26 +2550,42 @@ var init_use_navigation = __esm({
|
|
|
2492
2550
|
}
|
|
2493
2551
|
});
|
|
2494
2552
|
|
|
2553
|
+
// src/board/hooks/use-panel-focus.ts
|
|
2554
|
+
import { useCallback as useCallback7, useState as useState4 } from "react";
|
|
2555
|
+
function usePanelFocus(initialPanel = 3) {
|
|
2556
|
+
const [activePanelId, setActivePanelId] = useState4(initialPanel);
|
|
2557
|
+
const focusPanel = useCallback7((id) => {
|
|
2558
|
+
setActivePanelId(id);
|
|
2559
|
+
}, []);
|
|
2560
|
+
const isPanelActive = useCallback7((id) => activePanelId === id, [activePanelId]);
|
|
2561
|
+
return { activePanelId, focusPanel, isPanelActive };
|
|
2562
|
+
}
|
|
2563
|
+
var init_use_panel_focus = __esm({
|
|
2564
|
+
"src/board/hooks/use-panel-focus.ts"() {
|
|
2565
|
+
"use strict";
|
|
2566
|
+
}
|
|
2567
|
+
});
|
|
2568
|
+
|
|
2495
2569
|
// src/board/hooks/use-toast.ts
|
|
2496
|
-
import { useCallback as
|
|
2570
|
+
import { useCallback as useCallback8, useRef as useRef6, useState as useState5 } from "react";
|
|
2497
2571
|
function useToast() {
|
|
2498
|
-
const [toasts, setToasts] =
|
|
2572
|
+
const [toasts, setToasts] = useState5([]);
|
|
2499
2573
|
const timersRef = useRef6(/* @__PURE__ */ new Map());
|
|
2500
|
-
const clearTimer =
|
|
2574
|
+
const clearTimer = useCallback8((id) => {
|
|
2501
2575
|
const timer = timersRef.current.get(id);
|
|
2502
2576
|
if (timer) {
|
|
2503
2577
|
clearTimeout(timer);
|
|
2504
2578
|
timersRef.current.delete(id);
|
|
2505
2579
|
}
|
|
2506
2580
|
}, []);
|
|
2507
|
-
const removeToast =
|
|
2581
|
+
const removeToast = useCallback8(
|
|
2508
2582
|
(id) => {
|
|
2509
2583
|
clearTimer(id);
|
|
2510
2584
|
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
2511
2585
|
},
|
|
2512
2586
|
[clearTimer]
|
|
2513
2587
|
);
|
|
2514
|
-
const addToast =
|
|
2588
|
+
const addToast = useCallback8(
|
|
2515
2589
|
(t) => {
|
|
2516
2590
|
const id = `toast-${++nextId}`;
|
|
2517
2591
|
const newToast = { ...t, id, createdAt: Date.now() };
|
|
@@ -2540,25 +2614,25 @@ function useToast() {
|
|
|
2540
2614
|
[removeToast, clearTimer]
|
|
2541
2615
|
);
|
|
2542
2616
|
const toast = {
|
|
2543
|
-
info:
|
|
2617
|
+
info: useCallback8(
|
|
2544
2618
|
(message) => {
|
|
2545
2619
|
addToast({ type: "info", message });
|
|
2546
2620
|
},
|
|
2547
2621
|
[addToast]
|
|
2548
2622
|
),
|
|
2549
|
-
success:
|
|
2623
|
+
success: useCallback8(
|
|
2550
2624
|
(message) => {
|
|
2551
2625
|
addToast({ type: "success", message });
|
|
2552
2626
|
},
|
|
2553
2627
|
[addToast]
|
|
2554
2628
|
),
|
|
2555
|
-
error:
|
|
2629
|
+
error: useCallback8(
|
|
2556
2630
|
(message, retry) => {
|
|
2557
2631
|
addToast(retry ? { type: "error", message, retry } : { type: "error", message });
|
|
2558
2632
|
},
|
|
2559
2633
|
[addToast]
|
|
2560
2634
|
),
|
|
2561
|
-
loading:
|
|
2635
|
+
loading: useCallback8(
|
|
2562
2636
|
(message) => {
|
|
2563
2637
|
const id = addToast({ type: "loading", message });
|
|
2564
2638
|
return {
|
|
@@ -2575,7 +2649,7 @@ function useToast() {
|
|
|
2575
2649
|
[addToast, removeToast]
|
|
2576
2650
|
)
|
|
2577
2651
|
};
|
|
2578
|
-
const handleErrorAction =
|
|
2652
|
+
const handleErrorAction = useCallback8(
|
|
2579
2653
|
(action) => {
|
|
2580
2654
|
const errorToast = toasts.find((t) => t.type === "error");
|
|
2581
2655
|
if (!errorToast) return false;
|
|
@@ -2605,7 +2679,7 @@ var init_use_toast = __esm({
|
|
|
2605
2679
|
});
|
|
2606
2680
|
|
|
2607
2681
|
// src/board/hooks/use-ui-state.ts
|
|
2608
|
-
import { useCallback as
|
|
2682
|
+
import { useCallback as useCallback9, useReducer as useReducer2 } from "react";
|
|
2609
2683
|
function enterStatusMode(state) {
|
|
2610
2684
|
if (state.mode !== "normal" && state.mode !== "overlay:bulkAction") return state;
|
|
2611
2685
|
const previousMode = state.mode === "overlay:bulkAction" ? "multiSelect" : "normal";
|
|
@@ -2679,22 +2753,22 @@ function useUIState() {
|
|
|
2679
2753
|
const [state, dispatch] = useReducer2(uiReducer, INITIAL_STATE2);
|
|
2680
2754
|
return {
|
|
2681
2755
|
state,
|
|
2682
|
-
enterSearch:
|
|
2683
|
-
enterComment:
|
|
2684
|
-
enterStatus:
|
|
2685
|
-
enterCreate:
|
|
2686
|
-
enterCreateNl:
|
|
2687
|
-
enterLabel:
|
|
2688
|
-
enterMultiSelect:
|
|
2689
|
-
enterBulkAction:
|
|
2690
|
-
enterConfirmPick:
|
|
2691
|
-
enterFocus:
|
|
2692
|
-
enterFuzzyPicker:
|
|
2693
|
-
enterEditIssue:
|
|
2694
|
-
toggleHelp:
|
|
2695
|
-
exitOverlay:
|
|
2696
|
-
exitToNormal:
|
|
2697
|
-
clearMultiSelect:
|
|
2756
|
+
enterSearch: useCallback9(() => dispatch({ type: "ENTER_SEARCH" }), []),
|
|
2757
|
+
enterComment: useCallback9(() => dispatch({ type: "ENTER_COMMENT" }), []),
|
|
2758
|
+
enterStatus: useCallback9(() => dispatch({ type: "ENTER_STATUS" }), []),
|
|
2759
|
+
enterCreate: useCallback9(() => dispatch({ type: "ENTER_CREATE" }), []),
|
|
2760
|
+
enterCreateNl: useCallback9(() => dispatch({ type: "ENTER_CREATE_NL" }), []),
|
|
2761
|
+
enterLabel: useCallback9(() => dispatch({ type: "ENTER_LABEL" }), []),
|
|
2762
|
+
enterMultiSelect: useCallback9(() => dispatch({ type: "ENTER_MULTI_SELECT" }), []),
|
|
2763
|
+
enterBulkAction: useCallback9(() => dispatch({ type: "ENTER_BULK_ACTION" }), []),
|
|
2764
|
+
enterConfirmPick: useCallback9(() => dispatch({ type: "ENTER_CONFIRM_PICK" }), []),
|
|
2765
|
+
enterFocus: useCallback9(() => dispatch({ type: "ENTER_FOCUS" }), []),
|
|
2766
|
+
enterFuzzyPicker: useCallback9(() => dispatch({ type: "ENTER_FUZZY_PICKER" }), []),
|
|
2767
|
+
enterEditIssue: useCallback9(() => dispatch({ type: "ENTER_EDIT_ISSUE" }), []),
|
|
2768
|
+
toggleHelp: useCallback9(() => dispatch({ type: "TOGGLE_HELP" }), []),
|
|
2769
|
+
exitOverlay: useCallback9(() => dispatch({ type: "EXIT_OVERLAY" }), []),
|
|
2770
|
+
exitToNormal: useCallback9(() => dispatch({ type: "EXIT_TO_NORMAL" }), []),
|
|
2771
|
+
clearMultiSelect: useCallback9(() => dispatch({ type: "CLEAR_MULTI_SELECT" }), []),
|
|
2698
2772
|
canNavigate: canNavigate(state),
|
|
2699
2773
|
canAct: canAct(state),
|
|
2700
2774
|
isOverlay: isOverlay(state)
|
|
@@ -2714,7 +2788,7 @@ var init_use_ui_state = __esm({
|
|
|
2714
2788
|
|
|
2715
2789
|
// src/board/components/action-log.tsx
|
|
2716
2790
|
import { Box, Text } from "ink";
|
|
2717
|
-
import { useEffect as useEffect2, useState as
|
|
2791
|
+
import { useEffect as useEffect2, useState as useState6 } from "react";
|
|
2718
2792
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2719
2793
|
function relativeTime(ago) {
|
|
2720
2794
|
const seconds = Math.floor((Date.now() - ago) / 1e3);
|
|
@@ -2735,7 +2809,7 @@ function statusColor(status) {
|
|
|
2735
2809
|
return "yellow";
|
|
2736
2810
|
}
|
|
2737
2811
|
function ActionLog({ entries }) {
|
|
2738
|
-
const [, setTick] =
|
|
2812
|
+
const [, setTick] = useState6(0);
|
|
2739
2813
|
useEffect2(() => {
|
|
2740
2814
|
const id = setInterval(() => setTick((t) => t + 1), 5e3);
|
|
2741
2815
|
return () => clearInterval(id);
|
|
@@ -2774,14 +2848,61 @@ var init_action_log = __esm({
|
|
|
2774
2848
|
}
|
|
2775
2849
|
});
|
|
2776
2850
|
|
|
2777
|
-
// src/board/components/
|
|
2851
|
+
// src/board/components/activity-panel.tsx
|
|
2778
2852
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
2779
|
-
import {
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
const
|
|
2783
|
-
|
|
2853
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
2854
|
+
function ActivityPanel({ events, selectedIdx, isActive, height }) {
|
|
2855
|
+
const borderColor = isActive ? "cyan" : "gray";
|
|
2856
|
+
const maxRows = Math.max(1, height - 2);
|
|
2857
|
+
const visible = events.slice(0, maxRows);
|
|
2858
|
+
return /* @__PURE__ */ jsxs2(
|
|
2859
|
+
Box2,
|
|
2860
|
+
{
|
|
2861
|
+
borderStyle: "single",
|
|
2862
|
+
borderColor,
|
|
2863
|
+
flexDirection: "column",
|
|
2864
|
+
height,
|
|
2865
|
+
overflow: "hidden",
|
|
2866
|
+
children: [
|
|
2867
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, color: isActive ? "cyan" : "white", children: "[4] Activity" }),
|
|
2868
|
+
visible.length === 0 ? /* @__PURE__ */ jsx2(Text2, { color: "gray", children: " No recent activity" }) : visible.map((event, i) => {
|
|
2869
|
+
const isSel = isActive && i === selectedIdx;
|
|
2870
|
+
const ago = timeAgo(event.timestamp);
|
|
2871
|
+
return /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
2872
|
+
/* @__PURE__ */ jsxs2(Text2, { color: isSel ? "cyan" : "gray", bold: isSel, children: [
|
|
2873
|
+
isSel ? "\u25B6 " : " ",
|
|
2874
|
+
ago
|
|
2875
|
+
] }),
|
|
2876
|
+
/* @__PURE__ */ jsxs2(Text2, { color: isSel ? "white" : "gray", children: [
|
|
2877
|
+
" ",
|
|
2878
|
+
"@",
|
|
2879
|
+
event.actor,
|
|
2880
|
+
" ",
|
|
2881
|
+
event.summary,
|
|
2882
|
+
" "
|
|
2883
|
+
] }),
|
|
2884
|
+
/* @__PURE__ */ jsxs2(Text2, { dimColor: true, children: [
|
|
2885
|
+
"(",
|
|
2886
|
+
event.repoShortName,
|
|
2887
|
+
")"
|
|
2888
|
+
] })
|
|
2889
|
+
] }, `${event.repoShortName}:${event.issueNumber}:${i}`);
|
|
2890
|
+
})
|
|
2891
|
+
]
|
|
2892
|
+
}
|
|
2893
|
+
);
|
|
2784
2894
|
}
|
|
2895
|
+
var init_activity_panel = __esm({
|
|
2896
|
+
"src/board/components/activity-panel.tsx"() {
|
|
2897
|
+
"use strict";
|
|
2898
|
+
init_constants();
|
|
2899
|
+
}
|
|
2900
|
+
});
|
|
2901
|
+
|
|
2902
|
+
// src/board/components/detail-panel.tsx
|
|
2903
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
2904
|
+
import { useEffect as useEffect3 } from "react";
|
|
2905
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2785
2906
|
function stripMarkdown(text) {
|
|
2786
2907
|
return text.replace(/^#{1,6}\s+/gm, "").replace(/\*\*(.+?)\*\*/g, "$1").replace(/\*(.+?)\*/g, "$1").replace(/__(.+?)__/g, "$1").replace(/_(.+?)_/g, "$1").replace(/~~(.+?)~~/g, "$1").replace(/`{1,3}[^`]*`{1,3}/g, (m) => m.replace(/`/g, "")).replace(/^\s*[-*+]\s+/gm, " - ").replace(/^\s*\d+\.\s+/gm, " ").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/!\[([^\]]*)\]\([^)]+\)/g, "[$1]").replace(/^>\s+/gm, " ").replace(/---+/g, "").replace(/\n{3,}/g, "\n\n").trim();
|
|
2787
2908
|
}
|
|
@@ -2800,11 +2921,11 @@ function BodySection({
|
|
|
2800
2921
|
issueNumber
|
|
2801
2922
|
}) {
|
|
2802
2923
|
const { text, remaining } = formatBody(body, 15);
|
|
2803
|
-
return /* @__PURE__ */
|
|
2804
|
-
/* @__PURE__ */
|
|
2805
|
-
/* @__PURE__ */
|
|
2806
|
-
/* @__PURE__ */
|
|
2807
|
-
remaining > 0 ? /* @__PURE__ */
|
|
2924
|
+
return /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
2925
|
+
/* @__PURE__ */ jsx3(Text3, { children: "" }),
|
|
2926
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "--- Description ---" }),
|
|
2927
|
+
/* @__PURE__ */ jsx3(Text3, { wrap: "wrap", children: text }),
|
|
2928
|
+
remaining > 0 ? /* @__PURE__ */ jsxs3(Text3, { dimColor: true, children: [
|
|
2808
2929
|
"... (",
|
|
2809
2930
|
remaining,
|
|
2810
2931
|
" more lines \u2014 gh issue view ",
|
|
@@ -2825,185 +2946,143 @@ function formatCommentAge(createdAt) {
|
|
|
2825
2946
|
}
|
|
2826
2947
|
function DetailPanel({
|
|
2827
2948
|
issue,
|
|
2828
|
-
task: task2,
|
|
2829
2949
|
width,
|
|
2950
|
+
isActive,
|
|
2830
2951
|
commentsState,
|
|
2831
2952
|
fetchComments,
|
|
2832
2953
|
issueRepo
|
|
2833
2954
|
}) {
|
|
2955
|
+
const borderColor = isActive ? "cyan" : "gray";
|
|
2834
2956
|
useEffect3(() => {
|
|
2835
2957
|
if (!(issue && fetchComments && issueRepo)) return;
|
|
2836
2958
|
if (commentsState !== null && commentsState !== void 0) return;
|
|
2837
2959
|
fetchComments(issueRepo, issue.number);
|
|
2838
2960
|
}, [issue, issueRepo, fetchComments, commentsState]);
|
|
2839
|
-
if (!
|
|
2840
|
-
return /* @__PURE__ */
|
|
2841
|
-
|
|
2842
|
-
{
|
|
2843
|
-
width,
|
|
2844
|
-
borderStyle: "single",
|
|
2845
|
-
borderColor: "gray",
|
|
2846
|
-
flexDirection: "column",
|
|
2847
|
-
paddingX: 1,
|
|
2848
|
-
children: /* @__PURE__ */ jsx2(Text2, { color: "gray", children: "No item selected" })
|
|
2849
|
-
}
|
|
2850
|
-
);
|
|
2851
|
-
}
|
|
2852
|
-
if (issue) {
|
|
2853
|
-
return /* @__PURE__ */ jsxs2(
|
|
2854
|
-
Box2,
|
|
2961
|
+
if (!issue) {
|
|
2962
|
+
return /* @__PURE__ */ jsxs3(
|
|
2963
|
+
Box3,
|
|
2855
2964
|
{
|
|
2856
2965
|
width,
|
|
2857
2966
|
borderStyle: "single",
|
|
2858
|
-
borderColor
|
|
2967
|
+
borderColor,
|
|
2859
2968
|
flexDirection: "column",
|
|
2860
2969
|
paddingX: 1,
|
|
2861
2970
|
children: [
|
|
2862
|
-
/* @__PURE__ */
|
|
2863
|
-
|
|
2864
|
-
issue.number,
|
|
2865
|
-
" ",
|
|
2866
|
-
issue.title
|
|
2867
|
-
] }),
|
|
2868
|
-
/* @__PURE__ */ jsx2(Text2, { children: "" }),
|
|
2869
|
-
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
2870
|
-
/* @__PURE__ */ jsx2(Text2, { color: "gray", children: "State: " }),
|
|
2871
|
-
/* @__PURE__ */ jsx2(Text2, { color: issue.state === "open" ? "green" : "red", children: issue.state })
|
|
2872
|
-
] }),
|
|
2873
|
-
(issue.assignees ?? []).length > 0 ? /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
2874
|
-
/* @__PURE__ */ jsx2(Text2, { color: "gray", children: "Assignees: " }),
|
|
2875
|
-
/* @__PURE__ */ jsx2(Text2, { children: (issue.assignees ?? []).map((a) => a.login).join(", ") })
|
|
2876
|
-
] }) : null,
|
|
2877
|
-
issue.labels.length > 0 ? /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
2878
|
-
/* @__PURE__ */ jsx2(Text2, { color: "gray", children: "Labels: " }),
|
|
2879
|
-
/* @__PURE__ */ jsx2(Text2, { children: issue.labels.map((l) => l.name).join(", ") })
|
|
2880
|
-
] }) : null,
|
|
2881
|
-
issue.projectStatus ? /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
2882
|
-
/* @__PURE__ */ jsx2(Text2, { color: "gray", children: "Status: " }),
|
|
2883
|
-
/* @__PURE__ */ jsx2(Text2, { color: "magenta", children: issue.projectStatus })
|
|
2884
|
-
] }) : null,
|
|
2885
|
-
issue.targetDate ? /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
2886
|
-
/* @__PURE__ */ jsx2(Text2, { color: "gray", children: "Target: " }),
|
|
2887
|
-
/* @__PURE__ */ jsx2(Text2, { children: issue.targetDate })
|
|
2888
|
-
] }) : null,
|
|
2889
|
-
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
2890
|
-
/* @__PURE__ */ jsx2(Text2, { color: "gray", children: "Updated: " }),
|
|
2891
|
-
/* @__PURE__ */ jsx2(Text2, { children: new Date(issue.updatedAt).toLocaleString() })
|
|
2892
|
-
] }),
|
|
2893
|
-
issue.slackThreadUrl ? /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
2894
|
-
/* @__PURE__ */ jsx2(Text2, { color: "gray", children: "Slack: " }),
|
|
2895
|
-
/* @__PURE__ */ jsx2(Text2, { color: "blue", children: countSlackLinks(issue.body) > 1 ? `${countSlackLinks(issue.body)} links (s opens first)` : "thread (s to open)" })
|
|
2896
|
-
] }) : null,
|
|
2897
|
-
issue.body ? /* @__PURE__ */ jsx2(BodySection, { body: issue.body, issueNumber: issue.number }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
2898
|
-
/* @__PURE__ */ jsx2(Text2, { children: "" }),
|
|
2899
|
-
/* @__PURE__ */ jsx2(Text2, { color: "gray", children: "(no description)" })
|
|
2900
|
-
] }),
|
|
2901
|
-
/* @__PURE__ */ jsx2(Text2, { children: "" }),
|
|
2902
|
-
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "--- Comments ---" }),
|
|
2903
|
-
commentsState === "loading" ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "fetching comments..." }) : commentsState === "error" ? /* @__PURE__ */ jsx2(Text2, { color: "red", children: "could not load comments" }) : commentsState && commentsState.length === 0 ? /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "No comments yet." }) : commentsState && commentsState.length > 0 ? commentsState.slice(-5).map((comment, i) => (
|
|
2904
|
-
// biome-ignore lint/suspicious/noArrayIndexKey: stable list
|
|
2905
|
-
/* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginBottom: 1, children: [
|
|
2906
|
-
/* @__PURE__ */ jsxs2(Text2, { color: "cyan", children: [
|
|
2907
|
-
"@",
|
|
2908
|
-
comment.author.login,
|
|
2909
|
-
" \xB7 ",
|
|
2910
|
-
formatCommentAge(comment.createdAt)
|
|
2911
|
-
] }),
|
|
2912
|
-
/* @__PURE__ */ jsxs2(Text2, { wrap: "wrap", children: [
|
|
2913
|
-
" ",
|
|
2914
|
-
comment.body.split("\n")[0]
|
|
2915
|
-
] })
|
|
2916
|
-
] }, i)
|
|
2917
|
-
)) : /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "fetching comments..." }),
|
|
2918
|
-
/* @__PURE__ */ jsx2(Text2, { children: "" }),
|
|
2919
|
-
/* @__PURE__ */ jsx2(Text2, { color: "gray", dimColor: true, children: issue.url })
|
|
2971
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: isActive ? "cyan" : "white", children: "[0] Detail" }),
|
|
2972
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "No item selected" })
|
|
2920
2973
|
]
|
|
2921
2974
|
}
|
|
2922
2975
|
);
|
|
2923
2976
|
}
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
Box2,
|
|
2977
|
+
return /* @__PURE__ */ jsxs3(
|
|
2978
|
+
Box3,
|
|
2927
2979
|
{
|
|
2928
2980
|
width,
|
|
2929
2981
|
borderStyle: "single",
|
|
2930
|
-
borderColor
|
|
2982
|
+
borderColor,
|
|
2931
2983
|
flexDirection: "column",
|
|
2932
2984
|
paddingX: 1,
|
|
2933
2985
|
children: [
|
|
2934
|
-
/* @__PURE__ */
|
|
2935
|
-
/* @__PURE__ */
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2986
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, color: isActive ? "cyan" : "white", children: "[0] Detail" }),
|
|
2987
|
+
/* @__PURE__ */ jsxs3(Text3, { color: "cyan", bold: true, children: [
|
|
2988
|
+
"#",
|
|
2989
|
+
issue.number,
|
|
2990
|
+
" ",
|
|
2991
|
+
issue.title
|
|
2992
|
+
] }),
|
|
2993
|
+
/* @__PURE__ */ jsx3(Text3, { children: "" }),
|
|
2994
|
+
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
2995
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "State: " }),
|
|
2996
|
+
/* @__PURE__ */ jsx3(Text3, { color: issue.state === "open" ? "green" : "red", children: issue.state })
|
|
2939
2997
|
] }),
|
|
2940
|
-
|
|
2941
|
-
/* @__PURE__ */
|
|
2942
|
-
/* @__PURE__ */
|
|
2998
|
+
(issue.assignees ?? []).length > 0 ? /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
2999
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Assignees: " }),
|
|
3000
|
+
/* @__PURE__ */ jsx3(Text3, { children: (issue.assignees ?? []).map((a) => a.login).join(", ") })
|
|
2943
3001
|
] }) : null,
|
|
2944
|
-
|
|
2945
|
-
/* @__PURE__ */
|
|
2946
|
-
/* @__PURE__ */
|
|
3002
|
+
issue.labels.length > 0 ? /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
3003
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Labels: " }),
|
|
3004
|
+
/* @__PURE__ */ jsx3(Text3, { children: issue.labels.map((l) => l.name).join(", ") })
|
|
2947
3005
|
] }) : null,
|
|
2948
|
-
|
|
2949
|
-
/* @__PURE__ */
|
|
2950
|
-
/* @__PURE__ */
|
|
3006
|
+
issue.projectStatus ? /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
3007
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Status: " }),
|
|
3008
|
+
/* @__PURE__ */ jsx3(Text3, { color: "magenta", children: issue.projectStatus })
|
|
2951
3009
|
] }) : null,
|
|
2952
|
-
|
|
2953
|
-
/* @__PURE__ */
|
|
2954
|
-
/* @__PURE__ */
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
3010
|
+
issue.targetDate ? /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
3011
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Target: " }),
|
|
3012
|
+
/* @__PURE__ */ jsx3(Text3, { children: issue.targetDate })
|
|
3013
|
+
] }) : null,
|
|
3014
|
+
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
3015
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Updated: " }),
|
|
3016
|
+
/* @__PURE__ */ jsx3(Text3, { children: new Date(issue.updatedAt).toLocaleString() })
|
|
3017
|
+
] }),
|
|
3018
|
+
issue.slackThreadUrl ? /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
3019
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "Slack: " }),
|
|
3020
|
+
/* @__PURE__ */ jsx3(Text3, { color: "blue", children: countSlackLinks(issue.body) > 1 ? `${countSlackLinks(issue.body)} links (s opens first)` : "thread (s to open)" })
|
|
3021
|
+
] }) : null,
|
|
3022
|
+
issue.body ? /* @__PURE__ */ jsx3(BodySection, { body: issue.body, issueNumber: issue.number }) : /* @__PURE__ */ jsxs3(Fragment, { children: [
|
|
3023
|
+
/* @__PURE__ */ jsx3(Text3, { children: "" }),
|
|
3024
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "(no description)" })
|
|
3025
|
+
] }),
|
|
3026
|
+
/* @__PURE__ */ jsx3(Text3, { children: "" }),
|
|
3027
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "--- Comments ---" }),
|
|
3028
|
+
commentsState === "loading" ? /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "fetching comments..." }) : commentsState === "error" ? /* @__PURE__ */ jsx3(Text3, { color: "red", children: "could not load comments" }) : commentsState && commentsState.length === 0 ? /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "No comments yet." }) : commentsState && commentsState.length > 0 ? commentsState.slice(-5).map((comment, i) => (
|
|
3029
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: stable list
|
|
3030
|
+
/* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginBottom: 1, children: [
|
|
3031
|
+
/* @__PURE__ */ jsxs3(Text3, { color: "cyan", children: [
|
|
3032
|
+
"@",
|
|
3033
|
+
comment.author.login,
|
|
3034
|
+
" \xB7 ",
|
|
3035
|
+
formatCommentAge(comment.createdAt)
|
|
3036
|
+
] }),
|
|
3037
|
+
/* @__PURE__ */ jsxs3(Text3, { wrap: "wrap", children: [
|
|
3038
|
+
" ",
|
|
3039
|
+
comment.body.split("\n")[0]
|
|
3040
|
+
] })
|
|
3041
|
+
] }, i)
|
|
3042
|
+
)) : /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "fetching comments..." }),
|
|
3043
|
+
/* @__PURE__ */ jsx3(Text3, { children: "" }),
|
|
3044
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", dimColor: true, children: issue.url })
|
|
2966
3045
|
]
|
|
2967
3046
|
}
|
|
2968
3047
|
);
|
|
2969
3048
|
}
|
|
2970
|
-
var SLACK_URL_RE
|
|
3049
|
+
var SLACK_URL_RE;
|
|
2971
3050
|
var init_detail_panel = __esm({
|
|
2972
3051
|
"src/board/components/detail-panel.tsx"() {
|
|
2973
3052
|
"use strict";
|
|
2974
|
-
init_types();
|
|
2975
3053
|
SLACK_URL_RE = /https:\/\/[^/]+\.slack\.com\/archives\/[A-Z0-9]+\/p[0-9]+/gi;
|
|
2976
|
-
PRIORITY_LABELS2 = {
|
|
2977
|
-
[5 /* High */]: "High",
|
|
2978
|
-
[3 /* Medium */]: "Medium",
|
|
2979
|
-
[1 /* Low */]: "Low",
|
|
2980
|
-
[0 /* None */]: "None"
|
|
2981
|
-
};
|
|
2982
3054
|
}
|
|
2983
3055
|
});
|
|
2984
3056
|
|
|
2985
3057
|
// src/board/components/hint-bar.tsx
|
|
2986
|
-
import { Box as
|
|
2987
|
-
import { jsx as
|
|
2988
|
-
function HintBar({
|
|
3058
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
3059
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
3060
|
+
function HintBar({
|
|
3061
|
+
uiMode,
|
|
3062
|
+
activePanelId,
|
|
3063
|
+
multiSelectCount,
|
|
3064
|
+
searchQuery,
|
|
3065
|
+
mineOnly,
|
|
3066
|
+
hasUndoable
|
|
3067
|
+
}) {
|
|
2989
3068
|
if (uiMode === "multiSelect") {
|
|
2990
|
-
return /* @__PURE__ */
|
|
2991
|
-
/* @__PURE__ */
|
|
3069
|
+
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
3070
|
+
/* @__PURE__ */ jsxs4(Text4, { color: "cyan", bold: true, children: [
|
|
2992
3071
|
"[MULTI-SELECT] ",
|
|
2993
3072
|
multiSelectCount,
|
|
2994
3073
|
" selected"
|
|
2995
3074
|
] }),
|
|
2996
|
-
/* @__PURE__ */
|
|
3075
|
+
/* @__PURE__ */ jsx4(Text4, { color: "gray", children: " Space:toggle Enter:actions Esc:cancel" })
|
|
2997
3076
|
] });
|
|
2998
3077
|
}
|
|
2999
3078
|
if (uiMode === "focus") {
|
|
3000
|
-
return /* @__PURE__ */
|
|
3079
|
+
return /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsx4(Text4, { color: "magenta", bold: true, children: "[FOCUS] Focus mode \u2014 Esc to exit" }) });
|
|
3001
3080
|
}
|
|
3002
3081
|
if (uiMode === "search") {
|
|
3003
|
-
return /* @__PURE__ */
|
|
3004
|
-
/* @__PURE__ */
|
|
3005
|
-
/* @__PURE__ */
|
|
3006
|
-
searchQuery ? /* @__PURE__ */
|
|
3082
|
+
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
3083
|
+
/* @__PURE__ */ jsx4(Text4, { color: "yellow", bold: true, children: "[SEARCH]" }),
|
|
3084
|
+
/* @__PURE__ */ jsx4(Text4, { color: "gray", children: " type to filter Enter:confirm Esc:clear" }),
|
|
3085
|
+
searchQuery ? /* @__PURE__ */ jsxs4(Text4, { color: "yellow", children: [
|
|
3007
3086
|
' "',
|
|
3008
3087
|
searchQuery,
|
|
3009
3088
|
'"'
|
|
@@ -3011,19 +3090,22 @@ function HintBar({ uiMode, multiSelectCount, searchQuery, mineOnly, hasUndoable
|
|
|
3011
3090
|
] });
|
|
3012
3091
|
}
|
|
3013
3092
|
if (uiMode === "overlay:fuzzyPicker") {
|
|
3014
|
-
return /* @__PURE__ */
|
|
3093
|
+
return /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsx4(Text4, { color: "gray", children: "\u2191\u2193/Ctrl-J/K:nav Enter:jump Esc:close" }) });
|
|
3015
3094
|
}
|
|
3016
3095
|
if (uiMode.startsWith("overlay:")) {
|
|
3017
|
-
return /* @__PURE__ */
|
|
3018
|
-
}
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3096
|
+
return /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsx4(Text4, { color: "gray", children: "j/k:nav Enter:select Esc:cancel" }) });
|
|
3097
|
+
}
|
|
3098
|
+
const panelHints = {
|
|
3099
|
+
0: "j/k:scroll Esc:close ? help",
|
|
3100
|
+
1: "j/k:move Enter:filter 0-4:panel ? help",
|
|
3101
|
+
2: "j/k:move Enter:filter Esc:clear 0-4:panel ? help",
|
|
3102
|
+
3: `j/k:move p:pick m:status c:comment /:search n:new 0-4:panel${hasUndoable ? " u:undo" : ""} ? help q:quit`,
|
|
3103
|
+
4: "j/k:scroll Enter:jump r:refresh 0-4:panel ? help"
|
|
3104
|
+
};
|
|
3105
|
+
return /* @__PURE__ */ jsxs4(Box4, { children: [
|
|
3106
|
+
/* @__PURE__ */ jsx4(Text4, { color: "gray", children: panelHints[activePanelId] }),
|
|
3107
|
+
mineOnly ? /* @__PURE__ */ jsx4(Text4, { color: "cyan", children: " filter:@me" }) : null,
|
|
3108
|
+
searchQuery ? /* @__PURE__ */ jsxs4(Text4, { color: "yellow", children: [
|
|
3027
3109
|
' filter:"',
|
|
3028
3110
|
searchQuery,
|
|
3029
3111
|
'"'
|
|
@@ -3037,9 +3119,9 @@ var init_hint_bar = __esm({
|
|
|
3037
3119
|
});
|
|
3038
3120
|
|
|
3039
3121
|
// src/board/components/bulk-action-menu.tsx
|
|
3040
|
-
import { Box as
|
|
3041
|
-
import { useState as
|
|
3042
|
-
import { jsx as
|
|
3122
|
+
import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
|
|
3123
|
+
import { useState as useState7 } from "react";
|
|
3124
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
3043
3125
|
function getMenuItems(selectionType) {
|
|
3044
3126
|
if (selectionType === "github") {
|
|
3045
3127
|
return [
|
|
@@ -3058,7 +3140,7 @@ function getMenuItems(selectionType) {
|
|
|
3058
3140
|
}
|
|
3059
3141
|
function BulkActionMenu({ count, selectionType, onSelect, onCancel }) {
|
|
3060
3142
|
const items = getMenuItems(selectionType);
|
|
3061
|
-
const [selectedIdx, setSelectedIdx] =
|
|
3143
|
+
const [selectedIdx, setSelectedIdx] = useState7(0);
|
|
3062
3144
|
useInput2((input2, key) => {
|
|
3063
3145
|
if (key.escape) return onCancel();
|
|
3064
3146
|
if (key.return) {
|
|
@@ -3074,13 +3156,13 @@ function BulkActionMenu({ count, selectionType, onSelect, onCancel }) {
|
|
|
3074
3156
|
}
|
|
3075
3157
|
});
|
|
3076
3158
|
if (items.length === 0) {
|
|
3077
|
-
return /* @__PURE__ */
|
|
3078
|
-
/* @__PURE__ */
|
|
3079
|
-
/* @__PURE__ */
|
|
3159
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
3160
|
+
/* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "No bulk actions for mixed selection types." }),
|
|
3161
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Esc to cancel" })
|
|
3080
3162
|
] });
|
|
3081
3163
|
}
|
|
3082
|
-
return /* @__PURE__ */
|
|
3083
|
-
/* @__PURE__ */
|
|
3164
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
3165
|
+
/* @__PURE__ */ jsxs5(Text5, { color: "cyan", bold: true, children: [
|
|
3084
3166
|
"Bulk action (",
|
|
3085
3167
|
count,
|
|
3086
3168
|
" selected):"
|
|
@@ -3088,12 +3170,12 @@ function BulkActionMenu({ count, selectionType, onSelect, onCancel }) {
|
|
|
3088
3170
|
items.map((item, i) => {
|
|
3089
3171
|
const isSelected = i === selectedIdx;
|
|
3090
3172
|
const prefix = isSelected ? "> " : " ";
|
|
3091
|
-
return /* @__PURE__ */
|
|
3173
|
+
return /* @__PURE__ */ jsxs5(Text5, { ...isSelected ? { color: "cyan" } : {}, children: [
|
|
3092
3174
|
prefix,
|
|
3093
3175
|
item.label
|
|
3094
3176
|
] }, item.action.type);
|
|
3095
3177
|
}),
|
|
3096
|
-
/* @__PURE__ */
|
|
3178
|
+
/* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "j/k:navigate Enter:select Esc:cancel" })
|
|
3097
3179
|
] });
|
|
3098
3180
|
}
|
|
3099
3181
|
var init_bulk_action_menu = __esm({
|
|
@@ -3123,9 +3205,9 @@ import { mkdtempSync, readFileSync as readFileSync4, rmSync, writeFileSync as wr
|
|
|
3123
3205
|
import { tmpdir } from "os";
|
|
3124
3206
|
import { join as join4 } from "path";
|
|
3125
3207
|
import { TextInput } from "@inkjs/ui";
|
|
3126
|
-
import { Box as
|
|
3127
|
-
import { useEffect as useEffect4, useRef as useRef7, useState as
|
|
3128
|
-
import { jsx as
|
|
3208
|
+
import { Box as Box6, Text as Text6, useInput as useInput3, useStdin } from "ink";
|
|
3209
|
+
import { useEffect as useEffect4, useRef as useRef7, useState as useState8 } from "react";
|
|
3210
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
3129
3211
|
function CommentInput({
|
|
3130
3212
|
issueNumber,
|
|
3131
3213
|
onSubmit,
|
|
@@ -3133,8 +3215,8 @@ function CommentInput({
|
|
|
3133
3215
|
onPauseRefresh,
|
|
3134
3216
|
onResumeRefresh
|
|
3135
3217
|
}) {
|
|
3136
|
-
const [value, setValue] =
|
|
3137
|
-
const [editing, setEditing] =
|
|
3218
|
+
const [value, setValue] = useState8("");
|
|
3219
|
+
const [editing, setEditing] = useState8(false);
|
|
3138
3220
|
const { setRawMode } = useStdin();
|
|
3139
3221
|
const onSubmitRef = useRef7(onSubmit);
|
|
3140
3222
|
const onCancelRef = useRef7(onCancel);
|
|
@@ -3192,19 +3274,19 @@ function CommentInput({
|
|
|
3192
3274
|
}
|
|
3193
3275
|
}, [editing, value, setRawMode]);
|
|
3194
3276
|
if (editing) {
|
|
3195
|
-
return /* @__PURE__ */
|
|
3277
|
+
return /* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsxs6(Text6, { color: "cyan", children: [
|
|
3196
3278
|
"Opening editor for #",
|
|
3197
3279
|
issueNumber,
|
|
3198
3280
|
"\u2026"
|
|
3199
3281
|
] }) });
|
|
3200
3282
|
}
|
|
3201
|
-
return /* @__PURE__ */
|
|
3202
|
-
/* @__PURE__ */
|
|
3283
|
+
return /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
3284
|
+
/* @__PURE__ */ jsxs6(Text6, { color: "cyan", children: [
|
|
3203
3285
|
"comment #",
|
|
3204
3286
|
issueNumber,
|
|
3205
3287
|
": "
|
|
3206
3288
|
] }),
|
|
3207
|
-
/* @__PURE__ */
|
|
3289
|
+
/* @__PURE__ */ jsx6(
|
|
3208
3290
|
TextInput,
|
|
3209
3291
|
{
|
|
3210
3292
|
defaultValue: value,
|
|
@@ -3226,16 +3308,16 @@ var init_comment_input = __esm({
|
|
|
3226
3308
|
});
|
|
3227
3309
|
|
|
3228
3310
|
// src/board/components/confirm-prompt.tsx
|
|
3229
|
-
import { Box as
|
|
3230
|
-
import { jsx as
|
|
3311
|
+
import { Box as Box7, Text as Text7, useInput as useInput4 } from "ink";
|
|
3312
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
3231
3313
|
function ConfirmPrompt({ message, onConfirm, onCancel }) {
|
|
3232
3314
|
useInput4((input2, key) => {
|
|
3233
3315
|
if (input2 === "y" || input2 === "Y") return onConfirm();
|
|
3234
3316
|
if (input2 === "n" || input2 === "N" || key.escape) return onCancel();
|
|
3235
3317
|
});
|
|
3236
|
-
return /* @__PURE__ */
|
|
3237
|
-
/* @__PURE__ */
|
|
3238
|
-
/* @__PURE__ */
|
|
3318
|
+
return /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
3319
|
+
/* @__PURE__ */ jsx7(Text7, { color: "cyan", children: message }),
|
|
3320
|
+
/* @__PURE__ */ jsx7(Text7, { color: "gray", children: " (y/n)" })
|
|
3239
3321
|
] });
|
|
3240
3322
|
}
|
|
3241
3323
|
var init_confirm_prompt = __esm({
|
|
@@ -3246,9 +3328,9 @@ var init_confirm_prompt = __esm({
|
|
|
3246
3328
|
|
|
3247
3329
|
// src/board/components/label-picker.tsx
|
|
3248
3330
|
import { Spinner } from "@inkjs/ui";
|
|
3249
|
-
import { Box as
|
|
3250
|
-
import { useEffect as useEffect5, useRef as useRef8, useState as
|
|
3251
|
-
import { jsx as
|
|
3331
|
+
import { Box as Box8, Text as Text8, useInput as useInput5 } from "ink";
|
|
3332
|
+
import { useEffect as useEffect5, useRef as useRef8, useState as useState9 } from "react";
|
|
3333
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3252
3334
|
function LabelPicker({
|
|
3253
3335
|
repo,
|
|
3254
3336
|
currentLabels,
|
|
@@ -3257,11 +3339,11 @@ function LabelPicker({
|
|
|
3257
3339
|
onCancel,
|
|
3258
3340
|
onError
|
|
3259
3341
|
}) {
|
|
3260
|
-
const [labels, setLabels] =
|
|
3261
|
-
const [loading, setLoading] =
|
|
3262
|
-
const [fetchAttempted, setFetchAttempted] =
|
|
3263
|
-
const [selected, setSelected] =
|
|
3264
|
-
const [cursor, setCursor] =
|
|
3342
|
+
const [labels, setLabels] = useState9(labelCache[repo] ?? null);
|
|
3343
|
+
const [loading, setLoading] = useState9(labels === null);
|
|
3344
|
+
const [fetchAttempted, setFetchAttempted] = useState9(false);
|
|
3345
|
+
const [selected, setSelected] = useState9(new Set(currentLabels));
|
|
3346
|
+
const [cursor, setCursor] = useState9(0);
|
|
3265
3347
|
const submittedRef = useRef8(false);
|
|
3266
3348
|
useEffect5(() => {
|
|
3267
3349
|
if (labels !== null || fetchAttempted) return;
|
|
@@ -3323,21 +3405,21 @@ function LabelPicker({
|
|
|
3323
3405
|
}
|
|
3324
3406
|
});
|
|
3325
3407
|
if (loading) {
|
|
3326
|
-
return /* @__PURE__ */
|
|
3408
|
+
return /* @__PURE__ */ jsx8(Box8, { children: /* @__PURE__ */ jsx8(Spinner, { label: "Fetching labels..." }) });
|
|
3327
3409
|
}
|
|
3328
3410
|
const allLabels = labels ?? [];
|
|
3329
3411
|
if (allLabels.length === 0) {
|
|
3330
|
-
return /* @__PURE__ */
|
|
3331
|
-
/* @__PURE__ */
|
|
3332
|
-
/* @__PURE__ */
|
|
3333
|
-
/* @__PURE__ */
|
|
3412
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
3413
|
+
/* @__PURE__ */ jsx8(Text8, { color: "cyan", bold: true, children: "Labels:" }),
|
|
3414
|
+
/* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "No labels in this repo" }),
|
|
3415
|
+
/* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Esc:cancel" })
|
|
3334
3416
|
] });
|
|
3335
3417
|
}
|
|
3336
3418
|
const repoLabelNames = new Set(allLabels.map((l) => l.name));
|
|
3337
3419
|
const orphanedLabels = currentLabels.filter((l) => !repoLabelNames.has(l));
|
|
3338
|
-
return /* @__PURE__ */
|
|
3339
|
-
/* @__PURE__ */
|
|
3340
|
-
orphanedLabels.map((name) => /* @__PURE__ */
|
|
3420
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
3421
|
+
/* @__PURE__ */ jsx8(Text8, { color: "cyan", bold: true, children: "Labels (Space:toggle Enter:confirm Esc:cancel):" }),
|
|
3422
|
+
orphanedLabels.map((name) => /* @__PURE__ */ jsxs8(Text8, { dimColor: true, children: [
|
|
3341
3423
|
selected.has(name) ? "[x]" : "[ ]",
|
|
3342
3424
|
" ",
|
|
3343
3425
|
name,
|
|
@@ -3346,7 +3428,7 @@ function LabelPicker({
|
|
|
3346
3428
|
allLabels.map((label, i) => {
|
|
3347
3429
|
const isSel = i === cursor;
|
|
3348
3430
|
const isChecked = selected.has(label.name);
|
|
3349
|
-
return /* @__PURE__ */
|
|
3431
|
+
return /* @__PURE__ */ jsxs8(Text8, { ...isSel ? { color: "cyan" } : {}, children: [
|
|
3350
3432
|
isSel ? ">" : " ",
|
|
3351
3433
|
" ",
|
|
3352
3434
|
isChecked ? "[x]" : "[ ]",
|
|
@@ -3365,9 +3447,9 @@ var init_label_picker = __esm({
|
|
|
3365
3447
|
|
|
3366
3448
|
// src/board/components/create-issue-form.tsx
|
|
3367
3449
|
import { TextInput as TextInput2 } from "@inkjs/ui";
|
|
3368
|
-
import { Box as
|
|
3369
|
-
import { useState as
|
|
3370
|
-
import { jsx as
|
|
3450
|
+
import { Box as Box9, Text as Text9, useInput as useInput6 } from "ink";
|
|
3451
|
+
import { useState as useState10 } from "react";
|
|
3452
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
3371
3453
|
function CreateIssueForm({
|
|
3372
3454
|
repos,
|
|
3373
3455
|
defaultRepo,
|
|
@@ -3379,9 +3461,9 @@ function CreateIssueForm({
|
|
|
3379
3461
|
0,
|
|
3380
3462
|
repos.findIndex((r) => r.name === defaultRepo)
|
|
3381
3463
|
) : 0;
|
|
3382
|
-
const [repoIdx, setRepoIdx] =
|
|
3383
|
-
const [title, setTitle] =
|
|
3384
|
-
const [field, setField] =
|
|
3464
|
+
const [repoIdx, setRepoIdx] = useState10(defaultRepoIdx);
|
|
3465
|
+
const [title, setTitle] = useState10("");
|
|
3466
|
+
const [field, setField] = useState10("title");
|
|
3385
3467
|
useInput6((input2, key) => {
|
|
3386
3468
|
if (field === "labels") return;
|
|
3387
3469
|
if (key.escape) return onCancel();
|
|
@@ -3398,15 +3480,15 @@ function CreateIssueForm({
|
|
|
3398
3480
|
});
|
|
3399
3481
|
const selectedRepo = repos[repoIdx];
|
|
3400
3482
|
if (field === "labels" && selectedRepo) {
|
|
3401
|
-
return /* @__PURE__ */
|
|
3402
|
-
/* @__PURE__ */
|
|
3403
|
-
/* @__PURE__ */
|
|
3483
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
3484
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", bold: true, children: "Create Issue \u2014 Add Labels (optional)" }),
|
|
3485
|
+
/* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
3404
3486
|
"Repo: ",
|
|
3405
3487
|
selectedRepo.shortName,
|
|
3406
3488
|
" Title: ",
|
|
3407
3489
|
title
|
|
3408
3490
|
] }),
|
|
3409
|
-
/* @__PURE__ */
|
|
3491
|
+
/* @__PURE__ */ jsx9(
|
|
3410
3492
|
LabelPicker,
|
|
3411
3493
|
{
|
|
3412
3494
|
repo: selectedRepo.name,
|
|
@@ -3431,12 +3513,12 @@ function CreateIssueForm({
|
|
|
3431
3513
|
)
|
|
3432
3514
|
] });
|
|
3433
3515
|
}
|
|
3434
|
-
return /* @__PURE__ */
|
|
3435
|
-
/* @__PURE__ */
|
|
3436
|
-
/* @__PURE__ */
|
|
3437
|
-
/* @__PURE__ */
|
|
3438
|
-
repos.map((r, i) => /* @__PURE__ */
|
|
3439
|
-
|
|
3516
|
+
return /* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
3517
|
+
/* @__PURE__ */ jsx9(Text9, { color: "cyan", bold: true, children: "Create Issue" }),
|
|
3518
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
3519
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: field !== "repo", children: "Repo: " }),
|
|
3520
|
+
repos.map((r, i) => /* @__PURE__ */ jsx9(
|
|
3521
|
+
Text9,
|
|
3440
3522
|
{
|
|
3441
3523
|
...i === repoIdx ? { color: "cyan", bold: true } : {},
|
|
3442
3524
|
dimColor: field !== "repo",
|
|
@@ -3444,11 +3526,11 @@ function CreateIssueForm({
|
|
|
3444
3526
|
},
|
|
3445
3527
|
r.name
|
|
3446
3528
|
)),
|
|
3447
|
-
field === "repo" ? /* @__PURE__ */
|
|
3529
|
+
field === "repo" ? /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: " j/k:select Tab:next" }) : null
|
|
3448
3530
|
] }),
|
|
3449
|
-
/* @__PURE__ */
|
|
3450
|
-
/* @__PURE__ */
|
|
3451
|
-
field === "title" ? /* @__PURE__ */
|
|
3531
|
+
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
3532
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: field !== "title", children: "Title: " }),
|
|
3533
|
+
field === "title" ? /* @__PURE__ */ jsx9(
|
|
3452
3534
|
TextInput2,
|
|
3453
3535
|
{
|
|
3454
3536
|
defaultValue: title,
|
|
@@ -3465,9 +3547,9 @@ function CreateIssueForm({
|
|
|
3465
3547
|
}
|
|
3466
3548
|
}
|
|
3467
3549
|
}
|
|
3468
|
-
) : /* @__PURE__ */
|
|
3550
|
+
) : /* @__PURE__ */ jsx9(Text9, { children: title || "(empty)" })
|
|
3469
3551
|
] }),
|
|
3470
|
-
/* @__PURE__ */
|
|
3552
|
+
/* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "Tab:switch fields Enter:next Esc:cancel" })
|
|
3471
3553
|
] });
|
|
3472
3554
|
}
|
|
3473
3555
|
var init_create_issue_form = __esm({
|
|
@@ -3482,9 +3564,9 @@ import { spawnSync as spawnSync2 } from "child_process";
|
|
|
3482
3564
|
import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
3483
3565
|
import { tmpdir as tmpdir2 } from "os";
|
|
3484
3566
|
import { join as join5 } from "path";
|
|
3485
|
-
import { Box as
|
|
3486
|
-
import { useEffect as useEffect6, useRef as useRef9, useState as
|
|
3487
|
-
import { jsx as
|
|
3567
|
+
import { Box as Box10, Text as Text10, useStdin as useStdin2 } from "ink";
|
|
3568
|
+
import { useEffect as useEffect6, useRef as useRef9, useState as useState11 } from "react";
|
|
3569
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
3488
3570
|
function buildEditorFile(issue, repoName, statusOptions, repoLabels) {
|
|
3489
3571
|
const statusNames = statusOptions.map((o) => o.name).join(", ");
|
|
3490
3572
|
const labelNames = repoLabels.map((l) => l.name).join(", ");
|
|
@@ -3567,7 +3649,7 @@ function EditIssueOverlay({
|
|
|
3567
3649
|
onToastError,
|
|
3568
3650
|
onPushEntry
|
|
3569
3651
|
}) {
|
|
3570
|
-
const [editing, setEditing] =
|
|
3652
|
+
const [editing, setEditing] = useState11(true);
|
|
3571
3653
|
const { setRawMode } = useStdin2();
|
|
3572
3654
|
const onDoneRef = useRef9(onDone);
|
|
3573
3655
|
const onPauseRef = useRef9(onPauseRefresh);
|
|
@@ -3726,7 +3808,7 @@ function EditIssueOverlay({
|
|
|
3726
3808
|
onPushEntry
|
|
3727
3809
|
]);
|
|
3728
3810
|
if (!editing) return null;
|
|
3729
|
-
return /* @__PURE__ */
|
|
3811
|
+
return /* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsxs10(Text10, { color: "cyan", children: [
|
|
3730
3812
|
"Opening editor for #",
|
|
3731
3813
|
issue.number,
|
|
3732
3814
|
"\u2026"
|
|
@@ -3742,17 +3824,17 @@ var init_edit_issue_overlay = __esm({
|
|
|
3742
3824
|
});
|
|
3743
3825
|
|
|
3744
3826
|
// src/board/components/focus-mode.tsx
|
|
3745
|
-
import { Box as
|
|
3746
|
-
import { useCallback as
|
|
3747
|
-
import { jsx as
|
|
3827
|
+
import { Box as Box11, Text as Text11, useInput as useInput7 } from "ink";
|
|
3828
|
+
import { useCallback as useCallback10, useEffect as useEffect7, useRef as useRef10, useState as useState12 } from "react";
|
|
3829
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3748
3830
|
function formatTime(secs) {
|
|
3749
3831
|
const m = Math.floor(secs / 60);
|
|
3750
3832
|
const s = secs % 60;
|
|
3751
3833
|
return `${String(m).padStart(2, "0")}:${String(s).padStart(2, "0")}`;
|
|
3752
3834
|
}
|
|
3753
3835
|
function FocusMode({ label, durationSec, onExit, onEndAction }) {
|
|
3754
|
-
const [remaining, setRemaining] =
|
|
3755
|
-
const [timerDone, setTimerDone] =
|
|
3836
|
+
const [remaining, setRemaining] = useState12(durationSec);
|
|
3837
|
+
const [timerDone, setTimerDone] = useState12(false);
|
|
3756
3838
|
const bellSentRef = useRef10(false);
|
|
3757
3839
|
useEffect7(() => {
|
|
3758
3840
|
if (timerDone) return;
|
|
@@ -3774,7 +3856,7 @@ function FocusMode({ label, durationSec, onExit, onEndAction }) {
|
|
|
3774
3856
|
process.stdout.write("\x07");
|
|
3775
3857
|
}
|
|
3776
3858
|
}, [timerDone]);
|
|
3777
|
-
const handleInput =
|
|
3859
|
+
const handleInput = useCallback10(
|
|
3778
3860
|
(input2, key) => {
|
|
3779
3861
|
if (key.escape) {
|
|
3780
3862
|
if (timerDone) {
|
|
@@ -3801,23 +3883,23 @@ function FocusMode({ label, durationSec, onExit, onEndAction }) {
|
|
|
3801
3883
|
);
|
|
3802
3884
|
useInput7(handleInput);
|
|
3803
3885
|
if (timerDone) {
|
|
3804
|
-
return /* @__PURE__ */
|
|
3805
|
-
/* @__PURE__ */
|
|
3806
|
-
/* @__PURE__ */
|
|
3807
|
-
/* @__PURE__ */
|
|
3886
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
3887
|
+
/* @__PURE__ */ jsxs11(Box11, { children: [
|
|
3888
|
+
/* @__PURE__ */ jsx11(Text11, { color: "green", bold: true, children: "Focus complete!" }),
|
|
3889
|
+
/* @__PURE__ */ jsxs11(Text11, { color: "gray", children: [
|
|
3808
3890
|
" ",
|
|
3809
3891
|
label
|
|
3810
3892
|
] })
|
|
3811
3893
|
] }),
|
|
3812
|
-
/* @__PURE__ */
|
|
3813
|
-
/* @__PURE__ */
|
|
3814
|
-
/* @__PURE__ */
|
|
3815
|
-
/* @__PURE__ */
|
|
3816
|
-
/* @__PURE__ */
|
|
3817
|
-
/* @__PURE__ */
|
|
3818
|
-
/* @__PURE__ */
|
|
3819
|
-
/* @__PURE__ */
|
|
3820
|
-
/* @__PURE__ */
|
|
3894
|
+
/* @__PURE__ */ jsxs11(Box11, { marginTop: 1, children: [
|
|
3895
|
+
/* @__PURE__ */ jsx11(Text11, { color: "cyan", children: "[c]" }),
|
|
3896
|
+
/* @__PURE__ */ jsx11(Text11, { children: " Continue " }),
|
|
3897
|
+
/* @__PURE__ */ jsx11(Text11, { color: "cyan", children: "[b]" }),
|
|
3898
|
+
/* @__PURE__ */ jsx11(Text11, { children: " Break " }),
|
|
3899
|
+
/* @__PURE__ */ jsx11(Text11, { color: "cyan", children: "[d]" }),
|
|
3900
|
+
/* @__PURE__ */ jsx11(Text11, { children: " Done " }),
|
|
3901
|
+
/* @__PURE__ */ jsx11(Text11, { color: "gray", children: "[Esc]" }),
|
|
3902
|
+
/* @__PURE__ */ jsx11(Text11, { children: " Exit" })
|
|
3821
3903
|
] })
|
|
3822
3904
|
] });
|
|
3823
3905
|
}
|
|
@@ -3825,21 +3907,21 @@ function FocusMode({ label, durationSec, onExit, onEndAction }) {
|
|
|
3825
3907
|
const barWidth = 20;
|
|
3826
3908
|
const filled = Math.round(progress * barWidth);
|
|
3827
3909
|
const bar = "\u2588".repeat(filled) + "\u2591".repeat(barWidth - filled);
|
|
3828
|
-
return /* @__PURE__ */
|
|
3829
|
-
/* @__PURE__ */
|
|
3830
|
-
/* @__PURE__ */
|
|
3910
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", children: [
|
|
3911
|
+
/* @__PURE__ */ jsxs11(Box11, { children: [
|
|
3912
|
+
/* @__PURE__ */ jsxs11(Text11, { color: "magenta", bold: true, children: [
|
|
3831
3913
|
"Focus:",
|
|
3832
3914
|
" "
|
|
3833
3915
|
] }),
|
|
3834
|
-
/* @__PURE__ */
|
|
3916
|
+
/* @__PURE__ */ jsx11(Text11, { children: label })
|
|
3835
3917
|
] }),
|
|
3836
|
-
/* @__PURE__ */
|
|
3837
|
-
/* @__PURE__ */
|
|
3838
|
-
/* @__PURE__ */
|
|
3839
|
-
/* @__PURE__ */
|
|
3840
|
-
/* @__PURE__ */
|
|
3918
|
+
/* @__PURE__ */ jsxs11(Box11, { children: [
|
|
3919
|
+
/* @__PURE__ */ jsx11(Text11, { color: "magenta", children: bar }),
|
|
3920
|
+
/* @__PURE__ */ jsx11(Text11, { children: " " }),
|
|
3921
|
+
/* @__PURE__ */ jsx11(Text11, { bold: true, children: formatTime(remaining) }),
|
|
3922
|
+
/* @__PURE__ */ jsx11(Text11, { color: "gray", children: " remaining" })
|
|
3841
3923
|
] }),
|
|
3842
|
-
/* @__PURE__ */
|
|
3924
|
+
/* @__PURE__ */ jsx11(Text11, { color: "gray", dimColor: true, children: "Esc to exit focus" })
|
|
3843
3925
|
] });
|
|
3844
3926
|
}
|
|
3845
3927
|
var init_focus_mode = __esm({
|
|
@@ -3851,18 +3933,18 @@ var init_focus_mode = __esm({
|
|
|
3851
3933
|
// src/board/components/fuzzy-picker.tsx
|
|
3852
3934
|
import { TextInput as TextInput3 } from "@inkjs/ui";
|
|
3853
3935
|
import { Fzf } from "fzf";
|
|
3854
|
-
import { Box as
|
|
3855
|
-
import { useMemo as useMemo2, useState as
|
|
3856
|
-
import { jsx as
|
|
3936
|
+
import { Box as Box12, Text as Text12, useInput as useInput8 } from "ink";
|
|
3937
|
+
import { useMemo as useMemo2, useState as useState13 } from "react";
|
|
3938
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3857
3939
|
function keepCursorVisible(cursor, offset, visible) {
|
|
3858
3940
|
if (cursor < offset) return cursor;
|
|
3859
3941
|
if (cursor >= offset + visible) return cursor - visible + 1;
|
|
3860
3942
|
return offset;
|
|
3861
3943
|
}
|
|
3862
3944
|
function FuzzyPicker({ repos, onSelect, onClose }) {
|
|
3863
|
-
const [query, setQuery] =
|
|
3864
|
-
const [cursor, setCursor] =
|
|
3865
|
-
const [scrollOffset, setScrollOffset] =
|
|
3945
|
+
const [query, setQuery] = useState13("");
|
|
3946
|
+
const [cursor, setCursor] = useState13(0);
|
|
3947
|
+
const [scrollOffset, setScrollOffset] = useState13(0);
|
|
3866
3948
|
const allIssues = useMemo2(() => {
|
|
3867
3949
|
const items = [];
|
|
3868
3950
|
for (const rd of repos) {
|
|
@@ -3945,13 +4027,13 @@ function FuzzyPicker({ repos, onSelect, onClose }) {
|
|
|
3945
4027
|
});
|
|
3946
4028
|
const visibleResults = results.slice(scrollOffset, scrollOffset + VISIBLE);
|
|
3947
4029
|
const totalCount = results.length;
|
|
3948
|
-
return /* @__PURE__ */
|
|
3949
|
-
/* @__PURE__ */
|
|
3950
|
-
/* @__PURE__ */
|
|
4030
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
4031
|
+
/* @__PURE__ */ jsxs12(Box12, { children: [
|
|
4032
|
+
/* @__PURE__ */ jsxs12(Text12, { color: "cyan", bold: true, children: [
|
|
3951
4033
|
"Find issue",
|
|
3952
4034
|
" "
|
|
3953
4035
|
] }),
|
|
3954
|
-
/* @__PURE__ */
|
|
4036
|
+
/* @__PURE__ */ jsxs12(Text12, { color: "gray", children: [
|
|
3955
4037
|
"(",
|
|
3956
4038
|
totalCount,
|
|
3957
4039
|
" match",
|
|
@@ -3959,14 +4041,14 @@ function FuzzyPicker({ repos, onSelect, onClose }) {
|
|
|
3959
4041
|
")",
|
|
3960
4042
|
" "
|
|
3961
4043
|
] }),
|
|
3962
|
-
/* @__PURE__ */
|
|
4044
|
+
/* @__PURE__ */ jsx12(Text12, { color: "gray", dimColor: true, children: "\u2191\u2193/Ctrl-J/K nav Enter:jump Esc:close" })
|
|
3963
4045
|
] }),
|
|
3964
|
-
/* @__PURE__ */
|
|
3965
|
-
/* @__PURE__ */
|
|
4046
|
+
/* @__PURE__ */ jsxs12(Box12, { children: [
|
|
4047
|
+
/* @__PURE__ */ jsxs12(Text12, { color: "yellow", children: [
|
|
3966
4048
|
">",
|
|
3967
4049
|
" "
|
|
3968
4050
|
] }),
|
|
3969
|
-
/* @__PURE__ */
|
|
4051
|
+
/* @__PURE__ */ jsx12(
|
|
3970
4052
|
TextInput3,
|
|
3971
4053
|
{
|
|
3972
4054
|
defaultValue: query,
|
|
@@ -3983,7 +4065,7 @@ function FuzzyPicker({ repos, onSelect, onClose }) {
|
|
|
3983
4065
|
}
|
|
3984
4066
|
)
|
|
3985
4067
|
] }),
|
|
3986
|
-
scrollOffset > 0 ? /* @__PURE__ */
|
|
4068
|
+
scrollOffset > 0 ? /* @__PURE__ */ jsxs12(Text12, { color: "gray", dimColor: true, children: [
|
|
3987
4069
|
"\u25B2 ",
|
|
3988
4070
|
scrollOffset,
|
|
3989
4071
|
" more above"
|
|
@@ -3992,7 +4074,7 @@ function FuzzyPicker({ repos, onSelect, onClose }) {
|
|
|
3992
4074
|
const isSelected = scrollOffset + idx === cursor;
|
|
3993
4075
|
const labelStr = issue.labels ? ` [${issue.labels.split(" ").slice(0, 2).join("] [")}]` : "";
|
|
3994
4076
|
const assigneeStr = issue.assignee ? ` @${issue.assignee.split(" ")[0]}` : "";
|
|
3995
|
-
return /* @__PURE__ */
|
|
4077
|
+
return /* @__PURE__ */ jsx12(Box12, { children: isSelected ? /* @__PURE__ */ jsxs12(Text12, { color: "cyan", bold: true, children: [
|
|
3996
4078
|
">",
|
|
3997
4079
|
" ",
|
|
3998
4080
|
issue.repoShortName,
|
|
@@ -4002,7 +4084,7 @@ function FuzzyPicker({ repos, onSelect, onClose }) {
|
|
|
4002
4084
|
issue.title,
|
|
4003
4085
|
labelStr,
|
|
4004
4086
|
assigneeStr
|
|
4005
|
-
] }) : /* @__PURE__ */
|
|
4087
|
+
] }) : /* @__PURE__ */ jsxs12(Text12, { children: [
|
|
4006
4088
|
" ",
|
|
4007
4089
|
issue.repoShortName,
|
|
4008
4090
|
"#",
|
|
@@ -4013,12 +4095,12 @@ function FuzzyPicker({ repos, onSelect, onClose }) {
|
|
|
4013
4095
|
assigneeStr
|
|
4014
4096
|
] }) }, issue.navId);
|
|
4015
4097
|
}),
|
|
4016
|
-
totalCount === 0 ? /* @__PURE__ */
|
|
4098
|
+
totalCount === 0 ? /* @__PURE__ */ jsxs12(Text12, { dimColor: true, children: [
|
|
4017
4099
|
'No issues match "',
|
|
4018
4100
|
query,
|
|
4019
4101
|
'"'
|
|
4020
4102
|
] }) : null,
|
|
4021
|
-
results.length > scrollOffset + VISIBLE ? /* @__PURE__ */
|
|
4103
|
+
results.length > scrollOffset + VISIBLE ? /* @__PURE__ */ jsxs12(Text12, { color: "gray", dimColor: true, children: [
|
|
4022
4104
|
"\u25BC ",
|
|
4023
4105
|
results.length - scrollOffset - VISIBLE,
|
|
4024
4106
|
" more below"
|
|
@@ -4032,29 +4114,29 @@ var init_fuzzy_picker = __esm({
|
|
|
4032
4114
|
});
|
|
4033
4115
|
|
|
4034
4116
|
// src/board/components/help-overlay.tsx
|
|
4035
|
-
import { Box as
|
|
4036
|
-
import { jsx as
|
|
4117
|
+
import { Box as Box13, Text as Text13, useInput as useInput9 } from "ink";
|
|
4118
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
4037
4119
|
function HelpOverlay({ currentMode, onClose }) {
|
|
4038
4120
|
useInput9((_input, key) => {
|
|
4039
4121
|
if (key.escape) onClose();
|
|
4040
4122
|
});
|
|
4041
|
-
return /* @__PURE__ */
|
|
4042
|
-
/* @__PURE__ */
|
|
4043
|
-
/* @__PURE__ */
|
|
4044
|
-
/* @__PURE__ */
|
|
4123
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
4124
|
+
/* @__PURE__ */ jsxs13(Box13, { justifyContent: "space-between", children: [
|
|
4125
|
+
/* @__PURE__ */ jsx13(Text13, { color: "cyan", bold: true, children: "Keyboard Shortcuts" }),
|
|
4126
|
+
/* @__PURE__ */ jsxs13(Text13, { dimColor: true, children: [
|
|
4045
4127
|
"mode: ",
|
|
4046
4128
|
currentMode
|
|
4047
4129
|
] })
|
|
4048
4130
|
] }),
|
|
4049
|
-
/* @__PURE__ */
|
|
4050
|
-
SHORTCUTS.map((group) => /* @__PURE__ */
|
|
4051
|
-
/* @__PURE__ */
|
|
4052
|
-
group.items.map((item) => /* @__PURE__ */
|
|
4053
|
-
/* @__PURE__ */
|
|
4054
|
-
/* @__PURE__ */
|
|
4131
|
+
/* @__PURE__ */ jsx13(Text13, { children: " " }),
|
|
4132
|
+
SHORTCUTS.map((group) => /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginBottom: 1, children: [
|
|
4133
|
+
/* @__PURE__ */ jsx13(Text13, { color: "yellow", bold: true, children: group.category }),
|
|
4134
|
+
group.items.map((item) => /* @__PURE__ */ jsxs13(Box13, { children: [
|
|
4135
|
+
/* @__PURE__ */ jsx13(Box13, { width: 16, children: /* @__PURE__ */ jsx13(Text13, { color: "green", children: item.key }) }),
|
|
4136
|
+
/* @__PURE__ */ jsx13(Text13, { children: item.desc })
|
|
4055
4137
|
] }, item.key))
|
|
4056
4138
|
] }, group.category)),
|
|
4057
|
-
/* @__PURE__ */
|
|
4139
|
+
/* @__PURE__ */ jsx13(Text13, { dimColor: true, children: "Press ? or Esc to close" })
|
|
4058
4140
|
] });
|
|
4059
4141
|
}
|
|
4060
4142
|
var SHORTCUTS;
|
|
@@ -4067,9 +4149,10 @@ var init_help_overlay = __esm({
|
|
|
4067
4149
|
items: [
|
|
4068
4150
|
{ key: "j / Down", desc: "Move down" },
|
|
4069
4151
|
{ key: "k / Up", desc: "Move up" },
|
|
4070
|
-
{ key: "Tab", desc: "Next tab" },
|
|
4071
|
-
{ key: "Shift+Tab", desc: "Previous tab" },
|
|
4072
|
-
{ key: "1-9", desc: "Jump to tab by number" }
|
|
4152
|
+
{ key: "Tab", desc: "Next repo tab" },
|
|
4153
|
+
{ key: "Shift+Tab", desc: "Previous repo tab" },
|
|
4154
|
+
{ key: "1-9", desc: "Jump to repo tab by number" },
|
|
4155
|
+
{ key: "s / S", desc: "Next / prev status tab" }
|
|
4073
4156
|
]
|
|
4074
4157
|
},
|
|
4075
4158
|
{
|
|
@@ -4094,7 +4177,7 @@ var init_help_overlay = __esm({
|
|
|
4094
4177
|
{ key: "c", desc: "Comment on issue" },
|
|
4095
4178
|
{ key: "m", desc: "Move status" },
|
|
4096
4179
|
{ key: "e", desc: "Edit issue in $EDITOR" },
|
|
4097
|
-
{ key: "
|
|
4180
|
+
{ key: "o", desc: "Open Slack thread" },
|
|
4098
4181
|
{ key: "y", desc: "Copy issue link to clipboard" },
|
|
4099
4182
|
{ key: "n", desc: "Create new issue" },
|
|
4100
4183
|
{ key: "I", desc: "Natural-language issue create" },
|
|
@@ -4119,9 +4202,9 @@ import { mkdtempSync as mkdtempSync3, readFileSync as readFileSync6, rmSync as r
|
|
|
4119
4202
|
import { tmpdir as tmpdir3 } from "os";
|
|
4120
4203
|
import { join as join6 } from "path";
|
|
4121
4204
|
import { Spinner as Spinner2, TextInput as TextInput4 } from "@inkjs/ui";
|
|
4122
|
-
import { Box as
|
|
4123
|
-
import { useCallback as
|
|
4124
|
-
import { jsx as
|
|
4205
|
+
import { Box as Box14, Text as Text14, useInput as useInput10, useStdin as useStdin3 } from "ink";
|
|
4206
|
+
import { useCallback as useCallback11, useEffect as useEffect8, useRef as useRef11, useState as useState14 } from "react";
|
|
4207
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
4125
4208
|
function NlCreateOverlay({
|
|
4126
4209
|
repos,
|
|
4127
4210
|
defaultRepoName,
|
|
@@ -4132,13 +4215,13 @@ function NlCreateOverlay({
|
|
|
4132
4215
|
onResumeRefresh,
|
|
4133
4216
|
onLlmFallback
|
|
4134
4217
|
}) {
|
|
4135
|
-
const [, setInput] =
|
|
4136
|
-
const [isParsing, setIsParsing] =
|
|
4137
|
-
const [parsed, setParsed] =
|
|
4138
|
-
const [parseError, setParseError] =
|
|
4139
|
-
const [step, setStep] =
|
|
4140
|
-
const [body, setBody] =
|
|
4141
|
-
const [editingBody, setEditingBody] =
|
|
4218
|
+
const [, setInput] = useState14("");
|
|
4219
|
+
const [isParsing, setIsParsing] = useState14(false);
|
|
4220
|
+
const [parsed, setParsed] = useState14(null);
|
|
4221
|
+
const [parseError, setParseError] = useState14(null);
|
|
4222
|
+
const [step, setStep] = useState14("input");
|
|
4223
|
+
const [body, setBody] = useState14("");
|
|
4224
|
+
const [editingBody, setEditingBody] = useState14(false);
|
|
4142
4225
|
const submittedRef = useRef11(false);
|
|
4143
4226
|
const parseParamsRef = useRef11(null);
|
|
4144
4227
|
const onSubmitRef = useRef11(onSubmit);
|
|
@@ -4154,7 +4237,7 @@ function NlCreateOverlay({
|
|
|
4154
4237
|
0,
|
|
4155
4238
|
repos.findIndex((r) => r.name === defaultRepoName)
|
|
4156
4239
|
) : 0;
|
|
4157
|
-
const [repoIdx, setRepoIdx] =
|
|
4240
|
+
const [repoIdx, setRepoIdx] = useState14(defaultRepoIdx);
|
|
4158
4241
|
const selectedRepo = repos[repoIdx];
|
|
4159
4242
|
useInput10((inputChar, key) => {
|
|
4160
4243
|
if (isParsing || editingBody) return;
|
|
@@ -4214,7 +4297,7 @@ function NlCreateOverlay({
|
|
|
4214
4297
|
setEditingBody(false);
|
|
4215
4298
|
}
|
|
4216
4299
|
}, [editingBody, body, setRawMode]);
|
|
4217
|
-
const handleInputSubmit =
|
|
4300
|
+
const handleInputSubmit = useCallback11(
|
|
4218
4301
|
(text) => {
|
|
4219
4302
|
const trimmed = text.trim();
|
|
4220
4303
|
if (!trimmed) return;
|
|
@@ -4247,27 +4330,27 @@ function NlCreateOverlay({
|
|
|
4247
4330
|
});
|
|
4248
4331
|
}, [isParsing, onLlmFallback]);
|
|
4249
4332
|
if (isParsing) {
|
|
4250
|
-
return /* @__PURE__ */
|
|
4251
|
-
/* @__PURE__ */
|
|
4252
|
-
/* @__PURE__ */
|
|
4333
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
4334
|
+
/* @__PURE__ */ jsx14(Text14, { color: "cyan", bold: true, children: "\u2728 Creating Issue" }),
|
|
4335
|
+
/* @__PURE__ */ jsx14(Spinner2, { label: "Parsing..." })
|
|
4253
4336
|
] });
|
|
4254
4337
|
}
|
|
4255
4338
|
if (parsed && step === "body") {
|
|
4256
4339
|
if (editingBody) {
|
|
4257
|
-
return /* @__PURE__ */
|
|
4258
|
-
/* @__PURE__ */
|
|
4259
|
-
/* @__PURE__ */
|
|
4340
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
4341
|
+
/* @__PURE__ */ jsx14(Text14, { color: "cyan", bold: true, children: "\u2728 Creating Issue" }),
|
|
4342
|
+
/* @__PURE__ */ jsx14(Text14, { color: "cyan", children: "Opening editor for body\u2026" })
|
|
4260
4343
|
] });
|
|
4261
4344
|
}
|
|
4262
|
-
return /* @__PURE__ */
|
|
4263
|
-
/* @__PURE__ */
|
|
4264
|
-
/* @__PURE__ */
|
|
4265
|
-
/* @__PURE__ */
|
|
4266
|
-
/* @__PURE__ */
|
|
4345
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
4346
|
+
/* @__PURE__ */ jsx14(Text14, { color: "cyan", bold: true, children: "\u2728 Creating Issue" }),
|
|
4347
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
4348
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Title: " }),
|
|
4349
|
+
/* @__PURE__ */ jsx14(Text14, { children: parsed.title })
|
|
4267
4350
|
] }),
|
|
4268
|
-
/* @__PURE__ */
|
|
4269
|
-
/* @__PURE__ */
|
|
4270
|
-
/* @__PURE__ */
|
|
4351
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
4352
|
+
/* @__PURE__ */ jsx14(Text14, { color: "cyan", children: "body: " }),
|
|
4353
|
+
/* @__PURE__ */ jsx14(
|
|
4271
4354
|
TextInput4,
|
|
4272
4355
|
{
|
|
4273
4356
|
defaultValue: body,
|
|
@@ -4289,45 +4372,45 @@ function NlCreateOverlay({
|
|
|
4289
4372
|
}
|
|
4290
4373
|
)
|
|
4291
4374
|
] }),
|
|
4292
|
-
/* @__PURE__ */
|
|
4375
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Enter:create ctrl+e:editor Esc:back" })
|
|
4293
4376
|
] });
|
|
4294
4377
|
}
|
|
4295
4378
|
if (parsed) {
|
|
4296
4379
|
const labels = [...parsed.labels];
|
|
4297
|
-
return /* @__PURE__ */
|
|
4298
|
-
/* @__PURE__ */
|
|
4299
|
-
/* @__PURE__ */
|
|
4300
|
-
/* @__PURE__ */
|
|
4301
|
-
/* @__PURE__ */
|
|
4302
|
-
repos.length > 1 ? /* @__PURE__ */
|
|
4380
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
4381
|
+
/* @__PURE__ */ jsx14(Text14, { color: "cyan", bold: true, children: "\u2728 Creating Issue" }),
|
|
4382
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
4383
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Repo: " }),
|
|
4384
|
+
/* @__PURE__ */ jsx14(Text14, { color: "cyan", children: selectedRepo?.shortName ?? "(none)" }),
|
|
4385
|
+
repos.length > 1 ? /* @__PURE__ */ jsx14(Text14, { dimColor: true, children: " r:cycle" }) : null
|
|
4303
4386
|
] }),
|
|
4304
|
-
/* @__PURE__ */
|
|
4305
|
-
/* @__PURE__ */
|
|
4306
|
-
/* @__PURE__ */
|
|
4387
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
4388
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Title: " }),
|
|
4389
|
+
/* @__PURE__ */ jsx14(Text14, { children: parsed.title })
|
|
4307
4390
|
] }),
|
|
4308
|
-
labels.length > 0 ? /* @__PURE__ */
|
|
4309
|
-
/* @__PURE__ */
|
|
4310
|
-
/* @__PURE__ */
|
|
4391
|
+
labels.length > 0 ? /* @__PURE__ */ jsxs14(Box14, { children: [
|
|
4392
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Labels: " }),
|
|
4393
|
+
/* @__PURE__ */ jsx14(Text14, { children: labels.join(", ") })
|
|
4311
4394
|
] }) : null,
|
|
4312
|
-
parsed.assignee ? /* @__PURE__ */
|
|
4313
|
-
/* @__PURE__ */
|
|
4314
|
-
/* @__PURE__ */
|
|
4395
|
+
parsed.assignee ? /* @__PURE__ */ jsxs14(Box14, { children: [
|
|
4396
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Assignee: " }),
|
|
4397
|
+
/* @__PURE__ */ jsxs14(Text14, { children: [
|
|
4315
4398
|
"@",
|
|
4316
4399
|
parsed.assignee
|
|
4317
4400
|
] })
|
|
4318
4401
|
] }) : null,
|
|
4319
|
-
parsed.dueDate ? /* @__PURE__ */
|
|
4320
|
-
/* @__PURE__ */
|
|
4321
|
-
/* @__PURE__ */
|
|
4402
|
+
parsed.dueDate ? /* @__PURE__ */ jsxs14(Box14, { children: [
|
|
4403
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Due: " }),
|
|
4404
|
+
/* @__PURE__ */ jsx14(Text14, { children: formatDue(parsed.dueDate) })
|
|
4322
4405
|
] }) : null,
|
|
4323
|
-
/* @__PURE__ */
|
|
4406
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Enter:add body Esc:cancel" })
|
|
4324
4407
|
] });
|
|
4325
4408
|
}
|
|
4326
|
-
return /* @__PURE__ */
|
|
4327
|
-
/* @__PURE__ */
|
|
4328
|
-
/* @__PURE__ */
|
|
4329
|
-
/* @__PURE__ */
|
|
4330
|
-
/* @__PURE__ */
|
|
4409
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
4410
|
+
/* @__PURE__ */ jsx14(Text14, { color: "cyan", bold: true, children: "\u2728 What do you need to do?" }),
|
|
4411
|
+
/* @__PURE__ */ jsxs14(Box14, { children: [
|
|
4412
|
+
/* @__PURE__ */ jsx14(Text14, { color: "cyan", children: "> " }),
|
|
4413
|
+
/* @__PURE__ */ jsx14(
|
|
4331
4414
|
TextInput4,
|
|
4332
4415
|
{
|
|
4333
4416
|
placeholder: "fix login bug #bug #priority:high @me due friday",
|
|
@@ -4336,8 +4419,8 @@ function NlCreateOverlay({
|
|
|
4336
4419
|
}
|
|
4337
4420
|
)
|
|
4338
4421
|
] }),
|
|
4339
|
-
parseError ? /* @__PURE__ */
|
|
4340
|
-
/* @__PURE__ */
|
|
4422
|
+
parseError ? /* @__PURE__ */ jsx14(Text14, { color: "red", children: parseError }) : null,
|
|
4423
|
+
/* @__PURE__ */ jsx14(Text14, { dimColor: true, children: "Tip: #label @user due <date> Enter:parse Esc:cancel" })
|
|
4341
4424
|
] });
|
|
4342
4425
|
}
|
|
4343
4426
|
function buildLabelList(parsed) {
|
|
@@ -4357,12 +4440,12 @@ var init_nl_create_overlay = __esm({
|
|
|
4357
4440
|
|
|
4358
4441
|
// src/board/components/search-bar.tsx
|
|
4359
4442
|
import { TextInput as TextInput5 } from "@inkjs/ui";
|
|
4360
|
-
import { Box as
|
|
4361
|
-
import { jsx as
|
|
4443
|
+
import { Box as Box15, Text as Text15 } from "ink";
|
|
4444
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
4362
4445
|
function SearchBar({ defaultValue, onChange, onSubmit }) {
|
|
4363
|
-
return /* @__PURE__ */
|
|
4364
|
-
/* @__PURE__ */
|
|
4365
|
-
/* @__PURE__ */
|
|
4446
|
+
return /* @__PURE__ */ jsxs15(Box15, { children: [
|
|
4447
|
+
/* @__PURE__ */ jsx15(Text15, { color: "yellow", children: "/" }),
|
|
4448
|
+
/* @__PURE__ */ jsx15(
|
|
4366
4449
|
TextInput5,
|
|
4367
4450
|
{
|
|
4368
4451
|
defaultValue,
|
|
@@ -4380,9 +4463,9 @@ var init_search_bar = __esm({
|
|
|
4380
4463
|
});
|
|
4381
4464
|
|
|
4382
4465
|
// src/board/components/status-picker.tsx
|
|
4383
|
-
import { Box as
|
|
4384
|
-
import { useRef as useRef12, useState as
|
|
4385
|
-
import { jsx as
|
|
4466
|
+
import { Box as Box16, Text as Text16, useInput as useInput11 } from "ink";
|
|
4467
|
+
import { useRef as useRef12, useState as useState15 } from "react";
|
|
4468
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
4386
4469
|
function isTerminal(name) {
|
|
4387
4470
|
return TERMINAL_STATUS_RE.test(name);
|
|
4388
4471
|
}
|
|
@@ -4429,11 +4512,11 @@ function StatusPicker({
|
|
|
4429
4512
|
onCancel,
|
|
4430
4513
|
showTerminalStatuses = true
|
|
4431
4514
|
}) {
|
|
4432
|
-
const [selectedIdx, setSelectedIdx] =
|
|
4515
|
+
const [selectedIdx, setSelectedIdx] = useState15(() => {
|
|
4433
4516
|
const idx = options.findIndex((o) => o.name === currentStatus);
|
|
4434
4517
|
return idx >= 0 ? idx : 0;
|
|
4435
4518
|
});
|
|
4436
|
-
const [confirmingTerminal, setConfirmingTerminal] =
|
|
4519
|
+
const [confirmingTerminal, setConfirmingTerminal] = useState15(false);
|
|
4437
4520
|
const submittedRef = useRef12(false);
|
|
4438
4521
|
useInput11((input2, key) => {
|
|
4439
4522
|
if (confirmingTerminal) {
|
|
@@ -4458,26 +4541,26 @@ function StatusPicker({
|
|
|
4458
4541
|
});
|
|
4459
4542
|
if (confirmingTerminal) {
|
|
4460
4543
|
const opt = options[selectedIdx];
|
|
4461
|
-
return /* @__PURE__ */
|
|
4462
|
-
/* @__PURE__ */
|
|
4544
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
|
|
4545
|
+
/* @__PURE__ */ jsxs16(Text16, { color: "yellow", bold: true, children: [
|
|
4463
4546
|
"Mark as ",
|
|
4464
4547
|
opt?.name,
|
|
4465
4548
|
"?"
|
|
4466
4549
|
] }),
|
|
4467
|
-
/* @__PURE__ */
|
|
4468
|
-
/* @__PURE__ */
|
|
4550
|
+
/* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "This will close the issue on GitHub." }),
|
|
4551
|
+
/* @__PURE__ */ jsx16(Text16, { children: "Continue? [y/n]" })
|
|
4469
4552
|
] });
|
|
4470
4553
|
}
|
|
4471
|
-
return /* @__PURE__ */
|
|
4472
|
-
/* @__PURE__ */
|
|
4554
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
|
|
4555
|
+
/* @__PURE__ */ jsx16(Text16, { color: "cyan", bold: true, children: "Move to status:" }),
|
|
4473
4556
|
options.map((opt, i) => {
|
|
4474
4557
|
const isCurrent = opt.name === currentStatus;
|
|
4475
4558
|
const isSelected = i === selectedIdx;
|
|
4476
4559
|
const terminal = isTerminal(opt.name) && showTerminalStatuses;
|
|
4477
4560
|
const prefix = isSelected ? "> " : " ";
|
|
4478
4561
|
const suffix = isCurrent ? " (current)" : terminal ? " (Done)" : "";
|
|
4479
|
-
return /* @__PURE__ */
|
|
4480
|
-
|
|
4562
|
+
return /* @__PURE__ */ jsxs16(
|
|
4563
|
+
Text16,
|
|
4481
4564
|
{
|
|
4482
4565
|
...isSelected ? { color: "cyan" } : terminal ? { color: "yellow" } : {},
|
|
4483
4566
|
dimColor: isCurrent,
|
|
@@ -4490,7 +4573,7 @@ function StatusPicker({
|
|
|
4490
4573
|
opt.id
|
|
4491
4574
|
);
|
|
4492
4575
|
}),
|
|
4493
|
-
/* @__PURE__ */
|
|
4576
|
+
/* @__PURE__ */ jsx16(Text16, { dimColor: true, children: "j/k:navigate Enter:select Esc:cancel" })
|
|
4494
4577
|
] });
|
|
4495
4578
|
}
|
|
4496
4579
|
var init_status_picker = __esm({
|
|
@@ -4501,7 +4584,7 @@ var init_status_picker = __esm({
|
|
|
4501
4584
|
});
|
|
4502
4585
|
|
|
4503
4586
|
// src/board/components/overlay-renderer.tsx
|
|
4504
|
-
import { Fragment as Fragment2, jsx as
|
|
4587
|
+
import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
4505
4588
|
function OverlayRenderer({
|
|
4506
4589
|
uiState,
|
|
4507
4590
|
config: config2,
|
|
@@ -4542,9 +4625,9 @@ function OverlayRenderer({
|
|
|
4542
4625
|
onPushEntry
|
|
4543
4626
|
}) {
|
|
4544
4627
|
const { mode, helpVisible } = uiState;
|
|
4545
|
-
return /* @__PURE__ */
|
|
4546
|
-
helpVisible ? /* @__PURE__ */
|
|
4547
|
-
mode === "overlay:status" && selectedRepoStatusOptions.length > 0 ? /* @__PURE__ */
|
|
4628
|
+
return /* @__PURE__ */ jsxs17(Fragment2, { children: [
|
|
4629
|
+
helpVisible ? /* @__PURE__ */ jsx17(HelpOverlay, { currentMode: mode, onClose: onToggleHelp }) : null,
|
|
4630
|
+
mode === "overlay:status" && selectedRepoStatusOptions.length > 0 ? /* @__PURE__ */ jsx17(
|
|
4548
4631
|
StatusPicker,
|
|
4549
4632
|
{
|
|
4550
4633
|
options: selectedRepoStatusOptions,
|
|
@@ -4553,7 +4636,7 @@ function OverlayRenderer({
|
|
|
4553
4636
|
onCancel: onExitOverlay
|
|
4554
4637
|
}
|
|
4555
4638
|
) : null,
|
|
4556
|
-
mode === "overlay:create" ? /* @__PURE__ */
|
|
4639
|
+
mode === "overlay:create" ? /* @__PURE__ */ jsx17(
|
|
4557
4640
|
CreateIssueForm,
|
|
4558
4641
|
{
|
|
4559
4642
|
repos: config2.repos,
|
|
@@ -4563,7 +4646,7 @@ function OverlayRenderer({
|
|
|
4563
4646
|
labelCache
|
|
4564
4647
|
}
|
|
4565
4648
|
) : null,
|
|
4566
|
-
mode === "overlay:confirmPick" ? /* @__PURE__ */
|
|
4649
|
+
mode === "overlay:confirmPick" ? /* @__PURE__ */ jsx17(
|
|
4567
4650
|
ConfirmPrompt,
|
|
4568
4651
|
{
|
|
4569
4652
|
message: "Pick this issue?",
|
|
@@ -4571,7 +4654,7 @@ function OverlayRenderer({
|
|
|
4571
4654
|
onCancel: onCancelPick
|
|
4572
4655
|
}
|
|
4573
4656
|
) : null,
|
|
4574
|
-
mode === "overlay:bulkAction" ? /* @__PURE__ */
|
|
4657
|
+
mode === "overlay:bulkAction" ? /* @__PURE__ */ jsx17(
|
|
4575
4658
|
BulkActionMenu,
|
|
4576
4659
|
{
|
|
4577
4660
|
count: multiSelectCount,
|
|
@@ -4580,7 +4663,7 @@ function OverlayRenderer({
|
|
|
4580
4663
|
onCancel: onExitOverlay
|
|
4581
4664
|
}
|
|
4582
4665
|
) : null,
|
|
4583
|
-
mode === "focus" && focusLabel ? /* @__PURE__ */
|
|
4666
|
+
mode === "focus" && focusLabel ? /* @__PURE__ */ jsx17(
|
|
4584
4667
|
FocusMode,
|
|
4585
4668
|
{
|
|
4586
4669
|
label: focusLabel,
|
|
@@ -4590,7 +4673,7 @@ function OverlayRenderer({
|
|
|
4590
4673
|
},
|
|
4591
4674
|
focusKey
|
|
4592
4675
|
) : null,
|
|
4593
|
-
mode === "overlay:label" && selectedIssue && defaultRepo ? /* @__PURE__ */
|
|
4676
|
+
mode === "overlay:label" && selectedIssue && defaultRepo ? /* @__PURE__ */ jsx17(
|
|
4594
4677
|
LabelPicker,
|
|
4595
4678
|
{
|
|
4596
4679
|
repo: defaultRepo,
|
|
@@ -4601,8 +4684,8 @@ function OverlayRenderer({
|
|
|
4601
4684
|
onError: onLabelError
|
|
4602
4685
|
}
|
|
4603
4686
|
) : null,
|
|
4604
|
-
mode === "search" ? /* @__PURE__ */
|
|
4605
|
-
mode === "overlay:comment" && selectedIssue ? /* @__PURE__ */
|
|
4687
|
+
mode === "search" ? /* @__PURE__ */ jsx17(SearchBar, { defaultValue: searchQuery, onChange: onSearchChange, onSubmit: onSearchSubmit }) : null,
|
|
4688
|
+
mode === "overlay:comment" && selectedIssue ? /* @__PURE__ */ jsx17(
|
|
4606
4689
|
CommentInput,
|
|
4607
4690
|
{
|
|
4608
4691
|
issueNumber: selectedIssue.number,
|
|
@@ -4612,8 +4695,8 @@ function OverlayRenderer({
|
|
|
4612
4695
|
onResumeRefresh
|
|
4613
4696
|
}
|
|
4614
4697
|
) : null,
|
|
4615
|
-
mode === "overlay:fuzzyPicker" ? /* @__PURE__ */
|
|
4616
|
-
mode === "overlay:createNl" ? /* @__PURE__ */
|
|
4698
|
+
mode === "overlay:fuzzyPicker" ? /* @__PURE__ */ jsx17(FuzzyPicker, { repos, onSelect: onFuzzySelect, onClose: onFuzzyClose }) : null,
|
|
4699
|
+
mode === "overlay:createNl" ? /* @__PURE__ */ jsx17(
|
|
4617
4700
|
NlCreateOverlay,
|
|
4618
4701
|
{
|
|
4619
4702
|
repos: config2.repos,
|
|
@@ -4626,7 +4709,7 @@ function OverlayRenderer({
|
|
|
4626
4709
|
onLlmFallback
|
|
4627
4710
|
}
|
|
4628
4711
|
) : null,
|
|
4629
|
-
mode === "overlay:editIssue" && selectedIssue && selectedRepoName ? /* @__PURE__ */
|
|
4712
|
+
mode === "overlay:editIssue" && selectedIssue && selectedRepoName ? /* @__PURE__ */ jsx17(
|
|
4630
4713
|
EditIssueOverlay,
|
|
4631
4714
|
{
|
|
4632
4715
|
issue: selectedIssue,
|
|
@@ -4662,9 +4745,106 @@ var init_overlay_renderer = __esm({
|
|
|
4662
4745
|
}
|
|
4663
4746
|
});
|
|
4664
4747
|
|
|
4748
|
+
// src/board/components/panel-layout.tsx
|
|
4749
|
+
import { Box as Box17 } from "ink";
|
|
4750
|
+
import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4751
|
+
function getLayoutMode(cols) {
|
|
4752
|
+
if (cols >= WIDE_THRESHOLD) return "wide";
|
|
4753
|
+
if (cols >= MEDIUM_THRESHOLD) return "medium";
|
|
4754
|
+
return "stacked";
|
|
4755
|
+
}
|
|
4756
|
+
function getDetailWidth(cols) {
|
|
4757
|
+
return Math.floor(cols * 0.4);
|
|
4758
|
+
}
|
|
4759
|
+
function PanelLayout({
|
|
4760
|
+
cols,
|
|
4761
|
+
issuesPanelHeight,
|
|
4762
|
+
reposPanel,
|
|
4763
|
+
statusesPanel,
|
|
4764
|
+
issuesPanel,
|
|
4765
|
+
detailPanel,
|
|
4766
|
+
activityPanel
|
|
4767
|
+
}) {
|
|
4768
|
+
const mode = getLayoutMode(cols);
|
|
4769
|
+
if (mode === "wide") {
|
|
4770
|
+
const detailWidth = getDetailWidth(cols);
|
|
4771
|
+
return /* @__PURE__ */ jsxs18(Box17, { flexDirection: "column", children: [
|
|
4772
|
+
/* @__PURE__ */ jsxs18(Box17, { height: issuesPanelHeight, children: [
|
|
4773
|
+
/* @__PURE__ */ jsxs18(Box17, { flexDirection: "column", width: LEFT_COL_WIDTH, children: [
|
|
4774
|
+
reposPanel,
|
|
4775
|
+
statusesPanel
|
|
4776
|
+
] }),
|
|
4777
|
+
/* @__PURE__ */ jsx18(Box17, { flexGrow: 1, flexDirection: "column", children: issuesPanel }),
|
|
4778
|
+
/* @__PURE__ */ jsx18(Box17, { width: detailWidth, flexDirection: "column", children: detailPanel })
|
|
4779
|
+
] }),
|
|
4780
|
+
/* @__PURE__ */ jsx18(Box17, { height: ACTIVITY_HEIGHT, children: activityPanel })
|
|
4781
|
+
] });
|
|
4782
|
+
}
|
|
4783
|
+
if (mode === "medium") {
|
|
4784
|
+
return /* @__PURE__ */ jsxs18(Box17, { flexDirection: "column", children: [
|
|
4785
|
+
/* @__PURE__ */ jsxs18(Box17, { height: issuesPanelHeight, children: [
|
|
4786
|
+
/* @__PURE__ */ jsxs18(Box17, { flexDirection: "column", width: LEFT_COL_WIDTH, children: [
|
|
4787
|
+
reposPanel,
|
|
4788
|
+
statusesPanel
|
|
4789
|
+
] }),
|
|
4790
|
+
/* @__PURE__ */ jsx18(Box17, { flexGrow: 1, flexDirection: "column", children: issuesPanel })
|
|
4791
|
+
] }),
|
|
4792
|
+
/* @__PURE__ */ jsx18(Box17, { height: ACTIVITY_HEIGHT, children: activityPanel })
|
|
4793
|
+
] });
|
|
4794
|
+
}
|
|
4795
|
+
return /* @__PURE__ */ jsxs18(Box17, { flexDirection: "column", children: [
|
|
4796
|
+
reposPanel,
|
|
4797
|
+
statusesPanel,
|
|
4798
|
+
/* @__PURE__ */ jsx18(Box17, { flexGrow: 1, flexDirection: "column", children: issuesPanel }),
|
|
4799
|
+
/* @__PURE__ */ jsx18(Box17, { height: ACTIVITY_HEIGHT, children: activityPanel })
|
|
4800
|
+
] });
|
|
4801
|
+
}
|
|
4802
|
+
var WIDE_THRESHOLD, MEDIUM_THRESHOLD, LEFT_COL_WIDTH, ACTIVITY_HEIGHT;
|
|
4803
|
+
var init_panel_layout = __esm({
|
|
4804
|
+
"src/board/components/panel-layout.tsx"() {
|
|
4805
|
+
"use strict";
|
|
4806
|
+
WIDE_THRESHOLD = 160;
|
|
4807
|
+
MEDIUM_THRESHOLD = 100;
|
|
4808
|
+
LEFT_COL_WIDTH = 24;
|
|
4809
|
+
ACTIVITY_HEIGHT = 3;
|
|
4810
|
+
}
|
|
4811
|
+
});
|
|
4812
|
+
|
|
4813
|
+
// src/board/components/repos-panel.tsx
|
|
4814
|
+
import { Box as Box18, Text as Text17 } from "ink";
|
|
4815
|
+
import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
4816
|
+
function shortName(fullName) {
|
|
4817
|
+
return fullName.includes("/") ? fullName.split("/")[1] ?? fullName : fullName;
|
|
4818
|
+
}
|
|
4819
|
+
function ReposPanel({ repos, selectedIdx, isActive }) {
|
|
4820
|
+
const borderColor = isActive ? "cyan" : "gray";
|
|
4821
|
+
return /* @__PURE__ */ jsxs19(Box18, { borderStyle: "single", borderColor, flexDirection: "column", flexGrow: 1, children: [
|
|
4822
|
+
/* @__PURE__ */ jsx19(Text17, { bold: true, color: isActive ? "cyan" : "white", children: "[1] Repos" }),
|
|
4823
|
+
repos.length === 0 ? /* @__PURE__ */ jsx19(Text17, { color: "gray", children: " \u2014" }) : repos.map((repo, i) => {
|
|
4824
|
+
const isSel = i === selectedIdx;
|
|
4825
|
+
const label = shortName(repo.name);
|
|
4826
|
+
return /* @__PURE__ */ jsxs19(Box18, { children: [
|
|
4827
|
+
/* @__PURE__ */ jsxs19(Text17, { color: isSel ? "cyan" : isActive ? "white" : "gray", bold: isSel, children: [
|
|
4828
|
+
isSel ? "\u25B6 " : " ",
|
|
4829
|
+
label
|
|
4830
|
+
] }),
|
|
4831
|
+
/* @__PURE__ */ jsxs19(Text17, { color: "gray", children: [
|
|
4832
|
+
" ",
|
|
4833
|
+
repo.openCount
|
|
4834
|
+
] })
|
|
4835
|
+
] }, repo.name);
|
|
4836
|
+
})
|
|
4837
|
+
] });
|
|
4838
|
+
}
|
|
4839
|
+
var init_repos_panel = __esm({
|
|
4840
|
+
"src/board/components/repos-panel.tsx"() {
|
|
4841
|
+
"use strict";
|
|
4842
|
+
}
|
|
4843
|
+
});
|
|
4844
|
+
|
|
4665
4845
|
// src/board/components/issue-row.tsx
|
|
4666
|
-
import { Box as
|
|
4667
|
-
import { Fragment as Fragment3, jsx as
|
|
4846
|
+
import { Box as Box19, Text as Text18 } from "ink";
|
|
4847
|
+
import { Fragment as Fragment3, jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
4668
4848
|
function truncate(s, max) {
|
|
4669
4849
|
return s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
|
|
4670
4850
|
}
|
|
@@ -4705,30 +4885,30 @@ function IssueRow({ issue, selfLogin, isSelected }) {
|
|
|
4705
4885
|
const labels = (issue.labels ?? []).slice(0, 2);
|
|
4706
4886
|
const target = formatTargetDate(issue.targetDate);
|
|
4707
4887
|
const titleStr = truncate(issue.title, 42).padEnd(42);
|
|
4708
|
-
return /* @__PURE__ */
|
|
4709
|
-
isSelected ? /* @__PURE__ */
|
|
4710
|
-
/* @__PURE__ */
|
|
4888
|
+
return /* @__PURE__ */ jsxs20(Box19, { children: [
|
|
4889
|
+
isSelected ? /* @__PURE__ */ jsx20(Text18, { color: "cyan", bold: true, children: "\u25B6 " }) : /* @__PURE__ */ jsx20(Text18, { children: " " }),
|
|
4890
|
+
/* @__PURE__ */ jsxs20(Text18, { color: "cyan", children: [
|
|
4711
4891
|
"#",
|
|
4712
4892
|
String(issue.number).padEnd(5)
|
|
4713
4893
|
] }),
|
|
4714
|
-
/* @__PURE__ */
|
|
4715
|
-
isSelected ? /* @__PURE__ */
|
|
4716
|
-
/* @__PURE__ */
|
|
4717
|
-
/* @__PURE__ */
|
|
4894
|
+
/* @__PURE__ */ jsx20(Text18, { children: " " }),
|
|
4895
|
+
isSelected ? /* @__PURE__ */ jsx20(Text18, { color: "white", bold: true, children: titleStr }) : /* @__PURE__ */ jsx20(Text18, { children: titleStr }),
|
|
4896
|
+
/* @__PURE__ */ jsx20(Text18, { children: " " }),
|
|
4897
|
+
/* @__PURE__ */ jsx20(Box19, { width: LABEL_COL_WIDTH, children: labels.map((l, i) => /* @__PURE__ */ jsxs20(Text18, { children: [
|
|
4718
4898
|
i > 0 ? " " : "",
|
|
4719
|
-
/* @__PURE__ */
|
|
4899
|
+
/* @__PURE__ */ jsxs20(Text18, { color: labelColor(l.name), children: [
|
|
4720
4900
|
"[",
|
|
4721
4901
|
truncate(l.name, 12),
|
|
4722
4902
|
"]"
|
|
4723
4903
|
] })
|
|
4724
4904
|
] }, l.name)) }),
|
|
4725
|
-
/* @__PURE__ */
|
|
4726
|
-
/* @__PURE__ */
|
|
4727
|
-
/* @__PURE__ */
|
|
4728
|
-
/* @__PURE__ */
|
|
4729
|
-
target.text ? /* @__PURE__ */
|
|
4730
|
-
/* @__PURE__ */
|
|
4731
|
-
/* @__PURE__ */
|
|
4905
|
+
/* @__PURE__ */ jsx20(Text18, { children: " " }),
|
|
4906
|
+
/* @__PURE__ */ jsx20(Text18, { color: assigneeColor, children: assigneeText.padEnd(14) }),
|
|
4907
|
+
/* @__PURE__ */ jsx20(Text18, { children: " " }),
|
|
4908
|
+
/* @__PURE__ */ jsx20(Text18, { color: "gray", children: timeAgo2(issue.updatedAt).padStart(4) }),
|
|
4909
|
+
target.text ? /* @__PURE__ */ jsxs20(Fragment3, { children: [
|
|
4910
|
+
/* @__PURE__ */ jsx20(Text18, { children: " " }),
|
|
4911
|
+
/* @__PURE__ */ jsx20(Text18, { color: target.color, children: target.text })
|
|
4732
4912
|
] }) : null
|
|
4733
4913
|
] });
|
|
4734
4914
|
}
|
|
@@ -4751,68 +4931,21 @@ var init_issue_row = __esm({
|
|
|
4751
4931
|
}
|
|
4752
4932
|
});
|
|
4753
4933
|
|
|
4754
|
-
// src/board/components/task-row.tsx
|
|
4755
|
-
import { Box as Box17, Text as Text17 } from "ink";
|
|
4756
|
-
import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
4757
|
-
function truncate2(s, max) {
|
|
4758
|
-
return s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
|
|
4759
|
-
}
|
|
4760
|
-
function formatDue2(dateStr) {
|
|
4761
|
-
if (!dateStr) return { text: "", color: "gray" };
|
|
4762
|
-
const d = new Date(dateStr);
|
|
4763
|
-
const days = Math.ceil((d.getTime() - Date.now()) / 864e5);
|
|
4764
|
-
if (days < 0) return { text: `${Math.abs(days)}d overdue`, color: "red" };
|
|
4765
|
-
if (days === 0) return { text: "today", color: "yellow" };
|
|
4766
|
-
if (days === 1) return { text: "tomorrow", color: "white" };
|
|
4767
|
-
if (days <= 7) return { text: `in ${days}d`, color: "white" };
|
|
4768
|
-
return {
|
|
4769
|
-
text: d.toLocaleDateString("en-US", { month: "short", day: "numeric" }),
|
|
4770
|
-
color: "gray"
|
|
4771
|
-
};
|
|
4772
|
-
}
|
|
4773
|
-
function TaskRow({ task: task2, isSelected }) {
|
|
4774
|
-
const pri = PRIORITY_INDICATORS[task2.priority] ?? DEFAULT_PRIORITY;
|
|
4775
|
-
const due = formatDue2(task2.dueDate);
|
|
4776
|
-
const titleStr = truncate2(task2.title, 45).padEnd(45);
|
|
4777
|
-
return /* @__PURE__ */ jsxs18(Box17, { children: [
|
|
4778
|
-
isSelected ? /* @__PURE__ */ jsx18(Text17, { color: "cyan", bold: true, children: "\u25B6 " }) : /* @__PURE__ */ jsx18(Text17, { children: " " }),
|
|
4779
|
-
/* @__PURE__ */ jsx18(Text17, { color: pri.color, children: pri.text }),
|
|
4780
|
-
/* @__PURE__ */ jsx18(Text17, { children: " " }),
|
|
4781
|
-
isSelected ? /* @__PURE__ */ jsx18(Text17, { color: "white", bold: true, children: titleStr }) : /* @__PURE__ */ jsx18(Text17, { children: titleStr }),
|
|
4782
|
-
/* @__PURE__ */ jsx18(Text17, { children: " " }),
|
|
4783
|
-
/* @__PURE__ */ jsx18(Text17, { color: due.color, children: due.text })
|
|
4784
|
-
] });
|
|
4785
|
-
}
|
|
4786
|
-
var PRIORITY_INDICATORS, DEFAULT_PRIORITY;
|
|
4787
|
-
var init_task_row = __esm({
|
|
4788
|
-
"src/board/components/task-row.tsx"() {
|
|
4789
|
-
"use strict";
|
|
4790
|
-
init_types();
|
|
4791
|
-
PRIORITY_INDICATORS = {
|
|
4792
|
-
[5 /* High */]: { text: "[!]", color: "red" },
|
|
4793
|
-
[3 /* Medium */]: { text: "[~]", color: "yellow" },
|
|
4794
|
-
[1 /* Low */]: { text: "[\u2193]", color: "blue" },
|
|
4795
|
-
[0 /* None */]: { text: " ", color: "gray" }
|
|
4796
|
-
};
|
|
4797
|
-
DEFAULT_PRIORITY = { text: " ", color: "gray" };
|
|
4798
|
-
}
|
|
4799
|
-
});
|
|
4800
|
-
|
|
4801
4934
|
// src/board/components/row-renderer.tsx
|
|
4802
|
-
import { Box as
|
|
4803
|
-
import { jsx as
|
|
4935
|
+
import { Box as Box20, Text as Text19 } from "ink";
|
|
4936
|
+
import { jsx as jsx21, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
4804
4937
|
function RowRenderer({ row, selectedId, selfLogin, isMultiSelected }) {
|
|
4805
4938
|
switch (row.type) {
|
|
4806
4939
|
case "sectionHeader": {
|
|
4807
4940
|
const arrow = row.isCollapsed ? "\u25B6" : "\u25BC";
|
|
4808
4941
|
const isSel = selectedId === row.navId;
|
|
4809
|
-
return /* @__PURE__ */
|
|
4810
|
-
/* @__PURE__ */
|
|
4942
|
+
return /* @__PURE__ */ jsxs21(Box20, { children: [
|
|
4943
|
+
/* @__PURE__ */ jsxs21(Text19, { color: isSel ? "cyan" : "white", bold: true, children: [
|
|
4811
4944
|
arrow,
|
|
4812
4945
|
" ",
|
|
4813
4946
|
row.label
|
|
4814
4947
|
] }),
|
|
4815
|
-
/* @__PURE__ */
|
|
4948
|
+
/* @__PURE__ */ jsxs21(Text19, { color: "gray", children: [
|
|
4816
4949
|
" ",
|
|
4817
4950
|
"(",
|
|
4818
4951
|
row.count,
|
|
@@ -4826,26 +4959,26 @@ function RowRenderer({ row, selectedId, selfLogin, isMultiSelected }) {
|
|
|
4826
4959
|
if (row.navId) {
|
|
4827
4960
|
const arrow = row.isCollapsed ? "\u25B6" : "\u25BC";
|
|
4828
4961
|
const isSel = selectedId === row.navId;
|
|
4829
|
-
return /* @__PURE__ */
|
|
4830
|
-
/* @__PURE__ */
|
|
4962
|
+
return /* @__PURE__ */ jsxs21(Box20, { children: [
|
|
4963
|
+
/* @__PURE__ */ jsxs21(Text19, { color: isSel ? "cyan" : "gray", children: [
|
|
4831
4964
|
" ",
|
|
4832
4965
|
arrow,
|
|
4833
4966
|
" ",
|
|
4834
4967
|
row.text
|
|
4835
4968
|
] }),
|
|
4836
|
-
/* @__PURE__ */
|
|
4969
|
+
/* @__PURE__ */ jsxs21(Text19, { color: "gray", children: [
|
|
4837
4970
|
" (",
|
|
4838
4971
|
row.count,
|
|
4839
4972
|
")"
|
|
4840
4973
|
] })
|
|
4841
4974
|
] });
|
|
4842
4975
|
}
|
|
4843
|
-
return /* @__PURE__ */
|
|
4844
|
-
/* @__PURE__ */
|
|
4976
|
+
return /* @__PURE__ */ jsxs21(Box20, { children: [
|
|
4977
|
+
/* @__PURE__ */ jsxs21(Text19, { bold: true, color: "white", children: [
|
|
4845
4978
|
" ",
|
|
4846
4979
|
row.text
|
|
4847
4980
|
] }),
|
|
4848
|
-
row.count != null ? /* @__PURE__ */
|
|
4981
|
+
row.count != null ? /* @__PURE__ */ jsxs21(Text19, { color: "gray", children: [
|
|
4849
4982
|
" (",
|
|
4850
4983
|
row.count,
|
|
4851
4984
|
")"
|
|
@@ -4854,32 +4987,25 @@ function RowRenderer({ row, selectedId, selfLogin, isMultiSelected }) {
|
|
|
4854
4987
|
}
|
|
4855
4988
|
case "issue": {
|
|
4856
4989
|
const checkbox2 = isMultiSelected != null ? isMultiSelected ? "\u2611 " : "\u2610 " : "";
|
|
4857
|
-
return /* @__PURE__ */
|
|
4858
|
-
checkbox2 ? /* @__PURE__ */
|
|
4859
|
-
/* @__PURE__ */
|
|
4860
|
-
] });
|
|
4861
|
-
}
|
|
4862
|
-
case "task": {
|
|
4863
|
-
const checkbox2 = isMultiSelected != null ? isMultiSelected ? "\u2611 " : "\u2610 " : "";
|
|
4864
|
-
return /* @__PURE__ */ jsxs19(Box18, { children: [
|
|
4865
|
-
checkbox2 ? /* @__PURE__ */ jsx19(Text18, { color: isMultiSelected ? "cyan" : "gray", children: checkbox2 }) : null,
|
|
4866
|
-
/* @__PURE__ */ jsx19(TaskRow, { task: row.task, isSelected: selectedId === row.navId })
|
|
4990
|
+
return /* @__PURE__ */ jsxs21(Box20, { children: [
|
|
4991
|
+
checkbox2 ? /* @__PURE__ */ jsx21(Text19, { color: isMultiSelected ? "cyan" : "gray", children: checkbox2 }) : null,
|
|
4992
|
+
/* @__PURE__ */ jsx21(IssueRow, { issue: row.issue, selfLogin, isSelected: selectedId === row.navId })
|
|
4867
4993
|
] });
|
|
4868
4994
|
}
|
|
4869
4995
|
case "activity": {
|
|
4870
|
-
const ago =
|
|
4871
|
-
return /* @__PURE__ */
|
|
4996
|
+
const ago = new Date(row.event.timestamp).toLocaleTimeString();
|
|
4997
|
+
return /* @__PURE__ */ jsxs21(Text19, { dimColor: true, children: [
|
|
4872
4998
|
" ",
|
|
4873
4999
|
ago,
|
|
4874
5000
|
": ",
|
|
4875
|
-
/* @__PURE__ */
|
|
5001
|
+
/* @__PURE__ */ jsxs21(Text19, { color: "gray", children: [
|
|
4876
5002
|
"@",
|
|
4877
5003
|
row.event.actor
|
|
4878
5004
|
] }),
|
|
4879
5005
|
" ",
|
|
4880
5006
|
row.event.summary,
|
|
4881
5007
|
" ",
|
|
4882
|
-
/* @__PURE__ */
|
|
5008
|
+
/* @__PURE__ */ jsxs21(Text19, { dimColor: true, children: [
|
|
4883
5009
|
"(",
|
|
4884
5010
|
row.event.repoShortName,
|
|
4885
5011
|
")"
|
|
@@ -4887,62 +5013,66 @@ function RowRenderer({ row, selectedId, selfLogin, isMultiSelected }) {
|
|
|
4887
5013
|
] });
|
|
4888
5014
|
}
|
|
4889
5015
|
case "error":
|
|
4890
|
-
return /* @__PURE__ */
|
|
5016
|
+
return /* @__PURE__ */ jsxs21(Text19, { color: "red", children: [
|
|
4891
5017
|
" Error: ",
|
|
4892
5018
|
row.text
|
|
4893
5019
|
] });
|
|
4894
5020
|
case "gap":
|
|
4895
|
-
return /* @__PURE__ */
|
|
5021
|
+
return /* @__PURE__ */ jsx21(Text19, { children: "" });
|
|
4896
5022
|
}
|
|
4897
5023
|
}
|
|
4898
5024
|
var init_row_renderer = __esm({
|
|
4899
5025
|
"src/board/components/row-renderer.tsx"() {
|
|
4900
5026
|
"use strict";
|
|
4901
|
-
init_constants();
|
|
4902
5027
|
init_issue_row();
|
|
4903
|
-
init_task_row();
|
|
4904
5028
|
}
|
|
4905
5029
|
});
|
|
4906
5030
|
|
|
4907
|
-
// src/board/components/
|
|
4908
|
-
import { Box as
|
|
4909
|
-
import { jsx as
|
|
4910
|
-
function
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
5031
|
+
// src/board/components/statuses-panel.tsx
|
|
5032
|
+
import { Box as Box21, Text as Text20 } from "ink";
|
|
5033
|
+
import { jsx as jsx22, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
5034
|
+
function StatusesPanel({ groups, selectedIdx, isActive }) {
|
|
5035
|
+
const borderColor = isActive ? "cyan" : "gray";
|
|
5036
|
+
return /* @__PURE__ */ jsxs22(Box21, { borderStyle: "single", borderColor, flexDirection: "column", flexGrow: 1, children: [
|
|
5037
|
+
/* @__PURE__ */ jsx22(Text20, { bold: true, color: isActive ? "cyan" : "white", children: "[2] Statuses" }),
|
|
5038
|
+
groups.length === 0 ? /* @__PURE__ */ jsx22(Text20, { color: "gray", children: " \u2014" }) : groups.map((group, i) => {
|
|
5039
|
+
const isSel = i === selectedIdx;
|
|
5040
|
+
return /* @__PURE__ */ jsxs22(Box21, { children: [
|
|
5041
|
+
/* @__PURE__ */ jsxs22(Text20, { color: isSel ? "cyan" : isActive ? "white" : "gray", bold: isSel, children: [
|
|
5042
|
+
isSel ? "\u25B6 " : " ",
|
|
5043
|
+
group.label
|
|
5044
|
+
] }),
|
|
5045
|
+
/* @__PURE__ */ jsxs22(Text20, { color: "gray", children: [
|
|
5046
|
+
" ",
|
|
5047
|
+
group.count
|
|
5048
|
+
] })
|
|
5049
|
+
] }, group.id);
|
|
5050
|
+
})
|
|
5051
|
+
] });
|
|
5052
|
+
}
|
|
5053
|
+
var init_statuses_panel = __esm({
|
|
5054
|
+
"src/board/components/statuses-panel.tsx"() {
|
|
4925
5055
|
"use strict";
|
|
4926
5056
|
}
|
|
4927
5057
|
});
|
|
4928
5058
|
|
|
4929
5059
|
// src/board/components/toast-container.tsx
|
|
4930
5060
|
import { Spinner as Spinner3 } from "@inkjs/ui";
|
|
4931
|
-
import { Box as
|
|
4932
|
-
import { Fragment as Fragment4, jsx as
|
|
5061
|
+
import { Box as Box22, Text as Text21 } from "ink";
|
|
5062
|
+
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
4933
5063
|
function ToastContainer({ toasts }) {
|
|
4934
5064
|
if (toasts.length === 0) return null;
|
|
4935
|
-
return /* @__PURE__ */
|
|
4936
|
-
/* @__PURE__ */
|
|
4937
|
-
/* @__PURE__ */
|
|
5065
|
+
return /* @__PURE__ */ jsx23(Box22, { flexDirection: "column", children: toasts.map((t) => /* @__PURE__ */ jsx23(Box22, { children: t.type === "loading" ? /* @__PURE__ */ jsxs23(Fragment4, { children: [
|
|
5066
|
+
/* @__PURE__ */ jsx23(Spinner3, { label: "" }),
|
|
5067
|
+
/* @__PURE__ */ jsxs23(Text21, { color: "cyan", children: [
|
|
4938
5068
|
" ",
|
|
4939
5069
|
t.message
|
|
4940
5070
|
] })
|
|
4941
|
-
] }) : /* @__PURE__ */
|
|
5071
|
+
] }) : /* @__PURE__ */ jsxs23(Text21, { color: TYPE_COLORS[t.type], children: [
|
|
4942
5072
|
TYPE_PREFIXES[t.type],
|
|
4943
5073
|
" ",
|
|
4944
5074
|
t.message,
|
|
4945
|
-
t.type === "error" ? /* @__PURE__ */
|
|
5075
|
+
t.type === "error" ? /* @__PURE__ */ jsx23(Text21, { color: "gray", children: t.retry ? " [r]etry [d]ismiss" : " [d]ismiss" }) : null
|
|
4946
5076
|
] }) }, t.id)) });
|
|
4947
5077
|
}
|
|
4948
5078
|
var TYPE_COLORS, TYPE_PREFIXES;
|
|
@@ -4966,9 +5096,9 @@ var init_toast_container = __esm({
|
|
|
4966
5096
|
// src/board/components/dashboard.tsx
|
|
4967
5097
|
import { execFileSync as execFileSync3, spawnSync as spawnSync4 } from "child_process";
|
|
4968
5098
|
import { Spinner as Spinner4 } from "@inkjs/ui";
|
|
4969
|
-
import { Box as
|
|
4970
|
-
import { useCallback as
|
|
4971
|
-
import { Fragment as Fragment5, jsx as
|
|
5099
|
+
import { Box as Box23, Text as Text22, useApp, useStdout } from "ink";
|
|
5100
|
+
import { useCallback as useCallback12, useEffect as useEffect9, useMemo as useMemo3, useRef as useRef13, useState as useState16 } from "react";
|
|
5101
|
+
import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
4972
5102
|
function resolveStatusGroups(statusOptions, configuredGroups) {
|
|
4973
5103
|
if (configuredGroups && configuredGroups.length > 0) {
|
|
4974
5104
|
return configuredGroups.map((entry) => {
|
|
@@ -5006,7 +5136,7 @@ function groupByStatus(issues) {
|
|
|
5006
5136
|
}
|
|
5007
5137
|
return groups;
|
|
5008
5138
|
}
|
|
5009
|
-
function buildBoardTree(repos,
|
|
5139
|
+
function buildBoardTree(repos, activity) {
|
|
5010
5140
|
const sections = repos.map((rd) => {
|
|
5011
5141
|
const sectionId = rd.repo.name;
|
|
5012
5142
|
if (rd.error) {
|
|
@@ -5035,85 +5165,65 @@ function buildBoardTree(repos, tasks, activity) {
|
|
|
5035
5165
|
}
|
|
5036
5166
|
return { repo: rd.repo, sectionId, groups, error: null };
|
|
5037
5167
|
});
|
|
5038
|
-
return { activity, sections
|
|
5168
|
+
return { activity, sections };
|
|
5039
5169
|
}
|
|
5040
|
-
function
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
label: repo.shortName,
|
|
5044
|
-
count: groups.reduce((s, g) => s + g.issues.length, 0)
|
|
5045
|
-
}));
|
|
5046
|
-
if (tree.activity.length > 0)
|
|
5047
|
-
tabs.push({ id: "activity", label: "Activity", count: tree.activity.length });
|
|
5048
|
-
if (tree.tasks.length > 0)
|
|
5049
|
-
tabs.push({ id: "ticktick", label: "Tasks", count: tree.tasks.length });
|
|
5050
|
-
return tabs;
|
|
5051
|
-
}
|
|
5052
|
-
function buildNavItemsForTab(tabId, tree) {
|
|
5053
|
-
if (tabId === "activity") return [];
|
|
5054
|
-
if (tabId === "ticktick")
|
|
5055
|
-
return tree.tasks.map((task2) => ({
|
|
5056
|
-
id: `tt:${task2.id}`,
|
|
5057
|
-
section: tabId,
|
|
5058
|
-
type: "item"
|
|
5059
|
-
}));
|
|
5060
|
-
const section = tree.sections.find((s) => s.sectionId === tabId);
|
|
5170
|
+
function buildNavItemsForRepo(sections, repoName, statusGroupId) {
|
|
5171
|
+
if (!repoName) return [];
|
|
5172
|
+
const section = sections.find((s) => s.sectionId === repoName);
|
|
5061
5173
|
if (!section) return [];
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
);
|
|
5174
|
+
const activeGroup = section.groups.find((g) => g.subId === statusGroupId) ?? section.groups[0];
|
|
5175
|
+
if (!activeGroup) return [];
|
|
5176
|
+
return activeGroup.issues.map((issue) => ({
|
|
5177
|
+
id: `gh:${section.repo.name}:${issue.number}`,
|
|
5178
|
+
section: repoName,
|
|
5179
|
+
type: "item"
|
|
5180
|
+
}));
|
|
5069
5181
|
}
|
|
5070
|
-
function
|
|
5071
|
-
if (
|
|
5072
|
-
return
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
navId: `tt:${task2.id}`,
|
|
5083
|
-
task: task2
|
|
5084
|
-
}));
|
|
5085
|
-
const section = tree.sections.find((s) => s.sectionId === tabId);
|
|
5182
|
+
function buildFlatRowsForRepo(sections, repoName, statusGroupId) {
|
|
5183
|
+
if (!repoName) {
|
|
5184
|
+
return [
|
|
5185
|
+
{
|
|
5186
|
+
type: "subHeader",
|
|
5187
|
+
key: "select-repo",
|
|
5188
|
+
navId: null,
|
|
5189
|
+
text: "Select a repo in panel [1]"
|
|
5190
|
+
}
|
|
5191
|
+
];
|
|
5192
|
+
}
|
|
5193
|
+
const section = sections.find((s) => s.sectionId === repoName);
|
|
5086
5194
|
if (!section) return [];
|
|
5087
|
-
if (section.error)
|
|
5088
|
-
return [{ type: "error", key: `error:${
|
|
5089
|
-
|
|
5195
|
+
if (section.error) {
|
|
5196
|
+
return [{ type: "error", key: `error:${repoName}`, navId: null, text: section.error }];
|
|
5197
|
+
}
|
|
5198
|
+
if (section.groups.length === 0) {
|
|
5090
5199
|
return [
|
|
5091
|
-
{
|
|
5200
|
+
{
|
|
5201
|
+
type: "subHeader",
|
|
5202
|
+
key: `empty:${repoName}`,
|
|
5203
|
+
navId: null,
|
|
5204
|
+
text: "No open issues"
|
|
5205
|
+
}
|
|
5092
5206
|
];
|
|
5093
|
-
const rows = [];
|
|
5094
|
-
let isFirst = true;
|
|
5095
|
-
for (const group of section.groups) {
|
|
5096
|
-
if (!isFirst)
|
|
5097
|
-
rows.push({ type: "gap", key: `gap:${tabId}:${group.label}`, navId: null });
|
|
5098
|
-
isFirst = false;
|
|
5099
|
-
rows.push({
|
|
5100
|
-
type: "subHeader",
|
|
5101
|
-
key: group.subId,
|
|
5102
|
-
navId: null,
|
|
5103
|
-
text: group.label,
|
|
5104
|
-
count: group.issues.length,
|
|
5105
|
-
isCollapsed: false
|
|
5106
|
-
});
|
|
5107
|
-
for (const issue of group.issues)
|
|
5108
|
-
rows.push({
|
|
5109
|
-
type: "issue",
|
|
5110
|
-
key: `gh:${section.repo.name}:${issue.number}`,
|
|
5111
|
-
navId: `gh:${section.repo.name}:${issue.number}`,
|
|
5112
|
-
issue,
|
|
5113
|
-
repoName: section.repo.name
|
|
5114
|
-
});
|
|
5115
5207
|
}
|
|
5116
|
-
|
|
5208
|
+
const activeGroup = section.groups.find((g) => g.subId === statusGroupId) ?? section.groups[0];
|
|
5209
|
+
if (!activeGroup) return [];
|
|
5210
|
+
if (activeGroup.issues.length === 0) {
|
|
5211
|
+
return [
|
|
5212
|
+
{
|
|
5213
|
+
type: "subHeader",
|
|
5214
|
+
key: `empty-group:${statusGroupId}`,
|
|
5215
|
+
navId: null,
|
|
5216
|
+
text: "No issues in this status group"
|
|
5217
|
+
}
|
|
5218
|
+
];
|
|
5219
|
+
}
|
|
5220
|
+
return activeGroup.issues.map((issue) => ({
|
|
5221
|
+
type: "issue",
|
|
5222
|
+
key: `gh:${section.repo.name}:${issue.number}`,
|
|
5223
|
+
navId: `gh:${section.repo.name}:${issue.number}`,
|
|
5224
|
+
issue,
|
|
5225
|
+
repoName: section.repo.name
|
|
5226
|
+
}));
|
|
5117
5227
|
}
|
|
5118
5228
|
function openInBrowser(url) {
|
|
5119
5229
|
if (!(url.startsWith("https://") || url.startsWith("http://"))) return;
|
|
@@ -5133,13 +5243,13 @@ function findSelectedIssueWithRepo(repos, selectedId) {
|
|
|
5133
5243
|
return null;
|
|
5134
5244
|
}
|
|
5135
5245
|
function RefreshAge({ lastRefresh }) {
|
|
5136
|
-
const [, setTick] =
|
|
5246
|
+
const [, setTick] = useState16(0);
|
|
5137
5247
|
useEffect9(() => {
|
|
5138
5248
|
const id = setInterval(() => setTick((t) => t + 1), 1e4);
|
|
5139
5249
|
return () => clearInterval(id);
|
|
5140
5250
|
}, []);
|
|
5141
5251
|
if (!lastRefresh) return null;
|
|
5142
|
-
return /* @__PURE__ */
|
|
5252
|
+
return /* @__PURE__ */ jsxs24(Text22, { color: refreshAgeColor(lastRefresh), children: [
|
|
5143
5253
|
"Updated ",
|
|
5144
5254
|
timeAgo(lastRefresh)
|
|
5145
5255
|
] });
|
|
@@ -5163,19 +5273,16 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5163
5273
|
clearPendingMutation
|
|
5164
5274
|
} = useData(config2, options, refreshMs);
|
|
5165
5275
|
const allRepos = useMemo3(() => data?.repos ?? [], [data?.repos]);
|
|
5166
|
-
const allTasks = useMemo3(
|
|
5167
|
-
() => config2.ticktick.enabled ? data?.ticktick ?? [] : [],
|
|
5168
|
-
[data?.ticktick, config2.ticktick.enabled]
|
|
5169
|
-
);
|
|
5170
5276
|
const allActivity = useMemo3(() => data?.activity ?? [], [data?.activity]);
|
|
5171
5277
|
const ui = useUIState();
|
|
5172
|
-
const
|
|
5173
|
-
const [
|
|
5174
|
-
const
|
|
5278
|
+
const panelFocus = usePanelFocus(3);
|
|
5279
|
+
const [searchQuery, setSearchQuery] = useState16("");
|
|
5280
|
+
const [mineOnly, setMineOnly] = useState16(false);
|
|
5281
|
+
const handleToggleMine = useCallback12(() => {
|
|
5175
5282
|
setMineOnly((prev) => !prev);
|
|
5176
5283
|
}, []);
|
|
5177
5284
|
const { toasts, toast, handleErrorAction } = useToast();
|
|
5178
|
-
const [logVisible, setLogVisible] =
|
|
5285
|
+
const [logVisible, setLogVisible] = useState16(false);
|
|
5179
5286
|
const { entries: logEntries, pushEntry, undoLast, hasUndoable } = useActionLog(toast, refresh);
|
|
5180
5287
|
useEffect9(() => {
|
|
5181
5288
|
const last = logEntries[logEntries.length - 1];
|
|
@@ -5199,45 +5306,75 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5199
5306
|
const q = searchQuery.toLowerCase();
|
|
5200
5307
|
return filtered.map((rd) => ({ ...rd, issues: rd.issues.filter((i) => i.title.toLowerCase().includes(q)) })).filter((rd) => rd.issues.length > 0);
|
|
5201
5308
|
}, [allRepos, searchQuery, mineOnly, config2.board.assignee]);
|
|
5202
|
-
const
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5309
|
+
const boardTree = useMemo3(() => buildBoardTree(repos, allActivity), [repos, allActivity]);
|
|
5310
|
+
const [selectedRepoIdx, setSelectedRepoIdx] = useState16(0);
|
|
5311
|
+
const clampedRepoIdx = Math.min(selectedRepoIdx, Math.max(0, boardTree.sections.length - 1));
|
|
5312
|
+
const reposNav = {
|
|
5313
|
+
moveUp: useCallback12(() => setSelectedRepoIdx((i) => Math.max(0, i - 1)), []),
|
|
5314
|
+
moveDown: useCallback12(
|
|
5315
|
+
() => setSelectedRepoIdx((i) => Math.min(Math.max(0, boardTree.sections.length - 1), i + 1)),
|
|
5316
|
+
[boardTree.sections.length]
|
|
5317
|
+
)
|
|
5318
|
+
};
|
|
5319
|
+
const [selectedStatusIdx, setSelectedStatusIdx] = useState16(0);
|
|
5320
|
+
const selectedSection = boardTree.sections[clampedRepoIdx] ?? null;
|
|
5321
|
+
const clampedStatusIdx = Math.min(
|
|
5322
|
+
selectedStatusIdx,
|
|
5323
|
+
Math.max(0, (selectedSection?.groups.length ?? 1) - 1)
|
|
5210
5324
|
);
|
|
5211
|
-
const
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
(idx) => {
|
|
5225
|
-
const tab = tabs[idx];
|
|
5226
|
-
if (tab) setActiveTabId(tab.id);
|
|
5227
|
-
},
|
|
5228
|
-
[tabs]
|
|
5325
|
+
const statusesNav = {
|
|
5326
|
+
moveUp: useCallback12(() => setSelectedStatusIdx((i) => Math.max(0, i - 1)), []),
|
|
5327
|
+
moveDown: useCallback12(
|
|
5328
|
+
() => setSelectedStatusIdx(
|
|
5329
|
+
(i) => Math.min(Math.max(0, (selectedSection?.groups.length ?? 1) - 1), i + 1)
|
|
5330
|
+
),
|
|
5331
|
+
[selectedSection?.groups.length]
|
|
5332
|
+
)
|
|
5333
|
+
};
|
|
5334
|
+
const [activitySelectedIdx, setActivitySelectedIdx] = useState16(0);
|
|
5335
|
+
const clampedActivityIdx = Math.min(
|
|
5336
|
+
activitySelectedIdx,
|
|
5337
|
+
Math.max(0, boardTree.activity.length - 1)
|
|
5229
5338
|
);
|
|
5339
|
+
const activityNav = {
|
|
5340
|
+
moveUp: useCallback12(() => setActivitySelectedIdx((i) => Math.max(0, i - 1)), []),
|
|
5341
|
+
moveDown: useCallback12(
|
|
5342
|
+
() => setActivitySelectedIdx((i) => Math.min(Math.max(0, boardTree.activity.length - 1), i + 1)),
|
|
5343
|
+
[boardTree.activity.length]
|
|
5344
|
+
)
|
|
5345
|
+
};
|
|
5346
|
+
const selectedRepoName = selectedSection?.sectionId ?? null;
|
|
5347
|
+
const selectedStatusGroup = selectedSection?.groups[clampedStatusIdx] ?? null;
|
|
5348
|
+
const selectedStatusGroupId = selectedStatusGroup?.subId ?? null;
|
|
5349
|
+
const onRepoEnter = useCallback12(() => {
|
|
5350
|
+
setSelectedStatusIdx(0);
|
|
5351
|
+
panelFocus.focusPanel(3);
|
|
5352
|
+
}, [panelFocus]);
|
|
5353
|
+
const onStatusEnter = useCallback12(() => {
|
|
5354
|
+
panelFocus.focusPanel(3);
|
|
5355
|
+
}, [panelFocus]);
|
|
5356
|
+
const onActivityEnter = useCallback12(() => {
|
|
5357
|
+
const event = boardTree.activity[clampedActivityIdx];
|
|
5358
|
+
if (!event) return;
|
|
5359
|
+
const repoIdx = boardTree.sections.findIndex(
|
|
5360
|
+
(s) => s.repo.shortName === event.repoShortName || s.sectionId.endsWith(`/${event.repoShortName}`)
|
|
5361
|
+
);
|
|
5362
|
+
if (repoIdx >= 0) {
|
|
5363
|
+
setSelectedRepoIdx(repoIdx);
|
|
5364
|
+
setSelectedStatusIdx(0);
|
|
5365
|
+
panelFocus.focusPanel(3);
|
|
5366
|
+
}
|
|
5367
|
+
}, [boardTree, clampedActivityIdx, panelFocus]);
|
|
5230
5368
|
const navItems = useMemo3(
|
|
5231
|
-
() =>
|
|
5232
|
-
[
|
|
5369
|
+
() => buildNavItemsForRepo(boardTree.sections, selectedRepoName, selectedStatusGroupId),
|
|
5370
|
+
[boardTree.sections, selectedRepoName, selectedStatusGroupId]
|
|
5233
5371
|
);
|
|
5234
5372
|
const nav = useNavigation(navItems);
|
|
5235
|
-
const getRepoForId =
|
|
5373
|
+
const getRepoForId = useCallback12((id) => {
|
|
5236
5374
|
if (id.startsWith("gh:")) {
|
|
5237
5375
|
const parts = id.split(":");
|
|
5238
5376
|
return parts.length >= 3 ? `${parts[1]}` : null;
|
|
5239
5377
|
}
|
|
5240
|
-
if (id.startsWith("tt:")) return "ticktick";
|
|
5241
5378
|
return null;
|
|
5242
5379
|
}, []);
|
|
5243
5380
|
const multiSelect = useMultiSelect(getRepoForId);
|
|
@@ -5261,8 +5398,8 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5261
5398
|
const pendingPickRef = useRef13(null);
|
|
5262
5399
|
const labelCacheRef = useRef13({});
|
|
5263
5400
|
const commentCacheRef = useRef13({});
|
|
5264
|
-
const [commentTick, setCommentTick] =
|
|
5265
|
-
const handleFetchComments =
|
|
5401
|
+
const [commentTick, setCommentTick] = useState16(0);
|
|
5402
|
+
const handleFetchComments = useCallback12((repo, issueNumber) => {
|
|
5266
5403
|
const key = `${repo}:${issueNumber}`;
|
|
5267
5404
|
if (commentCacheRef.current[key] !== void 0) return;
|
|
5268
5405
|
commentCacheRef.current[key] = "loading";
|
|
@@ -5275,7 +5412,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5275
5412
|
setCommentTick((t) => t + 1);
|
|
5276
5413
|
});
|
|
5277
5414
|
}, []);
|
|
5278
|
-
const handleCreateIssueWithPrompt =
|
|
5415
|
+
const handleCreateIssueWithPrompt = useCallback12(
|
|
5279
5416
|
(repo, title, body, dueDate, labels) => {
|
|
5280
5417
|
actions.handleCreateIssue(repo, title, body, dueDate, labels).then((result) => {
|
|
5281
5418
|
if (result) {
|
|
@@ -5286,7 +5423,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5286
5423
|
},
|
|
5287
5424
|
[actions, ui]
|
|
5288
5425
|
);
|
|
5289
|
-
const handleConfirmPick =
|
|
5426
|
+
const handleConfirmPick = useCallback12(() => {
|
|
5290
5427
|
const pending = pendingPickRef.current;
|
|
5291
5428
|
pendingPickRef.current = null;
|
|
5292
5429
|
ui.exitOverlay();
|
|
@@ -5304,12 +5441,12 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5304
5441
|
})
|
|
5305
5442
|
);
|
|
5306
5443
|
}, [config2, toast, refresh, ui]);
|
|
5307
|
-
const handleCancelPick =
|
|
5444
|
+
const handleCancelPick = useCallback12(() => {
|
|
5308
5445
|
pendingPickRef.current = null;
|
|
5309
5446
|
ui.exitOverlay();
|
|
5310
5447
|
}, [ui]);
|
|
5311
|
-
const [focusLabel, setFocusLabel] =
|
|
5312
|
-
const handleEnterFocus =
|
|
5448
|
+
const [focusLabel, setFocusLabel] = useState16(null);
|
|
5449
|
+
const handleEnterFocus = useCallback12(() => {
|
|
5313
5450
|
const id = nav.selectedId;
|
|
5314
5451
|
if (!id || isHeaderId(id)) return;
|
|
5315
5452
|
let label = "";
|
|
@@ -5319,20 +5456,16 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5319
5456
|
const rc = config2.repos.find((r) => r.name === found.repoName);
|
|
5320
5457
|
label = `${rc?.shortName ?? found.repoName}#${found.issue.number} \u2014 ${found.issue.title}`;
|
|
5321
5458
|
}
|
|
5322
|
-
} else if (id.startsWith("tt:")) {
|
|
5323
|
-
const taskId = id.slice(3);
|
|
5324
|
-
const task2 = tasks.find((t) => t.id === taskId);
|
|
5325
|
-
if (task2) label = task2.title;
|
|
5326
5459
|
}
|
|
5327
5460
|
if (!label) return;
|
|
5328
5461
|
setFocusLabel(label);
|
|
5329
5462
|
ui.enterFocus();
|
|
5330
|
-
}, [nav.selectedId, repos,
|
|
5331
|
-
const handleFocusExit =
|
|
5463
|
+
}, [nav.selectedId, repos, config2.repos, ui]);
|
|
5464
|
+
const handleFocusExit = useCallback12(() => {
|
|
5332
5465
|
setFocusLabel(null);
|
|
5333
5466
|
ui.exitToNormal();
|
|
5334
5467
|
}, [ui]);
|
|
5335
|
-
const handleFocusEndAction =
|
|
5468
|
+
const handleFocusEndAction = useCallback12(
|
|
5336
5469
|
(action) => {
|
|
5337
5470
|
switch (action) {
|
|
5338
5471
|
case "restart":
|
|
@@ -5358,9 +5491,9 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5358
5491
|
},
|
|
5359
5492
|
[toast, ui]
|
|
5360
5493
|
);
|
|
5361
|
-
const [focusKey, setFocusKey] =
|
|
5494
|
+
const [focusKey, setFocusKey] = useState16(0);
|
|
5362
5495
|
const { stdout } = useStdout();
|
|
5363
|
-
const [termSize, setTermSize] =
|
|
5496
|
+
const [termSize, setTermSize] = useState16({
|
|
5364
5497
|
cols: stdout?.columns ?? 80,
|
|
5365
5498
|
rows: stdout?.rows ?? 24
|
|
5366
5499
|
});
|
|
@@ -5372,69 +5505,59 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5372
5505
|
stdout.off("resize", onResize);
|
|
5373
5506
|
};
|
|
5374
5507
|
}, [stdout]);
|
|
5375
|
-
const
|
|
5376
|
-
const detailPanelWidth =
|
|
5508
|
+
const layoutMode = getLayoutMode(termSize.cols);
|
|
5509
|
+
const detailPanelWidth = layoutMode === "wide" ? getDetailWidth(termSize.cols) : Math.floor(termSize.cols * 0.35);
|
|
5510
|
+
const showDetailPanel = layoutMode === "wide";
|
|
5377
5511
|
const overlayBarRows = ui.state.mode === "search" || ui.state.mode === "overlay:comment" ? 1 : 0;
|
|
5378
5512
|
const toastRows = toasts.length;
|
|
5379
5513
|
const logPaneRows = logVisible ? 4 : 0;
|
|
5380
|
-
const
|
|
5381
|
-
|
|
5514
|
+
const totalPanelHeight = Math.max(
|
|
5515
|
+
8,
|
|
5382
5516
|
termSize.rows - CHROME_ROWS - overlayBarRows - toastRows - logPaneRows
|
|
5383
5517
|
);
|
|
5518
|
+
const issuesPanelHeight = Math.max(5, totalPanelHeight - ACTIVITY_HEIGHT);
|
|
5384
5519
|
const flatRows = useMemo3(
|
|
5385
|
-
() =>
|
|
5386
|
-
[
|
|
5520
|
+
() => buildFlatRowsForRepo(boardTree.sections, selectedRepoName, selectedStatusGroupId),
|
|
5521
|
+
[boardTree.sections, selectedRepoName, selectedStatusGroupId]
|
|
5387
5522
|
);
|
|
5388
5523
|
const scrollRef = useRef13(0);
|
|
5389
|
-
const
|
|
5390
|
-
|
|
5391
|
-
|
|
5524
|
+
const prevRepoRef = useRef13(null);
|
|
5525
|
+
const prevStatusRef = useRef13(null);
|
|
5526
|
+
if (selectedRepoName !== prevRepoRef.current || selectedStatusGroupId !== prevStatusRef.current) {
|
|
5527
|
+
prevRepoRef.current = selectedRepoName;
|
|
5528
|
+
prevStatusRef.current = selectedStatusGroupId;
|
|
5392
5529
|
scrollRef.current = 0;
|
|
5393
5530
|
}
|
|
5394
5531
|
const selectedRowIdx = useMemo3(
|
|
5395
5532
|
() => flatRows.findIndex((r) => r.navId === nav.selectedId),
|
|
5396
5533
|
[flatRows, nav.selectedId]
|
|
5397
5534
|
);
|
|
5398
|
-
const stickyHeader = useMemo3(() => {
|
|
5399
|
-
if (selectedRowIdx < 0) return null;
|
|
5400
|
-
for (let i = selectedRowIdx; i >= 0; i--) {
|
|
5401
|
-
const row = flatRows[i];
|
|
5402
|
-
if (row?.type === "subHeader") return { text: row.text, count: row.count };
|
|
5403
|
-
}
|
|
5404
|
-
return null;
|
|
5405
|
-
}, [flatRows, selectedRowIdx]);
|
|
5406
5535
|
if (selectedRowIdx >= 0) {
|
|
5407
5536
|
if (selectedRowIdx < scrollRef.current) {
|
|
5408
5537
|
scrollRef.current = selectedRowIdx;
|
|
5409
|
-
} else if (selectedRowIdx >= scrollRef.current +
|
|
5410
|
-
scrollRef.current = selectedRowIdx -
|
|
5538
|
+
} else if (selectedRowIdx >= scrollRef.current + issuesPanelHeight) {
|
|
5539
|
+
scrollRef.current = selectedRowIdx - issuesPanelHeight + 1;
|
|
5411
5540
|
}
|
|
5412
5541
|
}
|
|
5413
|
-
const maxOffset = Math.max(0, flatRows.length -
|
|
5542
|
+
const maxOffset = Math.max(0, flatRows.length - issuesPanelHeight);
|
|
5414
5543
|
scrollRef.current = Math.max(0, Math.min(scrollRef.current, maxOffset));
|
|
5415
|
-
const visibleRows = flatRows.slice(scrollRef.current, scrollRef.current +
|
|
5544
|
+
const visibleRows = flatRows.slice(scrollRef.current, scrollRef.current + issuesPanelHeight);
|
|
5416
5545
|
const hasMoreAbove = scrollRef.current > 0;
|
|
5417
|
-
const hasMoreBelow = scrollRef.current +
|
|
5546
|
+
const hasMoreBelow = scrollRef.current + issuesPanelHeight < flatRows.length;
|
|
5418
5547
|
const aboveCount = scrollRef.current;
|
|
5419
|
-
const belowCount = flatRows.length - scrollRef.current -
|
|
5548
|
+
const belowCount = flatRows.length - scrollRef.current - issuesPanelHeight;
|
|
5420
5549
|
const selectedItem = useMemo3(() => {
|
|
5421
5550
|
const id = nav.selectedId;
|
|
5422
|
-
if (!id || isHeaderId(id)) return { issue: null,
|
|
5551
|
+
if (!id || isHeaderId(id)) return { issue: null, repoName: null };
|
|
5423
5552
|
if (id.startsWith("gh:")) {
|
|
5424
5553
|
for (const rd of repos) {
|
|
5425
5554
|
for (const issue of rd.issues) {
|
|
5426
|
-
if (`gh:${rd.repo.name}:${issue.number}` === id)
|
|
5427
|
-
return { issue, task: null, repoName: rd.repo.name };
|
|
5555
|
+
if (`gh:${rd.repo.name}:${issue.number}` === id) return { issue, repoName: rd.repo.name };
|
|
5428
5556
|
}
|
|
5429
5557
|
}
|
|
5430
5558
|
}
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
const task2 = tasks.find((t) => t.id === taskId);
|
|
5434
|
-
if (task2) return { issue: null, task: task2, repoName: null };
|
|
5435
|
-
}
|
|
5436
|
-
return { issue: null, task: null, repoName: null };
|
|
5437
|
-
}, [nav.selectedId, repos, tasks]);
|
|
5559
|
+
return { issue: null, repoName: null };
|
|
5560
|
+
}, [nav.selectedId, repos]);
|
|
5438
5561
|
const currentCommentsState = useMemo3(() => {
|
|
5439
5562
|
if (!(selectedItem.issue && selectedItem.repoName)) return null;
|
|
5440
5563
|
return commentCacheRef.current[`${selectedItem.repoName}:${selectedItem.issue.number}`] ?? null;
|
|
@@ -5445,20 +5568,20 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5445
5568
|
}, [selectedItem.repoName, config2.repos]);
|
|
5446
5569
|
const selectedRepoStatusOptions = useMemo3(() => {
|
|
5447
5570
|
const repoName = multiSelect.count > 0 ? multiSelect.constrainedRepo : selectedItem.repoName;
|
|
5448
|
-
if (!repoName
|
|
5571
|
+
if (!repoName) return [];
|
|
5449
5572
|
const rd = repos.find((r) => r.repo.name === repoName);
|
|
5450
5573
|
return rd?.statusOptions ?? [];
|
|
5451
5574
|
}, [selectedItem.repoName, repos, multiSelect.count, multiSelect.constrainedRepo]);
|
|
5452
|
-
const handleOpen =
|
|
5575
|
+
const handleOpen = useCallback12(() => {
|
|
5453
5576
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
5454
5577
|
if (found) openInBrowser(found.issue.url);
|
|
5455
5578
|
}, [repos, nav.selectedId]);
|
|
5456
|
-
const handleSlack =
|
|
5579
|
+
const handleSlack = useCallback12(() => {
|
|
5457
5580
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
5458
5581
|
if (!found?.issue.slackThreadUrl) return;
|
|
5459
5582
|
openInBrowser(found.issue.slackThreadUrl);
|
|
5460
5583
|
}, [repos, nav.selectedId]);
|
|
5461
|
-
const handleCopyLink =
|
|
5584
|
+
const handleCopyLink = useCallback12(() => {
|
|
5462
5585
|
const found = findSelectedIssueWithRepo(repos, nav.selectedId);
|
|
5463
5586
|
if (!found) return;
|
|
5464
5587
|
const rc = config2.repos.find((r) => r.name === found.repoName);
|
|
@@ -5484,17 +5607,12 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5484
5607
|
}
|
|
5485
5608
|
}, [repos, nav.selectedId, config2.repos, toast]);
|
|
5486
5609
|
const multiSelectType = useMemo3(() => {
|
|
5487
|
-
let hasGh = false;
|
|
5488
|
-
let hasTt = false;
|
|
5489
5610
|
for (const id of multiSelect.selected) {
|
|
5490
|
-
if (id.startsWith("
|
|
5491
|
-
if (id.startsWith("tt:")) hasTt = true;
|
|
5611
|
+
if (id.startsWith("tt:")) return "ticktick";
|
|
5492
5612
|
}
|
|
5493
|
-
if (hasGh && hasTt) return "mixed";
|
|
5494
|
-
if (hasTt) return "ticktick";
|
|
5495
5613
|
return "github";
|
|
5496
5614
|
}, [multiSelect.selected]);
|
|
5497
|
-
const handleBulkAction =
|
|
5615
|
+
const handleBulkAction = useCallback12(
|
|
5498
5616
|
(action) => {
|
|
5499
5617
|
const ids = multiSelect.selected;
|
|
5500
5618
|
switch (action.type) {
|
|
@@ -5527,10 +5645,9 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5527
5645
|
case "statusChange":
|
|
5528
5646
|
ui.enterStatus();
|
|
5529
5647
|
return;
|
|
5530
|
-
// status picker will call handleBulkStatusSelect on select
|
|
5531
5648
|
case "complete":
|
|
5532
5649
|
case "delete":
|
|
5533
|
-
toast.info(`Bulk ${action.type} not yet implemented
|
|
5650
|
+
toast.info(`Bulk ${action.type} not yet implemented`);
|
|
5534
5651
|
ui.exitOverlay();
|
|
5535
5652
|
multiSelect.clear();
|
|
5536
5653
|
return;
|
|
@@ -5538,7 +5655,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5538
5655
|
},
|
|
5539
5656
|
[multiSelect, actions, ui, toast]
|
|
5540
5657
|
);
|
|
5541
|
-
const handleBulkStatusSelect =
|
|
5658
|
+
const handleBulkStatusSelect = useCallback12(
|
|
5542
5659
|
(optionId) => {
|
|
5543
5660
|
const ids = multiSelect.selected;
|
|
5544
5661
|
ui.exitOverlay();
|
|
@@ -5554,20 +5671,28 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5554
5671
|
},
|
|
5555
5672
|
[multiSelect, actions, ui]
|
|
5556
5673
|
);
|
|
5557
|
-
const handleFuzzySelect =
|
|
5674
|
+
const handleFuzzySelect = useCallback12(
|
|
5558
5675
|
(navId) => {
|
|
5559
5676
|
nav.select(navId);
|
|
5560
5677
|
if (navId.startsWith("gh:")) {
|
|
5561
5678
|
const parts = navId.split(":");
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5679
|
+
const repoName = parts[1];
|
|
5680
|
+
if (parts.length >= 3 && repoName) {
|
|
5681
|
+
const repoIdx = boardTree.sections.findIndex((s) => s.sectionId === repoName);
|
|
5682
|
+
if (repoIdx >= 0) {
|
|
5683
|
+
setSelectedRepoIdx(repoIdx);
|
|
5684
|
+
const section = boardTree.sections[repoIdx];
|
|
5685
|
+
const issueNum = parts[2] ? Number(parts[2]) : null;
|
|
5686
|
+
const groupIdx = section?.groups.findIndex((g) => g.issues.some((iss) => iss.number === issueNum)) ?? -1;
|
|
5687
|
+
setSelectedStatusIdx(Math.max(0, groupIdx));
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5565
5690
|
}
|
|
5566
5691
|
ui.exitToNormal();
|
|
5567
5692
|
},
|
|
5568
|
-
[nav, ui]
|
|
5693
|
+
[nav, ui, boardTree]
|
|
5569
5694
|
);
|
|
5570
|
-
const onSearchEscape =
|
|
5695
|
+
const onSearchEscape = useCallback12(() => {
|
|
5571
5696
|
ui.exitOverlay();
|
|
5572
5697
|
setSearchQuery("");
|
|
5573
5698
|
}, [ui]);
|
|
@@ -5597,10 +5722,16 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5597
5722
|
handleToggleLog: () => setLogVisible((v) => !v)
|
|
5598
5723
|
},
|
|
5599
5724
|
onSearchEscape,
|
|
5600
|
-
|
|
5725
|
+
panelFocus,
|
|
5726
|
+
reposNav,
|
|
5727
|
+
statusesNav,
|
|
5728
|
+
activityNav,
|
|
5729
|
+
onRepoEnter,
|
|
5730
|
+
onStatusEnter,
|
|
5731
|
+
onActivityEnter
|
|
5601
5732
|
});
|
|
5602
5733
|
if (status === "loading" && !data) {
|
|
5603
|
-
return /* @__PURE__ */
|
|
5734
|
+
return /* @__PURE__ */ jsx24(Box23, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx24(Spinner4, { label: "Loading dashboard..." }) });
|
|
5604
5735
|
}
|
|
5605
5736
|
const now = data?.fetchedAt ?? /* @__PURE__ */ new Date();
|
|
5606
5737
|
const dateStr = now.toLocaleDateString("en-US", {
|
|
@@ -5608,36 +5739,122 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5608
5739
|
day: "numeric",
|
|
5609
5740
|
year: "numeric"
|
|
5610
5741
|
});
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5742
|
+
const reposData = boardTree.sections.map(({ repo, groups }) => ({
|
|
5743
|
+
name: repo.name,
|
|
5744
|
+
openCount: groups.reduce((s, g) => s + g.issues.length, 0)
|
|
5745
|
+
}));
|
|
5746
|
+
const statusesData = (selectedSection?.groups ?? []).map(({ label, subId, issues }) => ({
|
|
5747
|
+
id: subId,
|
|
5748
|
+
label,
|
|
5749
|
+
count: issues.length
|
|
5750
|
+
}));
|
|
5751
|
+
const reposPanel = /* @__PURE__ */ jsx24(
|
|
5752
|
+
ReposPanel,
|
|
5753
|
+
{
|
|
5754
|
+
repos: reposData,
|
|
5755
|
+
selectedIdx: clampedRepoIdx,
|
|
5756
|
+
isActive: panelFocus.activePanelId === 1
|
|
5757
|
+
}
|
|
5758
|
+
);
|
|
5759
|
+
const statusesPanel = /* @__PURE__ */ jsx24(
|
|
5760
|
+
StatusesPanel,
|
|
5761
|
+
{
|
|
5762
|
+
groups: statusesData,
|
|
5763
|
+
selectedIdx: clampedStatusIdx,
|
|
5764
|
+
isActive: panelFocus.activePanelId === 2
|
|
5765
|
+
}
|
|
5766
|
+
);
|
|
5767
|
+
const issuesBorderColor = panelFocus.activePanelId === 3 ? "cyan" : "gray";
|
|
5768
|
+
const issuesPanel = /* @__PURE__ */ jsxs24(
|
|
5769
|
+
Box23,
|
|
5770
|
+
{
|
|
5771
|
+
borderStyle: "single",
|
|
5772
|
+
borderColor: issuesBorderColor,
|
|
5773
|
+
flexDirection: "column",
|
|
5774
|
+
flexGrow: 1,
|
|
5775
|
+
overflow: "hidden",
|
|
5776
|
+
children: [
|
|
5777
|
+
/* @__PURE__ */ jsxs24(Text22, { bold: true, color: panelFocus.activePanelId === 3 ? "cyan" : "white", children: [
|
|
5778
|
+
"[3] Issues",
|
|
5779
|
+
selectedSection ? ` \u2014 ${selectedSection.repo.shortName}` : "",
|
|
5780
|
+
selectedStatusGroup ? ` / ${selectedStatusGroup.label}` : ""
|
|
5781
|
+
] }),
|
|
5782
|
+
hasMoreAbove ? /* @__PURE__ */ jsxs24(Text22, { color: "gray", dimColor: true, children: [
|
|
5783
|
+
" ",
|
|
5784
|
+
"\u25B2",
|
|
5785
|
+
" ",
|
|
5786
|
+
aboveCount,
|
|
5787
|
+
" more above"
|
|
5788
|
+
] }) : null,
|
|
5789
|
+
visibleRows.map((row) => /* @__PURE__ */ jsx24(
|
|
5790
|
+
RowRenderer,
|
|
5791
|
+
{
|
|
5792
|
+
row,
|
|
5793
|
+
selectedId: nav.selectedId,
|
|
5794
|
+
selfLogin: config2.board.assignee,
|
|
5795
|
+
isMultiSelected: ui.state.mode === "multiSelect" && row.navId ? multiSelect.isSelected(row.navId) : void 0
|
|
5796
|
+
},
|
|
5797
|
+
row.key
|
|
5798
|
+
)),
|
|
5799
|
+
hasMoreBelow ? /* @__PURE__ */ jsxs24(Text22, { color: "gray", dimColor: true, children: [
|
|
5800
|
+
" ",
|
|
5801
|
+
"\u25BC",
|
|
5802
|
+
" ",
|
|
5803
|
+
belowCount,
|
|
5804
|
+
" more below"
|
|
5805
|
+
] }) : null
|
|
5806
|
+
]
|
|
5807
|
+
}
|
|
5808
|
+
);
|
|
5809
|
+
const detailPanel = showDetailPanel ? /* @__PURE__ */ jsx24(
|
|
5810
|
+
DetailPanel,
|
|
5811
|
+
{
|
|
5812
|
+
issue: selectedItem.issue,
|
|
5813
|
+
width: detailPanelWidth,
|
|
5814
|
+
isActive: panelFocus.activePanelId === 0,
|
|
5815
|
+
issueRepo: selectedItem.repoName,
|
|
5816
|
+
fetchComments: handleFetchComments,
|
|
5817
|
+
commentsState: currentCommentsState
|
|
5818
|
+
}
|
|
5819
|
+
) : null;
|
|
5820
|
+
const activityPanel = /* @__PURE__ */ jsx24(
|
|
5821
|
+
ActivityPanel,
|
|
5822
|
+
{
|
|
5823
|
+
events: boardTree.activity,
|
|
5824
|
+
selectedIdx: clampedActivityIdx,
|
|
5825
|
+
isActive: panelFocus.activePanelId === 4,
|
|
5826
|
+
height: ACTIVITY_HEIGHT
|
|
5827
|
+
}
|
|
5828
|
+
);
|
|
5829
|
+
return /* @__PURE__ */ jsxs24(Box23, { flexDirection: "column", paddingX: 1, children: [
|
|
5830
|
+
/* @__PURE__ */ jsxs24(Box23, { children: [
|
|
5831
|
+
/* @__PURE__ */ jsx24(Text22, { color: "cyan", bold: true, children: "HOG BOARD" }),
|
|
5832
|
+
activeProfile ? /* @__PURE__ */ jsxs24(Text22, { color: "yellow", children: [
|
|
5615
5833
|
" [",
|
|
5616
5834
|
activeProfile,
|
|
5617
5835
|
"]"
|
|
5618
5836
|
] }) : null,
|
|
5619
|
-
/* @__PURE__ */
|
|
5837
|
+
/* @__PURE__ */ jsxs24(Text22, { color: "gray", children: [
|
|
5620
5838
|
" ",
|
|
5621
5839
|
"\u2014",
|
|
5622
5840
|
" ",
|
|
5623
5841
|
dateStr
|
|
5624
5842
|
] }),
|
|
5625
|
-
/* @__PURE__ */
|
|
5626
|
-
isRefreshing ? /* @__PURE__ */
|
|
5627
|
-
/* @__PURE__ */
|
|
5628
|
-
/* @__PURE__ */
|
|
5629
|
-
] }) : /* @__PURE__ */
|
|
5630
|
-
/* @__PURE__ */
|
|
5631
|
-
consecutiveFailures > 0 ? /* @__PURE__ */
|
|
5843
|
+
/* @__PURE__ */ jsx24(Text22, { children: " " }),
|
|
5844
|
+
isRefreshing ? /* @__PURE__ */ jsxs24(Fragment5, { children: [
|
|
5845
|
+
/* @__PURE__ */ jsx24(Spinner4, { label: "" }),
|
|
5846
|
+
/* @__PURE__ */ jsx24(Text22, { color: "cyan", children: " Refreshing..." })
|
|
5847
|
+
] }) : /* @__PURE__ */ jsxs24(Fragment5, { children: [
|
|
5848
|
+
/* @__PURE__ */ jsx24(RefreshAge, { lastRefresh }),
|
|
5849
|
+
consecutiveFailures > 0 ? /* @__PURE__ */ jsx24(Text22, { color: "red", children: " (!)" }) : null
|
|
5632
5850
|
] }),
|
|
5633
|
-
autoRefreshPaused ? /* @__PURE__ */
|
|
5851
|
+
autoRefreshPaused ? /* @__PURE__ */ jsx24(Text22, { color: "yellow", children: " Auto-refresh paused \u2014 press r to retry" }) : null
|
|
5634
5852
|
] }),
|
|
5635
|
-
error ? /* @__PURE__ */
|
|
5853
|
+
error ? /* @__PURE__ */ jsxs24(Text22, { color: "red", children: [
|
|
5636
5854
|
"Error: ",
|
|
5637
5855
|
error
|
|
5638
5856
|
] }) : null,
|
|
5639
|
-
/* @__PURE__ */
|
|
5640
|
-
/* @__PURE__ */ jsx22(
|
|
5857
|
+
/* @__PURE__ */ jsx24(
|
|
5641
5858
|
OverlayRenderer,
|
|
5642
5859
|
{
|
|
5643
5860
|
uiState: ui.state,
|
|
@@ -5679,64 +5896,25 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5679
5896
|
onPushEntry: pushEntry
|
|
5680
5897
|
}
|
|
5681
5898
|
),
|
|
5682
|
-
!ui.state.helpVisible && ui.state.mode !== "overlay:status" && ui.state.mode !== "overlay:create" && ui.state.mode !== "overlay:createNl" && ui.state.mode !== "overlay:bulkAction" && ui.state.mode !== "overlay:confirmPick" && ui.state.mode !== "focus" ? /* @__PURE__ */
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5697
|
-
" ",
|
|
5698
|
-
"\u25B2",
|
|
5699
|
-
" ",
|
|
5700
|
-
aboveCount,
|
|
5701
|
-
" more above"
|
|
5702
|
-
] }) : null,
|
|
5703
|
-
visibleRows.map((row) => /* @__PURE__ */ jsx22(
|
|
5704
|
-
RowRenderer,
|
|
5705
|
-
{
|
|
5706
|
-
row,
|
|
5707
|
-
selectedId: nav.selectedId,
|
|
5708
|
-
selfLogin: config2.board.assignee,
|
|
5709
|
-
isMultiSelected: ui.state.mode === "multiSelect" && row.navId ? multiSelect.isSelected(row.navId) : void 0
|
|
5710
|
-
},
|
|
5711
|
-
row.key
|
|
5712
|
-
)),
|
|
5713
|
-
hasMoreBelow ? /* @__PURE__ */ jsxs22(Text21, { color: "gray", dimColor: true, children: [
|
|
5714
|
-
" ",
|
|
5715
|
-
"\u25BC",
|
|
5716
|
-
" ",
|
|
5717
|
-
belowCount,
|
|
5718
|
-
" more below"
|
|
5719
|
-
] }) : null
|
|
5720
|
-
] }),
|
|
5721
|
-
showDetailPanel ? /* @__PURE__ */ jsx22(Box21, { marginLeft: 1, width: detailPanelWidth, children: /* @__PURE__ */ jsx22(
|
|
5722
|
-
DetailPanel,
|
|
5723
|
-
{
|
|
5724
|
-
issue: selectedItem.issue,
|
|
5725
|
-
task: selectedItem.task,
|
|
5726
|
-
width: detailPanelWidth,
|
|
5727
|
-
issueRepo: selectedItem.repoName,
|
|
5728
|
-
fetchComments: handleFetchComments,
|
|
5729
|
-
commentsState: currentCommentsState
|
|
5730
|
-
}
|
|
5731
|
-
) }) : null
|
|
5732
|
-
] })
|
|
5733
|
-
] }) : null,
|
|
5734
|
-
/* @__PURE__ */ jsx22(ToastContainer, { toasts }),
|
|
5735
|
-
logVisible ? /* @__PURE__ */ jsx22(ActionLog, { entries: logEntries }) : null,
|
|
5736
|
-
/* @__PURE__ */ jsx22(
|
|
5899
|
+
!ui.state.helpVisible && ui.state.mode !== "overlay:status" && ui.state.mode !== "overlay:create" && ui.state.mode !== "overlay:createNl" && ui.state.mode !== "overlay:bulkAction" && ui.state.mode !== "overlay:confirmPick" && ui.state.mode !== "focus" ? /* @__PURE__ */ jsx24(
|
|
5900
|
+
PanelLayout,
|
|
5901
|
+
{
|
|
5902
|
+
cols: termSize.cols,
|
|
5903
|
+
issuesPanelHeight,
|
|
5904
|
+
reposPanel,
|
|
5905
|
+
statusesPanel,
|
|
5906
|
+
issuesPanel,
|
|
5907
|
+
detailPanel,
|
|
5908
|
+
activityPanel
|
|
5909
|
+
}
|
|
5910
|
+
) : null,
|
|
5911
|
+
/* @__PURE__ */ jsx24(ToastContainer, { toasts }),
|
|
5912
|
+
logVisible ? /* @__PURE__ */ jsx24(ActionLog, { entries: logEntries }) : null,
|
|
5913
|
+
/* @__PURE__ */ jsx24(
|
|
5737
5914
|
HintBar,
|
|
5738
5915
|
{
|
|
5739
5916
|
uiMode: ui.state.mode,
|
|
5917
|
+
activePanelId: panelFocus.activePanelId,
|
|
5740
5918
|
multiSelectCount: multiSelect.count,
|
|
5741
5919
|
searchQuery,
|
|
5742
5920
|
mineOnly,
|
|
@@ -5758,14 +5936,18 @@ var init_dashboard = __esm({
|
|
|
5758
5936
|
init_use_keyboard();
|
|
5759
5937
|
init_use_multi_select();
|
|
5760
5938
|
init_use_navigation();
|
|
5939
|
+
init_use_panel_focus();
|
|
5761
5940
|
init_use_toast();
|
|
5762
5941
|
init_use_ui_state();
|
|
5763
5942
|
init_action_log();
|
|
5943
|
+
init_activity_panel();
|
|
5764
5944
|
init_detail_panel();
|
|
5765
5945
|
init_hint_bar();
|
|
5766
5946
|
init_overlay_renderer();
|
|
5947
|
+
init_panel_layout();
|
|
5948
|
+
init_repos_panel();
|
|
5767
5949
|
init_row_renderer();
|
|
5768
|
-
|
|
5950
|
+
init_statuses_panel();
|
|
5769
5951
|
init_toast_container();
|
|
5770
5952
|
PRIORITY_RANK = {
|
|
5771
5953
|
"priority:critical": 0,
|
|
@@ -5773,7 +5955,7 @@ var init_dashboard = __esm({
|
|
|
5773
5955
|
"priority:medium": 2,
|
|
5774
5956
|
"priority:low": 3
|
|
5775
5957
|
};
|
|
5776
|
-
CHROME_ROWS =
|
|
5958
|
+
CHROME_ROWS = 3;
|
|
5777
5959
|
}
|
|
5778
5960
|
});
|
|
5779
5961
|
|
|
@@ -5783,10 +5965,10 @@ __export(live_exports, {
|
|
|
5783
5965
|
runLiveDashboard: () => runLiveDashboard
|
|
5784
5966
|
});
|
|
5785
5967
|
import { render } from "ink";
|
|
5786
|
-
import { jsx as
|
|
5968
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
5787
5969
|
async function runLiveDashboard(config2, options, activeProfile) {
|
|
5788
5970
|
const instance = render(
|
|
5789
|
-
/* @__PURE__ */
|
|
5971
|
+
/* @__PURE__ */ jsx25(Dashboard, { config: config2, options, activeProfile: activeProfile ?? null })
|
|
5790
5972
|
);
|
|
5791
5973
|
setInkInstance(instance);
|
|
5792
5974
|
await instance.waitUntilExit();
|
|
@@ -5813,7 +5995,7 @@ function extractSlackUrl(body) {
|
|
|
5813
5995
|
const match = body.match(SLACK_URL_RE2);
|
|
5814
5996
|
return match?.[0];
|
|
5815
5997
|
}
|
|
5816
|
-
function fetchRecentActivity(repoName,
|
|
5998
|
+
function fetchRecentActivity(repoName, shortName2) {
|
|
5817
5999
|
try {
|
|
5818
6000
|
const output = execFileSync4(
|
|
5819
6001
|
"gh",
|
|
@@ -5867,7 +6049,7 @@ function fetchRecentActivity(repoName, shortName) {
|
|
|
5867
6049
|
}
|
|
5868
6050
|
events.push({
|
|
5869
6051
|
type: eventType,
|
|
5870
|
-
repoShortName:
|
|
6052
|
+
repoShortName: shortName2,
|
|
5871
6053
|
issueNumber: ev.number,
|
|
5872
6054
|
actor: ev.actor,
|
|
5873
6055
|
summary,
|
|
@@ -6009,7 +6191,7 @@ __export(format_static_exports, {
|
|
|
6009
6191
|
renderBoardJson: () => renderBoardJson,
|
|
6010
6192
|
renderStaticBoard: () => renderStaticBoard
|
|
6011
6193
|
});
|
|
6012
|
-
function
|
|
6194
|
+
function truncate2(s, max) {
|
|
6013
6195
|
return s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
|
|
6014
6196
|
}
|
|
6015
6197
|
function issueAssignee(issue, selfLogin) {
|
|
@@ -6022,13 +6204,13 @@ function issueAssignee(issue, selfLogin) {
|
|
|
6022
6204
|
}
|
|
6023
6205
|
function formatIssueLine(issue, selfLogin, maxTitle) {
|
|
6024
6206
|
const num = theme.text.accent(`#${String(issue.number).padEnd(5)}`);
|
|
6025
|
-
const title =
|
|
6207
|
+
const title = truncate2(issue.title, maxTitle);
|
|
6026
6208
|
const assignee = issueAssignee(issue, selfLogin);
|
|
6027
6209
|
return ` ${num} ${title.padEnd(maxTitle)} ${assignee}`;
|
|
6028
6210
|
}
|
|
6029
6211
|
function formatTaskLine(task2, maxTitle) {
|
|
6030
6212
|
const pri = task2.priority === 5 /* High */ ? theme.priority.high("[!]") : task2.priority === 3 /* Medium */ ? theme.priority.medium("[~]") : " ";
|
|
6031
|
-
const title =
|
|
6213
|
+
const title = truncate2(task2.title, maxTitle);
|
|
6032
6214
|
const due = task2.dueDate ? formatDueDate(task2.dueDate) : "";
|
|
6033
6215
|
return ` ${pri} ${title.padEnd(maxTitle)} ${theme.text.secondary(due)}`;
|
|
6034
6216
|
}
|
|
@@ -6449,13 +6631,13 @@ Configuring ${repoName}...`);
|
|
|
6449
6631
|
} else {
|
|
6450
6632
|
completionAction = { type: "closeIssue" };
|
|
6451
6633
|
}
|
|
6452
|
-
const
|
|
6634
|
+
const shortName2 = await input({
|
|
6453
6635
|
message: ` Short name for ${repoName}:`,
|
|
6454
6636
|
default: name
|
|
6455
6637
|
});
|
|
6456
6638
|
repos.push({
|
|
6457
6639
|
name: repoName,
|
|
6458
|
-
shortName,
|
|
6640
|
+
shortName: shortName2,
|
|
6459
6641
|
projectNumber,
|
|
6460
6642
|
statusFieldId,
|
|
6461
6643
|
...dueDateFieldId ? { dueDateFieldId } : {},
|
|
@@ -6949,7 +7131,7 @@ function resolveProjectId(projectId) {
|
|
|
6949
7131
|
process.exit(1);
|
|
6950
7132
|
}
|
|
6951
7133
|
var program = new Command();
|
|
6952
|
-
program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.
|
|
7134
|
+
program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.11.0").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
|
|
6953
7135
|
const opts = thisCommand.opts();
|
|
6954
7136
|
if (opts.json) setFormat("json");
|
|
6955
7137
|
if (opts.human) setFormat("human");
|
|
@@ -7144,7 +7326,7 @@ config.command("repos:add <name>").description("Add a repository to track (owner
|
|
|
7144
7326
|
console.error(`Repo "${name}" is already configured.`);
|
|
7145
7327
|
process.exit(1);
|
|
7146
7328
|
}
|
|
7147
|
-
const
|
|
7329
|
+
const shortName2 = name.split("/")[1] ?? name;
|
|
7148
7330
|
let completionAction;
|
|
7149
7331
|
switch (opts.completionType) {
|
|
7150
7332
|
case "addLabel":
|
|
@@ -7172,7 +7354,7 @@ config.command("repos:add <name>").description("Add a repository to track (owner
|
|
|
7172
7354
|
}
|
|
7173
7355
|
const newRepo = {
|
|
7174
7356
|
name,
|
|
7175
|
-
shortName,
|
|
7357
|
+
shortName: shortName2,
|
|
7176
7358
|
projectNumber: Number.parseInt(opts.projectNumber, 10),
|
|
7177
7359
|
statusFieldId: opts.statusFieldId,
|
|
7178
7360
|
completionAction
|
|
@@ -7182,7 +7364,7 @@ config.command("repos:add <name>").description("Add a repository to track (owner
|
|
|
7182
7364
|
if (useJson()) {
|
|
7183
7365
|
jsonOut({ ok: true, message: `Added ${name}`, data: newRepo });
|
|
7184
7366
|
} else {
|
|
7185
|
-
console.log(`Added ${
|
|
7367
|
+
console.log(`Added ${shortName2} \u2192 ${name}`);
|
|
7186
7368
|
}
|
|
7187
7369
|
});
|
|
7188
7370
|
config.command("repos:rm <name>").description("Remove a repository from tracking").action((name) => {
|