@kud/gh-ink 0.7.1 → 0.8.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 +8 -0
- package/dist/index.js +126 -43
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -177,6 +177,14 @@ declare const drillCmd: (item: AnyItem) => string | null;
|
|
|
177
177
|
declare const buildActions: (item: AnyItem, login: string, showFlash: (msg: string) => void, jiraBase?: string, jiraKeyRe?: RegExp, jiraTransitions?: JiraTransition[], onRefresh?: () => void, onRemove?: (item: GHItem) => void, onOpenView?: (item: AnyItem) => boolean, ext?: {
|
|
178
178
|
extensions?: InboxExtension[];
|
|
179
179
|
onOpenExt?: (id: string, target: ExtensionTarget) => void;
|
|
180
|
+
/**
|
|
181
|
+
* A mutation landed. Drops the cached glance now and schedules the refresh,
|
|
182
|
+
* replacing a bare `setTimeout(onRefresh, 1500)` at each call site.
|
|
183
|
+
*
|
|
184
|
+
* Both halves matter and only one is visible: the delay lets GitHub settle,
|
|
185
|
+
* the drop stops the pre-action cache outliving a quit inside that window.
|
|
186
|
+
*/
|
|
187
|
+
onActed?: () => void;
|
|
180
188
|
}) => Action[];
|
|
181
189
|
type CiStatusState = {
|
|
182
190
|
kind: "loading";
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { isPassCheck, isFailCheck, resolveThread, unresolveThread, replyToThread
|
|
|
5
5
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
6
6
|
import { $ } from 'zx';
|
|
7
7
|
import { spawn } from 'child_process';
|
|
8
|
-
import { readFileSync, mkdirSync, writeFileSync, existsSync, readdirSync, statSync } from 'fs';
|
|
8
|
+
import { readFileSync, mkdirSync, writeFileSync, existsSync, readdirSync, statSync, rmSync } from 'fs';
|
|
9
9
|
import { join } from 'path';
|
|
10
10
|
import { homedir } from 'os';
|
|
11
11
|
|
|
@@ -604,21 +604,34 @@ var healthLegend = [
|
|
|
604
604
|
["merged", "Merged"],
|
|
605
605
|
["closed", "Closed"]
|
|
606
606
|
];
|
|
607
|
+
var CACHE_TTL_MS = 12e4;
|
|
608
|
+
var CACHE_VERSION = 1;
|
|
607
609
|
var cacheDir = () => join(process.env.XDG_CACHE_HOME || join(homedir(), ".cache"), "ambre");
|
|
608
610
|
var cacheFile = (key) => join(cacheDir(), `${key.replace(/[^a-z0-9._-]/gi, "-")}.json`);
|
|
609
611
|
var readCache = (key) => {
|
|
610
612
|
try {
|
|
611
613
|
const raw = JSON.parse(readFileSync(cacheFile(key), "utf8"));
|
|
614
|
+
if (raw?.version !== CACHE_VERSION) return null;
|
|
612
615
|
if (!Array.isArray(raw?.sections)) return null;
|
|
613
616
|
return { sections: raw.sections, login: raw.login ?? "", at: raw.at ?? 0 };
|
|
614
617
|
} catch {
|
|
615
618
|
return null;
|
|
616
619
|
}
|
|
617
620
|
};
|
|
621
|
+
var isFresh = (cached, now = Date.now()) => !!cached && now - cached.at < CACHE_TTL_MS;
|
|
618
622
|
var writeCache = (key, data) => {
|
|
619
623
|
try {
|
|
620
624
|
mkdirSync(cacheDir(), { recursive: true });
|
|
621
|
-
writeFileSync(
|
|
625
|
+
writeFileSync(
|
|
626
|
+
cacheFile(key),
|
|
627
|
+
JSON.stringify({ version: CACHE_VERSION, ...data, at: Date.now() })
|
|
628
|
+
);
|
|
629
|
+
} catch {
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
var invalidateCache = (key) => {
|
|
633
|
+
try {
|
|
634
|
+
rmSync(cacheFile(key), { force: true });
|
|
622
635
|
} catch {
|
|
623
636
|
}
|
|
624
637
|
};
|
|
@@ -1052,6 +1065,7 @@ var FRAME_COLOR = "gray";
|
|
|
1052
1065
|
var FRAME_PAD_X = 1;
|
|
1053
1066
|
var FRAME_CHROME_COLS = 2 + FRAME_PAD_X * 2;
|
|
1054
1067
|
var COLS = (process.stdout.columns ?? 120) - FRAME_CHROME_COLS;
|
|
1068
|
+
var MODAL_CHROME_COLS = 2 + 1 * 2;
|
|
1055
1069
|
var topLevelCount = (s) => s.items.filter(
|
|
1056
1070
|
(i) => i.kind !== "repo-header" && i.kind !== "subgroup-header" && !i.indent
|
|
1057
1071
|
).length;
|
|
@@ -1121,7 +1135,7 @@ var buildActions = (item, login, showFlash, jiraBase, jiraKeyRe, jiraTransitions
|
|
|
1121
1135
|
showFlash(`\u22EF ${label} \xB7 ${resolution}\u2026`);
|
|
1122
1136
|
void quietly`jira issue move ${item.key} ${state} --resolution ${resolution}`.then(() => {
|
|
1123
1137
|
showFlash(`\u2713 ${label} \xB7 ${resolution}`);
|
|
1124
|
-
|
|
1138
|
+
ext?.onActed?.();
|
|
1125
1139
|
}).catch(() => showFlash(`\u2717 Move to ${label} failed`));
|
|
1126
1140
|
}
|
|
1127
1141
|
}))
|
|
@@ -1132,7 +1146,7 @@ var buildActions = (item, login, showFlash, jiraBase, jiraKeyRe, jiraTransitions
|
|
|
1132
1146
|
showFlash(`\u22EF Moving to ${label}\u2026`);
|
|
1133
1147
|
void quietly`jira issue move ${item.key} ${state}`.then(() => {
|
|
1134
1148
|
showFlash(`\u2713 Moved to ${label}`);
|
|
1135
|
-
|
|
1149
|
+
ext?.onActed?.();
|
|
1136
1150
|
}).catch(() => showFlash(`\u2717 Move to ${label} failed`));
|
|
1137
1151
|
}
|
|
1138
1152
|
}
|
|
@@ -1528,12 +1542,55 @@ var TURN_LEGEND = [
|
|
|
1528
1542
|
["\u2190", "#FF8700", "They spoke last \xB7 your turn"],
|
|
1529
1543
|
["\u2192", "#888888", "You spoke last \xB7 waiting on them"]
|
|
1530
1544
|
];
|
|
1545
|
+
var CELL_GUTTER = 2;
|
|
1546
|
+
var COL_GAP = 3;
|
|
1547
|
+
var cellWidthOf = (col) => Math.max(0, ...col.rows.map((r) => r.cell.length)) + CELL_GUTTER;
|
|
1548
|
+
var widthOf = (col) => Math.max(
|
|
1549
|
+
col.title.length,
|
|
1550
|
+
...col.rows.map((r) => cellWidthOf(col) + r.label.length)
|
|
1551
|
+
);
|
|
1552
|
+
var groupWidth = (group) => Math.max(0, ...group.map(widthOf));
|
|
1553
|
+
var layoutWidth = (groups) => groups.reduce((total, g) => total + groupWidth(g), 0) + COL_GAP * Math.max(0, groups.length - 1);
|
|
1554
|
+
var legendLayout = (cols, available) => {
|
|
1555
|
+
const across = cols.map((c) => [c]);
|
|
1556
|
+
if (layoutWidth(across) <= available) return across;
|
|
1557
|
+
const stacked = [cols.slice(0, -1), cols.slice(-1)];
|
|
1558
|
+
if (layoutWidth(stacked) <= available) return stacked;
|
|
1559
|
+
return [cols];
|
|
1560
|
+
};
|
|
1561
|
+
var LegendGroup = ({
|
|
1562
|
+
group,
|
|
1563
|
+
width,
|
|
1564
|
+
marginRight
|
|
1565
|
+
}) => /* @__PURE__ */ jsx(Box, { flexDirection: "column", width, marginRight, children: group.map((col, index) => {
|
|
1566
|
+
const cellWidth = cellWidthOf(col);
|
|
1567
|
+
return /* @__PURE__ */ jsxs(
|
|
1568
|
+
Box,
|
|
1569
|
+
{
|
|
1570
|
+
flexDirection: "column",
|
|
1571
|
+
marginTop: index === 0 ? 0 : 1,
|
|
1572
|
+
children: [
|
|
1573
|
+
/* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: col.title }),
|
|
1574
|
+
col.rows.map((row) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
1575
|
+
/* @__PURE__ */ jsx(Text, { color: row.color, bold: row.bold, children: row.cell.padEnd(cellWidth) }),
|
|
1576
|
+
/* @__PURE__ */ jsx(Text, { wrap: "truncate-end", children: row.label })
|
|
1577
|
+
] }, col.title + row.cell + row.label))
|
|
1578
|
+
]
|
|
1579
|
+
},
|
|
1580
|
+
col.title
|
|
1581
|
+
);
|
|
1582
|
+
}) });
|
|
1531
1583
|
var HelpModal = ({
|
|
1532
1584
|
workToggle,
|
|
1533
1585
|
extensions,
|
|
1534
1586
|
hasJira,
|
|
1535
1587
|
tabHelp
|
|
1536
1588
|
}) => {
|
|
1589
|
+
const { columns } = useWindowSize();
|
|
1590
|
+
const available = Math.max(
|
|
1591
|
+
20,
|
|
1592
|
+
columns - FRAME_CHROME_COLS - MODAL_CHROME_COLS
|
|
1593
|
+
);
|
|
1537
1594
|
const keys = [
|
|
1538
1595
|
["\u2191 \u2193", "navigate"],
|
|
1539
1596
|
["\u2190 \u2192 \xB7 tab", "switch tab"],
|
|
@@ -1555,6 +1612,49 @@ var HelpModal = ({
|
|
|
1555
1612
|
["?", "this help"],
|
|
1556
1613
|
["q", "quit"]
|
|
1557
1614
|
];
|
|
1615
|
+
const statusColumn = {
|
|
1616
|
+
title: "Status",
|
|
1617
|
+
rows: [
|
|
1618
|
+
...healthLegend.map(([health, label]) => ({
|
|
1619
|
+
cell: healthDisplay[health].glyph,
|
|
1620
|
+
color: healthDisplay[health].color,
|
|
1621
|
+
bold: true,
|
|
1622
|
+
label
|
|
1623
|
+
})),
|
|
1624
|
+
...TURN_LEGEND.map(([cell, color, label]) => ({
|
|
1625
|
+
cell,
|
|
1626
|
+
color,
|
|
1627
|
+
bold: true,
|
|
1628
|
+
label
|
|
1629
|
+
})),
|
|
1630
|
+
{
|
|
1631
|
+
cell: "\uF086",
|
|
1632
|
+
color: "#FF8700",
|
|
1633
|
+
bold: true,
|
|
1634
|
+
label: "Open-thread count"
|
|
1635
|
+
}
|
|
1636
|
+
]
|
|
1637
|
+
};
|
|
1638
|
+
const cols = [
|
|
1639
|
+
statusColumn,
|
|
1640
|
+
...tabHelp ? [
|
|
1641
|
+
{
|
|
1642
|
+
title: "Tabs",
|
|
1643
|
+
rows: tabHelp.map(([tab, meaning]) => ({
|
|
1644
|
+
cell: tab,
|
|
1645
|
+
color: "#FF8700",
|
|
1646
|
+
label: meaning
|
|
1647
|
+
}))
|
|
1648
|
+
}
|
|
1649
|
+
] : [],
|
|
1650
|
+
{
|
|
1651
|
+
title: "Keys",
|
|
1652
|
+
rows: keys.map(([key, label]) => ({ cell: key, color: "cyan", label }))
|
|
1653
|
+
}
|
|
1654
|
+
];
|
|
1655
|
+
const groups = legendLayout(cols, available);
|
|
1656
|
+
const widths = groups.map((g) => Math.min(groupWidth(g), available));
|
|
1657
|
+
const contentWidth = Math.min(available, layoutWidth(groups));
|
|
1558
1658
|
return /* @__PURE__ */ jsxs(
|
|
1559
1659
|
Box,
|
|
1560
1660
|
{
|
|
@@ -1562,42 +1662,18 @@ var HelpModal = ({
|
|
|
1562
1662
|
borderStyle: "round",
|
|
1563
1663
|
borderColor: "cyan",
|
|
1564
1664
|
paddingX: 1,
|
|
1665
|
+
width: contentWidth + MODAL_CHROME_COLS,
|
|
1565
1666
|
children: [
|
|
1566
1667
|
/* @__PURE__ */ jsx(Text, { color: "cyan", bold: true, children: "Legend" }),
|
|
1567
|
-
/* @__PURE__ */
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
}),
|
|
1577
|
-
TURN_LEGEND.map(([icon, color, label]) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
1578
|
-
/* @__PURE__ */ jsx(Text, { color, bold: true, children: icon + " " }),
|
|
1579
|
-
/* @__PURE__ */ jsx(Text, { children: " " + label })
|
|
1580
|
-
] }, icon)),
|
|
1581
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
1582
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "#FF8700", children: "\uF086 " }),
|
|
1583
|
-
/* @__PURE__ */ jsx(Text, { children: " Open-thread count" })
|
|
1584
|
-
] })
|
|
1585
|
-
] }),
|
|
1586
|
-
tabHelp ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginRight: 3, minWidth: 30, children: [
|
|
1587
|
-
/* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "Tabs" }),
|
|
1588
|
-
tabHelp.map(([tab, meaning]) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
1589
|
-
/* @__PURE__ */ jsx(Text, { color: "#FF8700", children: tab.padEnd(10) }),
|
|
1590
|
-
/* @__PURE__ */ jsx(Text, { children: meaning })
|
|
1591
|
-
] }, tab))
|
|
1592
|
-
] }) : null,
|
|
1593
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
1594
|
-
/* @__PURE__ */ jsx(Text, { bold: true, dimColor: true, children: "Keys" }),
|
|
1595
|
-
keys.map(([k, label]) => /* @__PURE__ */ jsxs(Box, { children: [
|
|
1596
|
-
/* @__PURE__ */ jsx(Text, { color: "cyan", children: k.padEnd(11) }),
|
|
1597
|
-
/* @__PURE__ */ jsx(Text, { children: label })
|
|
1598
|
-
] }, k))
|
|
1599
|
-
] })
|
|
1600
|
-
] }),
|
|
1668
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 1, width: contentWidth, children: groups.map((group, index) => /* @__PURE__ */ jsx(
|
|
1669
|
+
LegendGroup,
|
|
1670
|
+
{
|
|
1671
|
+
group,
|
|
1672
|
+
width: widths[index],
|
|
1673
|
+
marginRight: index === groups.length - 1 ? 0 : COL_GAP
|
|
1674
|
+
},
|
|
1675
|
+
group[0]?.title ?? index
|
|
1676
|
+
)) }),
|
|
1601
1677
|
tabHelp ? /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Each item lands in the FIRST tab that claims it, so counts are residuals rather than totals." }) : null,
|
|
1602
1678
|
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "esc \xB7 ? close" })
|
|
1603
1679
|
]
|
|
@@ -1673,6 +1749,7 @@ var BrowseScreen = ({
|
|
|
1673
1749
|
jiraKeyRe,
|
|
1674
1750
|
jiraTransitions,
|
|
1675
1751
|
onRefresh,
|
|
1752
|
+
onActed,
|
|
1676
1753
|
refreshing,
|
|
1677
1754
|
hasPending,
|
|
1678
1755
|
fetchedAt,
|
|
@@ -1807,7 +1884,7 @@ var BrowseScreen = ({
|
|
|
1807
1884
|
onRefresh,
|
|
1808
1885
|
removeItemFromSections,
|
|
1809
1886
|
openDrillView,
|
|
1810
|
-
{ extensions, onOpenExt }
|
|
1887
|
+
{ extensions, onOpenExt, onActed }
|
|
1811
1888
|
);
|
|
1812
1889
|
menu.open(actions);
|
|
1813
1890
|
};
|
|
@@ -2037,7 +2114,7 @@ var BrowseScreen = ({
|
|
|
2037
2114
|
showFlash(`\u22EF ${label} \xB7 ${resolution}\u2026`);
|
|
2038
2115
|
quietly`jira issue move ${jiraKey} ${state} --resolution ${resolution}`.then(() => {
|
|
2039
2116
|
showFlash(`\u2713 ${label} \xB7 ${resolution}`);
|
|
2040
|
-
|
|
2117
|
+
onActed?.();
|
|
2041
2118
|
}).catch(() => showFlash(`\u2717 Move to ${label} failed`));
|
|
2042
2119
|
}
|
|
2043
2120
|
}))
|
|
@@ -2049,7 +2126,7 @@ var BrowseScreen = ({
|
|
|
2049
2126
|
showFlash(`\u22EF Moving to ${label}\u2026`);
|
|
2050
2127
|
quietly`jira issue move ${jiraKey} ${state}`.then(() => {
|
|
2051
2128
|
showFlash(`\u2713 Moved to ${label}`);
|
|
2052
|
-
|
|
2129
|
+
onActed?.();
|
|
2053
2130
|
}).catch(() => showFlash(`\u2717 Move to ${label} failed`));
|
|
2054
2131
|
}
|
|
2055
2132
|
}
|
|
@@ -2280,9 +2357,14 @@ var App = ({
|
|
|
2280
2357
|
if (pending) showData(pending.sections, pending.login);
|
|
2281
2358
|
else revalidate(true);
|
|
2282
2359
|
};
|
|
2360
|
+
const onActed = () => {
|
|
2361
|
+
if (cacheKey) invalidateCache(cacheKey);
|
|
2362
|
+
setTimeout(() => applyOrRefresh(), 1500);
|
|
2363
|
+
};
|
|
2283
2364
|
useEffect(() => {
|
|
2284
2365
|
const cached = cacheKey ? readCache(cacheKey) : null;
|
|
2285
|
-
|
|
2366
|
+
const painted = !!cached && cached.sections.length > 0;
|
|
2367
|
+
if (painted && cached) {
|
|
2286
2368
|
displayedKey.current = signatureOf(cached.sections);
|
|
2287
2369
|
setFetchedAt(cached.at);
|
|
2288
2370
|
setState({
|
|
@@ -2291,7 +2373,7 @@ var App = ({
|
|
|
2291
2373
|
login: cached.login
|
|
2292
2374
|
});
|
|
2293
2375
|
}
|
|
2294
|
-
revalidate();
|
|
2376
|
+
if (!painted || !isFresh(cached)) revalidate();
|
|
2295
2377
|
}, []);
|
|
2296
2378
|
useEffect(() => {
|
|
2297
2379
|
if (!hasCiStatus || !ciFetcher) return;
|
|
@@ -2358,6 +2440,7 @@ var App = ({
|
|
|
2358
2440
|
jiraKeyRe,
|
|
2359
2441
|
jiraTransitions,
|
|
2360
2442
|
onRefresh: applyOrRefresh,
|
|
2443
|
+
onActed,
|
|
2361
2444
|
refreshing,
|
|
2362
2445
|
hasPending: pending !== null,
|
|
2363
2446
|
fetchedAt,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kud/gh-ink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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,7 +48,7 @@
|
|
|
48
48
|
"react": ">=19"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@kud/gh": "0.5.
|
|
51
|
+
"@kud/gh": "0.5.1",
|
|
52
52
|
"@kud/ink-ui": "0.14.0",
|
|
53
53
|
"zx": "8.8.5"
|
|
54
54
|
},
|