@kud/gh-ink 0.9.0 → 0.10.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 CHANGED
@@ -67,6 +67,7 @@ type GHItem = {
67
67
  health: Health;
68
68
  author?: string;
69
69
  age: string;
70
+ activityAge?: string;
70
71
  ts: number;
71
72
  unresolved: number;
72
73
  conversation: number;
@@ -217,7 +218,7 @@ declare const ActionMenu: ({ item, actions, cursor, }: {
217
218
  actions: Action[];
218
219
  cursor: number;
219
220
  }) => React.JSX.Element;
220
- declare const App: ({ fetcher, cacheKey, title, detailFor, isWorkRepo, initialIncludeWork, jiraBase, jiraKeyRe, jiraTransitions, workToggle, hasCiStatus, ciJob, ciFetcher, ciPollMs, extensions, tabHelp, }: {
221
+ declare const App: ({ fetcher, cacheKey, title, detailFor, isWorkRepo, initialIncludeWork, jiraBase, jiraKeyRe, jiraTransitions, workToggle, hasCiStatus, ciJob, ciFetcher, ciPollMs, extensions, tabHelp, emptyHint, }: {
221
222
  fetcher: () => Promise<{
222
223
  sections: Section[];
223
224
  login: string;
@@ -229,6 +230,7 @@ declare const App: ({ fetcher, cacheKey, title, detailFor, isWorkRepo, initialIn
229
230
  isWorkRepo?: (repo: string) => boolean;
230
231
  initialIncludeWork?: boolean;
231
232
  tabHelp?: [string, string][];
233
+ emptyHint?: string;
232
234
  jiraBase?: string;
233
235
  jiraKeyRe?: RegExp;
234
236
  jiraTransitions?: JiraTransition[];
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import React2, { createContext, useState, useRef, useEffect, useContext } from 'react';
2
2
  import { useWindowSize, useInput, Text, Box } from 'ink';
3
- import { colors, ScrollView, TextInput, LoadingScreen, Switch, useListCursor, Tabs, FooterHints } from '@kud/ink-ui';
3
+ import { colors, ScrollView, TextInput, LoadingScreen, Switch, StatusMessage, FooterHints, useListCursor, Tabs } from '@kud/ink-ui';
4
4
  import { isPassCheck, isFailCheck, resolveThread, unresolveThread, replyToThread, rerunFailedRun, mergePr, reRequestReviewer } from '@kud/gh';
5
5
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
6
  import { $ } from 'zx';
@@ -733,7 +733,9 @@ var repoPriority = (repo) => {
733
733
  };
734
734
  var sortItems = (items) => [...items].sort((a, b) => {
735
735
  const pd = repoPriority(a.repo) - repoPriority(b.repo);
736
- return pd !== 0 ? pd : a.repo.localeCompare(b.repo);
736
+ if (pd !== 0) return pd;
737
+ const rd = a.repo.localeCompare(b.repo);
738
+ return rd !== 0 ? rd : b.ts - a.ts;
737
739
  });
738
740
  var sortByRecency = (items) => [...items].sort((a, b) => b.ts - a.ts);
739
741
  var insertRepoHeaders = (items) => {
@@ -1363,13 +1365,14 @@ var InboxHeader = ({
1363
1365
  brand,
1364
1366
  work,
1365
1367
  loading,
1368
+ quiet,
1366
1369
  refreshing,
1367
1370
  hasPending,
1368
1371
  fetchedAt
1369
1372
  }) => {
1370
1373
  const total = sections.reduce((n, s) => n + topLevelCount(s), 0);
1371
- const countSeg = loading ? " loading\u2026 " : ` ${String(total).padStart(3)} item${total !== 1 ? "s" : ""} \xB7 `;
1372
- const userSeg = loading ? "" : `@${login} `;
1374
+ const countSeg = loading ? " loading\u2026 " : quiet ? " " : ` ${String(total).padStart(3)} item${total !== 1 ? "s" : ""} \xB7 `;
1375
+ const userSeg = loading || quiet ? "" : `@${login} `;
1373
1376
  const workLabel = work === void 0 ? "" : " w work \u25CF\u2500\u25CB home ";
1374
1377
  const [statusText, statusColor] = hasPending ? ["\u25CF new \xB7 r apply", "#FF8700"] : refreshing ? ["\u21BB refreshing\u2026", "cyan"] : fetchedAt ? [`updated ${agoText(fetchedAt)}`, void 0] : ["", void 0];
1375
1378
  const statusSeg = statusText ? statusText + " " : "";
@@ -1483,8 +1486,9 @@ var ItemRow = ({
1483
1486
  const numStr = `#${item.number}`.padEnd(7);
1484
1487
  const showAuthor = !!item.author && item.author !== login;
1485
1488
  const unresolvedLabel = item.unresolved > 0 ? `\uF086 ${item.unresolved}` : "";
1489
+ const ageLabel = item.activityAge && item.activityAge !== item.age ? `${item.activityAge} \xB7 ${item.age}` : item.age;
1486
1490
  const suffix = [
1487
- item.age || "",
1491
+ ageLabel || "",
1488
1492
  unresolvedLabel,
1489
1493
  showAuthor ? `by ${item.author}` : ""
1490
1494
  ].filter(Boolean).join(" ");
@@ -1501,7 +1505,7 @@ var ItemRow = ({
1501
1505
  repoLabel ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: repoLabel }) : null,
1502
1506
  unresolvedLabel ? /* @__PURE__ */ jsx(Text2, { bold: true, color: "#FF8700", children: " " + unresolvedLabel }) : null,
1503
1507
  showAuthor ? /* @__PURE__ */ jsx(Text2, { dimColor: true, italic: true, children: " by " + item.author }) : null,
1504
- item.age ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " " + item.age }) : null
1508
+ ageLabel ? /* @__PURE__ */ jsx(Text2, { dimColor: true, children: " " + ageLabel }) : null
1505
1509
  ] });
1506
1510
  };
1507
1511
  var useActionMenu = () => {
@@ -2280,6 +2284,29 @@ var BrowseScreen = ({
2280
2284
  }
2281
2285
  );
2282
2286
  };
2287
+ var NoRowsScreen = ({
2288
+ reason,
2289
+ detail,
2290
+ onRetry
2291
+ }) => {
2292
+ useInput((input) => {
2293
+ if (input === "q") process.exit(0);
2294
+ if (input === "r") onRetry();
2295
+ });
2296
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
2297
+ /* @__PURE__ */ jsx(StatusMessage, { variant: reason === "empty" ? "info" : "error", children: reason === "empty" ? "Nothing open." : `Fetch failed \u2014 ${detail ?? "no reason reported"}` }),
2298
+ reason === "empty" && detail ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text2, { dimColor: true, children: detail }) }) : null,
2299
+ /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(
2300
+ FooterHints,
2301
+ {
2302
+ hints: [
2303
+ ["r", "retry"],
2304
+ ["q", "quit"]
2305
+ ]
2306
+ }
2307
+ ) })
2308
+ ] });
2309
+ };
2283
2310
  var signatureOf = (sections) => JSON.stringify(sections, (k, v) => k === "age" ? void 0 : v);
