@kud/gh-ink 0.56.0 → 0.57.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +16 -0
- package/dist/index.js +111 -56
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -248,6 +248,22 @@ type DetailContext = {
|
|
|
248
248
|
* once. Optional so a host that cannot merge need not implement it.
|
|
249
249
|
*/
|
|
250
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;
|
|
251
267
|
};
|
|
252
268
|
type Action = {
|
|
253
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
|
|
@@ -1050,7 +1050,7 @@ var checksSentence = (d) => {
|
|
|
1050
1050
|
var turnSentences = (item, login) => {
|
|
1051
1051
|
if (item.pinned)
|
|
1052
1052
|
return [
|
|
1053
|
-
"You pinned this (
|
|
1053
|
+
"You pinned this (+). It stays under Your move until you unpin it, whatever else the row says."
|
|
1054
1054
|
];
|
|
1055
1055
|
if (!item.lastActor) return ["Nothing has been said on it yet."];
|
|
1056
1056
|
const d = item.detail;
|
|
@@ -1060,9 +1060,9 @@ var turnSentences = (item, login) => {
|
|
|
1060
1060
|
const them = item.author && item.author !== login ? item.author : null;
|
|
1061
1061
|
if (!them)
|
|
1062
1062
|
return [
|
|
1063
|
-
`You spoke last
|
|
1063
|
+
`You spoke last, ${when}. It is waiting on a reviewer, not on you.`
|
|
1064
1064
|
];
|
|
1065
|
-
const lines = [`You spoke last
|
|
1065
|
+
const lines = [`You spoke last, ${when}. The ball is with ${them}.`];
|
|
1066
1066
|
if (d?.lastCommitAt && d.lastEventAt && d.lastCommitAt < d.lastEventAt)
|
|
1067
1067
|
lines.push(
|
|
1068
1068
|
`Nothing has been pushed since ${relativeTime(
|
|
@@ -1849,7 +1849,7 @@ var InboxHeader = ({
|
|
|
1849
1849
|
children: statusSeg
|
|
1850
1850
|
}
|
|
1851
1851
|
) : null,
|
|
1852
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
1852
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, dimColor: true, children: "\u254C".repeat(fill) })
|
|
1853
1853
|
] });
|
|
1854
1854
|
};
|
|
1855
1855
|
var toCiStatusState = (status) => status ? { kind: "ready", status } : { kind: "error" };
|
|
@@ -1877,7 +1877,7 @@ var CiStatusLine = ({
|
|
|
1877
1877
|
] });
|
|
1878
1878
|
if (state.kind === "error")
|
|
1879
1879
|
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
1880
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
1880
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.error, bold: true, children: " \u2717 " }),
|
|
1881
1881
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: `${name} no build / not configured` })
|
|
1882
1882
|
] });
|
|
1883
1883
|
const { status } = state;
|
|
@@ -1902,9 +1902,17 @@ var RepoHeaderRow = ({
|
|
|
1902
1902
|
const fill = Math.max(4, FENCE_COLS - label.length);
|
|
1903
1903
|
const rule = "\u2500".repeat(fill);
|
|
1904
1904
|
return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
|
|
1905
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
1905
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
1906
1906
|
/* @__PURE__ */ jsx(Text3, { dimColor: !active, children: "\u2500\u2500 " }),
|
|
1907
|
-
/* @__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
|
+
),
|
|
1908
1916
|
/* @__PURE__ */ jsx(Text3, { dimColor: !active, children: " " + rule })
|
|
1909
1917
|
] });
|
|
1910
1918
|
};
|
|
@@ -1958,7 +1966,8 @@ var ItemRow = ({
|
|
|
1958
1966
|
parent,
|
|
1959
1967
|
sparkFrame = 0,
|
|
1960
1968
|
cols = COLS,
|
|
1961
|
-
markerCols = 0
|
|
1969
|
+
markerCols = 0,
|
|
1970
|
+
uniformLabels = []
|
|
1962
1971
|
}) => {
|
|
1963
1972
|
const backdropped = useBackdropped();
|
|
1964
1973
|
const transient = leaving ? "out" : refreshMark;
|
|
@@ -1974,14 +1983,14 @@ var ItemRow = ({
|
|
|
1974
1983
|
] });
|
|
1975
1984
|
if (item.kind === "show-more")
|
|
1976
1985
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1977
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
1986
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
1978
1987
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
|
|
1979
1988
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: active ? "\u21B5 " : " " }),
|
|
1980
1989
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: `+${item.hidden.length} more` })
|
|
1981
1990
|
] });
|
|
1982
1991
|
if (item.kind === "show-less")
|
|
1983
1992
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1984
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
1993
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
1985
1994
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
|
|
1986
1995
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: active ? "\u21B5 " : " " }),
|
|
1987
1996
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: "show less" })
|
|
@@ -1994,7 +2003,7 @@ var ItemRow = ({
|
|
|
1994
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
|
|
1995
2004
|
);
|
|
1996
2005
|
return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
|
|
1997
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2006
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
1998
2007
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
|
|
1999
2008
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: parent ? "\u252C " : " " }),
|
|
2000
2009
|
/* @__PURE__ */ jsx(Text3, { bold: true, color: transient ? TRANSIT_COLOUR[transient] : void 0, children: transitIcon + " " }),
|
|
@@ -2032,17 +2041,18 @@ var ItemRow = ({
|
|
|
2032
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;
|
|
2033
2042
|
const color = merged ? MERGED_COLOUR : transient ? TRANSIT_COLOUR[transient] : healthColor2;
|
|
2034
2043
|
const spokeLast = !!login && !!item.lastActor && item.lastActor === login;
|
|
2035
|
-
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];
|
|
2036
2045
|
const numStr = `#${item.number}`.padEnd(7);
|
|
2037
2046
|
const showAuthor = !!item.author && item.author !== login;
|
|
2038
2047
|
const sizeLabel = sizeOf(item);
|
|
2039
2048
|
const sizeParts = sizePartsOf(item);
|
|
2040
2049
|
const unresolvedLabel = item.unresolved > 0 ? `\uF086 ${item.unresolved}` : "";
|
|
2041
|
-
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;
|
|
2042
2052
|
const mergedLabel = merged ? "merged" : "";
|
|
2043
2053
|
const pillCaps = [mergedLabel, farewellLabel].filter(Boolean).length * 2;
|
|
2044
2054
|
const repoLabel = depthOf(item) > 0 ? item.repo : "";
|
|
2045
|
-
const implied = impliedLabels(item.repo);
|
|
2055
|
+
const implied = [...impliedLabels(item.repo), ...uniformLabels];
|
|
2046
2056
|
const labelNames = (item.labels ?? []).filter((l) => !implied.includes(l)).sort((a, b) => labelPriority(a) - labelPriority(b) || a.localeCompare(b)).slice(0, 2);
|
|
2047
2057
|
const givingUp = {
|
|
2048
2058
|
author: false,
|
|
@@ -2097,7 +2107,7 @@ var ItemRow = ({
|
|
|
2097
2107
|
const labelLabel = labelCell();
|
|
2098
2108
|
const titleMax = Math.max(1, cols - widthOf2());
|
|
2099
2109
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
2100
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2110
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
2101
2111
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: prefix }),
|
|
2102
2112
|
/* @__PURE__ */ jsx(Text3, { color, bold: true, children: icon + " " }),
|
|
2103
2113
|
/* @__PURE__ */ jsx(Text3, { color: turnColor, bold: turnIcon === "\u2190", children: turnIcon + " " }),
|
|
@@ -2119,9 +2129,19 @@ var ItemRow = ({
|
|
|
2119
2129
|
" ",
|
|
2120
2130
|
/* @__PURE__ */ jsx(Text3, { color: colors.error, children: sizeParts.removed })
|
|
2121
2131
|
] }) : null,
|
|
2122
|
-
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,
|
|
2123
2140
|
showAuthor && !givingUp.author ? /* @__PURE__ */ jsx(Text3, { dimColor: true, italic: true, children: " by " + item.author }) : null,
|
|
2124
|
-
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,
|
|
2125
2145
|
mergedLabel && !backdropped ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2126
2146
|
/* @__PURE__ */ jsx(Text3, { children: " " }),
|
|
2127
2147
|
/* @__PURE__ */ jsx(Pill, { color: MERGED_COLOUR, children: mergedLabel })
|
|
@@ -2170,15 +2190,15 @@ var ActionMenu = ({
|
|
|
2170
2190
|
{
|
|
2171
2191
|
flexDirection: "column",
|
|
2172
2192
|
borderStyle: "round",
|
|
2173
|
-
borderColor:
|
|
2193
|
+
borderColor: colors.info,
|
|
2174
2194
|
backgroundColor: OVERLAY_BG,
|
|
2175
2195
|
paddingX: 1,
|
|
2176
2196
|
marginTop: 1,
|
|
2177
2197
|
children: [
|
|
2178
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2198
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, bold: true, children: title }),
|
|
2179
2199
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: "\u2500".repeat(32) }),
|
|
2180
2200
|
actions.map((a, i) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
2181
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2201
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: i === cursor ? "\u276F " : " " }),
|
|
2182
2202
|
/* @__PURE__ */ jsx(Text3, { bold: i === cursor, children: a.label }),
|
|
2183
2203
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: " " + a.hint })
|
|
2184
2204
|
] }, a.label)),
|
|
@@ -2189,8 +2209,8 @@ var ActionMenu = ({
|
|
|
2189
2209
|
);
|
|
2190
2210
|
};
|
|
2191
2211
|
var TURN_LEGEND = [
|
|
2192
|
-
["\u2190", colors.accent, "They spoke last \xB7
|
|
2193
|
-
[
|
|
2212
|
+
["\u2190", colors.accent, "They spoke last \xB7 reply owed"],
|
|
2213
|
+
[PIN_MARK, colors.accent, "Pinned \xB7 stays under Your move"]
|
|
2194
2214
|
];
|
|
2195
2215
|
var CELL_GUTTER = 2;
|
|
2196
2216
|
var COL_GAP = 3;
|
|
@@ -2347,13 +2367,13 @@ var HelpModal = ({
|
|
|
2347
2367
|
{
|
|
2348
2368
|
flexDirection: "column",
|
|
2349
2369
|
borderStyle: "round",
|
|
2350
|
-
borderColor:
|
|
2370
|
+
borderColor: colors.info,
|
|
2351
2371
|
backgroundColor: OVERLAY_BG,
|
|
2352
2372
|
paddingX: 1,
|
|
2353
2373
|
width: contentWidth + MODAL_CHROME_COLS,
|
|
2354
2374
|
children: [
|
|
2355
2375
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
2356
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2376
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, bold: true, children: "Legend" }),
|
|
2357
2377
|
scrollable ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: ` ${offset + 1}\u2013${offset + shown} of ${totalRows}` }) : null
|
|
2358
2378
|
] }),
|
|
2359
2379
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, width: contentWidth, children: groups.map((group, index) => /* @__PURE__ */ jsx(
|
|
@@ -2377,7 +2397,7 @@ var ExplainModal = ({ item, login }) => /* @__PURE__ */ jsxs(
|
|
|
2377
2397
|
{
|
|
2378
2398
|
flexDirection: "column",
|
|
2379
2399
|
borderStyle: "round",
|
|
2380
|
-
borderColor:
|
|
2400
|
+
borderColor: colors.info,
|
|
2381
2401
|
backgroundColor: OVERLAY_BG,
|
|
2382
2402
|
paddingX: 1,
|
|
2383
2403
|
width: Math.min(COLS, 78),
|
|
@@ -2409,19 +2429,19 @@ var RepoPicker = ({
|
|
|
2409
2429
|
{
|
|
2410
2430
|
flexDirection: "column",
|
|
2411
2431
|
borderStyle: "round",
|
|
2412
|
-
borderColor:
|
|
2432
|
+
borderColor: colors.info,
|
|
2413
2433
|
backgroundColor: OVERLAY_BG,
|
|
2414
2434
|
paddingX: 1,
|
|
2415
2435
|
minWidth: 42,
|
|
2416
2436
|
children: [
|
|
2417
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2437
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, bold: true, children: `Filter by repo (${selected.size} on)` }),
|
|
2418
2438
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: "\u2500".repeat(36) }),
|
|
2419
2439
|
visible.map((repo, i) => {
|
|
2420
2440
|
const idx = start + i;
|
|
2421
2441
|
const on = selected.has(repo);
|
|
2422
2442
|
const active = idx === cursor;
|
|
2423
2443
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
2424
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
2444
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
2425
2445
|
/* @__PURE__ */ jsx(Text3, { color: on ? "green" : void 0, children: on ? "\u25C9 " : "\u25CB " }),
|
|
2426
2446
|
/* @__PURE__ */ jsx(Text3, { bold: active, children: repo })
|
|
2427
2447
|
] }, repo);
|
|
@@ -2454,6 +2474,8 @@ var BrowseScreen = ({
|
|
|
2454
2474
|
fetchedAt,
|
|
2455
2475
|
refreshError,
|
|
2456
2476
|
hidden,
|
|
2477
|
+
peelRef,
|
|
2478
|
+
onTyping,
|
|
2457
2479
|
onOpenPr,
|
|
2458
2480
|
onOpenIssue,
|
|
2459
2481
|
onOpenExt,
|
|
@@ -2475,7 +2497,6 @@ var BrowseScreen = ({
|
|
|
2475
2497
|
liveLabel
|
|
2476
2498
|
}) => {
|
|
2477
2499
|
const { rows } = useWindowSize();
|
|
2478
|
-
const { exit } = useApp();
|
|
2479
2500
|
const applyWork = (secs) => origin ? filterByOrigin(secs, origin.show, origin.match, login) : secs;
|
|
2480
2501
|
const initialSections = applyWork(sections);
|
|
2481
2502
|
const [localSections, setLocalSections] = useState(initialSections);
|
|
@@ -2579,6 +2600,12 @@ var BrowseScreen = ({
|
|
|
2579
2600
|
(w, i) => i.kind === "task" ? Math.max(w, [...i.marker ?? ""].length) : w,
|
|
2580
2601
|
0
|
|
2581
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
|
+
) : [];
|
|
2582
2609
|
const hasMore = viewStart + visibleCount < section.items.length;
|
|
2583
2610
|
const activeItem = section.items[cursor];
|
|
2584
2611
|
const showFlash = (msg) => {
|
|
@@ -2600,6 +2627,26 @@ var BrowseScreen = ({
|
|
|
2600
2627
|
const railRows = sidebar?.rows ?? [];
|
|
2601
2628
|
const railActive = showRail && railFocus && railRows.length > 0;
|
|
2602
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]);
|
|
2603
2650
|
const railCols = railWidth(COLS);
|
|
2604
2651
|
const listCols = showRail ? COLS - railCols : COLS;
|
|
2605
2652
|
const [sparkFrame, setSparkFrame] = useState(0);
|
|
@@ -2709,7 +2756,7 @@ var BrowseScreen = ({
|
|
|
2709
2756
|
return;
|
|
2710
2757
|
}
|
|
2711
2758
|
if (repoPicker) {
|
|
2712
|
-
if (key.
|
|
2759
|
+
if (key.return) return setRepoPicker(false);
|
|
2713
2760
|
if (input === "a") return setRepoFilter(/* @__PURE__ */ new Set());
|
|
2714
2761
|
if (input === " ") {
|
|
2715
2762
|
const repo = allRepos[repoCursor];
|
|
@@ -2765,10 +2812,6 @@ var BrowseScreen = ({
|
|
|
2765
2812
|
setRailCursor((c) => Math.min(railRows.length - 1, c + 1));
|
|
2766
2813
|
return;
|
|
2767
2814
|
}
|
|
2768
|
-
if (key.escape) {
|
|
2769
|
-
setRailFocus(false);
|
|
2770
|
-
return;
|
|
2771
|
-
}
|
|
2772
2815
|
if (key.return || input === "o") {
|
|
2773
2816
|
const row = railRows[railAt];
|
|
2774
2817
|
if (!row) return;
|
|
@@ -2784,23 +2827,15 @@ var BrowseScreen = ({
|
|
|
2784
2827
|
}))
|
|
2785
2828
|
return;
|
|
2786
2829
|
if (row.url) {
|
|
2787
|
-
quietly`open `.catch(() => {
|
|
2830
|
+
quietly`open ${row.url}`.catch(() => {
|
|
2788
2831
|
});
|
|
2789
|
-
showFlash(`\u2197 Opened `);
|
|
2832
|
+
showFlash(`\u2197 Opened ${row.key}`);
|
|
2790
2833
|
}
|
|
2791
2834
|
return;
|
|
2792
2835
|
}
|
|
2793
2836
|
if (input !== "r" && input !== "q" && !key.leftArrow && !key.rightArrow)
|
|
2794
2837
|
return;
|
|
2795
2838
|
}
|
|
2796
|
-
if (key.escape && search != null) {
|
|
2797
|
-
setSearch(null);
|
|
2798
|
-
return;
|
|
2799
|
-
}
|
|
2800
|
-
if (key.escape && repoFilter.size > 0) {
|
|
2801
|
-
setRepoFilter(/* @__PURE__ */ new Set());
|
|
2802
|
-
return;
|
|
2803
|
-
}
|
|
2804
2839
|
if (menu.handleKey(key)) return;
|
|
2805
2840
|
if (key.upArrow) {
|
|
2806
2841
|
const next = moveCursor(section.items, cursor, -1);
|
|
@@ -2818,10 +2853,7 @@ var BrowseScreen = ({
|
|
|
2818
2853
|
}
|
|
2819
2854
|
const step = key.leftArrow || key.tab && key.shift ? -1 : key.rightArrow || key.tab ? 1 : 0;
|
|
2820
2855
|
if (step !== 0)
|
|
2821
|
-
setTabIdx(
|
|
2822
|
-
(i) => (i + step + localSections.length) % localSections.length
|
|
2823
|
-
);
|
|
2824
|
-
if (input === "q") exit();
|
|
2856
|
+
setTabIdx((i) => (i + step + localSections.length) % localSections.length);
|
|
2825
2857
|
if (input === "r") {
|
|
2826
2858
|
onRefresh?.();
|
|
2827
2859
|
return;
|
|
@@ -3172,9 +3204,9 @@ var BrowseScreen = ({
|
|
|
3172
3204
|
}
|
|
3173
3205
|
) }),
|
|
3174
3206
|
search != null ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
3175
|
-
/* @__PURE__ */ jsx(Text3, { color:
|
|
3207
|
+
/* @__PURE__ */ jsx(Text3, { color: colors.info, children: " / " }),
|
|
3176
3208
|
/* @__PURE__ */ jsx(Text3, { children: search }),
|
|
3177
|
-
searchInput ? /* @__PURE__ */ jsx(Text3, { color:
|
|
3209
|
+
searchInput ? /* @__PURE__ */ jsx(Text3, { color: colors.info, children: "\u258F" }) : null,
|
|
3178
3210
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: ` ${matchCount} match${matchCount !== 1 ? "es" : ""}${searchInput ? " \u21B5 accept \xB7 esc clear" : " esc clear"}` })
|
|
3179
3211
|
] }) : repoFilter.size > 0 ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
3180
3212
|
/* @__PURE__ */ jsx(Text3, { color: colors.accent, children: " \u25C9 " }),
|
|
@@ -3212,6 +3244,7 @@ var BrowseScreen = ({
|
|
|
3212
3244
|
sparkFrame,
|
|
3213
3245
|
cols: listCols,
|
|
3214
3246
|
markerCols,
|
|
3247
|
+
uniformLabels,
|
|
3215
3248
|
gap: i > 0 && gapsAbove(section.items, viewStart + i)
|
|
3216
3249
|
},
|
|
3217
3250
|
`${viewStart + i}:${rowKey(item)}`
|
|
@@ -3250,7 +3283,7 @@ var BrowseScreen = ({
|
|
|
3250
3283
|
}
|
|
3251
3284
|
) : null
|
|
3252
3285
|
] }),
|
|
3253
|
-
/* @__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 }) })
|
|
3254
3287
|
]
|
|
3255
3288
|
}
|
|
3256
3289
|
);
|
|
@@ -3260,9 +3293,7 @@ var NoRowsScreen = ({
|
|
|
3260
3293
|
detail,
|
|
3261
3294
|
onRetry
|
|
3262
3295
|
}) => {
|
|
3263
|
-
const { exit } = useApp();
|
|
3264
3296
|
useInput((input) => {
|
|
3265
|
-
if (input === "q") exit();
|
|
3266
3297
|
if (input === "r") onRetry();
|
|
3267
3298
|
});
|
|
3268
3299
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
@@ -3311,6 +3342,24 @@ var App = ({
|
|
|
3311
3342
|
}) => {
|
|
3312
3343
|
const { rows } = useWindowSize();
|
|
3313
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
|
+
});
|
|
3314
3363
|
const [pending, setPending] = useState(null);
|
|
3315
3364
|
const [refreshing, setRefreshing] = useState(false);
|
|
3316
3365
|
const [fetchedAt, setFetchedAt] = useState(null);
|
|
@@ -3675,6 +3724,8 @@ var App = ({
|
|
|
3675
3724
|
budget,
|
|
3676
3725
|
skippedForBudget,
|
|
3677
3726
|
hidden: overlay !== null,
|
|
3727
|
+
peelRef: browsePeel,
|
|
3728
|
+
onTyping: setTyping,
|
|
3678
3729
|
mergedUrls,
|
|
3679
3730
|
leavingUrls,
|
|
3680
3731
|
transitSince,
|
|
@@ -3712,6 +3763,10 @@ var App = ({
|
|
|
3712
3763
|
item: overlay.item,
|
|
3713
3764
|
kind: overlay.kind,
|
|
3714
3765
|
login: state.login,
|
|
3766
|
+
registerPeel: (peel) => {
|
|
3767
|
+
drillPeel.current = peel;
|
|
3768
|
+
},
|
|
3769
|
+
onTyping: setTyping,
|
|
3715
3770
|
onBack: toBrowse,
|
|
3716
3771
|
onRefresh: applyOrRefresh,
|
|
3717
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.1",
|
|
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
|
},
|