@kud/gh-ink 0.30.0 → 0.32.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 +17 -1
- package/dist/index.js +42 -18
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -124,6 +124,22 @@ type GHItem = {
|
|
|
124
124
|
* never about the PR. Left unset, the section id decides as before.
|
|
125
125
|
*/
|
|
126
126
|
standing?: Standing;
|
|
127
|
+
/**
|
|
128
|
+
* A turn the viewer has claimed BY HAND, outranking everything inferred.
|
|
129
|
+
*
|
|
130
|
+
* The inference below is good and still gets things wrong in one direction it
|
|
131
|
+
* cannot see: a row can be genuinely yours while every signal says otherwise —
|
|
132
|
+
* nothing red, no unresolved thread, nobody waiting on a word from you — and
|
|
133
|
+
* no amount of reading the PR harder will discover it. That knowledge lives
|
|
134
|
+
* with the viewer, so this is the field where they put it.
|
|
135
|
+
*
|
|
136
|
+
* It is a PIN, not a correction: it applies whether or not the row was already
|
|
137
|
+
* yours, which is why it does not pair with an opposite. The other direction —
|
|
138
|
+
* "no reply is owed for this particular comment" — is a fact about one event
|
|
139
|
+
* and belongs where the events are read, not here; a host expresses it by
|
|
140
|
+
* handing back a `lastActor` that no longer claims a turn.
|
|
141
|
+
*/
|
|
142
|
+
pinned?: boolean;
|
|
127
143
|
indent: boolean;
|
|
128
144
|
};
|
|
129
145
|
type TaskRow = {
|
|
@@ -240,7 +256,7 @@ declare const sortItems: (items: GHItem[]) => GHItem[];
|
|
|
240
256
|
declare const sortByRecency: (items: GHItem[]) => GHItem[];
|
|
241
257
|
declare const insertRepoHeaders: (items: GHItem[]) => AnyItem[];
|
|
242
258
|
type Standing = "authored" | "queued" | "spoken";
|
|
243
|
-
declare const whoseMove: (health: Health, sectionId: string, standing?: Standing, theySpokeLast?: boolean) => "you" | "them";
|
|
259
|
+
declare const whoseMove: (health: Health, sectionId: string, standing?: Standing, theySpokeLast?: boolean, pinned?: boolean) => "you" | "them";
|
|
244
260
|
declare const layoutGHItems: (items: GHItem[], sectionId: string, login?: string) => AnyItem[];
|
|
245
261
|
/**
|
|
246
262
|
* A two-way repo split, when a host has one. `undefined` — the ordinary case —
|
package/dist/index.js
CHANGED
|
@@ -838,6 +838,10 @@ var checksSentence = (d) => {
|
|
|
838
838
|
return `Checks: ${parts.join(", ")}.`;
|
|
839
839
|
};
|
|
840
840
|
var turnSentences = (item, login) => {
|
|
841
|
+
if (item.pinned)
|
|
842
|
+
return [
|
|
843
|
+
"You pinned this (!). It stays under Your move until you unpin it, whatever else the row says."
|
|
844
|
+
];
|
|
841
845
|
if (!item.lastActor) return ["Nothing has been said on it yet."];
|
|
842
846
|
const d = item.detail;
|
|
843
847
|
const when = d?.lastEventAt ? `${relativeTime(d.lastEventAt)} ago` : "earlier";
|
|
@@ -937,8 +941,9 @@ var YOURS = {
|
|
|
937
941
|
queued: ["waiting", "pending", "threads", "approved"],
|
|
938
942
|
spoken: ["threads"]
|
|
939
943
|
};
|
|
940
|
-
var whoseMove = (health, sectionId, standing, theySpokeLast) => {
|
|
944
|
+
var whoseMove = (health, sectionId, standing, theySpokeLast, pinned) => {
|
|
941
945
|
const position = standing ?? STANDING[sectionId] ?? "queued";
|
|
946
|
+
if (pinned) return "you";
|
|
942
947
|
if (theySpokeLast && position === "authored") return "you";
|
|
943
948
|
return YOURS[position].includes(health) ? "you" : "them";
|
|
944
949
|
};
|
|
@@ -956,7 +961,8 @@ var layoutGHItems = (items, sectionId, login) => {
|
|
|
956
961
|
i.health,
|
|
957
962
|
sectionId,
|
|
958
963
|
i.standing,
|
|
959
|
-
!!login && !!i.lastActor && i.lastActor !== login
|
|
964
|
+
!!login && !!i.lastActor && i.lastActor !== login,
|
|
965
|
+
i.pinned
|
|
960
966
|
) === side
|
|
961
967
|
)
|
|
962
968
|
}));
|
|
@@ -1778,6 +1784,7 @@ var TRANSIT_LABEL = {
|
|
|
1778
1784
|
out: "GONE",
|
|
1779
1785
|
changed: "UPDATED"
|
|
1780
1786
|
};
|
|
1787
|
+
var LEAVING_HOLD_MS = 2500;
|
|
1781
1788
|
var TAB_MARK = "\u25CF";
|
|
1782
1789
|
var tabLabel = (label, marked, id) => marked.size === 0 ? label : `${marked.has(id) ? TAB_MARK : " "} ${label}`;
|
|
1783
1790
|
var ItemRow = ({
|
|
@@ -1786,11 +1793,13 @@ var ItemRow = ({
|
|
|
1786
1793
|
gap,
|
|
1787
1794
|
login,
|
|
1788
1795
|
merged,
|
|
1789
|
-
transient,
|
|
1796
|
+
transient: refreshMark,
|
|
1797
|
+
leaving,
|
|
1790
1798
|
lastChild,
|
|
1791
1799
|
parent,
|
|
1792
1800
|
sparkFrame = 0
|
|
1793
1801
|
}) => {
|
|
1802
|
+
const transient = leaving ? "out" : refreshMark;
|
|
1794
1803
|
if (item.kind === "repo-header")
|
|
1795
1804
|
return /* @__PURE__ */ jsx(RepoHeaderRow, { repo: item.repo, gap: gap ?? false });
|
|
1796
1805
|
if (item.kind === "subgroup-header")
|
|
@@ -1842,7 +1851,7 @@ var ItemRow = ({
|
|
|
1842
1851
|
const icon = merged ? MERGED_FRAMES[sparkFrame % MERGED_FRAMES.length] : transient === "out" ? TRANSIT_OUT_FRAMES[sparkFrame % TRANSIT_OUT_FRAMES.length] : transient === "in" ? TRANSIT_IN_FRAMES[sparkFrame % TRANSIT_IN_FRAMES.length] : healthIcon;
|
|
1843
1852
|
const color = merged ? MERGED_COLOUR : transient ? TRANSIT_COLOUR[transient] : healthColor2;
|
|
1844
1853
|
const spokeLast = !!login && !!item.lastActor && item.lastActor === login;
|
|
1845
|
-
const [turnIcon, turnColor] = !login || !item.lastActor ? [" ", "white"] : spokeLast ? ["\u2192", "#888888"] : ["\u2190", "#FF8700"];
|
|
1854
|
+
const [turnIcon, turnColor] = item.pinned ? ["!", "#FF8700"] : !login || !item.lastActor ? [" ", "white"] : spokeLast ? ["\u2192", "#888888"] : ["\u2190", "#FF8700"];
|
|
1846
1855
|
const numStr = `#${item.number}`.padEnd(7);
|
|
1847
1856
|
const showAuthor = !!item.author && item.author !== login;
|
|
1848
1857
|
const unresolvedLabel = item.unresolved > 0 ? `\uF086 ${item.unresolved}` : "";
|
|
@@ -2212,6 +2221,8 @@ var BrowseScreen = ({
|
|
|
2212
2221
|
skippedForBudget,
|
|
2213
2222
|
brand,
|
|
2214
2223
|
mergedUrls,
|
|
2224
|
+
leavingUrls,
|
|
2225
|
+
onLeave,
|
|
2215
2226
|
transients,
|
|
2216
2227
|
onTabChange
|
|
2217
2228
|
}) => {
|
|
@@ -2281,7 +2292,7 @@ var BrowseScreen = ({
|
|
|
2281
2292
|
)
|
|
2282
2293
|
);
|
|
2283
2294
|
}, [localSections, listHeight]);
|
|
2284
|
-
const
|
|
2295
|
+
const dismissItem = (target) => onLeave ? onLeave(target) : setLocalSections((prev) => withoutItem(prev, target));
|
|
2285
2296
|
const rawSection = localSections[safeTabIdx] ?? {
|
|
2286
2297
|
id: "empty",
|
|
2287
2298
|
label: "",
|
|
@@ -2313,7 +2324,7 @@ var BrowseScreen = ({
|
|
|
2313
2324
|
return out;
|
|
2314
2325
|
}, [localSections, transients]);
|
|
2315
2326
|
const [sparkFrame, setSparkFrame] = useState(0);
|
|
2316
|
-
const sparkling = (mergedUrls?.length ?? 0) > 0 || !!transients?.size && section.items.some((item) => transientOf(transients, item));
|
|
2327
|
+
const sparkling = (mergedUrls?.length ?? 0) > 0 || (leavingUrls?.length ?? 0) > 0 || !!transients?.size && section.items.some((item) => transientOf(transients, item));
|
|
2317
2328
|
useEffect(() => {
|
|
2318
2329
|
if (!sparkling) return;
|
|
2319
2330
|
const id = setInterval(() => setSparkFrame((f) => f + 1), MERGED_FRAME_MS);
|
|
@@ -2346,7 +2357,7 @@ var BrowseScreen = ({
|
|
|
2346
2357
|
jiraKeyRe,
|
|
2347
2358
|
jiraTransitions,
|
|
2348
2359
|
onRefresh,
|
|
2349
|
-
|
|
2360
|
+
dismissItem,
|
|
2350
2361
|
openDrillView,
|
|
2351
2362
|
{ extensions, onOpenExt, onActed }
|
|
2352
2363
|
);
|
|
@@ -2453,7 +2464,7 @@ var BrowseScreen = ({
|
|
|
2453
2464
|
item: activeItem ?? void 0,
|
|
2454
2465
|
ciJob: ciStatus?.job,
|
|
2455
2466
|
login,
|
|
2456
|
-
onRemove: (row) =>
|
|
2467
|
+
onRemove: (row) => dismissItem(row),
|
|
2457
2468
|
showFlash
|
|
2458
2469
|
});
|
|
2459
2470
|
return;
|
|
@@ -2562,7 +2573,7 @@ var BrowseScreen = ({
|
|
|
2562
2573
|
return;
|
|
2563
2574
|
}
|
|
2564
2575
|
if (input === "x" && activeItem.kind === "pr" && activeItem.standing === "queued" && login) {
|
|
2565
|
-
|
|
2576
|
+
dismissItem(activeItem);
|
|
2566
2577
|
showFlash(`\u22EF Removing you from #${activeItem.number}\u2026`);
|
|
2567
2578
|
void quietly`gh pr edit ${activeItem.number} --repo ${activeItem.repo} --remove-reviewer ${login}`.then(() => {
|
|
2568
2579
|
showFlash(`\u2713 Removed you as reviewer on #${activeItem.number}`);
|
|
@@ -2729,6 +2740,7 @@ var BrowseScreen = ({
|
|
|
2729
2740
|
active: viewStart + i === cursor,
|
|
2730
2741
|
login,
|
|
2731
2742
|
merged: (item.kind === "pr" || item.kind === "issue") && !!mergedUrls?.includes(item.url),
|
|
2743
|
+
leaving: (item.kind === "pr" || item.kind === "issue") && !!leavingUrls?.includes(item.url),
|
|
2732
2744
|
transient: transientOf(transients, item),
|
|
2733
2745
|
lastChild: "indent" in item && item.indent ? !isChildRow(section.items[viewStart + i + 1]) : void 0,
|
|
2734
2746
|
parent: item.kind === "task" && isChildRow(section.items[viewStart + i + 1]),
|
|
@@ -3043,8 +3055,9 @@ var App = ({
|
|
|
3043
3055
|
);
|
|
3044
3056
|
const [skippedForBudget, setSkippedForBudget] = useState(false);
|
|
3045
3057
|
const [mergedUrls, setMergedUrls] = useState([]);
|
|
3046
|
-
const
|
|
3047
|
-
|
|
3058
|
+
const [leavingUrls, setLeavingUrls] = useState([]);
|
|
3059
|
+
const holdTimers = useRef([]);
|
|
3060
|
+
useEffect(() => () => holdTimers.current.forEach(clearTimeout), []);
|
|
3048
3061
|
if (state.phase === "loading" || state.phase === "empty" || state.phase === "failed")
|
|
3049
3062
|
return /* @__PURE__ */ jsxs(
|
|
3050
3063
|
Box,
|
|
@@ -3092,17 +3105,26 @@ var App = ({
|
|
|
3092
3105
|
target: state.target
|
|
3093
3106
|
} : null;
|
|
3094
3107
|
const toBrowse = () => setState({ phase: "browse", sections: state.sections, login: state.login });
|
|
3095
|
-
const
|
|
3096
|
-
phase
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3108
|
+
const markLeaving = (target) => {
|
|
3109
|
+
if (state.phase !== "browse") toBrowse();
|
|
3110
|
+
setLeavingUrls(
|
|
3111
|
+
(prev) => prev.includes(target.url) ? prev : [...prev, target.url]
|
|
3112
|
+
);
|
|
3113
|
+
holdTimers.current.push(
|
|
3114
|
+
setTimeout(() => {
|
|
3115
|
+
setLeavingUrls((prev) => prev.filter((u) => u !== target.url));
|
|
3116
|
+
setState(
|
|
3117
|
+
(s) => s.phase === "browse" ? { ...s, sections: withoutItem(s.sections, target) } : s
|
|
3118
|
+
);
|
|
3119
|
+
}, LEAVING_HOLD_MS)
|
|
3120
|
+
);
|
|
3121
|
+
};
|
|
3100
3122
|
const markMerged = (target) => {
|
|
3101
3123
|
toBrowse();
|
|
3102
3124
|
setMergedUrls(
|
|
3103
3125
|
(prev) => prev.includes(target.url) ? prev : [...prev, target.url]
|
|
3104
3126
|
);
|
|
3105
|
-
|
|
3127
|
+
holdTimers.current.push(
|
|
3106
3128
|
setTimeout(() => {
|
|
3107
3129
|
setMergedUrls((prev) => prev.filter((u) => u !== target.url));
|
|
3108
3130
|
setState(
|
|
@@ -3133,6 +3155,8 @@ var App = ({
|
|
|
3133
3155
|
skippedForBudget,
|
|
3134
3156
|
hidden: overlay !== null,
|
|
3135
3157
|
mergedUrls,
|
|
3158
|
+
leavingUrls,
|
|
3159
|
+
onLeave: markLeaving,
|
|
3136
3160
|
transients,
|
|
3137
3161
|
onTabChange: setVisibleTab,
|
|
3138
3162
|
ciStatusState: hasCiStatus ? ciStatusState : void 0,
|
|
@@ -3166,7 +3190,7 @@ var App = ({
|
|
|
3166
3190
|
login: state.login,
|
|
3167
3191
|
onBack: toBrowse,
|
|
3168
3192
|
onRefresh: applyOrRefresh,
|
|
3169
|
-
onRemove:
|
|
3193
|
+
onRemove: markLeaving,
|
|
3170
3194
|
onMerged: markMerged
|
|
3171
3195
|
}),
|
|
3172
3196
|
overlay?.kind === "ext" && extensions?.find((e) => e.id === overlay.extId)?.body(toBrowse, overlay.target)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kud/gh-ink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.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",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"react": ">=19"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@kud/gh": "0.
|
|
51
|
+
"@kud/gh": "0.9.0",
|
|
52
52
|
"@kud/ink-ui": "0.14.0",
|
|
53
53
|
"zx": "8.8.5"
|
|
54
54
|
},
|