clairo 0.2.0 → 0.3.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/cli.js +277 -459
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
import meow from "meow";
|
|
5
5
|
|
|
6
6
|
// src/app.tsx
|
|
7
|
-
import { useState as
|
|
8
|
-
import { Box as
|
|
7
|
+
import { useState as useState8 } from "react";
|
|
8
|
+
import { Box as Box12, useApp, useInput as useInput10 } from "ink";
|
|
9
9
|
|
|
10
10
|
// src/components/github/GitHubView.tsx
|
|
11
|
-
import {
|
|
11
|
+
import { exec as exec3 } from "child_process";
|
|
12
|
+
import { useCallback, useEffect as useEffect3, useState as useState3 } from "react";
|
|
12
13
|
import { TitledBox as TitledBox4 } from "@mishieck/ink-titled-box";
|
|
13
|
-
import { Box as
|
|
14
|
+
import { Box as Box4, Text as Text4, useInput as useInput4 } from "ink";
|
|
14
15
|
|
|
15
16
|
// src/lib/config/index.ts
|
|
16
17
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -127,8 +128,6 @@ function getCurrentBranch() {
|
|
|
127
128
|
|
|
128
129
|
// src/lib/github/index.ts
|
|
129
130
|
import { exec } from "child_process";
|
|
130
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
131
|
-
import { join as join2 } from "path";
|
|
132
131
|
import { promisify } from "util";
|
|
133
132
|
var execAsync = promisify(exec);
|
|
134
133
|
async function isGhInstalled() {
|
|
@@ -241,178 +240,14 @@ async function getPRDetails(prNumber, repo) {
|
|
|
241
240
|
};
|
|
242
241
|
}
|
|
243
242
|
}
|
|
244
|
-
function getPRTemplate(repoPath) {
|
|
245
|
-
const templatePaths = [
|
|
246
|
-
".github/PULL_REQUEST_TEMPLATE.md",
|
|
247
|
-
".github/pull_request_template.md",
|
|
248
|
-
"PULL_REQUEST_TEMPLATE.md",
|
|
249
|
-
"pull_request_template.md",
|
|
250
|
-
"docs/PULL_REQUEST_TEMPLATE.md"
|
|
251
|
-
];
|
|
252
|
-
for (const templatePath of templatePaths) {
|
|
253
|
-
const fullPath = join2(repoPath, templatePath);
|
|
254
|
-
if (existsSync2(fullPath)) {
|
|
255
|
-
try {
|
|
256
|
-
return readFileSync2(fullPath, "utf-8");
|
|
257
|
-
} catch {
|
|
258
|
-
continue;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
return null;
|
|
263
|
-
}
|
|
264
|
-
async function createPR(repo, title, body, baseBranch) {
|
|
265
|
-
if (!await isGhInstalled()) {
|
|
266
|
-
return {
|
|
267
|
-
success: false,
|
|
268
|
-
error: "GitHub CLI (gh) is not installed",
|
|
269
|
-
errorType: "not_installed"
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
if (!await isGhAuthenticated()) {
|
|
273
|
-
return {
|
|
274
|
-
success: false,
|
|
275
|
-
error: "Not authenticated. Run 'gh auth login'",
|
|
276
|
-
errorType: "not_authenticated"
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
try {
|
|
280
|
-
const baseArg = baseBranch ? `--base "${baseBranch}"` : "";
|
|
281
|
-
const fields = "number,title,state,author,createdAt,isDraft";
|
|
282
|
-
const escapedTitle = title.replace(/"/g, '\\"');
|
|
283
|
-
const escapedBody = body.replace(/"/g, '\\"');
|
|
284
|
-
const { stdout } = await execAsync(
|
|
285
|
-
`gh pr create --title "${escapedTitle}" --body "${escapedBody}" ${baseArg} --repo "${repo}" --json ${fields}`
|
|
286
|
-
);
|
|
287
|
-
const pr = JSON.parse(stdout);
|
|
288
|
-
return { success: true, data: pr };
|
|
289
|
-
} catch (err) {
|
|
290
|
-
const message = err instanceof Error ? err.message : "Failed to create PR";
|
|
291
|
-
return {
|
|
292
|
-
success: false,
|
|
293
|
-
error: message,
|
|
294
|
-
errorType: "api_error"
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// src/components/github/CreatePRModal.tsx
|
|
300
|
-
import { useState } from "react";
|
|
301
|
-
import { Box, Text, useInput } from "ink";
|
|
302
|
-
|
|
303
|
-
// src/lib/editor.ts
|
|
304
|
-
import { spawnSync } from "child_process";
|
|
305
|
-
import { mkdtempSync, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
306
|
-
import { tmpdir } from "os";
|
|
307
|
-
import { join as join3 } from "path";
|
|
308
|
-
function openInEditor(content, filename) {
|
|
309
|
-
const editor = process.env.VISUAL || process.env.EDITOR || "vi";
|
|
310
|
-
const tempDir = mkdtempSync(join3(tmpdir(), "clairo-"));
|
|
311
|
-
const tempFile = join3(tempDir, filename);
|
|
312
|
-
try {
|
|
313
|
-
writeFileSync2(tempFile, content);
|
|
314
|
-
const result = spawnSync(editor, [tempFile], {
|
|
315
|
-
stdio: "inherit"
|
|
316
|
-
});
|
|
317
|
-
process.stdout.write("\x1B[2J\x1B[H");
|
|
318
|
-
process.stdout.emit("resize");
|
|
319
|
-
if (result.status !== 0) {
|
|
320
|
-
return null;
|
|
321
|
-
}
|
|
322
|
-
return readFileSync3(tempFile, "utf-8");
|
|
323
|
-
} finally {
|
|
324
|
-
try {
|
|
325
|
-
rmSync(tempDir, { recursive: true });
|
|
326
|
-
} catch {
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
// src/components/github/CreatePRModal.tsx
|
|
332
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
333
|
-
function CreatePRModal({ template, onSubmit, onCancel, loading, error }) {
|
|
334
|
-
const [title, setTitle] = useState("");
|
|
335
|
-
const [body, setBody] = useState(template ?? "");
|
|
336
|
-
const [selectedItem, setSelectedItem] = useState("title");
|
|
337
|
-
const items = ["title", "body", "submit"];
|
|
338
|
-
useInput(
|
|
339
|
-
(input, key) => {
|
|
340
|
-
if (loading) return;
|
|
341
|
-
if (key.escape) {
|
|
342
|
-
onCancel();
|
|
343
|
-
return;
|
|
344
|
-
}
|
|
345
|
-
if (key.upArrow || input === "k") {
|
|
346
|
-
setSelectedItem((prev) => {
|
|
347
|
-
const idx = items.indexOf(prev);
|
|
348
|
-
return items[Math.max(0, idx - 1)];
|
|
349
|
-
});
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
if (key.downArrow || input === "j") {
|
|
353
|
-
setSelectedItem((prev) => {
|
|
354
|
-
const idx = items.indexOf(prev);
|
|
355
|
-
return items[Math.min(items.length - 1, idx + 1)];
|
|
356
|
-
});
|
|
357
|
-
return;
|
|
358
|
-
}
|
|
359
|
-
if (key.return) {
|
|
360
|
-
if (selectedItem === "title") {
|
|
361
|
-
const newTitle = openInEditor(title, "PR_TITLE.txt");
|
|
362
|
-
if (newTitle !== null) {
|
|
363
|
-
setTitle(newTitle.split("\n")[0].trim());
|
|
364
|
-
}
|
|
365
|
-
} else if (selectedItem === "body") {
|
|
366
|
-
const newBody = openInEditor(body, "PR_DESCRIPTION.md");
|
|
367
|
-
if (newBody !== null) {
|
|
368
|
-
setBody(newBody);
|
|
369
|
-
}
|
|
370
|
-
} else if (selectedItem === "submit") {
|
|
371
|
-
if (title.trim()) {
|
|
372
|
-
onSubmit(title.trim(), body);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
},
|
|
377
|
-
{ isActive: !loading }
|
|
378
|
-
);
|
|
379
|
-
const renderItem = (item, label, value) => {
|
|
380
|
-
const isSelected = selectedItem === item;
|
|
381
|
-
const prefix = isSelected ? "> " : " ";
|
|
382
|
-
const color = isSelected ? "yellow" : void 0;
|
|
383
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
384
|
-
/* @__PURE__ */ jsxs(Text, { color, bold: isSelected, children: [
|
|
385
|
-
prefix,
|
|
386
|
-
label
|
|
387
|
-
] }),
|
|
388
|
-
value !== void 0 && /* @__PURE__ */ jsx(Box, { marginLeft: 4, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: value || "(empty - press Enter to edit)" }) })
|
|
389
|
-
] });
|
|
390
|
-
};
|
|
391
|
-
const truncatedBody = body ? body.split("\n").slice(0, 2).join(" ").slice(0, 60) + (body.length > 60 ? "..." : "") : "";
|
|
392
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, paddingY: 1, children: [
|
|
393
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "Create Pull Request" }),
|
|
394
|
-
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Up/Down to select, Enter to edit, Esc to cancel" }),
|
|
395
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1 }),
|
|
396
|
-
error && /* @__PURE__ */ jsx(Box, { marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: "red", children: error }) }),
|
|
397
|
-
renderItem("title", "Title", title),
|
|
398
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1 }),
|
|
399
|
-
renderItem("body", "Description", truncatedBody),
|
|
400
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 1 }),
|
|
401
|
-
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsxs(Text, { color: selectedItem === "submit" ? "green" : void 0, bold: selectedItem === "submit", children: [
|
|
402
|
-
selectedItem === "submit" ? "> " : " ",
|
|
403
|
-
title.trim() ? "[Submit PR]" : "[Enter title first]"
|
|
404
|
-
] }) }),
|
|
405
|
-
loading && /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(Text, { color: "yellow", children: "Creating PR..." }) })
|
|
406
|
-
] });
|
|
407
|
-
}
|
|
408
243
|
|
|
409
244
|
// src/components/github/PRDetailsBox.tsx
|
|
410
245
|
import { useRef } from "react";
|
|
411
246
|
import open from "open";
|
|
412
247
|
import { TitledBox } from "@mishieck/ink-titled-box";
|
|
413
|
-
import { Box
|
|
248
|
+
import { Box, Text, useInput } from "ink";
|
|
414
249
|
import { ScrollView } from "ink-scroll-view";
|
|
415
|
-
import { Fragment, jsx
|
|
250
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
416
251
|
function getCheckColor(check) {
|
|
417
252
|
const conclusion = check.conclusion ?? check.state;
|
|
418
253
|
if (conclusion === "SUCCESS") return "green";
|
|
@@ -450,7 +285,7 @@ function PRDetailsBox({ pr, loading, error, isFocused }) {
|
|
|
450
285
|
return { text: pr.mergeable ?? "UNKNOWN", color: "yellow" };
|
|
451
286
|
};
|
|
452
287
|
const mergeDisplay = getMergeDisplay();
|
|
453
|
-
|
|
288
|
+
useInput(
|
|
454
289
|
(input, key) => {
|
|
455
290
|
var _a2, _b2;
|
|
456
291
|
if (key.upArrow || input === "k") {
|
|
@@ -466,36 +301,36 @@ function PRDetailsBox({ pr, loading, error, isFocused }) {
|
|
|
466
301
|
},
|
|
467
302
|
{ isActive: isFocused }
|
|
468
303
|
);
|
|
469
|
-
return /* @__PURE__ */
|
|
470
|
-
loading && /* @__PURE__ */
|
|
471
|
-
error && /* @__PURE__ */
|
|
472
|
-
!loading && !error && !pr && /* @__PURE__ */
|
|
473
|
-
!loading && !error && pr && /* @__PURE__ */
|
|
474
|
-
/* @__PURE__ */
|
|
475
|
-
/* @__PURE__ */
|
|
304
|
+
return /* @__PURE__ */ jsx(TitledBox, { borderStyle: "round", titles: [displayTitle], borderColor, flexGrow: 2, children: /* @__PURE__ */ jsx(Box, { flexGrow: 1, overflow: "hidden", children: /* @__PURE__ */ jsx(ScrollView, { ref: scrollRef, flexGrow: 1, children: /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 1, children: [
|
|
305
|
+
loading && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Loading details..." }),
|
|
306
|
+
error && /* @__PURE__ */ jsx(Text, { color: "red", children: error }),
|
|
307
|
+
!loading && !error && !pr && /* @__PURE__ */ jsx(Text, { dimColor: true, children: "Select a PR to view details" }),
|
|
308
|
+
!loading && !error && pr && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
309
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: pr.title }),
|
|
310
|
+
/* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
|
|
476
311
|
"by ",
|
|
477
312
|
((_a = pr.author) == null ? void 0 : _a.login) ?? "unknown",
|
|
478
313
|
" | ",
|
|
479
314
|
((_b = pr.commits) == null ? void 0 : _b.length) ?? 0,
|
|
480
315
|
" commits"
|
|
481
316
|
] }),
|
|
482
|
-
/* @__PURE__ */
|
|
483
|
-
/* @__PURE__ */
|
|
484
|
-
/* @__PURE__ */
|
|
485
|
-
/* @__PURE__ */
|
|
486
|
-
/* @__PURE__ */
|
|
487
|
-
/* @__PURE__ */
|
|
317
|
+
/* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
318
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Review: " }),
|
|
319
|
+
/* @__PURE__ */ jsx(Text, { color: reviewColor, children: reviewStatus }),
|
|
320
|
+
/* @__PURE__ */ jsx(Text, { children: " | " }),
|
|
321
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Status: " }),
|
|
322
|
+
/* @__PURE__ */ jsx(Text, { color: mergeDisplay.color, children: mergeDisplay.text })
|
|
488
323
|
] }),
|
|
489
|
-
(((_c = pr.assignees) == null ? void 0 : _c.length) ?? 0) > 0 && /* @__PURE__ */
|
|
490
|
-
/* @__PURE__ */
|
|
491
|
-
/* @__PURE__ */
|
|
324
|
+
(((_c = pr.assignees) == null ? void 0 : _c.length) ?? 0) > 0 && /* @__PURE__ */ jsxs(Box, { marginTop: 1, children: [
|
|
325
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Assignees: " }),
|
|
326
|
+
/* @__PURE__ */ jsx(Text, { children: pr.assignees.map((a) => a.login).join(", ") })
|
|
492
327
|
] }),
|
|
493
|
-
(((_d = pr.reviews) == null ? void 0 : _d.length) ?? 0) > 0 && /* @__PURE__ */
|
|
494
|
-
/* @__PURE__ */
|
|
328
|
+
(((_d = pr.reviews) == null ? void 0 : _d.length) ?? 0) > 0 && /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
329
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Reviews:" }),
|
|
495
330
|
pr.reviews.map((review, idx) => {
|
|
496
331
|
const color = review.state === "APPROVED" ? "green" : review.state === "CHANGES_REQUESTED" ? "red" : review.state === "COMMENTED" ? "blue" : "yellow";
|
|
497
332
|
const icon = review.state === "APPROVED" ? "\u2713" : review.state === "CHANGES_REQUESTED" ? "\u2717" : review.state === "COMMENTED" ? "\u{1F4AC}" : "\u25CB";
|
|
498
|
-
return /* @__PURE__ */
|
|
333
|
+
return /* @__PURE__ */ jsxs(Text, { color, children: [
|
|
499
334
|
" ",
|
|
500
335
|
icon,
|
|
501
336
|
" ",
|
|
@@ -503,31 +338,31 @@ function PRDetailsBox({ pr, loading, error, isFocused }) {
|
|
|
503
338
|
] }, idx);
|
|
504
339
|
})
|
|
505
340
|
] }),
|
|
506
|
-
(((_e = pr.reviewRequests) == null ? void 0 : _e.length) ?? 0) > 0 && /* @__PURE__ */
|
|
507
|
-
/* @__PURE__ */
|
|
508
|
-
/* @__PURE__ */
|
|
341
|
+
(((_e = pr.reviewRequests) == null ? void 0 : _e.length) ?? 0) > 0 && /* @__PURE__ */ jsxs(Box, { children: [
|
|
342
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Pending: " }),
|
|
343
|
+
/* @__PURE__ */ jsx(Text, { color: "yellow", children: pr.reviewRequests.map((r) => r.login ?? r.name ?? r.slug ?? "Team").join(", ") })
|
|
509
344
|
] }),
|
|
510
|
-
(((_f = pr.statusCheckRollup) == null ? void 0 : _f.length) ?? 0) > 0 && /* @__PURE__ */
|
|
511
|
-
/* @__PURE__ */
|
|
512
|
-
(_g = pr.statusCheckRollup) == null ? void 0 : _g.map((check, idx) => /* @__PURE__ */
|
|
345
|
+
(((_f = pr.statusCheckRollup) == null ? void 0 : _f.length) ?? 0) > 0 && /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
346
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Checks:" }),
|
|
347
|
+
(_g = pr.statusCheckRollup) == null ? void 0 : _g.map((check, idx) => /* @__PURE__ */ jsxs(Text, { color: getCheckColor(check), children: [
|
|
513
348
|
" ",
|
|
514
349
|
getCheckIcon(check),
|
|
515
350
|
" ",
|
|
516
351
|
check.name ?? check.context
|
|
517
352
|
] }, idx))
|
|
518
353
|
] }),
|
|
519
|
-
pr.body && /* @__PURE__ */
|
|
520
|
-
/* @__PURE__ */
|
|
521
|
-
/* @__PURE__ */
|
|
354
|
+
pr.body && /* @__PURE__ */ jsxs(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
355
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Description:" }),
|
|
356
|
+
/* @__PURE__ */ jsx(Text, { children: pr.body })
|
|
522
357
|
] })
|
|
523
358
|
] })
|
|
524
359
|
] }) }) }) });
|
|
525
360
|
}
|
|
526
361
|
|
|
527
362
|
// src/components/github/PullRequestsBox.tsx
|
|
528
|
-
import { useEffect, useState
|
|
363
|
+
import { useEffect, useState } from "react";
|
|
529
364
|
import { TitledBox as TitledBox2 } from "@mishieck/ink-titled-box";
|
|
530
|
-
import { Box as
|
|
365
|
+
import { Box as Box2, Text as Text2, useInput as useInput2 } from "ink";
|
|
531
366
|
|
|
532
367
|
// src/lib/clipboard.ts
|
|
533
368
|
import { exec as exec2 } from "child_process";
|
|
@@ -551,7 +386,7 @@ async function copyToClipboard(text) {
|
|
|
551
386
|
}
|
|
552
387
|
|
|
553
388
|
// src/components/github/PullRequestsBox.tsx
|
|
554
|
-
import { Fragment as Fragment2, jsx as
|
|
389
|
+
import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
555
390
|
function PullRequestsBox({
|
|
556
391
|
prs,
|
|
557
392
|
selectedPR,
|
|
@@ -563,13 +398,13 @@ function PullRequestsBox({
|
|
|
563
398
|
repoSlug,
|
|
564
399
|
isFocused
|
|
565
400
|
}) {
|
|
566
|
-
const [highlightedIndex, setHighlightedIndex] =
|
|
401
|
+
const [highlightedIndex, setHighlightedIndex] = useState(0);
|
|
567
402
|
const totalItems = prs.length + 1;
|
|
568
403
|
useEffect(() => {
|
|
569
404
|
const idx = prs.findIndex((p) => p.number === (selectedPR == null ? void 0 : selectedPR.number));
|
|
570
405
|
if (idx >= 0) setHighlightedIndex(idx);
|
|
571
406
|
}, [selectedPR, prs]);
|
|
572
|
-
|
|
407
|
+
useInput2(
|
|
573
408
|
(input, key) => {
|
|
574
409
|
if (!isFocused) return;
|
|
575
410
|
if (key.upArrow || input === "k") {
|
|
@@ -596,16 +431,16 @@ function PullRequestsBox({
|
|
|
596
431
|
const title = "[2] Pull Requests";
|
|
597
432
|
const subtitle = branch ? ` (${branch})` : "";
|
|
598
433
|
const borderColor = isFocused ? "yellow" : void 0;
|
|
599
|
-
return /* @__PURE__ */
|
|
600
|
-
loading && /* @__PURE__ */
|
|
601
|
-
error && /* @__PURE__ */
|
|
602
|
-
!loading && !error && /* @__PURE__ */
|
|
603
|
-
prs.length === 0 && /* @__PURE__ */
|
|
434
|
+
return /* @__PURE__ */ jsx2(TitledBox2, { borderStyle: "round", titles: [`${title}${subtitle}`], borderColor, flexShrink: 0, children: /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", paddingX: 1, overflow: "hidden", children: [
|
|
435
|
+
loading && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Loading PRs..." }),
|
|
436
|
+
error && /* @__PURE__ */ jsx2(Text2, { color: "red", children: error }),
|
|
437
|
+
!loading && !error && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
438
|
+
prs.length === 0 && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "No PRs for this branch" }),
|
|
604
439
|
prs.map((pr, idx) => {
|
|
605
440
|
const isHighlighted = isFocused && idx === highlightedIndex;
|
|
606
441
|
const isSelected = pr.number === (selectedPR == null ? void 0 : selectedPR.number);
|
|
607
442
|
const prefix = isHighlighted ? "> " : isSelected ? "\u25CF " : " ";
|
|
608
|
-
return /* @__PURE__ */
|
|
443
|
+
return /* @__PURE__ */ jsxs2(Text2, { color: isSelected ? "green" : void 0, children: [
|
|
609
444
|
prefix,
|
|
610
445
|
"#",
|
|
611
446
|
pr.number,
|
|
@@ -614,7 +449,7 @@ function PullRequestsBox({
|
|
|
614
449
|
pr.title
|
|
615
450
|
] }, pr.number);
|
|
616
451
|
}),
|
|
617
|
-
/* @__PURE__ */
|
|
452
|
+
/* @__PURE__ */ jsxs2(Text2, { color: "blue", children: [
|
|
618
453
|
isFocused && highlightedIndex === prs.length ? "> " : " ",
|
|
619
454
|
"+ Create new PR"
|
|
620
455
|
] })
|
|
@@ -623,17 +458,17 @@ function PullRequestsBox({
|
|
|
623
458
|
}
|
|
624
459
|
|
|
625
460
|
// src/components/github/RemotesBox.tsx
|
|
626
|
-
import { useEffect as useEffect2, useState as
|
|
461
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
627
462
|
import { TitledBox as TitledBox3 } from "@mishieck/ink-titled-box";
|
|
628
|
-
import { Box as
|
|
629
|
-
import { jsx as
|
|
463
|
+
import { Box as Box3, Text as Text3, useInput as useInput3 } from "ink";
|
|
464
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
630
465
|
function RemotesBox({ remotes, selectedRemote, onSelect, loading, error, isFocused }) {
|
|
631
|
-
const [highlightedIndex, setHighlightedIndex] =
|
|
466
|
+
const [highlightedIndex, setHighlightedIndex] = useState2(0);
|
|
632
467
|
useEffect2(() => {
|
|
633
468
|
const idx = remotes.findIndex((r) => r.name === selectedRemote);
|
|
634
469
|
if (idx >= 0) setHighlightedIndex(idx);
|
|
635
470
|
}, [selectedRemote, remotes]);
|
|
636
|
-
|
|
471
|
+
useInput3(
|
|
637
472
|
(input, key) => {
|
|
638
473
|
if (!isFocused || remotes.length === 0) return;
|
|
639
474
|
if (key.upArrow || input === "k") {
|
|
@@ -650,15 +485,15 @@ function RemotesBox({ remotes, selectedRemote, onSelect, loading, error, isFocus
|
|
|
650
485
|
);
|
|
651
486
|
const title = "[1] Remotes";
|
|
652
487
|
const borderColor = isFocused ? "yellow" : void 0;
|
|
653
|
-
return /* @__PURE__ */
|
|
654
|
-
loading && /* @__PURE__ */
|
|
655
|
-
error && /* @__PURE__ */
|
|
656
|
-
!loading && !error && remotes.length === 0 && /* @__PURE__ */
|
|
488
|
+
return /* @__PURE__ */ jsx3(TitledBox3, { borderStyle: "round", titles: [title], borderColor, flexShrink: 0, children: /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", paddingX: 1, overflow: "hidden", children: [
|
|
489
|
+
loading && /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "Loading..." }),
|
|
490
|
+
error && /* @__PURE__ */ jsx3(Text3, { color: "red", children: error }),
|
|
491
|
+
!loading && !error && remotes.length === 0 && /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "No remotes configured" }),
|
|
657
492
|
!loading && !error && remotes.map((remote, idx) => {
|
|
658
493
|
const isHighlighted = isFocused && idx === highlightedIndex;
|
|
659
494
|
const isSelected = remote.name === selectedRemote;
|
|
660
495
|
const prefix = isHighlighted ? "> " : isSelected ? "\u25CF " : " ";
|
|
661
|
-
return /* @__PURE__ */
|
|
496
|
+
return /* @__PURE__ */ jsxs3(Text3, { color: isSelected ? "green" : void 0, children: [
|
|
662
497
|
prefix,
|
|
663
498
|
remote.name,
|
|
664
499
|
" (",
|
|
@@ -670,38 +505,26 @@ function RemotesBox({ remotes, selectedRemote, onSelect, loading, error, isFocus
|
|
|
670
505
|
}
|
|
671
506
|
|
|
672
507
|
// src/components/github/GitHubView.tsx
|
|
673
|
-
import { jsx as
|
|
674
|
-
function GitHubView({ isFocused,
|
|
675
|
-
const [isRepo, setIsRepo] =
|
|
676
|
-
const [repoPath, setRepoPath] =
|
|
677
|
-
const [remotes, setRemotes] =
|
|
678
|
-
const [currentBranch, setCurrentBranch] =
|
|
679
|
-
const [currentRepoSlug, setCurrentRepoSlug] =
|
|
680
|
-
const [selectedRemote, setSelectedRemote] =
|
|
681
|
-
const [selectedPR, setSelectedPR] =
|
|
682
|
-
const [prs, setPrs] =
|
|
683
|
-
const [prDetails, setPrDetails] =
|
|
684
|
-
const [loading, setLoading] =
|
|
508
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
509
|
+
function GitHubView({ isFocused, onKeybindingsChange }) {
|
|
510
|
+
const [isRepo, setIsRepo] = useState3(null);
|
|
511
|
+
const [repoPath, setRepoPath] = useState3(null);
|
|
512
|
+
const [remotes, setRemotes] = useState3([]);
|
|
513
|
+
const [currentBranch, setCurrentBranch] = useState3(null);
|
|
514
|
+
const [currentRepoSlug, setCurrentRepoSlug] = useState3(null);
|
|
515
|
+
const [selectedRemote, setSelectedRemote] = useState3(null);
|
|
516
|
+
const [selectedPR, setSelectedPR] = useState3(null);
|
|
517
|
+
const [prs, setPrs] = useState3([]);
|
|
518
|
+
const [prDetails, setPrDetails] = useState3(null);
|
|
519
|
+
const [loading, setLoading] = useState3({
|
|
685
520
|
remotes: true,
|
|
686
521
|
prs: false,
|
|
687
|
-
details: false
|
|
688
|
-
createPR: false
|
|
522
|
+
details: false
|
|
689
523
|
});
|
|
690
|
-
const [errors, setErrors] =
|
|
691
|
-
const [
|
|
692
|
-
const [prTemplate, setPrTemplate] = useState4(null);
|
|
693
|
-
const [focusedBox, setFocusedBox] = useState4("remotes");
|
|
524
|
+
const [errors, setErrors] = useState3({});
|
|
525
|
+
const [focusedBox, setFocusedBox] = useState3("remotes");
|
|
694
526
|
useEffect3(() => {
|
|
695
527
|
if (!isFocused) {
|
|
696
|
-
setShowCreatePR(false);
|
|
697
|
-
setErrors((prev) => ({ ...prev, createPR: void 0 }));
|
|
698
|
-
}
|
|
699
|
-
}, [isFocused]);
|
|
700
|
-
useEffect3(() => {
|
|
701
|
-
onModalChange == null ? void 0 : onModalChange(showCreatePR);
|
|
702
|
-
}, [showCreatePR, onModalChange]);
|
|
703
|
-
useEffect3(() => {
|
|
704
|
-
if (!isFocused || showCreatePR) {
|
|
705
528
|
onKeybindingsChange == null ? void 0 : onKeybindingsChange([]);
|
|
706
529
|
return;
|
|
707
530
|
}
|
|
@@ -710,13 +533,15 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
710
533
|
bindings.push({ key: "Enter", label: "Select Remote" });
|
|
711
534
|
} else if (focusedBox === "prs") {
|
|
712
535
|
bindings.push({ key: "n", label: "New PR", color: "green" });
|
|
536
|
+
bindings.push({ key: "r", label: "Refresh" });
|
|
713
537
|
bindings.push({ key: "o", label: "Open", color: "green" });
|
|
714
538
|
bindings.push({ key: "y", label: "Copy Link" });
|
|
715
539
|
} else if (focusedBox === "details") {
|
|
540
|
+
bindings.push({ key: "r", label: "Refresh" });
|
|
716
541
|
bindings.push({ key: "o", label: "Open", color: "green" });
|
|
717
542
|
}
|
|
718
543
|
onKeybindingsChange == null ? void 0 : onKeybindingsChange(bindings);
|
|
719
|
-
}, [isFocused, focusedBox,
|
|
544
|
+
}, [isFocused, focusedBox, onKeybindingsChange]);
|
|
720
545
|
useEffect3(() => {
|
|
721
546
|
const gitRepoCheck = isGitRepo();
|
|
722
547
|
setIsRepo(gitRepoCheck);
|
|
@@ -728,8 +553,6 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
728
553
|
const rootResult = getRepoRoot();
|
|
729
554
|
if (rootResult.success) {
|
|
730
555
|
setRepoPath(rootResult.data);
|
|
731
|
-
const template = getPRTemplate(rootResult.data);
|
|
732
|
-
setPrTemplate(template);
|
|
733
556
|
}
|
|
734
557
|
const branchResult = getCurrentBranch();
|
|
735
558
|
if (branchResult.success) {
|
|
@@ -746,6 +569,43 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
746
569
|
}
|
|
747
570
|
setLoading((prev) => ({ ...prev, remotes: false }));
|
|
748
571
|
}, []);
|
|
572
|
+
const refreshPRs = useCallback(async () => {
|
|
573
|
+
if (!currentBranch || !currentRepoSlug) return;
|
|
574
|
+
setLoading((prev) => ({ ...prev, prs: true }));
|
|
575
|
+
try {
|
|
576
|
+
const result = await listPRsForBranch(currentBranch, currentRepoSlug);
|
|
577
|
+
if (result.success) {
|
|
578
|
+
setPrs(result.data);
|
|
579
|
+
if (result.data.length > 0) {
|
|
580
|
+
setSelectedPR((prev) => prev ?? result.data[0]);
|
|
581
|
+
}
|
|
582
|
+
setErrors((prev) => ({ ...prev, prs: void 0 }));
|
|
583
|
+
} else {
|
|
584
|
+
setErrors((prev) => ({ ...prev, prs: result.error }));
|
|
585
|
+
}
|
|
586
|
+
} catch (err) {
|
|
587
|
+
setErrors((prev) => ({ ...prev, prs: String(err) }));
|
|
588
|
+
} finally {
|
|
589
|
+
setLoading((prev) => ({ ...prev, prs: false }));
|
|
590
|
+
}
|
|
591
|
+
}, [currentBranch, currentRepoSlug]);
|
|
592
|
+
const refreshDetails = useCallback(async () => {
|
|
593
|
+
if (!selectedPR || !currentRepoSlug) return;
|
|
594
|
+
setLoading((prev) => ({ ...prev, details: true }));
|
|
595
|
+
try {
|
|
596
|
+
const result = await getPRDetails(selectedPR.number, currentRepoSlug);
|
|
597
|
+
if (result.success) {
|
|
598
|
+
setPrDetails(result.data);
|
|
599
|
+
setErrors((prev) => ({ ...prev, details: void 0 }));
|
|
600
|
+
} else {
|
|
601
|
+
setErrors((prev) => ({ ...prev, details: result.error }));
|
|
602
|
+
}
|
|
603
|
+
} catch (err) {
|
|
604
|
+
setErrors((prev) => ({ ...prev, details: String(err) }));
|
|
605
|
+
} finally {
|
|
606
|
+
setLoading((prev) => ({ ...prev, details: false }));
|
|
607
|
+
}
|
|
608
|
+
}, [selectedPR, currentRepoSlug]);
|
|
749
609
|
useEffect3(() => {
|
|
750
610
|
if (!selectedRemote || !currentBranch) return;
|
|
751
611
|
const remote = remotes.find((r) => r.name === selectedRemote);
|
|
@@ -753,52 +613,21 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
753
613
|
const repo = getRepoFromRemote(remote.url);
|
|
754
614
|
if (!repo) return;
|
|
755
615
|
setCurrentRepoSlug(repo);
|
|
756
|
-
setLoading((prev) => ({ ...prev, prs: true }));
|
|
757
616
|
setPrs([]);
|
|
758
617
|
setSelectedPR(null);
|
|
759
|
-
const fetchPRs = async () => {
|
|
760
|
-
try {
|
|
761
|
-
const result = await listPRsForBranch(currentBranch, repo);
|
|
762
|
-
if (result.success) {
|
|
763
|
-
setPrs(result.data);
|
|
764
|
-
if (result.data.length > 0) {
|
|
765
|
-
setSelectedPR(result.data[0]);
|
|
766
|
-
}
|
|
767
|
-
setErrors((prev) => ({ ...prev, prs: void 0 }));
|
|
768
|
-
} else {
|
|
769
|
-
setErrors((prev) => ({ ...prev, prs: result.error }));
|
|
770
|
-
}
|
|
771
|
-
} catch (err) {
|
|
772
|
-
setErrors((prev) => ({ ...prev, prs: String(err) }));
|
|
773
|
-
} finally {
|
|
774
|
-
setLoading((prev) => ({ ...prev, prs: false }));
|
|
775
|
-
}
|
|
776
|
-
};
|
|
777
|
-
fetchPRs();
|
|
778
618
|
}, [selectedRemote, currentBranch, remotes]);
|
|
619
|
+
useEffect3(() => {
|
|
620
|
+
if (currentRepoSlug && currentBranch) {
|
|
621
|
+
refreshPRs();
|
|
622
|
+
}
|
|
623
|
+
}, [currentRepoSlug, currentBranch, refreshPRs]);
|
|
779
624
|
useEffect3(() => {
|
|
780
625
|
if (!selectedPR || !currentRepoSlug) {
|
|
781
626
|
setPrDetails(null);
|
|
782
627
|
return;
|
|
783
628
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
try {
|
|
787
|
-
const result = await getPRDetails(selectedPR.number, currentRepoSlug);
|
|
788
|
-
if (result.success) {
|
|
789
|
-
setPrDetails(result.data);
|
|
790
|
-
setErrors((prev) => ({ ...prev, details: void 0 }));
|
|
791
|
-
} else {
|
|
792
|
-
setErrors((prev) => ({ ...prev, details: result.error }));
|
|
793
|
-
}
|
|
794
|
-
} catch (err) {
|
|
795
|
-
setErrors((prev) => ({ ...prev, details: String(err) }));
|
|
796
|
-
} finally {
|
|
797
|
-
setLoading((prev) => ({ ...prev, details: false }));
|
|
798
|
-
}
|
|
799
|
-
};
|
|
800
|
-
fetchDetails();
|
|
801
|
-
}, [selectedPR, currentRepoSlug]);
|
|
629
|
+
refreshDetails();
|
|
630
|
+
}, [selectedPR, currentRepoSlug, refreshDetails]);
|
|
802
631
|
const handleRemoteSelect = useCallback(
|
|
803
632
|
(remoteName) => {
|
|
804
633
|
setSelectedRemote(remoteName);
|
|
@@ -812,57 +641,27 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
812
641
|
setSelectedPR(pr);
|
|
813
642
|
}, []);
|
|
814
643
|
const handleCreatePR = useCallback(() => {
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
const handleCreatePRSubmit = useCallback(
|
|
819
|
-
async (title, body) => {
|
|
820
|
-
if (!currentRepoSlug) return;
|
|
821
|
-
setLoading((prev) => ({ ...prev, createPR: true }));
|
|
822
|
-
setErrors((prev) => ({ ...prev, createPR: void 0 }));
|
|
823
|
-
try {
|
|
824
|
-
const result = await createPR(currentRepoSlug, title, body);
|
|
825
|
-
if (result.success) {
|
|
826
|
-
setShowCreatePR(false);
|
|
827
|
-
if (currentBranch) {
|
|
828
|
-
const prsResult = await listPRsForBranch(currentBranch, currentRepoSlug);
|
|
829
|
-
if (prsResult.success) {
|
|
830
|
-
setPrs(prsResult.data);
|
|
831
|
-
const newPR = prsResult.data.find((p) => p.number === result.data.number);
|
|
832
|
-
if (newPR) {
|
|
833
|
-
setSelectedPR(newPR);
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
}
|
|
837
|
-
} else {
|
|
838
|
-
setErrors((prev) => ({ ...prev, createPR: result.error }));
|
|
839
|
-
}
|
|
840
|
-
} catch (err) {
|
|
841
|
-
setErrors((prev) => ({ ...prev, createPR: String(err) }));
|
|
842
|
-
} finally {
|
|
843
|
-
setLoading((prev) => ({ ...prev, createPR: false }));
|
|
844
|
-
}
|
|
845
|
-
},
|
|
846
|
-
[currentRepoSlug, currentBranch]
|
|
847
|
-
);
|
|
848
|
-
const handleCreatePRCancel = useCallback(() => {
|
|
849
|
-
setShowCreatePR(false);
|
|
850
|
-
setErrors((prev) => ({ ...prev, createPR: void 0 }));
|
|
644
|
+
exec3("gh pr create --web", () => {
|
|
645
|
+
process.stdout.emit("resize");
|
|
646
|
+
});
|
|
851
647
|
}, []);
|
|
852
|
-
|
|
648
|
+
useInput4(
|
|
853
649
|
(input) => {
|
|
854
|
-
if (showCreatePR) return;
|
|
855
650
|
if (input === "1") setFocusedBox("remotes");
|
|
856
651
|
if (input === "2") setFocusedBox("prs");
|
|
857
652
|
if (input === "3") setFocusedBox("details");
|
|
653
|
+
if (input === "r") {
|
|
654
|
+
if (focusedBox === "prs") refreshPRs();
|
|
655
|
+
if (focusedBox === "details") refreshDetails();
|
|
656
|
+
}
|
|
858
657
|
},
|
|
859
|
-
{ isActive: isFocused
|
|
658
|
+
{ isActive: isFocused }
|
|
860
659
|
);
|
|
861
660
|
if (isRepo === false) {
|
|
862
|
-
return /* @__PURE__ */
|
|
661
|
+
return /* @__PURE__ */ jsx4(TitledBox4, { borderStyle: "round", titles: ["Error"], flexGrow: 1, children: /* @__PURE__ */ jsx4(Text4, { color: "red", children: "Current directory is not a git repository" }) });
|
|
863
662
|
}
|
|
864
|
-
return /* @__PURE__ */
|
|
865
|
-
/* @__PURE__ */
|
|
663
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", flexGrow: 1, children: [
|
|
664
|
+
/* @__PURE__ */ jsx4(
|
|
866
665
|
RemotesBox,
|
|
867
666
|
{
|
|
868
667
|
remotes,
|
|
@@ -870,10 +669,10 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
870
669
|
onSelect: handleRemoteSelect,
|
|
871
670
|
loading: loading.remotes,
|
|
872
671
|
error: errors.remotes,
|
|
873
|
-
isFocused: isFocused &&
|
|
672
|
+
isFocused: isFocused && focusedBox === "remotes"
|
|
874
673
|
}
|
|
875
674
|
),
|
|
876
|
-
/* @__PURE__ */
|
|
675
|
+
/* @__PURE__ */ jsx4(
|
|
877
676
|
PullRequestsBox,
|
|
878
677
|
{
|
|
879
678
|
prs,
|
|
@@ -884,36 +683,26 @@ function GitHubView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
884
683
|
error: errors.prs,
|
|
885
684
|
branch: currentBranch,
|
|
886
685
|
repoSlug: currentRepoSlug,
|
|
887
|
-
isFocused: isFocused &&
|
|
686
|
+
isFocused: isFocused && focusedBox === "prs"
|
|
888
687
|
}
|
|
889
688
|
),
|
|
890
|
-
|
|
891
|
-
CreatePRModal,
|
|
892
|
-
{
|
|
893
|
-
template: prTemplate,
|
|
894
|
-
onSubmit: handleCreatePRSubmit,
|
|
895
|
-
onCancel: handleCreatePRCancel,
|
|
896
|
-
loading: loading.createPR,
|
|
897
|
-
error: errors.createPR
|
|
898
|
-
}
|
|
899
|
-
),
|
|
900
|
-
/* @__PURE__ */ jsx5(
|
|
689
|
+
/* @__PURE__ */ jsx4(
|
|
901
690
|
PRDetailsBox,
|
|
902
691
|
{
|
|
903
692
|
pr: prDetails,
|
|
904
693
|
loading: loading.details,
|
|
905
694
|
error: errors.details,
|
|
906
|
-
isFocused: isFocused &&
|
|
695
|
+
isFocused: isFocused && focusedBox === "details"
|
|
907
696
|
}
|
|
908
697
|
)
|
|
909
698
|
] });
|
|
910
699
|
}
|
|
911
700
|
|
|
912
701
|
// src/components/jira/JiraView.tsx
|
|
913
|
-
import { useCallback as useCallback2, useEffect as useEffect5, useState as
|
|
702
|
+
import { useCallback as useCallback2, useEffect as useEffect5, useState as useState7 } from "react";
|
|
914
703
|
import open2 from "open";
|
|
915
704
|
import { TitledBox as TitledBox5 } from "@mishieck/ink-titled-box";
|
|
916
|
-
import { Box as
|
|
705
|
+
import { Box as Box10, Text as Text10, useInput as useInput9 } from "ink";
|
|
917
706
|
|
|
918
707
|
// src/lib/jira/parser.ts
|
|
919
708
|
var TICKET_KEY_PATTERN = /^[A-Z][A-Z0-9]+-\d+$/;
|
|
@@ -1139,15 +928,15 @@ async function applyTransition(auth, ticketKey, transitionId) {
|
|
|
1139
928
|
}
|
|
1140
929
|
|
|
1141
930
|
// src/components/jira/ChangeStatusModal.tsx
|
|
1142
|
-
import { useEffect as useEffect4, useState as
|
|
1143
|
-
import { Box as
|
|
931
|
+
import { useEffect as useEffect4, useState as useState4 } from "react";
|
|
932
|
+
import { Box as Box5, Text as Text5, useInput as useInput5 } from "ink";
|
|
1144
933
|
import SelectInput from "ink-select-input";
|
|
1145
|
-
import { jsx as
|
|
934
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1146
935
|
function ChangeStatusModal({ repoPath, ticketKey, currentStatus, onComplete, onCancel }) {
|
|
1147
|
-
const [transitions, setTransitions] =
|
|
1148
|
-
const [loading, setLoading] =
|
|
1149
|
-
const [applying, setApplying] =
|
|
1150
|
-
const [error, setError] =
|
|
936
|
+
const [transitions, setTransitions] = useState4([]);
|
|
937
|
+
const [loading, setLoading] = useState4(true);
|
|
938
|
+
const [applying, setApplying] = useState4(false);
|
|
939
|
+
const [error, setError] = useState4(null);
|
|
1151
940
|
useEffect4(() => {
|
|
1152
941
|
const fetchTransitions = async () => {
|
|
1153
942
|
const siteUrl = getJiraSiteUrl(repoPath);
|
|
@@ -1189,7 +978,7 @@ function ChangeStatusModal({ repoPath, ticketKey, currentStatus, onComplete, onC
|
|
|
1189
978
|
setApplying(false);
|
|
1190
979
|
}
|
|
1191
980
|
};
|
|
1192
|
-
|
|
981
|
+
useInput5(
|
|
1193
982
|
(_input, key) => {
|
|
1194
983
|
if (key.escape && !applying) {
|
|
1195
984
|
onCancel();
|
|
@@ -1202,24 +991,54 @@ function ChangeStatusModal({ repoPath, ticketKey, currentStatus, onComplete, onC
|
|
|
1202
991
|
value: t.id
|
|
1203
992
|
}));
|
|
1204
993
|
const initialIndex = Math.max(0, transitions.findIndex((t) => t.to.name === currentStatus));
|
|
1205
|
-
return /* @__PURE__ */
|
|
1206
|
-
/* @__PURE__ */
|
|
994
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, paddingY: 1, children: [
|
|
995
|
+
/* @__PURE__ */ jsxs5(Text5, { bold: true, color: "yellow", children: [
|
|
1207
996
|
"Change Status: ",
|
|
1208
997
|
ticketKey
|
|
1209
998
|
] }),
|
|
1210
|
-
loading && /* @__PURE__ */
|
|
1211
|
-
error && /* @__PURE__ */
|
|
1212
|
-
!loading && !error && transitions.length === 0 && /* @__PURE__ */
|
|
1213
|
-
!loading && !error && transitions.length > 0 && !applying && /* @__PURE__ */
|
|
1214
|
-
applying && /* @__PURE__ */
|
|
1215
|
-
/* @__PURE__ */
|
|
999
|
+
loading && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Loading transitions..." }),
|
|
1000
|
+
error && /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { color: "red", children: error }) }),
|
|
1001
|
+
!loading && !error && transitions.length === 0 && /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "No available transitions" }),
|
|
1002
|
+
!loading && !error && transitions.length > 0 && !applying && /* @__PURE__ */ jsx5(Box5, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx5(SelectInput, { items, initialIndex, onSelect: handleSelect }) }),
|
|
1003
|
+
applying && /* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { color: "yellow", children: "Updating status..." }) }),
|
|
1004
|
+
/* @__PURE__ */ jsx5(Box5, { marginTop: 1, children: /* @__PURE__ */ jsx5(Text5, { dimColor: true, children: "Esc to cancel" }) })
|
|
1216
1005
|
] });
|
|
1217
1006
|
}
|
|
1218
1007
|
|
|
1219
1008
|
// src/components/jira/ConfigureJiraSiteModal.tsx
|
|
1220
|
-
import { useState as
|
|
1221
|
-
import { Box as
|
|
1222
|
-
|
|
1009
|
+
import { useState as useState5 } from "react";
|
|
1010
|
+
import { Box as Box6, Text as Text6, useInput as useInput6 } from "ink";
|
|
1011
|
+
|
|
1012
|
+
// src/lib/editor.ts
|
|
1013
|
+
import { spawnSync } from "child_process";
|
|
1014
|
+
import { mkdtempSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1015
|
+
import { tmpdir } from "os";
|
|
1016
|
+
import { join as join2 } from "path";
|
|
1017
|
+
function openInEditor(content, filename) {
|
|
1018
|
+
const editor = process.env.VISUAL || process.env.EDITOR || "vi";
|
|
1019
|
+
const tempDir = mkdtempSync(join2(tmpdir(), "clairo-"));
|
|
1020
|
+
const tempFile = join2(tempDir, filename);
|
|
1021
|
+
try {
|
|
1022
|
+
writeFileSync2(tempFile, content);
|
|
1023
|
+
const result = spawnSync(editor, [tempFile], {
|
|
1024
|
+
stdio: "inherit"
|
|
1025
|
+
});
|
|
1026
|
+
process.stdout.write("\x1B[2J\x1B[H");
|
|
1027
|
+
process.stdout.emit("resize");
|
|
1028
|
+
if (result.status !== 0) {
|
|
1029
|
+
return null;
|
|
1030
|
+
}
|
|
1031
|
+
return readFileSync2(tempFile, "utf-8");
|
|
1032
|
+
} finally {
|
|
1033
|
+
try {
|
|
1034
|
+
rmSync(tempDir, { recursive: true });
|
|
1035
|
+
} catch {
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
// src/components/jira/ConfigureJiraSiteModal.tsx
|
|
1041
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1223
1042
|
function ConfigureJiraSiteModal({
|
|
1224
1043
|
initialSiteUrl,
|
|
1225
1044
|
initialEmail,
|
|
@@ -1228,13 +1047,13 @@ function ConfigureJiraSiteModal({
|
|
|
1228
1047
|
loading,
|
|
1229
1048
|
error
|
|
1230
1049
|
}) {
|
|
1231
|
-
const [siteUrl, setSiteUrl] =
|
|
1232
|
-
const [email, setEmail] =
|
|
1233
|
-
const [apiToken, setApiToken] =
|
|
1234
|
-
const [selectedItem, setSelectedItem] =
|
|
1050
|
+
const [siteUrl, setSiteUrl] = useState5(initialSiteUrl ?? "");
|
|
1051
|
+
const [email, setEmail] = useState5(initialEmail ?? "");
|
|
1052
|
+
const [apiToken, setApiToken] = useState5("");
|
|
1053
|
+
const [selectedItem, setSelectedItem] = useState5("siteUrl");
|
|
1235
1054
|
const items = ["siteUrl", "email", "apiToken", "submit"];
|
|
1236
1055
|
const canSubmit = siteUrl.trim() && email.trim() && apiToken.trim();
|
|
1237
|
-
|
|
1056
|
+
useInput6(
|
|
1238
1057
|
(input, key) => {
|
|
1239
1058
|
if (loading) return;
|
|
1240
1059
|
if (key.escape) {
|
|
@@ -1283,43 +1102,43 @@ function ConfigureJiraSiteModal({
|
|
|
1283
1102
|
const prefix = isSelected ? "> " : " ";
|
|
1284
1103
|
const color = isSelected ? "yellow" : void 0;
|
|
1285
1104
|
const displayValue = isSensitive && value ? "*".repeat(Math.min(value.length, 20)) : value;
|
|
1286
|
-
return /* @__PURE__ */
|
|
1287
|
-
/* @__PURE__ */
|
|
1105
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
1106
|
+
/* @__PURE__ */ jsxs6(Text6, { color, bold: isSelected, children: [
|
|
1288
1107
|
prefix,
|
|
1289
1108
|
label
|
|
1290
1109
|
] }),
|
|
1291
|
-
value !== void 0 && /* @__PURE__ */
|
|
1110
|
+
value !== void 0 && /* @__PURE__ */ jsx6(Box6, { marginLeft: 4, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: displayValue || "(empty - press Enter to edit)" }) })
|
|
1292
1111
|
] });
|
|
1293
1112
|
};
|
|
1294
|
-
return /* @__PURE__ */
|
|
1295
|
-
/* @__PURE__ */
|
|
1296
|
-
/* @__PURE__ */
|
|
1297
|
-
/* @__PURE__ */
|
|
1298
|
-
error && /* @__PURE__ */
|
|
1113
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, paddingY: 1, children: [
|
|
1114
|
+
/* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: "Configure Jira Site" }),
|
|
1115
|
+
/* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Up/Down to select, Enter to edit, Esc to cancel" }),
|
|
1116
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1 }),
|
|
1117
|
+
error && /* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { color: "red", children: error }) }),
|
|
1299
1118
|
renderItem("siteUrl", "Site URL (e.g., https://company.atlassian.net)", siteUrl),
|
|
1300
|
-
/* @__PURE__ */
|
|
1119
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1 }),
|
|
1301
1120
|
renderItem("email", "Email", email),
|
|
1302
|
-
/* @__PURE__ */
|
|
1121
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1 }),
|
|
1303
1122
|
renderItem("apiToken", "API Token", apiToken, true),
|
|
1304
|
-
/* @__PURE__ */
|
|
1305
|
-
/* @__PURE__ */
|
|
1123
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1 }),
|
|
1124
|
+
/* @__PURE__ */ jsx6(Box6, { children: /* @__PURE__ */ jsxs6(Text6, { color: selectedItem === "submit" ? "green" : void 0, bold: selectedItem === "submit", children: [
|
|
1306
1125
|
selectedItem === "submit" ? "> " : " ",
|
|
1307
1126
|
canSubmit ? "[Save Configuration]" : "[Fill all fields first]"
|
|
1308
1127
|
] }) }),
|
|
1309
|
-
loading && /* @__PURE__ */
|
|
1310
|
-
/* @__PURE__ */
|
|
1128
|
+
loading && /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: "Validating credentials..." }) }),
|
|
1129
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Get your API token from: https://id.atlassian.com/manage-profile/security/api-tokens" }) })
|
|
1311
1130
|
] });
|
|
1312
1131
|
}
|
|
1313
1132
|
|
|
1314
1133
|
// src/components/jira/LinkTicketModal.tsx
|
|
1315
|
-
import { useState as
|
|
1316
|
-
import { Box as
|
|
1134
|
+
import { useState as useState6 } from "react";
|
|
1135
|
+
import { Box as Box8, Text as Text8, useInput as useInput8 } from "ink";
|
|
1317
1136
|
|
|
1318
1137
|
// src/components/ui/TextInput.tsx
|
|
1319
|
-
import { Box as
|
|
1320
|
-
import { jsx as
|
|
1138
|
+
import { Box as Box7, Text as Text7, useInput as useInput7 } from "ink";
|
|
1139
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1321
1140
|
function TextInput({ value, onChange, placeholder, isActive, mask }) {
|
|
1322
|
-
|
|
1141
|
+
useInput7(
|
|
1323
1142
|
(input, key) => {
|
|
1324
1143
|
if (key.backspace || key.delete) {
|
|
1325
1144
|
if (value.length > 0) {
|
|
@@ -1338,18 +1157,18 @@ function TextInput({ value, onChange, placeholder, isActive, mask }) {
|
|
|
1338
1157
|
);
|
|
1339
1158
|
const displayValue = mask ? "*".repeat(value.length) : value;
|
|
1340
1159
|
const showPlaceholder = value.length === 0 && placeholder;
|
|
1341
|
-
return /* @__PURE__ */
|
|
1342
|
-
showPlaceholder ? /* @__PURE__ */
|
|
1343
|
-
isActive && /* @__PURE__ */
|
|
1160
|
+
return /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
1161
|
+
showPlaceholder ? /* @__PURE__ */ jsx7(Text7, { dimColor: true, children: placeholder }) : /* @__PURE__ */ jsx7(Text7, { children: displayValue }),
|
|
1162
|
+
isActive && /* @__PURE__ */ jsx7(Text7, { backgroundColor: "yellow", children: " " })
|
|
1344
1163
|
] }) });
|
|
1345
1164
|
}
|
|
1346
1165
|
|
|
1347
1166
|
// src/components/jira/LinkTicketModal.tsx
|
|
1348
|
-
import { jsx as
|
|
1167
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1349
1168
|
function LinkTicketModal({ onSubmit, onCancel, loading, error }) {
|
|
1350
|
-
const [ticketInput, setTicketInput] =
|
|
1169
|
+
const [ticketInput, setTicketInput] = useState6("");
|
|
1351
1170
|
const canSubmit = ticketInput.trim().length > 0;
|
|
1352
|
-
|
|
1171
|
+
useInput8(
|
|
1353
1172
|
(_input, key) => {
|
|
1354
1173
|
if (loading) return;
|
|
1355
1174
|
if (key.escape) {
|
|
@@ -1362,14 +1181,14 @@ function LinkTicketModal({ onSubmit, onCancel, loading, error }) {
|
|
|
1362
1181
|
},
|
|
1363
1182
|
{ isActive: !loading }
|
|
1364
1183
|
);
|
|
1365
|
-
return /* @__PURE__ */
|
|
1366
|
-
/* @__PURE__ */
|
|
1367
|
-
/* @__PURE__ */
|
|
1368
|
-
/* @__PURE__ */
|
|
1369
|
-
error && /* @__PURE__ */
|
|
1370
|
-
/* @__PURE__ */
|
|
1371
|
-
/* @__PURE__ */
|
|
1372
|
-
/* @__PURE__ */
|
|
1184
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, paddingY: 1, children: [
|
|
1185
|
+
/* @__PURE__ */ jsx8(Text8, { bold: true, color: "yellow", children: "Link Jira Ticket" }),
|
|
1186
|
+
/* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Type ticket ID, Enter to submit, Esc to cancel" }),
|
|
1187
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1 }),
|
|
1188
|
+
error && /* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: /* @__PURE__ */ jsx8(Text8, { color: "red", children: error }) }),
|
|
1189
|
+
/* @__PURE__ */ jsxs8(Box8, { children: [
|
|
1190
|
+
/* @__PURE__ */ jsx8(Text8, { color: "blue", children: "Ticket: " }),
|
|
1191
|
+
/* @__PURE__ */ jsx8(
|
|
1373
1192
|
TextInput,
|
|
1374
1193
|
{
|
|
1375
1194
|
value: ticketInput,
|
|
@@ -1379,23 +1198,23 @@ function LinkTicketModal({ onSubmit, onCancel, loading, error }) {
|
|
|
1379
1198
|
}
|
|
1380
1199
|
)
|
|
1381
1200
|
] }),
|
|
1382
|
-
loading && /* @__PURE__ */
|
|
1383
|
-
/* @__PURE__ */
|
|
1201
|
+
loading && /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { color: "yellow", children: "Fetching ticket..." }) }),
|
|
1202
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { dimColor: true, children: "Examples: PROJ-123 or https://company.atlassian.net/browse/PROJ-123" }) })
|
|
1384
1203
|
] });
|
|
1385
1204
|
}
|
|
1386
1205
|
|
|
1387
1206
|
// src/components/jira/TicketItem.tsx
|
|
1388
|
-
import { Box as
|
|
1389
|
-
import { jsx as
|
|
1207
|
+
import { Box as Box9, Text as Text9 } from "ink";
|
|
1208
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1390
1209
|
function TicketItem({ ticketKey, summary, status, isHighlighted, isSelected }) {
|
|
1391
1210
|
const prefix = isHighlighted ? "> " : isSelected ? "\u25CF " : " ";
|
|
1392
1211
|
const textColor = isSelected ? "green" : void 0;
|
|
1393
|
-
return /* @__PURE__ */
|
|
1212
|
+
return /* @__PURE__ */ jsx9(Box9, { children: /* @__PURE__ */ jsxs9(Text9, { color: textColor, children: [
|
|
1394
1213
|
prefix,
|
|
1395
|
-
/* @__PURE__ */
|
|
1214
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: "blue", children: ticketKey }),
|
|
1396
1215
|
" ",
|
|
1397
1216
|
summary,
|
|
1398
|
-
status && /* @__PURE__ */
|
|
1217
|
+
status && /* @__PURE__ */ jsxs9(Text9, { dimColor: true, children: [
|
|
1399
1218
|
" [",
|
|
1400
1219
|
status,
|
|
1401
1220
|
"]"
|
|
@@ -1404,19 +1223,19 @@ function TicketItem({ ticketKey, summary, status, isHighlighted, isSelected }) {
|
|
|
1404
1223
|
}
|
|
1405
1224
|
|
|
1406
1225
|
// src/components/jira/JiraView.tsx
|
|
1407
|
-
import { jsx as
|
|
1226
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1408
1227
|
function JiraView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
1409
|
-
const [repoPath, setRepoPath] =
|
|
1410
|
-
const [currentBranch, setCurrentBranch] =
|
|
1411
|
-
const [isRepo, setIsRepo] =
|
|
1412
|
-
const [jiraState, setJiraState] =
|
|
1413
|
-
const [tickets, setTickets] =
|
|
1414
|
-
const [highlightedIndex, setHighlightedIndex] =
|
|
1415
|
-
const [showConfigureModal, setShowConfigureModal] =
|
|
1416
|
-
const [showLinkModal, setShowLinkModal] =
|
|
1417
|
-
const [showStatusModal, setShowStatusModal] =
|
|
1418
|
-
const [loading, setLoading] =
|
|
1419
|
-
const [errors, setErrors] =
|
|
1228
|
+
const [repoPath, setRepoPath] = useState7(null);
|
|
1229
|
+
const [currentBranch, setCurrentBranch] = useState7(null);
|
|
1230
|
+
const [isRepo, setIsRepo] = useState7(null);
|
|
1231
|
+
const [jiraState, setJiraState] = useState7("not_configured");
|
|
1232
|
+
const [tickets, setTickets] = useState7([]);
|
|
1233
|
+
const [highlightedIndex, setHighlightedIndex] = useState7(0);
|
|
1234
|
+
const [showConfigureModal, setShowConfigureModal] = useState7(false);
|
|
1235
|
+
const [showLinkModal, setShowLinkModal] = useState7(false);
|
|
1236
|
+
const [showStatusModal, setShowStatusModal] = useState7(false);
|
|
1237
|
+
const [loading, setLoading] = useState7({ configure: false, link: false });
|
|
1238
|
+
const [errors, setErrors] = useState7({});
|
|
1420
1239
|
useEffect5(() => {
|
|
1421
1240
|
if (!isFocused) {
|
|
1422
1241
|
setShowConfigureModal(false);
|
|
@@ -1579,7 +1398,7 @@ function JiraView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
1579
1398
|
});
|
|
1580
1399
|
}
|
|
1581
1400
|
}, [repoPath, tickets, highlightedIndex]);
|
|
1582
|
-
|
|
1401
|
+
useInput9(
|
|
1583
1402
|
(input, key) => {
|
|
1584
1403
|
if (showConfigureModal || showLinkModal || showStatusModal) return;
|
|
1585
1404
|
if (input === "c" && jiraState === "not_configured") {
|
|
@@ -1619,12 +1438,12 @@ function JiraView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
1619
1438
|
{ isActive: isFocused && !showConfigureModal && !showLinkModal && !showStatusModal }
|
|
1620
1439
|
);
|
|
1621
1440
|
if (isRepo === false) {
|
|
1622
|
-
return /* @__PURE__ */
|
|
1441
|
+
return /* @__PURE__ */ jsx10(TitledBox5, { borderStyle: "round", titles: ["Jira"], flexShrink: 0, children: /* @__PURE__ */ jsx10(Text10, { color: "red", children: "Not a git repository" }) });
|
|
1623
1442
|
}
|
|
1624
1443
|
if (showConfigureModal) {
|
|
1625
1444
|
const siteUrl = repoPath ? getJiraSiteUrl(repoPath) : void 0;
|
|
1626
1445
|
const creds = repoPath ? getJiraCredentials(repoPath) : { email: null, apiToken: null };
|
|
1627
|
-
return /* @__PURE__ */
|
|
1446
|
+
return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", flexShrink: 0, children: /* @__PURE__ */ jsx10(
|
|
1628
1447
|
ConfigureJiraSiteModal,
|
|
1629
1448
|
{
|
|
1630
1449
|
initialSiteUrl: siteUrl ?? void 0,
|
|
@@ -1640,7 +1459,7 @@ function JiraView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
1640
1459
|
) });
|
|
1641
1460
|
}
|
|
1642
1461
|
if (showLinkModal) {
|
|
1643
|
-
return /* @__PURE__ */
|
|
1462
|
+
return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", flexShrink: 0, children: /* @__PURE__ */ jsx10(
|
|
1644
1463
|
LinkTicketModal,
|
|
1645
1464
|
{
|
|
1646
1465
|
onSubmit: handleLinkSubmit,
|
|
@@ -1655,7 +1474,7 @@ function JiraView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
1655
1474
|
}
|
|
1656
1475
|
if (showStatusModal && repoPath && currentBranch && tickets[highlightedIndex]) {
|
|
1657
1476
|
const ticket = tickets[highlightedIndex];
|
|
1658
|
-
return /* @__PURE__ */
|
|
1477
|
+
return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", flexShrink: 0, children: /* @__PURE__ */ jsx10(
|
|
1659
1478
|
ChangeStatusModal,
|
|
1660
1479
|
{
|
|
1661
1480
|
repoPath,
|
|
@@ -1672,10 +1491,10 @@ function JiraView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
1672
1491
|
}
|
|
1673
1492
|
const title = "[4] Jira";
|
|
1674
1493
|
const borderColor = isFocused ? "yellow" : void 0;
|
|
1675
|
-
return /* @__PURE__ */
|
|
1676
|
-
jiraState === "not_configured" && /* @__PURE__ */
|
|
1677
|
-
jiraState === "no_tickets" && /* @__PURE__ */
|
|
1678
|
-
jiraState === "has_tickets" && tickets.map((ticket, idx) => /* @__PURE__ */
|
|
1494
|
+
return /* @__PURE__ */ jsx10(TitledBox5, { borderStyle: "round", titles: [title], borderColor, flexShrink: 0, children: /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", paddingX: 1, children: [
|
|
1495
|
+
jiraState === "not_configured" && /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "No Jira site configured" }),
|
|
1496
|
+
jiraState === "no_tickets" && /* @__PURE__ */ jsx10(Text10, { dimColor: true, children: "No tickets linked to this branch" }),
|
|
1497
|
+
jiraState === "has_tickets" && tickets.map((ticket, idx) => /* @__PURE__ */ jsx10(
|
|
1679
1498
|
TicketItem,
|
|
1680
1499
|
{
|
|
1681
1500
|
ticketKey: ticket.key,
|
|
@@ -1689,8 +1508,8 @@ function JiraView({ isFocused, onModalChange, onKeybindingsChange }) {
|
|
|
1689
1508
|
}
|
|
1690
1509
|
|
|
1691
1510
|
// src/components/ui/KeybindingsBar.tsx
|
|
1692
|
-
import { Box as
|
|
1693
|
-
import { jsx as
|
|
1511
|
+
import { Box as Box11, Text as Text11 } from "ink";
|
|
1512
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1694
1513
|
var globalBindings = [
|
|
1695
1514
|
{ key: "1-4", label: "Focus" },
|
|
1696
1515
|
{ key: "j/k", label: "Navigate" },
|
|
@@ -1701,20 +1520,20 @@ var modalBindings = [
|
|
|
1701
1520
|
];
|
|
1702
1521
|
function KeybindingsBar({ contextBindings = [], modalOpen = false }) {
|
|
1703
1522
|
const allBindings = modalOpen ? [...contextBindings, ...modalBindings] : [...contextBindings, ...globalBindings];
|
|
1704
|
-
return /* @__PURE__ */
|
|
1705
|
-
/* @__PURE__ */
|
|
1706
|
-
/* @__PURE__ */
|
|
1523
|
+
return /* @__PURE__ */ jsx11(Box11, { flexShrink: 0, paddingX: 1, gap: 2, children: allBindings.map((binding) => /* @__PURE__ */ jsxs11(Box11, { gap: 1, children: [
|
|
1524
|
+
/* @__PURE__ */ jsx11(Text11, { bold: true, color: binding.color ?? "yellow", children: binding.key }),
|
|
1525
|
+
/* @__PURE__ */ jsx11(Text11, { dimColor: true, children: binding.label })
|
|
1707
1526
|
] }, binding.key)) });
|
|
1708
1527
|
}
|
|
1709
1528
|
|
|
1710
1529
|
// src/app.tsx
|
|
1711
|
-
import { jsx as
|
|
1530
|
+
import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1712
1531
|
function App() {
|
|
1713
1532
|
const { exit } = useApp();
|
|
1714
|
-
const [focusedView, setFocusedView] =
|
|
1715
|
-
const [modalOpen, setModalOpen] =
|
|
1716
|
-
const [contextBindings, setContextBindings] =
|
|
1717
|
-
|
|
1533
|
+
const [focusedView, setFocusedView] = useState8("github");
|
|
1534
|
+
const [modalOpen, setModalOpen] = useState8(false);
|
|
1535
|
+
const [contextBindings, setContextBindings] = useState8([]);
|
|
1536
|
+
useInput10(
|
|
1718
1537
|
(input, key) => {
|
|
1719
1538
|
if (key.ctrl && input === "c") {
|
|
1720
1539
|
exit();
|
|
@@ -1728,16 +1547,15 @@ function App() {
|
|
|
1728
1547
|
},
|
|
1729
1548
|
{ isActive: !modalOpen }
|
|
1730
1549
|
);
|
|
1731
|
-
return /* @__PURE__ */
|
|
1732
|
-
/* @__PURE__ */
|
|
1550
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexGrow: 1, flexDirection: "column", overflow: "hidden", children: [
|
|
1551
|
+
/* @__PURE__ */ jsx12(
|
|
1733
1552
|
GitHubView,
|
|
1734
1553
|
{
|
|
1735
1554
|
isFocused: focusedView === "github",
|
|
1736
|
-
onModalChange: setModalOpen,
|
|
1737
1555
|
onKeybindingsChange: focusedView === "github" ? setContextBindings : void 0
|
|
1738
1556
|
}
|
|
1739
1557
|
),
|
|
1740
|
-
/* @__PURE__ */
|
|
1558
|
+
/* @__PURE__ */ jsx12(
|
|
1741
1559
|
JiraView,
|
|
1742
1560
|
{
|
|
1743
1561
|
isFocused: focusedView === "jira",
|
|
@@ -1745,7 +1563,7 @@ function App() {
|
|
|
1745
1563
|
onKeybindingsChange: focusedView === "jira" ? setContextBindings : void 0
|
|
1746
1564
|
}
|
|
1747
1565
|
),
|
|
1748
|
-
/* @__PURE__ */
|
|
1566
|
+
/* @__PURE__ */ jsx12(KeybindingsBar, { contextBindings, modalOpen })
|
|
1749
1567
|
] });
|
|
1750
1568
|
}
|
|
1751
1569
|
|
|
@@ -1753,16 +1571,16 @@ function App() {
|
|
|
1753
1571
|
import { render as inkRender } from "ink";
|
|
1754
1572
|
|
|
1755
1573
|
// src/lib/Screen.tsx
|
|
1756
|
-
import { Box as
|
|
1757
|
-
import { useCallback as useCallback3, useEffect as useEffect6, useState as
|
|
1758
|
-
import { jsx as
|
|
1574
|
+
import { Box as Box13, useStdout } from "ink";
|
|
1575
|
+
import { useCallback as useCallback3, useEffect as useEffect6, useState as useState9 } from "react";
|
|
1576
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
1759
1577
|
function Screen({ children }) {
|
|
1760
1578
|
const { stdout } = useStdout();
|
|
1761
1579
|
const getSize = useCallback3(
|
|
1762
1580
|
() => ({ height: stdout.rows, width: stdout.columns }),
|
|
1763
1581
|
[stdout]
|
|
1764
1582
|
);
|
|
1765
|
-
const [size, setSize] =
|
|
1583
|
+
const [size, setSize] = useState9(getSize);
|
|
1766
1584
|
useEffect6(() => {
|
|
1767
1585
|
const onResize = () => setSize(getSize());
|
|
1768
1586
|
stdout.on("resize", onResize);
|
|
@@ -1770,17 +1588,17 @@ function Screen({ children }) {
|
|
|
1770
1588
|
stdout.off("resize", onResize);
|
|
1771
1589
|
};
|
|
1772
1590
|
}, [stdout, getSize]);
|
|
1773
|
-
return /* @__PURE__ */
|
|
1591
|
+
return /* @__PURE__ */ jsx13(Box13, { height: size.height, width: size.width, children });
|
|
1774
1592
|
}
|
|
1775
1593
|
|
|
1776
1594
|
// src/lib/render.tsx
|
|
1777
|
-
import { jsx as
|
|
1595
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
1778
1596
|
var ENTER_ALT_BUFFER = "\x1B[?1049h";
|
|
1779
1597
|
var EXIT_ALT_BUFFER = "\x1B[?1049l";
|
|
1780
1598
|
var CLEAR_SCREEN = "\x1B[2J\x1B[H";
|
|
1781
1599
|
function render(node, options) {
|
|
1782
1600
|
process.stdout.write(ENTER_ALT_BUFFER + CLEAR_SCREEN);
|
|
1783
|
-
const element = /* @__PURE__ */
|
|
1601
|
+
const element = /* @__PURE__ */ jsx14(Screen, { children: node });
|
|
1784
1602
|
const instance = inkRender(element, options);
|
|
1785
1603
|
setImmediate(() => instance.rerender(element));
|
|
1786
1604
|
const cleanup = () => process.stdout.write(EXIT_ALT_BUFFER);
|
|
@@ -1801,7 +1619,7 @@ function render(node, options) {
|
|
|
1801
1619
|
}
|
|
1802
1620
|
|
|
1803
1621
|
// src/cli.tsx
|
|
1804
|
-
import { jsx as
|
|
1622
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1805
1623
|
meow(
|
|
1806
1624
|
`
|
|
1807
1625
|
Usage
|
|
@@ -1823,4 +1641,4 @@ meow(
|
|
|
1823
1641
|
}
|
|
1824
1642
|
}
|
|
1825
1643
|
);
|
|
1826
|
-
render(/* @__PURE__ */
|
|
1644
|
+
render(/* @__PURE__ */ jsx15(App, {}));
|