@kud/gh-ink 0.14.0 → 0.16.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.js +91 -22
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -607,7 +607,7 @@ var healthLegend = [
|
|
|
607
607
|
["closed", "Closed"]
|
|
608
608
|
];
|
|
609
609
|
var CACHE_TTL_MS = 12e4;
|
|
610
|
-
var CACHE_VERSION =
|
|
610
|
+
var CACHE_VERSION = 2;
|
|
611
611
|
var cacheDir = () => join(process.env.XDG_CACHE_HOME || join(homedir(), ".cache"), "ambre");
|
|
612
612
|
var cacheFile = (key) => join(cacheDir(), `${key.replace(/[^a-z0-9._-]/gi, "-")}.json`);
|
|
613
613
|
var readCache = (key) => {
|
|
@@ -733,6 +733,15 @@ var transientOf = (transients, item) => {
|
|
|
733
733
|
const key = keyOf(item);
|
|
734
734
|
return key ? transients.get(key) : void 0;
|
|
735
735
|
};
|
|
736
|
+
var tabsOfMarks = (sections, marks) => {
|
|
737
|
+
const out = /* @__PURE__ */ new Map();
|
|
738
|
+
for (const section of sections)
|
|
739
|
+
for (const item of section.items) {
|
|
740
|
+
const key = keyOf(item);
|
|
741
|
+
if (key && marks.has(key)) out.set(key, section.id);
|
|
742
|
+
}
|
|
743
|
+
return out;
|
|
744
|
+
};
|
|
736
745
|
var quietly = $({ quiet: true });
|
|
737
746
|
var relativeTime = (iso) => {
|
|
738
747
|
const diff = (Date.now() - new Date(iso).getTime()) / 1e3;
|
|
@@ -1575,6 +1584,8 @@ var TRANSIT_LABEL = {
|
|
|
1575
1584
|
out: "GONE",
|
|
1576
1585
|
changed: "UPDATED"
|
|
1577
1586
|
};
|
|
1587
|
+
var TAB_MARK = "\u25CF";
|
|
1588
|
+
var tabLabel = (label, marked, id) => marked.size === 0 ? label : `${marked.has(id) ? TAB_MARK : " "} ${label}`;
|
|
1578
1589
|
var ItemRow = ({
|
|
1579
1590
|
item,
|
|
1580
1591
|
active,
|
|
@@ -1607,12 +1618,27 @@ var ItemRow = ({
|
|
|
1607
1618
|
] });
|
|
1608
1619
|
if (item.kind === "task") {
|
|
1609
1620
|
const note = item.note ?? "";
|
|
1610
|
-
const
|
|
1621
|
+
const transitIcon = !transient ? " " : transient === "out" ? TRANSIT_OUT_FRAMES[sparkFrame % TRANSIT_OUT_FRAMES.length] : transient === "in" ? TRANSIT_IN_FRAMES[sparkFrame % TRANSIT_IN_FRAMES.length] : "\u25C9";
|
|
1622
|
+
const transitLabel2 = transient ? TRANSIT_LABEL[transient] : "";
|
|
1623
|
+
const titleMax2 = Math.max(
|
|
1624
|
+
20,
|
|
1625
|
+
COLS - item.key.length - note.length - transitLabel2.length - 12
|
|
1626
|
+
);
|
|
1611
1627
|
return /* @__PURE__ */ jsxs(Box, { marginTop: gap ? 1 : 0, children: [
|
|
1612
1628
|
/* @__PURE__ */ jsx(Text2, { color: "cyan", children: active ? "\u276F " : " " }),
|
|
1629
|
+
/* @__PURE__ */ jsx(Text2, { bold: true, color: transient ? TRANSIT_COLOUR[transient] : void 0, children: transitIcon + " " }),
|
|
1613
1630
|
/* @__PURE__ */ jsx(Text2, { color: "#FF8700", bold: active, children: item.key + " " }),
|
|
1614
|
-
/* @__PURE__ */ jsx(
|
|
1615
|
-
|
|
1631
|
+
/* @__PURE__ */ jsx(
|
|
1632
|
+
Text2,
|
|
1633
|
+
{
|
|
1634
|
+
bold: active || transient === "in",
|
|
1635
|
+
dimColor: transient === "out",
|
|
1636
|
+
strikethrough: transient === "out",
|
|
1637
|
+
children: truncate(item.summary, titleMax2)
|
|
1638
|
+
}
|
|
1639
|
+
),
|
|
1640
|
+
note ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: ` ${note}` }) : null,
|
|
1641
|
+
transitLabel2 ? /* @__PURE__ */ jsx(Text2, { bold: true, color: TRANSIT_COLOUR[transient], children: " " + transitLabel2 }) : null
|
|
1616
1642
|
] });
|
|
1617
1643
|
}
|
|
1618
1644
|
const { glyph: healthIcon, color: healthColor2 } = healthDisplay[item.health];
|
|
@@ -1947,7 +1973,8 @@ var BrowseScreen = ({
|
|
|
1947
1973
|
initialIncludeWork,
|
|
1948
1974
|
brand,
|
|
1949
1975
|
mergedUrls,
|
|
1950
|
-
transients
|
|
1976
|
+
transients,
|
|
1977
|
+
onTabChange
|
|
1951
1978
|
}) => {
|
|
1952
1979
|
const { rows } = useWindowSize();
|
|
1953
1980
|
const [includeWork, setIncludeWork] = useState(
|
|
@@ -1963,6 +1990,9 @@ var BrowseScreen = ({
|
|
|
1963
1990
|
const [viewStarts, setViewStarts] = useState({});
|
|
1964
1991
|
const safeTabIdx = Math.min(tabIdx, Math.max(0, localSections.length - 1));
|
|
1965
1992
|
const activeId = localSections[safeTabIdx]?.id ?? "";
|
|
1993
|
+
useEffect(() => {
|
|
1994
|
+
onTabChange?.(activeId);
|
|
1995
|
+
}, [activeId]);
|
|
1966
1996
|
const [flash, setFlash] = useState(null);
|
|
1967
1997
|
const menu = useActionMenu();
|
|
1968
1998
|
const [search, setSearch] = useState(null);
|
|
@@ -2037,8 +2067,15 @@ var BrowseScreen = ({
|
|
|
2037
2067
|
setFlash(msg);
|
|
2038
2068
|
setTimeout(() => setFlash(null), 2e3);
|
|
2039
2069
|
};
|
|
2070
|
+
const markedTabs = useMemo(() => {
|
|
2071
|
+
const out = /* @__PURE__ */ new Set();
|
|
2072
|
+
if (!transients?.size) return out;
|
|
2073
|
+
for (const s of localSections)
|
|
2074
|
+
if (s.items.some((item) => transientOf(transients, item))) out.add(s.id);
|
|
2075
|
+
return out;
|
|
2076
|
+
}, [localSections, transients]);
|
|
2040
2077
|
const [sparkFrame, setSparkFrame] = useState(0);
|
|
2041
|
-
const sparkling = (mergedUrls?.length ?? 0) > 0 ||
|
|
2078
|
+
const sparkling = (mergedUrls?.length ?? 0) > 0 || !!transients?.size && section.items.some((item) => transientOf(transients, item));
|
|
2042
2079
|
useEffect(() => {
|
|
2043
2080
|
if (!sparkling) return;
|
|
2044
2081
|
const id = setInterval(() => setSparkFrame((f) => f + 1), MERGED_FRAME_MS);
|
|
@@ -2387,7 +2424,7 @@ var BrowseScreen = ({
|
|
|
2387
2424
|
active: section.id,
|
|
2388
2425
|
items: localSections.map((s) => ({
|
|
2389
2426
|
value: s.id,
|
|
2390
|
-
label: s.label,
|
|
2427
|
+
label: tabLabel(s.label, markedTabs, s.id),
|
|
2391
2428
|
count: topLevelCount(s)
|
|
2392
2429
|
}))
|
|
2393
2430
|
}
|
|
@@ -2515,13 +2552,8 @@ var App = ({
|
|
|
2515
2552
|
const displayedKey = useRef("");
|
|
2516
2553
|
const displayedSections = useRef([]);
|
|
2517
2554
|
const [transients, setTransients] = useState(NO_TRANSIENTS);
|
|
2518
|
-
const
|
|
2519
|
-
|
|
2520
|
-
() => () => {
|
|
2521
|
-
if (transitTimer.current) clearTimeout(transitTimer.current);
|
|
2522
|
-
},
|
|
2523
|
-
[]
|
|
2524
|
-
);
|
|
2555
|
+
const transitTabs = useRef(/* @__PURE__ */ new Map());
|
|
2556
|
+
const [visibleTab, setVisibleTab] = useState("");
|
|
2525
2557
|
const showData = (sections, login) => {
|
|
2526
2558
|
const before = displayedSections.current;
|
|
2527
2559
|
displayedSections.current = sections;
|
|
@@ -2529,25 +2561,61 @@ var App = ({
|
|
|
2529
2561
|
setPending(null);
|
|
2530
2562
|
setFetchedAt(Date.now());
|
|
2531
2563
|
if (before.length === 0) {
|
|
2564
|
+
transitTabs.current = /* @__PURE__ */ new Map();
|
|
2532
2565
|
setTransients(NO_TRANSIENTS);
|
|
2533
2566
|
setState({ phase: "browse", sections, login });
|
|
2534
2567
|
return;
|
|
2535
2568
|
}
|
|
2536
|
-
const { transients:
|
|
2569
|
+
const { transients: fresh, union } = diffSections(before, sections);
|
|
2570
|
+
const marks = new Map(fresh);
|
|
2571
|
+
for (const [key, mark] of transients)
|
|
2572
|
+
if (!marks.has(key)) marks.set(key, mark);
|
|
2573
|
+
const tabs = tabsOfMarks(union, marks);
|
|
2574
|
+
for (const key of [...marks.keys()]) if (!tabs.has(key)) marks.delete(key);
|
|
2537
2575
|
if (marks.size === 0) {
|
|
2576
|
+
transitTabs.current = /* @__PURE__ */ new Map();
|
|
2577
|
+
setTransients(NO_TRANSIENTS);
|
|
2538
2578
|
setState({ phase: "browse", sections, login });
|
|
2539
2579
|
return;
|
|
2540
2580
|
}
|
|
2581
|
+
transitTabs.current = tabs;
|
|
2541
2582
|
setTransients(marks);
|
|
2542
2583
|
setState({ phase: "browse", sections: union, login });
|
|
2543
|
-
if (transitTimer.current) clearTimeout(transitTimer.current);
|
|
2544
|
-
transitTimer.current = setTimeout(() => {
|
|
2545
|
-
setTransients(NO_TRANSIENTS);
|
|
2546
|
-
setState(
|
|
2547
|
-
(prev) => prev.phase === "browse" && prev.sections === union ? { ...prev, sections } : prev
|
|
2548
|
-
);
|
|
2549
|
-
}, TRANSIT_HOLD_MS);
|
|
2550
2584
|
};
|
|
2585
|
+
const settleTab = (tabId, marks) => {
|
|
2586
|
+
const keys = [...transitTabs.current].filter(([, tab]) => tab === tabId).map(([key]) => key);
|
|
2587
|
+
for (const key of keys) transitTabs.current.delete(key);
|
|
2588
|
+
const gone = new Set(keys.filter((key) => marks.get(key) === "out"));
|
|
2589
|
+
setTransients((prev) => {
|
|
2590
|
+
const next = new Map(prev);
|
|
2591
|
+
for (const key of keys) next.delete(key);
|
|
2592
|
+
return next.size === 0 ? NO_TRANSIENTS : next;
|
|
2593
|
+
});
|
|
2594
|
+
setState(
|
|
2595
|
+
(prev) => prev.phase !== "browse" ? prev : {
|
|
2596
|
+
...prev,
|
|
2597
|
+
sections: prev.sections.map(
|
|
2598
|
+
(section) => section.id !== tabId ? section : {
|
|
2599
|
+
...section,
|
|
2600
|
+
items: section.items.filter((item) => {
|
|
2601
|
+
const key = keyOf(item);
|
|
2602
|
+
return !(key && gone.has(key));
|
|
2603
|
+
})
|
|
2604
|
+
}
|
|
2605
|
+
)
|
|
2606
|
+
}
|
|
2607
|
+
);
|
|
2608
|
+
};
|
|
2609
|
+
useEffect(() => {
|
|
2610
|
+
if (transients.size === 0) return;
|
|
2611
|
+
if (state.phase !== "browse" || !visibleTab) return;
|
|
2612
|
+
if (![...transitTabs.current.values()].includes(visibleTab)) return;
|
|
2613
|
+
const timer = setTimeout(
|
|
2614
|
+
() => settleTab(visibleTab, transients),
|
|
2615
|
+
TRANSIT_HOLD_MS
|
|
2616
|
+
);
|
|
2617
|
+
return () => clearTimeout(timer);
|
|
2618
|
+
}, [transients, visibleTab, state.phase]);
|
|
2551
2619
|
const pendingSummary = useMemo(
|
|
2552
2620
|
() => pending ? summariseDiff(
|
|
2553
2621
|
diffSections(displayedSections.current, pending.sections).counts
|
|
@@ -2732,6 +2800,7 @@ var App = ({
|
|
|
2732
2800
|
hidden: overlay !== null,
|
|
2733
2801
|
mergedUrls,
|
|
2734
2802
|
transients,
|
|
2803
|
+
onTabChange: setVisibleTab,
|
|
2735
2804
|
ciStatusState: hasCiStatus ? ciStatusState : void 0,
|
|
2736
2805
|
ciJob,
|
|
2737
2806
|
tabHelp,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kud/gh-ink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.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",
|