@ondrej-svec/hog 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +223 -258
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1998,7 +1998,8 @@ function useKeyboard({
|
|
|
1998
1998
|
selectedIssue,
|
|
1999
1999
|
selectedRepoStatusOptionsLength,
|
|
2000
2000
|
actions,
|
|
2001
|
-
onSearchEscape
|
|
2001
|
+
onSearchEscape,
|
|
2002
|
+
tabNav
|
|
2002
2003
|
}) {
|
|
2003
2004
|
const {
|
|
2004
2005
|
exit,
|
|
@@ -2046,14 +2047,14 @@ function useKeyboard({
|
|
|
2046
2047
|
multiSelect.clear();
|
|
2047
2048
|
ui.clearMultiSelect();
|
|
2048
2049
|
}
|
|
2049
|
-
key.shift ?
|
|
2050
|
+
key.shift ? tabNav.prev() : tabNav.next();
|
|
2050
2051
|
return;
|
|
2051
2052
|
}
|
|
2052
2053
|
}
|
|
2053
2054
|
if (ui.state.mode === "multiSelect") {
|
|
2054
2055
|
if (input2 === " ") {
|
|
2055
2056
|
const id = nav.selectedId;
|
|
2056
|
-
if (id
|
|
2057
|
+
if (id) {
|
|
2057
2058
|
multiSelect.toggle(id);
|
|
2058
2059
|
}
|
|
2059
2060
|
return;
|
|
@@ -2075,6 +2076,11 @@ function useKeyboard({
|
|
|
2075
2076
|
}
|
|
2076
2077
|
if (input2 === "r" && handleErrorAction("retry")) return;
|
|
2077
2078
|
if (ui.canAct) {
|
|
2079
|
+
const digit = parseInt(input2, 10);
|
|
2080
|
+
if (!Number.isNaN(digit) && digit >= 1 && digit <= tabNav.count) {
|
|
2081
|
+
tabNav.jumpTo(digit - 1);
|
|
2082
|
+
return;
|
|
2083
|
+
}
|
|
2078
2084
|
if (input2 === "/") {
|
|
2079
2085
|
multiSelect.clear();
|
|
2080
2086
|
ui.enterSearch();
|
|
@@ -2138,10 +2144,6 @@ function useKeyboard({
|
|
|
2138
2144
|
handleEnterFocus();
|
|
2139
2145
|
return;
|
|
2140
2146
|
}
|
|
2141
|
-
if (input2 === "C") {
|
|
2142
|
-
nav.collapseAll();
|
|
2143
|
-
return;
|
|
2144
|
-
}
|
|
2145
2147
|
if (input2 === "l") {
|
|
2146
2148
|
if (selectedIssue) {
|
|
2147
2149
|
multiSelect.clear();
|
|
@@ -2169,19 +2171,13 @@ function useKeyboard({
|
|
|
2169
2171
|
}
|
|
2170
2172
|
if (input2 === " ") {
|
|
2171
2173
|
const id = nav.selectedId;
|
|
2172
|
-
if (id
|
|
2174
|
+
if (id) {
|
|
2173
2175
|
multiSelect.toggle(id);
|
|
2174
2176
|
ui.enterMultiSelect();
|
|
2175
|
-
} else if (isHeaderId(nav.selectedId)) {
|
|
2176
|
-
nav.toggleSection();
|
|
2177
2177
|
}
|
|
2178
2178
|
return;
|
|
2179
2179
|
}
|
|
2180
2180
|
if (key.return) {
|
|
2181
|
-
if (isHeaderId(nav.selectedId)) {
|
|
2182
|
-
nav.toggleSection();
|
|
2183
|
-
return;
|
|
2184
|
-
}
|
|
2185
2181
|
handleOpen();
|
|
2186
2182
|
return;
|
|
2187
2183
|
}
|
|
@@ -2190,6 +2186,7 @@ function useKeyboard({
|
|
|
2190
2186
|
[
|
|
2191
2187
|
ui,
|
|
2192
2188
|
nav,
|
|
2189
|
+
tabNav,
|
|
2193
2190
|
exit,
|
|
2194
2191
|
refresh,
|
|
2195
2192
|
handleSlack,
|
|
@@ -2228,7 +2225,6 @@ function useKeyboard({
|
|
|
2228
2225
|
var init_use_keyboard = __esm({
|
|
2229
2226
|
"src/board/hooks/use-keyboard.ts"() {
|
|
2230
2227
|
"use strict";
|
|
2231
|
-
init_constants();
|
|
2232
2228
|
}
|
|
2233
2229
|
});
|
|
2234
2230
|
|
|
@@ -2337,7 +2333,16 @@ function navReducer(state, action) {
|
|
|
2337
2333
|
case "SET_ITEMS": {
|
|
2338
2334
|
const sections = [...new Set(action.items.map((i) => i.section))];
|
|
2339
2335
|
const isFirstLoad = state.sections.length === 0;
|
|
2340
|
-
|
|
2336
|
+
let collapsedSections;
|
|
2337
|
+
if (isFirstLoad) {
|
|
2338
|
+
collapsedSections = new Set(sections.filter((s) => s === "activity"));
|
|
2339
|
+
} else {
|
|
2340
|
+
const validIds = /* @__PURE__ */ new Set([
|
|
2341
|
+
...sections,
|
|
2342
|
+
...action.items.filter((i) => i.type === "subHeader").map((i) => i.id)
|
|
2343
|
+
]);
|
|
2344
|
+
collapsedSections = new Set([...state.collapsedSections].filter((id) => validIds.has(id)));
|
|
2345
|
+
}
|
|
2341
2346
|
const selectionValid = state.selectedId != null && action.items.some((i) => i.id === state.selectedId);
|
|
2342
2347
|
if (!isFirstLoad && selectionValid && arraysEqual(sections, state.sections)) {
|
|
2343
2348
|
return state.allItems === action.items ? state : { ...state, allItems: action.items };
|
|
@@ -2980,14 +2985,7 @@ var init_detail_panel = __esm({
|
|
|
2980
2985
|
// src/board/components/hint-bar.tsx
|
|
2981
2986
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
2982
2987
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
2983
|
-
function HintBar({
|
|
2984
|
-
uiMode,
|
|
2985
|
-
multiSelectCount,
|
|
2986
|
-
searchQuery,
|
|
2987
|
-
mineOnly,
|
|
2988
|
-
hasUndoable,
|
|
2989
|
-
onHeader
|
|
2990
|
-
}) {
|
|
2988
|
+
function HintBar({ uiMode, multiSelectCount, searchQuery, mineOnly, hasUndoable }) {
|
|
2991
2989
|
if (uiMode === "multiSelect") {
|
|
2992
2990
|
return /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
2993
2991
|
/* @__PURE__ */ jsxs3(Text3, { color: "cyan", bold: true, children: [
|
|
@@ -3018,20 +3016,9 @@ function HintBar({
|
|
|
3018
3016
|
if (uiMode.startsWith("overlay:")) {
|
|
3019
3017
|
return /* @__PURE__ */ jsx3(Box3, { children: /* @__PURE__ */ jsx3(Text3, { color: "gray", children: "j/k:nav Enter:select Esc:cancel" }) });
|
|
3020
3018
|
}
|
|
3021
|
-
if (onHeader) {
|
|
3022
|
-
return /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
3023
|
-
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "j/k:nav Enter/Space:expand-collapse Tab:next-section C:collapse-all ?:more q:quit" }),
|
|
3024
|
-
mineOnly ? /* @__PURE__ */ jsx3(Text3, { color: "cyan", children: " filter:@me" }) : null,
|
|
3025
|
-
searchQuery ? /* @__PURE__ */ jsxs3(Text3, { color: "yellow", children: [
|
|
3026
|
-
' filter:"',
|
|
3027
|
-
searchQuery,
|
|
3028
|
-
'"'
|
|
3029
|
-
] }) : null
|
|
3030
|
-
] });
|
|
3031
|
-
}
|
|
3032
3019
|
return /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
3033
3020
|
/* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
3034
|
-
"j/k:nav Enter:open m:status c:comment F:find t:@me e:edit
|
|
3021
|
+
"j/k:nav Tab:next-tab 1-9:jump Enter:open m:status c:comment F:find t:@me e:edit",
|
|
3035
3022
|
hasUndoable ? " u:undo" : "",
|
|
3036
3023
|
" ?:more q:quit"
|
|
3037
3024
|
] }),
|
|
@@ -4080,15 +4067,16 @@ var init_help_overlay = __esm({
|
|
|
4080
4067
|
items: [
|
|
4081
4068
|
{ key: "j / Down", desc: "Move down" },
|
|
4082
4069
|
{ key: "k / Up", desc: "Move up" },
|
|
4083
|
-
{ key: "Tab", desc: "Next
|
|
4084
|
-
{ key: "Shift+Tab", desc: "Previous
|
|
4070
|
+
{ key: "Tab", desc: "Next tab" },
|
|
4071
|
+
{ key: "Shift+Tab", desc: "Previous tab" },
|
|
4072
|
+
{ key: "1-9", desc: "Jump to tab by number" }
|
|
4085
4073
|
]
|
|
4086
4074
|
},
|
|
4087
4075
|
{
|
|
4088
4076
|
category: "View",
|
|
4089
4077
|
items: [
|
|
4090
|
-
{ key: "Enter", desc: "
|
|
4091
|
-
{ key: "Space", desc: "
|
|
4078
|
+
{ key: "Enter", desc: "Open issue in browser" },
|
|
4079
|
+
{ key: "Space", desc: "Multi-select item" },
|
|
4092
4080
|
{ key: "/", desc: "Search (inline filter)" },
|
|
4093
4081
|
{ key: "F", desc: "Fuzzy find issue (telescope-style)" },
|
|
4094
4082
|
{ key: "t", desc: "Toggle @me filter (my issues only)" },
|
|
@@ -4117,7 +4105,6 @@ var init_help_overlay = __esm({
|
|
|
4117
4105
|
category: "Board",
|
|
4118
4106
|
items: [
|
|
4119
4107
|
{ key: "L", desc: "Toggle action log" },
|
|
4120
|
-
{ key: "C", desc: "Collapse all sections" },
|
|
4121
4108
|
{ key: "r", desc: "Refresh data" },
|
|
4122
4109
|
{ key: "q", desc: "Quit" }
|
|
4123
4110
|
]
|
|
@@ -4910,23 +4897,45 @@ var init_row_renderer = __esm({
|
|
|
4910
4897
|
}
|
|
4911
4898
|
});
|
|
4912
4899
|
|
|
4900
|
+
// src/board/components/tab-bar.tsx
|
|
4901
|
+
import { Box as Box19, Text as Text19 } from "ink";
|
|
4902
|
+
import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
4903
|
+
function TabBar({ tabs, activeTabId, totalWidth }) {
|
|
4904
|
+
return /* @__PURE__ */ jsx20(Box19, { width: totalWidth, children: tabs.map((tab, i) => {
|
|
4905
|
+
const isActive = tab.id === activeTabId;
|
|
4906
|
+
return /* @__PURE__ */ jsx20(Box19, { marginRight: 2, children: /* @__PURE__ */ jsxs20(Text19, { bold: isActive, color: isActive ? "cyan" : "gray", children: [
|
|
4907
|
+
i + 1,
|
|
4908
|
+
":",
|
|
4909
|
+
tab.label,
|
|
4910
|
+
" (",
|
|
4911
|
+
tab.count,
|
|
4912
|
+
")"
|
|
4913
|
+
] }) }, tab.id);
|
|
4914
|
+
}) });
|
|
4915
|
+
}
|
|
4916
|
+
var init_tab_bar = __esm({
|
|
4917
|
+
"src/board/components/tab-bar.tsx"() {
|
|
4918
|
+
"use strict";
|
|
4919
|
+
}
|
|
4920
|
+
});
|
|
4921
|
+
|
|
4913
4922
|
// src/board/components/toast-container.tsx
|
|
4914
4923
|
import { Spinner as Spinner3 } from "@inkjs/ui";
|
|
4915
|
-
import { Box as
|
|
4916
|
-
import { Fragment as Fragment4, jsx as
|
|
4924
|
+
import { Box as Box20, Text as Text20 } from "ink";
|
|
4925
|
+
import { Fragment as Fragment4, jsx as jsx21, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
4917
4926
|
function ToastContainer({ toasts }) {
|
|
4918
4927
|
if (toasts.length === 0) return null;
|
|
4919
|
-
return /* @__PURE__ */
|
|
4920
|
-
/* @__PURE__ */
|
|
4921
|
-
/* @__PURE__ */
|
|
4928
|
+
return /* @__PURE__ */ jsx21(Box20, { flexDirection: "column", children: toasts.map((t) => /* @__PURE__ */ jsx21(Box20, { children: t.type === "loading" ? /* @__PURE__ */ jsxs21(Fragment4, { children: [
|
|
4929
|
+
/* @__PURE__ */ jsx21(Spinner3, { label: "" }),
|
|
4930
|
+
/* @__PURE__ */ jsxs21(Text20, { color: "cyan", children: [
|
|
4922
4931
|
" ",
|
|
4923
4932
|
t.message
|
|
4924
4933
|
] })
|
|
4925
|
-
] }) : /* @__PURE__ */
|
|
4934
|
+
] }) : /* @__PURE__ */ jsxs21(Text20, { color: TYPE_COLORS[t.type], children: [
|
|
4926
4935
|
TYPE_PREFIXES[t.type],
|
|
4927
4936
|
" ",
|
|
4928
4937
|
t.message,
|
|
4929
|
-
t.type === "error" ? /* @__PURE__ */
|
|
4938
|
+
t.type === "error" ? /* @__PURE__ */ jsx21(Text20, { color: "gray", children: t.retry ? " [r]etry [d]ismiss" : " [d]ismiss" }) : null
|
|
4930
4939
|
] }) }, t.id)) });
|
|
4931
4940
|
}
|
|
4932
4941
|
var TYPE_COLORS, TYPE_PREFIXES;
|
|
@@ -4950,9 +4959,9 @@ var init_toast_container = __esm({
|
|
|
4950
4959
|
// src/board/components/dashboard.tsx
|
|
4951
4960
|
import { execFileSync as execFileSync3, spawnSync as spawnSync4 } from "child_process";
|
|
4952
4961
|
import { Spinner as Spinner4 } from "@inkjs/ui";
|
|
4953
|
-
import { Box as
|
|
4962
|
+
import { Box as Box21, Text as Text21, useApp, useStdout } from "ink";
|
|
4954
4963
|
import { useCallback as useCallback11, useEffect as useEffect9, useMemo as useMemo3, useRef as useRef13, useState as useState15 } from "react";
|
|
4955
|
-
import { Fragment as Fragment5, jsx as
|
|
4964
|
+
import { Fragment as Fragment5, jsx as jsx22, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
4956
4965
|
function resolveStatusGroups(statusOptions, configuredGroups) {
|
|
4957
4966
|
if (configuredGroups && configuredGroups.length > 0) {
|
|
4958
4967
|
return configuredGroups.map((entry) => {
|
|
@@ -4990,187 +4999,112 @@ function groupByStatus(issues) {
|
|
|
4990
4999
|
}
|
|
4991
5000
|
return groups;
|
|
4992
5001
|
}
|
|
4993
|
-
function
|
|
4994
|
-
const
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
issues.sort((a, b) => issuePriorityRank(a) - issuePriorityRank(b));
|
|
5000
|
-
return issues;
|
|
5001
|
-
}
|
|
5002
|
-
function buildNavItems(repos, tasks, activityCount) {
|
|
5003
|
-
const items = [];
|
|
5004
|
-
if (activityCount > 0) {
|
|
5005
|
-
items.push({ id: "header:activity", section: "activity", type: "header" });
|
|
5006
|
-
}
|
|
5007
|
-
for (const rd of repos) {
|
|
5008
|
-
items.push({ id: `header:${rd.repo.shortName}`, section: rd.repo.shortName, type: "header" });
|
|
5002
|
+
function buildBoardTree(repos, tasks, activity) {
|
|
5003
|
+
const sections = repos.map((rd) => {
|
|
5004
|
+
const sectionId = rd.repo.name;
|
|
5005
|
+
if (rd.error) {
|
|
5006
|
+
return { repo: rd.repo, sectionId, groups: [], error: rd.error };
|
|
5007
|
+
}
|
|
5009
5008
|
const statusGroupDefs = resolveStatusGroups(rd.statusOptions, rd.repo.statusGroups);
|
|
5010
5009
|
const byStatus = groupByStatus(rd.issues);
|
|
5011
|
-
const
|
|
5010
|
+
const coveredKeys = /* @__PURE__ */ new Set();
|
|
5011
|
+
const groups = [];
|
|
5012
5012
|
for (const sg of statusGroupDefs) {
|
|
5013
|
-
const
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
for (const issue of groupIssues) {
|
|
5018
|
-
items.push({
|
|
5019
|
-
id: `gh:${rd.repo.name}:${issue.number}`,
|
|
5020
|
-
section: rd.repo.shortName,
|
|
5021
|
-
type: "item",
|
|
5022
|
-
subSection: subId
|
|
5023
|
-
});
|
|
5024
|
-
}
|
|
5025
|
-
for (const s of sg.statuses) coveredStatuses.add(s);
|
|
5026
|
-
}
|
|
5027
|
-
for (const [status, issues] of byStatus) {
|
|
5028
|
-
if (!(coveredStatuses.has(status) || isTerminalStatus(status)) && issues.length > 0) {
|
|
5029
|
-
const subId = `sub:${rd.repo.shortName}:${status}`;
|
|
5030
|
-
items.push({ id: subId, section: rd.repo.shortName, type: "subHeader" });
|
|
5031
|
-
for (const issue of issues) {
|
|
5032
|
-
items.push({
|
|
5033
|
-
id: `gh:${rd.repo.name}:${issue.number}`,
|
|
5034
|
-
section: rd.repo.shortName,
|
|
5035
|
-
type: "item",
|
|
5036
|
-
subSection: subId
|
|
5037
|
-
});
|
|
5013
|
+
const issues = [];
|
|
5014
|
+
for (const [status, statusIssues] of byStatus) {
|
|
5015
|
+
if (sg.statuses.some((s) => s.toLowerCase().trim() === status.toLowerCase().trim())) {
|
|
5016
|
+
issues.push(...statusIssues);
|
|
5038
5017
|
}
|
|
5039
5018
|
}
|
|
5019
|
+
if (issues.length === 0) continue;
|
|
5020
|
+
issues.sort((a, b) => issuePriorityRank(a) - issuePriorityRank(b));
|
|
5021
|
+
groups.push({ label: sg.label, subId: `sub:${sectionId}:${sg.label}`, issues });
|
|
5022
|
+
for (const s of sg.statuses) coveredKeys.add(s.toLowerCase().trim());
|
|
5023
|
+
}
|
|
5024
|
+
for (const [status, statusIssues] of byStatus) {
|
|
5025
|
+
if (!(coveredKeys.has(status.toLowerCase().trim()) || isTerminalStatus(status))) {
|
|
5026
|
+
groups.push({ label: status, subId: `sub:${sectionId}:${status}`, issues: statusIssues });
|
|
5027
|
+
}
|
|
5040
5028
|
}
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5029
|
+
return { repo: rd.repo, sectionId, groups, error: null };
|
|
5030
|
+
});
|
|
5031
|
+
return { activity, sections, tasks };
|
|
5032
|
+
}
|
|
5033
|
+
function buildTabs(tree) {
|
|
5034
|
+
const tabs = tree.sections.map(({ repo, groups }) => ({
|
|
5035
|
+
id: repo.name,
|
|
5036
|
+
label: repo.shortName,
|
|
5037
|
+
count: groups.reduce((s, g) => s + g.issues.length, 0)
|
|
5038
|
+
}));
|
|
5039
|
+
if (tree.activity.length > 0)
|
|
5040
|
+
tabs.push({ id: "activity", label: "Activity", count: tree.activity.length });
|
|
5041
|
+
if (tree.tasks.length > 0)
|
|
5042
|
+
tabs.push({ id: "ticktick", label: "Tasks", count: tree.tasks.length });
|
|
5043
|
+
return tabs;
|
|
5044
|
+
}
|
|
5045
|
+
function buildNavItemsForTab(tabId, tree) {
|
|
5046
|
+
if (tabId === "activity") return [];
|
|
5047
|
+
if (tabId === "ticktick")
|
|
5048
|
+
return tree.tasks.map((task2) => ({
|
|
5049
|
+
id: `tt:${task2.id}`,
|
|
5050
|
+
section: tabId,
|
|
5051
|
+
type: "item"
|
|
5052
|
+
}));
|
|
5053
|
+
const section = tree.sections.find((s) => s.sectionId === tabId);
|
|
5054
|
+
if (!section) return [];
|
|
5055
|
+
return section.groups.flatMap(
|
|
5056
|
+
(group) => group.issues.map((issue) => ({
|
|
5057
|
+
id: `gh:${section.repo.name}:${issue.number}`,
|
|
5058
|
+
section: tabId,
|
|
5059
|
+
type: "item"
|
|
5060
|
+
}))
|
|
5061
|
+
);
|
|
5049
5062
|
}
|
|
5050
|
-
function
|
|
5063
|
+
function buildFlatRowsForTab(tabId, tree) {
|
|
5064
|
+
if (tabId === "activity")
|
|
5065
|
+
return tree.activity.map((event, i) => ({
|
|
5066
|
+
type: "activity",
|
|
5067
|
+
key: `act:${i}`,
|
|
5068
|
+
navId: null,
|
|
5069
|
+
event
|
|
5070
|
+
}));
|
|
5071
|
+
if (tabId === "ticktick")
|
|
5072
|
+
return tree.tasks.map((task2) => ({
|
|
5073
|
+
type: "task",
|
|
5074
|
+
key: `tt:${task2.id}`,
|
|
5075
|
+
navId: `tt:${task2.id}`,
|
|
5076
|
+
task: task2
|
|
5077
|
+
}));
|
|
5078
|
+
const section = tree.sections.find((s) => s.sectionId === tabId);
|
|
5079
|
+
if (!section) return [];
|
|
5080
|
+
if (section.error)
|
|
5081
|
+
return [{ type: "error", key: `error:${tabId}`, navId: null, text: section.error }];
|
|
5082
|
+
if (section.groups.length === 0)
|
|
5083
|
+
return [
|
|
5084
|
+
{ type: "subHeader", key: `empty:${tabId}`, navId: null, text: "No open issues" }
|
|
5085
|
+
];
|
|
5051
5086
|
const rows = [];
|
|
5052
|
-
|
|
5053
|
-
|
|
5087
|
+
let isFirst = true;
|
|
5088
|
+
for (const group of section.groups) {
|
|
5089
|
+
if (!isFirst)
|
|
5090
|
+
rows.push({ type: "gap", key: `gap:${tabId}:${group.label}`, navId: null });
|
|
5091
|
+
isFirst = false;
|
|
5054
5092
|
rows.push({
|
|
5055
|
-
type: "
|
|
5056
|
-
key:
|
|
5057
|
-
navId:
|
|
5058
|
-
|
|
5059
|
-
count:
|
|
5060
|
-
|
|
5061
|
-
isCollapsed: collapsed
|
|
5093
|
+
type: "subHeader",
|
|
5094
|
+
key: group.subId,
|
|
5095
|
+
navId: null,
|
|
5096
|
+
text: group.label,
|
|
5097
|
+
count: group.issues.length,
|
|
5098
|
+
isCollapsed: false
|
|
5062
5099
|
});
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
const collapsed = isCollapsed(repo.shortName);
|
|
5072
|
-
rows.push({
|
|
5073
|
-
type: "sectionHeader",
|
|
5074
|
-
key: `header:${repo.shortName}`,
|
|
5075
|
-
navId: `header:${repo.shortName}`,
|
|
5076
|
-
label: repo.shortName,
|
|
5077
|
-
count: issues.length,
|
|
5078
|
-
countLabel: "issues",
|
|
5079
|
-
isCollapsed: collapsed
|
|
5080
|
-
});
|
|
5081
|
-
if (!collapsed) {
|
|
5082
|
-
if (repoError) {
|
|
5083
|
-
rows.push({ type: "error", key: `error:${repo.shortName}`, navId: null, text: repoError });
|
|
5084
|
-
} else if (issues.length === 0) {
|
|
5085
|
-
rows.push({
|
|
5086
|
-
type: "subHeader",
|
|
5087
|
-
key: `empty:${repo.shortName}`,
|
|
5088
|
-
navId: null,
|
|
5089
|
-
text: "No open issues"
|
|
5090
|
-
});
|
|
5091
|
-
} else {
|
|
5092
|
-
const statusGroupDefs = resolveStatusGroups(rd.statusOptions, rd.repo.statusGroups);
|
|
5093
|
-
const byStatus = groupByStatus(issues);
|
|
5094
|
-
const coveredStatuses = /* @__PURE__ */ new Set();
|
|
5095
|
-
let isFirstGroup = true;
|
|
5096
|
-
for (const sg of statusGroupDefs) {
|
|
5097
|
-
const groupIssues = collectGroupIssues(sg, byStatus);
|
|
5098
|
-
if (groupIssues.length === 0) continue;
|
|
5099
|
-
if (!isFirstGroup) {
|
|
5100
|
-
rows.push({ type: "gap", key: `gap:${repo.shortName}:${sg.label}`, navId: null });
|
|
5101
|
-
}
|
|
5102
|
-
isFirstGroup = false;
|
|
5103
|
-
const subId = `sub:${repo.shortName}:${sg.label}`;
|
|
5104
|
-
const subCollapsed = isCollapsed(subId);
|
|
5105
|
-
rows.push({
|
|
5106
|
-
type: "subHeader",
|
|
5107
|
-
key: subId,
|
|
5108
|
-
navId: subId,
|
|
5109
|
-
text: sg.label,
|
|
5110
|
-
count: groupIssues.length,
|
|
5111
|
-
isCollapsed: subCollapsed
|
|
5112
|
-
});
|
|
5113
|
-
if (!subCollapsed) {
|
|
5114
|
-
for (const issue of groupIssues) {
|
|
5115
|
-
rows.push({
|
|
5116
|
-
type: "issue",
|
|
5117
|
-
key: `gh:${repo.name}:${issue.number}`,
|
|
5118
|
-
navId: `gh:${repo.name}:${issue.number}`,
|
|
5119
|
-
issue,
|
|
5120
|
-
repoName: repo.name
|
|
5121
|
-
});
|
|
5122
|
-
}
|
|
5123
|
-
}
|
|
5124
|
-
for (const s of sg.statuses) coveredStatuses.add(s);
|
|
5125
|
-
}
|
|
5126
|
-
for (const [status, groupIssues] of byStatus) {
|
|
5127
|
-
if (!(coveredStatuses.has(status) || isTerminalStatus(status)) && groupIssues.length > 0) {
|
|
5128
|
-
if (!isFirstGroup) {
|
|
5129
|
-
rows.push({ type: "gap", key: `gap:${repo.shortName}:${status}`, navId: null });
|
|
5130
|
-
}
|
|
5131
|
-
isFirstGroup = false;
|
|
5132
|
-
const subId = `sub:${repo.shortName}:${status}`;
|
|
5133
|
-
const subCollapsed = isCollapsed(subId);
|
|
5134
|
-
rows.push({
|
|
5135
|
-
type: "subHeader",
|
|
5136
|
-
key: subId,
|
|
5137
|
-
navId: subId,
|
|
5138
|
-
text: status,
|
|
5139
|
-
count: groupIssues.length,
|
|
5140
|
-
isCollapsed: subCollapsed
|
|
5141
|
-
});
|
|
5142
|
-
if (!subCollapsed) {
|
|
5143
|
-
for (const issue of groupIssues) {
|
|
5144
|
-
rows.push({
|
|
5145
|
-
type: "issue",
|
|
5146
|
-
key: `gh:${repo.name}:${issue.number}`,
|
|
5147
|
-
navId: `gh:${repo.name}:${issue.number}`,
|
|
5148
|
-
issue,
|
|
5149
|
-
repoName: repo.name
|
|
5150
|
-
});
|
|
5151
|
-
}
|
|
5152
|
-
}
|
|
5153
|
-
}
|
|
5154
|
-
}
|
|
5155
|
-
}
|
|
5156
|
-
}
|
|
5157
|
-
}
|
|
5158
|
-
if (tasks.length > 0) {
|
|
5159
|
-
const collapsed = isCollapsed("ticktick");
|
|
5160
|
-
rows.push({
|
|
5161
|
-
type: "sectionHeader",
|
|
5162
|
-
key: "header:ticktick",
|
|
5163
|
-
navId: "header:ticktick",
|
|
5164
|
-
label: "Personal (TickTick)",
|
|
5165
|
-
count: tasks.length,
|
|
5166
|
-
countLabel: "tasks",
|
|
5167
|
-
isCollapsed: collapsed
|
|
5168
|
-
});
|
|
5169
|
-
if (!collapsed) {
|
|
5170
|
-
for (const task2 of tasks) {
|
|
5171
|
-
rows.push({ type: "task", key: `tt:${task2.id}`, navId: `tt:${task2.id}`, task: task2 });
|
|
5172
|
-
}
|
|
5173
|
-
}
|
|
5100
|
+
for (const issue of group.issues)
|
|
5101
|
+
rows.push({
|
|
5102
|
+
type: "issue",
|
|
5103
|
+
key: `gh:${section.repo.name}:${issue.number}`,
|
|
5104
|
+
navId: `gh:${section.repo.name}:${issue.number}`,
|
|
5105
|
+
issue,
|
|
5106
|
+
repoName: section.repo.name
|
|
5107
|
+
});
|
|
5174
5108
|
}
|
|
5175
5109
|
return rows;
|
|
5176
5110
|
}
|
|
@@ -5198,7 +5132,7 @@ function RefreshAge({ lastRefresh }) {
|
|
|
5198
5132
|
return () => clearInterval(id);
|
|
5199
5133
|
}, []);
|
|
5200
5134
|
if (!lastRefresh) return null;
|
|
5201
|
-
return /* @__PURE__ */
|
|
5135
|
+
return /* @__PURE__ */ jsxs22(Text21, { color: refreshAgeColor(lastRefresh), children: [
|
|
5202
5136
|
"Updated ",
|
|
5203
5137
|
timeAgo(lastRefresh)
|
|
5204
5138
|
] });
|
|
@@ -5263,9 +5197,32 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5263
5197
|
const q = searchQuery.toLowerCase();
|
|
5264
5198
|
return allTasks.filter((t) => t.title.toLowerCase().includes(q));
|
|
5265
5199
|
}, [allTasks, searchQuery]);
|
|
5200
|
+
const boardTree = useMemo3(
|
|
5201
|
+
() => buildBoardTree(repos, tasks, allActivity),
|
|
5202
|
+
[repos, tasks, allActivity]
|
|
5203
|
+
);
|
|
5204
|
+
const tabs = useMemo3(() => buildTabs(boardTree), [boardTree]);
|
|
5205
|
+
const [activeTabId, setActiveTabId] = useState15(null);
|
|
5206
|
+
const effectiveTabId = activeTabId ?? tabs[0]?.id ?? null;
|
|
5207
|
+
const activeTabIdx = tabs.findIndex((t) => t.id === effectiveTabId);
|
|
5208
|
+
const nextTab = useCallback11(() => {
|
|
5209
|
+
if (tabs.length === 0) return;
|
|
5210
|
+
setActiveTabId(tabs[(Math.max(activeTabIdx, 0) + 1) % tabs.length]?.id ?? null);
|
|
5211
|
+
}, [activeTabIdx, tabs]);
|
|
5212
|
+
const prevTab = useCallback11(() => {
|
|
5213
|
+
if (tabs.length === 0) return;
|
|
5214
|
+
setActiveTabId(tabs[(Math.max(activeTabIdx, 0) - 1 + tabs.length) % tabs.length]?.id ?? null);
|
|
5215
|
+
}, [activeTabIdx, tabs]);
|
|
5216
|
+
const jumpToTab = useCallback11(
|
|
5217
|
+
(idx) => {
|
|
5218
|
+
const tab = tabs[idx];
|
|
5219
|
+
if (tab) setActiveTabId(tab.id);
|
|
5220
|
+
},
|
|
5221
|
+
[tabs]
|
|
5222
|
+
);
|
|
5266
5223
|
const navItems = useMemo3(
|
|
5267
|
-
() =>
|
|
5268
|
-
[
|
|
5224
|
+
() => buildNavItemsForTab(effectiveTabId ?? "", boardTree),
|
|
5225
|
+
[effectiveTabId, boardTree]
|
|
5269
5226
|
);
|
|
5270
5227
|
const nav = useNavigation(navItems);
|
|
5271
5228
|
const getRepoForId = useCallback11((id) => {
|
|
@@ -5418,8 +5375,8 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5418
5375
|
termSize.rows - CHROME_ROWS - overlayBarRows - toastRows - logPaneRows
|
|
5419
5376
|
);
|
|
5420
5377
|
const flatRows = useMemo3(
|
|
5421
|
-
() =>
|
|
5422
|
-
[
|
|
5378
|
+
() => buildFlatRowsForTab(effectiveTabId ?? "", boardTree),
|
|
5379
|
+
[effectiveTabId, boardTree]
|
|
5423
5380
|
);
|
|
5424
5381
|
const scrollRef = useRef13(0);
|
|
5425
5382
|
const selectedRowIdx = useMemo3(
|
|
@@ -5580,6 +5537,12 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5580
5537
|
const handleFuzzySelect = useCallback11(
|
|
5581
5538
|
(navId) => {
|
|
5582
5539
|
nav.select(navId);
|
|
5540
|
+
if (navId.startsWith("gh:")) {
|
|
5541
|
+
const parts = navId.split(":");
|
|
5542
|
+
if (parts.length >= 3 && parts[1]) setActiveTabId(parts[1]);
|
|
5543
|
+
} else if (navId.startsWith("tt:")) {
|
|
5544
|
+
setActiveTabId("ticktick");
|
|
5545
|
+
}
|
|
5583
5546
|
ui.exitToNormal();
|
|
5584
5547
|
},
|
|
5585
5548
|
[nav, ui]
|
|
@@ -5613,10 +5576,11 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5613
5576
|
handleUndo: undoLast,
|
|
5614
5577
|
handleToggleLog: () => setLogVisible((v) => !v)
|
|
5615
5578
|
},
|
|
5616
|
-
onSearchEscape
|
|
5579
|
+
onSearchEscape,
|
|
5580
|
+
tabNav: { next: nextTab, prev: prevTab, jumpTo: jumpToTab, count: tabs.length }
|
|
5617
5581
|
});
|
|
5618
5582
|
if (status === "loading" && !data) {
|
|
5619
|
-
return /* @__PURE__ */
|
|
5583
|
+
return /* @__PURE__ */ jsx22(Box21, { flexDirection: "column", padding: 1, children: /* @__PURE__ */ jsx22(Spinner4, { label: "Loading dashboard..." }) });
|
|
5620
5584
|
}
|
|
5621
5585
|
const now = data?.fetchedAt ?? /* @__PURE__ */ new Date();
|
|
5622
5586
|
const dateStr = now.toLocaleDateString("en-US", {
|
|
@@ -5624,35 +5588,36 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5624
5588
|
day: "numeric",
|
|
5625
5589
|
year: "numeric"
|
|
5626
5590
|
});
|
|
5627
|
-
return /* @__PURE__ */
|
|
5628
|
-
/* @__PURE__ */
|
|
5629
|
-
/* @__PURE__ */
|
|
5630
|
-
activeProfile ? /* @__PURE__ */
|
|
5591
|
+
return /* @__PURE__ */ jsxs22(Box21, { flexDirection: "column", paddingX: 1, children: [
|
|
5592
|
+
/* @__PURE__ */ jsxs22(Box21, { children: [
|
|
5593
|
+
/* @__PURE__ */ jsx22(Text21, { color: "cyan", bold: true, children: "HOG BOARD" }),
|
|
5594
|
+
activeProfile ? /* @__PURE__ */ jsxs22(Text21, { color: "yellow", children: [
|
|
5631
5595
|
" [",
|
|
5632
5596
|
activeProfile,
|
|
5633
5597
|
"]"
|
|
5634
5598
|
] }) : null,
|
|
5635
|
-
/* @__PURE__ */
|
|
5599
|
+
/* @__PURE__ */ jsxs22(Text21, { color: "gray", children: [
|
|
5636
5600
|
" ",
|
|
5637
5601
|
"\u2014",
|
|
5638
5602
|
" ",
|
|
5639
5603
|
dateStr
|
|
5640
5604
|
] }),
|
|
5641
|
-
/* @__PURE__ */
|
|
5642
|
-
isRefreshing ? /* @__PURE__ */
|
|
5643
|
-
/* @__PURE__ */
|
|
5644
|
-
/* @__PURE__ */
|
|
5645
|
-
] }) : /* @__PURE__ */
|
|
5646
|
-
/* @__PURE__ */
|
|
5647
|
-
consecutiveFailures > 0 ? /* @__PURE__ */
|
|
5605
|
+
/* @__PURE__ */ jsx22(Text21, { children: " " }),
|
|
5606
|
+
isRefreshing ? /* @__PURE__ */ jsxs22(Fragment5, { children: [
|
|
5607
|
+
/* @__PURE__ */ jsx22(Spinner4, { label: "" }),
|
|
5608
|
+
/* @__PURE__ */ jsx22(Text21, { color: "cyan", children: " Refreshing..." })
|
|
5609
|
+
] }) : /* @__PURE__ */ jsxs22(Fragment5, { children: [
|
|
5610
|
+
/* @__PURE__ */ jsx22(RefreshAge, { lastRefresh }),
|
|
5611
|
+
consecutiveFailures > 0 ? /* @__PURE__ */ jsx22(Text21, { color: "red", children: " (!)" }) : null
|
|
5648
5612
|
] }),
|
|
5649
|
-
autoRefreshPaused ? /* @__PURE__ */
|
|
5613
|
+
autoRefreshPaused ? /* @__PURE__ */ jsx22(Text21, { color: "yellow", children: " Auto-refresh paused \u2014 press r to retry" }) : null
|
|
5650
5614
|
] }),
|
|
5651
|
-
error ? /* @__PURE__ */
|
|
5615
|
+
error ? /* @__PURE__ */ jsxs22(Text21, { color: "red", children: [
|
|
5652
5616
|
"Error: ",
|
|
5653
5617
|
error
|
|
5654
5618
|
] }) : null,
|
|
5655
|
-
/* @__PURE__ */
|
|
5619
|
+
/* @__PURE__ */ jsx22(TabBar, { tabs, activeTabId: effectiveTabId, totalWidth: termSize.cols }),
|
|
5620
|
+
/* @__PURE__ */ jsx22(
|
|
5656
5621
|
OverlayRenderer,
|
|
5657
5622
|
{
|
|
5658
5623
|
uiState: ui.state,
|
|
@@ -5694,16 +5659,16 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5694
5659
|
onPushEntry: pushEntry
|
|
5695
5660
|
}
|
|
5696
5661
|
),
|
|
5697
|
-
!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__ */
|
|
5698
|
-
/* @__PURE__ */
|
|
5699
|
-
hasMoreAbove ? /* @__PURE__ */
|
|
5662
|
+
!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__ */ jsxs22(Box21, { height: viewportHeight, children: [
|
|
5663
|
+
/* @__PURE__ */ jsxs22(Box21, { flexDirection: "column", flexGrow: 1, children: [
|
|
5664
|
+
hasMoreAbove ? /* @__PURE__ */ jsxs22(Text21, { color: "gray", dimColor: true, children: [
|
|
5700
5665
|
" ",
|
|
5701
5666
|
"\u25B2",
|
|
5702
5667
|
" ",
|
|
5703
5668
|
aboveCount,
|
|
5704
5669
|
" more above"
|
|
5705
5670
|
] }) : null,
|
|
5706
|
-
visibleRows.map((row) => /* @__PURE__ */
|
|
5671
|
+
visibleRows.map((row) => /* @__PURE__ */ jsx22(
|
|
5707
5672
|
RowRenderer,
|
|
5708
5673
|
{
|
|
5709
5674
|
row,
|
|
@@ -5713,7 +5678,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5713
5678
|
},
|
|
5714
5679
|
row.key
|
|
5715
5680
|
)),
|
|
5716
|
-
hasMoreBelow ? /* @__PURE__ */
|
|
5681
|
+
hasMoreBelow ? /* @__PURE__ */ jsxs22(Text21, { color: "gray", dimColor: true, children: [
|
|
5717
5682
|
" ",
|
|
5718
5683
|
"\u25BC",
|
|
5719
5684
|
" ",
|
|
@@ -5721,7 +5686,7 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5721
5686
|
" more below"
|
|
5722
5687
|
] }) : null
|
|
5723
5688
|
] }),
|
|
5724
|
-
showDetailPanel ? /* @__PURE__ */
|
|
5689
|
+
showDetailPanel ? /* @__PURE__ */ jsx22(Box21, { marginLeft: 1, width: detailPanelWidth, children: /* @__PURE__ */ jsx22(
|
|
5725
5690
|
DetailPanel,
|
|
5726
5691
|
{
|
|
5727
5692
|
issue: selectedItem.issue,
|
|
@@ -5733,17 +5698,16 @@ function Dashboard({ config: config2, options, activeProfile }) {
|
|
|
5733
5698
|
}
|
|
5734
5699
|
) }) : null
|
|
5735
5700
|
] }) : null,
|
|
5736
|
-
/* @__PURE__ */
|
|
5737
|
-
logVisible ? /* @__PURE__ */
|
|
5738
|
-
/* @__PURE__ */
|
|
5701
|
+
/* @__PURE__ */ jsx22(ToastContainer, { toasts }),
|
|
5702
|
+
logVisible ? /* @__PURE__ */ jsx22(ActionLog, { entries: logEntries }) : null,
|
|
5703
|
+
/* @__PURE__ */ jsx22(
|
|
5739
5704
|
HintBar,
|
|
5740
5705
|
{
|
|
5741
5706
|
uiMode: ui.state.mode,
|
|
5742
5707
|
multiSelectCount: multiSelect.count,
|
|
5743
5708
|
searchQuery,
|
|
5744
5709
|
mineOnly,
|
|
5745
|
-
hasUndoable
|
|
5746
|
-
onHeader: isHeaderId(nav.selectedId)
|
|
5710
|
+
hasUndoable
|
|
5747
5711
|
}
|
|
5748
5712
|
)
|
|
5749
5713
|
] });
|
|
@@ -5768,6 +5732,7 @@ var init_dashboard = __esm({
|
|
|
5768
5732
|
init_hint_bar();
|
|
5769
5733
|
init_overlay_renderer();
|
|
5770
5734
|
init_row_renderer();
|
|
5735
|
+
init_tab_bar();
|
|
5771
5736
|
init_toast_container();
|
|
5772
5737
|
PRIORITY_RANK = {
|
|
5773
5738
|
"priority:critical": 0,
|
|
@@ -5775,7 +5740,7 @@ var init_dashboard = __esm({
|
|
|
5775
5740
|
"priority:medium": 2,
|
|
5776
5741
|
"priority:low": 3
|
|
5777
5742
|
};
|
|
5778
|
-
CHROME_ROWS =
|
|
5743
|
+
CHROME_ROWS = 5;
|
|
5779
5744
|
}
|
|
5780
5745
|
});
|
|
5781
5746
|
|
|
@@ -5785,10 +5750,10 @@ __export(live_exports, {
|
|
|
5785
5750
|
runLiveDashboard: () => runLiveDashboard
|
|
5786
5751
|
});
|
|
5787
5752
|
import { render } from "ink";
|
|
5788
|
-
import { jsx as
|
|
5753
|
+
import { jsx as jsx23 } from "react/jsx-runtime";
|
|
5789
5754
|
async function runLiveDashboard(config2, options, activeProfile) {
|
|
5790
5755
|
const instance = render(
|
|
5791
|
-
/* @__PURE__ */
|
|
5756
|
+
/* @__PURE__ */ jsx23(Dashboard, { config: config2, options, activeProfile: activeProfile ?? null })
|
|
5792
5757
|
);
|
|
5793
5758
|
setInkInstance(instance);
|
|
5794
5759
|
await instance.waitUntilExit();
|
|
@@ -6951,7 +6916,7 @@ function resolveProjectId(projectId) {
|
|
|
6951
6916
|
process.exit(1);
|
|
6952
6917
|
}
|
|
6953
6918
|
var program = new Command();
|
|
6954
|
-
program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.
|
|
6919
|
+
program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.9.0").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
|
|
6955
6920
|
const opts = thisCommand.opts();
|
|
6956
6921
|
if (opts.json) setFormat("json");
|
|
6957
6922
|
if (opts.human) setFormat("human");
|