@kud/gh-ink 0.55.1 → 0.57.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/index.d.ts +23 -0
- package/dist/index.js +127 -58
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -65,6 +65,13 @@ type SidebarRow = {
|
|
|
65
65
|
* an error about a host decision the reader cannot change.
|
|
66
66
|
*/
|
|
67
67
|
url?: string;
|
|
68
|
+
/**
|
|
69
|
+
* A one-cell mark drawn before the key on the facts line — a priority
|
|
70
|
+
* arrow — and its colour: the same pair `TaskRow` takes, so a host fills
|
|
71
|
+
* both from one source. Absent draws the blank the cell keeps anyway.
|
|
72
|
+
*/
|
|
73
|
+
marker?: string;
|
|
74
|
+
markerColor?: string;
|
|
68
75
|
};
|
|
69
76
|
/**
|
|
70
77
|
* Plain data, deliberately: a host caches its last fetch to disk and paints it
|
|
@@ -241,6 +248,22 @@ type DetailContext = {
|
|
|
241
248
|
* once. Optional so a host that cannot merge need not implement it.
|
|
242
249
|
*/
|
|
243
250
|
onMerged?: (item: GHItem) => void;
|
|
251
|
+
/**
|
|
252
|
+
* Where a drill publishes its PEEL — close the topmost layer it owns and say
|
|
253
|
+
* whether there was one. `esc` and `backspace` are bound once at the app root
|
|
254
|
+
* and routed here; a drill view binds neither itself, per `@kud/ink-ui`'s
|
|
255
|
+
* contract that a view exported from a `*-ink` package takes `onBack` and
|
|
256
|
+
* leaves the app's keys to the app.
|
|
257
|
+
*
|
|
258
|
+
* Returning `false` means "no layer of mine was open", at which point the root
|
|
259
|
+
* closes the drill itself.
|
|
260
|
+
*/
|
|
261
|
+
registerPeel?: (peel: (() => boolean) | null) => void;
|
|
262
|
+
/**
|
|
263
|
+
* True while a text field inside the drill owns the keyboard — a reply box —
|
|
264
|
+
* so the root stands `q`, `esc` and `backspace` down and the field keeps them.
|
|
265
|
+
*/
|
|
266
|
+
onTyping?: (typing: boolean) => void;
|
|
244
267
|
};
|
|
245
268
|
type Action = {
|
|
246
269
|
label: string;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React2, { createContext, useState, useRef, useEffect, useMemo, useContext } from 'react';
|
|
2
|
-
import { useWindowSize, useInput, Text, Box
|
|
3
|
-
import { colors, ScrollView, TextInput, LoadingScreen, ProgressBar, StatusMessage, FooterHints, useListCursor, Tabs, pillWidth, Pill } from '@kud/ink-ui';
|
|
2
|
+
import { useWindowSize, useInput, Text, Box } from 'ink';
|
|
3
|
+
import { colors, ScrollView, TextInput, useAppKeys, LoadingScreen, ProgressBar, StatusMessage, FooterHints, useListCursor, Tabs, pillWidth, Pill } from '@kud/ink-ui';
|
|
4
4
|
import { isPassCheck, isFailCheck, isInconclusiveCheck, resolveThread, unresolveThread, replyToThread, rerunFailedRun, mergePr, reRequestReviewer } from '@kud/gh';
|
|
5
5
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
6
6
|
import { $ } from 'zx';
|
|
@@ -8,7 +8,7 @@ import { spawn } from 'child_process';
|
|
|
8
8
|
import { readFileSync, mkdirSync, writeFileSync, existsSync, readdirSync, statSync, watch, rmSync } from 'fs';
|
|
9
9
|
import { join, dirname, basename } from 'path';
|
|
10
10
|
import { homedir } from 'os';
|
|
11
|
-
import { depthOf, checkoutDirs, profileOf, inboxConfig, relativeTime, filterBySearch, filterByRepos, filterByOrigin,
|
|
11
|
+
import { PIN_MARK, depthOf, checkoutDirs, profileOf, inboxConfig, relativeTime, filterBySearch, filterByRepos, filterByOrigin, sizeOf, sizePartsOf, impliedLabels, labelPriority } from '@kud/gh-workflow';
|
|
12
12
|
export { PIN_MARK, bandOf, checkoutDirs, configureInbox, filterByOrigin, filterByRepos, filterBySearch, impliedLabels, inboxConfig, insertRepoHeaders, labelPriority, layoutGHItems, profileOf, relativeTime, repoPriority, resetInboxConfig, sortByRecency, sortItems, whoseMove } from '@kud/gh-workflow';
|
|
13
13
|
|
|
14
14
|
// src/components/comments-panel.tsx
|
|
@@ -687,7 +687,8 @@ var SidePanel = ({
|
|
|
687
687
|
/* @__PURE__ */ jsx(Text, { color: colors.accent, bold: true, children: row.wantsYou ? "\u2190 " : " " }),
|
|
688
688
|
/* @__PURE__ */ jsx(Text, { bold: active, children: truncateWords(row.label, labelCols) })
|
|
689
689
|
] }),
|
|
690
|
-
/* @__PURE__ */ jsxs(Box, {
|
|
690
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
691
|
+
/* @__PURE__ */ jsx(Text, { color: row.markerColor, children: " ".repeat(FACTS_INDENT - 2) + (row.marker ?? " ") + " " }),
|
|
691
692
|
/* @__PURE__ */ jsx(Text, { color: colors.secondary, children: row.key.padEnd(KEY_COLS) + GUTTER }),
|
|
692
693
|
/* @__PURE__ */ jsx(Progress, { row }),
|
|
693
694
|
/* @__PURE__ */ jsx(Text, { children: GUTTER + (row.live !== void 0 ? liveLabel(row.live).slice(0, liveCols) : "") })
|
|
@@ -1049,7 +1050,7 @@ var checksSentence = (d) => {
|
|
|
1049
1050
|
var turnSentences = (item, login) => {
|
|
1050
1051
|
if (item.pinned)
|
|
1051
1052
|
return [
|
|
1052
|
-
"You pinned this (
|
|
1053
|
+
"You pinned this (+). It stays under Your move until you unpin it, whatever else the row says."
|
|
1053
1054
|
];
|
|
1054
1055
|
if (!item.lastActor) return ["Nothing has been said on it yet."];
|
|
1055
1056
|
const d = item.detail;
|
|
@@ -1059,9 +1060,9 @@ var turnSentences = (item, login) => {
|
|
|
1059
1060
|
const them = item.author && item.author !== login ? item.author : null;
|
|
1060
1061
|
if (!them)
|
|
1061
1062
|
return [
|
|
1062
|
-
`You spoke last
|
|
1063
|
+
`You spoke last, ${when}. It is waiting on a reviewer, not on you.`
|
|
1063
1064
|
];
|
|
1064
|
-
const lines = [`You spoke last
|
|
1065
|
+
const lines = [`You spoke last, ${when}. The ball is with ${them}.`];
|
|
1065
1066
|
if (d?.lastCommitAt && d.lastEventAt && d.lastCommitAt < d.lastEventAt)
|
|
1066
1067
|
lines.push(
|
|
1067
1068
|
`Nothing has been pushed since ${relativeTime(
|
|
@@ -1848,7 +1849,7 @@ var InboxHeader = ({
|
|
|
1848
1849
|
children: statusSeg
|
|
1849
1850
|
}
|
|
1850
1851
|
) : null,
|
|
1851
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
1852
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, dimColor: true, children: "\u254C".repeat(fill) })
|
|
1852
1853
|
] });
|
|
1853
1854
|
};
|
|
1854
1855
|
var toCiStatusState = (status) => status ? { kind: "ready", status } : { kind: "error" };
|
|
@@ -1876,7 +1877,7 @@ var CiStatusLine = ({
|
|
|
1876
1877
|
] });
|
|
1877
1878
|
if (state.kind === "error")
|
|
1878
1879
|
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
1879
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
1880
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.error, bold: true, children: " \u2717 " }),
|
|
1880
1881
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: `${name} no build / not configured` })
|
|
1881
1882
|
] });
|
|
1882
1883
|
const { status } = state;
|
|
@@ -1901,9 +1902,17 @@ var RepoHeaderRow = ({
|
|
|
1901
1902
|
const fill = Math.max(4, FENCE_COLS - label.length);
|
|
1902
1903
|
const rule = "\u2500".repeat(fill);
|
|
1903
1904
|
return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
|
|
1904
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
1905
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
1905
1906
|
/* @__PURE__ */ jsx(Text3, { dimColor: !active, children: "\u2500\u2500 " }),
|
|
1906
|
-
/* @__PURE__ */ jsx(
|
|
1907
|
+
/* @__PURE__ */ jsx(
|
|
1908
|
+
Text3,
|
|
1909
|
+
{
|
|
1910
|
+
dimColor: false,
|
|
1911
|
+
color: active ? void 0 : colors.secondary,
|
|
1912
|
+
bold: active,
|
|
1913
|
+
children: repo
|
|
1914
|
+
}
|
|
1915
|
+
),
|
|
1907
1916
|
/* @__PURE__ */ jsx(Text3, { dimColor: !active, children: " " + rule })
|
|
1908
1917
|
] });
|
|
1909
1918
|
};
|
|
@@ -1957,7 +1966,8 @@ var ItemRow = ({
|
|
|
1957
1966
|
parent,
|
|
1958
1967
|
sparkFrame = 0,
|
|
1959
1968
|
cols = COLS,
|
|
1960
|
-
markerCols = 0
|
|
1969
|
+
markerCols = 0,
|
|
1970
|
+
uniformLabels = []
|
|
1961
1971
|
}) => {
|
|
1962
1972
|
const backdropped = useBackdropped();
|
|
1963
1973
|
const transient = leaving ? "out" : refreshMark;
|
|
@@ -1973,14 +1983,14 @@ var ItemRow = ({
|
|
|
1973
1983
|
] });
|
|
1974
1984
|
if (item.kind === "show-more")
|
|
1975
1985
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1976
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
1986
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
1977
1987
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
|
|
1978
1988
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: active ? "\u21B5 " : " " }),
|
|
1979
1989
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: `+${item.hidden.length} more` })
|
|
1980
1990
|
] });
|
|
1981
1991
|
if (item.kind === "show-less")
|
|
1982
1992
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1983
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
1993
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
1984
1994
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
|
|
1985
1995
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: active ? "\u21B5 " : " " }),
|
|
1986
1996
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: "show less" })
|
|
@@ -1993,7 +2003,7 @@ var ItemRow = ({
|
|
|
1993
2003
|
cols - item.key.length - note.length - (item.pill ? pillWidth(item.pill) + 1 : 0) - (farewellLabel ? pillWidth(farewellLabel) + 2 : 0) - prefix.length - (markerCols > 0 ? markerCols + 1 : 0) - 12
|
|
1994
2004
|
);
|
|
1995
2005
|
return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
|
|
1996
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2006
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
1997
2007
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
|
|
1998
2008
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: parent ? "\u252C " : " " }),
|
|
1999
2009
|
/* @__PURE__ */ jsx(Text3, { bold: true, color: transient ? TRANSIT_COLOUR[transient] : void 0, children: transitIcon + " " }),
|
|
@@ -2031,17 +2041,18 @@ var ItemRow = ({
|
|
|
2031
2041
|
const icon = merged ? MERGED_FRAMES[sparkFrame % MERGED_FRAMES.length] : transient && isDeparture(transient) ? TRANSIT_OUT_FRAMES[rampAt(TRANSIT_OUT_FRAMES.length)] : transient && isArrival(transient) ? TRANSIT_IN_FRAMES[rampAt(TRANSIT_IN_FRAMES.length)] : healthIcon;
|
|
2032
2042
|
const color = merged ? MERGED_COLOUR : transient ? TRANSIT_COLOUR[transient] : healthColor2;
|
|
2033
2043
|
const spokeLast = !!login && !!item.lastActor && item.lastActor === login;
|
|
2034
|
-
const [turnIcon, turnColor] = item.pinned ? [PIN_MARK, colors.accent] : !login || !item.lastActor
|
|
2044
|
+
const [turnIcon, turnColor] = item.pinned ? [PIN_MARK, colors.accent] : !login || !item.lastActor || spokeLast ? [" ", colors.muted] : ["\u2190", colors.accent];
|
|
2035
2045
|
const numStr = `#${item.number}`.padEnd(7);
|
|
2036
2046
|
const showAuthor = !!item.author && item.author !== login;
|
|
2037
2047
|
const sizeLabel = sizeOf(item);
|
|
2038
2048
|
const sizeParts = sizePartsOf(item);
|
|
2039
2049
|
const unresolvedLabel = item.unresolved > 0 ? `\uF086 ${item.unresolved}` : "";
|
|
2040
|
-
const
|
|
2050
|
+
const agePair = item.activityAge && item.activityAge !== item.age ? { activity: item.activityAge, lifetime: item.age } : null;
|
|
2051
|
+
const ageLabel = agePair ? `${agePair.activity} (${agePair.lifetime})` : item.age;
|
|
2041
2052
|
const mergedLabel = merged ? "merged" : "";
|
|
2042
2053
|
const pillCaps = [mergedLabel, farewellLabel].filter(Boolean).length * 2;
|
|
2043
2054
|
const repoLabel = depthOf(item) > 0 ? item.repo : "";
|
|
2044
|
-
const implied = impliedLabels(item.repo);
|
|
2055
|
+
const implied = [...impliedLabels(item.repo), ...uniformLabels];
|
|
2045
2056
|
const labelNames = (item.labels ?? []).filter((l) => !implied.includes(l)).sort((a, b) => labelPriority(a) - labelPriority(b) || a.localeCompare(b)).slice(0, 2);
|
|
2046
2057
|
const givingUp = {
|
|
2047
2058
|
author: false,
|
|
@@ -2096,7 +2107,7 @@ var ItemRow = ({
|
|
|
2096
2107
|
const labelLabel = labelCell();
|
|
2097
2108
|
const titleMax = Math.max(1, cols - widthOf2());
|
|
2098
2109
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
2099
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2110
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
2100
2111
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
|
|
2101
2112
|
/* @__PURE__ */ jsx(Text3, { color, bold: true, children: icon + " " }),
|
|
2102
2113
|
/* @__PURE__ */ jsx(Text3, { color: turnColor, bold: turnIcon === "\u2190", children: turnIcon + " " }),
|
|
@@ -2118,9 +2129,19 @@ var ItemRow = ({
|
|
|
2118
2129
|
" ",
|
|
2119
2130
|
/* @__PURE__ */ jsx(Text3, { color: colors.error, children: sizeParts.removed })
|
|
2120
2131
|
] }) : null,
|
|
2121
|
-
unresolvedLabel && !givingUp.threads ? /* @__PURE__ */ jsx(
|
|
2132
|
+
unresolvedLabel && !givingUp.threads ? /* @__PURE__ */ jsx(
|
|
2133
|
+
Text3,
|
|
2134
|
+
{
|
|
2135
|
+
bold: !spokeLast,
|
|
2136
|
+
color: spokeLast ? colors.secondary : colors.accent,
|
|
2137
|
+
children: " " + unresolvedLabel
|
|
2138
|
+
}
|
|
2139
|
+
) : null,
|
|
2122
2140
|
showAuthor && !givingUp.author ? /* @__PURE__ */ jsx(Text3, { dimColor: true, italic: true, children: " by " + item.author }) : null,
|
|
2123
|
-
ageLabel && !givingUp.age ? /* @__PURE__ */
|
|
2141
|
+
ageLabel && !givingUp.age ? agePair ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2142
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.secondary, children: " " + agePair.activity }),
|
|
2143
|
+
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: ` (${agePair.lifetime})` })
|
|
2144
|
+
] }) : /* @__PURE__ */ jsx(Text3, { color: colors.secondary, children: " " + ageLabel }) : null,
|
|
2124
2145
|
mergedLabel && !backdropped ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2125
2146
|
/* @__PURE__ */ jsx(Text3, { children: " " }),
|
|
2126
2147
|
/* @__PURE__ */ jsx(Pill, { color: MERGED_COLOUR, children: mergedLabel })
|
|
@@ -2169,15 +2190,15 @@ var ActionMenu = ({
|
|
|
2169
2190
|
{
|
|
2170
2191
|
flexDirection: "column",
|
|
2171
2192
|
borderStyle: "round",
|
|
2172
|
-
borderColor:
|
|
2193
|
+
borderColor: colors.info,
|
|
2173
2194
|
backgroundColor: OVERLAY_BG,
|
|
2174
2195
|
paddingX: 1,
|
|
2175
2196
|
marginTop: 1,
|
|
2176
2197
|
children: [
|
|
2177
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2198
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, bold: true, children: title }),
|
|
2178
2199
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: "\u2500".repeat(32) }),
|
|
2179
2200
|
actions.map((a, i) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
2180
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2201
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: i === cursor ? "\u276F " : " " }),
|
|
2181
2202
|
/* @__PURE__ */ jsx(Text3, { bold: i === cursor, children: a.label }),
|
|
2182
2203
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: " " + a.hint })
|
|
2183
2204
|
] }, a.label)),
|
|
@@ -2188,8 +2209,8 @@ var ActionMenu = ({
|
|
|
2188
2209
|
);
|
|
2189
2210
|
};
|
|
2190
2211
|
var TURN_LEGEND = [
|
|
2191
|
-
["\u2190", colors.accent, "They spoke last \xB7
|
|
2192
|
-
[
|
|
2212
|
+
["\u2190", colors.accent, "They spoke last \xB7 reply owed"],
|
|
2213
|
+
[PIN_MARK, colors.accent, "Pinned \xB7 stays under Your move"]
|
|
2193
2214
|
];
|
|
2194
2215
|
var CELL_GUTTER = 2;
|
|
2195
2216
|
var COL_GAP = 3;
|
|
@@ -2346,13 +2367,13 @@ var HelpModal = ({
|
|
|
2346
2367
|
{
|
|
2347
2368
|
flexDirection: "column",
|
|
2348
2369
|
borderStyle: "round",
|
|
2349
|
-
borderColor:
|
|
2370
|
+
borderColor: colors.info,
|
|
2350
2371
|
backgroundColor: OVERLAY_BG,
|
|
2351
2372
|
paddingX: 1,
|
|
2352
2373
|
width: contentWidth + MODAL_CHROME_COLS,
|
|
2353
2374
|
children: [
|
|
2354
2375
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
2355
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2376
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, bold: true, children: "Legend" }),
|
|
2356
2377
|
scrollable ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: ` ${offset + 1}\u2013${offset + shown} of ${totalRows}` }) : null
|
|
2357
2378
|
] }),
|
|
2358
2379
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, width: contentWidth, children: groups.map((group, index) => /* @__PURE__ */ jsx(
|
|
@@ -2376,7 +2397,7 @@ var ExplainModal = ({ item, login }) => /* @__PURE__ */ jsxs(
|
|
|
2376
2397
|
{
|
|
2377
2398
|
flexDirection: "column",
|
|
2378
2399
|
borderStyle: "round",
|
|
2379
|
-
borderColor:
|
|
2400
|
+
borderColor: colors.info,
|
|
2380
2401
|
backgroundColor: OVERLAY_BG,
|
|
2381
2402
|
paddingX: 1,
|
|
2382
2403
|
width: Math.min(COLS, 78),
|
|
@@ -2408,19 +2429,19 @@ var RepoPicker = ({
|
|
|
2408
2429
|
{
|
|
2409
2430
|
flexDirection: "column",
|
|
2410
2431
|
borderStyle: "round",
|
|
2411
|
-
borderColor:
|
|
2432
|
+
borderColor: colors.info,
|
|
2412
2433
|
backgroundColor: OVERLAY_BG,
|
|
2413
2434
|
paddingX: 1,
|
|
2414
2435
|
minWidth: 42,
|
|
2415
2436
|
children: [
|
|
2416
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2437
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, bold: true, children: `Filter by repo (${selected.size} on)` }),
|
|
2417
2438
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: "\u2500".repeat(36) }),
|
|
2418
2439
|
visible.map((repo, i) => {
|
|
2419
2440
|
const idx = start + i;
|
|
2420
2441
|
const on = selected.has(repo);
|
|
2421
2442
|
const active = idx === cursor;
|
|
2422
2443
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
2423
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2444
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
2424
2445
|
/* @__PURE__ */ jsx(Text3, { color: on ? "green" : void 0, children: on ? "\u25C9 " : "\u25CB " }),
|
|
2425
2446
|
/* @__PURE__ */ jsx(Text3, { bold: active, children: repo })
|
|
2426
2447
|
] }, repo);
|
|
@@ -2453,6 +2474,8 @@ var BrowseScreen = ({
|
|
|
2453
2474
|
fetchedAt,
|
|
2454
2475
|
refreshError,
|
|
2455
2476
|
hidden,
|
|
2477
|
+
peelRef,
|
|
2478
|
+
onTyping,
|
|
2456
2479
|
onOpenPr,
|
|
2457
2480
|
onOpenIssue,
|
|
2458
2481
|
onOpenExt,
|
|
@@ -2474,7 +2497,6 @@ var BrowseScreen = ({
|
|
|
2474
2497
|
liveLabel
|
|
2475
2498
|
}) => {
|
|
2476
2499
|
const { rows } = useWindowSize();
|
|
2477
|
-
const { exit } = useApp();
|
|
2478
2500
|
const applyWork = (secs) => origin ? filterByOrigin(secs, origin.show, origin.match, login) : secs;
|
|
2479
2501
|
const initialSections = applyWork(sections);
|
|
2480
2502
|
const [localSections, setLocalSections] = useState(initialSections);
|
|
@@ -2578,6 +2600,12 @@ var BrowseScreen = ({
|
|
|
2578
2600
|
(w, i) => i.kind === "task" ? Math.max(w, [...i.marker ?? ""].length) : w,
|
|
2579
2601
|
0
|
|
2580
2602
|
);
|
|
2603
|
+
const labelBearing = section.items.filter(
|
|
2604
|
+
(i) => i.kind === "pr" || i.kind === "issue"
|
|
2605
|
+
);
|
|
2606
|
+
const uniformLabels = labelBearing.length > 1 ? (labelBearing[0]?.labels ?? []).filter(
|
|
2607
|
+
(name) => labelBearing.every((i) => (i.labels ?? []).includes(name))
|
|
2608
|
+
) : [];
|
|
2581
2609
|
const hasMore = viewStart + visibleCount < section.items.length;
|
|
2582
2610
|
const activeItem = section.items[cursor];
|
|
2583
2611
|
const showFlash = (msg) => {
|
|
@@ -2599,6 +2627,26 @@ var BrowseScreen = ({
|
|
|
2599
2627
|
const railRows = sidebar?.rows ?? [];
|
|
2600
2628
|
const railActive = showRail && railFocus && railRows.length > 0;
|
|
2601
2629
|
const railAt = Math.min(railCursor, Math.max(0, railRows.length - 1));
|
|
2630
|
+
const peel = () => {
|
|
2631
|
+
if (help) return setHelp(false), true;
|
|
2632
|
+
if (explain) return setExplain(false), true;
|
|
2633
|
+
if (repoPicker) return setRepoPicker(false), true;
|
|
2634
|
+
if (railActive) return setRailFocus(false), true;
|
|
2635
|
+
if (menu.actions !== null) return menu.close(), true;
|
|
2636
|
+
if (search != null) return setSearch(null), true;
|
|
2637
|
+
if (repoFilter.size > 0) return setRepoFilter(/* @__PURE__ */ new Set()), true;
|
|
2638
|
+
return false;
|
|
2639
|
+
};
|
|
2640
|
+
useEffect(() => {
|
|
2641
|
+
if (!peelRef) return;
|
|
2642
|
+
peelRef.current = peel;
|
|
2643
|
+
return () => {
|
|
2644
|
+
peelRef.current = null;
|
|
2645
|
+
};
|
|
2646
|
+
});
|
|
2647
|
+
useEffect(() => {
|
|
2648
|
+
onTyping?.(searchInput);
|
|
2649
|
+
}, [searchInput, onTyping]);
|
|
2602
2650
|
const railCols = railWidth(COLS);
|
|
2603
2651
|
const listCols = showRail ? COLS - railCols : COLS;
|
|
2604
2652
|
const [sparkFrame, setSparkFrame] = useState(0);
|
|
@@ -2708,7 +2756,7 @@ var BrowseScreen = ({
|
|
|
2708
2756
|
return;
|
|
2709
2757
|
}
|
|
2710
2758
|
if (repoPicker) {
|
|
2711
|
-
if (key.
|
|
2759
|
+
if (key.return) return setRepoPicker(false);
|
|
2712
2760
|
if (input === "a") return setRepoFilter(/* @__PURE__ */ new Set());
|
|
2713
2761
|
if (input === " ") {
|
|
2714
2762
|
const repo = allRepos[repoCursor];
|
|
@@ -2764,30 +2812,30 @@ var BrowseScreen = ({
|
|
|
2764
2812
|
setRailCursor((c) => Math.min(railRows.length - 1, c + 1));
|
|
2765
2813
|
return;
|
|
2766
2814
|
}
|
|
2767
|
-
if (key.escape) {
|
|
2768
|
-
setRailFocus(false);
|
|
2769
|
-
return;
|
|
2770
|
-
}
|
|
2771
2815
|
if (key.return || input === "o") {
|
|
2772
2816
|
const row = railRows[railAt];
|
|
2773
|
-
if (row
|
|
2774
|
-
|
|
2817
|
+
if (!row) return;
|
|
2818
|
+
if (key.return && openDrillView({
|
|
2819
|
+
kind: "task",
|
|
2820
|
+
key: row.key,
|
|
2821
|
+
ticket: row.key,
|
|
2822
|
+
summary: row.label,
|
|
2823
|
+
url: row.url ?? "",
|
|
2824
|
+
status: "",
|
|
2825
|
+
age: "",
|
|
2826
|
+
indent: false
|
|
2827
|
+
}))
|
|
2828
|
+
return;
|
|
2829
|
+
if (row.url) {
|
|
2830
|
+
quietly`open `.catch(() => {
|
|
2775
2831
|
});
|
|
2776
|
-
showFlash(`\u2197 Opened
|
|
2832
|
+
showFlash(`\u2197 Opened `);
|
|
2777
2833
|
}
|
|
2778
2834
|
return;
|
|
2779
2835
|
}
|
|
2780
2836
|
if (input !== "r" && input !== "q" && !key.leftArrow && !key.rightArrow)
|
|
2781
2837
|
return;
|
|
2782
2838
|
}
|
|
2783
|
-
if (key.escape && search != null) {
|
|
2784
|
-
setSearch(null);
|
|
2785
|
-
return;
|
|
2786
|
-
}
|
|
2787
|
-
if (key.escape && repoFilter.size > 0) {
|
|
2788
|
-
setRepoFilter(/* @__PURE__ */ new Set());
|
|
2789
|
-
return;
|
|
2790
|
-
}
|
|
2791
2839
|
if (menu.handleKey(key)) return;
|
|
2792
2840
|
if (key.upArrow) {
|
|
2793
2841
|
const next = moveCursor(section.items, cursor, -1);
|
|
@@ -2805,10 +2853,7 @@ var BrowseScreen = ({
|
|
|
2805
2853
|
}
|
|
2806
2854
|
const step = key.leftArrow || key.tab && key.shift ? -1 : key.rightArrow || key.tab ? 1 : 0;
|
|
2807
2855
|
if (step !== 0)
|
|
2808
|
-
setTabIdx(
|
|
2809
|
-
(i) => (i + step + localSections.length) % localSections.length
|
|
2810
|
-
);
|
|
2811
|
-
if (input === "q") exit();
|
|
2856
|
+
setTabIdx((i) => (i + step + localSections.length) % localSections.length);
|
|
2812
2857
|
if (input === "r") {
|
|
2813
2858
|
onRefresh?.();
|
|
2814
2859
|
return;
|
|
@@ -3048,6 +3093,7 @@ var BrowseScreen = ({
|
|
|
3048
3093
|
[
|
|
3049
3094
|
["\u2191\u2193", "initiative"],
|
|
3050
3095
|
["\u21B5", "open"],
|
|
3096
|
+
["o", "browser"],
|
|
3051
3097
|
["\u21E5/esc", "back to list"],
|
|
3052
3098
|
["?", "help"],
|
|
3053
3099
|
["q", "quit"]
|
|
@@ -3158,9 +3204,9 @@ var BrowseScreen = ({
|
|
|
3158
3204
|
}
|
|
3159
3205
|
) }),
|
|
3160
3206
|
search != null ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
3161
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
3207
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: " / " }),
|
|
3162
3208
|
/* @__PURE__ */ jsx(Text3, { children: search }),
|
|
3163
|
-
searchInput ? /* @__PURE__ */ jsx(Text3, { color:
|
|
3209
|
+
searchInput ? /* @__PURE__ */ jsx(Text3, { color: colors.info, children: "\u258F" }) : null,
|
|
3164
3210
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: ` ${matchCount} match${matchCount !== 1 ? "es" : ""}${searchInput ? " \u21B5 accept \xB7 esc clear" : " esc clear"}` })
|
|
3165
3211
|
] }) : repoFilter.size > 0 ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
3166
3212
|
/* @__PURE__ */ jsx(Text3, { color: colors.accent, children: " \u25C9 " }),
|
|
@@ -3198,6 +3244,7 @@ var BrowseScreen = ({
|
|
|
3198
3244
|
sparkFrame,
|
|
3199
3245
|
cols: listCols,
|
|
3200
3246
|
markerCols,
|
|
3247
|
+
uniformLabels,
|
|
3201
3248
|
gap: i > 0 && gapsAbove(section.items, viewStart + i)
|
|
3202
3249
|
},
|
|
3203
3250
|
`${viewStart + i}:${rowKey(item)}`
|
|
@@ -3236,7 +3283,7 @@ var BrowseScreen = ({
|
|
|
3236
3283
|
}
|
|
3237
3284
|
) : null
|
|
3238
3285
|
] }),
|
|
3239
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: flash ? /* @__PURE__ */ jsx(Text3, { color:
|
|
3286
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: flash ? /* @__PURE__ */ jsx(Text3, { color: colors.success, children: flash }) : /* @__PURE__ */ jsx(FooterHints, { hints }) })
|
|
3240
3287
|
]
|
|
3241
3288
|
}
|
|
3242
3289
|
);
|
|
@@ -3246,9 +3293,7 @@ var NoRowsScreen = ({
|
|
|
3246
3293
|
detail,
|
|
3247
3294
|
onRetry
|
|
3248
3295
|
}) => {
|
|
3249
|
-
const { exit } = useApp();
|
|
3250
3296
|
useInput((input) => {
|
|
3251
|
-
if (input === "q") exit();
|
|
3252
3297
|
if (input === "r") onRetry();
|
|
3253
3298
|
});
|
|
3254
3299
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
@@ -3297,6 +3342,24 @@ var App = ({
|
|
|
3297
3342
|
}) => {
|
|
3298
3343
|
const { rows } = useWindowSize();
|
|
3299
3344
|
const [state, setState] = useState({ phase: "loading" });
|
|
3345
|
+
const browsePeel = useRef(null);
|
|
3346
|
+
const drillPeel = useRef(null);
|
|
3347
|
+
const [typing, setTyping] = useState(false);
|
|
3348
|
+
useAppKeys({
|
|
3349
|
+
isActive: !typing,
|
|
3350
|
+
onBack: () => {
|
|
3351
|
+
if (state.phase === "pr" || state.phase === "issue" || state.phase === "ext") {
|
|
3352
|
+
if (drillPeel.current?.()) return true;
|
|
3353
|
+
setState({
|
|
3354
|
+
phase: "browse",
|
|
3355
|
+
sections: state.sections,
|
|
3356
|
+
login: state.login
|
|
3357
|
+
});
|
|
3358
|
+
return true;
|
|
3359
|
+
}
|
|
3360
|
+
return browsePeel.current?.() ?? false;
|
|
3361
|
+
}
|
|
3362
|
+
});
|
|
3300
3363
|
const [pending, setPending] = useState(null);
|
|
3301
3364
|
const [refreshing, setRefreshing] = useState(false);
|
|
3302
3365
|
const [fetchedAt, setFetchedAt] = useState(null);
|
|
@@ -3661,6 +3724,8 @@ var App = ({
|
|
|
3661
3724
|
budget,
|
|
3662
3725
|
skippedForBudget,
|
|
3663
3726
|
hidden: overlay !== null,
|
|
3727
|
+
peelRef: browsePeel,
|
|
3728
|
+
onTyping: setTyping,
|
|
3664
3729
|
mergedUrls,
|
|
3665
3730
|
leavingUrls,
|
|
3666
3731
|
transitSince,
|
|
@@ -3698,6 +3763,10 @@ var App = ({
|
|
|
3698
3763
|
item: overlay.item,
|
|
3699
3764
|
kind: overlay.kind,
|
|
3700
3765
|
login: state.login,
|
|
3766
|
+
registerPeel: (peel) => {
|
|
3767
|
+
drillPeel.current = peel;
|
|
3768
|
+
},
|
|
3769
|
+
onTyping: setTyping,
|
|
3701
3770
|
onBack: toBrowse,
|
|
3702
3771
|
onRefresh: applyOrRefresh,
|
|
3703
3772
|
onRemove: markLeaving,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kud/gh-ink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.57.0",
|
|
4
4
|
"description": "Ink components for rendering GitHub PR review comments and health — controlled, presentation-only, built on @kud/ink-ui and fed by @kud/gh.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
"react": ">=19"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@kud/gh": "0.
|
|
52
|
-
"@kud/gh-workflow": "0.12.
|
|
51
|
+
"@kud/gh": "0.17.0",
|
|
52
|
+
"@kud/gh-workflow": "0.12.1",
|
|
53
53
|
"@kud/ink-ui": "0.29.0",
|
|
54
54
|
"zx": "8.8.5"
|
|
55
55
|
},
|