@kud/gh-ink 0.68.1 → 0.69.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 +45 -7
- package/dist/index.js +216 -46
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { ReactNode } from 'react';
|
|
2
2
|
import { PrComments, PrHealthData, PrCheck, Health } from '@kud/gh';
|
|
3
|
-
import { GHItem, AnyItem, Section, CiStatus, OriginSplit } from '@kud/gh-workflow';
|
|
3
|
+
import { GHItem, AnyItem, Section, CiStatus, OriginSplit, TaskRow } from '@kud/gh-workflow';
|
|
4
4
|
export { AnyItem, Band, CiStatus, GHDetail, GHItem, InboxConfig, Move, NEEDS_YOU_SECTION, NeedsYou, OriginSplit, PIN_MARK, RepoHeader, RepoProfile, Section, ShowLess, ShowMore, Standing, SubgroupHeader, TaskRow, bandOf, checkoutDirs, configureInbox, filterByOrigin, filterByRepos, filterBySearch, impliedLabels, inboxConfig, insertRepoHeaders, labelPriority, layoutGHItems, profileOf, relativeTime, repoPriority, resetInboxConfig, sortByRecency, sortItems, whoseMove } from '@kud/gh-workflow';
|
|
5
5
|
import { StyledLine } from '@kud/ink-ui';
|
|
6
6
|
|
|
@@ -272,11 +272,17 @@ type PrRowProps = {
|
|
|
272
272
|
gutter?: boolean;
|
|
273
273
|
};
|
|
274
274
|
/**
|
|
275
|
-
* The trailing block, in reading order: how contested, how big, how
|
|
276
|
-
*
|
|
277
|
-
*
|
|
275
|
+
* The trailing block, in reading order: whose, how contested, how big, how
|
|
276
|
+
* recent. Author leads because it is read as a column of names rather than
|
|
277
|
+
* scanned per row; threads follow because they are the one cell that makes a
|
|
278
|
+
* claim on you; age ends the row so every row ends on the date.
|
|
279
|
+
*
|
|
280
|
+
* Fixed columns rather than inline text: `by <login>` used to sit right after
|
|
281
|
+
* the title, so its position floated with title length and finding one
|
|
282
|
+
* author's rows meant reading each line. Aligned, the eye runs down a column
|
|
283
|
+
* instead — the same move the 2026-09-30 alignment made for the other three.
|
|
278
284
|
*/
|
|
279
|
-
declare const TRAILING: readonly ["threads", "size", "age"];
|
|
285
|
+
declare const TRAILING: readonly ["author", "threads", "size", "age"];
|
|
280
286
|
/** Width of each trailing column, in terminal cells. Zero draws no column. */
|
|
281
287
|
type TrailingColumns = Record<(typeof TRAILING)[number], number>;
|
|
282
288
|
/** Which trailing columns a whole section has given up. */
|
|
@@ -554,6 +560,7 @@ type Action = {
|
|
|
554
560
|
subActions?: Action[];
|
|
555
561
|
group?: ActionGroup;
|
|
556
562
|
icon?: string;
|
|
563
|
+
tone?: "dim" | "error";
|
|
557
564
|
};
|
|
558
565
|
type MenuGap = {
|
|
559
566
|
gap: true;
|
|
@@ -577,6 +584,27 @@ type JiraTransition = {
|
|
|
577
584
|
/** Offered as a second step when the transition asks for a resolution. */
|
|
578
585
|
resolutions?: string[];
|
|
579
586
|
};
|
|
587
|
+
/**
|
|
588
|
+
* One transition the ticket's workflow currently allows, as the host resolved
|
|
589
|
+
* it — the shape `jira issue move KEY --json` reports, trimmed to what the
|
|
590
|
+
* menu needs. `id` is carried so a future executor that can address a
|
|
591
|
+
* transition directly has it; today's `jira issue move` takes only the NAME,
|
|
592
|
+
* so execution passes `name` verbatim and `id` rides along unused.
|
|
593
|
+
*/
|
|
594
|
+
type JiraAvailableTransition = {
|
|
595
|
+
id: string;
|
|
596
|
+
name: string;
|
|
597
|
+
to: {
|
|
598
|
+
name: string;
|
|
599
|
+
};
|
|
600
|
+
};
|
|
601
|
+
/**
|
|
602
|
+
* Resolve the live transitions for a ticket, called lazily when its move
|
|
603
|
+
* submenu opens — never at board fetch, where one call per visible ticket
|
|
604
|
+
* would spend the Jira quota the board just spent. A host without one keeps
|
|
605
|
+
* the static `jiraTransitions` list exactly as before.
|
|
606
|
+
*/
|
|
607
|
+
type JiraTransitionsFor = (ticket: string) => Promise<JiraAvailableTransition[]>;
|
|
580
608
|
type ExplainSection = {
|
|
581
609
|
heading: string;
|
|
582
610
|
lines: string[];
|
|
@@ -707,6 +735,15 @@ declare const buildActions: (item: AnyItem, login: string, showFlash: (msg: stri
|
|
|
707
735
|
* the settlement signal.
|
|
708
736
|
*/
|
|
709
737
|
onSettled?: (item: GHItem, result: SettledResult) => void;
|
|
738
|
+
/**
|
|
739
|
+
* Open the ticket's move submenu through the live-transitions hook. Passed
|
|
740
|
+
* by the browse screen (which owns the menu the rows open into) only when
|
|
741
|
+
* the host wired `jiraTransitionsFor`; its presence is what switches
|
|
742
|
+
* "Move status" from the static sub-list below to the lazy submenu. A
|
|
743
|
+
* host that calls buildActions directly without it gets today's static
|
|
744
|
+
* list, hook or no hook.
|
|
745
|
+
*/
|
|
746
|
+
onOpenMove?: (item: TaskRow) => void;
|
|
710
747
|
}) => Action[];
|
|
711
748
|
type CiStatusState = {
|
|
712
749
|
kind: "loading";
|
|
@@ -763,7 +800,7 @@ declare const ActionMenu: ({ item, actions, cursor, cols, }: {
|
|
|
763
800
|
cols?: number;
|
|
764
801
|
}) => React.JSX.Element;
|
|
765
802
|
declare const signatureOf: (sections: Section[]) => string;
|
|
766
|
-
declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jiraKeyRe, jiraSetupHint, jiraTransitions, hasCiStatus, ciJob, ciFetcher, ciPollMs, stripFetcher, stripLabel, stripPollMs, watchPath, watchDebounceMs, watchJitterMs, extensions, tabHelp, emptyHint, liveLabel, onSettled, }: {
|
|
803
|
+
declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jiraKeyRe, jiraSetupHint, jiraTransitions, jiraTransitionsFor, hasCiStatus, ciJob, ciFetcher, ciPollMs, stripFetcher, stripLabel, stripPollMs, watchPath, watchDebounceMs, watchJitterMs, extensions, tabHelp, emptyHint, liveLabel, onSettled, }: {
|
|
767
804
|
fetcher: () => Promise<{
|
|
768
805
|
sections: Section[];
|
|
769
806
|
login: string;
|
|
@@ -803,6 +840,7 @@ declare const App: ({ fetcher, cacheKey, title, detailFor, origin, jiraBase, jir
|
|
|
803
840
|
jiraKeyRe?: RegExp;
|
|
804
841
|
jiraSetupHint?: string;
|
|
805
842
|
jiraTransitions?: JiraTransition[];
|
|
843
|
+
jiraTransitionsFor?: JiraTransitionsFor;
|
|
806
844
|
hasCiStatus?: boolean;
|
|
807
845
|
ciJob?: string;
|
|
808
846
|
ciFetcher?: () => Promise<CiStatus | null>;
|
|
@@ -871,4 +909,4 @@ declare const matchesFilter: (repo: string, filter: RepoFilter) => boolean;
|
|
|
871
909
|
*/
|
|
872
910
|
declare const parsePatterns: (value: string) => string[];
|
|
873
911
|
|
|
874
|
-
export { type Action, type ActionGroup, ActionMenu, App, COLS, type ChromeHints, type ChromeSpec, type ChromeState, CiStatusLine, type CiStatusState, type Command, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxExtension, type JiraTransition, type LiveLabel, MIN_SIDEBAR_COLS, type MenuGap, type MenuRow, PrRow, type PrRowProps, type Rails, type RepoFilter, type RowAnnouncement, type RowMotion, SIDEBAR_COLS, type SettledResult, SidePanel, type Sidebar, type SidebarRow, type StatusStrip, StatusStripLine, type StripItem, type StripState, type StripStatusState, type TrailingColumns, type TrailingShed, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, isMenuGap, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, menuRowsOf, menuTone, moveCursor, numberColumnsOf, openInTab, parsePatterns, railCapacity, railHeights, railRowsOf, railWidth, railsOf, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, sectionShedOf, signatureOf, stripGlyph, stripLayout, stripSignature, toCiStatusState, trailingColumnsOf, truncate, useActionMenu, useChrome, windowCount, withHeaders, withoutItem, workCount, writeCache };
|
|
912
|
+
export { type Action, type ActionGroup, ActionMenu, App, COLS, type ChromeHints, type ChromeSpec, type ChromeState, CiStatusLine, type CiStatusState, type Command, CommentsPanel, type CommentsPanelProps, type DetailContext, type ExplainSection, type ExtensionTarget, HealthPanel, type HealthPanelProps, type InboxBudget, type InboxExtension, type JiraAvailableTransition, type JiraTransition, type JiraTransitionsFor, type LiveLabel, MIN_SIDEBAR_COLS, type MenuGap, type MenuRow, PrRow, type PrRowProps, type Rails, type RepoFilter, type RowAnnouncement, type RowMotion, SIDEBAR_COLS, type SettledResult, SidePanel, type Sidebar, type SidebarRow, type StatusStrip, StatusStripLine, type StripItem, type StripState, type StripStatusState, type TrailingColumns, type TrailingShed, ageLabel, budgetNotice, buildActions, buildCheckoutCmd, clipboard, counts, drillCmd, explainGhAction, explainItem, fitCount, gapsAbove, healthColor, healthDisplay, healthGlyph, healthLegend, isMenuGap, itermRun, jumpToRepo, jumpToRepoPane, matchesFilter, maxViewStart, menuRowsOf, menuTone, moveCursor, numberColumnsOf, openInTab, parsePatterns, railCapacity, railHeights, railRowsOf, railWidth, railsOf, readCache, renderMarkdown, reposInSections, resolveRepoPath, runHere, runInPane, runInPaneHorizontal, sameCiStatusState, sectionShedOf, signatureOf, stripGlyph, stripLayout, stripSignature, toCiStatusState, trailingColumnsOf, truncate, useActionMenu, useChrome, windowCount, withHeaders, withoutItem, workCount, writeCache };
|
package/dist/index.js
CHANGED
|
@@ -839,20 +839,28 @@ var ageLabelOf = (item) => {
|
|
|
839
839
|
const pair = agePairOf(item);
|
|
840
840
|
return pair ? `${pair.activity} (${pair.lifetime})` : item.age;
|
|
841
841
|
};
|
|
842
|
-
var TRAILING = ["threads", "size", "age"];
|
|
842
|
+
var TRAILING = ["author", "threads", "size", "age"];
|
|
843
843
|
var cellsOf = (s) => [...s].length;
|
|
844
|
+
var AUTHOR_CELL_MAX = 16;
|
|
845
|
+
var authorLabelOf = (item) => {
|
|
846
|
+
if (!item.author) return "";
|
|
847
|
+
const full = `@${item.author}`;
|
|
848
|
+
return full.length <= AUTHOR_CELL_MAX ? full : `${full.slice(0, AUTHOR_CELL_MAX - 1)}\u2026`;
|
|
849
|
+
};
|
|
844
850
|
var trailingColumnsOf = (items) => items.reduce(
|
|
845
851
|
(w, item) => ({
|
|
852
|
+
author: Math.max(w.author, cellsOf(authorLabelOf(item))),
|
|
846
853
|
threads: Math.max(w.threads, cellsOf(threadsLabelOf(item))),
|
|
847
854
|
size: Math.max(w.size, cellsOf(sizeOf(item) ?? "")),
|
|
848
855
|
age: Math.max(w.age, cellsOf(ageLabelOf(item) ?? ""))
|
|
849
856
|
}),
|
|
850
|
-
{ threads: 0, size: 0, age: 0 }
|
|
857
|
+
{ author: 0, threads: 0, size: 0, age: 0 }
|
|
851
858
|
);
|
|
852
859
|
var numberColumnsOf = (items) => items.reduce((w, item) => Math.max(w, cellsOf(`#${item.number}`)), 0) + 2;
|
|
853
860
|
var sectionShedOf = (rows, context) => rows.reduce((shed, row) => {
|
|
854
861
|
const { givingUp } = layoutOf({ ...context, ...row });
|
|
855
862
|
return {
|
|
863
|
+
author: shed.author || givingUp.author,
|
|
856
864
|
threads: shed.threads || givingUp.threads,
|
|
857
865
|
size: shed.size || givingUp.size,
|
|
858
866
|
age: shed.age || givingUp.age
|
|
@@ -873,6 +881,7 @@ var layoutOf = ({
|
|
|
873
881
|
const numCols = numberCols ?? numberColumnsOf([item]);
|
|
874
882
|
const numStr = `#${item.number}`.padEnd(numCols);
|
|
875
883
|
const showAuthor = !!item.author && item.author !== login;
|
|
884
|
+
const authorLabel = authorLabelOf(item);
|
|
876
885
|
const sizeParts = sizePartsOf(item);
|
|
877
886
|
const unresolvedLabel = threadsLabelOf(item);
|
|
878
887
|
const agePair = agePairOf(item);
|
|
@@ -883,7 +892,7 @@ var layoutOf = ({
|
|
|
883
892
|
const implied = [...impliedLabels(item.repo), ...uniformLabels];
|
|
884
893
|
const labelNames = (item.labels ?? []).filter((l) => !implied.includes(l)).sort((a, b) => labelPriority(a) - labelPriority(b) || a.localeCompare(b)).slice(0, 2);
|
|
885
894
|
const givingUp = {
|
|
886
|
-
author:
|
|
895
|
+
author: !!shed.author,
|
|
887
896
|
size: !!shed.size,
|
|
888
897
|
threads: !!shed.threads,
|
|
889
898
|
age: !!shed.age,
|
|
@@ -912,10 +921,9 @@ var layoutOf = ({
|
|
|
912
921
|
(w, k) => givingUp[k] || own[k] === 0 ? w : w + 2 + own[k],
|
|
913
922
|
0
|
|
914
923
|
);
|
|
915
|
-
const author = showAuthor && !givingUp.author ? ` by ${item.author}`.length : 0;
|
|
916
924
|
const pills = announcements.reduce((w, a) => w + 2 + a.label.length, 0);
|
|
917
925
|
const cell = labelCell();
|
|
918
|
-
return (gutter ? 2 : 0) + prefix.length + 2 + 2 + numCols + (cell ? 2 + cell.length + 1 : 0) + (givingUp.repo ? 0 : repoLabel.length) +
|
|
926
|
+
return (gutter ? 2 : 0) + prefix.length + 2 + 2 + numCols + (cell ? 2 + cell.length + 1 : 0) + (givingUp.repo ? 0 : repoLabel.length) + block + pills + pillCaps + 4;
|
|
919
927
|
};
|
|
920
928
|
const MIN_TITLE = 24;
|
|
921
929
|
for (const give of [
|
|
@@ -935,6 +943,7 @@ var layoutOf = ({
|
|
|
935
943
|
return {
|
|
936
944
|
numStr,
|
|
937
945
|
showAuthor,
|
|
946
|
+
authorLabel,
|
|
938
947
|
sizeParts,
|
|
939
948
|
unresolvedLabel,
|
|
940
949
|
agePair,
|
|
@@ -973,6 +982,7 @@ var PrRow = ({
|
|
|
973
982
|
const {
|
|
974
983
|
numStr,
|
|
975
984
|
showAuthor,
|
|
985
|
+
authorLabel,
|
|
976
986
|
sizeParts,
|
|
977
987
|
unresolvedLabel,
|
|
978
988
|
agePair,
|
|
@@ -1017,8 +1027,8 @@ var PrRow = ({
|
|
|
1017
1027
|
),
|
|
1018
1028
|
labelLabel ? /* @__PURE__ */ jsx(Text3, { color: colors.secondary, children: labelLabel + " " }) : null,
|
|
1019
1029
|
repoLabel && !givingUp.repo ? /* @__PURE__ */ jsx(Text3, { dimColor: true, children: repoLabel }) : null,
|
|
1020
|
-
showAuthor && !givingUp.author ? /* @__PURE__ */ jsx(Text3, { dimColor: true, italic: true, children: " by " + item.author }) : null,
|
|
1021
1030
|
/* @__PURE__ */ jsx(Box, { flexGrow: 1 }),
|
|
1031
|
+
block.author > 0 && !givingUp.author ? /* @__PURE__ */ jsx(Box, { marginLeft: 2, width: block.author, flexShrink: 0, children: showAuthor ? /* @__PURE__ */ jsx(Text3, { color: colors.secondary, children: authorLabel }) : null }) : null,
|
|
1022
1032
|
block.threads > 0 && !givingUp.threads ? /* @__PURE__ */ jsx(
|
|
1023
1033
|
Box,
|
|
1024
1034
|
{
|
|
@@ -1436,6 +1446,116 @@ var reconcile = (prev, fresh, now, holdMs = HOLD_MS) => {
|
|
|
1436
1446
|
};
|
|
1437
1447
|
var quietly = $({ quiet: true });
|
|
1438
1448
|
var isMenuGap = (row) => "gap" in row;
|
|
1449
|
+
var jiraMovesCache = /* @__PURE__ */ new Map();
|
|
1450
|
+
var cachedJiraMoves = (ticket, status) => {
|
|
1451
|
+
const entry = jiraMovesCache.get(ticket);
|
|
1452
|
+
return entry && entry.status === status ? entry.moves : void 0;
|
|
1453
|
+
};
|
|
1454
|
+
var storeJiraMoves = (ticket, status, moves) => {
|
|
1455
|
+
jiraMovesCache.set(ticket, { status, moves });
|
|
1456
|
+
};
|
|
1457
|
+
var invalidateJiraMoves = (ticket) => jiraMovesCache.delete(ticket);
|
|
1458
|
+
var orderJiraMoves = (available, configured) => {
|
|
1459
|
+
const known = /* @__PURE__ */ new Set();
|
|
1460
|
+
const ordered = [];
|
|
1461
|
+
for (const { label, transition, resolutions } of configured ?? []) {
|
|
1462
|
+
const live = available.find((t) => t.name === transition);
|
|
1463
|
+
if (!live) continue;
|
|
1464
|
+
known.add(live.name);
|
|
1465
|
+
ordered.push(
|
|
1466
|
+
resolutions && resolutions.length > 0 ? { label, transition: live.name, resolutions } : { label, transition: live.name }
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1469
|
+
const rest = available.filter((t) => !known.has(t.name)).sort((a, b) => a.name.localeCompare(b.name)).map((t) => ({ label: t.name, transition: t.name }));
|
|
1470
|
+
return [...ordered, ...rest];
|
|
1471
|
+
};
|
|
1472
|
+
var jiraMoveActions = (ticket, moves, showFlash, onActed) => moves.map(
|
|
1473
|
+
({ label, transition, resolutions }) => resolutions && resolutions.length > 0 ? {
|
|
1474
|
+
label,
|
|
1475
|
+
hint: "",
|
|
1476
|
+
run: () => {
|
|
1477
|
+
},
|
|
1478
|
+
subActions: resolutions.map((resolution) => ({
|
|
1479
|
+
label: resolution,
|
|
1480
|
+
hint: "",
|
|
1481
|
+
run: () => {
|
|
1482
|
+
showFlash(`\u22EF ${label} \xB7 ${resolution}\u2026`);
|
|
1483
|
+
void quietly`jira issue move ${ticket} ${transition} --resolution ${resolution}`.then(() => {
|
|
1484
|
+
invalidateJiraMoves(ticket);
|
|
1485
|
+
showFlash(`\u2713 ${label} \xB7 ${resolution}`);
|
|
1486
|
+
onActed?.();
|
|
1487
|
+
}).catch(() => showFlash(`\u2717 Move to ${label} failed`));
|
|
1488
|
+
}
|
|
1489
|
+
}))
|
|
1490
|
+
} : {
|
|
1491
|
+
label,
|
|
1492
|
+
hint: "",
|
|
1493
|
+
run: () => {
|
|
1494
|
+
showFlash(`\u22EF Moving to ${label}\u2026`);
|
|
1495
|
+
void quietly`jira issue move ${ticket} ${transition}`.then(() => {
|
|
1496
|
+
invalidateJiraMoves(ticket);
|
|
1497
|
+
showFlash(`\u2713 Moved to ${label}`);
|
|
1498
|
+
onActed?.();
|
|
1499
|
+
}).catch(() => showFlash(`\u2717 Move to ${label} failed`));
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
);
|
|
1503
|
+
var jiraLoadingActions = () => [
|
|
1504
|
+
{ label: "Loading transitions\u2026", hint: "", tone: "dim", run: () => {
|
|
1505
|
+
} }
|
|
1506
|
+
];
|
|
1507
|
+
var openJiraMoves = (deps) => {
|
|
1508
|
+
const {
|
|
1509
|
+
ticket,
|
|
1510
|
+
status,
|
|
1511
|
+
fetch,
|
|
1512
|
+
configured,
|
|
1513
|
+
open,
|
|
1514
|
+
isOpen,
|
|
1515
|
+
showFlash,
|
|
1516
|
+
onActed
|
|
1517
|
+
} = deps;
|
|
1518
|
+
const openOrdered = (moves) => {
|
|
1519
|
+
const ordered = orderJiraMoves(moves, configured);
|
|
1520
|
+
open(
|
|
1521
|
+
ordered.length > 0 ? jiraMoveActions(ticket, ordered, showFlash, onActed) : [
|
|
1522
|
+
{
|
|
1523
|
+
label: "No transitions available",
|
|
1524
|
+
hint: "",
|
|
1525
|
+
tone: "dim",
|
|
1526
|
+
run: () => {
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
]
|
|
1530
|
+
);
|
|
1531
|
+
};
|
|
1532
|
+
const hit = cachedJiraMoves(ticket, status);
|
|
1533
|
+
if (hit) {
|
|
1534
|
+
openOrdered(hit);
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
const attempt = ++openJiraMovesSeq;
|
|
1538
|
+
open(jiraLoadingActions());
|
|
1539
|
+
void fetch(ticket).then(
|
|
1540
|
+
(moves) => {
|
|
1541
|
+
if (attempt !== openJiraMovesSeq || !isOpen()) return;
|
|
1542
|
+
storeJiraMoves(ticket, status, moves);
|
|
1543
|
+
openOrdered(moves);
|
|
1544
|
+
},
|
|
1545
|
+
() => {
|
|
1546
|
+
if (attempt !== openJiraMovesSeq || !isOpen()) return;
|
|
1547
|
+
open([
|
|
1548
|
+
{
|
|
1549
|
+
label: "Couldn't load transitions \u2014 Retry",
|
|
1550
|
+
hint: "",
|
|
1551
|
+
tone: "error",
|
|
1552
|
+
run: () => openJiraMoves(deps)
|
|
1553
|
+
}
|
|
1554
|
+
]);
|
|
1555
|
+
}
|
|
1556
|
+
);
|
|
1557
|
+
};
|
|
1558
|
+
var openJiraMovesSeq = 0;
|
|
1439
1559
|
var healthSentence = (item) => {
|
|
1440
1560
|
const glyph = displayFor(item.health).glyph.trim();
|
|
1441
1561
|
const d = item.detail;
|
|
@@ -2021,46 +2141,59 @@ var buildActions = (item, login, showFlash, jiraBase, jiraKeyRe, jiraTransitions
|
|
|
2021
2141
|
} : null;
|
|
2022
2142
|
if (item.kind === "task") {
|
|
2023
2143
|
const base = drillAction ? [drillAction, open, copyUrl] : [open, copyUrl];
|
|
2024
|
-
if (item.ticket && jiraTransitions && jiraTransitions.length > 0) {
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
(
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2144
|
+
if (item.ticket && (ext?.onOpenMove ?? (jiraTransitions && jiraTransitions.length > 0))) {
|
|
2145
|
+
if (ext?.onOpenMove) {
|
|
2146
|
+
const task = item;
|
|
2147
|
+
const openMove = ext.onOpenMove;
|
|
2148
|
+
base.push({
|
|
2149
|
+
label: "Move status",
|
|
2150
|
+
hint: "t",
|
|
2151
|
+
// The task's act: changing its state, the one mutation this menu owns.
|
|
2152
|
+
// Guarded by the caller's own condition above — without a hook or
|
|
2153
|
+
// configured transitions there is no such row, and none is invented here.
|
|
2154
|
+
group: "act",
|
|
2155
|
+
run: () => openMove(task)
|
|
2156
|
+
});
|
|
2157
|
+
} else
|
|
2158
|
+
base.push({
|
|
2159
|
+
label: "Move status",
|
|
2160
|
+
hint: "t",
|
|
2161
|
+
// The task's act: changing its state, the one mutation this menu owns.
|
|
2162
|
+
// Guarded by the caller's own condition above — without configured
|
|
2163
|
+
// transitions there is no such row, and none is invented here.
|
|
2164
|
+
group: "act",
|
|
2165
|
+
run: () => {
|
|
2166
|
+
},
|
|
2167
|
+
subActions: jiraTransitions.map(
|
|
2168
|
+
({ label, transition, resolutions }) => resolutions && resolutions.length > 0 ? {
|
|
2169
|
+
label,
|
|
2170
|
+
hint: "",
|
|
2171
|
+
run: () => {
|
|
2172
|
+
},
|
|
2173
|
+
subActions: resolutions.map((resolution) => ({
|
|
2174
|
+
label: resolution,
|
|
2175
|
+
hint: "",
|
|
2176
|
+
run: () => {
|
|
2177
|
+
showFlash(`\u22EF ${label} \xB7 ${resolution}\u2026`);
|
|
2178
|
+
void quietly`jira issue move ${item.ticket} ${transition} --resolution ${resolution}`.then(() => {
|
|
2179
|
+
showFlash(`\u2713 ${label} \xB7 ${resolution}`);
|
|
2180
|
+
ext?.onActed?.();
|
|
2181
|
+
}).catch(() => showFlash(`\u2717 Move to ${label} failed`));
|
|
2182
|
+
}
|
|
2183
|
+
}))
|
|
2184
|
+
} : {
|
|
2185
|
+
label,
|
|
2042
2186
|
hint: "",
|
|
2043
2187
|
run: () => {
|
|
2044
|
-
showFlash(`\u22EF
|
|
2045
|
-
void quietly`jira issue move ${item.ticket} ${transition}
|
|
2046
|
-
showFlash(`\u2713
|
|
2188
|
+
showFlash(`\u22EF Moving to ${label}\u2026`);
|
|
2189
|
+
void quietly`jira issue move ${item.ticket} ${transition}`.then(() => {
|
|
2190
|
+
showFlash(`\u2713 Moved to ${label}`);
|
|
2047
2191
|
ext?.onActed?.();
|
|
2048
2192
|
}).catch(() => showFlash(`\u2717 Move to ${label} failed`));
|
|
2049
2193
|
}
|
|
2050
|
-
}))
|
|
2051
|
-
} : {
|
|
2052
|
-
label,
|
|
2053
|
-
hint: "",
|
|
2054
|
-
run: () => {
|
|
2055
|
-
showFlash(`\u22EF Moving to ${label}\u2026`);
|
|
2056
|
-
void quietly`jira issue move ${item.ticket} ${transition}`.then(() => {
|
|
2057
|
-
showFlash(`\u2713 Moved to ${label}`);
|
|
2058
|
-
ext?.onActed?.();
|
|
2059
|
-
}).catch(() => showFlash(`\u2717 Move to ${label} failed`));
|
|
2060
2194
|
}
|
|
2061
|
-
|
|
2062
|
-
)
|
|
2063
|
-
});
|
|
2195
|
+
)
|
|
2196
|
+
});
|
|
2064
2197
|
}
|
|
2065
2198
|
return byGroup(base);
|
|
2066
2199
|
}
|
|
@@ -2731,7 +2864,8 @@ var ActionMenu = ({
|
|
|
2731
2864
|
Text3,
|
|
2732
2865
|
{
|
|
2733
2866
|
bold: i === cursor,
|
|
2734
|
-
color: isCloseRow(row) ? colors.error : void 0,
|
|
2867
|
+
color: row.tone === "error" ? colors.error : isCloseRow(row) ? colors.error : void 0,
|
|
2868
|
+
dimColor: row.tone === "dim" ? true : void 0,
|
|
2735
2869
|
children: row.label
|
|
2736
2870
|
}
|
|
2737
2871
|
) }),
|
|
@@ -3014,6 +3148,7 @@ var BrowseScreen = ({
|
|
|
3014
3148
|
jiraKeyRe,
|
|
3015
3149
|
jiraSetupHint,
|
|
3016
3150
|
jiraTransitions,
|
|
3151
|
+
jiraTransitionsFor,
|
|
3017
3152
|
onRefresh,
|
|
3018
3153
|
onActed,
|
|
3019
3154
|
onSettled,
|
|
@@ -3277,6 +3412,24 @@ var BrowseScreen = ({
|
|
|
3277
3412
|
}
|
|
3278
3413
|
return false;
|
|
3279
3414
|
};
|
|
3415
|
+
const menuActionsRef = useRef(null);
|
|
3416
|
+
useEffect(() => {
|
|
3417
|
+
menuActionsRef.current = menu.actions;
|
|
3418
|
+
});
|
|
3419
|
+
const openMoveFor = (task) => {
|
|
3420
|
+
if (!task.ticket || !jiraTransitionsFor) return;
|
|
3421
|
+
const fetch = jiraTransitionsFor;
|
|
3422
|
+
openJiraMoves({
|
|
3423
|
+
ticket: task.ticket,
|
|
3424
|
+
status: task.status,
|
|
3425
|
+
fetch,
|
|
3426
|
+
configured: jiraTransitions,
|
|
3427
|
+
open: (rows2) => menu.open(rows2),
|
|
3428
|
+
isOpen: () => menuActionsRef.current !== null,
|
|
3429
|
+
showFlash,
|
|
3430
|
+
onActed
|
|
3431
|
+
});
|
|
3432
|
+
};
|
|
3280
3433
|
const openMenu = () => {
|
|
3281
3434
|
if (!activeItem || activeItem.kind === "repo-header" || activeItem.kind === "subgroup-header")
|
|
3282
3435
|
return;
|
|
@@ -3293,7 +3446,13 @@ var BrowseScreen = ({
|
|
|
3293
3446
|
onRefresh,
|
|
3294
3447
|
dismissItem,
|
|
3295
3448
|
openDrillView,
|
|
3296
|
-
{
|
|
3449
|
+
{
|
|
3450
|
+
extensions,
|
|
3451
|
+
onOpenExt,
|
|
3452
|
+
onActed,
|
|
3453
|
+
onSettled,
|
|
3454
|
+
onOpenMove: jiraTransitionsFor ? openMoveFor : void 0
|
|
3455
|
+
}
|
|
3297
3456
|
);
|
|
3298
3457
|
menu.open(actions);
|
|
3299
3458
|
};
|
|
@@ -3629,9 +3788,13 @@ var BrowseScreen = ({
|
|
|
3629
3788
|
return;
|
|
3630
3789
|
}
|
|
3631
3790
|
}
|
|
3632
|
-
if (input === "t" && activeItem && activeItem.kind === "task" && activeItem.ticket && jiraTransitions && jiraTransitions.length > 0) {
|
|
3791
|
+
if (input === "t" && activeItem && activeItem.kind === "task" && activeItem.ticket && (jiraTransitionsFor ?? (jiraTransitions && jiraTransitions.length > 0))) {
|
|
3792
|
+
if (jiraTransitionsFor) {
|
|
3793
|
+
openMoveFor(activeItem);
|
|
3794
|
+
return;
|
|
3795
|
+
}
|
|
3633
3796
|
const jiraKey = activeItem.ticket;
|
|
3634
|
-
const actions = jiraTransitions.map(
|
|
3797
|
+
const actions = (jiraTransitions ?? []).map(
|
|
3635
3798
|
({ label, transition, resolutions }) => resolutions && resolutions.length > 0 ? {
|
|
3636
3799
|
label,
|
|
3637
3800
|
hint: "",
|
|
@@ -3903,8 +4066,13 @@ var BrowseScreen = ({
|
|
|
3903
4066
|
!overlayOpen && search != null ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
3904
4067
|
/* @__PURE__ */ jsx(Text3, { color: searchBar.glyphColor, children: ` ${searchBar.glyph} ` }),
|
|
3905
4068
|
/* @__PURE__ */ jsx(Text3, { children: search.slice(0, filter.caret) }),
|
|
3906
|
-
searchBar.caret ? /* @__PURE__ */
|
|
3907
|
-
|
|
4069
|
+
searchBar.caret && filter.caret < search.length ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4070
|
+
/* @__PURE__ */ jsx(Text3, { inverse: true, children: search[filter.caret] }),
|
|
4071
|
+
/* @__PURE__ */ jsx(Text3, { children: search.slice(filter.caret + 1) })
|
|
4072
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4073
|
+
searchBar.caret ? /* @__PURE__ */ jsx(Text3, { color: colors.info, children: "\u258F" }) : null,
|
|
4074
|
+
/* @__PURE__ */ jsx(Text3, { children: search.slice(filter.caret) })
|
|
4075
|
+
] }),
|
|
3908
4076
|
/* @__PURE__ */ jsx(Text3, { dimColor: true, children: ` ${matchCount} match${matchCount !== 1 ? "es" : ""} ${searchInput ? filter.hints.map(([k, label]) => `${k} ${label}`).join(" \xB7 ") : searchBar.hints}` })
|
|
3909
4077
|
] }) : !overlayOpen && repoFilter.size > 0 ? /* @__PURE__ */ jsxs(Box, { marginBottom: 1, children: [
|
|
3910
4078
|
/* @__PURE__ */ jsx(Text3, { color: colors.accent, children: " \u25C9 " }),
|
|
@@ -4038,6 +4206,7 @@ var App = ({
|
|
|
4038
4206
|
jiraKeyRe,
|
|
4039
4207
|
jiraSetupHint,
|
|
4040
4208
|
jiraTransitions,
|
|
4209
|
+
jiraTransitionsFor,
|
|
4041
4210
|
hasCiStatus,
|
|
4042
4211
|
ciJob,
|
|
4043
4212
|
ciFetcher,
|
|
@@ -4489,6 +4658,7 @@ var App = ({
|
|
|
4489
4658
|
jiraKeyRe,
|
|
4490
4659
|
jiraSetupHint,
|
|
4491
4660
|
jiraTransitions,
|
|
4661
|
+
jiraTransitionsFor,
|
|
4492
4662
|
onRefresh: applyOrRefresh,
|
|
4493
4663
|
onActed,
|
|
4494
4664
|
onSettled,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kud/gh-ink",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.69.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",
|
|
@@ -44,16 +44,17 @@
|
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
+
"@kud/ink-ui": ">=0.33.0 <1",
|
|
47
48
|
"ink": ">=7",
|
|
48
49
|
"react": ">=19"
|
|
49
50
|
},
|
|
50
51
|
"dependencies": {
|
|
51
52
|
"@kud/gh": "0.20.0",
|
|
52
53
|
"@kud/gh-workflow": "0.14.1",
|
|
53
|
-
"@kud/ink-ui": "0.33.1",
|
|
54
54
|
"zx": "8.8.5"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
+
"@kud/ink-ui": "0.34.0",
|
|
57
58
|
"@types/node": "22.20.1",
|
|
58
59
|
"@types/react": "19.2.17",
|
|
59
60
|
"ink": "7.1.0",
|