@tangle-network/sandbox-ui 0.116.8 → 0.117.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 +50 -0
- package/dist/{WorkflowGraph-B-NsdYz_.js → WorkflowGraph-CzWs8P7y.js} +1 -1
- package/dist/chat.js +1 -1
- package/dist/connections-DDRGYDvF.js +180 -0
- package/dist/connections.d.ts +2 -0
- package/dist/connections.js +2 -0
- package/dist/{dashboard-DJQFB7iZ.js → dashboard-euyfLroA.js} +462 -386
- package/dist/dashboard.js +1 -1
- package/dist/globals.css +72 -33
- package/dist/{index-iDiLnSoo.d.ts → index-CcbhfDa-.d.ts} +5 -1
- package/dist/index-ClRHbsoX.d.ts +61 -0
- package/dist/{index-l96iy93N.d.ts → index-z_zNuZHm.d.ts} +3 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +6 -5
- package/dist/integrations.d.ts +192 -52
- package/dist/integrations.js +874 -366
- package/dist/{provider-logo-DjqmConF.js → provider-logo-BiuiO_c2.js} +2 -1
- package/dist/styles.css +72 -33
- package/dist/{workbench-DVOVERx0.js → workbench-B1UltdHQ.js} +17 -3
- package/dist/workbench.d.ts +1 -1
- package/dist/workbench.js +1 -1
- package/dist/workflows.js +1 -1
- package/dist/{workspace-Pq-koOTW.js → workspace-fIHRXmWT.js} +41 -8
- package/dist/workspace.d.ts +1 -1
- package/dist/workspace.js +1 -1
- package/package.json +5 -1
- package/dist/{chat-BOvFAe6p.js → chat-Ci6Xi1rd.js} +1 -1
|
@@ -8,8 +8,8 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
|
8
8
|
import * as React$1 from "react";
|
|
9
9
|
import { useEffect, useRef, useState } from "react";
|
|
10
10
|
import { focusField, focusFieldWithin, focusRing, focusRingInset, timeAgo } from "@tangle-network/ui/utils";
|
|
11
|
-
import { Activity, BarChart2, Bell, Bot, Box, Camera, Check, CheckCircle2, ChevronDown, ChevronLeft, ChevronRight, Clock, Code2, Copy, Cpu, DollarSign, Download, ExternalLink, File, FileEdit, FilePlus, FileText, GitBranch, GitCommit, Globe, HardDrive, Key, Layers, Loader2, MemoryStick, MessageSquare, Monitor, MoreHorizontal, MoreVertical, Network, PanelLeft, Play, Plug, Plus, Power, PowerOff, RefreshCw, RotateCcw, Server, Settings, ShieldAlert, Skull, Terminal, Timer, Trash2, User, Users, Wrench, X, XCircle } from "lucide-react";
|
|
12
11
|
import { createPortal } from "react-dom";
|
|
12
|
+
import { Activity, BarChart2, Bell, Bot, Box, Camera, Check, CheckCircle2, ChevronDown, ChevronLeft, ChevronRight, Clock, Code2, Copy, Cpu, DollarSign, Download, ExternalLink, File, FileEdit, FilePlus, FileText, GitBranch, GitCommit, Globe, HardDrive, Key, Layers, Loader2, MemoryStick, MessageSquare, Monitor, MoreHorizontal, MoreVertical, Network, PanelLeft, Play, Plug, Plus, Power, PowerOff, RefreshCw, RotateCcw, Server, Settings, ShieldAlert, Skull, Terminal, Timer, Trash2, User, Users, Wrench, X, XCircle } from "lucide-react";
|
|
13
13
|
import * as Select from "@radix-ui/react-select";
|
|
14
14
|
//#region src/dashboard/sidebar-context.tsx
|
|
15
15
|
const PANEL_OPEN_KEY = "sandbox-sidebar-panel-open";
|
|
@@ -1489,6 +1489,12 @@ function Spec({ icon, value, unit }) {
|
|
|
1489
1489
|
]
|
|
1490
1490
|
});
|
|
1491
1491
|
}
|
|
1492
|
+
function UnknownMetric({ label }) {
|
|
1493
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1494
|
+
className: "flex items-center justify-between text-xs font-mono uppercase tracking-wide text-muted-foreground",
|
|
1495
|
+
children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx("span", { children: "Unknown" })]
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1492
1498
|
function SandboxCard({ sandbox, onOpenIDE, onOpenTerminal, onWake, onRestore, onDelete, onStop, onResume, onFork, onKeepAlive, onUsage, onHealth, className }) {
|
|
1493
1499
|
const isRunning = sandbox.status === "running";
|
|
1494
1500
|
const isTransitioning = sandbox.status === "provisioning" || sandbox.status === "creating";
|
|
@@ -1502,9 +1508,9 @@ function SandboxCard({ sandbox, onOpenIDE, onOpenTerminal, onWake, onRestore, on
|
|
|
1502
1508
|
const resumeHandler = isStopped ? resolveResumeHandler(sandbox.status) : void 0;
|
|
1503
1509
|
const status = STATUS_META[sandbox.status];
|
|
1504
1510
|
const isArchived = sandbox.status === "archived";
|
|
1505
|
-
const cpuPercent = sandbox.cpuPercent
|
|
1506
|
-
const ramUsed = sandbox.ramUsed
|
|
1507
|
-
const ramTotal = sandbox.ramTotal
|
|
1511
|
+
const cpuPercent = sandbox.cpuPercent;
|
|
1512
|
+
const ramUsed = sandbox.ramUsed;
|
|
1513
|
+
const ramTotal = sandbox.ramTotal;
|
|
1508
1514
|
const diskUsed = sandbox.diskUsed;
|
|
1509
1515
|
const diskTotal = sandbox.diskTotal;
|
|
1510
1516
|
const specs = [
|
|
@@ -1514,7 +1520,7 @@ function SandboxCard({ sandbox, onOpenIDE, onOpenTerminal, onWake, onRestore, on
|
|
|
1514
1520
|
value: sandbox.vcpu,
|
|
1515
1521
|
unit: "vCPU"
|
|
1516
1522
|
},
|
|
1517
|
-
ramTotal > 0 && {
|
|
1523
|
+
ramTotal != null && ramTotal > 0 && {
|
|
1518
1524
|
key: "ram",
|
|
1519
1525
|
icon: /* @__PURE__ */ jsx(MemoryStick, { className: "h-3.5 w-3.5" }),
|
|
1520
1526
|
value: ramTotal,
|
|
@@ -1531,27 +1537,35 @@ function SandboxCard({ sandbox, onOpenIDE, onOpenTerminal, onWake, onRestore, on
|
|
|
1531
1537
|
className: cn$1("group relative flex flex-col justify-between overflow-hidden rounded-lg border bg-surface-container p-5 transition-colors", isRunning ? "border-[var(--status-running)]/30" : "border-[var(--md3-outline-variant)]", "hover:border-foreground/15", className),
|
|
1532
1538
|
children: [
|
|
1533
1539
|
/* @__PURE__ */ jsxs("div", {
|
|
1534
|
-
className: "flex items-start justify-between",
|
|
1535
|
-
children: [/* @__PURE__ */ jsxs("div", {
|
|
1536
|
-
className: "
|
|
1537
|
-
children: [/* @__PURE__ */
|
|
1538
|
-
className: "
|
|
1539
|
-
children:
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
"
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1540
|
+
className: "flex min-w-0 items-start justify-between gap-3",
|
|
1541
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1542
|
+
className: "min-w-0 flex-1",
|
|
1543
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1544
|
+
className: "flex min-w-0 items-center gap-2",
|
|
1545
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
1546
|
+
className: "min-w-0 flex-1 truncate text-sm font-bold text-foreground",
|
|
1547
|
+
title: sandbox.name,
|
|
1548
|
+
"aria-label": sandbox.name,
|
|
1549
|
+
children: sandbox.name
|
|
1550
|
+
}), sandbox.team && /* @__PURE__ */ jsxs("span", {
|
|
1551
|
+
className: "inline-flex min-w-0 max-w-40 items-center gap-1 rounded-full bg-[var(--accent-surface-soft)] px-2 py-0.5 text-[10px] font-semibold text-[var(--accent-text)]",
|
|
1552
|
+
title: `Shared with ${sandbox.team.name ?? "Team"} · ${sandbox.team.role}`,
|
|
1553
|
+
children: [/* @__PURE__ */ jsx(Users, {
|
|
1554
|
+
className: "h-3 w-3 shrink-0",
|
|
1555
|
+
"aria-hidden": "true"
|
|
1556
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1557
|
+
className: "min-w-0 truncate",
|
|
1558
|
+
children: sandbox.team.name ?? "Team"
|
|
1559
|
+
})]
|
|
1560
|
+
})]
|
|
1561
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
1562
|
+
className: "mt-0.5 min-w-0 truncate font-mono text-[10px] tracking-wider text-muted-foreground uppercase",
|
|
1563
|
+
children: [sandbox.nodeId || "Unknown Node", sandbox.team && /* @__PURE__ */ jsxs("span", {
|
|
1564
|
+
className: "ml-2 normal-case tracking-normal",
|
|
1565
|
+
children: ["· your role: ", sandbox.team.role]
|
|
1566
|
+
})]
|
|
1553
1567
|
})]
|
|
1554
|
-
})
|
|
1568
|
+
}), /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
1555
1569
|
asChild: true,
|
|
1556
1570
|
children: /* @__PURE__ */ jsx("button", {
|
|
1557
1571
|
type: "button",
|
|
@@ -1636,19 +1650,22 @@ function SandboxCard({ sandbox, onOpenIDE, onOpenTerminal, onWake, onRestore, on
|
|
|
1636
1650
|
isRunning ? /* @__PURE__ */ jsxs("div", {
|
|
1637
1651
|
className: "space-y-2 rounded-md border border-[var(--md3-outline-variant)] bg-surface-container-high p-3",
|
|
1638
1652
|
children: [
|
|
1639
|
-
/* @__PURE__ */ jsx(ResourceMeter, {
|
|
1653
|
+
cpuPercent != null ? /* @__PURE__ */ jsx(ResourceMeter, {
|
|
1640
1654
|
label: "CPU",
|
|
1641
1655
|
value: cpuPercent,
|
|
1642
1656
|
max: 100,
|
|
1643
1657
|
icon: /* @__PURE__ */ jsx(Cpu, { className: "h-3 w-3" })
|
|
1644
|
-
}),
|
|
1645
|
-
ramTotal > 0
|
|
1646
|
-
label: "
|
|
1658
|
+
}) : /* @__PURE__ */ jsx(UnknownMetric, { label: "CPU" }),
|
|
1659
|
+
ramUsed != null && ramTotal != null && ramTotal > 0 ? /* @__PURE__ */ jsx(ResourceMeter, {
|
|
1660
|
+
label: "RAM",
|
|
1647
1661
|
value: ramUsed,
|
|
1648
1662
|
max: ramTotal,
|
|
1649
|
-
valueLabel:
|
|
1663
|
+
valueLabel: String(ramUsed) + " / " + String(ramTotal) + " GB",
|
|
1650
1664
|
icon: /* @__PURE__ */ jsx(MemoryStick, { className: "h-3 w-3" })
|
|
1651
|
-
}),
|
|
1665
|
+
}) : ramUsed != null ? /* @__PURE__ */ jsxs("p", {
|
|
1666
|
+
className: "flex items-center justify-between text-xs font-mono uppercase tracking-wide text-muted-foreground",
|
|
1667
|
+
children: [/* @__PURE__ */ jsx("span", { children: "RAM" }), /* @__PURE__ */ jsxs("span", { children: [String(ramUsed), " GB used; capacity unknown"] })]
|
|
1668
|
+
}) : /* @__PURE__ */ jsx(UnknownMetric, { label: "RAM" }),
|
|
1652
1669
|
diskUsed != null && diskTotal != null && diskTotal > 0 && /* @__PURE__ */ jsx(ResourceMeter, {
|
|
1653
1670
|
label: "DISK",
|
|
1654
1671
|
value: diskUsed,
|
|
@@ -1702,13 +1719,13 @@ function SandboxCard({ sandbox, onOpenIDE, onOpenTerminal, onWake, onRestore, on
|
|
|
1702
1719
|
children: isRunning ? /* @__PURE__ */ jsxs("button", {
|
|
1703
1720
|
type: "button",
|
|
1704
1721
|
onClick: () => onOpenIDE?.(sandbox.id),
|
|
1705
|
-
className: "flex w-full items-center justify-center gap-2 rounded-md bg-[var(--btn-primary-bg)] px-4 py-2 text-sm font-semibold text-[var(--btn-primary-text)] transition-colors hover:bg-[var(--btn-primary-hover)] active:scale-[0.97]",
|
|
1722
|
+
className: cn$1("flex w-full items-center justify-center gap-2 min-h-11 rounded-md bg-[var(--btn-primary-bg)] px-4 py-2 text-sm font-semibold text-[var(--btn-primary-text)] transition-colors hover:bg-[var(--btn-primary-hover)] active:scale-[0.97]", focusRing),
|
|
1706
1723
|
children: [/* @__PURE__ */ jsx(Network, { className: "h-4 w-4" }), "Connect Session"]
|
|
1707
1724
|
}) : /* @__PURE__ */ jsxs("button", {
|
|
1708
1725
|
type: "button",
|
|
1709
1726
|
onClick: () => resumeHandler?.(sandbox.id),
|
|
1710
1727
|
disabled: isTransitioning || !resumeHandler,
|
|
1711
|
-
className: cn$1("flex w-full items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-semibold transition-colors border", isTransitioning || !resumeHandler ? "bg-muted text-muted-foreground cursor-not-allowed border-[var(--md3-outline-variant)]" : "bg-surface-container-high text-foreground hover:bg-surface-container-highest border-[var(--md3-outline-variant)] active:scale-[0.97]"),
|
|
1728
|
+
className: cn$1("flex min-h-11 w-full items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-semibold transition-colors border", focusRing, isTransitioning || !resumeHandler ? "bg-muted text-muted-foreground cursor-not-allowed border-[var(--md3-outline-variant)]" : "bg-surface-container-high text-foreground hover:bg-surface-container-highest border-[var(--md3-outline-variant)] active:scale-[0.97]"),
|
|
1712
1729
|
children: [/* @__PURE__ */ jsx(Play, { className: "h-4 w-4" }), isTransitioning ? "Starting..." : resumeLabel]
|
|
1713
1730
|
})
|
|
1714
1731
|
})
|
|
@@ -1741,7 +1758,7 @@ function NewSandboxCard({ onClick, className }) {
|
|
|
1741
1758
|
const statusColors = {
|
|
1742
1759
|
running: {
|
|
1743
1760
|
dot: "bg-[var(--code-success)] animate-pulse",
|
|
1744
|
-
text: "text-[var(--
|
|
1761
|
+
text: "text-[var(--surface-success-text)]",
|
|
1745
1762
|
bar: "bg-[var(--code-success)]"
|
|
1746
1763
|
},
|
|
1747
1764
|
hibernating: {
|
|
@@ -1751,12 +1768,12 @@ const statusColors = {
|
|
|
1751
1768
|
},
|
|
1752
1769
|
provisioning: {
|
|
1753
1770
|
dot: "bg-primary animate-pulse",
|
|
1754
|
-
text: "text-
|
|
1771
|
+
text: "text-[var(--accent-text)]",
|
|
1755
1772
|
bar: "bg-primary"
|
|
1756
1773
|
},
|
|
1757
1774
|
creating: {
|
|
1758
1775
|
dot: "bg-primary animate-pulse",
|
|
1759
|
-
text: "text-
|
|
1776
|
+
text: "text-[var(--accent-text)]",
|
|
1760
1777
|
bar: "bg-primary"
|
|
1761
1778
|
},
|
|
1762
1779
|
stopped: {
|
|
@@ -1766,7 +1783,7 @@ const statusColors = {
|
|
|
1766
1783
|
},
|
|
1767
1784
|
failed: {
|
|
1768
1785
|
dot: "bg-[var(--code-error)]",
|
|
1769
|
-
text: "text-[var(--
|
|
1786
|
+
text: "text-[var(--surface-danger-text)]",
|
|
1770
1787
|
bar: "bg-[var(--code-error)]"
|
|
1771
1788
|
},
|
|
1772
1789
|
archived: {
|
|
@@ -1779,6 +1796,7 @@ function isResumable(status) {
|
|
|
1779
1796
|
return status !== "running" && status !== "provisioning" && status !== "creating";
|
|
1780
1797
|
}
|
|
1781
1798
|
function MiniMeter({ label, percent, className }) {
|
|
1799
|
+
const hasValue = percent != null && Number.isFinite(percent);
|
|
1782
1800
|
return /* @__PURE__ */ jsxs("div", {
|
|
1783
1801
|
className: cn$1("space-y-1", className),
|
|
1784
1802
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
@@ -1786,44 +1804,91 @@ function MiniMeter({ label, percent, className }) {
|
|
|
1786
1804
|
children: [/* @__PURE__ */ jsx("span", {
|
|
1787
1805
|
className: "font-bold",
|
|
1788
1806
|
children: label
|
|
1789
|
-
}), /* @__PURE__ */
|
|
1790
|
-
className: "text-
|
|
1791
|
-
children:
|
|
1807
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1808
|
+
className: hasValue ? "text-[var(--accent-text)]" : "text-muted-foreground",
|
|
1809
|
+
children: hasValue ? String(percent) + "%" : "Unknown"
|
|
1792
1810
|
})]
|
|
1793
1811
|
}), /* @__PURE__ */ jsx("div", {
|
|
1794
|
-
className: "h-1.5 w-full
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1812
|
+
className: "h-1.5 w-full overflow-hidden rounded-full bg-muted",
|
|
1813
|
+
"aria-hidden": "true",
|
|
1814
|
+
children: hasValue && /* @__PURE__ */ jsx("div", {
|
|
1815
|
+
className: "h-full rounded-full bg-primary",
|
|
1816
|
+
style: { width: String(percent) + "%" }
|
|
1798
1817
|
})
|
|
1799
1818
|
})]
|
|
1800
1819
|
});
|
|
1801
1820
|
}
|
|
1821
|
+
function StatusIndicator({ status }) {
|
|
1822
|
+
const sc = statusColors[status] ?? statusColors.stopped;
|
|
1823
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1824
|
+
className: "flex items-center gap-2 whitespace-nowrap",
|
|
1825
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1826
|
+
className: cn$1("flex h-2.5 w-2.5 shrink-0 rounded-full", sc.dot),
|
|
1827
|
+
"aria-hidden": "true",
|
|
1828
|
+
...sc.dot.includes("animate-") ? { "data-motion": "essential" } : {}
|
|
1829
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1830
|
+
className: cn$1("text-xs font-bold uppercase tracking-wide", sc.text),
|
|
1831
|
+
children: status.charAt(0).toUpperCase() + status.slice(1)
|
|
1832
|
+
})]
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1835
|
+
function SandboxResources({ sandbox, className }) {
|
|
1836
|
+
if (sandbox.status === "running") {
|
|
1837
|
+
const ramPercent = sandbox.ramUsed != null && sandbox.ramTotal != null && sandbox.ramTotal > 0 ? Math.round(sandbox.ramUsed / sandbox.ramTotal * 100) : void 0;
|
|
1838
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1839
|
+
className: cn$1("min-w-0 space-y-3", className),
|
|
1840
|
+
children: [/* @__PURE__ */ jsx(MiniMeter, {
|
|
1841
|
+
label: "CPU",
|
|
1842
|
+
percent: sandbox.cpuPercent
|
|
1843
|
+
}), /* @__PURE__ */ jsx(MiniMeter, {
|
|
1844
|
+
label: "RAM",
|
|
1845
|
+
percent: ramPercent
|
|
1846
|
+
})]
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1849
|
+
if (sandbox.status === "provisioning" || sandbox.status === "creating") return /* @__PURE__ */ jsxs("div", {
|
|
1850
|
+
className: cn$1("flex min-w-0 items-center gap-2 text-[var(--accent-text)] italic text-[10px] font-bold", className),
|
|
1851
|
+
children: [/* @__PURE__ */ jsx(RefreshCw, {
|
|
1852
|
+
className: "h-3.5 w-3.5 shrink-0 animate-spin",
|
|
1853
|
+
"data-motion": "essential"
|
|
1854
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1855
|
+
className: "min-w-0 truncate",
|
|
1856
|
+
title: sandbox.provisioningMessage ?? "Allocating nodes...",
|
|
1857
|
+
children: sandbox.provisioningMessage ?? "Allocating nodes..."
|
|
1858
|
+
})]
|
|
1859
|
+
});
|
|
1860
|
+
if (sandbox.status === "hibernating") return /* @__PURE__ */ jsx("p", {
|
|
1861
|
+
className: cn$1("text-xs text-muted-foreground", className),
|
|
1862
|
+
children: "Not running"
|
|
1863
|
+
});
|
|
1864
|
+
return null;
|
|
1865
|
+
}
|
|
1866
|
+
function getPageItems(page, totalPages) {
|
|
1867
|
+
if (totalPages <= 7) return Array.from({ length: totalPages }, (_, index) => index + 1);
|
|
1868
|
+
let start = Math.max(2, page - 1);
|
|
1869
|
+
let end = Math.min(totalPages - 1, page + 1);
|
|
1870
|
+
if (page <= 3) {
|
|
1871
|
+
start = 2;
|
|
1872
|
+
end = 5;
|
|
1873
|
+
} else if (page >= totalPages - 2) {
|
|
1874
|
+
start = totalPages - 4;
|
|
1875
|
+
end = totalPages - 1;
|
|
1876
|
+
}
|
|
1877
|
+
const items = [1];
|
|
1878
|
+
if (start > 2) items.push("start-ellipsis");
|
|
1879
|
+
for (let current = start; current <= end; current += 1) items.push(current);
|
|
1880
|
+
if (end < totalPages - 1) items.push("end-ellipsis");
|
|
1881
|
+
items.push(totalPages);
|
|
1882
|
+
return items;
|
|
1883
|
+
}
|
|
1802
1884
|
function SandboxTable({ sandboxes, page = 1, pageSize = 10, total, onPageChange, onOpenIDE, onOpenTerminal, onSSH, onResume, onWake, onMore, onDelete, onStop, onKeepAlive, onUsage, onHealth, onFork, className }) {
|
|
1803
|
-
const totalCount = total ?? sandboxes.length;
|
|
1804
|
-
const
|
|
1885
|
+
const totalCount = Math.max(0, total ?? sandboxes.length);
|
|
1886
|
+
const safePageSize = Number.isFinite(pageSize) ? Math.max(1, Math.floor(pageSize)) : 10;
|
|
1887
|
+
const totalPages = Math.ceil(totalCount / safePageSize);
|
|
1888
|
+
const currentPage = Math.min(Number.isFinite(page) ? Math.max(1, Math.floor(page)) : 1, Math.max(1, totalPages));
|
|
1889
|
+
const rangeStart = totalCount === 0 || sandboxes.length === 0 ? 0 : (currentPage - 1) * safePageSize + 1;
|
|
1890
|
+
const rangeEnd = rangeStart === 0 ? 0 : Math.min(rangeStart + sandboxes.length - 1, totalCount);
|
|
1805
1891
|
const hasTeamSandboxes = sandboxes.some((sb) => sb.team !== void 0);
|
|
1806
|
-
const tableScrollRef = React$1.useRef(null);
|
|
1807
|
-
const [hasHiddenColumns, setHasHiddenColumns] = React$1.useState(false);
|
|
1808
|
-
React$1.useEffect(() => {
|
|
1809
|
-
const scroller = tableScrollRef.current;
|
|
1810
|
-
const table = scroller?.querySelector("table");
|
|
1811
|
-
if (!scroller || !table) return;
|
|
1812
|
-
const measure = () => setHasHiddenColumns(scroller.scrollWidth > scroller.clientWidth + 1);
|
|
1813
|
-
measure();
|
|
1814
|
-
if (typeof ResizeObserver === "undefined") {
|
|
1815
|
-
window.addEventListener("resize", measure);
|
|
1816
|
-
return () => window.removeEventListener("resize", measure);
|
|
1817
|
-
}
|
|
1818
|
-
const observer = new ResizeObserver(measure);
|
|
1819
|
-
observer.observe(scroller);
|
|
1820
|
-
observer.observe(table);
|
|
1821
|
-
return () => observer.disconnect();
|
|
1822
|
-
}, [sandboxes, hasTeamSandboxes]);
|
|
1823
|
-
const scrollColumns = (direction) => {
|
|
1824
|
-
const scroller = tableScrollRef.current;
|
|
1825
|
-
scroller?.scrollBy({ left: direction * scroller.clientWidth * .75 });
|
|
1826
|
-
};
|
|
1827
1892
|
const resolveResumeHandler = (status) => {
|
|
1828
1893
|
if (onResume) return onResume;
|
|
1829
1894
|
if (status === "hibernating") return onWake;
|
|
@@ -1836,348 +1901,359 @@ function SandboxTable({ sandboxes, page = 1, pageSize = 10, total, onPageChange,
|
|
|
1836
1901
|
};
|
|
1837
1902
|
return /* @__PURE__ */ jsxs("div", {
|
|
1838
1903
|
className: cn$1("w-full", className),
|
|
1839
|
-
children: [
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
children: /* @__PURE__ */
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1904
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1905
|
+
className: "w-full bg-surface-container rounded-2xl overflow-hidden border border-[var(--md3-outline-variant)]",
|
|
1906
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1907
|
+
className: cn$1("max-h-[min(60vh,35rem)] overflow-x-hidden overflow-y-auto", focusRingInset),
|
|
1908
|
+
role: "region",
|
|
1909
|
+
"aria-label": "Sandbox list",
|
|
1910
|
+
tabIndex: 0,
|
|
1911
|
+
children: /* @__PURE__ */ jsxs("table", {
|
|
1912
|
+
className: "w-full table-fixed border-collapse text-left",
|
|
1913
|
+
children: [/* @__PURE__ */ jsx("thead", {
|
|
1914
|
+
className: "sticky top-0 z-10",
|
|
1915
|
+
children: /* @__PURE__ */ jsxs("tr", {
|
|
1916
|
+
className: "bg-surface-container-high border-b border-[var(--md3-outline-variant)]",
|
|
1917
|
+
children: [
|
|
1918
|
+
/* @__PURE__ */ jsx("th", {
|
|
1919
|
+
scope: "col",
|
|
1920
|
+
className: "hidden w-36 px-3 py-4 text-xs font-semibold uppercase tracking-wider text-muted-foreground xl:table-cell",
|
|
1921
|
+
children: "Status"
|
|
1922
|
+
}),
|
|
1923
|
+
/* @__PURE__ */ jsx("th", {
|
|
1924
|
+
scope: "col",
|
|
1925
|
+
className: "px-3 py-4 text-xs font-semibold uppercase tracking-wider text-muted-foreground xl:px-6",
|
|
1926
|
+
children: "Sandbox"
|
|
1927
|
+
}),
|
|
1928
|
+
hasTeamSandboxes && /* @__PURE__ */ jsx("th", {
|
|
1929
|
+
scope: "col",
|
|
1930
|
+
className: "hidden w-32 px-3 py-4 text-xs font-semibold uppercase tracking-wider text-muted-foreground xl:table-cell",
|
|
1931
|
+
children: "Scope"
|
|
1932
|
+
}),
|
|
1933
|
+
/* @__PURE__ */ jsx("th", {
|
|
1934
|
+
scope: "col",
|
|
1935
|
+
className: "hidden w-28 px-3 py-4 text-xs font-semibold uppercase tracking-wider text-muted-foreground xl:table-cell",
|
|
1936
|
+
children: "Environment"
|
|
1937
|
+
}),
|
|
1938
|
+
/* @__PURE__ */ jsx("th", {
|
|
1939
|
+
scope: "col",
|
|
1940
|
+
className: "hidden w-48 px-3 py-4 text-xs font-semibold uppercase tracking-wider text-muted-foreground xl:table-cell",
|
|
1941
|
+
children: "Resources"
|
|
1942
|
+
}),
|
|
1943
|
+
/* @__PURE__ */ jsx("th", {
|
|
1944
|
+
scope: "col",
|
|
1945
|
+
className: "w-28 px-2 py-4 text-right text-xs font-semibold uppercase tracking-wider text-muted-foreground xl:w-72 xl:px-4",
|
|
1946
|
+
children: "Actions"
|
|
1947
|
+
})
|
|
1948
|
+
]
|
|
1949
|
+
})
|
|
1950
|
+
}), /* @__PURE__ */ jsx("tbody", {
|
|
1951
|
+
className: "divide-y divide-border",
|
|
1952
|
+
children: sandboxes.map((sb) => {
|
|
1953
|
+
const isActive = sb.status === "running";
|
|
1954
|
+
const isHibernating = sb.status === "hibernating";
|
|
1955
|
+
const isProvisioning = sb.status === "provisioning" || sb.status === "creating";
|
|
1956
|
+
const resumeHandler = isResumable(sb.status) ? resolveResumeHandler(sb.status) : void 0;
|
|
1957
|
+
const onRowClick = resolveRowClick(sb);
|
|
1958
|
+
const resumeLabel = isHibernating ? "Wake Up" : "Resume";
|
|
1959
|
+
const stopRowClick = (e) => e.stopPropagation();
|
|
1960
|
+
return /* @__PURE__ */ jsxs("tr", {
|
|
1961
|
+
className: cn$1("group relative transition-colors", onRowClick ? "cursor-pointer hover:bg-surface-container-high" : "hover:bg-surface-container-high"),
|
|
1962
|
+
onClick: onRowClick,
|
|
1876
1963
|
children: [
|
|
1877
|
-
/* @__PURE__ */ jsx("
|
|
1878
|
-
className: "px-
|
|
1879
|
-
children:
|
|
1880
|
-
}),
|
|
1881
|
-
/* @__PURE__ */ jsx("th", {
|
|
1882
|
-
className: "px-6 py-4 text-xs font-semibold text-muted-foreground uppercase tracking-wider",
|
|
1883
|
-
children: "Sandbox Name"
|
|
1884
|
-
}),
|
|
1885
|
-
hasTeamSandboxes && /* @__PURE__ */ jsx("th", {
|
|
1886
|
-
className: "px-6 py-4 text-xs font-semibold text-muted-foreground uppercase tracking-wider",
|
|
1887
|
-
children: "Scope"
|
|
1888
|
-
}),
|
|
1889
|
-
/* @__PURE__ */ jsx("th", {
|
|
1890
|
-
className: "px-6 py-4 text-xs font-semibold text-muted-foreground uppercase tracking-wider",
|
|
1891
|
-
children: "Environment"
|
|
1964
|
+
/* @__PURE__ */ jsx("td", {
|
|
1965
|
+
className: "hidden px-3 py-4 align-top xl:table-cell xl:w-36 xl:px-4 xl:py-5",
|
|
1966
|
+
children: /* @__PURE__ */ jsx(StatusIndicator, { status: sb.status })
|
|
1892
1967
|
}),
|
|
1893
|
-
/* @__PURE__ */ jsx("
|
|
1894
|
-
className: "px-
|
|
1895
|
-
children: "
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
return /* @__PURE__ */ jsxs("tr", {
|
|
1915
|
-
className: cn$1("group relative transition-colors", onRowClick ? "cursor-pointer hover:bg-surface-container-high" : "hover:bg-surface-container-high"),
|
|
1916
|
-
onClick: onRowClick,
|
|
1917
|
-
children: [
|
|
1918
|
-
/* @__PURE__ */ jsx("td", {
|
|
1919
|
-
className: "px-6 py-5 whitespace-nowrap",
|
|
1920
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
1921
|
-
className: "flex items-center gap-2",
|
|
1922
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
1923
|
-
className: cn$1("flex h-2.5 w-2.5 rounded-full", sc.dot),
|
|
1924
|
-
...sc.dot.includes("animate-") ? { "data-motion": "essential" } : {}
|
|
1925
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
1926
|
-
className: cn$1("text-xs font-bold uppercase tracking-wide", sc.text),
|
|
1927
|
-
children: sb.status.charAt(0).toUpperCase() + sb.status.slice(1)
|
|
1968
|
+
/* @__PURE__ */ jsx("td", {
|
|
1969
|
+
className: "min-w-0 px-3 py-4 align-top xl:px-6 xl:py-5",
|
|
1970
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
1971
|
+
className: "flex min-w-0 flex-col gap-2",
|
|
1972
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1973
|
+
className: "flex min-w-0 items-start gap-2",
|
|
1974
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1975
|
+
className: "shrink-0 xl:hidden",
|
|
1976
|
+
children: /* @__PURE__ */ jsx(StatusIndicator, { status: sb.status })
|
|
1977
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1978
|
+
className: "min-w-0 flex-1",
|
|
1979
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1980
|
+
className: "block min-w-0 truncate text-sm font-bold text-foreground transition-colors group-hover:text-[var(--accent-text)]",
|
|
1981
|
+
title: sb.name,
|
|
1982
|
+
"aria-label": sb.name,
|
|
1983
|
+
children: sb.name
|
|
1984
|
+
}), sb.nodeId && /* @__PURE__ */ jsx("span", {
|
|
1985
|
+
className: "block min-w-0 truncate text-[10px] font-mono text-muted-foreground",
|
|
1986
|
+
title: sb.nodeId,
|
|
1987
|
+
children: sb.nodeId
|
|
1988
|
+
})]
|
|
1928
1989
|
})]
|
|
1929
|
-
})
|
|
1930
|
-
|
|
1931
|
-
/* @__PURE__ */ jsx("td", {
|
|
1932
|
-
className: "px-6 py-5",
|
|
1933
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
1934
|
-
className: cn$1("flex min-w-0 flex-col", hasTeamSandboxes ? "max-w-36" : "max-w-64"),
|
|
1935
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
1936
|
-
className: "truncate text-sm font-bold text-foreground group-hover:text-primary transition-colors",
|
|
1937
|
-
title: sb.name,
|
|
1938
|
-
children: sb.name
|
|
1939
|
-
}), sb.nodeId && /* @__PURE__ */ jsx("span", {
|
|
1940
|
-
className: "truncate text-[10px] font-mono text-muted-foreground",
|
|
1941
|
-
title: sb.nodeId,
|
|
1942
|
-
children: sb.nodeId
|
|
1943
|
-
})]
|
|
1944
|
-
})
|
|
1945
|
-
}),
|
|
1946
|
-
hasTeamSandboxes && /* @__PURE__ */ jsx("td", {
|
|
1947
|
-
className: "px-6 py-5",
|
|
1948
|
-
children: sb.team ? /* @__PURE__ */ jsxs("div", {
|
|
1949
|
-
className: "inline-flex max-w-40 items-center gap-1.5 rounded-full bg-[var(--accent-surface-soft)] px-2.5 py-1 text-[11px] font-semibold text-[var(--accent-text)]",
|
|
1950
|
-
title: `Shared with ${sb.team.name ?? "Team"} · ${sb.team.role}`,
|
|
1990
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1991
|
+
className: "grid min-w-0 gap-1 text-[11px] xl:hidden",
|
|
1951
1992
|
children: [
|
|
1952
|
-
/* @__PURE__ */
|
|
1953
|
-
className: "
|
|
1954
|
-
|
|
1993
|
+
hasTeamSandboxes && /* @__PURE__ */ jsxs("div", {
|
|
1994
|
+
className: "flex min-w-0 gap-2",
|
|
1995
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1996
|
+
className: "shrink-0 text-muted-foreground",
|
|
1997
|
+
children: "Scope"
|
|
1998
|
+
}), sb.team ? /* @__PURE__ */ jsxs("span", {
|
|
1999
|
+
className: "min-w-0 truncate text-foreground",
|
|
2000
|
+
title: "Shared with " + (sb.team.name ?? "Team") + " · " + sb.team.role,
|
|
2001
|
+
children: [
|
|
2002
|
+
sb.team.name ?? "Team",
|
|
2003
|
+
" - ",
|
|
2004
|
+
sb.team.role
|
|
2005
|
+
]
|
|
2006
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
2007
|
+
className: "text-foreground",
|
|
2008
|
+
children: "Personal"
|
|
2009
|
+
})]
|
|
1955
2010
|
}),
|
|
1956
|
-
/* @__PURE__ */
|
|
1957
|
-
className: "min-w-0
|
|
1958
|
-
children:
|
|
2011
|
+
(sb.customImage ?? sb.image) && /* @__PURE__ */ jsxs("div", {
|
|
2012
|
+
className: "flex min-w-0 gap-2",
|
|
2013
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2014
|
+
className: "shrink-0 text-muted-foreground",
|
|
2015
|
+
children: "Environment"
|
|
2016
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
2017
|
+
className: "min-w-0 truncate text-foreground",
|
|
2018
|
+
title: sb.customImage ?? sb.image,
|
|
2019
|
+
children: sb.customImage ?? sb.image
|
|
2020
|
+
})]
|
|
1959
2021
|
}),
|
|
1960
|
-
/* @__PURE__ */ jsxs("
|
|
1961
|
-
className: "
|
|
1962
|
-
children: [
|
|
2022
|
+
(isActive || isProvisioning || isHibernating) && /* @__PURE__ */ jsxs("div", {
|
|
2023
|
+
className: "flex min-w-0 flex-col gap-1",
|
|
2024
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2025
|
+
className: "text-muted-foreground",
|
|
2026
|
+
children: "Resources"
|
|
2027
|
+
}), /* @__PURE__ */ jsx(SandboxResources, { sandbox: sb })]
|
|
1963
2028
|
})
|
|
1964
2029
|
]
|
|
1965
|
-
})
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
2030
|
+
})]
|
|
2031
|
+
})
|
|
2032
|
+
}),
|
|
2033
|
+
hasTeamSandboxes && /* @__PURE__ */ jsx("td", {
|
|
2034
|
+
className: "hidden px-3 py-4 align-top xl:table-cell xl:px-4 xl:py-5",
|
|
2035
|
+
children: sb.team ? /* @__PURE__ */ jsxs("div", {
|
|
2036
|
+
className: "inline-flex max-w-full items-center gap-1.5 overflow-hidden rounded-full bg-[var(--accent-surface-soft)] px-2.5 py-1 text-[11px] font-semibold text-[var(--accent-text)]",
|
|
2037
|
+
title: "Shared with " + (sb.team.name ?? "Team") + " · " + sb.team.role,
|
|
2038
|
+
children: [
|
|
2039
|
+
/* @__PURE__ */ jsx(Users, {
|
|
2040
|
+
className: "h-3 w-3 shrink-0",
|
|
1970
2041
|
"aria-hidden": "true"
|
|
1971
|
-
}),
|
|
1972
|
-
|
|
1973
|
-
}),
|
|
1974
|
-
/* @__PURE__ */ jsx("td", {
|
|
1975
|
-
className: "px-6 py-5",
|
|
1976
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
1977
|
-
className: cn$1("flex min-w-0 items-center gap-3", hasTeamSandboxes ? "max-w-26" : "max-w-28"),
|
|
1978
|
-
children: [sb.imageIcon && /* @__PURE__ */ jsx("div", {
|
|
1979
|
-
className: "w-8 h-8 shrink-0 rounded-lg bg-surface-container-high flex items-center justify-center",
|
|
1980
|
-
children: sb.imageIcon
|
|
1981
|
-
}), sb.image && /* @__PURE__ */ jsx("span", {
|
|
1982
|
-
className: "min-w-0 truncate text-xs font-bold text-foreground",
|
|
1983
|
-
title: sb.image,
|
|
1984
|
-
children: sb.image
|
|
1985
|
-
})]
|
|
1986
|
-
})
|
|
1987
|
-
}),
|
|
1988
|
-
/* @__PURE__ */ jsx("td", {
|
|
1989
|
-
className: "px-6 py-5",
|
|
1990
|
-
children: isActive ? /* @__PURE__ */ jsxs("div", {
|
|
1991
|
-
className: cn$1("space-y-3", hasTeamSandboxes ? "w-44" : "w-48"),
|
|
1992
|
-
children: [/* @__PURE__ */ jsx(MiniMeter, {
|
|
1993
|
-
label: "CPU",
|
|
1994
|
-
percent: sb.cpuPercent ?? 0
|
|
1995
|
-
}), /* @__PURE__ */ jsx(MiniMeter, {
|
|
1996
|
-
label: "RAM",
|
|
1997
|
-
percent: sb.ramTotal ? Math.round((sb.ramUsed ?? 0) / sb.ramTotal * 100) : 0
|
|
1998
|
-
})]
|
|
1999
|
-
}) : isProvisioning ? /* @__PURE__ */ jsxs("div", {
|
|
2000
|
-
className: cn$1("flex items-center gap-2 text-primary italic text-[10px] font-bold", hasTeamSandboxes ? "max-w-44" : "max-w-48"),
|
|
2001
|
-
children: [/* @__PURE__ */ jsx(RefreshCw, {
|
|
2002
|
-
className: "h-3.5 w-3.5 shrink-0 animate-spin",
|
|
2003
|
-
"data-motion": "essential"
|
|
2004
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
2042
|
+
}),
|
|
2043
|
+
/* @__PURE__ */ jsx("span", {
|
|
2005
2044
|
className: "min-w-0 truncate",
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
type: "button",
|
|
2048
|
-
onClick: (e) => {
|
|
2049
|
-
stopRowClick(e);
|
|
2050
|
-
onSSH?.(sb.id);
|
|
2051
|
-
},
|
|
2052
|
-
className: "p-2 rounded-lg hover:bg-surface-container-high text-muted-foreground hover:text-foreground transition-all active:scale-90",
|
|
2053
|
-
title: "SSH",
|
|
2054
|
-
children: /* @__PURE__ */ jsx(Key, { className: "h-4 w-4" })
|
|
2055
|
-
})
|
|
2056
|
-
] }),
|
|
2057
|
-
resumeHandler && /* @__PURE__ */ jsxs("button", {
|
|
2045
|
+
children: sb.team.name ?? "Team"
|
|
2046
|
+
}),
|
|
2047
|
+
/* @__PURE__ */ jsxs("span", {
|
|
2048
|
+
className: "shrink-0 font-normal text-muted-foreground",
|
|
2049
|
+
children: ["- ", sb.team.role]
|
|
2050
|
+
})
|
|
2051
|
+
]
|
|
2052
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
2053
|
+
className: "inline-flex items-center gap-1.5 rounded-full bg-surface-container-high px-2.5 py-1 text-[11px] font-medium text-muted-foreground",
|
|
2054
|
+
title: "Personal sandbox",
|
|
2055
|
+
children: [/* @__PURE__ */ jsx(User, {
|
|
2056
|
+
className: "h-3 w-3",
|
|
2057
|
+
"aria-hidden": "true"
|
|
2058
|
+
}), "Personal"]
|
|
2059
|
+
})
|
|
2060
|
+
}),
|
|
2061
|
+
/* @__PURE__ */ jsx("td", {
|
|
2062
|
+
className: "hidden px-3 py-4 align-top xl:table-cell xl:px-4 xl:py-5",
|
|
2063
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2064
|
+
className: "flex min-w-0 items-center gap-2",
|
|
2065
|
+
children: [sb.imageIcon && /* @__PURE__ */ jsx("div", {
|
|
2066
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-surface-container-high",
|
|
2067
|
+
children: sb.imageIcon
|
|
2068
|
+
}), (sb.customImage ?? sb.image) && /* @__PURE__ */ jsx("span", {
|
|
2069
|
+
className: "min-w-0 truncate text-xs font-bold text-foreground",
|
|
2070
|
+
title: sb.customImage ?? sb.image,
|
|
2071
|
+
children: sb.customImage ?? sb.image
|
|
2072
|
+
})]
|
|
2073
|
+
})
|
|
2074
|
+
}),
|
|
2075
|
+
/* @__PURE__ */ jsx("td", {
|
|
2076
|
+
className: "hidden px-3 py-4 align-top xl:table-cell xl:px-4 xl:py-5",
|
|
2077
|
+
children: /* @__PURE__ */ jsx(SandboxResources, { sandbox: sb })
|
|
2078
|
+
}),
|
|
2079
|
+
/* @__PURE__ */ jsx("td", {
|
|
2080
|
+
className: "w-28 px-2 py-3 text-right align-top xl:w-72 xl:px-4 xl:py-5",
|
|
2081
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2082
|
+
className: "flex min-w-0 flex-wrap items-center justify-end gap-1",
|
|
2083
|
+
children: [
|
|
2084
|
+
isActive && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2085
|
+
/* @__PURE__ */ jsx("button", {
|
|
2058
2086
|
type: "button",
|
|
2059
2087
|
onClick: (e) => {
|
|
2060
2088
|
stopRowClick(e);
|
|
2061
|
-
|
|
2089
|
+
onOpenIDE?.(sb.id);
|
|
2062
2090
|
},
|
|
2063
|
-
className: "
|
|
2064
|
-
|
|
2065
|
-
|
|
2091
|
+
className: cn$1("min-h-11 min-w-11 shrink-0 p-2 rounded-lg hover:bg-surface-container-high text-muted-foreground hover:text-foreground transition-all active:scale-90", focusRing),
|
|
2092
|
+
"aria-label": "Open IDE",
|
|
2093
|
+
title: "Open IDE",
|
|
2094
|
+
children: /* @__PURE__ */ jsx(Code2, { className: "h-4 w-4" })
|
|
2066
2095
|
}),
|
|
2067
|
-
(
|
|
2068
|
-
const runItem = (handler) => (e) => {
|
|
2069
|
-
e.stopPropagation();
|
|
2070
|
-
handler(sb.id);
|
|
2071
|
-
};
|
|
2072
|
-
const overflowSections = [];
|
|
2073
|
-
if (isActive) {
|
|
2074
|
-
const lifecycle = [];
|
|
2075
|
-
if (onStop) lifecycle.push(/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2076
|
-
onClick: runItem(onStop),
|
|
2077
|
-
children: [/* @__PURE__ */ jsx(PowerOff, { className: "mr-2 h-4 w-4" }), " Stop Sandbox"]
|
|
2078
|
-
}, "stop"));
|
|
2079
|
-
if (onKeepAlive) lifecycle.push(/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2080
|
-
onClick: runItem(onKeepAlive),
|
|
2081
|
-
children: [/* @__PURE__ */ jsx(Clock, { className: "mr-2 h-4 w-4" }), " Keep Alive"]
|
|
2082
|
-
}, "keep-alive"));
|
|
2083
|
-
if (lifecycle.length) overflowSections.push(lifecycle);
|
|
2084
|
-
const observability = [];
|
|
2085
|
-
if (onUsage) observability.push(/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2086
|
-
onClick: runItem(onUsage),
|
|
2087
|
-
children: [/* @__PURE__ */ jsx(BarChart2, { className: "mr-2 h-4 w-4" }), " View Usage"]
|
|
2088
|
-
}, "usage"));
|
|
2089
|
-
if (onHealth) observability.push(/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2090
|
-
onClick: runItem(onHealth),
|
|
2091
|
-
children: [/* @__PURE__ */ jsx(Activity, { className: "mr-2 h-4 w-4" }), " Health Check"]
|
|
2092
|
-
}, "health"));
|
|
2093
|
-
if (observability.length) overflowSections.push(observability);
|
|
2094
|
-
if (onFork) overflowSections.push([/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2095
|
-
onClick: runItem(onFork),
|
|
2096
|
-
children: [/* @__PURE__ */ jsx(Copy, { className: "mr-2 h-4 w-4" }), " Fork Sandbox"]
|
|
2097
|
-
}, "fork")]);
|
|
2098
|
-
} else if (isResumable(sb.status)) {
|
|
2099
|
-
if (onFork) overflowSections.push([/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2100
|
-
onClick: runItem(onFork),
|
|
2101
|
-
children: [/* @__PURE__ */ jsx(Copy, { className: "mr-2 h-4 w-4" }), " Fork Sandbox"]
|
|
2102
|
-
}, "fork")]);
|
|
2103
|
-
}
|
|
2104
|
-
if (onMore) overflowSections.push([/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2105
|
-
onClick: runItem(onMore),
|
|
2106
|
-
children: [/* @__PURE__ */ jsx(ExternalLink, { className: "mr-2 h-4 w-4" }), " View Details"]
|
|
2107
|
-
}, "view-details")]);
|
|
2108
|
-
if (overflowSections.length === 0) return null;
|
|
2109
|
-
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
2110
|
-
asChild: true,
|
|
2111
|
-
children: /* @__PURE__ */ jsx("button", {
|
|
2112
|
-
type: "button",
|
|
2113
|
-
onClick: stopRowClick,
|
|
2114
|
-
className: `p-2 rounded-lg hover:bg-surface-container-high text-muted-foreground hover:text-foreground transition-all active:scale-90 ${focusRing}`,
|
|
2115
|
-
"aria-label": `More actions for ${sb.name}`,
|
|
2116
|
-
title: "More actions",
|
|
2117
|
-
children: /* @__PURE__ */ jsx(MoreVertical, { className: "h-4 w-4" })
|
|
2118
|
-
})
|
|
2119
|
-
}), /* @__PURE__ */ jsx(DropdownMenuContent, {
|
|
2120
|
-
align: "end",
|
|
2121
|
-
className: "min-w-[180px]",
|
|
2122
|
-
children: overflowSections.map((section, sectionIdx) => /* @__PURE__ */ jsxs(React$1.Fragment, { children: [sectionIdx > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}), section] }, sectionIdx))
|
|
2123
|
-
})] });
|
|
2124
|
-
})(),
|
|
2125
|
-
onDelete && canAdminSandbox(sb) && /* @__PURE__ */ jsx("button", {
|
|
2096
|
+
/* @__PURE__ */ jsx("button", {
|
|
2126
2097
|
type: "button",
|
|
2127
|
-
"aria-label": `Delete ${sb.name}`,
|
|
2128
2098
|
onClick: (e) => {
|
|
2129
2099
|
stopRowClick(e);
|
|
2130
|
-
|
|
2100
|
+
onOpenTerminal?.(sb.id);
|
|
2131
2101
|
},
|
|
2132
|
-
className:
|
|
2133
|
-
|
|
2134
|
-
|
|
2102
|
+
className: cn$1("min-h-11 min-w-11 shrink-0 p-2 rounded-lg hover:bg-surface-container-high text-muted-foreground hover:text-foreground transition-all active:scale-90", focusRing),
|
|
2103
|
+
"aria-label": "Open terminal",
|
|
2104
|
+
title: "Terminal",
|
|
2105
|
+
children: /* @__PURE__ */ jsx(Terminal, { className: "h-4 w-4" })
|
|
2106
|
+
}),
|
|
2107
|
+
/* @__PURE__ */ jsx("button", {
|
|
2108
|
+
type: "button",
|
|
2109
|
+
onClick: (e) => {
|
|
2110
|
+
stopRowClick(e);
|
|
2111
|
+
onSSH?.(sb.id);
|
|
2112
|
+
},
|
|
2113
|
+
className: cn$1("min-h-11 min-w-11 shrink-0 p-2 rounded-lg hover:bg-surface-container-high text-muted-foreground hover:text-foreground transition-all active:scale-90", focusRing),
|
|
2114
|
+
"aria-label": "Open SSH details",
|
|
2115
|
+
title: "SSH",
|
|
2116
|
+
children: /* @__PURE__ */ jsx(Key, { className: "h-4 w-4" })
|
|
2135
2117
|
})
|
|
2136
|
-
]
|
|
2137
|
-
|
|
2118
|
+
] }),
|
|
2119
|
+
resumeHandler && /* @__PURE__ */ jsxs("button", {
|
|
2120
|
+
type: "button",
|
|
2121
|
+
onClick: (e) => {
|
|
2122
|
+
stopRowClick(e);
|
|
2123
|
+
resumeHandler(sb.id);
|
|
2124
|
+
},
|
|
2125
|
+
className: cn$1("inline-flex min-h-11 items-center gap-1.5 px-3 py-1.5 rounded-lg border border-[var(--md3-outline-variant)] text-[var(--accent-text)] text-[10px] font-bold uppercase tracking-wider hover:bg-[var(--accent-surface-soft)] active:scale-95 transition-all", focusRing),
|
|
2126
|
+
title: resumeLabel,
|
|
2127
|
+
children: [/* @__PURE__ */ jsx(Play, { className: "h-3 w-3" }), resumeLabel]
|
|
2128
|
+
}),
|
|
2129
|
+
(() => {
|
|
2130
|
+
const runItem = (handler) => (e) => {
|
|
2131
|
+
e.stopPropagation();
|
|
2132
|
+
handler(sb.id);
|
|
2133
|
+
};
|
|
2134
|
+
const overflowSections = [];
|
|
2135
|
+
if (isActive) {
|
|
2136
|
+
const lifecycle = [];
|
|
2137
|
+
if (onStop) lifecycle.push(/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2138
|
+
onClick: runItem(onStop),
|
|
2139
|
+
children: [/* @__PURE__ */ jsx(PowerOff, { className: "mr-2 h-4 w-4" }), " Stop Sandbox"]
|
|
2140
|
+
}, "stop"));
|
|
2141
|
+
if (onKeepAlive) lifecycle.push(/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2142
|
+
onClick: runItem(onKeepAlive),
|
|
2143
|
+
children: [/* @__PURE__ */ jsx(Clock, { className: "mr-2 h-4 w-4" }), " Keep Alive"]
|
|
2144
|
+
}, "keep-alive"));
|
|
2145
|
+
if (lifecycle.length) overflowSections.push(lifecycle);
|
|
2146
|
+
const observability = [];
|
|
2147
|
+
if (onUsage) observability.push(/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2148
|
+
onClick: runItem(onUsage),
|
|
2149
|
+
children: [/* @__PURE__ */ jsx(BarChart2, { className: "mr-2 h-4 w-4" }), " View Usage"]
|
|
2150
|
+
}, "usage"));
|
|
2151
|
+
if (onHealth) observability.push(/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2152
|
+
onClick: runItem(onHealth),
|
|
2153
|
+
children: [/* @__PURE__ */ jsx(Activity, { className: "mr-2 h-4 w-4" }), " Health Check"]
|
|
2154
|
+
}, "health"));
|
|
2155
|
+
if (observability.length) overflowSections.push(observability);
|
|
2156
|
+
if (onFork) overflowSections.push([/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2157
|
+
onClick: runItem(onFork),
|
|
2158
|
+
children: [/* @__PURE__ */ jsx(Copy, { className: "mr-2 h-4 w-4" }), " Fork Sandbox"]
|
|
2159
|
+
}, "fork")]);
|
|
2160
|
+
} else if (isResumable(sb.status)) {
|
|
2161
|
+
if (onFork) overflowSections.push([/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2162
|
+
onClick: runItem(onFork),
|
|
2163
|
+
children: [/* @__PURE__ */ jsx(Copy, { className: "mr-2 h-4 w-4" }), " Fork Sandbox"]
|
|
2164
|
+
}, "fork")]);
|
|
2165
|
+
}
|
|
2166
|
+
if (onMore) overflowSections.push([/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
2167
|
+
onClick: runItem(onMore),
|
|
2168
|
+
children: [/* @__PURE__ */ jsx(ExternalLink, { className: "mr-2 h-4 w-4" }), " View Details"]
|
|
2169
|
+
}, "view-details")]);
|
|
2170
|
+
if (overflowSections.length === 0) return null;
|
|
2171
|
+
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
2172
|
+
asChild: true,
|
|
2173
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
2174
|
+
type: "button",
|
|
2175
|
+
onClick: stopRowClick,
|
|
2176
|
+
className: `min-h-11 min-w-11 shrink-0 p-2 rounded-lg hover:bg-surface-container-high text-muted-foreground hover:text-foreground transition-all active:scale-90 ${focusRing}`,
|
|
2177
|
+
"aria-label": `More actions for ${sb.name}`,
|
|
2178
|
+
title: "More actions",
|
|
2179
|
+
children: /* @__PURE__ */ jsx(MoreVertical, { className: "h-4 w-4" })
|
|
2180
|
+
})
|
|
2181
|
+
}), /* @__PURE__ */ jsx(DropdownMenuContent, {
|
|
2182
|
+
align: "end",
|
|
2183
|
+
className: "min-w-[180px]",
|
|
2184
|
+
children: overflowSections.map((section, sectionIdx) => /* @__PURE__ */ jsxs(React$1.Fragment, { children: [sectionIdx > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}), section] }, sectionIdx))
|
|
2185
|
+
})] });
|
|
2186
|
+
})(),
|
|
2187
|
+
onDelete && canAdminSandbox(sb) && /* @__PURE__ */ jsx("button", {
|
|
2188
|
+
type: "button",
|
|
2189
|
+
"aria-label": `Delete ${sb.name}`,
|
|
2190
|
+
onClick: (e) => {
|
|
2191
|
+
stopRowClick(e);
|
|
2192
|
+
onDelete(sb.id);
|
|
2193
|
+
},
|
|
2194
|
+
className: `min-h-11 min-w-11 shrink-0 p-2 rounded-lg hover:bg-[var(--surface-danger-bg)] text-muted-foreground hover:text-[var(--surface-danger-text)] transition-all active:scale-90 ${focusRing}`,
|
|
2195
|
+
title: "Delete",
|
|
2196
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "h-4 w-4" })
|
|
2197
|
+
})
|
|
2198
|
+
]
|
|
2138
2199
|
})
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
})
|
|
2142
|
-
})]
|
|
2143
|
-
})
|
|
2144
|
-
})
|
|
2145
|
-
}),
|
|
2146
|
-
totalPages > 1 && /* @__PURE__ */ jsxs("div", {
|
|
2147
|
-
className: "mt-6 flex flex-col md:flex-row justify-between items-center text-muted-foreground text-xs font-medium gap-4",
|
|
2148
|
-
children: [/* @__PURE__ */ jsxs("p", { children: [
|
|
2149
|
-
"Showing ",
|
|
2150
|
-
sandboxes.length,
|
|
2151
|
-
" of ",
|
|
2152
|
-
totalCount,
|
|
2153
|
-
" active sandboxes"
|
|
2154
|
-
] }), /* @__PURE__ */ jsxs("div", {
|
|
2155
|
-
className: "flex items-center gap-2",
|
|
2156
|
-
children: [
|
|
2157
|
-
/* @__PURE__ */ jsx("button", {
|
|
2158
|
-
type: "button",
|
|
2159
|
-
onClick: () => onPageChange?.(page - 1),
|
|
2160
|
-
disabled: page <= 1,
|
|
2161
|
-
className: "p-2 rounded-lg border border-[var(--md3-outline-variant)] hover:bg-surface-container-high transition-colors disabled:opacity-30",
|
|
2162
|
-
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
|
|
2163
|
-
}),
|
|
2164
|
-
Array.from({ length: Math.min(totalPages, 5) }, (_, i) => i + 1).map((p) => /* @__PURE__ */ jsx("button", {
|
|
2165
|
-
type: "button",
|
|
2166
|
-
onClick: () => onPageChange?.(p),
|
|
2167
|
-
className: cn$1("px-3 py-1 rounded-lg transition-colors", p === page ? "bg-[var(--accent-surface-soft)] text-primary border border-[var(--md3-outline)]" : "hover:bg-surface-container-high"),
|
|
2168
|
-
children: p
|
|
2169
|
-
}, p)),
|
|
2170
|
-
/* @__PURE__ */ jsx("button", {
|
|
2171
|
-
type: "button",
|
|
2172
|
-
onClick: () => onPageChange?.(page + 1),
|
|
2173
|
-
disabled: page >= totalPages,
|
|
2174
|
-
className: "p-2 rounded-lg border border-[var(--md3-outline-variant)] hover:bg-surface-container-high transition-colors disabled:opacity-30",
|
|
2175
|
-
children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
|
|
2200
|
+
})
|
|
2201
|
+
]
|
|
2202
|
+
}, sb.id);
|
|
2176
2203
|
})
|
|
2177
|
-
]
|
|
2178
|
-
})
|
|
2204
|
+
})]
|
|
2205
|
+
})
|
|
2179
2206
|
})
|
|
2180
|
-
|
|
2207
|
+
}), totalPages > 1 && /* @__PURE__ */ jsxs("div", {
|
|
2208
|
+
className: "mt-6 flex flex-col items-center justify-between gap-4 text-xs font-medium text-muted-foreground sm:flex-row",
|
|
2209
|
+
children: [/* @__PURE__ */ jsx("p", { children: rangeStart === 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2210
|
+
"Showing 0 of ",
|
|
2211
|
+
totalCount,
|
|
2212
|
+
" sandboxes"
|
|
2213
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2214
|
+
"Showing ",
|
|
2215
|
+
rangeStart,
|
|
2216
|
+
"-",
|
|
2217
|
+
rangeEnd,
|
|
2218
|
+
" of ",
|
|
2219
|
+
totalCount,
|
|
2220
|
+
" sandboxes"
|
|
2221
|
+
] }) }), /* @__PURE__ */ jsxs("nav", {
|
|
2222
|
+
className: "flex flex-wrap items-center justify-center gap-1",
|
|
2223
|
+
"aria-label": "Sandbox pages",
|
|
2224
|
+
children: [
|
|
2225
|
+
/* @__PURE__ */ jsx("button", {
|
|
2226
|
+
type: "button",
|
|
2227
|
+
onClick: () => onPageChange?.(currentPage - 1),
|
|
2228
|
+
disabled: !onPageChange || currentPage <= 1,
|
|
2229
|
+
"aria-label": "Previous page",
|
|
2230
|
+
className: cn$1("min-h-11 min-w-11 rounded-lg border border-[var(--md3-outline-variant)] p-2 transition-colors hover:bg-surface-container-high disabled:opacity-30", focusRing),
|
|
2231
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "h-4 w-4" })
|
|
2232
|
+
}),
|
|
2233
|
+
getPageItems(currentPage, totalPages).map((item) => typeof item === "number" ? /* @__PURE__ */ jsx("button", {
|
|
2234
|
+
type: "button",
|
|
2235
|
+
onClick: () => onPageChange?.(item),
|
|
2236
|
+
disabled: !onPageChange,
|
|
2237
|
+
"aria-label": "Go to page " + item,
|
|
2238
|
+
"aria-current": item === currentPage ? "page" : void 0,
|
|
2239
|
+
className: cn$1("min-h-11 min-w-11 rounded-lg px-2 py-1 transition-colors", item === currentPage ? "border border-[var(--md3-outline)] bg-[var(--accent-surface-soft)] text-[var(--accent-text)]" : "hover:bg-surface-container-high", !onPageChange && "cursor-not-allowed opacity-30"),
|
|
2240
|
+
children: item
|
|
2241
|
+
}, item) : /* @__PURE__ */ jsx("span", {
|
|
2242
|
+
className: "px-1",
|
|
2243
|
+
"aria-hidden": "true",
|
|
2244
|
+
children: "..."
|
|
2245
|
+
}, item)),
|
|
2246
|
+
/* @__PURE__ */ jsx("button", {
|
|
2247
|
+
type: "button",
|
|
2248
|
+
onClick: () => onPageChange?.(currentPage + 1),
|
|
2249
|
+
disabled: !onPageChange || currentPage >= totalPages,
|
|
2250
|
+
"aria-label": "Next page",
|
|
2251
|
+
className: cn$1("min-h-11 min-w-11 rounded-lg border border-[var(--md3-outline-variant)] p-2 transition-colors hover:bg-surface-container-high disabled:opacity-30", focusRing),
|
|
2252
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
|
|
2253
|
+
})
|
|
2254
|
+
]
|
|
2255
|
+
})]
|
|
2256
|
+
})]
|
|
2181
2257
|
});
|
|
2182
2258
|
}
|
|
2183
2259
|
//#endregion
|