2284
2311
  var App = ({
2285
2312
  fetcher,
@@ -2297,7 +2324,8 @@ var App = ({
2297
2324
  ciFetcher,
2298
2325
  ciPollMs = 6e4,
2299
2326
  extensions,
2300
- tabHelp
2327
+ tabHelp,
2328
+ emptyHint
2301
2329
  }) => {
2302
2330
  const [state, setState] = useState({ phase: "loading" });
2303
2331
  const [pending, setPending] = useState(null);
@@ -2329,8 +2357,8 @@ var App = ({
2329
2357
  const freshKey = signatureOf(fresh.sections);
2330
2358
  if (!displayedKey.current) {
2331
2359
  if (fresh.sections.length === 0) {
2332
- console.log(`${title[0].toUpperCase()}${title.slice(1)} empty.`);
2333
- process.exit(0);
2360
+ setState({ phase: "empty" });
2361
+ return;
2334
2362
  }
2335
2363
  showData(fresh.sections, fresh.login);
2336
2364
  } else if (freshKey !== displayedKey.current) {
@@ -2342,8 +2370,8 @@ var App = ({
2342
2370
  setRefreshing(false);
2343
2371
  const message = err.message;
2344
2372
  if (!displayedKey.current) {
2345
- console.error("Error:", message);
2346
- process.exit(1);
2373
+ setState({ phase: "failed", message });
2374
+ return;
2347
2375
  }
2348
2376
  setRefreshError({ message, at: Date.now() });
2349
2377
  });
@@ -2387,7 +2415,7 @@ var App = ({
2387
2415
  clearInterval(id);
2388
2416
  };
2389
2417
  }, [hasCiStatus, ciFetcher, ciPollMs]);
2390
- if (state.phase === "loading")
2418
+ if (state.phase === "loading" || state.phase === "empty" || state.phase === "failed")
2391
2419
  return /* @__PURE__ */ jsxs(
2392
2420
  Box,
2393
2421
  {
@@ -2404,12 +2432,20 @@ var App = ({
2404
2432
  brand: brandOf(title),
2405
2433
  sections: [],
2406
2434
  login: "",
2407
- work: workToggle ? initialIncludeWork ?? true : void 0,
2408
- loading: true
2435
+ work: workToggle && state.phase === "loading" ? initialIncludeWork ?? true : void 0,
2436
+ loading: state.phase === "loading",
2437
+ quiet: state.phase !== "loading"
2409
2438
  }
2410
2439
  ),
2411
2440
  hasCiStatus ? /* @__PURE__ */ jsx(CiStatusLine, { state: ciStatusState, job: ciJob }) : null,
2412
- /* @__PURE__ */ jsx(LoadingScreen, { label: `Fetching ${title}\u2026` })
2441
+ state.phase === "loading" ? /* @__PURE__ */ jsx(LoadingScreen, { label: `Fetching ${title}\u2026` }) : /* @__PURE__ */ jsx(
2442
+ NoRowsScreen,
2443
+ {
2444
+ reason: state.phase === "empty" ? "empty" : "failed",
2445
+ detail: state.phase === "failed" ? state.message : emptyHint,
2446
+ onRetry: () => revalidate(true)
2447
+ }
2448
+ )
2413
2449
  ]
2414
2450
  }
2415
2451
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kud/gh-ink",
3
- "version": "0.9.0",
3
+ "version": "0.10.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",