@kud/gh-ink 0.10.0 → 0.11.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 +8 -1
- package/dist/index.js +52 -10
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -20,8 +20,9 @@ type HealthPanelProps = {
|
|
|
20
20
|
error: string | null;
|
|
21
21
|
reload: () => void;
|
|
22
22
|
onOpenCheck: (check: PrCheck) => void;
|
|
23
|
+
onMerged?: () => void;
|
|
23
24
|
};
|
|
24
|
-
declare const HealthPanel: ({ repo, number, data, error, reload, onOpenCheck, }: HealthPanelProps) => React.JSX.Element;
|
|
25
|
+
declare const HealthPanel: ({ repo, number, data, error, reload, onOpenCheck, onMerged, }: HealthPanelProps) => React.JSX.Element;
|
|
25
26
|
|
|
26
27
|
declare const renderMarkdown: (raw: string, width: number, fileLink?: (path: string, line?: number) => string) => StyledLine[];
|
|
27
28
|
|
|
@@ -128,6 +129,12 @@ type DetailContext = {
|
|
|
128
129
|
onBack: () => void;
|
|
129
130
|
onRefresh: () => void;
|
|
130
131
|
onRemove: (item: GHItem) => void;
|
|
132
|
+
/**
|
|
133
|
+
* The PR just merged from here. Returns to the list, marks the row merged for
|
|
134
|
+
* a few seconds, then drops it — distinct from onRemove, which drops it at
|
|
135
|
+
* once. Optional so a host that cannot merge need not implement it.
|
|
136
|
+
*/
|
|
137
|
+
onMerged?: (item: GHItem) => void;
|
|
131
138
|
};
|
|
132
139
|
type Action = {
|
|
133
140
|
label: string;
|
package/dist/index.js
CHANGED
|
@@ -452,7 +452,8 @@ var HealthPanel = ({
|
|
|
452
452
|
data,
|
|
453
453
|
error,
|
|
454
454
|
reload,
|
|
455
|
-
onOpenCheck
|
|
455
|
+
onOpenCheck,
|
|
456
|
+
onMerged
|
|
456
457
|
}) => {
|
|
457
458
|
const [cursor, setCursor] = useState(0);
|
|
458
459
|
const [note, setNote] = useState(null);
|
|
@@ -475,13 +476,14 @@ var HealthPanel = ({
|
|
|
475
476
|
setNote(msg);
|
|
476
477
|
setTimeout(() => setNote(null), 2500);
|
|
477
478
|
};
|
|
478
|
-
const act = async (msg, run) => {
|
|
479
|
+
const act = async (msg, run, onSuccess) => {
|
|
479
480
|
setBusy(true);
|
|
480
481
|
setNote(`\u22EF ${msg}\u2026`);
|
|
481
482
|
try {
|
|
482
483
|
await run();
|
|
483
484
|
flash(`\u2713 ${msg}`);
|
|
484
|
-
|
|
485
|
+
if (onSuccess) onSuccess();
|
|
486
|
+
else reload();
|
|
485
487
|
} catch {
|
|
486
488
|
flash(`\u2717 ${msg} failed`);
|
|
487
489
|
} finally {
|
|
@@ -498,7 +500,7 @@ var HealthPanel = ({
|
|
|
498
500
|
if (busy) return;
|
|
499
501
|
if (confirm === "merge") {
|
|
500
502
|
if (input === "y" || input === "Y")
|
|
501
|
-
void act("merge", () => mergePr(repo, number));
|
|
503
|
+
void act("merge", () => mergePr(repo, number), onMerged);
|
|
502
504
|
setConfirm(null);
|
|
503
505
|
return;
|
|
504
506
|
}
|
|
@@ -1446,11 +1448,17 @@ var RepoHeaderRow = ({ repo, gap }) => {
|
|
|
1446
1448
|
const fill = Math.max(4, 46 - label.length);
|
|
1447
1449
|
return /* @__PURE__ */ jsx(Box, { marginTop: gap ? 1 : 0, children: /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " " + label + "\u2500".repeat(fill) }) });
|
|
1448
1450
|
};
|
|
1451
|
+
var MERGED_HOLD_MS = 3e3;
|
|
1452
|
+
var MERGED_FRAME_MS = 150;
|
|
1453
|
+
var MERGED_FRAMES = ["\u2726", "\u2727", "\u2736", "\u2727"];
|
|
1454
|
+
var MERGED_COLOUR = "#A371F7";
|
|
1449
1455
|
var ItemRow = ({
|
|
1450
1456
|
item,
|
|
1451
1457
|
active,
|
|
1452
1458
|
gap,
|
|
1453
|
-
login
|
|
1459
|
+
login,
|
|
1460
|
+
merged,
|
|
1461
|
+
sparkFrame = 0
|
|
1454
1462
|
}) => {
|
|
1455
1463
|
if (item.kind === "repo-header")
|
|
1456
1464
|
return /* @__PURE__ */ jsx(RepoHeaderRow, { repo: item.repo, gap: gap ?? false });
|
|
@@ -1481,16 +1489,20 @@ var ItemRow = ({
|
|
|
1481
1489
|
/* @__PURE__ */ jsx(Text2, { bold: active, children: truncate(item.summary, titleMax2) })
|
|
1482
1490
|
] });
|
|
1483
1491
|
}
|
|
1484
|
-
const { glyph:
|
|
1492
|
+
const { glyph: healthIcon, color: healthColor2 } = healthDisplay[item.health];
|
|
1493
|
+
const icon = merged ? MERGED_FRAMES[sparkFrame % MERGED_FRAMES.length] : healthIcon;
|
|
1494
|
+
const color = merged ? MERGED_COLOUR : healthColor2;
|
|
1485
1495
|
const [turnIcon, turnColor] = !login || !item.lastActor ? [" ", "white"] : item.lastActor === login ? ["\u2192", "#888888"] : ["\u2190", "#FF8700"];
|
|
1486
1496
|
const numStr = `#${item.number}`.padEnd(7);
|
|
1487
1497
|
const showAuthor = !!item.author && item.author !== login;
|
|
1488
1498
|
const unresolvedLabel = item.unresolved > 0 ? `\uF086 ${item.unresolved}` : "";
|
|
1489
1499
|
const ageLabel = item.activityAge && item.activityAge !== item.age ? `${item.activityAge} \xB7 ${item.age}` : item.age;
|
|
1500
|
+
const mergedLabel = merged ? "MERGED" : "";
|
|
1490
1501
|
const suffix = [
|
|
1491
1502
|
ageLabel || "",
|
|
1492
1503
|
unresolvedLabel,
|
|
1493
|
-
showAuthor ? `by ${item.author}` : ""
|
|
1504
|
+
showAuthor ? `by ${item.author}` : "",
|
|
1505
|
+
mergedLabel
|
|
1494
1506
|
].filter(Boolean).join(" ");
|
|
1495
1507
|
const repoLabel = item.indent ? item.repo : "";
|
|
1496
1508
|
const fixedWidth = 2 + (item.indent ? 3 : 0) + 2 + 2 + 7 + repoLabel.length + suffix.length + 6;
|
|
@@ -1505,7 +1517,8 @@ var ItemRow = ({
|
|
|
1505
1517
|
repoLabel ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: repoLabel }) : null,
|
|
1506
1518
|
unresolvedLabel ? /* @__PURE__ */ jsx(Text2, { bold: true, color: "#FF8700", children: " " + unresolvedLabel }) : null,
|
|
1507
1519
|
showAuthor ? /* @__PURE__ */ jsx(Text2, { dimColor: true, italic: true, children: " by " + item.author }) : null,
|
|
1508
|
-
ageLabel ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " " + ageLabel }) : null
|
|
1520
|
+
ageLabel ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " " + ageLabel }) : null,
|
|
1521
|
+
mergedLabel ? /* @__PURE__ */ jsx(Text2, { bold: true, color: MERGED_COLOUR, children: " " + mergedLabel }) : null
|
|
1509
1522
|
] });
|
|
1510
1523
|
};
|
|
1511
1524
|
var useActionMenu = () => {
|
|
@@ -1794,7 +1807,8 @@ var BrowseScreen = ({
|
|
|
1794
1807
|
tabHelp,
|
|
1795
1808
|
isWorkRepo,
|
|
1796
1809
|
initialIncludeWork,
|
|
1797
|
-
brand
|
|
1810
|
+
brand,
|
|
1811
|
+
mergedUrls
|
|
1798
1812
|
}) => {
|
|
1799
1813
|
const { rows } = useWindowSize();
|
|
1800
1814
|
const [includeWork, setIncludeWork] = useState(
|
|
@@ -1884,6 +1898,13 @@ var BrowseScreen = ({
|
|
|
1884
1898
|
setFlash(msg);
|
|
1885
1899
|
setTimeout(() => setFlash(null), 2e3);
|
|
1886
1900
|
};
|
|
1901
|
+
const [sparkFrame, setSparkFrame] = useState(0);
|
|
1902
|
+
const sparkling = (mergedUrls?.length ?? 0) > 0;
|
|
1903
|
+
useEffect(() => {
|
|
1904
|
+
if (!sparkling) return;
|
|
1905
|
+
const id = setInterval(() => setSparkFrame((f) => f + 1), MERGED_FRAME_MS);
|
|
1906
|
+
return () => clearInterval(id);
|
|
1907
|
+
}, [sparkling]);
|
|
1887
1908
|
useEffect(() => {
|
|
1888
1909
|
if (refreshError) showFlash(`\u2717 ${refreshError.message}`);
|
|
1889
1910
|
}, [refreshError]);
|
|
@@ -2249,6 +2270,8 @@ var BrowseScreen = ({
|
|
|
2249
2270
|
item,
|
|
2250
2271
|
active: viewStart + i === cursor,
|
|
2251
2272
|
login,
|
|
2273
|
+
merged: (item.kind === "pr" || item.kind === "issue") && !!mergedUrls?.includes(item.url),
|
|
2274
|
+
sparkFrame,
|
|
2252
2275
|
gap: viewStart + i > 0 && (item.kind === "repo-header" || item.kind === "subgroup-header" || // A header is always followed by a blank line before its
|
|
2253
2276
|
// first child — in Other PRs that's "free" because the
|
|
2254
2277
|
// child is itself a repo-header (gap above). A jira row
|
|
@@ -2415,6 +2438,9 @@ var App = ({
|
|
|
2415
2438
|
clearInterval(id);
|
|
2416
2439
|
};
|
|
2417
2440
|
}, [hasCiStatus, ciFetcher, ciPollMs]);
|
|
2441
|
+
const [mergedUrls, setMergedUrls] = useState([]);
|
|
2442
|
+
const mergeTimers = useRef([]);
|
|
2443
|
+
useEffect(() => () => mergeTimers.current.forEach(clearTimeout), []);
|
|
2418
2444
|
if (state.phase === "loading" || state.phase === "empty" || state.phase === "failed")
|
|
2419
2445
|
return /* @__PURE__ */ jsxs(
|
|
2420
2446
|
Box,
|
|
@@ -2460,6 +2486,20 @@ var App = ({
|
|
|
2460
2486
|
sections: withoutItem(state.sections, target),
|
|
2461
2487
|
login: state.login
|
|
2462
2488
|
});
|
|
2489
|
+
const markMerged = (target) => {
|
|
2490
|
+
toBrowse();
|
|
2491
|
+
setMergedUrls(
|
|
2492
|
+
(prev) => prev.includes(target.url) ? prev : [...prev, target.url]
|
|
2493
|
+
);
|
|
2494
|
+
mergeTimers.current.push(
|
|
2495
|
+
setTimeout(() => {
|
|
2496
|
+
setMergedUrls((prev) => prev.filter((u) => u !== target.url));
|
|
2497
|
+
setState(
|
|
2498
|
+
(s) => s.phase === "browse" ? { ...s, sections: withoutItem(s.sections, target) } : s
|
|
2499
|
+
);
|
|
2500
|
+
}, MERGED_HOLD_MS)
|
|
2501
|
+
);
|
|
2502
|
+
};
|
|
2463
2503
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2464
2504
|
/* @__PURE__ */ jsx(
|
|
2465
2505
|
BrowseScreen,
|
|
@@ -2480,6 +2520,7 @@ var App = ({
|
|
|
2480
2520
|
isWorkRepo,
|
|
2481
2521
|
initialIncludeWork,
|
|
2482
2522
|
hidden: overlay !== null,
|
|
2523
|
+
mergedUrls,
|
|
2483
2524
|
ciStatusState: hasCiStatus ? ciStatusState : void 0,
|
|
2484
2525
|
ciJob,
|
|
2485
2526
|
tabHelp,
|
|
@@ -2511,7 +2552,8 @@ var App = ({
|
|
|
2511
2552
|
login: state.login,
|
|
2512
2553
|
onBack: toBrowse,
|
|
2513
2554
|
onRefresh: applyOrRefresh,
|
|
2514
|
-
onRemove: removeAndReturn
|
|
2555
|
+
onRemove: removeAndReturn,
|
|
2556
|
+
onMerged: markMerged
|
|
2515
2557
|
}),
|
|
2516
2558
|
overlay?.kind === "ext" && extensions?.find((e) => e.id === overlay.extId)?.body(toBrowse, overlay.target)
|
|
2517
2559
|
] });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kud/gh-ink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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",
|