@kud/gh-ink 0.58.0 → 0.59.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 +116 -16
- package/dist/index.js +356 -160
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -136,32 +136,112 @@ declare const counts: (row: SidebarRow, liveLabel?: LiveLabel) => string;
|
|
|
136
136
|
*/
|
|
137
137
|
declare const railCapacity: (height: number, rows: number) => number;
|
|
138
138
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
139
|
+
* One rail, or several stacked in one column. A host with one thing to rail —
|
|
140
|
+
* initiatives — passes the one; a host with two kinds of container passes both,
|
|
141
|
+
* and the panel draws them in order under one rule, each with its own heading.
|
|
142
|
+
* A stack rather than a second prop because the second rail needs everything
|
|
143
|
+
* the first has — a heading, a window, a cursor — and nothing more.
|
|
144
|
+
*/
|
|
145
|
+
type Rails = Sidebar | Sidebar[];
|
|
146
|
+
/** The stack as an array, whichever shape the host chose. */
|
|
147
|
+
declare const railsOf: (rails: Rails | undefined) => Sidebar[];
|
|
148
|
+
/** Every row of every section in order — the space the rail's cursor moves in. */
|
|
149
|
+
declare const railRowsOf: (rails: Rails | undefined) => SidebarRow[];
|
|
150
|
+
/**
|
|
151
|
+
* How the rail's height is shared out down a stack. Each section takes what it
|
|
152
|
+
* needs while that fits inside an even share of what is left, so a short
|
|
153
|
+
* section hands its surplus down rather than sitting beside a stripe of blank
|
|
154
|
+
* lines while the section under it says `+4 more`. Even shares rather than
|
|
155
|
+
* first-come, because the FIRST section is the one most likely to be long, and
|
|
156
|
+
* letting it fill the column would leave the second with a heading and nothing
|
|
157
|
+
* under it — a section that is visibly there and unreadable.
|
|
158
|
+
*/
|
|
159
|
+
declare const railHeights: (height: number, rowCounts: number[]) => number[];
|
|
160
|
+
/**
|
|
161
|
+
* A right-hand rail standing beside the list: one section, or a stack of them.
|
|
147
162
|
*
|
|
148
163
|
* Presentational, like every other row renderer here: it DRAWS a cursor but does
|
|
149
164
|
* not own one, and it never calls `useInput`. Where the cursor is, and whether
|
|
150
165
|
* the arrows are pointed at this rail at all, are the host's state — which is
|
|
151
|
-
* what lets a screen with two focus regions have exactly one of them lit.
|
|
166
|
+
* what lets a screen with two focus regions have exactly one of them lit. The
|
|
167
|
+
* cursor counts across the whole stack, in `railRowsOf` order, so the host
|
|
168
|
+
* moves one number and never learns where a section boundary falls.
|
|
152
169
|
*/
|
|
153
170
|
declare const SidePanel: ({ sidebar, liveLabel, width, height, focused, cursor, }: {
|
|
154
|
-
sidebar:
|
|
171
|
+
sidebar: Rails;
|
|
155
172
|
liveLabel?: LiveLabel;
|
|
156
173
|
/** From `railWidth`, so the list beside it can subtract the same number. */
|
|
157
174
|
width?: number;
|
|
158
175
|
height?: number;
|
|
159
176
|
/** The arrows are pointed here, so this rail draws the cursor. */
|
|
160
177
|
focused?: boolean;
|
|
161
|
-
/** Which row the cursor is on. Only drawn while `focused`. */
|
|
178
|
+
/** Which row the cursor is on, counted across every section. Only drawn while `focused`. */
|
|
162
179
|
cursor?: number;
|
|
163
180
|
}) => React.JSX.Element;
|
|
164
181
|
|
|
182
|
+
/**
|
|
183
|
+
* One state per thing, from a closed set the strip knows how to draw. The host
|
|
184
|
+
* decides what "warn" means — an error-rate edge, a stale feed, a flaky build —
|
|
185
|
+
* and the strip only ever says it with a shape.
|
|
186
|
+
*
|
|
187
|
+
* `unknown` is a state and not the absence of one: "nothing heard from it" is
|
|
188
|
+
* a fact about the feed that a green tick would paper over, and a strip that
|
|
189
|
+
* draws an unmeasured thing as fine is the one failure it cannot afford.
|
|
190
|
+
*/
|
|
191
|
+
type StripState = "ok" | "warn" | "fail" | "unknown";
|
|
192
|
+
type StripItem = {
|
|
193
|
+
/** The name on screen. Short — it is drawn once per item across one line. */
|
|
194
|
+
key: string;
|
|
195
|
+
state: StripState;
|
|
196
|
+
/**
|
|
197
|
+
* A second, independent alarm beside the state — a build on fire next to a
|
|
198
|
+
* service that is serving fine, say. Drawn as its own mark rather than folded
|
|
199
|
+
* into `state`, because the two answer different questions and a reader
|
|
200
|
+
* needs to see when they disagree.
|
|
201
|
+
*/
|
|
202
|
+
alarm?: boolean;
|
|
203
|
+
/** Where `o` goes when this item is opened from a rail row. Unused here. */
|
|
204
|
+
url?: string;
|
|
205
|
+
};
|
|
206
|
+
type StatusStrip = {
|
|
207
|
+
/** What the row is a strip OF, in the host's words: `services`, say. */
|
|
208
|
+
title: string;
|
|
209
|
+
items: StripItem[];
|
|
210
|
+
/** When this snapshot was taken (ms). Drawn as an age at the end of the row. */
|
|
211
|
+
at?: number;
|
|
212
|
+
};
|
|
213
|
+
declare const stripGlyph: (state: StripState) => [string, string];
|
|
214
|
+
declare const ageLabel: (at: number | undefined, now?: number) => string;
|
|
215
|
+
/**
|
|
216
|
+
* The strip as plain text, at the width it has to fit. Exported so a test — or a
|
|
217
|
+
* host laying out its own row — can ask the same question the renderer asks.
|
|
218
|
+
*
|
|
219
|
+
* Wide: every item named with its mark, so the row reads as a roll call. Narrow:
|
|
220
|
+
* counts for what is fine, and names ONLY for what is not — the reader of a
|
|
221
|
+
* narrow terminal loses the roll call, never the failures. When even the
|
|
222
|
+
* failures do not fit, the worst few are named and the rest counted, so the
|
|
223
|
+
* row still says "and N more" rather than silently dropping the fourth fire.
|
|
224
|
+
*/
|
|
225
|
+
declare const stripLayout: (strip: StatusStrip, width: number, now?: number) => {
|
|
226
|
+
parts: StripItem[] | null;
|
|
227
|
+
summary: string;
|
|
228
|
+
age: string;
|
|
229
|
+
};
|
|
230
|
+
/**
|
|
231
|
+
* A standing single-line row, the same height across loading / absent / ready
|
|
232
|
+
* so the content below it never jumps — the same contract `CiStatusLine` keeps,
|
|
233
|
+
* and drawn in the same place, because a reader learns one row of glances.
|
|
234
|
+
*/
|
|
235
|
+
declare const StatusStripLine: ({ strip, label, width, now, }: {
|
|
236
|
+
/** `undefined` while the first poll is out; `null` when the host has nothing. */
|
|
237
|
+
strip: StatusStrip | null | undefined;
|
|
238
|
+
/** What to call the row before the data arrives with its own title. */
|
|
239
|
+
label?: string;
|
|
240
|
+
/** Columns the row may use. */
|
|
241
|
+
width: number;
|
|
242
|
+
now?: number;
|
|
243
|
+
}) => React.JSX.Element;
|
|
244
|
+
|
|
165
245
|
declare const renderMarkdown: (raw: string, width: number, fileLink?: (path: string, line?: number) => string) => StyledLine[];
|
|
166
246
|
|
|
167
247
|
declare const healthDisplay: Record<Health, {
|
|
@@ -234,14 +314,14 @@ type CachedCockpit = {
|
|
|
234
314
|
* rail left out of the file is a rail that does not exist until the next
|
|
235
315
|
* refresh — `i` did nothing and the footer did not even offer it.
|
|
236
316
|
*/
|
|
237
|
-
sidebar?:
|
|
317
|
+
sidebar?: Rails;
|
|
238
318
|
};
|
|
239
319
|
declare const readCache: (key: string) => CachedCockpit | null;
|
|
240
320
|
declare const writeCache: (key: string, data: {
|
|
241
321
|
sections: Section[];
|
|
242
322
|
login: string;
|
|
243
323
|
budget?: InboxBudget;
|
|
244
|
-
sidebar?:
|
|
324
|
+
sidebar?: Rails;
|
|
245
325
|
}) => void;
|
|
246
326
|
|
|
247
327
|
type DetailContext = {
|
|
@@ -422,6 +502,14 @@ type CiStatusState = {
|
|
|
422
502
|
kind: "ready";
|
|
423
503
|
status: CiStatus;
|
|
424
504
|
};
|
|
505
|
+
type StripStatusState = {
|
|
506
|
+
kind: "loading";
|
|
507
|
+
} | {
|
|
508
|
+
kind: "ready";
|
|
509
|
+
strip: StatusStrip | null;
|
|
510
|
+
};
|
|
511
|
+
/** What the strip SAYS, ignoring when it said it. */
|
|
512
|
+
declare const stripSignature: (strip: StatusStrip | null) => string;
|
|
425
513
|
declare const toCiStatusState: (status: CiStatus | null) => CiStatusState;
|
|
426
514
|
declare const sameCiStatusState: (a: CiStatusState, b: CiStatusState) => boolean;
|
|
427
515
|
declare const CiStatusLine: ({ state, job, }: {
|
|
@@ -446,7 +534,7 @@ declare const ActionMenu: ({ item, actions, cursor, }: {
|
|
|
446
534
|
cursor: number;
|
|
447
535
|
}) => React.JSX.Element;
|
|
448
536
|
declare const signatureOf: (sections: Section[]) => string;
|
|
449
|
-
declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jiraKeyRe, jiraSetupHint, jiraTransitions, hasCiStatus, ciJob, ciFetcher, ciPollMs, watchPath, watchDebounceMs, watchJitterMs, extensions, tabHelp, emptyHint, liveLabel, }: {
|
|
537
|
+
declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jiraKeyRe, jiraSetupHint, jiraTransitions, hasCiStatus, ciJob, ciFetcher, ciPollMs, stripFetcher, stripLabel, stripPollMs, watchPath, watchDebounceMs, watchJitterMs, extensions, tabHelp, emptyHint, liveLabel, }: {
|
|
450
538
|
fetcher: () => Promise<{
|
|
451
539
|
sections: Section[];
|
|
452
540
|
login: string;
|
|
@@ -466,7 +554,7 @@ declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jir
|
|
|
466
554
|
* Part of the fetch result rather than a static prop because it is data, and
|
|
467
555
|
* data that goes stale the same way the rows do.
|
|
468
556
|
*/
|
|
469
|
-
sidebar?:
|
|
557
|
+
sidebar?: Rails;
|
|
470
558
|
}>;
|
|
471
559
|
cacheKey?: string;
|
|
472
560
|
/**
|
|
@@ -490,6 +578,18 @@ declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jir
|
|
|
490
578
|
ciJob?: string;
|
|
491
579
|
ciFetcher?: () => Promise<CiStatus | null>;
|
|
492
580
|
ciPollMs?: number;
|
|
581
|
+
/**
|
|
582
|
+
* A standing status strip under the CI line — one row of things and the
|
|
583
|
+
* state each is in, polled on its own timer like the CI line and for the
|
|
584
|
+
* same reason: it is a glance at something that moves on its own schedule.
|
|
585
|
+
* Wiring a fetcher reserves the row; leaving it out draws nothing. `null`
|
|
586
|
+
* from the fetcher means "nothing configured" and is drawn as such, while a
|
|
587
|
+
* rejected poll keeps the last strip up.
|
|
588
|
+
*/
|
|
589
|
+
stripFetcher?: () => Promise<StatusStrip | null>;
|
|
590
|
+
/** What to call the row before its first answer arrives with a title. */
|
|
591
|
+
stripLabel?: string;
|
|
592
|
+
stripPollMs?: number;
|
|
493
593
|
/**
|
|
494
594
|
* A file something else touches when it has changed GitHub on your behalf —
|
|
495
595
|
* a Claude session closing an issue, a script merging a PR. Touching it makes
|
|
@@ -529,4 +629,4 @@ declare const matchesFilter: (repo: string, filter: RepoFilter) => boolean;
|
|
|
529
629
|
*/
|
|
530
630
|
declare const parsePatterns: (value: string) => string[];
|
|
531
631
|
|
|
532
|
-
export { type Action, ActionMenu, App, COLS, CiStatusLine, type CiStatusState, type Command, 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 };
|
|
632
|
+
export { type Action, ActionMenu, App, COLS, CiStatusLine, type CiStatusState, type Command, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxExtension, type JiraTransition, type LiveLabel, MIN_SIDEBAR_COLS, type Rails, type RepoFilter, SIDEBAR_COLS, SidePanel, type Sidebar, type SidebarRow, type StatusStrip, StatusStripLine, type StripItem, type StripState, type StripStatusState, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, railCapacity, railHeights, railRowsOf, railWidth, railsOf, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, signatureOf, stripGlyph, stripLayout, stripSignature, toCiStatusState, truncate, useActionMenu, windowCount, withHeaders, withoutItem, workCount, writeCache };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React2, { createContext, useState, useRef, useEffect, useMemo, useContext } from 'react';
|
|
2
2
|
import { useWindowSize, useInput, Text, Box } from 'ink';
|
|
3
|
-
import { colors, ScrollView, TextInput, useAppKeys, LoadingScreen,
|
|
3
|
+
import { colors, ScrollView, TextInput, useAppKeys, LoadingScreen, StatusMessage, FooterHints, useListCursor, CommandPalette, Tabs, ProgressBar, 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';
|
|
@@ -634,15 +634,28 @@ var Progress = ({ row }) => {
|
|
|
634
634
|
/* @__PURE__ */ jsx(Text, { color: colors.secondary, children: GUTTER + fraction.padStart(FRACTION_COLS) })
|
|
635
635
|
] });
|
|
636
636
|
};
|
|
637
|
-
var
|
|
637
|
+
var railsOf = (rails) => rails === void 0 ? [] : Array.isArray(rails) ? rails : [rails];
|
|
638
|
+
var railRowsOf = (rails) => railsOf(rails).flatMap((s) => s.rows);
|
|
639
|
+
var linesFor = (rows) => HEADING_LINES + Math.max(1, rows) * ROW_LINES;
|
|
640
|
+
var railHeights = (height, rowCounts) => {
|
|
641
|
+
const out = [];
|
|
642
|
+
let remaining = height;
|
|
643
|
+
rowCounts.forEach((rows, i) => {
|
|
644
|
+
const share = Math.floor(remaining / (rowCounts.length - i));
|
|
645
|
+
const h = Math.min(share, linesFor(rows));
|
|
646
|
+
out.push(h);
|
|
647
|
+
remaining -= h;
|
|
648
|
+
});
|
|
649
|
+
return out;
|
|
650
|
+
};
|
|
651
|
+
var RailSection = ({
|
|
638
652
|
sidebar,
|
|
639
|
-
liveLabel
|
|
640
|
-
|
|
653
|
+
liveLabel,
|
|
654
|
+
content,
|
|
641
655
|
height,
|
|
642
|
-
focused
|
|
643
|
-
cursor
|
|
656
|
+
focused,
|
|
657
|
+
cursor
|
|
644
658
|
}) => {
|
|
645
|
-
const content = contentOf(width);
|
|
646
659
|
const labelCols = content - MARKS;
|
|
647
660
|
const liveCols = content - FACTS_FIXED;
|
|
648
661
|
const capacity = height === void 0 ? sidebar.rows.length : railCapacity(height, sidebar.rows.length);
|
|
@@ -653,6 +666,46 @@ var SidePanel = ({
|
|
|
653
666
|
const rule = "\u254C".repeat(
|
|
654
667
|
Math.max(0, content - [...sidebar.title].length - focus.length - 1)
|
|
655
668
|
);
|
|
669
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", height, children: [
|
|
670
|
+
/* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
671
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: sidebar.title }),
|
|
672
|
+
focused ? /* @__PURE__ */ jsx(Text, { color: colors.accent, children: focus }) : null,
|
|
673
|
+
/* @__PURE__ */ jsx(Text, { color: colors.info, dimColor: true, children: ` ${rule}` })
|
|
674
|
+
] }),
|
|
675
|
+
sidebar.rows.length === 0 ? /* @__PURE__ */ jsx(Box, { paddingLeft: MARKS, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: "nothing open" }) }) : shown.map((row, i) => {
|
|
676
|
+
const active = focused && start + i === cursor;
|
|
677
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
678
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
679
|
+
/* @__PURE__ */ jsx(Text, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
680
|
+
/* @__PURE__ */ jsx(Text, { color: colors.accent, bold: true, children: row.wantsYou ? "\u2190 " : " " }),
|
|
681
|
+
/* @__PURE__ */ jsx(Text, { bold: active, children: truncateWords(row.label, labelCols) })
|
|
682
|
+
] }),
|
|
683
|
+
/* @__PURE__ */ jsxs(Box, { children: [
|
|
684
|
+
/* @__PURE__ */ jsx(Text, { color: row.markerColor, children: " ".repeat(FACTS_INDENT - 2) + (row.marker ?? " ") + " " }),
|
|
685
|
+
/* @__PURE__ */ jsx(Text, { color: colors.secondary, children: row.key.padEnd(KEY_COLS) + GUTTER }),
|
|
686
|
+
/* @__PURE__ */ jsx(Progress, { row }),
|
|
687
|
+
/* @__PURE__ */ jsx(Text, { children: GUTTER + (row.live !== void 0 ? liveLabel(row.live).slice(0, liveCols) : "") })
|
|
688
|
+
] })
|
|
689
|
+
] }, row.key);
|
|
690
|
+
}),
|
|
691
|
+
hidden > 0 ? /* @__PURE__ */ jsx(Box, { paddingLeft: MARKS, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: `+${hidden} more` }) }) : null
|
|
692
|
+
] });
|
|
693
|
+
};
|
|
694
|
+
var SidePanel = ({
|
|
695
|
+
sidebar,
|
|
696
|
+
liveLabel = defaultLiveLabel,
|
|
697
|
+
width = SIDEBAR_COLS,
|
|
698
|
+
height,
|
|
699
|
+
focused = false,
|
|
700
|
+
cursor = 0
|
|
701
|
+
}) => {
|
|
702
|
+
const content = contentOf(width);
|
|
703
|
+
const sections = railsOf(sidebar);
|
|
704
|
+
const heights = height === void 0 ? sections.map(() => void 0) : railHeights(
|
|
705
|
+
height,
|
|
706
|
+
sections.map((s) => s.rows.length)
|
|
707
|
+
);
|
|
708
|
+
let offset = 0;
|
|
656
709
|
return (
|
|
657
710
|
// A rule down the left rather than a full box: the rail's other three edges
|
|
658
711
|
// already have the frame's border a column or two away, and a second
|
|
@@ -660,7 +713,7 @@ var SidePanel = ({
|
|
|
660
713
|
// focus and act on, which this cannot be. One line is the whole claim: what
|
|
661
714
|
// is left of it is the list, what is right of it is not. In the frame's own
|
|
662
715
|
// colour and not dimmed, so the two rules read as one hierarchy.
|
|
663
|
-
/* @__PURE__ */
|
|
716
|
+
/* @__PURE__ */ jsx(
|
|
664
717
|
Box,
|
|
665
718
|
{
|
|
666
719
|
flexDirection: "column",
|
|
@@ -673,34 +726,113 @@ var SidePanel = ({
|
|
|
673
726
|
borderRight: false,
|
|
674
727
|
borderBottom: false,
|
|
675
728
|
paddingLeft: PAD,
|
|
676
|
-
children:
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
/* @__PURE__ */ jsx(Text, { children: GUTTER + (row.live !== void 0 ? liveLabel(row.live).slice(0, liveCols) : "") })
|
|
695
|
-
] })
|
|
696
|
-
] }, row.key);
|
|
697
|
-
}),
|
|
698
|
-
hidden > 0 ? /* @__PURE__ */ jsx(Box, { paddingLeft: MARKS, children: /* @__PURE__ */ jsx(Text, { color: colors.muted, children: `+${hidden} more` }) }) : null
|
|
699
|
-
]
|
|
729
|
+
children: sections.map((section, i) => {
|
|
730
|
+
const first = offset;
|
|
731
|
+
offset += section.rows.length;
|
|
732
|
+
const inside = focused && cursor >= first && cursor < offset;
|
|
733
|
+
const owns = inside || focused && sections.length === 1;
|
|
734
|
+
return /* @__PURE__ */ jsx(
|
|
735
|
+
RailSection,
|
|
736
|
+
{
|
|
737
|
+
sidebar: section,
|
|
738
|
+
liveLabel,
|
|
739
|
+
content,
|
|
740
|
+
height: heights[i],
|
|
741
|
+
focused: owns,
|
|
742
|
+
cursor: cursor - first
|
|
743
|
+
},
|
|
744
|
+
section.title
|
|
745
|
+
);
|
|
746
|
+
})
|
|
700
747
|
}
|
|
701
748
|
)
|
|
702
749
|
);
|
|
703
750
|
};
|
|
751
|
+
var stripGlyph = (state) => {
|
|
752
|
+
switch (state) {
|
|
753
|
+
case "ok":
|
|
754
|
+
return ["\u2713", colors.success];
|
|
755
|
+
case "warn":
|
|
756
|
+
return ["!", colors.warning];
|
|
757
|
+
case "fail":
|
|
758
|
+
return ["\u2717", colors.error];
|
|
759
|
+
case "unknown":
|
|
760
|
+
return ["\u25CB", colors.muted];
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
var ALARM = "\u25B2";
|
|
764
|
+
var SEVERITY = {
|
|
765
|
+
fail: 0,
|
|
766
|
+
warn: 1,
|
|
767
|
+
unknown: 2,
|
|
768
|
+
ok: 3
|
|
769
|
+
};
|
|
770
|
+
var ageLabel = (at, now = Date.now()) => {
|
|
771
|
+
if (at === void 0) return "";
|
|
772
|
+
const s = Math.max(0, Math.round((now - at) / 1e3));
|
|
773
|
+
if (s < 60) return `${s}s`;
|
|
774
|
+
const m = Math.round(s / 60);
|
|
775
|
+
if (m < 60) return `${m}m`;
|
|
776
|
+
return `${Math.round(m / 60)}h`;
|
|
777
|
+
};
|
|
778
|
+
var itemText = (item) => `${stripGlyph(item.state)[0]} ${item.key}${item.alarm ? ALARM : ""}`;
|
|
779
|
+
var stripLayout = (strip, width, now = Date.now()) => {
|
|
780
|
+
const age = ageLabel(strip.at, now);
|
|
781
|
+
const fixed = 2 + strip.title.length + 2 + (age ? age.length + 3 : 0);
|
|
782
|
+
const full = strip.items.map(itemText).join(" ");
|
|
783
|
+
if (fixed + full.length <= width)
|
|
784
|
+
return { parts: strip.items, summary: full, age };
|
|
785
|
+
const sorted = [...strip.items].sort(
|
|
786
|
+
(a, b) => SEVERITY[a.state] - SEVERITY[b.state]
|
|
787
|
+
);
|
|
788
|
+
const bad = sorted.filter((i) => i.state !== "ok" || i.alarm);
|
|
789
|
+
const ok = strip.items.length - bad.length;
|
|
790
|
+
const tally = (n, s) => n > 0 ? `${n} ${stripGlyph(s)[0]}` : "";
|
|
791
|
+
let named = [];
|
|
792
|
+
let text = "";
|
|
793
|
+
for (let n = bad.length; n >= 0; n--) {
|
|
794
|
+
named = bad.slice(0, n);
|
|
795
|
+
const rest = bad.slice(n);
|
|
796
|
+
const counts2 = ["fail", "warn", "unknown"].map((s) => tally(rest.filter((i) => i.state === s).length, s)).filter(Boolean);
|
|
797
|
+
text = [tally(ok, "ok"), ...counts2, ...named.map(itemText)].filter(Boolean).join(" \xB7 ");
|
|
798
|
+
if (fixed + text.length <= width) break;
|
|
799
|
+
}
|
|
800
|
+
return { parts: null, summary: text, age };
|
|
801
|
+
};
|
|
802
|
+
var StatusStripLine = ({
|
|
803
|
+
strip,
|
|
804
|
+
label = "status",
|
|
805
|
+
width,
|
|
806
|
+
now
|
|
807
|
+
}) => {
|
|
808
|
+
if (strip === void 0)
|
|
809
|
+
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
810
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \xB7 " }),
|
|
811
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${label} loading\u2026` })
|
|
812
|
+
] });
|
|
813
|
+
if (strip === null)
|
|
814
|
+
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
815
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: " \u25CB " }),
|
|
816
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: `${label} no signal / not configured` })
|
|
817
|
+
] });
|
|
818
|
+
const { parts, summary, age } = stripLayout(strip, width, now);
|
|
819
|
+
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
820
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${strip.title} ` }),
|
|
821
|
+
parts ? parts.map((item, i) => {
|
|
822
|
+
const [glyph, color] = stripGlyph(item.state);
|
|
823
|
+
return /* @__PURE__ */ jsxs(React2.Fragment, { children: [
|
|
824
|
+
i > 0 ? /* @__PURE__ */ jsx(Text, { children: " " }) : null,
|
|
825
|
+
/* @__PURE__ */ jsx(Text, { color, bold: true, children: glyph }),
|
|
826
|
+
/* @__PURE__ */ jsxs(Text, { children: [
|
|
827
|
+
" ",
|
|
828
|
+
item.key
|
|
829
|
+
] }),
|
|
830
|
+
item.alarm ? /* @__PURE__ */ jsx(Text, { color: colors.error, bold: true, children: ALARM }) : null
|
|
831
|
+
] }, item.key);
|
|
832
|
+
}) : /* @__PURE__ */ jsx(Text, { children: summary }),
|
|
833
|
+
age ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: ` ${age}` }) : null
|
|
834
|
+
] });
|
|
835
|
+
};
|
|
704
836
|
var healthDisplay = {
|
|
705
837
|
none: { glyph: " ", color: colors.muted },
|
|
706
838
|
draft: { glyph: "~", color: colors.muted },
|
|
@@ -749,7 +881,7 @@ var displayFor = (h) => h ? healthDisplay[h] : UNREAD_DISPLAY;
|
|
|
749
881
|
|
|
750
882
|
// src/inbox/cache.ts
|
|
751
883
|
var cacheTtlMs = () => inboxConfig().cacheTtlMs;
|
|
752
|
-
var CACHE_VERSION =
|
|
884
|
+
var CACHE_VERSION = 5;
|
|
753
885
|
var cacheDir = () => join(
|
|
754
886
|
process.env.XDG_CACHE_HOME || join(homedir(), ".cache"),
|
|
755
887
|
inboxConfig().cacheNamespace
|
|
@@ -765,7 +897,7 @@ var readCache = (key) => {
|
|
|
765
897
|
login: raw.login ?? "",
|
|
766
898
|
at: raw.at ?? 0,
|
|
767
899
|
budget: raw.budget,
|
|
768
|
-
...Array.isArray(
|
|
900
|
+
...railsOf(raw.sidebar).every((s) => Array.isArray(s?.rows)) && raw.sidebar !== void 0 ? { sidebar: raw.sidebar } : {}
|
|
769
901
|
};
|
|
770
902
|
} catch {
|
|
771
903
|
return null;
|
|
@@ -1059,9 +1191,7 @@ var turnSentences = (item, login) => {
|
|
|
1059
1191
|
return [`${item.lastActor} spoke last (\u2190), ${when}. Your reply is owed.`];
|
|
1060
1192
|
const them = item.author && item.author !== login ? item.author : null;
|
|
1061
1193
|
if (!them)
|
|
1062
|
-
return [
|
|
1063
|
-
`You spoke last, ${when}. It is waiting on a reviewer, not on you.`
|
|
1064
|
-
];
|
|
1194
|
+
return [`You spoke last, ${when}. It is waiting on a reviewer, not on you.`];
|
|
1065
1195
|
const lines = [`You spoke last, ${when}. The ball is with ${them}.`];
|
|
1066
1196
|
if (d?.lastCommitAt && d.lastEventAt && d.lastCommitAt < d.lastEventAt)
|
|
1067
1197
|
lines.push(
|
|
@@ -1440,7 +1570,7 @@ var backdropStyle = (props) => ({
|
|
|
1440
1570
|
inverse: false,
|
|
1441
1571
|
backgroundColor: void 0
|
|
1442
1572
|
});
|
|
1443
|
-
var
|
|
1573
|
+
var Text4 = ({ children, ...props }) => {
|
|
1444
1574
|
const dimmed = useContext(DimContext);
|
|
1445
1575
|
return dimmed ? /* @__PURE__ */ jsx(Text, { ...props, ...backdropStyle(props), children }) : /* @__PURE__ */ jsx(Text, { ...props, children });
|
|
1446
1576
|
};
|
|
@@ -1836,13 +1966,13 @@ var InboxHeader = ({
|
|
|
1836
1966
|
COLS - brand.length - countSeg.length - userSeg.length - workLabel.length - budgetSeg.length - statusSeg.length
|
|
1837
1967
|
);
|
|
1838
1968
|
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
1839
|
-
/* @__PURE__ */ jsx(
|
|
1840
|
-
/* @__PURE__ */ jsx(
|
|
1841
|
-
userSeg ? /* @__PURE__ */ jsx(
|
|
1842
|
-
scopeLabel ? /* @__PURE__ */ jsx(
|
|
1843
|
-
budgetLabel ? /* @__PURE__ */ jsx(
|
|
1969
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.accent, bold: true, children: brand }),
|
|
1970
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: countSeg }),
|
|
1971
|
+
userSeg ? /* @__PURE__ */ jsx(Text4, { children: userSeg }) : null,
|
|
1972
|
+
scopeLabel ? /* @__PURE__ */ jsx(Text4, { dimColor: true, children: workLabel }) : null,
|
|
1973
|
+
budgetLabel ? /* @__PURE__ */ jsx(Text4, { bold: true, color: budgetCritical ? "#FF5F5F" : colors.accent, children: budgetSeg }) : null,
|
|
1844
1974
|
statusText ? /* @__PURE__ */ jsx(
|
|
1845
|
-
|
|
1975
|
+
Text4,
|
|
1846
1976
|
{
|
|
1847
1977
|
color: statusColor,
|
|
1848
1978
|
dimColor: !statusColor,
|
|
@@ -1850,9 +1980,10 @@ var InboxHeader = ({
|
|
|
1850
1980
|
children: statusSeg
|
|
1851
1981
|
}
|
|
1852
1982
|
) : null,
|
|
1853
|
-
/* @__PURE__ */ jsx(
|
|
1983
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, dimColor: true, children: "\u254C".repeat(fill) })
|
|
1854
1984
|
] });
|
|
1855
1985
|
};
|
|
1986
|
+
var stripSignature = (strip) => strip === null ? "\u2205" : strip.items.map((i) => `${i.key}=${i.state}${i.alarm ? "\u25B2" : ""}`).join(",");
|
|
1856
1987
|
var toCiStatusState = (status) => status ? { kind: "ready", status } : { kind: "error" };
|
|
1857
1988
|
var sameCiStatusState = (a, b) => {
|
|
1858
1989
|
if (a.kind !== b.kind) return false;
|
|
@@ -1873,24 +2004,24 @@ var CiStatusLine = ({
|
|
|
1873
2004
|
const name = job ?? "ci";
|
|
1874
2005
|
if (state.kind === "loading")
|
|
1875
2006
|
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
1876
|
-
/* @__PURE__ */ jsx(
|
|
1877
|
-
/* @__PURE__ */ jsx(
|
|
2007
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: " \xB7 " }),
|
|
2008
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: `${name} loading\u2026` })
|
|
1878
2009
|
] });
|
|
1879
2010
|
if (state.kind === "error")
|
|
1880
2011
|
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
1881
|
-
/* @__PURE__ */ jsx(
|
|
1882
|
-
/* @__PURE__ */ jsx(
|
|
2012
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.error, bold: true, children: " \u2717 " }),
|
|
2013
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: `${name} no build / not configured` })
|
|
1883
2014
|
] });
|
|
1884
2015
|
const { status } = state;
|
|
1885
2016
|
const [, color] = jenkinsResultDisplay(status.result, status.building);
|
|
1886
2017
|
const label = status.building ? "BUILDING" : status.result;
|
|
1887
2018
|
return /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
1888
|
-
/* @__PURE__ */ jsx(
|
|
1889
|
-
/* @__PURE__ */ jsx(
|
|
1890
|
-
/* @__PURE__ */ jsx(
|
|
1891
|
-
/* @__PURE__ */ jsx(
|
|
1892
|
-
/* @__PURE__ */ jsx(
|
|
1893
|
-
status.age ? /* @__PURE__ */ jsx(
|
|
2019
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: " " }),
|
|
2020
|
+
/* @__PURE__ */ jsx(Text4, { color, bold: true, children: "\u25CF " }),
|
|
2021
|
+
/* @__PURE__ */ jsx(Text4, { bold: true, children: status.job }),
|
|
2022
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: " " + label }),
|
|
2023
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.accent, children: " #" + status.buildNumber }),
|
|
2024
|
+
status.age ? /* @__PURE__ */ jsx(Text4, { dimColor: true, children: " " + status.age }) : null
|
|
1894
2025
|
] });
|
|
1895
2026
|
};
|
|
1896
2027
|
var FENCE_COLS = 46;
|
|
@@ -1903,10 +2034,10 @@ var RepoHeaderRow = ({
|
|
|
1903
2034
|
const fill = Math.max(4, FENCE_COLS - label.length);
|
|
1904
2035
|
const rule = "\u2500".repeat(fill);
|
|
1905
2036
|
return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
|
|
1906
|
-
/* @__PURE__ */ jsx(
|
|
1907
|
-
/* @__PURE__ */ jsx(
|
|
2037
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
2038
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: !active, children: "\u2500\u2500 " }),
|
|
1908
2039
|
/* @__PURE__ */ jsx(
|
|
1909
|
-
|
|
2040
|
+
Text4,
|
|
1910
2041
|
{
|
|
1911
2042
|
dimColor: false,
|
|
1912
2043
|
color: active ? void 0 : colors.secondary,
|
|
@@ -1914,7 +2045,7 @@ var RepoHeaderRow = ({
|
|
|
1914
2045
|
children: repo
|
|
1915
2046
|
}
|
|
1916
2047
|
),
|
|
1917
|
-
/* @__PURE__ */ jsx(
|
|
2048
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: !active, children: " " + rule })
|
|
1918
2049
|
] });
|
|
1919
2050
|
};
|
|
1920
2051
|
var MERGED_HOLD_MS = 3e3;
|
|
@@ -1979,22 +2110,22 @@ var ItemRow = ({
|
|
|
1979
2110
|
return /* @__PURE__ */ jsx(RepoHeaderRow, { repo: item.repo, gap: gap ?? false, active });
|
|
1980
2111
|
if (item.kind === "subgroup-header")
|
|
1981
2112
|
return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
|
|
1982
|
-
/* @__PURE__ */ jsx(
|
|
1983
|
-
/* @__PURE__ */ jsx(
|
|
2113
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.accent, bold: true, children: " \xBB " }),
|
|
2114
|
+
/* @__PURE__ */ jsx(Text4, { bold: true, children: item.label })
|
|
1984
2115
|
] });
|
|
1985
2116
|
if (item.kind === "show-more")
|
|
1986
2117
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1987
|
-
/* @__PURE__ */ jsx(
|
|
1988
|
-
/* @__PURE__ */ jsx(
|
|
1989
|
-
/* @__PURE__ */ jsx(
|
|
1990
|
-
/* @__PURE__ */ jsx(
|
|
2118
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
2119
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: prefix }),
|
|
2120
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: active ? "\u21B5 " : " " }),
|
|
2121
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: `+${item.hidden.length} more` })
|
|
1991
2122
|
] });
|
|
1992
2123
|
if (item.kind === "show-less")
|
|
1993
2124
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
1994
|
-
/* @__PURE__ */ jsx(
|
|
1995
|
-
/* @__PURE__ */ jsx(
|
|
1996
|
-
/* @__PURE__ */ jsx(
|
|
1997
|
-
/* @__PURE__ */ jsx(
|
|
2125
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
2126
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: prefix }),
|
|
2127
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: active ? "\u21B5 " : " " }),
|
|
2128
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: "show less" })
|
|
1998
2129
|
] });
|
|
1999
2130
|
if (item.kind === "task") {
|
|
2000
2131
|
const note = item.note ?? "";
|
|
@@ -2004,14 +2135,14 @@ var ItemRow = ({
|
|
|
2004
2135
|
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
|
|
2005
2136
|
);
|
|
2006
2137
|
return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
|
|
2007
|
-
/* @__PURE__ */ jsx(
|
|
2008
|
-
/* @__PURE__ */ jsx(
|
|
2009
|
-
/* @__PURE__ */ jsx(
|
|
2010
|
-
/* @__PURE__ */ jsx(
|
|
2011
|
-
markerCols > 0 ? /* @__PURE__ */ jsx(
|
|
2012
|
-
/* @__PURE__ */ jsx(
|
|
2138
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
2139
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: prefix }),
|
|
2140
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: parent ? "\u252C " : " " }),
|
|
2141
|
+
/* @__PURE__ */ jsx(Text4, { bold: true, color: transient ? TRANSIT_COLOUR[transient] : void 0, children: transitIcon + " " }),
|
|
2142
|
+
markerCols > 0 ? /* @__PURE__ */ jsx(Text4, { color: item.markerColor, children: (item.marker ?? "").padEnd(markerCols) + " " }) : null,
|
|
2143
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.accent, bold: active, children: item.key + " " }),
|
|
2013
2144
|
/* @__PURE__ */ jsx(
|
|
2014
|
-
|
|
2145
|
+
Text4,
|
|
2015
2146
|
{
|
|
2016
2147
|
bold: active || !!transient && isArrival(transient),
|
|
2017
2148
|
dimColor: !!transient && isDeparture(transient),
|
|
@@ -2020,7 +2151,7 @@ var ItemRow = ({
|
|
|
2020
2151
|
}
|
|
2021
2152
|
),
|
|
2022
2153
|
item.pill && !backdropped ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2023
|
-
/* @__PURE__ */ jsx(
|
|
2154
|
+
/* @__PURE__ */ jsx(Text4, { children: " " }),
|
|
2024
2155
|
/* @__PURE__ */ jsx(
|
|
2025
2156
|
Pill,
|
|
2026
2157
|
{
|
|
@@ -2031,9 +2162,9 @@ var ItemRow = ({
|
|
|
2031
2162
|
}
|
|
2032
2163
|
)
|
|
2033
2164
|
] }) : null,
|
|
2034
|
-
note ? /* @__PURE__ */ jsx(
|
|
2165
|
+
note ? /* @__PURE__ */ jsx(Text4, { dimColor: true, children: ` ${note}` }) : null,
|
|
2035
2166
|
farewellLabel && !backdropped ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2036
|
-
/* @__PURE__ */ jsx(
|
|
2167
|
+
/* @__PURE__ */ jsx(Text4, { children: " " }),
|
|
2037
2168
|
/* @__PURE__ */ jsx(Pill, { color: TRANSIT_COLOUR.out, children: farewellLabel })
|
|
2038
2169
|
] }) : null
|
|
2039
2170
|
] });
|
|
@@ -2049,7 +2180,7 @@ var ItemRow = ({
|
|
|
2049
2180
|
const sizeParts = sizePartsOf(item);
|
|
2050
2181
|
const unresolvedLabel = item.unresolved > 0 ? `\uF086 ${item.unresolved}` : "";
|
|
2051
2182
|
const agePair = item.activityAge && item.activityAge !== item.age ? { activity: item.activityAge, lifetime: item.age } : null;
|
|
2052
|
-
const
|
|
2183
|
+
const ageLabel2 = agePair ? `${agePair.activity} (${agePair.lifetime})` : item.age;
|
|
2053
2184
|
const mergedLabel = merged ? "merged" : "";
|
|
2054
2185
|
const pillCaps = [mergedLabel, farewellLabel].filter(Boolean).length * 2;
|
|
2055
2186
|
const repoLabel = depthOf(item) > 0 ? item.repo : "";
|
|
@@ -2082,7 +2213,7 @@ var ItemRow = ({
|
|
|
2082
2213
|
};
|
|
2083
2214
|
const widthOf2 = () => {
|
|
2084
2215
|
const suffix = [
|
|
2085
|
-
givingUp.age ? "" :
|
|
2216
|
+
givingUp.age ? "" : ageLabel2 || "",
|
|
2086
2217
|
// ASCII only, so no PUA double-width correction — see the label cell.
|
|
2087
2218
|
givingUp.size ? "" : sizeLabel || "",
|
|
2088
2219
|
givingUp.threads ? "" : unresolvedLabel,
|
|
@@ -2108,13 +2239,13 @@ var ItemRow = ({
|
|
|
2108
2239
|
const labelLabel = labelCell();
|
|
2109
2240
|
const titleMax = Math.max(1, cols - widthOf2());
|
|
2110
2241
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
2111
|
-
/* @__PURE__ */ jsx(
|
|
2112
|
-
/* @__PURE__ */ jsx(
|
|
2113
|
-
/* @__PURE__ */ jsx(
|
|
2114
|
-
/* @__PURE__ */ jsx(
|
|
2115
|
-
/* @__PURE__ */ jsx(
|
|
2242
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
2243
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: prefix }),
|
|
2244
|
+
/* @__PURE__ */ jsx(Text4, { color, bold: true, children: icon + " " }),
|
|
2245
|
+
/* @__PURE__ */ jsx(Text4, { color: turnColor, bold: turnIcon === "\u2190", children: turnIcon + " " }),
|
|
2246
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.accent, children: numStr }),
|
|
2116
2247
|
/* @__PURE__ */ jsx(
|
|
2117
|
-
|
|
2248
|
+
Text4,
|
|
2118
2249
|
{
|
|
2119
2250
|
bold: active || !!transient && isArrival(transient),
|
|
2120
2251
|
dimColor: !!transient && isDeparture(transient),
|
|
@@ -2122,33 +2253,33 @@ var ItemRow = ({
|
|
|
2122
2253
|
children: truncate(item.title, titleMax) + " "
|
|
2123
2254
|
}
|
|
2124
2255
|
),
|
|
2125
|
-
labelLabel ? /* @__PURE__ */ jsx(
|
|
2126
|
-
repoLabel && !givingUp.repo ? /* @__PURE__ */ jsx(
|
|
2127
|
-
sizeParts && !givingUp.size ? /* @__PURE__ */ jsxs(
|
|
2256
|
+
labelLabel ? /* @__PURE__ */ jsx(Text4, { color: colors.secondary, children: labelLabel + " " }) : null,
|
|
2257
|
+
repoLabel && !givingUp.repo ? /* @__PURE__ */ jsx(Text4, { dimColor: true, children: repoLabel }) : null,
|
|
2258
|
+
sizeParts && !givingUp.size ? /* @__PURE__ */ jsxs(Text4, { children: [
|
|
2128
2259
|
" ",
|
|
2129
|
-
/* @__PURE__ */ jsx(
|
|
2260
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.success, children: sizeParts.added }),
|
|
2130
2261
|
" ",
|
|
2131
|
-
/* @__PURE__ */ jsx(
|
|
2262
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.error, children: sizeParts.removed })
|
|
2132
2263
|
] }) : null,
|
|
2133
2264
|
unresolvedLabel && !givingUp.threads ? /* @__PURE__ */ jsx(
|
|
2134
|
-
|
|
2265
|
+
Text4,
|
|
2135
2266
|
{
|
|
2136
2267
|
bold: !spokeLast,
|
|
2137
2268
|
color: spokeLast ? colors.secondary : colors.accent,
|
|
2138
2269
|
children: " " + unresolvedLabel
|
|
2139
2270
|
}
|
|
2140
2271
|
) : null,
|
|
2141
|
-
showAuthor && !givingUp.author ? /* @__PURE__ */ jsx(
|
|
2142
|
-
|
|
2143
|
-
/* @__PURE__ */ jsx(
|
|
2144
|
-
/* @__PURE__ */ jsx(
|
|
2145
|
-
] }) : /* @__PURE__ */ jsx(
|
|
2272
|
+
showAuthor && !givingUp.author ? /* @__PURE__ */ jsx(Text4, { dimColor: true, italic: true, children: " by " + item.author }) : null,
|
|
2273
|
+
ageLabel2 && !givingUp.age ? agePair ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2274
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.secondary, children: " " + agePair.activity }),
|
|
2275
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: ` (${agePair.lifetime})` })
|
|
2276
|
+
] }) : /* @__PURE__ */ jsx(Text4, { color: colors.secondary, children: " " + ageLabel2 }) : null,
|
|
2146
2277
|
mergedLabel && !backdropped ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2147
|
-
/* @__PURE__ */ jsx(
|
|
2278
|
+
/* @__PURE__ */ jsx(Text4, { children: " " }),
|
|
2148
2279
|
/* @__PURE__ */ jsx(Pill, { color: MERGED_COLOUR, children: mergedLabel })
|
|
2149
2280
|
] }) : null,
|
|
2150
2281
|
farewellLabel && !backdropped ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2151
|
-
/* @__PURE__ */ jsx(
|
|
2282
|
+
/* @__PURE__ */ jsx(Text4, { children: " " }),
|
|
2152
2283
|
/* @__PURE__ */ jsx(Pill, { color: TRANSIT_COLOUR.out, children: farewellLabel })
|
|
2153
2284
|
] }) : null
|
|
2154
2285
|
] });
|
|
@@ -2196,15 +2327,15 @@ var ActionMenu = ({
|
|
|
2196
2327
|
paddingX: 1,
|
|
2197
2328
|
marginTop: 1,
|
|
2198
2329
|
children: [
|
|
2199
|
-
/* @__PURE__ */ jsx(
|
|
2200
|
-
/* @__PURE__ */ jsx(
|
|
2330
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, bold: true, children: title }),
|
|
2331
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: "\u2500".repeat(32) }),
|
|
2201
2332
|
actions.map((a, i) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
2202
|
-
/* @__PURE__ */ jsx(
|
|
2203
|
-
/* @__PURE__ */ jsx(
|
|
2204
|
-
/* @__PURE__ */ jsx(
|
|
2333
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, children: i === cursor ? "\u276F " : " " }),
|
|
2334
|
+
/* @__PURE__ */ jsx(Text4, { bold: i === cursor, children: a.label }),
|
|
2335
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: " " + a.hint })
|
|
2205
2336
|
] }, a.label)),
|
|
2206
|
-
/* @__PURE__ */ jsx(
|
|
2207
|
-
/* @__PURE__ */ jsx(
|
|
2337
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: "\u2500".repeat(32) }),
|
|
2338
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: "\u2191\u2193 navigate \u21B5 confirm esc cancel" })
|
|
2208
2339
|
]
|
|
2209
2340
|
}
|
|
2210
2341
|
);
|
|
@@ -2252,11 +2383,11 @@ var LegendGroup = ({
|
|
|
2252
2383
|
width,
|
|
2253
2384
|
marginRight
|
|
2254
2385
|
}) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width, marginRight, children: [
|
|
2255
|
-
pinned !== void 0 ? /* @__PURE__ */ jsx(
|
|
2386
|
+
pinned !== void 0 ? /* @__PURE__ */ jsx(Text4, { bold: true, dimColor: true, children: pinned ?? " " }) : null,
|
|
2256
2387
|
lines.map(
|
|
2257
|
-
(line, index) => line.kind === "gap" ? /* @__PURE__ */ jsx(
|
|
2258
|
-
/* @__PURE__ */ jsx(
|
|
2259
|
-
/* @__PURE__ */ jsx(
|
|
2388
|
+
(line, index) => line.kind === "gap" ? /* @__PURE__ */ jsx(Text4, { children: " " }, index) : line.kind === "title" ? /* @__PURE__ */ jsx(Text4, { bold: true, dimColor: true, children: line.text }, index) : /* @__PURE__ */ jsxs(Box, { children: [
|
|
2389
|
+
/* @__PURE__ */ jsx(Text4, { color: line.row.color, bold: line.row.bold, children: line.row.cell.padEnd(line.cellWidth) }),
|
|
2390
|
+
/* @__PURE__ */ jsx(Text4, { wrap: "truncate-end", children: line.row.label })
|
|
2260
2391
|
] }, index)
|
|
2261
2392
|
)
|
|
2262
2393
|
] });
|
|
@@ -2377,8 +2508,8 @@ var HelpModal = ({
|
|
|
2377
2508
|
width: contentWidth + MODAL_CHROME_COLS,
|
|
2378
2509
|
children: [
|
|
2379
2510
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
2380
|
-
/* @__PURE__ */ jsx(
|
|
2381
|
-
scrollable ? /* @__PURE__ */ jsx(
|
|
2511
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, bold: true, children: "Legend" }),
|
|
2512
|
+
scrollable ? /* @__PURE__ */ jsx(Text4, { dimColor: true, children: ` ${offset + 1}\u2013${offset + shown} of ${totalRows}` }) : null
|
|
2382
2513
|
] }),
|
|
2383
2514
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, width: contentWidth, children: groups.map((group, index) => /* @__PURE__ */ jsx(
|
|
2384
2515
|
LegendGroup,
|
|
@@ -2390,8 +2521,8 @@ var HelpModal = ({
|
|
|
2390
2521
|
},
|
|
2391
2522
|
group[0]?.title ?? index
|
|
2392
2523
|
)) }),
|
|
2393
|
-
tabHelp && !scrollable ? /* @__PURE__ */ jsx(
|
|
2394
|
-
/* @__PURE__ */ jsx(
|
|
2524
|
+
tabHelp && !scrollable ? /* @__PURE__ */ jsx(Text4, { dimColor: true, children: LEGEND_FOOTNOTE }) : null,
|
|
2525
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: scrollable ? "\u2191\u2193 scroll \xB7 esc \xB7 ? close" : "esc \xB7 ? close" })
|
|
2395
2526
|
]
|
|
2396
2527
|
}
|
|
2397
2528
|
);
|
|
@@ -2406,13 +2537,13 @@ var ExplainModal = ({ item, login }) => /* @__PURE__ */ jsxs(
|
|
|
2406
2537
|
paddingX: 1,
|
|
2407
2538
|
width: Math.min(COLS, 78),
|
|
2408
2539
|
children: [
|
|
2409
|
-
/* @__PURE__ */ jsx(
|
|
2410
|
-
/* @__PURE__ */ jsx(
|
|
2540
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.accent, bold: true, children: `#${item.number} \xB7 ${item.repo}` }),
|
|
2541
|
+
/* @__PURE__ */ jsx(Text4, { children: item.title }),
|
|
2411
2542
|
explainItem(item, login).map((section) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
2412
|
-
/* @__PURE__ */ jsx(
|
|
2413
|
-
section.lines.map((line, i) => /* @__PURE__ */ jsx(
|
|
2543
|
+
/* @__PURE__ */ jsx(Text4, { bold: true, dimColor: true, children: section.heading }),
|
|
2544
|
+
section.lines.map((line, i) => /* @__PURE__ */ jsx(Text4, { children: " " + line }, i))
|
|
2414
2545
|
] }, section.heading)),
|
|
2415
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
|
|
2546
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text4, { dimColor: true, children: "esc \xB7 e close" }) })
|
|
2416
2547
|
]
|
|
2417
2548
|
}
|
|
2418
2549
|
);
|
|
@@ -2438,21 +2569,21 @@ var RepoPicker = ({
|
|
|
2438
2569
|
paddingX: 1,
|
|
2439
2570
|
minWidth: 42,
|
|
2440
2571
|
children: [
|
|
2441
|
-
/* @__PURE__ */ jsx(
|
|
2442
|
-
/* @__PURE__ */ jsx(
|
|
2572
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, bold: true, children: `Filter by repo (${selected.size} on)` }),
|
|
2573
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: "\u2500".repeat(36) }),
|
|
2443
2574
|
visible.map((repo, i) => {
|
|
2444
2575
|
const idx = start + i;
|
|
2445
2576
|
const on = selected.has(repo);
|
|
2446
2577
|
const active = idx === cursor;
|
|
2447
2578
|
return /* @__PURE__ */ jsxs(Box, { children: [
|
|
2448
|
-
/* @__PURE__ */ jsx(
|
|
2449
|
-
/* @__PURE__ */ jsx(
|
|
2450
|
-
/* @__PURE__ */ jsx(
|
|
2579
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, children: active ? "\u276F " : " " }),
|
|
2580
|
+
/* @__PURE__ */ jsx(Text4, { color: on ? "green" : void 0, children: on ? "\u25C9 " : "\u25CB " }),
|
|
2581
|
+
/* @__PURE__ */ jsx(Text4, { bold: active, children: repo })
|
|
2451
2582
|
] }, repo);
|
|
2452
2583
|
}),
|
|
2453
|
-
repos.length > budget ? /* @__PURE__ */ jsx(
|
|
2454
|
-
/* @__PURE__ */ jsx(
|
|
2455
|
-
/* @__PURE__ */ jsx(
|
|
2584
|
+
repos.length > budget ? /* @__PURE__ */ jsx(Text4, { dimColor: true, children: ` \u2026 ${repos.length} repos total` }) : null,
|
|
2585
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: "\u2500".repeat(36) }),
|
|
2586
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: "space toggle \xB7 a clear all \xB7 \u21B5/esc done" })
|
|
2456
2587
|
]
|
|
2457
2588
|
}
|
|
2458
2589
|
);
|
|
@@ -2487,6 +2618,8 @@ var BrowseScreen = ({
|
|
|
2487
2618
|
extensions,
|
|
2488
2619
|
ciStatusState,
|
|
2489
2620
|
ciJob,
|
|
2621
|
+
stripState,
|
|
2622
|
+
stripLabel,
|
|
2490
2623
|
tabHelp,
|
|
2491
2624
|
origin,
|
|
2492
2625
|
budget,
|
|
@@ -2528,12 +2661,13 @@ var BrowseScreen = ({
|
|
|
2528
2661
|
const [palette, setPalette] = useState(null);
|
|
2529
2662
|
const filterActive = search != null || repoFilter.size > 0;
|
|
2530
2663
|
const reserveCiRow = ciStatusState != null;
|
|
2664
|
+
const reserveStripRow = stripState != null;
|
|
2531
2665
|
const ciStatus = ciStatusState?.kind === "ready" ? ciStatusState.status : null;
|
|
2532
2666
|
const listHeight = Math.max(
|
|
2533
2667
|
5,
|
|
2534
2668
|
// -10 rather than -8: the extra 2 are the frame's top and bottom border
|
|
2535
2669
|
// rows, so the tree never grows taller than the terminal inside the frame.
|
|
2536
|
-
rows - 10 - (filterActive ? 2 : 0) - (reserveCiRow ? 2 : 0)
|
|
2670
|
+
rows - 10 - (filterActive ? 2 : 0) - (reserveCiRow ? 2 : 0) - (reserveStripRow ? 2 : 0)
|
|
2537
2671
|
);
|
|
2538
2672
|
useEffect(() => {
|
|
2539
2673
|
setCursors((p) => ({ ...p, [activeId]: 0 }));
|
|
@@ -2627,10 +2761,13 @@ var BrowseScreen = ({
|
|
|
2627
2761
|
return out;
|
|
2628
2762
|
}, [localSections, transients]);
|
|
2629
2763
|
const [railOpen, setRailOpen] = useState(false);
|
|
2630
|
-
const
|
|
2764
|
+
const rails = railsOf(sidebar);
|
|
2765
|
+
const hasRail = rails.length > 0;
|
|
2766
|
+
const railTitle = rails.map((s) => s.title.toLowerCase()).join(" \xB7 ");
|
|
2767
|
+
const showRail = railOpen && hasRail;
|
|
2631
2768
|
const [railFocus, setRailFocus] = useState(false);
|
|
2632
2769
|
const [railCursor, setRailCursor] = useState(0);
|
|
2633
|
-
const railRows = sidebar
|
|
2770
|
+
const railRows = railRowsOf(sidebar);
|
|
2634
2771
|
const railActive = showRail && railFocus && railRows.length > 0;
|
|
2635
2772
|
const railAt = Math.min(railCursor, Math.max(0, railRows.length - 1));
|
|
2636
2773
|
const peel = () => {
|
|
@@ -2804,7 +2941,7 @@ var BrowseScreen = ({
|
|
|
2804
2941
|
setRepoPicker(true);
|
|
2805
2942
|
return;
|
|
2806
2943
|
}
|
|
2807
|
-
if (input === "i" &&
|
|
2944
|
+
if (input === "i" && hasRail) {
|
|
2808
2945
|
setRailOpen((open) => {
|
|
2809
2946
|
if (open) setRailFocus(false);
|
|
2810
2947
|
return !open;
|
|
@@ -2845,6 +2982,13 @@ var BrowseScreen = ({
|
|
|
2845
2982
|
}
|
|
2846
2983
|
return;
|
|
2847
2984
|
}
|
|
2985
|
+
if (input === "c") {
|
|
2986
|
+
const row = railRows[railAt];
|
|
2987
|
+
if (!row?.url) return;
|
|
2988
|
+
clipboard(row.url);
|
|
2989
|
+
showFlash(`\u2713 Copied URL for ${row.key}`);
|
|
2990
|
+
return;
|
|
2991
|
+
}
|
|
2848
2992
|
if (input !== "r" && input !== "q" && !key.leftArrow && !key.rightArrow)
|
|
2849
2993
|
return;
|
|
2850
2994
|
}
|
|
@@ -3103,9 +3247,10 @@ var BrowseScreen = ({
|
|
|
3103
3247
|
// reach a row is worse than a short footer: it names a key that does
|
|
3104
3248
|
// nothing where you are standing.
|
|
3105
3249
|
[
|
|
3106
|
-
["\u2191\u2193", "
|
|
3250
|
+
["\u2191\u2193", "row"],
|
|
3107
3251
|
["\u21B5", "open"],
|
|
3108
3252
|
["o", "browser"],
|
|
3253
|
+
["c", "copy url"],
|
|
3109
3254
|
["\u21E5/esc", "back to list"],
|
|
3110
3255
|
["?", "help"],
|
|
3111
3256
|
["q", "quit"]
|
|
@@ -3128,7 +3273,7 @@ var BrowseScreen = ({
|
|
|
3128
3273
|
...jiraBase ? [["\u2303K", "launch"]] : [],
|
|
3129
3274
|
// Advertised only where it does something, and named for what it
|
|
3130
3275
|
// shows rather than for the furniture: nobody wants "a sidebar".
|
|
3131
|
-
...showRail ? [["\u21E5",
|
|
3276
|
+
...showRail ? [["\u21E5", railTitle]] : hasRail ? [["i", railTitle]] : [],
|
|
3132
3277
|
["?", "help"],
|
|
3133
3278
|
["q", "quit"]
|
|
3134
3279
|
];
|
|
@@ -3142,11 +3287,11 @@ var BrowseScreen = ({
|
|
|
3142
3287
|
const query = palette.trim();
|
|
3143
3288
|
const ticketKey = jiraKeyRe ? query.toUpperCase().match(jiraKeyRe)?.[0] : void 0;
|
|
3144
3289
|
const commands = [];
|
|
3145
|
-
const rich = (key, where) => /* @__PURE__ */ jsxs(
|
|
3290
|
+
const rich = (key, where) => /* @__PURE__ */ jsxs(Text4, { children: [
|
|
3146
3291
|
"Open ",
|
|
3147
|
-
/* @__PURE__ */ jsx(
|
|
3292
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.accent, children: key }),
|
|
3148
3293
|
" ",
|
|
3149
|
-
/* @__PURE__ */ jsx(
|
|
3294
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, children: where })
|
|
3150
3295
|
] });
|
|
3151
3296
|
const labels = /* @__PURE__ */ new Map();
|
|
3152
3297
|
if (ticketKey && jiraBase) {
|
|
@@ -3234,7 +3379,14 @@ var BrowseScreen = ({
|
|
|
3234
3379
|
selected: repoFilter,
|
|
3235
3380
|
cursor: Math.min(repoCursor, Math.max(0, allRepos.length - 1))
|
|
3236
3381
|
}
|
|
3237
|
-
) : menu.actions && activeItem && activeItem.kind !== "repo-header" ? /* @__PURE__ */ jsx(
|
|
3382
|
+
) : menu.actions && activeItem && activeItem.kind !== "repo-header" ? /* @__PURE__ */ jsx(
|
|
3383
|
+
ActionMenu,
|
|
3384
|
+
{
|
|
3385
|
+
item: activeItem,
|
|
3386
|
+
actions: menu.actions,
|
|
3387
|
+
cursor: menu.cursor
|
|
3388
|
+
}
|
|
3389
|
+
) : null;
|
|
3238
3390
|
return /* @__PURE__ */ jsxs(
|
|
3239
3391
|
Box,
|
|
3240
3392
|
{
|
|
@@ -3262,9 +3414,17 @@ var BrowseScreen = ({
|
|
|
3262
3414
|
}
|
|
3263
3415
|
),
|
|
3264
3416
|
ciStatusState ? /* @__PURE__ */ jsx(CiStatusLine, { state: ciStatusState, job: ciJob }) : null,
|
|
3417
|
+
stripState ? /* @__PURE__ */ jsx(
|
|
3418
|
+
StatusStripLine,
|
|
3419
|
+
{
|
|
3420
|
+
strip: stripState.kind === "ready" ? stripState.strip : void 0,
|
|
3421
|
+
label: stripLabel,
|
|
3422
|
+
width: COLS
|
|
3423
|
+
}
|
|
3424
|
+
) : null,
|
|
3265
3425
|
skippedForBudget ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
3266
|
-
/* @__PURE__ */ jsx(
|
|
3267
|
-
/* @__PURE__ */ jsx(
|
|
3426
|
+
/* @__PURE__ */ jsx(Text4, { bold: true, color: colors.accent, children: " \u26A1 auto-refresh paused to save API budget" }),
|
|
3427
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: " r refreshes anyway" })
|
|
3268
3428
|
] }) : null,
|
|
3269
3429
|
/* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(
|
|
3270
3430
|
Tabs,
|
|
@@ -3300,14 +3460,14 @@ var BrowseScreen = ({
|
|
|
3300
3460
|
}
|
|
3301
3461
|
) }),
|
|
3302
3462
|
search != null ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
3303
|
-
/* @__PURE__ */ jsx(
|
|
3304
|
-
/* @__PURE__ */ jsx(
|
|
3305
|
-
searchInput ? /* @__PURE__ */ jsx(
|
|
3306
|
-
/* @__PURE__ */ jsx(
|
|
3463
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.info, children: " / " }),
|
|
3464
|
+
/* @__PURE__ */ jsx(Text4, { children: search }),
|
|
3465
|
+
searchInput ? /* @__PURE__ */ jsx(Text4, { color: colors.info, children: "\u258F" }) : null,
|
|
3466
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: ` ${matchCount} match${matchCount !== 1 ? "es" : ""}${searchInput ? " \u21B5 accept \xB7 esc clear" : " esc clear"}` })
|
|
3307
3467
|
] }) : repoFilter.size > 0 ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
3308
|
-
/* @__PURE__ */ jsx(
|
|
3309
|
-
/* @__PURE__ */ jsx(
|
|
3310
|
-
/* @__PURE__ */ jsx(
|
|
3468
|
+
/* @__PURE__ */ jsx(Text4, { color: colors.accent, children: " \u25C9 " }),
|
|
3469
|
+
/* @__PURE__ */ jsx(Text4, { children: `${repoFilter.size} repo${repoFilter.size !== 1 ? "s" : ""}` }),
|
|
3470
|
+
/* @__PURE__ */ jsx(Text4, { dimColor: true, children: " f edit \xB7 esc clear" })
|
|
3311
3471
|
] }) : null,
|
|
3312
3472
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
3313
3473
|
/* @__PURE__ */ jsxs(
|
|
@@ -3345,7 +3505,7 @@ var BrowseScreen = ({
|
|
|
3345
3505
|
},
|
|
3346
3506
|
`${viewStart + i}:${rowKey(item)}`
|
|
3347
3507
|
)) }),
|
|
3348
|
-
hasMore && /* @__PURE__ */ jsxs(
|
|
3508
|
+
hasMore && /* @__PURE__ */ jsxs(Text4, { dimColor: true, children: [
|
|
3349
3509
|
" ",
|
|
3350
3510
|
"\u2193 ",
|
|
3351
3511
|
section.items.length - viewStart - visibleCount,
|
|
@@ -3367,10 +3527,10 @@ var BrowseScreen = ({
|
|
|
3367
3527
|
]
|
|
3368
3528
|
}
|
|
3369
3529
|
),
|
|
3370
|
-
showRail
|
|
3530
|
+
showRail ? /* @__PURE__ */ jsx(
|
|
3371
3531
|
SidePanel,
|
|
3372
3532
|
{
|
|
3373
|
-
sidebar,
|
|
3533
|
+
sidebar: rails,
|
|
3374
3534
|
liveLabel,
|
|
3375
3535
|
width: railCols,
|
|
3376
3536
|
height: listHeight,
|
|
@@ -3379,7 +3539,7 @@ var BrowseScreen = ({
|
|
|
3379
3539
|
}
|
|
3380
3540
|
) : null
|
|
3381
3541
|
] }),
|
|
3382
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: flash ? /* @__PURE__ */ jsx(
|
|
3542
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: flash ? /* @__PURE__ */ jsx(Text4, { color: colors.success, children: flash }) : /* @__PURE__ */ jsx(FooterHints, { hints }) })
|
|
3383
3543
|
]
|
|
3384
3544
|
}
|
|
3385
3545
|
);
|
|
@@ -3394,7 +3554,7 @@ var NoRowsScreen = ({
|
|
|
3394
3554
|
});
|
|
3395
3555
|
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
3396
3556
|
/* @__PURE__ */ jsx(StatusMessage, { variant: reason === "empty" ? "info" : "error", children: reason === "empty" ? "Nothing open." : `Fetch failed \u2014 ${detail ?? "no reason reported"}` }),
|
|
3397
|
-
reason === "empty" && detail ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
|
|
3557
|
+
reason === "empty" && detail ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text4, { dimColor: true, children: detail }) }) : null,
|
|
3398
3558
|
/* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
|
|
3399
3559
|
FooterHints,
|
|
3400
3560
|
{
|
|
@@ -3425,6 +3585,9 @@ var App = ({
|
|
|
3425
3585
|
ciJob,
|
|
3426
3586
|
ciFetcher,
|
|
3427
3587
|
ciPollMs = 6e4,
|
|
3588
|
+
stripFetcher,
|
|
3589
|
+
stripLabel,
|
|
3590
|
+
stripPollMs = 3e5,
|
|
3428
3591
|
watchPath,
|
|
3429
3592
|
watchDebounceMs = 400,
|
|
3430
3593
|
// Zero by default, deliberately. A package that adds randomness to its own
|
|
@@ -3468,6 +3631,15 @@ var App = ({
|
|
|
3468
3631
|
const next = toCiStatusState(status);
|
|
3469
3632
|
return sameCiStatusState(prev, next) ? prev : next;
|
|
3470
3633
|
});
|
|
3634
|
+
const hasStrip = !!stripFetcher;
|
|
3635
|
+
const [stripState, setStripState] = useState({
|
|
3636
|
+
kind: "loading"
|
|
3637
|
+
});
|
|
3638
|
+
const applyStrip = (strip) => setStripState((prev) => {
|
|
3639
|
+
const next = { kind: "ready", strip };
|
|
3640
|
+
if (prev.kind !== "ready") return next;
|
|
3641
|
+
return stripSignature(prev.strip) === stripSignature(strip) ? prev : next;
|
|
3642
|
+
});
|
|
3471
3643
|
const displayedKey = useRef("");
|
|
3472
3644
|
const displayedSections = useRef([]);
|
|
3473
3645
|
const [transients, setTransients] = useState(NO_TRANSIENTS);
|
|
@@ -3550,13 +3722,10 @@ var App = ({
|
|
|
3550
3722
|
const running = [...heldSince].filter(([tab]) => held.has(tab));
|
|
3551
3723
|
if (running.length === 0) return;
|
|
3552
3724
|
const remaining = (at) => at + TRANSIT_HOLD_MS - Date.now();
|
|
3553
|
-
const timer = setTimeout(
|
|
3554
|
-
(
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
},
|
|
3558
|
-
Math.max(0, Math.min(...running.map(([, at]) => remaining(at))))
|
|
3559
|
-
);
|
|
3725
|
+
const timer = setTimeout(() => {
|
|
3726
|
+
for (const [tab, at] of running)
|
|
3727
|
+
if (remaining(at) <= 0) settleTab(tab, transients);
|
|
3728
|
+
}, Math.max(0, Math.min(...running.map(([, at]) => remaining(at)))));
|
|
3560
3729
|
return () => clearTimeout(timer);
|
|
3561
3730
|
}, [transients, heldSince, state.phase]);
|
|
3562
3731
|
const pendingSummary = useMemo(
|
|
@@ -3664,6 +3833,23 @@ var App = ({
|
|
|
3664
3833
|
clearInterval(id);
|
|
3665
3834
|
};
|
|
3666
3835
|
}, [hasCiStatus, ciFetcher, ciPollMs]);
|
|
3836
|
+
useEffect(() => {
|
|
3837
|
+
if (!stripFetcher) return;
|
|
3838
|
+
let live = true;
|
|
3839
|
+
const poll = () => {
|
|
3840
|
+
stripFetcher().then((strip) => {
|
|
3841
|
+
if (!live) return;
|
|
3842
|
+
applyStrip(strip);
|
|
3843
|
+
}).catch(() => {
|
|
3844
|
+
});
|
|
3845
|
+
};
|
|
3846
|
+
poll();
|
|
3847
|
+
const id = setInterval(poll, stripPollMs);
|
|
3848
|
+
return () => {
|
|
3849
|
+
live = false;
|
|
3850
|
+
clearInterval(id);
|
|
3851
|
+
};
|
|
3852
|
+
}, [stripFetcher, stripPollMs]);
|
|
3667
3853
|
useEffect(() => {
|
|
3668
3854
|
if (!watchPath) return;
|
|
3669
3855
|
const dir = dirname(watchPath);
|
|
@@ -3748,6 +3934,14 @@ var App = ({
|
|
|
3748
3934
|
}
|
|
3749
3935
|
),
|
|
3750
3936
|
hasCiStatus ? /* @__PURE__ */ jsx(CiStatusLine, { state: ciStatusState, job: ciJob }) : null,
|
|
3937
|
+
hasStrip ? /* @__PURE__ */ jsx(
|
|
3938
|
+
StatusStripLine,
|
|
3939
|
+
{
|
|
3940
|
+
strip: stripState.kind === "ready" ? stripState.strip : void 0,
|
|
3941
|
+
label: stripLabel,
|
|
3942
|
+
width: COLS
|
|
3943
|
+
}
|
|
3944
|
+
) : null,
|
|
3751
3945
|
/* @__PURE__ */ jsx(
|
|
3752
3946
|
Box,
|
|
3753
3947
|
{
|
|
@@ -3834,6 +4028,8 @@ var App = ({
|
|
|
3834
4028
|
liveLabel,
|
|
3835
4029
|
ciStatusState: hasCiStatus ? ciStatusState : void 0,
|
|
3836
4030
|
ciJob,
|
|
4031
|
+
stripState: hasStrip ? stripState : void 0,
|
|
4032
|
+
stripLabel,
|
|
3837
4033
|
tabHelp,
|
|
3838
4034
|
onOpenPr: (item) => setState({
|
|
3839
4035
|
phase: "pr",
|
|
@@ -3888,4 +4084,4 @@ var matchesFilter = (repo, filter) => {
|
|
|
3888
4084
|
};
|
|
3889
4085
|
var parsePatterns = (value) => value.split(",").map((p) => p.trim()).filter(Boolean);
|
|
3890
4086
|
|
|
3891
|
-
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 };
|
|
4087
|
+
export { ActionMenu, App, COLS, CiStatusLine, CommentsPanel, HealthPanel, MIN_SIDEBAR_COLS, SIDEBAR_COLS, SidePanel, StatusStripLine, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, moveCursor, openInTab, parsePatterns, railCapacity, railHeights, railRowsOf, railWidth, railsOf, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, signatureOf, stripGlyph, stripLayout, stripSignature, 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.59.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",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"@kud/gh": "0.17.0",
|
|
52
|
-
"@kud/gh-workflow": "0.
|
|
52
|
+
"@kud/gh-workflow": "0.13.0",
|
|
53
53
|
"@kud/ink-ui": "0.30.0",
|
|
54
54
|
"zx": "8.8.5"
|
|
55
55
|
},
|