@kud/gh-ink 0.53.0 → 0.54.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 +48 -13
- package/dist/index.js +28 -14
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -66,19 +66,26 @@ type SidebarRow = {
|
|
|
66
66
|
*/
|
|
67
67
|
url?: string;
|
|
68
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* Plain data, deliberately: a host caches its last fetch to disk and paints it
|
|
71
|
+
* on the next launch, and this rides along in that file. A function on it would
|
|
72
|
+
* not survive the round trip, so the host's words for `live` travel as a prop
|
|
73
|
+
* on `SidePanel` instead — vocabulary is configuration, not data that goes
|
|
74
|
+
* stale.
|
|
75
|
+
*/
|
|
69
76
|
type Sidebar = {
|
|
70
77
|
/** Heading for the rail. The host's vocabulary, never ours. */
|
|
71
78
|
title: string;
|
|
72
79
|
rows: SidebarRow[];
|
|
73
|
-
/**
|
|
74
|
-
* What to call `live` on screen, in the host's words — `4 on board` and `off
|
|
75
|
-
* board` on a ticket cockpit, say. Takes the number rather than a word pair
|
|
76
|
-
* because the two states need not share a sentence shape: "off board" has no
|
|
77
|
-
* N in it. `live` itself stays a number, so the absent-draws-nothing contract
|
|
78
|
-
* and the host's sort are untouched.
|
|
79
|
-
*/
|
|
80
|
-
liveLabel?: (live: number) => string;
|
|
81
80
|
};
|
|
81
|
+
/**
|
|
82
|
+
* What to call `live` on screen, in the host's words — `4 on board` and `off
|
|
83
|
+
* board` on a ticket cockpit, say. Takes the number rather than a word pair
|
|
84
|
+
* because the two states need not share a sentence shape: "off board" has no
|
|
85
|
+
* N in it. `live` itself stays a number, so the absent-draws-nothing contract
|
|
86
|
+
* and the host's sort are untouched.
|
|
87
|
+
*/
|
|
88
|
+
type LiveLabel = (live: number) => string;
|
|
82
89
|
/**
|
|
83
90
|
* The rail's width, INCLUDING its rule and padding. Exported because the list
|
|
84
91
|
* beside it has to shrink by exactly this much: every row in that list truncates
|
|
@@ -91,8 +98,18 @@ type Sidebar = {
|
|
|
91
98
|
* word and left the rail listing keys with an ellipsis after them. The key line
|
|
92
99
|
* was never the constraint — the label is what makes a key readable, and a rail
|
|
93
100
|
* you cannot read is forty columns spent on nothing.
|
|
101
|
+
*
|
|
102
|
+
* Widened again once the label became the row's first line: at 45 usable
|
|
103
|
+
* columns a real epic title still lost its last two words. But a 200-column
|
|
104
|
+
* terminal has room to give where a 120-column one does not — at 120 a rail
|
|
105
|
+
* this wide leaves the list 52 columns, which elides a PR title past its own
|
|
106
|
+
* key. So this is the CEILING, and `railWidth` sizes the rail to the frame:
|
|
107
|
+
* a third of it, never below the 52 the grid was laid out for, never above.
|
|
94
108
|
*/
|
|
95
|
-
declare const SIDEBAR_COLS =
|
|
109
|
+
declare const SIDEBAR_COLS = 64;
|
|
110
|
+
declare const MIN_SIDEBAR_COLS = 52;
|
|
111
|
+
/** How wide the rail is in a frame of `cols` — pass the same number to `width`. */
|
|
112
|
+
declare const railWidth: (cols: number) => number;
|
|
96
113
|
/**
|
|
97
114
|
* The plain-text facts of a row, for a host or a test that wants them as one
|
|
98
115
|
* string: how far through, then how much is moving. Either half may be missing
|
|
@@ -100,7 +117,7 @@ declare const SIDEBAR_COLS = 52;
|
|
|
100
117
|
* counted, because "nothing is moving" is exactly the thing a roadmap is read
|
|
101
118
|
* to notice.
|
|
102
119
|
*/
|
|
103
|
-
declare const counts: (row: SidebarRow, liveLabel?:
|
|
120
|
+
declare const counts: (row: SidebarRow, liveLabel?: LiveLabel) => string;
|
|
104
121
|
/**
|
|
105
122
|
* How many rows fit in `height` — one fewer than would physically fit whenever
|
|
106
123
|
* that means anything is left over, to buy the line that says so.
|
|
@@ -126,8 +143,11 @@ declare const railCapacity: (height: number, rows: number) => number;
|
|
|
126
143
|
* the arrows are pointed at this rail at all, are the host's state — which is
|
|
127
144
|
* what lets a screen with two focus regions have exactly one of them lit.
|
|
128
145
|
*/
|
|
129
|
-
declare const SidePanel: ({ sidebar, height, focused, cursor, }: {
|
|
146
|
+
declare const SidePanel: ({ sidebar, liveLabel, width, height, focused, cursor, }: {
|
|
130
147
|
sidebar: Sidebar;
|
|
148
|
+
liveLabel?: LiveLabel;
|
|
149
|
+
/** From `railWidth`, so the list beside it can subtract the same number. */
|
|
150
|
+
width?: number;
|
|
131
151
|
height?: number;
|
|
132
152
|
/** The arrows are pointed here, so this rail draws the cursor. */
|
|
133
153
|
focused?: boolean;
|
|
@@ -192,12 +212,20 @@ type CachedCockpit = {
|
|
|
192
212
|
login: string;
|
|
193
213
|
at: number;
|
|
194
214
|
budget?: InboxBudget;
|
|
215
|
+
/**
|
|
216
|
+
* The rail, when the host supplied one. Cached beside the rows because it is
|
|
217
|
+
* painted beside them: a launch that trusts the cache never refetches, so a
|
|
218
|
+
* rail left out of the file is a rail that does not exist until the next
|
|
219
|
+
* refresh — `i` did nothing and the footer did not even offer it.
|
|
220
|
+
*/
|
|
221
|
+
sidebar?: Sidebar;
|
|
195
222
|
};
|
|
196
223
|
declare const readCache: (key: string) => CachedCockpit | null;
|
|
197
224
|
declare const writeCache: (key: string, data: {
|
|
198
225
|
sections: Section[];
|
|
199
226
|
login: string;
|
|
200
227
|
budget?: InboxBudget;
|
|
228
|
+
sidebar?: Sidebar;
|
|
201
229
|
}) => void;
|
|
202
230
|
|
|
203
231
|
type DetailContext = {
|
|
@@ -386,7 +414,7 @@ declare const ActionMenu: ({ item, actions, cursor, }: {
|
|
|
386
414
|
cursor: number;
|
|
387
415
|
}) => React.JSX.Element;
|
|
388
416
|
declare const signatureOf: (sections: Section[]) => string;
|
|
389
|
-
declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jiraKeyRe, jiraTransitions, hasCiStatus, ciJob, ciFetcher, ciPollMs, watchPath, watchDebounceMs, watchJitterMs, extensions, tabHelp, emptyHint, }: {
|
|
417
|
+
declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jiraKeyRe, jiraTransitions, hasCiStatus, ciJob, ciFetcher, ciPollMs, watchPath, watchDebounceMs, watchJitterMs, extensions, tabHelp, emptyHint, liveLabel, }: {
|
|
390
418
|
fetcher: () => Promise<{
|
|
391
419
|
sections: Section[];
|
|
392
420
|
login: string;
|
|
@@ -409,6 +437,13 @@ declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jir
|
|
|
409
437
|
sidebar?: Sidebar;
|
|
410
438
|
}>;
|
|
411
439
|
cacheKey?: string;
|
|
440
|
+
/**
|
|
441
|
+
* What the rail calls a row's `live` count, in this host's words — `4 on
|
|
442
|
+
* board` / `off board` on a ticket cockpit. A prop rather than part of the
|
|
443
|
+
* fetch result because it is vocabulary, not data: it never goes stale, and
|
|
444
|
+
* a function would not survive the cache the sidebar is painted from.
|
|
445
|
+
*/
|
|
446
|
+
liveLabel?: LiveLabel;
|
|
412
447
|
title?: string;
|
|
413
448
|
detailFor?: (ctx: DetailContext) => React.ReactNode;
|
|
414
449
|
/** A two-way repo split, and what to call the side on screen. See OriginSplit. */
|
|
@@ -461,4 +496,4 @@ declare const matchesFilter: (repo: string, filter: RepoFilter) => boolean;
|
|
|
461
496
|
*/
|
|
462
497
|
declare const parsePatterns: (value: string) => string[];
|
|
463
498
|
|
|
464
|
-
export { type Action, ActionMenu, App, COLS, CiStatusLine, type CiStatusState, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxExtension, type JiraTransition, type RepoFilter, SIDEBAR_COLS, SidePanel, type Sidebar, type SidebarRow, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, railCapacity, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, signatureOf, toCiStatusState, truncate, useActionMenu, windowCount, withHeaders, withoutItem, workCount, writeCache };
|
|
499
|
+
export { type Action, ActionMenu, App, COLS, CiStatusLine, type CiStatusState, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxExtension, type JiraTransition, type LiveLabel, MIN_SIDEBAR_COLS, type RepoFilter, SIDEBAR_COLS, SidePanel, type Sidebar, type SidebarRow, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, railCapacity, railWidth, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, signatureOf, toCiStatusState, truncate, useActionMenu, windowCount, withHeaders, withoutItem, workCount, writeCache };
|
package/dist/index.js
CHANGED
|
@@ -585,18 +585,19 @@ var HealthPanel = ({
|
|
|
585
585
|
] }) }) : note ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: colors.success, children: " " + note }) }) : null
|
|
586
586
|
] });
|
|
587
587
|
};
|
|
588
|
-
var SIDEBAR_COLS =
|
|
588
|
+
var SIDEBAR_COLS = 64;
|
|
589
|
+
var MIN_SIDEBAR_COLS = 52;
|
|
590
|
+
var railWidth = (cols) => Math.max(MIN_SIDEBAR_COLS, Math.min(SIDEBAR_COLS, Math.round(cols / 3)));
|
|
589
591
|
var RULE = 1;
|
|
590
592
|
var PAD = 2;
|
|
591
|
-
var
|
|
593
|
+
var contentOf = (width) => width - RULE - PAD;
|
|
592
594
|
var MARKS = 4;
|
|
593
|
-
var LABEL_COLS = CONTENT - MARKS;
|
|
594
595
|
var FACTS_INDENT = 6;
|
|
595
596
|
var KEY_COLS = 10;
|
|
596
597
|
var BAR_COLS = 10;
|
|
597
598
|
var FRACTION_COLS = 5;
|
|
598
599
|
var GUTTER = " ";
|
|
599
|
-
var
|
|
600
|
+
var FACTS_FIXED = FACTS_INDENT + KEY_COLS + BAR_COLS + FRACTION_COLS + GUTTER.length * 3;
|
|
600
601
|
var defaultLiveLabel = (live) => live === 0 ? "nothing live" : `${live} live`;
|
|
601
602
|
var fractionOf = (row) => row.done !== void 0 && row.total !== void 0 ? `${row.done}/${row.total}` : "";
|
|
602
603
|
var counts = (row, liveLabel = defaultLiveLabel) => [fractionOf(row), row.live !== void 0 ? liveLabel(row.live) : ""].filter(Boolean).join(" \xB7 ");
|
|
@@ -634,18 +635,22 @@ var Progress = ({ row }) => {
|
|
|
634
635
|
};
|
|
635
636
|
var SidePanel = ({
|
|
636
637
|
sidebar,
|
|
638
|
+
liveLabel = defaultLiveLabel,
|
|
639
|
+
width = SIDEBAR_COLS,
|
|
637
640
|
height,
|
|
638
641
|
focused = false,
|
|
639
642
|
cursor = 0
|
|
640
643
|
}) => {
|
|
641
|
-
const
|
|
644
|
+
const content = contentOf(width);
|
|
645
|
+
const labelCols = content - MARKS;
|
|
646
|
+
const liveCols = content - FACTS_FIXED;
|
|
642
647
|
const capacity = height === void 0 ? sidebar.rows.length : railCapacity(height, sidebar.rows.length);
|
|
643
648
|
const start = focused && cursor >= capacity ? Math.min(cursor - capacity + 1, sidebar.rows.length - capacity) : 0;
|
|
644
649
|
const shown = sidebar.rows.slice(start, start + capacity);
|
|
645
650
|
const hidden = sidebar.rows.length - shown.length;
|
|
646
651
|
const focus = focused ? " \u25CF focus" : "";
|
|
647
652
|
const rule = "\u254C".repeat(
|
|
648
|
-
Math.max(0,
|
|
653
|
+
Math.max(0, content - [...sidebar.title].length - focus.length - 1)
|
|
649
654
|
);
|
|
650
655
|
return (
|
|
651
656
|
// A rule down the left rather than a full box: the rail's other three edges
|
|
@@ -658,7 +663,7 @@ var SidePanel = ({
|
|
|
658
663
|
Box,
|
|
659
664
|
{
|
|
660
665
|
flexDirection: "column",
|
|
661
|
-
width
|
|
666
|
+
width,
|
|
662
667
|
flexShrink: 0,
|
|
663
668
|
height,
|
|
664
669
|
borderStyle: "single",
|
|
@@ -679,12 +684,12 @@ var SidePanel = ({
|
|
|
679
684
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
680
685
|
/* @__PURE__ */ jsx(Text, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
681
686
|
/* @__PURE__ */ jsx(Text, { color: colors.accent, bold: true, children: row.wantsYou ? "\u2190 " : " " }),
|
|
682
|
-
/* @__PURE__ */ jsx(Text, { bold: active, children: truncateWords(row.label,
|
|
687
|
+
/* @__PURE__ */ jsx(Text, { bold: active, children: truncateWords(row.label, labelCols) })
|
|
683
688
|
] }),
|
|
684
689
|
/* @__PURE__ */ jsxs(Box, { paddingLeft: FACTS_INDENT, children: [
|
|
685
690
|
/* @__PURE__ */ jsx(Text, { color: colors.secondary, children: row.key.padEnd(KEY_COLS) + GUTTER }),
|
|
686
691
|
/* @__PURE__ */ jsx(Progress, { row }),
|
|
687
|
-
/* @__PURE__ */ jsx(Text, { children: GUTTER + (row.live !== void 0 ? liveLabel(row.live).slice(0,
|
|
692
|
+
/* @__PURE__ */ jsx(Text, { children: GUTTER + (row.live !== void 0 ? liveLabel(row.live).slice(0, liveCols) : "") })
|
|
688
693
|
] })
|
|
689
694
|
] }, row.key);
|
|
690
695
|
}),
|
|
@@ -757,7 +762,8 @@ var readCache = (key) => {
|
|
|
757
762
|
sections: raw.sections,
|
|
758
763
|
login: raw.login ?? "",
|
|
759
764
|
at: raw.at ?? 0,
|
|
760
|
-
budget: raw.budget
|
|
765
|
+
budget: raw.budget,
|
|
766
|
+
...Array.isArray(raw.sidebar?.rows) ? { sidebar: raw.sidebar } : {}
|
|
761
767
|
};
|
|
762
768
|
} catch {
|
|
763
769
|
return null;
|
|
@@ -2401,7 +2407,8 @@ var BrowseScreen = ({
|
|
|
2401
2407
|
onLeave,
|
|
2402
2408
|
transients,
|
|
2403
2409
|
onTabChange,
|
|
2404
|
-
sidebar
|
|
2410
|
+
sidebar,
|
|
2411
|
+
liveLabel
|
|
2405
2412
|
}) => {
|
|
2406
2413
|
const { rows } = useWindowSize();
|
|
2407
2414
|
const { exit } = useApp();
|
|
@@ -2525,7 +2532,8 @@ var BrowseScreen = ({
|
|
|
2525
2532
|
const railRows = sidebar?.rows ?? [];
|
|
2526
2533
|
const railActive = showRail && railFocus && railRows.length > 0;
|
|
2527
2534
|
const railAt = Math.min(railCursor, Math.max(0, railRows.length - 1));
|
|
2528
|
-
const
|
|
2535
|
+
const railCols = railWidth(COLS);
|
|
2536
|
+
const listCols = showRail ? COLS - railCols : COLS;
|
|
2529
2537
|
const [sparkFrame, setSparkFrame] = useState(0);
|
|
2530
2538
|
const sparkling = (mergedUrls?.length ?? 0) > 0 || (leavingUrls?.length ?? 0) > 0 || // Any MARKED TAB, not just rows on screen. The scope used to be this tab's
|
|
2531
2539
|
// own items, which was right while the animation lived on the rows and is
|
|
@@ -3152,6 +3160,8 @@ var BrowseScreen = ({
|
|
|
3152
3160
|
SidePanel,
|
|
3153
3161
|
{
|
|
3154
3162
|
sidebar,
|
|
3163
|
+
liveLabel,
|
|
3164
|
+
width: railCols,
|
|
3155
3165
|
height: listHeight,
|
|
3156
3166
|
focused: railActive,
|
|
3157
3167
|
cursor: railAt
|
|
@@ -3214,7 +3224,8 @@ var App = ({
|
|
|
3214
3224
|
watchJitterMs = 0,
|
|
3215
3225
|
extensions,
|
|
3216
3226
|
tabHelp,
|
|
3217
|
-
emptyHint
|
|
3227
|
+
emptyHint,
|
|
3228
|
+
liveLabel
|
|
3218
3229
|
}) => {
|
|
3219
3230
|
const { rows } = useWindowSize();
|
|
3220
3231
|
const [state, setState] = useState({ phase: "loading" });
|
|
@@ -3391,6 +3402,7 @@ var App = ({
|
|
|
3391
3402
|
displayedKey.current = signatureOf(cached.sections);
|
|
3392
3403
|
displayedSections.current = cached.sections;
|
|
3393
3404
|
setFetchedAt(cached.at);
|
|
3405
|
+
if (cached.sidebar) setSidebar(cached.sidebar);
|
|
3394
3406
|
setState({
|
|
3395
3407
|
phase: "browse",
|
|
3396
3408
|
sections: cached.sections,
|
|
@@ -3435,6 +3447,7 @@ var App = ({
|
|
|
3435
3447
|
const shared = cacheKey ? readCache(cacheKey) : null;
|
|
3436
3448
|
if (shared && shared.at > firedAt) {
|
|
3437
3449
|
receive({ sections: shared.sections, login: shared.login });
|
|
3450
|
+
if (shared.sidebar) setSidebar(shared.sidebar);
|
|
3438
3451
|
setFetchedAt(shared.at);
|
|
3439
3452
|
return;
|
|
3440
3453
|
}
|
|
@@ -3579,6 +3592,7 @@ var App = ({
|
|
|
3579
3592
|
transients,
|
|
3580
3593
|
onTabChange: setVisibleTab,
|
|
3581
3594
|
sidebar,
|
|
3595
|
+
liveLabel,
|
|
3582
3596
|
ciStatusState: hasCiStatus ? ciStatusState : void 0,
|
|
3583
3597
|
ciJob,
|
|
3584
3598
|
tabHelp,
|
|
@@ -3631,4 +3645,4 @@ var matchesFilter = (repo, filter) => {
|
|
|
3631
3645
|
};
|
|
3632
3646
|
var parsePatterns = (value) => value.split(",").map((p) => p.trim()).filter(Boolean);
|
|
3633
3647
|
|
|
3634
|
-
export { ActionMenu, App, COLS, CiStatusLine, CommentsPanel, HealthPanel, SIDEBAR_COLS, SidePanel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, railCapacity, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, signatureOf, toCiStatusState, truncate, useActionMenu, windowCount, withHeaders, withoutItem, workCount, writeCache };
|
|
3648
|
+
export { ActionMenu, App, COLS, CiStatusLine, CommentsPanel, HealthPanel, MIN_SIDEBAR_COLS, SIDEBAR_COLS, SidePanel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, railCapacity, railWidth, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, signatureOf, toCiStatusState, truncate, useActionMenu, windowCount, withHeaders, withoutItem, workCount, writeCache };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kud/gh-ink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.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",
|