cicy-desktop 2.1.95 → 2.1.96
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/package.json +6 -6
- package/src/backends/homepage-preload.js +2 -0
- package/src/backends/homepage-react/assets/index-BtVG2Py6.js +365 -0
- package/src/backends/homepage-react/index.html +1 -1
- package/src/backends/sidecar-ipc.js +79 -20
- package/src/i18n/locales/en.json +32 -0
- package/src/i18n/locales/fr.json +32 -0
- package/src/i18n/locales/ja.json +32 -0
- package/src/i18n/locales/zh-CN.json +32 -0
- package/src/sidecar/docker.js +83 -19
- package/workers/render/src/App.jsx +108 -8
- package/src/backends/homepage-react/assets/index-C7gQsfPP.js +0 -365
|
@@ -1537,7 +1537,12 @@ function DockerInstallDrawerHost() {
|
|
|
1537
1537
|
// Desktop and runs it (主人指令), streaming progress through the drawer above.
|
|
1538
1538
|
function DockerCard({ dockerTeam, onOpen, onRefresh }) {
|
|
1539
1539
|
const [status, setStatus] = useState(null);
|
|
1540
|
-
const [busy, setBusy] = useState(
|
|
1540
|
+
const [busy, setBusy] = useState(""); // "" | bootstrap | restart | stop | upgrade
|
|
1541
|
+
const [menuOpen, setMenuOpen] = useState(false);
|
|
1542
|
+
const [menuPos, setMenuPos] = useState({ top: 0, left: 0 });
|
|
1543
|
+
const kebabRef = useRef(null);
|
|
1544
|
+
const menuRef = useRef(null);
|
|
1545
|
+
const MENU_W = 184;
|
|
1541
1546
|
const DOCKER_BLUE = "#2496ed";
|
|
1542
1547
|
|
|
1543
1548
|
const checkStatus = useCallback(async () => {
|
|
@@ -1547,8 +1552,31 @@ function DockerCard({ dockerTeam, onOpen, onRefresh }) {
|
|
|
1547
1552
|
|
|
1548
1553
|
useEffect(() => { checkStatus(); }, [checkStatus]);
|
|
1549
1554
|
|
|
1555
|
+
// Close the ⋯ menu on outside-click / Esc (mirrors LocalTeamCard).
|
|
1556
|
+
useEffect(() => {
|
|
1557
|
+
if (!menuOpen) return;
|
|
1558
|
+
const onDoc = (e) => {
|
|
1559
|
+
if (kebabRef.current?.contains(e.target) || menuRef.current?.contains(e.target)) return;
|
|
1560
|
+
setMenuOpen(false);
|
|
1561
|
+
};
|
|
1562
|
+
const onKey = (e) => { if (e.key === "Escape") setMenuOpen(false); };
|
|
1563
|
+
document.addEventListener("mousedown", onDoc);
|
|
1564
|
+
document.addEventListener("keydown", onKey);
|
|
1565
|
+
return () => { document.removeEventListener("mousedown", onDoc); document.removeEventListener("keydown", onKey); };
|
|
1566
|
+
}, [menuOpen]);
|
|
1567
|
+
|
|
1568
|
+
const toggleMenu = () => {
|
|
1569
|
+
if (!menuOpen && kebabRef.current) {
|
|
1570
|
+
const r = kebabRef.current.getBoundingClientRect();
|
|
1571
|
+
const left = Math.max(8, Math.min(r.right - MENU_W, window.innerWidth - MENU_W - 8));
|
|
1572
|
+
setMenuPos({ top: Math.round(r.bottom + 4), left: Math.round(left) });
|
|
1573
|
+
}
|
|
1574
|
+
setMenuOpen((v) => !v);
|
|
1575
|
+
};
|
|
1576
|
+
|
|
1577
|
+
// Install / start: streams through the drawer modal (logs + progress + retry).
|
|
1550
1578
|
const runBootstrap = useCallback(async () => {
|
|
1551
|
-
setBusy(
|
|
1579
|
+
setBusy("bootstrap");
|
|
1552
1580
|
dockerDrawer.open({ onRetry: runBootstrap });
|
|
1553
1581
|
const unsub = window.cicy?.docker?.onAppProgress?.((ev) => dockerDrawer.push(ev));
|
|
1554
1582
|
try {
|
|
@@ -1559,11 +1587,41 @@ function DockerCard({ dockerTeam, onOpen, onRefresh }) {
|
|
|
1559
1587
|
dockerDrawer.finish({ ok: false, message: e.message });
|
|
1560
1588
|
} finally {
|
|
1561
1589
|
try { unsub && unsub(); } catch {}
|
|
1562
|
-
setBusy(
|
|
1563
|
-
|
|
1590
|
+
setBusy(""); checkStatus();
|
|
1591
|
+
}
|
|
1592
|
+
}, [checkStatus, onRefresh]);
|
|
1593
|
+
|
|
1594
|
+
// Upgrade: re-pull the R2 image + recreate the container — also through the
|
|
1595
|
+
// drawer so the user sees the pull/import/restart log (主人: 升级要能看日志).
|
|
1596
|
+
const runUpgrade = useCallback(async () => {
|
|
1597
|
+
setMenuOpen(false); setBusy("upgrade");
|
|
1598
|
+
dockerDrawer.open({ onRetry: runUpgrade });
|
|
1599
|
+
const unsub = window.cicy?.docker?.onAppProgress?.((ev) => dockerDrawer.push(ev));
|
|
1600
|
+
try {
|
|
1601
|
+
const r = await window.cicy?.docker?.appUpgrade?.();
|
|
1602
|
+
dockerDrawer.finish({ ok: !!r?.ok, message: r?.ok ? tr("docker.upgraded", "已升级到最新") : (r?.error || tr("docker.upgradeFailed", "升级失败")) });
|
|
1603
|
+
if (r?.ok) onRefresh?.();
|
|
1604
|
+
} catch (e) {
|
|
1605
|
+
dockerDrawer.finish({ ok: false, message: e.message });
|
|
1606
|
+
} finally {
|
|
1607
|
+
try { unsub && unsub(); } catch {}
|
|
1608
|
+
setBusy(""); checkStatus();
|
|
1564
1609
|
}
|
|
1565
1610
|
}, [checkStatus, onRefresh]);
|
|
1566
1611
|
|
|
1612
|
+
// Restart / stop: quick lifecycle ops with a toast (no full drawer needed).
|
|
1613
|
+
const runOp = useCallback(async (op, fn, okMsg) => {
|
|
1614
|
+
setMenuOpen(false); setBusy(op);
|
|
1615
|
+
toast.show({ id: "docker-op", message: tr(`docker.${op}ing`, op === "restart" ? "重启中…" : "停止中…"), status: "running" });
|
|
1616
|
+
try {
|
|
1617
|
+
const r = await fn();
|
|
1618
|
+
if (r?.ok) toast.show({ id: "docker-op", message: okMsg, status: "done", ttl: 2500 });
|
|
1619
|
+
else toast.show({ id: "docker-op", message: (r?.error || tr("docker.opFailed", "操作失败")), status: "error", ttl: 6000 });
|
|
1620
|
+
} catch (e) {
|
|
1621
|
+
toast.show({ id: "docker-op", message: e.message, status: "error", ttl: 6000 });
|
|
1622
|
+
} finally { setBusy(""); checkStatus(); }
|
|
1623
|
+
}, [checkStatus]);
|
|
1624
|
+
|
|
1567
1625
|
// Render only on Windows. window.cicy.platform is sync, so we can decide
|
|
1568
1626
|
// immediately without waiting on the async appStatus probe.
|
|
1569
1627
|
const platform = window.cicy?.platform || status?.platform;
|
|
@@ -1572,13 +1630,14 @@ function DockerCard({ dockerTeam, onOpen, onRefresh }) {
|
|
|
1572
1630
|
const running = !!status?.running || dockerTeam?.status === "running";
|
|
1573
1631
|
const installed = !!status?.installed;
|
|
1574
1632
|
const tone = running ? "ok" : installed ? "warn" : "off";
|
|
1633
|
+
const isBusy = !!busy;
|
|
1575
1634
|
const stateText = running
|
|
1576
1635
|
? tr("docker.running", "运行中 · :8009")
|
|
1577
1636
|
: installed
|
|
1578
1637
|
? tr("docker.notRunning", "未启动 · 点「启动」")
|
|
1579
1638
|
: tr("docker.notInstalled", "Docker Desktop 未安装");
|
|
1580
1639
|
|
|
1581
|
-
const ctaLabel =
|
|
1640
|
+
const ctaLabel = isBusy
|
|
1582
1641
|
? tr("docker.working", "处理中…")
|
|
1583
1642
|
: running
|
|
1584
1643
|
? tr("localTeams.open", "打开")
|
|
@@ -1587,11 +1646,14 @@ function DockerCard({ dockerTeam, onOpen, onRefresh }) {
|
|
|
1587
1646
|
: tr("docker.install", "下载安装");
|
|
1588
1647
|
|
|
1589
1648
|
const onCta = () => {
|
|
1590
|
-
if (
|
|
1649
|
+
if (isBusy) return;
|
|
1591
1650
|
if (running) { onOpen?.(dockerTeam?.id); return; }
|
|
1592
1651
|
runBootstrap();
|
|
1593
1652
|
};
|
|
1594
1653
|
|
|
1654
|
+
// The ⋯ menu (重启 / 停止 / 升级) is only meaningful once Docker is installed.
|
|
1655
|
+
const showMenu = installed;
|
|
1656
|
+
|
|
1595
1657
|
return (
|
|
1596
1658
|
<div data-id="DockerCard" className={`bcard bcard--docker${running ? " bcard--online" : ""}`}>
|
|
1597
1659
|
<div className="bcard__accent" style={{ background: DOCKER_BLUE }} />
|
|
@@ -1602,6 +1664,44 @@ function DockerCard({ dockerTeam, onOpen, onRefresh }) {
|
|
|
1602
1664
|
<path d="M21.81 10.25c-.06-.05-.67-.51-1.95-.51-.34 0-.68.03-1.01.09-.25-1.69-1.64-2.51-1.7-2.55l-.34-.2-.22.32a4.5 4.5 0 0 0-.59 1.4c-.23.94-.09 1.83.39 2.59-.58.32-1.51.4-1.7.41H2.62a.61.61 0 0 0-.61.61 9.32 9.32 0 0 0 .57 3.35 4.9 4.9 0 0 0 1.95 2.53c.92.52 2.42.82 4.12.82.77 0 1.54-.07 2.3-.21a9.6 9.6 0 0 0 3-1.09 8.3 8.3 0 0 0 2.05-1.68c.98-1.11 1.56-2.35 1.99-3.45h.17c1.36 0 2.2-.55 2.66-1l.13-.16zM4.7 11.33h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16H4.7a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.46 0h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16H7.16a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.5 0h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16H9.66a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.47 0h1.78a.16.16 0 0 0 .16-.16V9.58a.16.16 0 0 0-.16-.16h-1.78a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16M7.16 9.06h1.78a.16.16 0 0 0 .16-.16V7.31a.16.16 0 0 0-.16-.16H7.16a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.5 0h1.78a.16.16 0 0 0 .16-.16V7.31a.16.16 0 0 0-.16-.16H9.66a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16m2.47 0h1.78a.16.16 0 0 0 .16-.16V7.31a.16.16 0 0 0-.16-.16h-1.78a.16.16 0 0 0-.16.16v1.59c0 .09.07.16.16.16" />
|
|
1603
1665
|
</svg>
|
|
1604
1666
|
</div>
|
|
1667
|
+
{showMenu && (
|
|
1668
|
+
<div className="bcard__menuwrap" onClick={(e) => e.stopPropagation()}>
|
|
1669
|
+
<button
|
|
1670
|
+
type="button"
|
|
1671
|
+
ref={kebabRef}
|
|
1672
|
+
data-id="DockerCard-menu-btn"
|
|
1673
|
+
className="bcard__kebab"
|
|
1674
|
+
title={tr("docker.manage", "管理 Docker cicy-code")}
|
|
1675
|
+
disabled={isBusy}
|
|
1676
|
+
onClick={toggleMenu}
|
|
1677
|
+
>
|
|
1678
|
+
{isBusy ? <Spinner /> : <KebabIcon />}
|
|
1679
|
+
</button>
|
|
1680
|
+
{menuOpen && createPortal(
|
|
1681
|
+
<div className="bcard__menu bcard__menu--portal" data-id="DockerCard-menu" role="menu"
|
|
1682
|
+
ref={menuRef}
|
|
1683
|
+
style={{ position: "fixed", top: menuPos.top, left: menuPos.left, width: MENU_W }}
|
|
1684
|
+
onClick={(e) => e.stopPropagation()}>
|
|
1685
|
+
{running && (
|
|
1686
|
+
<button type="button" data-id="DockerCard-restart" className="bcard__menu-item"
|
|
1687
|
+
onClick={() => runOp("restart", () => window.cicy.docker.appRestart(), tr("docker.restarted", "已重启"))}>
|
|
1688
|
+
{tr("docker.restart", "重启")}
|
|
1689
|
+
</button>
|
|
1690
|
+
)}
|
|
1691
|
+
<button type="button" data-id="DockerCard-upgrade" className="bcard__menu-item is-accent" onClick={runUpgrade}>
|
|
1692
|
+
{tr("docker.upgrade", "升级(拉取最新镜像)")}
|
|
1693
|
+
</button>
|
|
1694
|
+
{running && (
|
|
1695
|
+
<button type="button" data-id="DockerCard-stop" className="bcard__menu-item is-danger"
|
|
1696
|
+
onClick={() => runOp("stop", () => window.cicy.docker.appStop(), tr("docker.stopped", "已停止"))}>
|
|
1697
|
+
{tr("docker.stop", "停止")}
|
|
1698
|
+
</button>
|
|
1699
|
+
)}
|
|
1700
|
+
</div>,
|
|
1701
|
+
document.body
|
|
1702
|
+
)}
|
|
1703
|
+
</div>
|
|
1704
|
+
)}
|
|
1605
1705
|
</div>
|
|
1606
1706
|
<div className="bcard__body">
|
|
1607
1707
|
<h3 className="bcard__name">{tr("docker.title", "Docker cicy-code")}</h3>
|
|
@@ -1612,11 +1712,11 @@ function DockerCard({ dockerTeam, onOpen, onRefresh }) {
|
|
|
1612
1712
|
type="button"
|
|
1613
1713
|
className="bcard__cta"
|
|
1614
1714
|
data-id="DockerCard-cta"
|
|
1615
|
-
disabled={
|
|
1715
|
+
disabled={isBusy}
|
|
1616
1716
|
onClick={onCta}
|
|
1617
1717
|
style={!running ? { background: DOCKER_BLUE, color: "white" } : undefined}
|
|
1618
1718
|
>
|
|
1619
|
-
{
|
|
1719
|
+
{isBusy ? <Spinner /> : <ArrowIcon />}
|
|
1620
1720
|
<span>{ctaLabel}</span>
|
|
1621
1721
|
</button>
|
|
1622
1722
|
</div>
|