next-ai-editor 1.0.1 → 1.1.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/README.md +174 -77
- package/dist/index.cjs +537 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +50 -0
- package/dist/index.js +538 -27
- package/dist/index.js.map +1 -1
- package/dist/next-ai-editor.css +707 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1006,13 +1006,6 @@ function MessageList({
|
|
|
1006
1006
|
] });
|
|
1007
1007
|
}
|
|
1008
1008
|
function getServiceUrl() {
|
|
1009
|
-
var _a, _b;
|
|
1010
|
-
if (typeof window !== "undefined" && ((_a = window.env) == null ? void 0 : _a.NEXT_PUBLIC_AI_EDITOR_SERVICE_URL)) {
|
|
1011
|
-
return window.env.NEXT_PUBLIC_AI_EDITOR_SERVICE_URL;
|
|
1012
|
-
}
|
|
1013
|
-
if (typeof process !== "undefined" && ((_b = process.env) == null ? void 0 : _b.NEXT_PUBLIC_AI_EDITOR_SERVICE_URL)) {
|
|
1014
|
-
return process.env.NEXT_PUBLIC_AI_EDITOR_SERVICE_URL;
|
|
1015
|
-
}
|
|
1016
1009
|
if (typeof window !== "undefined") {
|
|
1017
1010
|
const hostname = window.location.hostname;
|
|
1018
1011
|
if (hostname === "localhost" || hostname === "127.0.0.1") {
|
|
@@ -1369,7 +1362,7 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
1369
1362
|
* This source code is licensed under the ISC license.
|
|
1370
1363
|
* See the LICENSE file in the root directory of this source tree.
|
|
1371
1364
|
*/
|
|
1372
|
-
const __iconNode$
|
|
1365
|
+
const __iconNode$a = [
|
|
1373
1366
|
[
|
|
1374
1367
|
"path",
|
|
1375
1368
|
{
|
|
@@ -1380,14 +1373,22 @@ const __iconNode$4 = [
|
|
|
1380
1373
|
["path", { d: "m3.3 7 8.7 5 8.7-5", key: "g66t2b" }],
|
|
1381
1374
|
["path", { d: "M12 22V12", key: "d0xqtd" }]
|
|
1382
1375
|
];
|
|
1383
|
-
const Box = createLucideIcon("box", __iconNode$
|
|
1376
|
+
const Box = createLucideIcon("box", __iconNode$a);
|
|
1384
1377
|
/**
|
|
1385
1378
|
* @license lucide-react v0.562.0 - ISC
|
|
1386
1379
|
*
|
|
1387
1380
|
* This source code is licensed under the ISC license.
|
|
1388
1381
|
* See the LICENSE file in the root directory of this source tree.
|
|
1389
1382
|
*/
|
|
1390
|
-
const __iconNode$
|
|
1383
|
+
const __iconNode$9 = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
|
|
1384
|
+
const Check = createLucideIcon("check", __iconNode$9);
|
|
1385
|
+
/**
|
|
1386
|
+
* @license lucide-react v0.562.0 - ISC
|
|
1387
|
+
*
|
|
1388
|
+
* This source code is licensed under the ISC license.
|
|
1389
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1390
|
+
*/
|
|
1391
|
+
const __iconNode$8 = [
|
|
1391
1392
|
[
|
|
1392
1393
|
"path",
|
|
1393
1394
|
{
|
|
@@ -1399,14 +1400,68 @@ const __iconNode$3 = [
|
|
|
1399
1400
|
["path", { d: "M10 12.5 8 15l2 2.5", key: "1tg20x" }],
|
|
1400
1401
|
["path", { d: "m14 12.5 2 2.5-2 2.5", key: "yinavb" }]
|
|
1401
1402
|
];
|
|
1402
|
-
const FileCode = createLucideIcon("file-code", __iconNode$
|
|
1403
|
+
const FileCode = createLucideIcon("file-code", __iconNode$8);
|
|
1403
1404
|
/**
|
|
1404
1405
|
* @license lucide-react v0.562.0 - ISC
|
|
1405
1406
|
*
|
|
1406
1407
|
* This source code is licensed under the ISC license.
|
|
1407
1408
|
* See the LICENSE file in the root directory of this source tree.
|
|
1408
1409
|
*/
|
|
1409
|
-
const __iconNode$
|
|
1410
|
+
const __iconNode$7 = [
|
|
1411
|
+
[
|
|
1412
|
+
"path",
|
|
1413
|
+
{
|
|
1414
|
+
d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
|
|
1415
|
+
key: "1oefj6"
|
|
1416
|
+
}
|
|
1417
|
+
],
|
|
1418
|
+
["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }],
|
|
1419
|
+
["path", { d: "M10 9H8", key: "b1mrlr" }],
|
|
1420
|
+
["path", { d: "M16 13H8", key: "t4e002" }],
|
|
1421
|
+
["path", { d: "M16 17H8", key: "z1uh3a" }]
|
|
1422
|
+
];
|
|
1423
|
+
const FileText = createLucideIcon("file-text", __iconNode$7);
|
|
1424
|
+
/**
|
|
1425
|
+
* @license lucide-react v0.562.0 - ISC
|
|
1426
|
+
*
|
|
1427
|
+
* This source code is licensed under the ISC license.
|
|
1428
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1429
|
+
*/
|
|
1430
|
+
const __iconNode$6 = [
|
|
1431
|
+
["line", { x1: "6", x2: "6", y1: "3", y2: "15", key: "17qcm7" }],
|
|
1432
|
+
["circle", { cx: "18", cy: "6", r: "3", key: "1h7g24" }],
|
|
1433
|
+
["circle", { cx: "6", cy: "18", r: "3", key: "fqmcym" }],
|
|
1434
|
+
["path", { d: "M18 9a9 9 0 0 1-9 9", key: "n2h4wq" }]
|
|
1435
|
+
];
|
|
1436
|
+
const GitBranch = createLucideIcon("git-branch", __iconNode$6);
|
|
1437
|
+
/**
|
|
1438
|
+
* @license lucide-react v0.562.0 - ISC
|
|
1439
|
+
*
|
|
1440
|
+
* This source code is licensed under the ISC license.
|
|
1441
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1442
|
+
*/
|
|
1443
|
+
const __iconNode$5 = [
|
|
1444
|
+
["circle", { cx: "18", cy: "18", r: "3", key: "1xkwt0" }],
|
|
1445
|
+
["circle", { cx: "6", cy: "6", r: "3", key: "1lh9wr" }],
|
|
1446
|
+
["path", { d: "M13 6h3a2 2 0 0 1 2 2v7", key: "1yeb86" }],
|
|
1447
|
+
["line", { x1: "6", x2: "6", y1: "9", y2: "21", key: "rroup" }]
|
|
1448
|
+
];
|
|
1449
|
+
const GitPullRequest = createLucideIcon("git-pull-request", __iconNode$5);
|
|
1450
|
+
/**
|
|
1451
|
+
* @license lucide-react v0.562.0 - ISC
|
|
1452
|
+
*
|
|
1453
|
+
* This source code is licensed under the ISC license.
|
|
1454
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1455
|
+
*/
|
|
1456
|
+
const __iconNode$4 = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
|
|
1457
|
+
const LoaderCircle = createLucideIcon("loader-circle", __iconNode$4);
|
|
1458
|
+
/**
|
|
1459
|
+
* @license lucide-react v0.562.0 - ISC
|
|
1460
|
+
*
|
|
1461
|
+
* This source code is licensed under the ISC license.
|
|
1462
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1463
|
+
*/
|
|
1464
|
+
const __iconNode$3 = [
|
|
1410
1465
|
[
|
|
1411
1466
|
"path",
|
|
1412
1467
|
{
|
|
@@ -1416,7 +1471,26 @@ const __iconNode$2 = [
|
|
|
1416
1471
|
],
|
|
1417
1472
|
["path", { d: "m15 5 4 4", key: "1mk7zo" }]
|
|
1418
1473
|
];
|
|
1419
|
-
const Pencil = createLucideIcon("pencil", __iconNode$
|
|
1474
|
+
const Pencil = createLucideIcon("pencil", __iconNode$3);
|
|
1475
|
+
/**
|
|
1476
|
+
* @license lucide-react v0.562.0 - ISC
|
|
1477
|
+
*
|
|
1478
|
+
* This source code is licensed under the ISC license.
|
|
1479
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
1480
|
+
*/
|
|
1481
|
+
const __iconNode$2 = [
|
|
1482
|
+
[
|
|
1483
|
+
"path",
|
|
1484
|
+
{
|
|
1485
|
+
d: "M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",
|
|
1486
|
+
key: "1s2grr"
|
|
1487
|
+
}
|
|
1488
|
+
],
|
|
1489
|
+
["path", { d: "M20 2v4", key: "1rf3ol" }],
|
|
1490
|
+
["path", { d: "M22 4h-4", key: "gwowj6" }],
|
|
1491
|
+
["circle", { cx: "4", cy: "20", r: "2", key: "6kqj1y" }]
|
|
1492
|
+
];
|
|
1493
|
+
const Sparkles = createLucideIcon("sparkles", __iconNode$2);
|
|
1420
1494
|
/**
|
|
1421
1495
|
* @license lucide-react v0.562.0 - ISC
|
|
1422
1496
|
*
|
|
@@ -1440,6 +1514,263 @@ const __iconNode = [
|
|
|
1440
1514
|
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
1441
1515
|
];
|
|
1442
1516
|
const X = createLucideIcon("x", __iconNode);
|
|
1517
|
+
function usePRStatus() {
|
|
1518
|
+
const [status, setStatus] = useState(null);
|
|
1519
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
1520
|
+
const [error, setError] = useState(null);
|
|
1521
|
+
const fetchStatus = useCallback(async () => {
|
|
1522
|
+
try {
|
|
1523
|
+
setIsLoading(true);
|
|
1524
|
+
setError(null);
|
|
1525
|
+
const response = await fetch(buildServiceUrl("api/pr/status"));
|
|
1526
|
+
if (!response.ok) {
|
|
1527
|
+
throw new Error("Failed to fetch PR status");
|
|
1528
|
+
}
|
|
1529
|
+
const data = await response.json();
|
|
1530
|
+
setStatus(data);
|
|
1531
|
+
} catch (err) {
|
|
1532
|
+
setError(err instanceof Error ? err.message : "Unknown error");
|
|
1533
|
+
setStatus(null);
|
|
1534
|
+
} finally {
|
|
1535
|
+
setIsLoading(false);
|
|
1536
|
+
}
|
|
1537
|
+
}, []);
|
|
1538
|
+
useEffect(() => {
|
|
1539
|
+
fetchStatus();
|
|
1540
|
+
}, [fetchStatus]);
|
|
1541
|
+
return {
|
|
1542
|
+
status,
|
|
1543
|
+
isLoading,
|
|
1544
|
+
error,
|
|
1545
|
+
refresh: fetchStatus
|
|
1546
|
+
};
|
|
1547
|
+
}
|
|
1548
|
+
function useCreatePR() {
|
|
1549
|
+
const [isCreating, setIsCreating] = useState(false);
|
|
1550
|
+
const [isGenerating, setIsGenerating] = useState(false);
|
|
1551
|
+
const generateContent = useCallback(async () => {
|
|
1552
|
+
setIsGenerating(true);
|
|
1553
|
+
try {
|
|
1554
|
+
const response = await fetch(buildServiceUrl("api/pr/generate-description"), {
|
|
1555
|
+
method: "POST",
|
|
1556
|
+
headers: { "Content-Type": "application/json" },
|
|
1557
|
+
body: JSON.stringify({})
|
|
1558
|
+
});
|
|
1559
|
+
if (!response.ok) {
|
|
1560
|
+
throw new Error("Failed to generate PR content");
|
|
1561
|
+
}
|
|
1562
|
+
const data = await response.json();
|
|
1563
|
+
return {
|
|
1564
|
+
title: data.title || "",
|
|
1565
|
+
description: data.description || ""
|
|
1566
|
+
};
|
|
1567
|
+
} catch (err) {
|
|
1568
|
+
console.error("Error generating PR content:", err);
|
|
1569
|
+
return { title: "", description: "" };
|
|
1570
|
+
} finally {
|
|
1571
|
+
setIsGenerating(false);
|
|
1572
|
+
}
|
|
1573
|
+
}, []);
|
|
1574
|
+
const createPR = useCallback(async (input) => {
|
|
1575
|
+
setIsCreating(true);
|
|
1576
|
+
try {
|
|
1577
|
+
const response = await fetch(buildServiceUrl("api/pr/create"), {
|
|
1578
|
+
method: "POST",
|
|
1579
|
+
headers: { "Content-Type": "application/json" },
|
|
1580
|
+
body: JSON.stringify(input)
|
|
1581
|
+
});
|
|
1582
|
+
const data = await response.json();
|
|
1583
|
+
if (!response.ok) {
|
|
1584
|
+
return {
|
|
1585
|
+
success: false,
|
|
1586
|
+
error: data.error || "Failed to create PR",
|
|
1587
|
+
branchName: data.branchName,
|
|
1588
|
+
partialSuccess: data.partialSuccess
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
return {
|
|
1592
|
+
success: true,
|
|
1593
|
+
prUrl: data.prUrl,
|
|
1594
|
+
prNumber: data.prNumber,
|
|
1595
|
+
branchName: data.branchName
|
|
1596
|
+
};
|
|
1597
|
+
} catch (err) {
|
|
1598
|
+
return {
|
|
1599
|
+
success: false,
|
|
1600
|
+
error: err instanceof Error ? err.message : "Failed to create PR"
|
|
1601
|
+
};
|
|
1602
|
+
} finally {
|
|
1603
|
+
setIsCreating(false);
|
|
1604
|
+
}
|
|
1605
|
+
}, []);
|
|
1606
|
+
return {
|
|
1607
|
+
createPR,
|
|
1608
|
+
generateContent,
|
|
1609
|
+
isCreating,
|
|
1610
|
+
isGenerating
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
function PRBlock({ onCancel, onSuccess }) {
|
|
1614
|
+
const [title, setTitle] = useState("");
|
|
1615
|
+
const [description, setDescription] = useState("");
|
|
1616
|
+
const [error, setError] = useState(null);
|
|
1617
|
+
const [result, setResult] = useState(null);
|
|
1618
|
+
const [blockState, setBlockState] = useState("generating");
|
|
1619
|
+
const hasGenerated = useRef(false);
|
|
1620
|
+
const { status } = usePRStatus();
|
|
1621
|
+
const { createPR, generateContent, isGenerating } = useCreatePR();
|
|
1622
|
+
useEffect(() => {
|
|
1623
|
+
if (!hasGenerated.current) {
|
|
1624
|
+
hasGenerated.current = true;
|
|
1625
|
+
generateContent().then((content) => {
|
|
1626
|
+
setTitle(content.title);
|
|
1627
|
+
setDescription(content.description);
|
|
1628
|
+
setBlockState("form");
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
}, [generateContent]);
|
|
1632
|
+
const handleRegenerate = useCallback(async () => {
|
|
1633
|
+
setError(null);
|
|
1634
|
+
const content = await generateContent();
|
|
1635
|
+
setTitle(content.title);
|
|
1636
|
+
setDescription(content.description);
|
|
1637
|
+
}, [generateContent]);
|
|
1638
|
+
const handleSubmit = useCallback(async () => {
|
|
1639
|
+
if (!title.trim()) {
|
|
1640
|
+
setError("Title is required");
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
setError(null);
|
|
1644
|
+
setBlockState("creating");
|
|
1645
|
+
const prResult = await createPR({ title: title.trim(), description });
|
|
1646
|
+
if (prResult.success) {
|
|
1647
|
+
setResult(prResult);
|
|
1648
|
+
setBlockState("success");
|
|
1649
|
+
onSuccess == null ? void 0 : onSuccess(prResult);
|
|
1650
|
+
} else {
|
|
1651
|
+
setError(prResult.error || "Failed to create PR");
|
|
1652
|
+
setBlockState("form");
|
|
1653
|
+
}
|
|
1654
|
+
}, [title, description, createPR, onSuccess]);
|
|
1655
|
+
if (blockState === "success" && result) {
|
|
1656
|
+
return /* @__PURE__ */ jsx("div", { className: "pr-block pr-block-success", children: /* @__PURE__ */ jsxs("div", { className: "pr-block-success-content", children: [
|
|
1657
|
+
/* @__PURE__ */ jsx("div", { className: "pr-block-success-icon", children: /* @__PURE__ */ jsx(Check, { size: 16 }) }),
|
|
1658
|
+
/* @__PURE__ */ jsxs("div", { className: "pr-block-success-text", children: [
|
|
1659
|
+
/* @__PURE__ */ jsx("span", { className: "pr-block-success-title", children: "PR Created" }),
|
|
1660
|
+
/* @__PURE__ */ jsxs(
|
|
1661
|
+
"a",
|
|
1662
|
+
{
|
|
1663
|
+
href: result.prUrl,
|
|
1664
|
+
target: "_blank",
|
|
1665
|
+
rel: "noopener noreferrer",
|
|
1666
|
+
className: "pr-block-success-link",
|
|
1667
|
+
children: [
|
|
1668
|
+
"#",
|
|
1669
|
+
result.prNumber
|
|
1670
|
+
]
|
|
1671
|
+
}
|
|
1672
|
+
),
|
|
1673
|
+
/* @__PURE__ */ jsxs("span", { className: "pr-block-success-branch", children: [
|
|
1674
|
+
"on ",
|
|
1675
|
+
/* @__PURE__ */ jsx("code", { children: result.branchName })
|
|
1676
|
+
] })
|
|
1677
|
+
] })
|
|
1678
|
+
] }) });
|
|
1679
|
+
}
|
|
1680
|
+
if (blockState === "generating") {
|
|
1681
|
+
return /* @__PURE__ */ jsx("div", { className: "pr-block pr-block-generating", children: /* @__PURE__ */ jsxs("div", { className: "pr-block-loading", children: [
|
|
1682
|
+
/* @__PURE__ */ jsx(LoaderCircle, { size: 16, className: "pr-block-spinner" }),
|
|
1683
|
+
/* @__PURE__ */ jsx("span", { children: "Generating PR details..." })
|
|
1684
|
+
] }) });
|
|
1685
|
+
}
|
|
1686
|
+
const isDisabled = blockState === "creating" || isGenerating;
|
|
1687
|
+
return /* @__PURE__ */ jsxs("div", { className: "pr-block", children: [
|
|
1688
|
+
/* @__PURE__ */ jsxs("div", { className: "pr-block-header", children: [
|
|
1689
|
+
/* @__PURE__ */ jsx("span", { className: "pr-block-title", children: "Create Pull Request" }),
|
|
1690
|
+
/* @__PURE__ */ jsx(
|
|
1691
|
+
"button",
|
|
1692
|
+
{
|
|
1693
|
+
className: "pr-block-cancel",
|
|
1694
|
+
onClick: onCancel,
|
|
1695
|
+
disabled: blockState === "creating",
|
|
1696
|
+
title: "Cancel",
|
|
1697
|
+
children: /* @__PURE__ */ jsx(X, { size: 14 })
|
|
1698
|
+
}
|
|
1699
|
+
)
|
|
1700
|
+
] }),
|
|
1701
|
+
/* @__PURE__ */ jsxs("div", { className: "pr-block-content", children: [
|
|
1702
|
+
error && /* @__PURE__ */ jsx("div", { className: "pr-block-error", children: error }),
|
|
1703
|
+
/* @__PURE__ */ jsxs("div", { className: "pr-block-field", children: [
|
|
1704
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "pr-block-title", children: "Title" }),
|
|
1705
|
+
/* @__PURE__ */ jsx(
|
|
1706
|
+
"input",
|
|
1707
|
+
{
|
|
1708
|
+
id: "pr-block-title",
|
|
1709
|
+
type: "text",
|
|
1710
|
+
value: title,
|
|
1711
|
+
onChange: (e) => setTitle(e.target.value),
|
|
1712
|
+
placeholder: "PR title...",
|
|
1713
|
+
disabled: isDisabled
|
|
1714
|
+
}
|
|
1715
|
+
)
|
|
1716
|
+
] }),
|
|
1717
|
+
/* @__PURE__ */ jsxs("div", { className: "pr-block-field", children: [
|
|
1718
|
+
/* @__PURE__ */ jsxs("div", { className: "pr-block-field-header", children: [
|
|
1719
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "pr-block-description", children: "Description" }),
|
|
1720
|
+
/* @__PURE__ */ jsxs(
|
|
1721
|
+
"button",
|
|
1722
|
+
{
|
|
1723
|
+
className: "pr-block-regenerate",
|
|
1724
|
+
onClick: handleRegenerate,
|
|
1725
|
+
disabled: isDisabled,
|
|
1726
|
+
children: [
|
|
1727
|
+
isGenerating ? /* @__PURE__ */ jsx(LoaderCircle, { size: 12, className: "pr-block-spinner" }) : /* @__PURE__ */ jsx(Sparkles, { size: 12 }),
|
|
1728
|
+
"Regen"
|
|
1729
|
+
]
|
|
1730
|
+
}
|
|
1731
|
+
)
|
|
1732
|
+
] }),
|
|
1733
|
+
/* @__PURE__ */ jsx(
|
|
1734
|
+
"textarea",
|
|
1735
|
+
{
|
|
1736
|
+
id: "pr-block-description",
|
|
1737
|
+
value: description,
|
|
1738
|
+
onChange: (e) => setDescription(e.target.value),
|
|
1739
|
+
placeholder: "Describe your changes...",
|
|
1740
|
+
disabled: isDisabled,
|
|
1741
|
+
rows: 3
|
|
1742
|
+
}
|
|
1743
|
+
)
|
|
1744
|
+
] }),
|
|
1745
|
+
status && /* @__PURE__ */ jsxs("div", { className: "pr-block-info", children: [
|
|
1746
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1747
|
+
/* @__PURE__ */ jsx(FileText, { size: 12 }),
|
|
1748
|
+
status.changedFiles.length,
|
|
1749
|
+
" files"
|
|
1750
|
+
] }),
|
|
1751
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
1752
|
+
/* @__PURE__ */ jsx(GitBranch, { size: 12 }),
|
|
1753
|
+
status.baseBranch
|
|
1754
|
+
] })
|
|
1755
|
+
] })
|
|
1756
|
+
] }),
|
|
1757
|
+
/* @__PURE__ */ jsx("div", { className: "pr-block-footer", children: /* @__PURE__ */ jsx(
|
|
1758
|
+
"button",
|
|
1759
|
+
{
|
|
1760
|
+
className: "pr-block-submit",
|
|
1761
|
+
onClick: handleSubmit,
|
|
1762
|
+
disabled: isDisabled || !title.trim(),
|
|
1763
|
+
children: blockState === "creating" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1764
|
+
/* @__PURE__ */ jsx(LoaderCircle, { size: 14, className: "pr-block-spinner" }),
|
|
1765
|
+
"Creating..."
|
|
1766
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1767
|
+
/* @__PURE__ */ jsx(GitPullRequest, { size: 14 }),
|
|
1768
|
+
"Create PR"
|
|
1769
|
+
] })
|
|
1770
|
+
}
|
|
1771
|
+
) })
|
|
1772
|
+
] });
|
|
1773
|
+
}
|
|
1443
1774
|
function ChatPanel({
|
|
1444
1775
|
isExpanded,
|
|
1445
1776
|
onToggle,
|
|
@@ -1454,9 +1785,19 @@ function ChatPanel({
|
|
|
1454
1785
|
const textareaRef = useRef(null);
|
|
1455
1786
|
const [contextRanges, setContextRanges] = useState([]);
|
|
1456
1787
|
const [isMessagesCollapsed, setMessagesCollapsed] = useState(false);
|
|
1788
|
+
const [showPRBlock, setShowPRBlock] = useState(false);
|
|
1457
1789
|
const { messages, isStreaming, sendMessage, startedToolIds, completedToolIds, todos } = useChatStream({
|
|
1458
1790
|
threadId
|
|
1459
1791
|
});
|
|
1792
|
+
const { status: prStatus, isLoading: prLoading, refresh: refreshPRStatus } = usePRStatus();
|
|
1793
|
+
const hasChanges = (prStatus == null ? void 0 : prStatus.hasChanges) ?? false;
|
|
1794
|
+
const prevIsStreaming = useRef(isStreaming);
|
|
1795
|
+
useEffect(() => {
|
|
1796
|
+
if (prevIsStreaming.current && !isStreaming) {
|
|
1797
|
+
refreshPRStatus();
|
|
1798
|
+
}
|
|
1799
|
+
prevIsStreaming.current = isStreaming;
|
|
1800
|
+
}, [isStreaming, refreshPRStatus]);
|
|
1460
1801
|
useEffect(() => {
|
|
1461
1802
|
if (attachedContext) {
|
|
1462
1803
|
setContextRanges((prev) => [...prev, {
|
|
@@ -1539,11 +1880,15 @@ function ChatPanel({
|
|
|
1539
1880
|
}
|
|
1540
1881
|
return count;
|
|
1541
1882
|
}, [commentMessages]);
|
|
1883
|
+
const handlePRCancel = useCallback(() => {
|
|
1884
|
+
setShowPRBlock(false);
|
|
1885
|
+
}, []);
|
|
1886
|
+
const prButtonTitle = prLoading ? "Checking for changes..." : hasChanges ? `Create PR (${prStatus == null ? void 0 : prStatus.changedFiles.length} files)` : "No changes to commit";
|
|
1542
1887
|
if (!isExpanded) {
|
|
1543
1888
|
return null;
|
|
1544
1889
|
}
|
|
1545
|
-
return /* @__PURE__ */ jsxs("div", { className: `chat-panel ai-editor-ui ${theme} ${commentMessages.length === 0 ? "empty" : ""}`, children: [
|
|
1546
|
-
commentMessages.length > 0 && /* @__PURE__ */ jsxs("div", { className: `chat-panel-messages-container ${isMessagesCollapsed ? "collapsed" : "expanded"}`, children: [
|
|
1890
|
+
return /* @__PURE__ */ jsxs("div", { className: `chat-panel ai-editor-ui ${theme} ${commentMessages.length === 0 && !showPRBlock ? "empty" : ""}`, children: [
|
|
1891
|
+
(commentMessages.length > 0 || showPRBlock) && /* @__PURE__ */ jsxs("div", { className: `chat-panel-messages-container ${isMessagesCollapsed ? "collapsed" : "expanded"}`, children: [
|
|
1547
1892
|
/* @__PURE__ */ jsx("div", { className: "chat-panel-messages-header", children: /* @__PURE__ */ jsxs(
|
|
1548
1893
|
"div",
|
|
1549
1894
|
{
|
|
@@ -1559,18 +1904,21 @@ function ChatPanel({
|
|
|
1559
1904
|
]
|
|
1560
1905
|
}
|
|
1561
1906
|
) }),
|
|
1562
|
-
/* @__PURE__ */
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1907
|
+
/* @__PURE__ */ jsxs("div", { className: "chat-panel-messages", children: [
|
|
1908
|
+
/* @__PURE__ */ jsx(
|
|
1909
|
+
MessageList,
|
|
1910
|
+
{
|
|
1911
|
+
messages: commentMessages,
|
|
1912
|
+
isStreaming,
|
|
1913
|
+
startedToolIds,
|
|
1914
|
+
completedToolIds,
|
|
1915
|
+
todos
|
|
1916
|
+
}
|
|
1917
|
+
),
|
|
1918
|
+
showPRBlock && /* @__PURE__ */ jsx(PRBlock, { onCancel: handlePRCancel })
|
|
1919
|
+
] })
|
|
1572
1920
|
] }),
|
|
1573
|
-
commentMessages.length === 0 && /* @__PURE__ */ jsx("div", { className: "chat-panel-empty-content", children: /* @__PURE__ */ jsx(
|
|
1921
|
+
commentMessages.length === 0 && !showPRBlock && /* @__PURE__ */ jsx("div", { className: "chat-panel-empty-content", children: /* @__PURE__ */ jsx(
|
|
1574
1922
|
MessageList,
|
|
1575
1923
|
{
|
|
1576
1924
|
messages: [],
|
|
@@ -1647,6 +1995,16 @@ function ChatPanel({
|
|
|
1647
1995
|
title: "Select Text",
|
|
1648
1996
|
children: /* @__PURE__ */ jsx(Type, { size: 16 })
|
|
1649
1997
|
}
|
|
1998
|
+
),
|
|
1999
|
+
/* @__PURE__ */ jsx(
|
|
2000
|
+
"button",
|
|
2001
|
+
{
|
|
2002
|
+
className: `tool-button ${showPRBlock ? "active" : ""}`,
|
|
2003
|
+
onClick: () => setShowPRBlock(!showPRBlock),
|
|
2004
|
+
disabled: !hasChanges || prLoading,
|
|
2005
|
+
title: prButtonTitle,
|
|
2006
|
+
children: /* @__PURE__ */ jsx(GitPullRequest, { size: 16 })
|
|
2007
|
+
}
|
|
1650
2008
|
)
|
|
1651
2009
|
] }),
|
|
1652
2010
|
/* @__PURE__ */ jsx(
|
|
@@ -2108,11 +2466,164 @@ function EditorOverlay({ theme, onComponentSelect }) {
|
|
|
2108
2466
|
}
|
|
2109
2467
|
);
|
|
2110
2468
|
}
|
|
2469
|
+
function PRView({ onClose, onSuccess }) {
|
|
2470
|
+
const [title, setTitle] = useState("");
|
|
2471
|
+
const [description, setDescription] = useState("");
|
|
2472
|
+
const [error, setError] = useState(null);
|
|
2473
|
+
const [result, setResult] = useState(null);
|
|
2474
|
+
const hasGenerated = useRef(false);
|
|
2475
|
+
const { status } = usePRStatus();
|
|
2476
|
+
const { createPR, generateContent, isCreating, isGenerating } = useCreatePR();
|
|
2477
|
+
useEffect(() => {
|
|
2478
|
+
if (!hasGenerated.current && !isGenerating) {
|
|
2479
|
+
hasGenerated.current = true;
|
|
2480
|
+
generateContent().then((content) => {
|
|
2481
|
+
setTitle(content.title);
|
|
2482
|
+
setDescription(content.description);
|
|
2483
|
+
});
|
|
2484
|
+
}
|
|
2485
|
+
}, [isGenerating, generateContent]);
|
|
2486
|
+
useEffect(() => {
|
|
2487
|
+
if (result == null ? void 0 : result.success) {
|
|
2488
|
+
const timer = setTimeout(() => {
|
|
2489
|
+
onClose();
|
|
2490
|
+
}, 2e3);
|
|
2491
|
+
return () => clearTimeout(timer);
|
|
2492
|
+
}
|
|
2493
|
+
}, [result == null ? void 0 : result.success, onClose]);
|
|
2494
|
+
const handleRegenerate = useCallback(async () => {
|
|
2495
|
+
setError(null);
|
|
2496
|
+
const content = await generateContent();
|
|
2497
|
+
setTitle(content.title);
|
|
2498
|
+
setDescription(content.description);
|
|
2499
|
+
}, [generateContent]);
|
|
2500
|
+
const handleSubmit = useCallback(async () => {
|
|
2501
|
+
if (!title.trim()) {
|
|
2502
|
+
setError("Title is required");
|
|
2503
|
+
return;
|
|
2504
|
+
}
|
|
2505
|
+
setError(null);
|
|
2506
|
+
const prResult = await createPR({ title: title.trim(), description });
|
|
2507
|
+
if (prResult.success) {
|
|
2508
|
+
setResult(prResult);
|
|
2509
|
+
onSuccess == null ? void 0 : onSuccess(prResult);
|
|
2510
|
+
} else {
|
|
2511
|
+
setError(prResult.error || "Failed to create PR");
|
|
2512
|
+
}
|
|
2513
|
+
}, [title, description, createPR, onSuccess]);
|
|
2514
|
+
if (result == null ? void 0 : result.success) {
|
|
2515
|
+
return /* @__PURE__ */ jsx("div", { className: "pr-view", children: /* @__PURE__ */ jsxs("div", { className: "pr-view-success", children: [
|
|
2516
|
+
/* @__PURE__ */ jsx("div", { className: "pr-view-success-icon", children: /* @__PURE__ */ jsx(Check, { size: 32 }) }),
|
|
2517
|
+
/* @__PURE__ */ jsx("h3", { children: "PR Created!" }),
|
|
2518
|
+
/* @__PURE__ */ jsxs("p", { children: [
|
|
2519
|
+
/* @__PURE__ */ jsxs("a", { href: result.prUrl, target: "_blank", rel: "noopener noreferrer", children: [
|
|
2520
|
+
"#",
|
|
2521
|
+
result.prNumber
|
|
2522
|
+
] }),
|
|
2523
|
+
" ",
|
|
2524
|
+
"on ",
|
|
2525
|
+
/* @__PURE__ */ jsx("code", { children: result.branchName })
|
|
2526
|
+
] })
|
|
2527
|
+
] }) });
|
|
2528
|
+
}
|
|
2529
|
+
if (isGenerating && !title) {
|
|
2530
|
+
return /* @__PURE__ */ jsx("div", { className: "pr-view", children: /* @__PURE__ */ jsxs("div", { className: "pr-view-loading", children: [
|
|
2531
|
+
/* @__PURE__ */ jsx(LoaderCircle, { size: 24, className: "pr-view-spinner" }),
|
|
2532
|
+
/* @__PURE__ */ jsx("p", { children: "Generating PR details..." })
|
|
2533
|
+
] }) });
|
|
2534
|
+
}
|
|
2535
|
+
return /* @__PURE__ */ jsxs("div", { className: "pr-view", children: [
|
|
2536
|
+
/* @__PURE__ */ jsxs("div", { className: "pr-view-content", children: [
|
|
2537
|
+
error && /* @__PURE__ */ jsx("div", { className: "pr-view-error", children: error }),
|
|
2538
|
+
/* @__PURE__ */ jsxs("div", { className: "pr-view-field", children: [
|
|
2539
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "pr-title", children: "Title" }),
|
|
2540
|
+
/* @__PURE__ */ jsx(
|
|
2541
|
+
"input",
|
|
2542
|
+
{
|
|
2543
|
+
id: "pr-title",
|
|
2544
|
+
type: "text",
|
|
2545
|
+
value: title,
|
|
2546
|
+
onChange: (e) => setTitle(e.target.value),
|
|
2547
|
+
placeholder: "PR title...",
|
|
2548
|
+
disabled: isCreating || isGenerating
|
|
2549
|
+
}
|
|
2550
|
+
)
|
|
2551
|
+
] }),
|
|
2552
|
+
/* @__PURE__ */ jsxs("div", { className: "pr-view-field", children: [
|
|
2553
|
+
/* @__PURE__ */ jsxs("div", { className: "pr-view-field-header", children: [
|
|
2554
|
+
/* @__PURE__ */ jsx("label", { htmlFor: "pr-description", children: "Description" }),
|
|
2555
|
+
/* @__PURE__ */ jsxs(
|
|
2556
|
+
"button",
|
|
2557
|
+
{
|
|
2558
|
+
className: "pr-view-regenerate",
|
|
2559
|
+
onClick: handleRegenerate,
|
|
2560
|
+
disabled: isGenerating || isCreating,
|
|
2561
|
+
children: [
|
|
2562
|
+
isGenerating ? /* @__PURE__ */ jsx(LoaderCircle, { size: 12, className: "pr-view-spinner" }) : /* @__PURE__ */ jsx(Sparkles, { size: 12 }),
|
|
2563
|
+
"Regenerate"
|
|
2564
|
+
]
|
|
2565
|
+
}
|
|
2566
|
+
)
|
|
2567
|
+
] }),
|
|
2568
|
+
/* @__PURE__ */ jsx(
|
|
2569
|
+
"textarea",
|
|
2570
|
+
{
|
|
2571
|
+
id: "pr-description",
|
|
2572
|
+
value: description,
|
|
2573
|
+
onChange: (e) => setDescription(e.target.value),
|
|
2574
|
+
placeholder: "Describe your changes...",
|
|
2575
|
+
disabled: isCreating || isGenerating
|
|
2576
|
+
}
|
|
2577
|
+
)
|
|
2578
|
+
] }),
|
|
2579
|
+
status && /* @__PURE__ */ jsxs("div", { className: "pr-view-info", children: [
|
|
2580
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2581
|
+
/* @__PURE__ */ jsx(FileText, { size: 12 }),
|
|
2582
|
+
status.changedFiles.length,
|
|
2583
|
+
" files"
|
|
2584
|
+
] }),
|
|
2585
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2586
|
+
/* @__PURE__ */ jsx(GitBranch, { size: 12 }),
|
|
2587
|
+
status.baseBranch
|
|
2588
|
+
] })
|
|
2589
|
+
] })
|
|
2590
|
+
] }),
|
|
2591
|
+
/* @__PURE__ */ jsxs("div", { className: "pr-view-footer", children: [
|
|
2592
|
+
/* @__PURE__ */ jsx(
|
|
2593
|
+
"button",
|
|
2594
|
+
{
|
|
2595
|
+
className: "pr-view-btn pr-view-btn-secondary",
|
|
2596
|
+
onClick: onClose,
|
|
2597
|
+
disabled: isCreating,
|
|
2598
|
+
children: "Cancel"
|
|
2599
|
+
}
|
|
2600
|
+
),
|
|
2601
|
+
/* @__PURE__ */ jsx(
|
|
2602
|
+
"button",
|
|
2603
|
+
{
|
|
2604
|
+
className: "pr-view-btn pr-view-btn-primary",
|
|
2605
|
+
onClick: handleSubmit,
|
|
2606
|
+
disabled: isCreating || !title.trim(),
|
|
2607
|
+
children: isCreating ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2608
|
+
/* @__PURE__ */ jsx(LoaderCircle, { size: 14, className: "pr-view-spinner" }),
|
|
2609
|
+
"Creating..."
|
|
2610
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2611
|
+
/* @__PURE__ */ jsx(GitPullRequest, { size: 14 }),
|
|
2612
|
+
"Create PR"
|
|
2613
|
+
] })
|
|
2614
|
+
}
|
|
2615
|
+
)
|
|
2616
|
+
] })
|
|
2617
|
+
] });
|
|
2618
|
+
}
|
|
2111
2619
|
export {
|
|
2112
2620
|
AIEditorProvider,
|
|
2113
2621
|
ChatPanel,
|
|
2114
2622
|
ControlPill,
|
|
2623
|
+
PRView,
|
|
2115
2624
|
buildServiceUrl,
|
|
2116
|
-
getServiceUrl
|
|
2625
|
+
getServiceUrl,
|
|
2626
|
+
useCreatePR,
|
|
2627
|
+
usePRStatus
|
|
2117
2628
|
};
|
|
2118
2629
|
//# sourceMappingURL=index.js.map
|