@tangle-network/sandbox-ui 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth.d.ts +15 -1
- package/dist/auth.js +3 -1
- package/dist/chunk-HY5IBRCE.js +1171 -0
- package/dist/{chunk-COCSO7FG.js → chunk-PCTEG6HR.js} +69 -1
- package/dist/{chunk-67C53XVV.js → chunk-QGI5E7JD.js} +1 -1
- package/dist/dashboard.d.ts +3 -113
- package/dist/dashboard.js +13 -1
- package/dist/index-BOjBJwzD.d.ts +219 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +103 -6
- package/dist/pages.d.ts +25 -1
- package/dist/pages.js +541 -221
- package/dist/tokens.css +111 -1
- package/dist/workspace.d.ts +1 -1
- package/dist/workspace.js +1 -1
- package/package.json +1 -1
- package/tailwind.config.cjs +39 -0
- package/dist/chunk-OM6ON27W.js +0 -829
|
@@ -0,0 +1,1171 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Logo
|
|
3
|
+
} from "./chunk-OKCIKTXQ.js";
|
|
4
|
+
import {
|
|
5
|
+
DropdownMenu,
|
|
6
|
+
DropdownMenuContent,
|
|
7
|
+
DropdownMenuItem,
|
|
8
|
+
DropdownMenuLabel,
|
|
9
|
+
DropdownMenuSeparator,
|
|
10
|
+
DropdownMenuTrigger
|
|
11
|
+
} from "./chunk-MCGKDCOR.js";
|
|
12
|
+
import {
|
|
13
|
+
Skeleton
|
|
14
|
+
} from "./chunk-FRGMMANX.js";
|
|
15
|
+
import {
|
|
16
|
+
Badge
|
|
17
|
+
} from "./chunk-MXCSSOGH.js";
|
|
18
|
+
import {
|
|
19
|
+
Button
|
|
20
|
+
} from "./chunk-HWLX5NME.js";
|
|
21
|
+
import {
|
|
22
|
+
cn
|
|
23
|
+
} from "./chunk-RQHJBTEU.js";
|
|
24
|
+
|
|
25
|
+
// src/dashboard/app-sidebar.tsx
|
|
26
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
27
|
+
function MaterialIcon({ name, className }) {
|
|
28
|
+
return /* @__PURE__ */ jsx(
|
|
29
|
+
"span",
|
|
30
|
+
{
|
|
31
|
+
className: cn("material-symbols-outlined", className),
|
|
32
|
+
style: { fontVariationSettings: "'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24" },
|
|
33
|
+
children: name
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
function DefaultLink({
|
|
38
|
+
href,
|
|
39
|
+
to,
|
|
40
|
+
className,
|
|
41
|
+
children,
|
|
42
|
+
...rest
|
|
43
|
+
}) {
|
|
44
|
+
return /* @__PURE__ */ jsx("a", { href: href ?? to, className, ...rest, children });
|
|
45
|
+
}
|
|
46
|
+
function AppSidebar({
|
|
47
|
+
navItems,
|
|
48
|
+
activeNavId,
|
|
49
|
+
sandboxes = [],
|
|
50
|
+
activeSandboxId,
|
|
51
|
+
onSandboxChange,
|
|
52
|
+
onNewAgent,
|
|
53
|
+
className,
|
|
54
|
+
LinkComponent = DefaultLink
|
|
55
|
+
}) {
|
|
56
|
+
const Link = LinkComponent;
|
|
57
|
+
const activeSandbox = sandboxes.find((s) => s.id === activeSandboxId) ?? sandboxes[0];
|
|
58
|
+
return /* @__PURE__ */ jsxs(
|
|
59
|
+
"aside",
|
|
60
|
+
{
|
|
61
|
+
className: cn(
|
|
62
|
+
"h-screen w-64 fixed left-0 top-0 flex flex-col py-6 bg-slate-800/40 z-40 pt-20",
|
|
63
|
+
className
|
|
64
|
+
),
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ jsx("div", { className: "px-6 mb-8", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 p-3 rounded-xl bg-surface-container-low", children: [
|
|
67
|
+
/* @__PURE__ */ jsx("div", { className: "w-10 h-10 rounded-lg bg-primary-container flex items-center justify-center", children: /* @__PURE__ */ jsx(MaterialIcon, { name: "terminal", className: "text-on-primary-container text-sm" }) }),
|
|
68
|
+
/* @__PURE__ */ jsx("div", { className: "min-w-0", children: activeSandbox ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
69
|
+
/* @__PURE__ */ jsx("div", { className: "font-mono text-xs text-white font-bold tracking-tight truncate", children: activeSandbox.name }),
|
|
70
|
+
activeSandbox.label && /* @__PURE__ */ jsx("div", { className: "font-mono text-[10px] text-slate-500 truncate", children: activeSandbox.label })
|
|
71
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "font-mono text-xs text-slate-500", children: "No sandbox selected" }) })
|
|
72
|
+
] }) }),
|
|
73
|
+
/* @__PURE__ */ jsx("nav", { className: "flex-1 px-4 space-y-1", children: navItems.map((item) => {
|
|
74
|
+
const isActive = activeNavId === item.id;
|
|
75
|
+
return /* @__PURE__ */ jsxs(
|
|
76
|
+
Link,
|
|
77
|
+
{
|
|
78
|
+
href: item.href,
|
|
79
|
+
to: item.href,
|
|
80
|
+
className: cn(
|
|
81
|
+
"flex items-center gap-3 px-4 py-3 rounded-lg font-mono text-xs transition-colors",
|
|
82
|
+
isActive ? "bg-violet-500/10 text-violet-300 border-r-4 border-violet-500" : "text-slate-500 hover:bg-slate-800 hover:text-slate-300"
|
|
83
|
+
),
|
|
84
|
+
children: [
|
|
85
|
+
/* @__PURE__ */ jsx(MaterialIcon, { name: item.icon, className: "text-lg" }),
|
|
86
|
+
/* @__PURE__ */ jsx("span", { children: item.label }),
|
|
87
|
+
item.badge && /* @__PURE__ */ jsx("span", { className: "ml-auto px-2 py-0.5 rounded-full bg-primary-container text-on-primary text-[9px] font-bold", children: item.badge })
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
item.id
|
|
91
|
+
);
|
|
92
|
+
}) }),
|
|
93
|
+
/* @__PURE__ */ jsxs("div", { className: "px-4 py-4 mt-auto space-y-1 border-t border-outline-variant/10", children: [
|
|
94
|
+
onNewAgent && /* @__PURE__ */ jsxs(
|
|
95
|
+
"button",
|
|
96
|
+
{
|
|
97
|
+
type: "button",
|
|
98
|
+
onClick: onNewAgent,
|
|
99
|
+
className: "w-full flex items-center justify-center gap-2 bg-gradient-to-r from-md3-primary to-primary-container text-on-primary font-bold py-2.5 rounded-lg mb-4 text-xs active:scale-95 duration-200 transition-transform",
|
|
100
|
+
children: [
|
|
101
|
+
/* @__PURE__ */ jsx(MaterialIcon, { name: "add", className: "text-sm" }),
|
|
102
|
+
"New Agent"
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
),
|
|
106
|
+
/* @__PURE__ */ jsxs(
|
|
107
|
+
Link,
|
|
108
|
+
{
|
|
109
|
+
href: "/docs",
|
|
110
|
+
to: "/docs",
|
|
111
|
+
className: "flex items-center gap-3 px-4 py-2 rounded-lg text-slate-500 hover:bg-slate-800 hover:text-slate-300 transition-colors font-mono text-xs",
|
|
112
|
+
children: [
|
|
113
|
+
/* @__PURE__ */ jsx(MaterialIcon, { name: "menu_book", className: "text-sm" }),
|
|
114
|
+
"Documentation"
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
),
|
|
118
|
+
/* @__PURE__ */ jsxs(
|
|
119
|
+
Link,
|
|
120
|
+
{
|
|
121
|
+
href: "/support",
|
|
122
|
+
to: "/support",
|
|
123
|
+
className: "flex items-center gap-3 px-4 py-2 rounded-lg text-slate-500 hover:bg-slate-800 hover:text-slate-300 transition-colors font-mono text-xs",
|
|
124
|
+
children: [
|
|
125
|
+
/* @__PURE__ */ jsx(MaterialIcon, { name: "contact_support", className: "text-sm" }),
|
|
126
|
+
"Support"
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
] })
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/dashboard/cluster-status-bar.tsx
|
|
137
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
138
|
+
function MaterialIcon2({ name, className }) {
|
|
139
|
+
return /* @__PURE__ */ jsx2("span", { className: cn("material-symbols-outlined", className), style: { fontVariationSettings: "'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24" }, children: name });
|
|
140
|
+
}
|
|
141
|
+
function ClusterStatusBar({ items, latency, className }) {
|
|
142
|
+
return /* @__PURE__ */ jsxs2(
|
|
143
|
+
"footer",
|
|
144
|
+
{
|
|
145
|
+
className: cn(
|
|
146
|
+
"fixed bottom-0 left-0 lg:left-64 right-0 h-10 bg-surface-container-highest/80 backdrop-blur-md border-t border-outline-variant/5 flex items-center justify-between px-6 z-30",
|
|
147
|
+
className
|
|
148
|
+
),
|
|
149
|
+
children: [
|
|
150
|
+
/* @__PURE__ */ jsx2("div", { className: "flex items-center gap-6 overflow-x-auto whitespace-nowrap", children: items.map((item, i) => /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
151
|
+
/* @__PURE__ */ jsx2(MaterialIcon2, { name: item.icon, className: "text-[14px] text-md3-primary" }),
|
|
152
|
+
/* @__PURE__ */ jsxs2("span", { className: "text-[10px] font-mono text-on-surface-variant", children: [
|
|
153
|
+
item.label,
|
|
154
|
+
": ",
|
|
155
|
+
/* @__PURE__ */ jsx2("span", { className: cn("text-white", item.valueClass), children: item.value })
|
|
156
|
+
] })
|
|
157
|
+
] }, i)) }),
|
|
158
|
+
latency && /* @__PURE__ */ jsxs2("div", { className: "hidden sm:flex items-center gap-2", children: [
|
|
159
|
+
/* @__PURE__ */ jsxs2("span", { className: "text-[10px] font-mono text-on-surface-variant", children: [
|
|
160
|
+
"System Latency: ",
|
|
161
|
+
/* @__PURE__ */ jsx2("span", { className: "text-white", children: latency })
|
|
162
|
+
] }),
|
|
163
|
+
/* @__PURE__ */ jsxs2("div", { className: "flex gap-0.5 h-3 items-end", children: [
|
|
164
|
+
/* @__PURE__ */ jsx2("div", { className: "w-0.5 h-1 bg-md3-primary" }),
|
|
165
|
+
/* @__PURE__ */ jsx2("div", { className: "w-0.5 h-2 bg-md3-primary" }),
|
|
166
|
+
/* @__PURE__ */ jsx2("div", { className: "w-0.5 h-1.5 bg-md3-primary" }),
|
|
167
|
+
/* @__PURE__ */ jsx2("div", { className: "w-0.5 h-3 bg-md3-primary" }),
|
|
168
|
+
/* @__PURE__ */ jsx2("div", { className: "w-0.5 h-2.5 bg-md3-primary" })
|
|
169
|
+
] })
|
|
170
|
+
] })
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/dashboard/dashboard-layout.tsx
|
|
177
|
+
import * as React from "react";
|
|
178
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
179
|
+
var variantStyles = {
|
|
180
|
+
sandbox: {
|
|
181
|
+
activeNav: "bg-[var(--accent-surface-soft)] text-[var(--accent-text)]",
|
|
182
|
+
userGradient: "bg-[image:var(--accent-gradient-strong)]"
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
function DefaultLink2({
|
|
186
|
+
href,
|
|
187
|
+
to,
|
|
188
|
+
className,
|
|
189
|
+
children,
|
|
190
|
+
...rest
|
|
191
|
+
}) {
|
|
192
|
+
return /* @__PURE__ */ jsx3("a", { href: href ?? to, className, ...rest, children });
|
|
193
|
+
}
|
|
194
|
+
function UserIcon({ className }) {
|
|
195
|
+
return /* @__PURE__ */ jsxs3("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
196
|
+
/* @__PURE__ */ jsx3("title", { children: "User icon" }),
|
|
197
|
+
/* @__PURE__ */ jsx3("path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" }),
|
|
198
|
+
/* @__PURE__ */ jsx3("circle", { cx: "12", cy: "7", r: "4" })
|
|
199
|
+
] });
|
|
200
|
+
}
|
|
201
|
+
function SettingsIcon({ className }) {
|
|
202
|
+
return /* @__PURE__ */ jsxs3("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
203
|
+
/* @__PURE__ */ jsx3("title", { children: "Settings icon" }),
|
|
204
|
+
/* @__PURE__ */ jsx3("path", { d: "M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" }),
|
|
205
|
+
/* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "3" })
|
|
206
|
+
] });
|
|
207
|
+
}
|
|
208
|
+
function LogOutIcon({ className }) {
|
|
209
|
+
return /* @__PURE__ */ jsxs3("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
210
|
+
/* @__PURE__ */ jsx3("title", { children: "Log out icon" }),
|
|
211
|
+
/* @__PURE__ */ jsx3("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
|
|
212
|
+
/* @__PURE__ */ jsx3("polyline", { points: "16,17 21,12 16,7" }),
|
|
213
|
+
/* @__PURE__ */ jsx3("line", { x1: "21", x2: "9", y1: "12", y2: "12" })
|
|
214
|
+
] });
|
|
215
|
+
}
|
|
216
|
+
function MaterialIcon3({ name, className }) {
|
|
217
|
+
return /* @__PURE__ */ jsx3(
|
|
218
|
+
"span",
|
|
219
|
+
{
|
|
220
|
+
className: cn("material-symbols-outlined", className),
|
|
221
|
+
style: { fontVariationSettings: "'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24" },
|
|
222
|
+
children: name
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
function MenuIcon({ className }) {
|
|
227
|
+
return /* @__PURE__ */ jsxs3("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
228
|
+
/* @__PURE__ */ jsx3("title", { children: "Menu icon" }),
|
|
229
|
+
/* @__PURE__ */ jsx3("line", { x1: "4", x2: "20", y1: "12", y2: "12" }),
|
|
230
|
+
/* @__PURE__ */ jsx3("line", { x1: "4", x2: "20", y1: "6", y2: "6" }),
|
|
231
|
+
/* @__PURE__ */ jsx3("line", { x1: "4", x2: "20", y1: "18", y2: "18" })
|
|
232
|
+
] });
|
|
233
|
+
}
|
|
234
|
+
function XIcon({ className }) {
|
|
235
|
+
return /* @__PURE__ */ jsxs3("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className, children: [
|
|
236
|
+
/* @__PURE__ */ jsx3("title", { children: "Close icon" }),
|
|
237
|
+
/* @__PURE__ */ jsx3("path", { d: "M18 6 6 18" }),
|
|
238
|
+
/* @__PURE__ */ jsx3("path", { d: "m6 6 12 12" })
|
|
239
|
+
] });
|
|
240
|
+
}
|
|
241
|
+
function DashboardLayout({
|
|
242
|
+
children,
|
|
243
|
+
variant = "sandbox",
|
|
244
|
+
navItems,
|
|
245
|
+
activeNavId,
|
|
246
|
+
user,
|
|
247
|
+
isLoading = false,
|
|
248
|
+
onLogout,
|
|
249
|
+
onSettingsClick,
|
|
250
|
+
settingsHref = "/dashboard/settings",
|
|
251
|
+
onNewSandbox,
|
|
252
|
+
className,
|
|
253
|
+
sidebarClassName,
|
|
254
|
+
contentClassName,
|
|
255
|
+
topNavLinks,
|
|
256
|
+
activeTopNavHref,
|
|
257
|
+
sandboxName,
|
|
258
|
+
sandboxLabel,
|
|
259
|
+
LinkComponent = DefaultLink2,
|
|
260
|
+
footer
|
|
261
|
+
}) {
|
|
262
|
+
const styles = variantStyles[variant];
|
|
263
|
+
const Link = LinkComponent;
|
|
264
|
+
const [mobileMenuOpen, setMobileMenuOpen] = React.useState(false);
|
|
265
|
+
const handleNavClick = () => {
|
|
266
|
+
setMobileMenuOpen(false);
|
|
267
|
+
};
|
|
268
|
+
const SidebarContent = () => /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
269
|
+
/* @__PURE__ */ jsx3("div", { className: "px-6 mb-8", children: /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-3 p-3 rounded-xl bg-surface-container-low", children: [
|
|
270
|
+
/* @__PURE__ */ jsx3("div", { className: "w-10 h-10 rounded-lg bg-primary-container flex items-center justify-center", children: /* @__PURE__ */ jsx3(MaterialIcon3, { name: "terminal", className: "text-on-primary-container text-sm" }) }),
|
|
271
|
+
/* @__PURE__ */ jsx3("div", { className: "min-w-0", children: sandboxName ? /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
272
|
+
/* @__PURE__ */ jsx3("div", { className: "font-mono text-xs text-white font-bold tracking-tight truncate", children: sandboxName }),
|
|
273
|
+
sandboxLabel && /* @__PURE__ */ jsx3("div", { className: "font-mono text-[10px] text-slate-500 truncate", children: sandboxLabel })
|
|
274
|
+
] }) : /* @__PURE__ */ jsx3("div", { className: "font-mono text-xs text-slate-500", children: "No sandbox selected" }) })
|
|
275
|
+
] }) }),
|
|
276
|
+
/* @__PURE__ */ jsx3("nav", { className: "flex-1 px-4 space-y-1", "aria-label": "Main navigation", children: navItems.map((item) => {
|
|
277
|
+
const isActive = activeNavId === item.id;
|
|
278
|
+
return /* @__PURE__ */ jsxs3(
|
|
279
|
+
Link,
|
|
280
|
+
{
|
|
281
|
+
href: item.href,
|
|
282
|
+
to: item.href,
|
|
283
|
+
onClick: handleNavClick,
|
|
284
|
+
"aria-current": isActive ? "page" : void 0,
|
|
285
|
+
className: cn(
|
|
286
|
+
"flex items-center gap-3 px-4 py-3 rounded-lg font-mono text-xs transition-colors",
|
|
287
|
+
isActive ? "bg-violet-500/10 text-violet-300 border-r-4 border-violet-500" : "text-slate-500 hover:bg-slate-800 hover:text-slate-300"
|
|
288
|
+
),
|
|
289
|
+
children: [
|
|
290
|
+
item.materialIcon ? /* @__PURE__ */ jsx3(MaterialIcon3, { name: item.materialIcon, className: "text-lg" }) : /* @__PURE__ */ jsx3(item.icon, { className: "h-5 w-5", "aria-hidden": "true" }),
|
|
291
|
+
/* @__PURE__ */ jsx3("span", { children: item.label })
|
|
292
|
+
]
|
|
293
|
+
},
|
|
294
|
+
item.id
|
|
295
|
+
);
|
|
296
|
+
}) }),
|
|
297
|
+
/* @__PURE__ */ jsxs3("div", { className: "px-4 py-4 mt-auto space-y-1 border-t border-outline-variant/10", children: [
|
|
298
|
+
/* @__PURE__ */ jsxs3(
|
|
299
|
+
"button",
|
|
300
|
+
{
|
|
301
|
+
type: "button",
|
|
302
|
+
onClick: onNewSandbox,
|
|
303
|
+
className: "w-full flex items-center justify-center gap-2 bg-gradient-to-r from-md3-primary to-primary-container text-on-primary font-bold py-2.5 rounded-lg mb-4 text-xs active:scale-95 duration-200 transition-transform",
|
|
304
|
+
children: [
|
|
305
|
+
/* @__PURE__ */ jsx3(MaterialIcon3, { name: "add", className: "text-sm" }),
|
|
306
|
+
"New Agent"
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
),
|
|
310
|
+
/* @__PURE__ */ jsxs3(
|
|
311
|
+
Link,
|
|
312
|
+
{
|
|
313
|
+
href: "/docs",
|
|
314
|
+
to: "/docs",
|
|
315
|
+
className: "flex items-center gap-3 px-4 py-2 rounded-lg text-slate-500 hover:bg-slate-800 hover:text-slate-300 transition-colors font-mono text-xs",
|
|
316
|
+
children: [
|
|
317
|
+
/* @__PURE__ */ jsx3(MaterialIcon3, { name: "menu_book", className: "text-sm" }),
|
|
318
|
+
"Documentation"
|
|
319
|
+
]
|
|
320
|
+
}
|
|
321
|
+
),
|
|
322
|
+
/* @__PURE__ */ jsxs3(
|
|
323
|
+
Link,
|
|
324
|
+
{
|
|
325
|
+
href: "/support",
|
|
326
|
+
to: "/support",
|
|
327
|
+
className: "flex items-center gap-3 px-4 py-2 rounded-lg text-slate-500 hover:bg-slate-800 hover:text-slate-300 transition-colors font-mono text-xs",
|
|
328
|
+
children: [
|
|
329
|
+
/* @__PURE__ */ jsx3(MaterialIcon3, { name: "contact_support", className: "text-sm" }),
|
|
330
|
+
"Support"
|
|
331
|
+
]
|
|
332
|
+
}
|
|
333
|
+
)
|
|
334
|
+
] })
|
|
335
|
+
] });
|
|
336
|
+
return /* @__PURE__ */ jsxs3("div", { className: cn("min-h-screen bg-surface text-on-surface", className), children: [
|
|
337
|
+
/* @__PURE__ */ jsxs3("nav", { className: "fixed top-0 w-full z-50 bg-slate-950/60 backdrop-blur-xl flex justify-between items-center px-8 h-16 font-sans text-sm tracking-tight", children: [
|
|
338
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-8", children: [
|
|
339
|
+
/* @__PURE__ */ jsx3(Logo, { variant, size: "md", className: "hidden md:block" }),
|
|
340
|
+
topNavLinks && topNavLinks.length > 0 && /* @__PURE__ */ jsx3("div", { className: "hidden md:flex gap-6", children: topNavLinks.map((link) => /* @__PURE__ */ jsx3(
|
|
341
|
+
Link,
|
|
342
|
+
{
|
|
343
|
+
href: link.href,
|
|
344
|
+
to: link.href,
|
|
345
|
+
className: cn(
|
|
346
|
+
"transition-all duration-300 px-2 py-1 rounded",
|
|
347
|
+
activeTopNavHref === link.href ? "text-white border-b-2 border-violet-500 pb-1" : "text-slate-400 hover:text-slate-200 hover:bg-white/5"
|
|
348
|
+
),
|
|
349
|
+
children: link.label
|
|
350
|
+
},
|
|
351
|
+
link.href
|
|
352
|
+
)) })
|
|
353
|
+
] }),
|
|
354
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-4", children: [
|
|
355
|
+
onNewSandbox && /* @__PURE__ */ jsxs3(
|
|
356
|
+
"button",
|
|
357
|
+
{
|
|
358
|
+
type: "button",
|
|
359
|
+
onClick: onNewSandbox,
|
|
360
|
+
className: "hidden md:flex items-center gap-2 bg-md3-primary text-on-primary px-4 py-2 rounded-lg font-bold hover:shadow-[0_0_15px_rgba(209,188,255,0.4)] transition-all active:scale-95 text-xs",
|
|
361
|
+
children: [
|
|
362
|
+
/* @__PURE__ */ jsx3(MaterialIcon3, { name: "add", className: "text-sm" }),
|
|
363
|
+
"New Sandbox"
|
|
364
|
+
]
|
|
365
|
+
}
|
|
366
|
+
),
|
|
367
|
+
/* @__PURE__ */ jsx3("button", { type: "button", className: "text-slate-400 hover:text-violet-400 transition-colors p-2 rounded-lg hover:bg-white/5", children: /* @__PURE__ */ jsx3(MaterialIcon3, { name: "notifications" }) }),
|
|
368
|
+
onSettingsClick ? /* @__PURE__ */ jsx3("button", { type: "button", onClick: onSettingsClick, className: "text-slate-400 hover:text-violet-400 transition-colors p-2 rounded-lg hover:bg-white/5", children: /* @__PURE__ */ jsx3(MaterialIcon3, { name: "settings" }) }) : /* @__PURE__ */ jsx3(Link, { href: settingsHref, to: settingsHref, className: "text-slate-400 hover:text-violet-400 transition-colors p-2 rounded-lg hover:bg-white/5", children: /* @__PURE__ */ jsx3(MaterialIcon3, { name: "settings" }) }),
|
|
369
|
+
/* @__PURE__ */ jsxs3(DropdownMenu, { children: [
|
|
370
|
+
/* @__PURE__ */ jsx3(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx3("button", { type: "button", className: "w-8 h-8 rounded-full bg-surface-container-highest flex items-center justify-center border border-outline-variant/20 overflow-hidden", "aria-label": "User menu", children: user?.avatarUrl ? /* @__PURE__ */ jsx3("img", { src: user.avatarUrl, alt: "", className: "w-full h-full object-cover" }) : /* @__PURE__ */ jsx3(UserIcon, { className: "h-4 w-4 text-on-surface-variant" }) }) }),
|
|
371
|
+
/* @__PURE__ */ jsxs3(DropdownMenuContent, { align: "end", className: "w-56", children: [
|
|
372
|
+
/* @__PURE__ */ jsx3(DropdownMenuLabel, { children: isLoading ? /* @__PURE__ */ jsx3(Skeleton, { className: "h-4 w-24" }) : /* @__PURE__ */ jsxs3("div", { children: [
|
|
373
|
+
/* @__PURE__ */ jsx3("p", { className: "truncate text-sm", children: user?.email ?? "Not logged in" }),
|
|
374
|
+
/* @__PURE__ */ jsxs3("p", { className: "text-muted-foreground text-xs capitalize", children: [
|
|
375
|
+
user?.tier ?? "Free",
|
|
376
|
+
" Plan"
|
|
377
|
+
] })
|
|
378
|
+
] }) }),
|
|
379
|
+
/* @__PURE__ */ jsx3(DropdownMenuSeparator, {}),
|
|
380
|
+
onSettingsClick ? /* @__PURE__ */ jsxs3(DropdownMenuItem, { onClick: onSettingsClick, children: [
|
|
381
|
+
/* @__PURE__ */ jsx3(SettingsIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
|
|
382
|
+
"Settings"
|
|
383
|
+
] }) : /* @__PURE__ */ jsx3(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs3(Link, { href: settingsHref, to: settingsHref, className: "flex items-center", children: [
|
|
384
|
+
/* @__PURE__ */ jsx3(SettingsIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
|
|
385
|
+
"Settings"
|
|
386
|
+
] }) }),
|
|
387
|
+
onLogout && /* @__PURE__ */ jsxs3(DropdownMenuItem, { className: "text-red-400", onClick: onLogout, children: [
|
|
388
|
+
/* @__PURE__ */ jsx3(LogOutIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
|
|
389
|
+
"Sign Out"
|
|
390
|
+
] })
|
|
391
|
+
] })
|
|
392
|
+
] })
|
|
393
|
+
] }),
|
|
394
|
+
/* @__PURE__ */ jsx3(
|
|
395
|
+
"button",
|
|
396
|
+
{
|
|
397
|
+
type: "button",
|
|
398
|
+
onClick: () => setMobileMenuOpen(!mobileMenuOpen),
|
|
399
|
+
className: "rounded-md p-2 hover:bg-white/5 md:hidden",
|
|
400
|
+
"aria-label": mobileMenuOpen ? "Close menu" : "Open menu",
|
|
401
|
+
"aria-expanded": mobileMenuOpen,
|
|
402
|
+
children: mobileMenuOpen ? /* @__PURE__ */ jsx3(XIcon, { className: "h-6 w-6" }) : /* @__PURE__ */ jsx3(MenuIcon, { className: "h-6 w-6" })
|
|
403
|
+
}
|
|
404
|
+
)
|
|
405
|
+
] }),
|
|
406
|
+
mobileMenuOpen && /* @__PURE__ */ jsx3("div", { className: "fixed inset-0 z-30 bg-black/50 md:hidden", onClick: () => setMobileMenuOpen(false), "aria-hidden": "true" }),
|
|
407
|
+
/* @__PURE__ */ jsx3(
|
|
408
|
+
"aside",
|
|
409
|
+
{
|
|
410
|
+
className: cn(
|
|
411
|
+
"fixed top-16 bottom-0 left-0 z-30 flex w-64 flex-col bg-slate-900/95 backdrop-blur-xl transition-transform duration-200 lg:hidden",
|
|
412
|
+
sidebarClassName,
|
|
413
|
+
mobileMenuOpen ? "translate-x-0" : "-translate-x-full"
|
|
414
|
+
),
|
|
415
|
+
children: /* @__PURE__ */ jsx3(SidebarContent, {})
|
|
416
|
+
}
|
|
417
|
+
),
|
|
418
|
+
/* @__PURE__ */ jsx3(
|
|
419
|
+
"aside",
|
|
420
|
+
{
|
|
421
|
+
className: cn(
|
|
422
|
+
"hidden lg:flex h-screen w-64 fixed left-0 top-0 flex-col py-6 bg-slate-800/40 z-40 pt-20",
|
|
423
|
+
sidebarClassName
|
|
424
|
+
),
|
|
425
|
+
children: /* @__PURE__ */ jsx3(SidebarContent, {})
|
|
426
|
+
}
|
|
427
|
+
),
|
|
428
|
+
/* @__PURE__ */ jsx3("main", { className: cn("lg:ml-64 pt-24 px-8 pb-12 min-h-screen", contentClassName), children }),
|
|
429
|
+
footer
|
|
430
|
+
] });
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// src/dashboard/resource-meter.tsx
|
|
434
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
435
|
+
function getColorByUsage(percent) {
|
|
436
|
+
if (percent >= 90) return "from-red-500 to-red-300";
|
|
437
|
+
if (percent >= 70) return "from-yellow-500 to-yellow-300";
|
|
438
|
+
if (percent >= 40) return "from-blue-500 to-blue-300";
|
|
439
|
+
return "from-green-500 to-green-300";
|
|
440
|
+
}
|
|
441
|
+
function MaterialIcon4({ name, className }) {
|
|
442
|
+
return /* @__PURE__ */ jsx4("span", { className: cn("material-symbols-outlined", className), style: { fontVariationSettings: "'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24" }, children: name });
|
|
443
|
+
}
|
|
444
|
+
function ResourceMeter({ label, value, max = 100, unit, icon, className }) {
|
|
445
|
+
const percent = max > 0 ? Math.min(value / max * 100, 100) : 0;
|
|
446
|
+
const gradient = getColorByUsage(percent);
|
|
447
|
+
return /* @__PURE__ */ jsxs4("div", { className: cn("space-y-2", className), children: [
|
|
448
|
+
/* @__PURE__ */ jsxs4("div", { className: "flex justify-between text-[11px] font-bold font-mono text-on-surface uppercase tracking-tight", children: [
|
|
449
|
+
/* @__PURE__ */ jsxs4("span", { className: "flex items-center gap-1", children: [
|
|
450
|
+
icon && /* @__PURE__ */ jsx4(MaterialIcon4, { name: icon, className: "text-xs" }),
|
|
451
|
+
label
|
|
452
|
+
] }),
|
|
453
|
+
/* @__PURE__ */ jsx4("span", { className: "text-primary-fixed-dim", children: unit ? `${value}${unit} / ${max}${unit}` : `${Math.round(percent)}%` })
|
|
454
|
+
] }),
|
|
455
|
+
/* @__PURE__ */ jsx4("div", { className: "h-2 w-full bg-surface-container-highest rounded-full overflow-hidden", children: /* @__PURE__ */ jsx4(
|
|
456
|
+
"div",
|
|
457
|
+
{
|
|
458
|
+
className: cn("h-full bg-gradient-to-r rounded-full transition-all duration-500", gradient),
|
|
459
|
+
style: { width: `${percent}%` }
|
|
460
|
+
}
|
|
461
|
+
) })
|
|
462
|
+
] });
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// src/dashboard/sandbox-card.tsx
|
|
466
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
467
|
+
function MaterialIcon5({ name, className }) {
|
|
468
|
+
return /* @__PURE__ */ jsx5("span", { className: cn("material-symbols-outlined", className), style: { fontVariationSettings: "'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24" }, children: name });
|
|
469
|
+
}
|
|
470
|
+
var statusConfig = {
|
|
471
|
+
running: { color: "text-green-400", bgColor: "bg-green-500/10", borderColor: "border-green-500/20", dotClass: "bg-green-400 animate-pulse", label: "Running" },
|
|
472
|
+
hibernating: { color: "text-blue-400", bgColor: "bg-blue-500/10", borderColor: "border-blue-500/20", dotClass: "bg-slate-500", label: "Hibernating" },
|
|
473
|
+
provisioning: { color: "text-orange-400", bgColor: "bg-orange-500/10", borderColor: "border-orange-500/20", dotClass: "bg-orange-500 animate-ping", label: "Provisioning" },
|
|
474
|
+
stopped: { color: "text-slate-400", bgColor: "bg-slate-500/10", borderColor: "border-slate-500/20", dotClass: "bg-slate-500", label: "Stopped" },
|
|
475
|
+
failed: { color: "text-red-400", bgColor: "bg-red-500/10", borderColor: "border-red-500/20", dotClass: "bg-red-500", label: "Failed" },
|
|
476
|
+
archived: { color: "text-slate-400", bgColor: "bg-slate-500/10", borderColor: "border-slate-500/20", dotClass: "bg-slate-600", label: "Archived" }
|
|
477
|
+
};
|
|
478
|
+
var glowMap = {
|
|
479
|
+
node: "shadow-[0_0_20px_-5px_rgba(34,197,94,0.15)] border border-green-500/20",
|
|
480
|
+
python: "shadow-[0_0_20px_-5px_rgba(59,130,246,0.15)] border border-blue-500/20",
|
|
481
|
+
ubuntu: "shadow-[0_0_20px_-5px_rgba(234,88,12,0.15)] border border-orange-500/20"
|
|
482
|
+
};
|
|
483
|
+
function getGlow(image) {
|
|
484
|
+
if (!image) return "";
|
|
485
|
+
const lower = image.toLowerCase();
|
|
486
|
+
for (const [key, cls] of Object.entries(glowMap)) {
|
|
487
|
+
if (lower.includes(key)) return cls;
|
|
488
|
+
}
|
|
489
|
+
return "";
|
|
490
|
+
}
|
|
491
|
+
function SandboxCard({ sandbox, onOpenIDE, onOpenTerminal, onWake, onRestore, className }) {
|
|
492
|
+
const status = statusConfig[sandbox.status] ?? statusConfig.stopped;
|
|
493
|
+
const glow = getGlow(sandbox.image);
|
|
494
|
+
const isActive = sandbox.status === "running";
|
|
495
|
+
const isHibernating = sandbox.status === "hibernating";
|
|
496
|
+
const isProvisioning = sandbox.status === "provisioning";
|
|
497
|
+
const isArchived = sandbox.status === "archived";
|
|
498
|
+
return /* @__PURE__ */ jsxs5(
|
|
499
|
+
"div",
|
|
500
|
+
{
|
|
501
|
+
className: cn(
|
|
502
|
+
"bg-surface-container-low rounded-xl p-6 relative overflow-hidden group hover:bg-surface-container transition-all duration-300",
|
|
503
|
+
glow,
|
|
504
|
+
isArchived && "opacity-60 hover:opacity-100 bg-surface-container-lowest",
|
|
505
|
+
className
|
|
506
|
+
),
|
|
507
|
+
children: [
|
|
508
|
+
/* @__PURE__ */ jsx5("div", { className: "absolute top-0 right-0 p-4", children: /* @__PURE__ */ jsxs5("span", { className: cn("flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-black tracking-widest uppercase border", status.bgColor, status.color, status.borderColor), children: [
|
|
509
|
+
/* @__PURE__ */ jsx5("span", { className: cn("w-2 h-2 rounded-full", status.dotClass) }),
|
|
510
|
+
status.label
|
|
511
|
+
] }) }),
|
|
512
|
+
/* @__PURE__ */ jsx5("div", { className: "mb-6", children: /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3 mb-2", children: [
|
|
513
|
+
sandbox.imageIcon && /* @__PURE__ */ jsx5("div", { className: "w-10 h-10 rounded-lg flex items-center justify-center bg-surface-container-high", children: sandbox.imageIcon }),
|
|
514
|
+
/* @__PURE__ */ jsxs5("div", { className: "min-w-0", children: [
|
|
515
|
+
/* @__PURE__ */ jsx5("h3", { className: "text-xl font-bold text-white group-hover:text-md3-primary transition-colors truncate", children: sandbox.name }),
|
|
516
|
+
sandbox.nodeId && /* @__PURE__ */ jsx5("p", { className: "text-on-surface-variant font-mono text-xs truncate", children: sandbox.nodeId })
|
|
517
|
+
] })
|
|
518
|
+
] }) }),
|
|
519
|
+
isProvisioning ? /* @__PURE__ */ jsxs5("div", { className: "mb-8 mt-10", children: [
|
|
520
|
+
/* @__PURE__ */ jsx5("p", { className: "text-[10px] font-bold font-mono text-orange-400 mb-3 uppercase text-center animate-pulse tracking-widest", children: sandbox.provisioningMessage ?? "Initializing..." }),
|
|
521
|
+
/* @__PURE__ */ jsx5("div", { className: "h-2 w-full bg-surface-container-highest rounded-full overflow-hidden", children: /* @__PURE__ */ jsx5(
|
|
522
|
+
"div",
|
|
523
|
+
{
|
|
524
|
+
className: "h-full bg-gradient-to-r from-orange-600 via-orange-400 to-orange-300 transition-all duration-500",
|
|
525
|
+
style: { width: `${sandbox.provisioningPercent ?? 50}%` }
|
|
526
|
+
}
|
|
527
|
+
) })
|
|
528
|
+
] }) : !isArchived ? /* @__PURE__ */ jsxs5("div", { className: cn("space-y-5 mb-8", !isActive && "opacity-40"), children: [
|
|
529
|
+
/* @__PURE__ */ jsx5(ResourceMeter, { label: "CPU Usage", icon: "memory", value: sandbox.cpuPercent ?? 0 }),
|
|
530
|
+
/* @__PURE__ */ jsx5(
|
|
531
|
+
ResourceMeter,
|
|
532
|
+
{
|
|
533
|
+
label: "RAM Usage",
|
|
534
|
+
icon: "database",
|
|
535
|
+
value: sandbox.ramUsed ?? 0,
|
|
536
|
+
max: sandbox.ramTotal ?? 1,
|
|
537
|
+
unit: "GB"
|
|
538
|
+
}
|
|
539
|
+
)
|
|
540
|
+
] }) : /* @__PURE__ */ jsx5("div", { className: "mb-6", children: sandbox.archivedAt && /* @__PURE__ */ jsx5("p", { className: "text-slate-500 font-mono text-[10px]", children: sandbox.archivedAt }) }),
|
|
541
|
+
isActive && /* @__PURE__ */ jsxs5("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
542
|
+
/* @__PURE__ */ jsxs5(
|
|
543
|
+
"button",
|
|
544
|
+
{
|
|
545
|
+
type: "button",
|
|
546
|
+
onClick: () => onOpenIDE?.(sandbox.id),
|
|
547
|
+
className: "flex items-center justify-center gap-2 py-2.5 bg-surface-container-high hover:bg-md3-primary hover:text-on-primary rounded-lg transition-all duration-300 text-xs font-bold shadow-sm",
|
|
548
|
+
children: [
|
|
549
|
+
/* @__PURE__ */ jsx5(MaterialIcon5, { name: "open_in_new", className: "text-sm" }),
|
|
550
|
+
"Open IDE"
|
|
551
|
+
]
|
|
552
|
+
}
|
|
553
|
+
),
|
|
554
|
+
/* @__PURE__ */ jsxs5(
|
|
555
|
+
"button",
|
|
556
|
+
{
|
|
557
|
+
type: "button",
|
|
558
|
+
onClick: () => onOpenTerminal?.(sandbox.id),
|
|
559
|
+
className: "flex items-center justify-center gap-2 py-2.5 bg-surface-container-high hover:bg-slate-700 rounded-lg transition-all text-xs font-bold border border-outline-variant/10",
|
|
560
|
+
children: [
|
|
561
|
+
/* @__PURE__ */ jsx5(MaterialIcon5, { name: "terminal", className: "text-sm" }),
|
|
562
|
+
"Terminal"
|
|
563
|
+
]
|
|
564
|
+
}
|
|
565
|
+
)
|
|
566
|
+
] }),
|
|
567
|
+
isHibernating && /* @__PURE__ */ jsxs5(
|
|
568
|
+
"button",
|
|
569
|
+
{
|
|
570
|
+
type: "button",
|
|
571
|
+
onClick: () => onWake?.(sandbox.id),
|
|
572
|
+
className: "w-full flex items-center justify-center gap-2 py-3 bg-md3-primary/10 text-md3-primary hover:bg-md3-primary hover:text-on-primary rounded-lg transition-all duration-300 text-xs font-black",
|
|
573
|
+
children: [
|
|
574
|
+
/* @__PURE__ */ jsx5(MaterialIcon5, { name: "power_settings_new", className: "text-sm" }),
|
|
575
|
+
"Wake Sandbox"
|
|
576
|
+
]
|
|
577
|
+
}
|
|
578
|
+
),
|
|
579
|
+
isProvisioning && /* @__PURE__ */ jsx5(
|
|
580
|
+
"button",
|
|
581
|
+
{
|
|
582
|
+
type: "button",
|
|
583
|
+
disabled: true,
|
|
584
|
+
className: "w-full flex items-center justify-center gap-2 py-3 bg-surface-container-high text-on-surface-variant cursor-not-allowed rounded-lg text-xs font-bold border border-outline-variant/10",
|
|
585
|
+
children: "Please Wait..."
|
|
586
|
+
}
|
|
587
|
+
),
|
|
588
|
+
isArchived && /* @__PURE__ */ jsx5(
|
|
589
|
+
"button",
|
|
590
|
+
{
|
|
591
|
+
type: "button",
|
|
592
|
+
onClick: () => onRestore?.(sandbox.id),
|
|
593
|
+
className: "w-full py-2 bg-slate-800/50 hover:bg-slate-800 text-slate-400 hover:text-white rounded-lg transition-all text-xs font-bold border border-slate-700/50",
|
|
594
|
+
children: "Restore Sandbox"
|
|
595
|
+
}
|
|
596
|
+
)
|
|
597
|
+
]
|
|
598
|
+
}
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
function NewSandboxCard({ onClick, className }) {
|
|
602
|
+
return /* @__PURE__ */ jsxs5(
|
|
603
|
+
"button",
|
|
604
|
+
{
|
|
605
|
+
type: "button",
|
|
606
|
+
onClick,
|
|
607
|
+
className: cn(
|
|
608
|
+
"border-2 border-dashed border-outline-variant/20 rounded-xl p-6 flex flex-col items-center justify-center text-center group cursor-pointer hover:border-md3-primary/40 hover:bg-md3-primary/5 transition-all duration-300 w-full",
|
|
609
|
+
className
|
|
610
|
+
),
|
|
611
|
+
children: [
|
|
612
|
+
/* @__PURE__ */ jsx5("div", { className: "w-14 h-14 rounded-full bg-surface-container flex items-center justify-center mb-4 group-hover:bg-md3-primary/20 group-hover:text-md3-primary transition-all group-active:scale-90", children: /* @__PURE__ */ jsx5(MaterialIcon5, { name: "add_box", className: "text-3xl" }) }),
|
|
613
|
+
/* @__PURE__ */ jsx5("h4", { className: "font-bold text-slate-400 group-hover:text-white mb-1", children: "New Environment" }),
|
|
614
|
+
/* @__PURE__ */ jsx5("p", { className: "text-xs text-slate-600", children: "Instantiate a fresh compute node" })
|
|
615
|
+
]
|
|
616
|
+
}
|
|
617
|
+
);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// src/dashboard/sandbox-table.tsx
|
|
621
|
+
import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
622
|
+
function MaterialIcon6({ name, className }) {
|
|
623
|
+
return /* @__PURE__ */ jsx6("span", { className: cn("material-symbols-outlined", className), style: { fontVariationSettings: "'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24" }, children: name });
|
|
624
|
+
}
|
|
625
|
+
var statusColors = {
|
|
626
|
+
running: { dot: "bg-green-400 animate-pulse", text: "text-green-400", bar: "bg-green-400" },
|
|
627
|
+
hibernating: { dot: "bg-slate-500", text: "text-on-surface-variant", bar: "bg-slate-500" },
|
|
628
|
+
provisioning: { dot: "bg-secondary-fixed animate-pulse", text: "text-secondary-fixed", bar: "bg-secondary-fixed" },
|
|
629
|
+
stopped: { dot: "bg-slate-500", text: "text-slate-400", bar: "bg-slate-500" },
|
|
630
|
+
failed: { dot: "bg-red-500", text: "text-red-400", bar: "bg-red-500" },
|
|
631
|
+
archived: { dot: "bg-slate-600", text: "text-slate-500", bar: "bg-slate-600" }
|
|
632
|
+
};
|
|
633
|
+
function MiniMeter({ label, percent, className }) {
|
|
634
|
+
return /* @__PURE__ */ jsxs6("div", { className: cn("space-y-1", className), children: [
|
|
635
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex justify-between text-[10px] font-mono text-on-surface-variant", children: [
|
|
636
|
+
/* @__PURE__ */ jsx6("span", { className: "font-bold", children: label }),
|
|
637
|
+
/* @__PURE__ */ jsxs6("span", { className: "text-primary-fixed", children: [
|
|
638
|
+
percent,
|
|
639
|
+
"%"
|
|
640
|
+
] })
|
|
641
|
+
] }),
|
|
642
|
+
/* @__PURE__ */ jsx6("div", { className: "h-1.5 w-full bg-surface-container-highest rounded-full overflow-hidden", children: /* @__PURE__ */ jsx6("div", { className: "h-full bg-md3-primary rounded-full", style: { width: `${percent}%` } }) })
|
|
643
|
+
] });
|
|
644
|
+
}
|
|
645
|
+
function SandboxTable({
|
|
646
|
+
sandboxes,
|
|
647
|
+
page = 1,
|
|
648
|
+
pageSize = 10,
|
|
649
|
+
total,
|
|
650
|
+
onPageChange,
|
|
651
|
+
onOpenIDE,
|
|
652
|
+
onOpenTerminal,
|
|
653
|
+
onSSH,
|
|
654
|
+
onWake,
|
|
655
|
+
onMore,
|
|
656
|
+
className
|
|
657
|
+
}) {
|
|
658
|
+
const totalCount = total ?? sandboxes.length;
|
|
659
|
+
const totalPages = Math.ceil(totalCount / pageSize);
|
|
660
|
+
return /* @__PURE__ */ jsxs6("div", { className: cn("w-full", className), children: [
|
|
661
|
+
/* @__PURE__ */ jsx6("div", { className: "w-full bg-surface-container-low rounded-2xl overflow-hidden shadow-2xl border border-outline-variant/10", children: /* @__PURE__ */ jsx6("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs6("table", { className: "w-full text-left border-collapse", children: [
|
|
662
|
+
/* @__PURE__ */ jsx6("thead", { children: /* @__PURE__ */ jsxs6("tr", { className: "bg-surface-container-high/50 border-b border-outline-variant/10", children: [
|
|
663
|
+
/* @__PURE__ */ jsx6("th", { className: "px-6 py-4 text-xs font-semibold text-on-surface-variant uppercase tracking-wider", children: "Status" }),
|
|
664
|
+
/* @__PURE__ */ jsx6("th", { className: "px-6 py-4 text-xs font-semibold text-on-surface-variant uppercase tracking-wider", children: "Sandbox Name" }),
|
|
665
|
+
/* @__PURE__ */ jsx6("th", { className: "px-6 py-4 text-xs font-semibold text-on-surface-variant uppercase tracking-wider", children: "Environment" }),
|
|
666
|
+
/* @__PURE__ */ jsx6("th", { className: "px-6 py-4 text-xs font-semibold text-on-surface-variant uppercase tracking-wider", children: "Resources" }),
|
|
667
|
+
/* @__PURE__ */ jsx6("th", { className: "px-6 py-4 text-xs font-semibold text-on-surface-variant uppercase tracking-wider text-right", children: "Actions" })
|
|
668
|
+
] }) }),
|
|
669
|
+
/* @__PURE__ */ jsx6("tbody", { className: "divide-y divide-outline-variant/5", children: sandboxes.map((sb) => {
|
|
670
|
+
const sc = statusColors[sb.status] ?? statusColors.stopped;
|
|
671
|
+
const isActive = sb.status === "running";
|
|
672
|
+
const isHibernating = sb.status === "hibernating";
|
|
673
|
+
const isProvisioning = sb.status === "provisioning";
|
|
674
|
+
return /* @__PURE__ */ jsxs6("tr", { className: "hover:bg-surface-container-highest/20 transition-colors group relative", children: [
|
|
675
|
+
/* @__PURE__ */ jsx6("td", { className: "px-6 py-5 whitespace-nowrap", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
676
|
+
/* @__PURE__ */ jsx6("span", { className: cn("flex h-2.5 w-2.5 rounded-full", sc.dot) }),
|
|
677
|
+
/* @__PURE__ */ jsx6("span", { className: cn("text-xs font-bold uppercase tracking-wide", sc.text), children: sb.status.charAt(0).toUpperCase() + sb.status.slice(1) })
|
|
678
|
+
] }) }),
|
|
679
|
+
/* @__PURE__ */ jsx6("td", { className: "px-6 py-5", children: /* @__PURE__ */ jsxs6("div", { className: "flex flex-col", children: [
|
|
680
|
+
/* @__PURE__ */ jsx6("span", { className: "text-sm font-bold text-white group-hover:text-md3-primary transition-colors", children: sb.name }),
|
|
681
|
+
sb.nodeId && /* @__PURE__ */ jsx6("span", { className: "text-[10px] font-mono text-on-surface-variant", children: sb.nodeId })
|
|
682
|
+
] }) }),
|
|
683
|
+
/* @__PURE__ */ jsx6("td", { className: "px-6 py-5", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3", children: [
|
|
684
|
+
sb.imageIcon && /* @__PURE__ */ jsx6("div", { className: "w-8 h-8 rounded-lg bg-surface-container-high flex items-center justify-center", children: sb.imageIcon }),
|
|
685
|
+
sb.image && /* @__PURE__ */ jsx6("span", { className: "text-xs font-bold text-white", children: sb.image })
|
|
686
|
+
] }) }),
|
|
687
|
+
/* @__PURE__ */ jsx6("td", { className: "px-6 py-5", children: isActive ? /* @__PURE__ */ jsxs6("div", { className: "space-y-3 w-48", children: [
|
|
688
|
+
/* @__PURE__ */ jsx6(MiniMeter, { label: "CPU", percent: sb.cpuPercent ?? 0 }),
|
|
689
|
+
/* @__PURE__ */ jsx6(MiniMeter, { label: "RAM", percent: sb.ramTotal ? Math.round((sb.ramUsed ?? 0) / sb.ramTotal * 100) : 0 })
|
|
690
|
+
] }) : isProvisioning ? /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2 text-md3-primary/80 italic text-[10px] font-bold", children: [
|
|
691
|
+
/* @__PURE__ */ jsx6(MaterialIcon6, { name: "refresh", className: "text-[14px] animate-spin" }),
|
|
692
|
+
sb.provisioningMessage ?? "Allocating nodes..."
|
|
693
|
+
] }) : isHibernating ? /* @__PURE__ */ jsxs6("div", { className: "space-y-3 w-48 opacity-30", children: [
|
|
694
|
+
/* @__PURE__ */ jsx6(MiniMeter, { label: "CPU", percent: 0 }),
|
|
695
|
+
/* @__PURE__ */ jsx6(MiniMeter, { label: "RAM", percent: 0 })
|
|
696
|
+
] }) : null }),
|
|
697
|
+
/* @__PURE__ */ jsx6("td", { className: "px-6 py-5 text-right", children: /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-end gap-1", children: [
|
|
698
|
+
isActive && /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
699
|
+
/* @__PURE__ */ jsx6("button", { type: "button", onClick: () => onOpenIDE?.(sb.id), className: "p-2 rounded-lg hover:bg-surface-container-highest text-on-surface-variant hover:text-white transition-all active:scale-90", title: "Open IDE", children: /* @__PURE__ */ jsx6(MaterialIcon6, { name: "terminal", className: "text-[20px]" }) }),
|
|
700
|
+
/* @__PURE__ */ jsx6("button", { type: "button", onClick: () => onOpenTerminal?.(sb.id), className: "p-2 rounded-lg hover:bg-surface-container-highest text-on-surface-variant hover:text-white transition-all active:scale-90", title: "Terminal", children: /* @__PURE__ */ jsx6(MaterialIcon6, { name: "tab", className: "text-[20px]" }) }),
|
|
701
|
+
/* @__PURE__ */ jsx6("button", { type: "button", onClick: () => onSSH?.(sb.id), className: "p-2 rounded-lg hover:bg-surface-container-highest text-on-surface-variant hover:text-white transition-all active:scale-90", title: "SSH", children: /* @__PURE__ */ jsx6(MaterialIcon6, { name: "vpn_key", className: "text-[20px]" }) })
|
|
702
|
+
] }),
|
|
703
|
+
isHibernating && /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => onWake?.(sb.id), className: "px-3 py-1.5 rounded-lg border border-md3-primary/30 text-md3-primary text-[10px] font-bold uppercase tracking-wider hover:bg-md3-primary/10 active:scale-95 transition-all", children: "Wake Up" }),
|
|
704
|
+
/* @__PURE__ */ jsx6("button", { type: "button", onClick: () => onMore?.(sb.id), className: "p-2 rounded-lg hover:bg-surface-container-highest text-on-surface-variant hover:text-white transition-all active:scale-90", children: /* @__PURE__ */ jsx6(MaterialIcon6, { name: "more_vert", className: "text-[20px]" }) })
|
|
705
|
+
] }) })
|
|
706
|
+
] }, sb.id);
|
|
707
|
+
}) })
|
|
708
|
+
] }) }) }),
|
|
709
|
+
totalPages > 1 && /* @__PURE__ */ jsxs6("div", { className: "mt-6 flex flex-col md:flex-row justify-between items-center text-on-surface-variant text-xs font-medium gap-4", children: [
|
|
710
|
+
/* @__PURE__ */ jsxs6("p", { children: [
|
|
711
|
+
"Showing ",
|
|
712
|
+
sandboxes.length,
|
|
713
|
+
" of ",
|
|
714
|
+
totalCount,
|
|
715
|
+
" active sandboxes"
|
|
716
|
+
] }),
|
|
717
|
+
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
|
|
718
|
+
/* @__PURE__ */ jsx6("button", { type: "button", onClick: () => onPageChange?.(page - 1), disabled: page <= 1, className: "p-2 rounded-lg border border-outline-variant/10 hover:bg-surface-container-high transition-colors disabled:opacity-30", children: /* @__PURE__ */ jsx6(MaterialIcon6, { name: "chevron_left", className: "text-[18px]" }) }),
|
|
719
|
+
Array.from({ length: Math.min(totalPages, 5) }, (_, i) => i + 1).map((p) => /* @__PURE__ */ jsx6(
|
|
720
|
+
"button",
|
|
721
|
+
{
|
|
722
|
+
type: "button",
|
|
723
|
+
onClick: () => onPageChange?.(p),
|
|
724
|
+
className: cn(
|
|
725
|
+
"px-3 py-1 rounded-lg transition-colors",
|
|
726
|
+
p === page ? "bg-md3-primary/10 text-md3-primary border border-md3-primary/20" : "hover:bg-surface-container-high"
|
|
727
|
+
),
|
|
728
|
+
children: p
|
|
729
|
+
},
|
|
730
|
+
p
|
|
731
|
+
)),
|
|
732
|
+
/* @__PURE__ */ jsx6("button", { type: "button", onClick: () => onPageChange?.(page + 1), disabled: page >= totalPages, className: "p-2 rounded-lg border border-outline-variant/10 hover:bg-surface-container-high transition-colors disabled:opacity-30", children: /* @__PURE__ */ jsx6(MaterialIcon6, { name: "chevron_right", className: "text-[18px]" }) })
|
|
733
|
+
] })
|
|
734
|
+
] })
|
|
735
|
+
] });
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// src/dashboard/backend-selector.tsx
|
|
739
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
740
|
+
function BackendSelector({
|
|
741
|
+
backends,
|
|
742
|
+
selected,
|
|
743
|
+
onChange,
|
|
744
|
+
label = "Models",
|
|
745
|
+
hint,
|
|
746
|
+
multiSelect = true,
|
|
747
|
+
className
|
|
748
|
+
}) {
|
|
749
|
+
const toggle = (type) => {
|
|
750
|
+
if (multiSelect) {
|
|
751
|
+
onChange(
|
|
752
|
+
selected.includes(type) ? selected.filter((b) => b !== type) : [...selected, type]
|
|
753
|
+
);
|
|
754
|
+
} else {
|
|
755
|
+
onChange([type]);
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
return /* @__PURE__ */ jsxs7("div", { className, children: [
|
|
759
|
+
/* @__PURE__ */ jsxs7("label", { className: "mb-2 block font-medium text-sm", children: [
|
|
760
|
+
label,
|
|
761
|
+
multiSelect && /* @__PURE__ */ jsx7("span", { className: "ml-2 font-normal text-muted-foreground", children: "(select multiple to compare)" })
|
|
762
|
+
] }),
|
|
763
|
+
/* @__PURE__ */ jsx7("div", { className: "flex flex-wrap gap-2", children: backends.map((backend) => {
|
|
764
|
+
const isSelected = selected.includes(backend.type);
|
|
765
|
+
return /* @__PURE__ */ jsx7(
|
|
766
|
+
"button",
|
|
767
|
+
{
|
|
768
|
+
type: "button",
|
|
769
|
+
onClick: () => toggle(backend.type),
|
|
770
|
+
className: `rounded-lg border px-3 py-2 text-sm transition-colors ${isSelected ? "border-blue-500 bg-blue-500/10 text-blue-400" : "border-border bg-background text-muted-foreground hover:border-muted-foreground/50"}`,
|
|
771
|
+
title: backend.description,
|
|
772
|
+
children: backend.label
|
|
773
|
+
},
|
|
774
|
+
backend.type
|
|
775
|
+
);
|
|
776
|
+
}) }),
|
|
777
|
+
multiSelect && selected.length > 1 && /* @__PURE__ */ jsx7("p", { className: "mt-2 text-muted-foreground text-xs", children: hint || `Will run on ${selected.length} variants in parallel for comparison` })
|
|
778
|
+
] });
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// src/dashboard/profile-selector.tsx
|
|
782
|
+
import { Check, ChevronDown, Plus, Settings } from "lucide-react";
|
|
783
|
+
import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
784
|
+
function ProfileSelector({
|
|
785
|
+
profiles,
|
|
786
|
+
selectedId,
|
|
787
|
+
onSelect,
|
|
788
|
+
onCreateClick,
|
|
789
|
+
onManageClick,
|
|
790
|
+
label = "Profile",
|
|
791
|
+
placeholder = "Default (no custom profile)",
|
|
792
|
+
showMetrics = true,
|
|
793
|
+
className
|
|
794
|
+
}) {
|
|
795
|
+
const selected = profiles.find((p) => p.id === selectedId);
|
|
796
|
+
const builtinProfiles = profiles.filter((p) => p.is_builtin);
|
|
797
|
+
const customProfiles = profiles.filter((p) => !p.is_builtin);
|
|
798
|
+
return /* @__PURE__ */ jsxs8("div", { className, children: [
|
|
799
|
+
label && /* @__PURE__ */ jsx8("label", { className: "mb-2 block font-medium text-sm", children: label }),
|
|
800
|
+
/* @__PURE__ */ jsxs8(DropdownMenu, { children: [
|
|
801
|
+
/* @__PURE__ */ jsx8(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs8(Button, { variant: "outline", className: "w-full justify-between", children: [
|
|
802
|
+
/* @__PURE__ */ jsx8("span", { className: "truncate", children: selected ? selected.name : placeholder }),
|
|
803
|
+
/* @__PURE__ */ jsx8(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })
|
|
804
|
+
] }) }),
|
|
805
|
+
/* @__PURE__ */ jsxs8(DropdownMenuContent, { className: "w-[300px]", align: "start", children: [
|
|
806
|
+
/* @__PURE__ */ jsxs8(
|
|
807
|
+
DropdownMenuItem,
|
|
808
|
+
{
|
|
809
|
+
onClick: () => onSelect(null),
|
|
810
|
+
className: "flex items-center justify-between",
|
|
811
|
+
children: [
|
|
812
|
+
/* @__PURE__ */ jsx8("span", { children: placeholder }),
|
|
813
|
+
!selectedId && /* @__PURE__ */ jsx8(Check, { className: "h-4 w-4 text-green-400" })
|
|
814
|
+
]
|
|
815
|
+
}
|
|
816
|
+
),
|
|
817
|
+
builtinProfiles.length > 0 && /* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
818
|
+
/* @__PURE__ */ jsx8(DropdownMenuSeparator, {}),
|
|
819
|
+
/* @__PURE__ */ jsx8(DropdownMenuLabel, { children: "Built-in Profiles" }),
|
|
820
|
+
builtinProfiles.map((profile) => /* @__PURE__ */ jsxs8(
|
|
821
|
+
DropdownMenuItem,
|
|
822
|
+
{
|
|
823
|
+
onClick: () => onSelect(profile),
|
|
824
|
+
className: "flex flex-col items-start gap-1",
|
|
825
|
+
children: [
|
|
826
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex w-full items-center justify-between", children: [
|
|
827
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
828
|
+
/* @__PURE__ */ jsx8("span", { className: "font-medium", children: profile.name }),
|
|
829
|
+
profile.extends && /* @__PURE__ */ jsxs8(Badge, { variant: "secondary", className: "border-0 text-xs", children: [
|
|
830
|
+
"extends ",
|
|
831
|
+
profile.extends
|
|
832
|
+
] })
|
|
833
|
+
] }),
|
|
834
|
+
selectedId === profile.id && /* @__PURE__ */ jsx8(Check, { className: "h-4 w-4 text-green-400" })
|
|
835
|
+
] }),
|
|
836
|
+
profile.description && /* @__PURE__ */ jsx8("span", { className: "line-clamp-1 text-muted-foreground text-xs", children: profile.description })
|
|
837
|
+
]
|
|
838
|
+
},
|
|
839
|
+
profile.id
|
|
840
|
+
))
|
|
841
|
+
] }),
|
|
842
|
+
customProfiles.length > 0 && /* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
843
|
+
/* @__PURE__ */ jsx8(DropdownMenuSeparator, {}),
|
|
844
|
+
/* @__PURE__ */ jsx8(DropdownMenuLabel, { children: "Custom Profiles" }),
|
|
845
|
+
customProfiles.map((profile) => /* @__PURE__ */ jsxs8(
|
|
846
|
+
DropdownMenuItem,
|
|
847
|
+
{
|
|
848
|
+
onClick: () => onSelect(profile),
|
|
849
|
+
className: "flex flex-col items-start gap-1",
|
|
850
|
+
children: [
|
|
851
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex w-full items-center justify-between", children: [
|
|
852
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
853
|
+
/* @__PURE__ */ jsx8("span", { className: "font-medium", children: profile.name }),
|
|
854
|
+
profile.model && /* @__PURE__ */ jsx8(Badge, { variant: "secondary", className: "border-0 text-xs", children: profile.model.split("/").pop() })
|
|
855
|
+
] }),
|
|
856
|
+
selectedId === profile.id && /* @__PURE__ */ jsx8(Check, { className: "h-4 w-4 text-green-400" })
|
|
857
|
+
] }),
|
|
858
|
+
profile.description && /* @__PURE__ */ jsx8("span", { className: "line-clamp-1 text-muted-foreground text-xs", children: profile.description }),
|
|
859
|
+
showMetrics && profile.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */ jsxs8("div", { className: "flex gap-3 text-muted-foreground text-xs", children: [
|
|
860
|
+
/* @__PURE__ */ jsxs8("span", { children: [
|
|
861
|
+
profile.metrics.total_runs,
|
|
862
|
+
" runs"
|
|
863
|
+
] }),
|
|
864
|
+
/* @__PURE__ */ jsxs8("span", { children: [
|
|
865
|
+
profile.metrics.success_rate.toFixed(0),
|
|
866
|
+
"% success"
|
|
867
|
+
] }),
|
|
868
|
+
/* @__PURE__ */ jsxs8("span", { children: [
|
|
869
|
+
"~",
|
|
870
|
+
(profile.metrics.avg_duration_ms / 1e3).toFixed(1),
|
|
871
|
+
"s avg"
|
|
872
|
+
] })
|
|
873
|
+
] })
|
|
874
|
+
]
|
|
875
|
+
},
|
|
876
|
+
profile.id
|
|
877
|
+
))
|
|
878
|
+
] }),
|
|
879
|
+
(onCreateClick || onManageClick) && /* @__PURE__ */ jsxs8(Fragment4, { children: [
|
|
880
|
+
/* @__PURE__ */ jsx8(DropdownMenuSeparator, {}),
|
|
881
|
+
onCreateClick && /* @__PURE__ */ jsxs8(
|
|
882
|
+
DropdownMenuItem,
|
|
883
|
+
{
|
|
884
|
+
onClick: onCreateClick,
|
|
885
|
+
className: "text-blue-400",
|
|
886
|
+
children: [
|
|
887
|
+
/* @__PURE__ */ jsx8(Plus, { className: "mr-2 h-4 w-4" }),
|
|
888
|
+
"Create New Profile"
|
|
889
|
+
]
|
|
890
|
+
}
|
|
891
|
+
),
|
|
892
|
+
onManageClick && /* @__PURE__ */ jsxs8(
|
|
893
|
+
DropdownMenuItem,
|
|
894
|
+
{
|
|
895
|
+
onClick: onManageClick,
|
|
896
|
+
className: "text-muted-foreground",
|
|
897
|
+
children: [
|
|
898
|
+
/* @__PURE__ */ jsx8(Settings, { className: "mr-2 h-4 w-4" }),
|
|
899
|
+
"Manage Profiles"
|
|
900
|
+
]
|
|
901
|
+
}
|
|
902
|
+
)
|
|
903
|
+
] })
|
|
904
|
+
] })
|
|
905
|
+
] })
|
|
906
|
+
] });
|
|
907
|
+
}
|
|
908
|
+
function ProfileComparison({
|
|
909
|
+
profiles,
|
|
910
|
+
className
|
|
911
|
+
}) {
|
|
912
|
+
const profilesWithMetrics = profiles.filter(
|
|
913
|
+
(p) => p.metrics && p.metrics.total_runs > 0
|
|
914
|
+
);
|
|
915
|
+
if (profilesWithMetrics.length === 0) {
|
|
916
|
+
return null;
|
|
917
|
+
}
|
|
918
|
+
const bestSuccess = profilesWithMetrics.reduce(
|
|
919
|
+
(best, p) => (p.metrics?.success_rate ?? 0) > (best.metrics?.success_rate ?? 0) ? p : best
|
|
920
|
+
);
|
|
921
|
+
const fastestProfile = profilesWithMetrics.reduce(
|
|
922
|
+
(best, p) => (p.metrics?.avg_duration_ms ?? Number.POSITIVE_INFINITY) < (best.metrics?.avg_duration_ms ?? Number.POSITIVE_INFINITY) ? p : best
|
|
923
|
+
);
|
|
924
|
+
return /* @__PURE__ */ jsxs8("div", { className: `rounded-lg border border-border p-4 ${className ?? ""}`, children: [
|
|
925
|
+
/* @__PURE__ */ jsx8("h4", { className: "mb-3 font-medium text-sm", children: "Profile Performance" }),
|
|
926
|
+
/* @__PURE__ */ jsx8("div", { className: "space-y-3", children: profilesWithMetrics.map((profile) => {
|
|
927
|
+
const isBestSuccess = profile.id === bestSuccess.id;
|
|
928
|
+
const isFastest = profile.id === fastestProfile.id;
|
|
929
|
+
return /* @__PURE__ */ jsxs8(
|
|
930
|
+
"div",
|
|
931
|
+
{
|
|
932
|
+
className: "flex items-center justify-between gap-4",
|
|
933
|
+
children: [
|
|
934
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
935
|
+
/* @__PURE__ */ jsx8("span", { className: "font-medium", children: profile.name }),
|
|
936
|
+
isBestSuccess && /* @__PURE__ */ jsx8(Badge, { className: "border-0 bg-green-500/10 text-green-400 text-xs", children: "Best Success" }),
|
|
937
|
+
isFastest && !isBestSuccess && /* @__PURE__ */ jsx8(Badge, { className: "border-0 bg-blue-500/10 text-blue-400 text-xs", children: "Fastest" })
|
|
938
|
+
] }),
|
|
939
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-4 text-sm", children: [
|
|
940
|
+
/* @__PURE__ */ jsxs8("span", { children: [
|
|
941
|
+
/* @__PURE__ */ jsx8("span", { className: "text-muted-foreground", children: "Success:" }),
|
|
942
|
+
" ",
|
|
943
|
+
/* @__PURE__ */ jsxs8(
|
|
944
|
+
"span",
|
|
945
|
+
{
|
|
946
|
+
className: (profile.metrics?.success_rate ?? 0) >= 80 ? "text-green-400" : (profile.metrics?.success_rate ?? 0) >= 50 ? "text-yellow-400" : "text-red-400",
|
|
947
|
+
children: [
|
|
948
|
+
profile.metrics?.success_rate.toFixed(0),
|
|
949
|
+
"%"
|
|
950
|
+
]
|
|
951
|
+
}
|
|
952
|
+
)
|
|
953
|
+
] }),
|
|
954
|
+
/* @__PURE__ */ jsxs8("span", { children: [
|
|
955
|
+
/* @__PURE__ */ jsx8("span", { className: "text-muted-foreground", children: "Avg:" }),
|
|
956
|
+
" ",
|
|
957
|
+
((profile.metrics?.avg_duration_ms ?? 0) / 1e3).toFixed(1),
|
|
958
|
+
"s"
|
|
959
|
+
] }),
|
|
960
|
+
/* @__PURE__ */ jsxs8("span", { className: "text-muted-foreground", children: [
|
|
961
|
+
profile.metrics?.total_runs,
|
|
962
|
+
" runs"
|
|
963
|
+
] })
|
|
964
|
+
] })
|
|
965
|
+
]
|
|
966
|
+
},
|
|
967
|
+
profile.id
|
|
968
|
+
);
|
|
969
|
+
}) })
|
|
970
|
+
] });
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
// src/dashboard/variant-list.tsx
|
|
974
|
+
import {
|
|
975
|
+
Check as Check2,
|
|
976
|
+
CheckCircle2,
|
|
977
|
+
Clock,
|
|
978
|
+
ExternalLink,
|
|
979
|
+
Loader2,
|
|
980
|
+
Timer,
|
|
981
|
+
X,
|
|
982
|
+
XCircle
|
|
983
|
+
} from "lucide-react";
|
|
984
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
985
|
+
var statusConfig2 = {
|
|
986
|
+
pending: {
|
|
987
|
+
icon: Clock,
|
|
988
|
+
color: "text-yellow-400",
|
|
989
|
+
bg: "bg-yellow-500/10",
|
|
990
|
+
label: "Pending",
|
|
991
|
+
animate: false
|
|
992
|
+
},
|
|
993
|
+
running: {
|
|
994
|
+
icon: Loader2,
|
|
995
|
+
color: "text-blue-400",
|
|
996
|
+
bg: "bg-blue-500/10",
|
|
997
|
+
label: "Running",
|
|
998
|
+
animate: true
|
|
999
|
+
},
|
|
1000
|
+
completed: {
|
|
1001
|
+
icon: CheckCircle2,
|
|
1002
|
+
color: "text-green-400",
|
|
1003
|
+
bg: "bg-green-500/10",
|
|
1004
|
+
label: "Completed",
|
|
1005
|
+
animate: false
|
|
1006
|
+
},
|
|
1007
|
+
failed: {
|
|
1008
|
+
icon: XCircle,
|
|
1009
|
+
color: "text-red-400",
|
|
1010
|
+
bg: "bg-red-500/10",
|
|
1011
|
+
label: "Failed",
|
|
1012
|
+
animate: false
|
|
1013
|
+
},
|
|
1014
|
+
cancelled: {
|
|
1015
|
+
icon: XCircle,
|
|
1016
|
+
color: "text-gray-400",
|
|
1017
|
+
bg: "bg-gray-500/10",
|
|
1018
|
+
label: "Cancelled",
|
|
1019
|
+
animate: false
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
var outcomeConfig = {
|
|
1023
|
+
pending_review: {
|
|
1024
|
+
color: "text-amber-400",
|
|
1025
|
+
bg: "bg-amber-500/10",
|
|
1026
|
+
label: "Pending Review"
|
|
1027
|
+
},
|
|
1028
|
+
accepted: {
|
|
1029
|
+
color: "text-green-400",
|
|
1030
|
+
bg: "bg-green-500/10",
|
|
1031
|
+
label: "Accepted"
|
|
1032
|
+
},
|
|
1033
|
+
rejected: {
|
|
1034
|
+
color: "text-red-400",
|
|
1035
|
+
bg: "bg-red-500/10",
|
|
1036
|
+
label: "Rejected"
|
|
1037
|
+
},
|
|
1038
|
+
merged_with_conflicts: {
|
|
1039
|
+
color: "text-orange-400",
|
|
1040
|
+
bg: "bg-orange-500/10",
|
|
1041
|
+
label: "Merged (conflicts)"
|
|
1042
|
+
},
|
|
1043
|
+
expired: {
|
|
1044
|
+
color: "text-gray-400",
|
|
1045
|
+
bg: "bg-gray-500/10",
|
|
1046
|
+
label: "Expired"
|
|
1047
|
+
}
|
|
1048
|
+
};
|
|
1049
|
+
function VariantList({
|
|
1050
|
+
variants,
|
|
1051
|
+
selectedId,
|
|
1052
|
+
onSelect,
|
|
1053
|
+
onAccept,
|
|
1054
|
+
onReject,
|
|
1055
|
+
isActioning,
|
|
1056
|
+
className
|
|
1057
|
+
}) {
|
|
1058
|
+
return /* @__PURE__ */ jsx9("div", { className: `space-y-3 ${className || ""}`, children: variants.map((variant) => {
|
|
1059
|
+
const status = statusConfig2[variant.status];
|
|
1060
|
+
const StatusIcon = status.icon;
|
|
1061
|
+
const isSelected = variant.id === selectedId;
|
|
1062
|
+
return /* @__PURE__ */ jsxs9(
|
|
1063
|
+
"div",
|
|
1064
|
+
{
|
|
1065
|
+
className: `cursor-pointer rounded-lg border p-4 transition-colors ${isSelected ? "border-blue-500 bg-blue-500/5" : "border-border hover:border-muted-foreground/50"}`,
|
|
1066
|
+
onClick: () => onSelect?.(variant.id),
|
|
1067
|
+
children: [
|
|
1068
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-between", children: [
|
|
1069
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-3", children: [
|
|
1070
|
+
/* @__PURE__ */ jsxs9(Badge, { className: `${status.bg} ${status.color} border-0`, children: [
|
|
1071
|
+
/* @__PURE__ */ jsx9(
|
|
1072
|
+
StatusIcon,
|
|
1073
|
+
{
|
|
1074
|
+
className: `mr-1 h-3 w-3 ${status.animate ? "animate-spin" : ""}`
|
|
1075
|
+
}
|
|
1076
|
+
),
|
|
1077
|
+
status.label
|
|
1078
|
+
] }),
|
|
1079
|
+
/* @__PURE__ */ jsx9("span", { className: "font-medium", children: variant.label }),
|
|
1080
|
+
variant.sublabel && /* @__PURE__ */ jsxs9("span", { className: "text-muted-foreground text-sm", children: [
|
|
1081
|
+
"(",
|
|
1082
|
+
variant.sublabel,
|
|
1083
|
+
")"
|
|
1084
|
+
] }),
|
|
1085
|
+
variant.durationMs && /* @__PURE__ */ jsxs9("span", { className: "flex items-center gap-1 text-muted-foreground text-sm", children: [
|
|
1086
|
+
/* @__PURE__ */ jsx9(Timer, { className: "h-3 w-3" }),
|
|
1087
|
+
(variant.durationMs / 1e3).toFixed(2),
|
|
1088
|
+
"s"
|
|
1089
|
+
] })
|
|
1090
|
+
] }),
|
|
1091
|
+
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
1092
|
+
variant.outcome && /* @__PURE__ */ jsx9(
|
|
1093
|
+
Badge,
|
|
1094
|
+
{
|
|
1095
|
+
className: `${outcomeConfig[variant.outcome].bg} ${outcomeConfig[variant.outcome].color} border-0`,
|
|
1096
|
+
children: outcomeConfig[variant.outcome].label
|
|
1097
|
+
}
|
|
1098
|
+
),
|
|
1099
|
+
variant.status === "completed" && variant.outcome === "pending_review" && onAccept && onReject && /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
1100
|
+
/* @__PURE__ */ jsxs9(
|
|
1101
|
+
Button,
|
|
1102
|
+
{
|
|
1103
|
+
variant: "outline",
|
|
1104
|
+
size: "sm",
|
|
1105
|
+
className: "text-green-400 hover:bg-green-500/10",
|
|
1106
|
+
onClick: (e) => {
|
|
1107
|
+
e.stopPropagation();
|
|
1108
|
+
onAccept(variant.id);
|
|
1109
|
+
},
|
|
1110
|
+
disabled: isActioning === variant.id,
|
|
1111
|
+
children: [
|
|
1112
|
+
/* @__PURE__ */ jsx9(Check2, { className: "mr-1 h-4 w-4" }),
|
|
1113
|
+
"Accept"
|
|
1114
|
+
]
|
|
1115
|
+
}
|
|
1116
|
+
),
|
|
1117
|
+
/* @__PURE__ */ jsxs9(
|
|
1118
|
+
Button,
|
|
1119
|
+
{
|
|
1120
|
+
variant: "outline",
|
|
1121
|
+
size: "sm",
|
|
1122
|
+
className: "text-red-400 hover:bg-red-500/10",
|
|
1123
|
+
onClick: (e) => {
|
|
1124
|
+
e.stopPropagation();
|
|
1125
|
+
onReject(variant.id);
|
|
1126
|
+
},
|
|
1127
|
+
disabled: isActioning === variant.id,
|
|
1128
|
+
children: [
|
|
1129
|
+
/* @__PURE__ */ jsx9(X, { className: "mr-1 h-4 w-4" }),
|
|
1130
|
+
"Reject"
|
|
1131
|
+
]
|
|
1132
|
+
}
|
|
1133
|
+
)
|
|
1134
|
+
] }),
|
|
1135
|
+
variant.detailsUrl && /* @__PURE__ */ jsx9(
|
|
1136
|
+
Button,
|
|
1137
|
+
{
|
|
1138
|
+
variant: "ghost",
|
|
1139
|
+
size: "sm",
|
|
1140
|
+
className: "text-muted-foreground",
|
|
1141
|
+
onClick: (e) => {
|
|
1142
|
+
e.stopPropagation();
|
|
1143
|
+
window.open(variant.detailsUrl, "_blank");
|
|
1144
|
+
},
|
|
1145
|
+
children: /* @__PURE__ */ jsx9(ExternalLink, { className: "h-4 w-4" })
|
|
1146
|
+
}
|
|
1147
|
+
)
|
|
1148
|
+
] })
|
|
1149
|
+
] }),
|
|
1150
|
+
variant.error && /* @__PURE__ */ jsx9("p", { className: "mt-2 text-red-400 text-sm", children: variant.error }),
|
|
1151
|
+
variant.summary && /* @__PURE__ */ jsx9("p", { className: "mt-2 line-clamp-2 text-muted-foreground text-sm", children: variant.summary })
|
|
1152
|
+
]
|
|
1153
|
+
},
|
|
1154
|
+
variant.id
|
|
1155
|
+
);
|
|
1156
|
+
}) });
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
export {
|
|
1160
|
+
AppSidebar,
|
|
1161
|
+
ClusterStatusBar,
|
|
1162
|
+
DashboardLayout,
|
|
1163
|
+
ResourceMeter,
|
|
1164
|
+
SandboxCard,
|
|
1165
|
+
NewSandboxCard,
|
|
1166
|
+
SandboxTable,
|
|
1167
|
+
BackendSelector,
|
|
1168
|
+
ProfileSelector,
|
|
1169
|
+
ProfileComparison,
|
|
1170
|
+
VariantList
|
|
1171
|
+
};
|