next-ai-editor 1.0.2 → 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 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +50 -0
- package/dist/index.js +538 -20
- 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
|
@@ -1362,7 +1362,7 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
1362
1362
|
* This source code is licensed under the ISC license.
|
|
1363
1363
|
* See the LICENSE file in the root directory of this source tree.
|
|
1364
1364
|
*/
|
|
1365
|
-
const __iconNode$
|
|
1365
|
+
const __iconNode$a = [
|
|
1366
1366
|
[
|
|
1367
1367
|
"path",
|
|
1368
1368
|
{
|
|
@@ -1373,14 +1373,22 @@ const __iconNode$4 = [
|
|
|
1373
1373
|
["path", { d: "m3.3 7 8.7 5 8.7-5", key: "g66t2b" }],
|
|
1374
1374
|
["path", { d: "M12 22V12", key: "d0xqtd" }]
|
|
1375
1375
|
];
|
|
1376
|
-
const Box = createLucideIcon("box", __iconNode$
|
|
1376
|
+
const Box = createLucideIcon("box", __iconNode$a);
|
|
1377
1377
|
/**
|
|
1378
1378
|
* @license lucide-react v0.562.0 - ISC
|
|
1379
1379
|
*
|
|
1380
1380
|
* This source code is licensed under the ISC license.
|
|
1381
1381
|
* See the LICENSE file in the root directory of this source tree.
|
|
1382
1382
|
*/
|
|
1383
|
-
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 = [
|
|
1384
1392
|
[
|
|
1385
1393
|
"path",
|
|
1386
1394
|
{
|
|
@@ -1392,14 +1400,68 @@ const __iconNode$3 = [
|
|
|
1392
1400
|
["path", { d: "M10 12.5 8 15l2 2.5", key: "1tg20x" }],
|
|
1393
1401
|
["path", { d: "m14 12.5 2 2.5-2 2.5", key: "yinavb" }]
|
|
1394
1402
|
];
|
|
1395
|
-
const FileCode = createLucideIcon("file-code", __iconNode$
|
|
1403
|
+
const FileCode = createLucideIcon("file-code", __iconNode$8);
|
|
1396
1404
|
/**
|
|
1397
1405
|
* @license lucide-react v0.562.0 - ISC
|
|
1398
1406
|
*
|
|
1399
1407
|
* This source code is licensed under the ISC license.
|
|
1400
1408
|
* See the LICENSE file in the root directory of this source tree.
|
|
1401
1409
|
*/
|
|
1402
|
-
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 = [
|
|
1403
1465
|
[
|
|
1404
1466
|
"path",
|
|
1405
1467
|
{
|
|
@@ -1409,7 +1471,26 @@ const __iconNode$2 = [
|
|
|
1409
1471
|
],
|
|
1410
1472
|
["path", { d: "m15 5 4 4", key: "1mk7zo" }]
|
|
1411
1473
|
];
|
|
1412
|
-
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);
|
|
1413
1494
|
/**
|
|
1414
1495
|
* @license lucide-react v0.562.0 - ISC
|
|
1415
1496
|
*
|
|
@@ -1433,6 +1514,263 @@ const __iconNode = [
|
|
|
1433
1514
|
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
1434
1515
|
];
|
|
1435
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
|
+
}
|
|
1436
1774
|
function ChatPanel({
|
|
1437
1775
|
isExpanded,
|
|
1438
1776
|
onToggle,
|
|
@@ -1447,9 +1785,19 @@ function ChatPanel({
|
|
|
1447
1785
|
const textareaRef = useRef(null);
|
|
1448
1786
|
const [contextRanges, setContextRanges] = useState([]);
|
|
1449
1787
|
const [isMessagesCollapsed, setMessagesCollapsed] = useState(false);
|
|
1788
|
+
const [showPRBlock, setShowPRBlock] = useState(false);
|
|
1450
1789
|
const { messages, isStreaming, sendMessage, startedToolIds, completedToolIds, todos } = useChatStream({
|
|
1451
1790
|
threadId
|
|
1452
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]);
|
|
1453
1801
|
useEffect(() => {
|
|
1454
1802
|
if (attachedContext) {
|
|
1455
1803
|
setContextRanges((prev) => [...prev, {
|
|
@@ -1532,11 +1880,15 @@ function ChatPanel({
|
|
|
1532
1880
|
}
|
|
1533
1881
|
return count;
|
|
1534
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";
|
|
1535
1887
|
if (!isExpanded) {
|
|
1536
1888
|
return null;
|
|
1537
1889
|
}
|
|
1538
|
-
return /* @__PURE__ */ jsxs("div", { className: `chat-panel ai-editor-ui ${theme} ${commentMessages.length === 0 ? "empty" : ""}`, children: [
|
|
1539
|
-
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: [
|
|
1540
1892
|
/* @__PURE__ */ jsx("div", { className: "chat-panel-messages-header", children: /* @__PURE__ */ jsxs(
|
|
1541
1893
|
"div",
|
|
1542
1894
|
{
|
|
@@ -1552,18 +1904,21 @@ function ChatPanel({
|
|
|
1552
1904
|
]
|
|
1553
1905
|
}
|
|
1554
1906
|
) }),
|
|
1555
|
-
/* @__PURE__ */
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
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
|
+
] })
|
|
1565
1920
|
] }),
|
|
1566
|
-
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(
|
|
1567
1922
|
MessageList,
|
|
1568
1923
|
{
|
|
1569
1924
|
messages: [],
|
|
@@ -1640,6 +1995,16 @@ function ChatPanel({
|
|
|
1640
1995
|
title: "Select Text",
|
|
1641
1996
|
children: /* @__PURE__ */ jsx(Type, { size: 16 })
|
|
1642
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
|
+
}
|
|
1643
2008
|
)
|
|
1644
2009
|
] }),
|
|
1645
2010
|
/* @__PURE__ */ jsx(
|
|
@@ -2101,11 +2466,164 @@ function EditorOverlay({ theme, onComponentSelect }) {
|
|
|
2101
2466
|
}
|
|
2102
2467
|
);
|
|
2103
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
|
+
}
|
|
2104
2619
|
export {
|
|
2105
2620
|
AIEditorProvider,
|
|
2106
2621
|
ChatPanel,
|
|
2107
2622
|
ControlPill,
|
|
2623
|
+
PRView,
|
|
2108
2624
|
buildServiceUrl,
|
|
2109
|
-
getServiceUrl
|
|
2625
|
+
getServiceUrl,
|
|
2626
|
+
useCreatePR,
|
|
2627
|
+
usePRStatus
|
|
2110
2628
|
};
|
|
2111
2629
|
//# sourceMappingURL=index.js.map
|