@tangle-network/sandbox-ui 0.14.0 → 0.15.2
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 +1 -74
- package/dist/auth.js +1 -4
- package/dist/chat.d.ts +1 -136
- package/dist/chat.js +2 -15
- package/dist/chunk-2BUPSB7O.js +0 -0
- package/dist/chunk-3J6FG3FJ.js +18 -0
- package/dist/chunk-76IQLPW2.js +206 -0
- package/dist/chunk-7ZA5SEK3.js +239 -0
- package/dist/chunk-AZ3AWMTM.js +8 -0
- package/dist/chunk-CMY7W45U.js +380 -0
- package/dist/chunk-EI44GEQ5.js +6 -0
- package/dist/chunk-ENMWGVDL.js +858 -0
- package/dist/{chunk-5OQ27N57.js → chunk-GPT7VKK6.js} +34 -38
- package/dist/chunk-HLZTKSGT.js +2652 -0
- package/dist/chunk-JBGKGLD7.js +16 -0
- package/dist/chunk-NJNME4J4.js +14 -0
- package/dist/chunk-QPAJR74X.js +20 -0
- package/dist/chunk-TK46XFLM.js +28 -0
- package/dist/chunk-WID73FPH.js +89 -0
- package/dist/chunk-YVXK4XRO.js +30 -0
- package/dist/dashboard.d.ts +450 -4
- package/dist/dashboard.js +20 -891
- package/dist/editor.d.ts +1 -120
- package/dist/editor.js +1 -5
- package/dist/files.d.ts +1 -129
- package/dist/files.js +2 -7
- package/dist/globals.css +2 -1265
- package/dist/hooks.d.ts +114 -11
- package/dist/hooks.js +17 -88
- package/dist/index.d.ts +24 -99
- package/dist/index.js +251 -256
- package/dist/markdown.d.ts +1 -29
- package/dist/markdown.js +2 -2
- package/dist/openui.d.ts +8 -115
- package/dist/openui.js +1 -6
- package/dist/pages.d.ts +13 -12
- package/dist/pages.js +91 -115
- package/dist/primitives.d.ts +14 -49
- package/dist/primitives.js +69 -77
- package/dist/run.d.ts +1 -14
- package/dist/run.js +2 -22
- package/dist/sdk-hooks.d.ts +3 -283
- package/dist/sdk-hooks.js +10 -14
- package/dist/stores.d.ts +2 -14
- package/dist/stores.js +11 -39
- package/dist/styles.css +2 -1265
- package/dist/template-card-DStb8boW.d.ts +183 -0
- package/dist/types.d.ts +11 -8
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +1 -44
- package/dist/utils.js +6 -12
- package/dist/workspace.d.ts +5 -10
- package/dist/workspace.js +3 -19
- package/package.json +19 -54
- package/dist/active-sessions-store-CeOmXgv5.d.ts +0 -85
- package/dist/artifact-pane-Bh45Ssco.d.ts +0 -24
- package/dist/branding-DCi5VEik.d.ts +0 -13
- package/dist/button-CMQuQEW_.d.ts +0 -17
- package/dist/chat-container-f4yEs6KN.d.ts +0 -106
- package/dist/chunk-34A66VBG.js +0 -214
- package/dist/chunk-34I7UFSX.js +0 -92
- package/dist/chunk-36QY2W5G.js +0 -802
- package/dist/chunk-4CLN43XT.js +0 -45
- package/dist/chunk-54SQQMMM.js +0 -156
- package/dist/chunk-66EZOYZR.js +0 -102
- package/dist/chunk-BX6AQMUS.js +0 -183
- package/dist/chunk-DI3NZ5ZX.js +0 -192
- package/dist/chunk-DPGIXDAI.js +0 -220
- package/dist/chunk-DXMIEK4K.js +0 -1426
- package/dist/chunk-GSZA3TSY.js +0 -79
- package/dist/chunk-HB5Y37YU.js +0 -54
- package/dist/chunk-LQNEZDRM.js +0 -109
- package/dist/chunk-MA7YKRUP.js +0 -131
- package/dist/chunk-MKTSMWVD.js +0 -109
- package/dist/chunk-MQXABZTB.js +0 -1348
- package/dist/chunk-MT5FJ3ZT.js +0 -186
- package/dist/chunk-NKUPJC34.js +0 -2070
- package/dist/chunk-OEX7NZE3.js +0 -321
- package/dist/chunk-OKLQVY3Y.js +0 -139
- package/dist/chunk-Q56BYXQF.js +0 -61
- package/dist/chunk-QD4QE5P5.js +0 -40
- package/dist/chunk-QDH5GEGY.js +0 -630
- package/dist/chunk-QID2OOMG.js +0 -133
- package/dist/chunk-QMU2PWOU.js +0 -493
- package/dist/chunk-RQHJBTEU.js +0 -10
- package/dist/chunk-T7HMZEVO.js +0 -216
- package/dist/chunk-U6QTHMY6.js +0 -1290
- package/dist/chunk-US6JKJKH.js +0 -124
- package/dist/chunk-VX3XOUEB.js +0 -63
- package/dist/chunk-XLG757B6.js +0 -933
- package/dist/chunk-ZMNSRDMH.js +0 -127
- package/dist/chunk-ZNCEM5CD.js +0 -316
- package/dist/document-editor-pane-A70-EhdQ.d.ts +0 -124
- package/dist/document-editor-pane-TLPVRBBU.js +0 -11
- package/dist/expanded-tool-detail-Dh99mcbY.d.ts +0 -63
- package/dist/file-tabs-BLfxfmAH.d.ts +0 -51
- package/dist/parts-CyGkM6Fp.d.ts +0 -50
- package/dist/run-CtFZ6s-D.d.ts +0 -41
- package/dist/sidebar-drop-zone-tDBsuOH5.d.ts +0 -301
- package/dist/sidecar-CFU2W9j1.d.ts +0 -8
- package/dist/template-card-BAtvcAkU.d.ts +0 -18
- package/dist/tool-call-feed-Bs3MyQMT.d.ts +0 -68
- package/dist/tool-display-Ct9nFAzJ.d.ts +0 -32
- package/dist/usage-chart-CPTcNlGs.d.ts +0 -73
- package/dist/use-sandbox-metrics-DWc0k9Xm.d.ts +0 -153
- package/dist/variant-list-BrHYcBCk.d.ts +0 -540
package/dist/chunk-NKUPJC34.js
DELETED
|
@@ -1,2070 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Logo
|
|
3
|
-
} from "./chunk-OKLQVY3Y.js";
|
|
4
|
-
import {
|
|
5
|
-
Avatar,
|
|
6
|
-
AvatarFallback,
|
|
7
|
-
AvatarImage,
|
|
8
|
-
DropdownMenu,
|
|
9
|
-
DropdownMenuContent,
|
|
10
|
-
DropdownMenuItem,
|
|
11
|
-
DropdownMenuLabel,
|
|
12
|
-
DropdownMenuSeparator,
|
|
13
|
-
DropdownMenuTrigger
|
|
14
|
-
} from "./chunk-34A66VBG.js";
|
|
15
|
-
import {
|
|
16
|
-
Skeleton
|
|
17
|
-
} from "./chunk-66EZOYZR.js";
|
|
18
|
-
import {
|
|
19
|
-
Badge
|
|
20
|
-
} from "./chunk-ZMNSRDMH.js";
|
|
21
|
-
import {
|
|
22
|
-
Button
|
|
23
|
-
} from "./chunk-MKTSMWVD.js";
|
|
24
|
-
import {
|
|
25
|
-
cn
|
|
26
|
-
} from "./chunk-RQHJBTEU.js";
|
|
27
|
-
|
|
28
|
-
// src/dashboard/sidebar-context.tsx
|
|
29
|
-
import * as React from "react";
|
|
30
|
-
import { jsx } from "react/jsx-runtime";
|
|
31
|
-
var PANEL_OPEN_KEY = "sandbox-sidebar-panel-open";
|
|
32
|
-
var SIDEBAR_MODE_KEY = "sandbox-sidebar-mode";
|
|
33
|
-
var SIDEBAR_RAIL_WIDTH = 64;
|
|
34
|
-
var SIDEBAR_PANEL_WIDTH = 260;
|
|
35
|
-
var SIDEBAR_TOTAL_WIDTH = SIDEBAR_RAIL_WIDTH + SIDEBAR_PANEL_WIDTH;
|
|
36
|
-
var SIDEBAR_MOBILE_WIDTH = 256;
|
|
37
|
-
var SidebarContext = React.createContext(null);
|
|
38
|
-
function readStorage(key, fallback) {
|
|
39
|
-
if (typeof window === "undefined") return fallback;
|
|
40
|
-
try {
|
|
41
|
-
return localStorage.getItem(key) ?? fallback;
|
|
42
|
-
} catch {
|
|
43
|
-
return fallback;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
function writeStorage(key, value) {
|
|
47
|
-
if (typeof window === "undefined") return;
|
|
48
|
-
try {
|
|
49
|
-
localStorage.setItem(key, value);
|
|
50
|
-
} catch {
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
function SidebarProvider({
|
|
54
|
-
defaultPanelOpen = true,
|
|
55
|
-
defaultMode = "projects",
|
|
56
|
-
hasPanels = true,
|
|
57
|
-
children
|
|
58
|
-
}) {
|
|
59
|
-
const [panelOpen, setPanelOpenState] = React.useState(
|
|
60
|
-
() => readStorage(PANEL_OPEN_KEY, String(defaultPanelOpen)) === "true"
|
|
61
|
-
);
|
|
62
|
-
const [mode, setModeState] = React.useState(
|
|
63
|
-
() => readStorage(SIDEBAR_MODE_KEY, defaultMode)
|
|
64
|
-
);
|
|
65
|
-
const [hidden, setHidden] = React.useState(false);
|
|
66
|
-
const setPanelOpen = React.useCallback((open) => {
|
|
67
|
-
setPanelOpenState(open);
|
|
68
|
-
writeStorage(PANEL_OPEN_KEY, String(open));
|
|
69
|
-
}, []);
|
|
70
|
-
const togglePanel = React.useCallback(() => {
|
|
71
|
-
setPanelOpenState((prev) => {
|
|
72
|
-
const next = !prev;
|
|
73
|
-
writeStorage(PANEL_OPEN_KEY, String(next));
|
|
74
|
-
return next;
|
|
75
|
-
});
|
|
76
|
-
}, []);
|
|
77
|
-
const setMode = React.useCallback((m) => {
|
|
78
|
-
setModeState(m);
|
|
79
|
-
writeStorage(SIDEBAR_MODE_KEY, m);
|
|
80
|
-
}, []);
|
|
81
|
-
const switchModeStable = React.useCallback((m) => {
|
|
82
|
-
setModeState((prevMode) => {
|
|
83
|
-
if (prevMode === m) {
|
|
84
|
-
setPanelOpenState((prevOpen) => {
|
|
85
|
-
const next = !prevOpen;
|
|
86
|
-
writeStorage(PANEL_OPEN_KEY, String(next));
|
|
87
|
-
return next;
|
|
88
|
-
});
|
|
89
|
-
return prevMode;
|
|
90
|
-
}
|
|
91
|
-
setPanelOpenState(() => {
|
|
92
|
-
writeStorage(PANEL_OPEN_KEY, "true");
|
|
93
|
-
return true;
|
|
94
|
-
});
|
|
95
|
-
writeStorage(SIDEBAR_MODE_KEY, m);
|
|
96
|
-
return m;
|
|
97
|
-
});
|
|
98
|
-
}, []);
|
|
99
|
-
const contentMargin = hidden ? 0 : panelOpen && hasPanels ? SIDEBAR_TOTAL_WIDTH : SIDEBAR_RAIL_WIDTH;
|
|
100
|
-
const value = React.useMemo(
|
|
101
|
-
() => ({
|
|
102
|
-
panelOpen,
|
|
103
|
-
setPanelOpen,
|
|
104
|
-
togglePanel,
|
|
105
|
-
mode,
|
|
106
|
-
setMode,
|
|
107
|
-
switchMode: switchModeStable,
|
|
108
|
-
hidden,
|
|
109
|
-
setHidden,
|
|
110
|
-
contentMargin,
|
|
111
|
-
hasPanels
|
|
112
|
-
}),
|
|
113
|
-
[panelOpen, setPanelOpen, togglePanel, mode, setMode, switchModeStable, hidden, setHidden, contentMargin, hasPanels]
|
|
114
|
-
);
|
|
115
|
-
return /* @__PURE__ */ jsx(SidebarContext.Provider, { value, children });
|
|
116
|
-
}
|
|
117
|
-
function useSidebar() {
|
|
118
|
-
const ctx = React.useContext(SidebarContext);
|
|
119
|
-
if (!ctx) throw new Error("useSidebar must be used within a SidebarProvider");
|
|
120
|
-
return ctx;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// src/dashboard/app-sidebar.tsx
|
|
124
|
-
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
125
|
-
function DefaultLink({
|
|
126
|
-
href,
|
|
127
|
-
to,
|
|
128
|
-
className,
|
|
129
|
-
children,
|
|
130
|
-
...rest
|
|
131
|
-
}) {
|
|
132
|
-
return /* @__PURE__ */ jsx2("a", { href: href ?? to, className, ...rest, children });
|
|
133
|
-
}
|
|
134
|
-
function getInitials(name, email) {
|
|
135
|
-
if (name) return name.split(" ").map((w) => w[0]).filter(Boolean).slice(0, 2).join("").toUpperCase();
|
|
136
|
-
if (email) return email[0].toUpperCase();
|
|
137
|
-
return "?";
|
|
138
|
-
}
|
|
139
|
-
function SettingsIcon({ className }) {
|
|
140
|
-
return /* @__PURE__ */ jsxs("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: [
|
|
141
|
-
/* @__PURE__ */ jsx2("title", { children: "Settings icon" }),
|
|
142
|
-
/* @__PURE__ */ jsx2("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" }),
|
|
143
|
-
/* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "3" })
|
|
144
|
-
] });
|
|
145
|
-
}
|
|
146
|
-
function LogOutIcon({ className }) {
|
|
147
|
-
return /* @__PURE__ */ jsxs("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: [
|
|
148
|
-
/* @__PURE__ */ jsx2("title", { children: "Log out icon" }),
|
|
149
|
-
/* @__PURE__ */ jsx2("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
|
|
150
|
-
/* @__PURE__ */ jsx2("polyline", { points: "16,17 21,12 16,7" }),
|
|
151
|
-
/* @__PURE__ */ jsx2("line", { x1: "21", x2: "9", y1: "12", y2: "12" })
|
|
152
|
-
] });
|
|
153
|
-
}
|
|
154
|
-
function Sidebar({ children, className, style }) {
|
|
155
|
-
const { panelOpen, hidden, hasPanels } = useSidebar();
|
|
156
|
-
return /* @__PURE__ */ jsx2(
|
|
157
|
-
"div",
|
|
158
|
-
{
|
|
159
|
-
"data-sidebar": "true",
|
|
160
|
-
className: cn(
|
|
161
|
-
"fixed inset-y-0 left-0 z-40 flex bg-card border-r border-border transition-[transform,width] duration-200 ease-in-out",
|
|
162
|
-
hidden && "-translate-x-full",
|
|
163
|
-
className
|
|
164
|
-
),
|
|
165
|
-
style: { width: panelOpen && hasPanels ? SIDEBAR_TOTAL_WIDTH : SIDEBAR_RAIL_WIDTH, ...style },
|
|
166
|
-
children
|
|
167
|
-
}
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
function SidebarRail({ children, className, wide = false }) {
|
|
171
|
-
return /* @__PURE__ */ jsx2(
|
|
172
|
-
"div",
|
|
173
|
-
{
|
|
174
|
-
className: cn(
|
|
175
|
-
"flex flex-col h-full shrink-0 bg-transparent",
|
|
176
|
-
wide ? "w-full" : "w-16",
|
|
177
|
-
className
|
|
178
|
-
),
|
|
179
|
-
children
|
|
180
|
-
}
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
function SidebarRailHeader({ children, className }) {
|
|
184
|
-
return /* @__PURE__ */ jsx2("div", { className: cn("flex h-14 items-center justify-center border-b border-border", className), children });
|
|
185
|
-
}
|
|
186
|
-
function SidebarRailNav({ children, className }) {
|
|
187
|
-
return /* @__PURE__ */ jsx2("nav", { className: cn("flex flex-col items-center gap-1 py-3 flex-1", className), children });
|
|
188
|
-
}
|
|
189
|
-
function SidebarRailFooter({ children, className }) {
|
|
190
|
-
return /* @__PURE__ */ jsx2("div", { className: cn("flex flex-col items-center gap-1 pb-3", className), children });
|
|
191
|
-
}
|
|
192
|
-
function RailSeparator({ className }) {
|
|
193
|
-
return /* @__PURE__ */ jsx2("div", { className: cn("my-2 h-px w-10 bg-[var(--md3-outline-variant)]", className) });
|
|
194
|
-
}
|
|
195
|
-
function RailButton({ icon: Icon2, label, isActive, badge, onClick, className, showLabel }) {
|
|
196
|
-
return /* @__PURE__ */ jsxs(
|
|
197
|
-
"button",
|
|
198
|
-
{
|
|
199
|
-
type: "button",
|
|
200
|
-
onClick,
|
|
201
|
-
title: label,
|
|
202
|
-
className: cn(
|
|
203
|
-
"group relative flex items-center justify-center rounded-xl transition-all duration-200",
|
|
204
|
-
showLabel ? "w-full justify-start px-3 h-11 gap-3" : "w-11 h-11 justify-center",
|
|
205
|
-
"hover:bg-[var(--accent-surface-soft)] hover:text-[var(--accent-text)]",
|
|
206
|
-
"active:scale-95",
|
|
207
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",
|
|
208
|
-
isActive && "bg-[var(--accent-surface-strong)] text-[var(--accent-text)]",
|
|
209
|
-
!isActive && "text-muted-foreground",
|
|
210
|
-
className
|
|
211
|
-
),
|
|
212
|
-
children: [
|
|
213
|
-
/* @__PURE__ */ jsx2(Icon2, { className: "h-5 w-5 shrink-0" }),
|
|
214
|
-
showLabel && /* @__PURE__ */ jsx2("span", { className: "text-sm font-medium", children: label }),
|
|
215
|
-
badge !== void 0 && badge > 0 && /* @__PURE__ */ jsx2("span", { className: "absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-primary text-[9px] font-bold text-[var(--md3-on-primary)] px-1 shadow-sm", children: badge > 99 ? "99+" : badge })
|
|
216
|
-
]
|
|
217
|
-
}
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
function RailModeButton({ mode, icon, label, badge, className, showLabel }) {
|
|
221
|
-
const { panelOpen, mode: currentMode, switchMode } = useSidebar();
|
|
222
|
-
return /* @__PURE__ */ jsx2(
|
|
223
|
-
RailButton,
|
|
224
|
-
{
|
|
225
|
-
icon,
|
|
226
|
-
label,
|
|
227
|
-
isActive: mode === currentMode && panelOpen,
|
|
228
|
-
badge,
|
|
229
|
-
onClick: () => switchMode(mode),
|
|
230
|
-
className,
|
|
231
|
-
showLabel
|
|
232
|
-
}
|
|
233
|
-
);
|
|
234
|
-
}
|
|
235
|
-
function SidebarPanel({ children, className }) {
|
|
236
|
-
const { panelOpen } = useSidebar();
|
|
237
|
-
return /* @__PURE__ */ jsx2(
|
|
238
|
-
"div",
|
|
239
|
-
{
|
|
240
|
-
className: cn(
|
|
241
|
-
"transition-[opacity] duration-150 h-full overflow-hidden border-l border-border bg-card",
|
|
242
|
-
panelOpen ? "w-[260px] opacity-100" : "w-0 opacity-0 pointer-events-none",
|
|
243
|
-
className
|
|
244
|
-
),
|
|
245
|
-
children: /* @__PURE__ */ jsx2("div", { className: "flex flex-col h-full w-[260px]", children })
|
|
246
|
-
}
|
|
247
|
-
);
|
|
248
|
-
}
|
|
249
|
-
function SidebarPanelHeader({ children, title, className }) {
|
|
250
|
-
return /* @__PURE__ */ jsx2("div", { className: cn("flex h-14 items-center px-4 border-b border-border shrink-0", className), children: children ?? /* @__PURE__ */ jsx2("h2", { className: "text-sm font-semibold text-foreground", children: title }) });
|
|
251
|
-
}
|
|
252
|
-
function SidebarPanelContent({ children, className }) {
|
|
253
|
-
return /* @__PURE__ */ jsx2("div", { className: cn("flex-1 overflow-y-auto px-2 py-2", className), children });
|
|
254
|
-
}
|
|
255
|
-
function SidebarContent({ children, className }) {
|
|
256
|
-
const { contentMargin } = useSidebar();
|
|
257
|
-
return /* @__PURE__ */ jsx2(
|
|
258
|
-
"main",
|
|
259
|
-
{
|
|
260
|
-
className: cn(
|
|
261
|
-
"min-h-screen transition-[margin-left] duration-200 ease-in-out lg:ml-[var(--sb-content-margin,0px)]",
|
|
262
|
-
className
|
|
263
|
-
),
|
|
264
|
-
style: { "--sb-content-margin": `${contentMargin}px` },
|
|
265
|
-
children
|
|
266
|
-
}
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
function ProfileAvatar({
|
|
270
|
-
user,
|
|
271
|
-
isLoading = false,
|
|
272
|
-
onLogout,
|
|
273
|
-
onSettingsClick,
|
|
274
|
-
settingsHref = "/dashboard/settings",
|
|
275
|
-
children,
|
|
276
|
-
className,
|
|
277
|
-
LinkComponent
|
|
278
|
-
}) {
|
|
279
|
-
const Link = LinkComponent ?? DefaultLink;
|
|
280
|
-
return /* @__PURE__ */ jsxs(DropdownMenu, { children: [
|
|
281
|
-
/* @__PURE__ */ jsx2(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx2(
|
|
282
|
-
"button",
|
|
283
|
-
{
|
|
284
|
-
type: "button",
|
|
285
|
-
className: cn(
|
|
286
|
-
"flex items-center justify-center w-12 h-12 rounded-lg transition-colors hover:bg-[var(--accent-surface-soft)]",
|
|
287
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",
|
|
288
|
-
className
|
|
289
|
-
),
|
|
290
|
-
"aria-label": "User menu",
|
|
291
|
-
children: isLoading ? /* @__PURE__ */ jsx2(Skeleton, { className: "h-7 w-7 rounded-full" }) : /* @__PURE__ */ jsxs(Avatar, { className: "h-7 w-7", children: [
|
|
292
|
-
user?.avatarUrl && /* @__PURE__ */ jsx2(AvatarImage, { src: user.avatarUrl, alt: "" }),
|
|
293
|
-
/* @__PURE__ */ jsx2(AvatarFallback, { className: "text-[10px] bg-violet-500/20 text-violet-300", children: getInitials(user?.name, user?.email) })
|
|
294
|
-
] })
|
|
295
|
-
}
|
|
296
|
-
) }),
|
|
297
|
-
/* @__PURE__ */ jsxs(DropdownMenuContent, { side: "right", align: "end", sideOffset: 8, className: "w-72", children: [
|
|
298
|
-
/* @__PURE__ */ jsx2(DropdownMenuLabel, { className: "p-0 font-normal", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 px-2 py-3", children: [
|
|
299
|
-
/* @__PURE__ */ jsxs(Avatar, { className: "h-12 w-12 shrink-0", children: [
|
|
300
|
-
user?.avatarUrl && /* @__PURE__ */ jsx2(AvatarImage, { src: user.avatarUrl, alt: "" }),
|
|
301
|
-
/* @__PURE__ */ jsx2(AvatarFallback, { className: "text-sm bg-[var(--surface-violet-bg)] text-[var(--surface-violet-text)]", children: getInitials(user?.name, user?.email) })
|
|
302
|
-
] }),
|
|
303
|
-
/* @__PURE__ */ jsx2("div", { className: "min-w-0 flex-1", children: isLoading ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
304
|
-
/* @__PURE__ */ jsx2(Skeleton, { className: "h-4 w-24 mb-1" }),
|
|
305
|
-
/* @__PURE__ */ jsx2(Skeleton, { className: "h-3 w-32" })
|
|
306
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
307
|
-
/* @__PURE__ */ jsx2("p", { className: "text-sm font-semibold truncate", children: user?.name ?? user?.email ?? "Not logged in" }),
|
|
308
|
-
user?.email && user?.name && /* @__PURE__ */ jsx2("p", { className: "text-xs text-muted-foreground truncate", children: user.email }),
|
|
309
|
-
user?.tier && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground capitalize", children: [
|
|
310
|
-
user.tier,
|
|
311
|
-
" Plan"
|
|
312
|
-
] })
|
|
313
|
-
] }) })
|
|
314
|
-
] }) }),
|
|
315
|
-
/* @__PURE__ */ jsx2(DropdownMenuSeparator, {}),
|
|
316
|
-
children,
|
|
317
|
-
onSettingsClick ? /* @__PURE__ */ jsxs(DropdownMenuItem, { onClick: onSettingsClick, children: [
|
|
318
|
-
/* @__PURE__ */ jsx2(SettingsIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
|
|
319
|
-
"Settings"
|
|
320
|
-
] }) : /* @__PURE__ */ jsx2(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs(Link, { href: settingsHref, to: settingsHref, className: "flex items-center", children: [
|
|
321
|
-
/* @__PURE__ */ jsx2(SettingsIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
|
|
322
|
-
"Settings"
|
|
323
|
-
] }) }),
|
|
324
|
-
onLogout && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
325
|
-
/* @__PURE__ */ jsx2(DropdownMenuSeparator, {}),
|
|
326
|
-
/* @__PURE__ */ jsxs(DropdownMenuItem, { className: "text-[var(--surface-danger-text)]", onClick: onLogout, children: [
|
|
327
|
-
/* @__PURE__ */ jsx2(LogOutIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
|
|
328
|
-
"Sign Out"
|
|
329
|
-
] })
|
|
330
|
-
] })
|
|
331
|
-
] })
|
|
332
|
-
] });
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// src/dashboard/cluster-status-bar.tsx
|
|
336
|
-
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
337
|
-
function ClusterStatusBar({ items, latency, className }) {
|
|
338
|
-
if (!items?.length) return null;
|
|
339
|
-
return /* @__PURE__ */ jsx3("div", { className: cn("fixed bottom-6 left-1/2 -translate-x-1/2 z-40 w-max max-w-[90vw] animate-in slide-in-from-bottom flex justify-center", className), children: /* @__PURE__ */ jsxs2("div", { className: "overflow-hidden rounded-full border border-border bg-card px-6 py-3 flex flex-wrap sm:flex-nowrap items-center justify-between gap-8 shadow-sm", children: [
|
|
340
|
-
/* @__PURE__ */ jsx3("div", { className: "flex items-center gap-6", children: items.map((item, i) => /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
|
|
341
|
-
/* @__PURE__ */ jsx3("span", { className: "text-[var(--md3-primary)] [&_svg]:h-[18px] [&_svg]:w-[18px]", children: item.icon }),
|
|
342
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex flex-col", children: [
|
|
343
|
-
/* @__PURE__ */ jsx3("span", { className: "text-[10px] text-[var(--md3-on-surface-variant)] uppercase tracking-wider font-bold", children: item.label }),
|
|
344
|
-
/* @__PURE__ */ jsx3("span", { className: cn("text-xs font-bold text-foreground", item.valueClass), children: item.value })
|
|
345
|
-
] })
|
|
346
|
-
] }, i)) }),
|
|
347
|
-
latency && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
348
|
-
/* @__PURE__ */ jsx3("div", { className: "h-6 w-px bg-border" }),
|
|
349
|
-
/* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3", children: [
|
|
350
|
-
/* @__PURE__ */ jsxs2("div", { className: "relative flex h-2.5 w-2.5 items-center justify-center", children: [
|
|
351
|
-
/* @__PURE__ */ jsx3("span", { className: "absolute inline-flex h-full w-full animate-ping rounded-full bg-green-400 opacity-75" }),
|
|
352
|
-
/* @__PURE__ */ jsx3("span", { className: "relative inline-flex h-2 w-2 rounded-full bg-green-500" })
|
|
353
|
-
] }),
|
|
354
|
-
/* @__PURE__ */ jsx3("span", { className: "text-xs font-mono text-green-400 font-bold", children: latency })
|
|
355
|
-
] })
|
|
356
|
-
] })
|
|
357
|
-
] }) });
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// src/dashboard/credit-balance.tsx
|
|
361
|
-
import * as React2 from "react";
|
|
362
|
-
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
363
|
-
function CreditBalance({
|
|
364
|
-
amount,
|
|
365
|
-
description = "Credits are automatically deducted based on hourly Sandbox usage and Agent operations.",
|
|
366
|
-
onTopUp,
|
|
367
|
-
quickAmounts = [10, 25, 100],
|
|
368
|
-
className
|
|
369
|
-
}) {
|
|
370
|
-
const [topUpValue, setTopUpValue] = React2.useState("50.00");
|
|
371
|
-
return /* @__PURE__ */ jsxs3(
|
|
372
|
-
"div",
|
|
373
|
-
{
|
|
374
|
-
className: cn(
|
|
375
|
-
"bg-card p-5 rounded-xl flex flex-col justify-between border border-border",
|
|
376
|
-
className
|
|
377
|
-
),
|
|
378
|
-
children: [
|
|
379
|
-
/* @__PURE__ */ jsxs3("div", { children: [
|
|
380
|
-
/* @__PURE__ */ jsx4("h3", { className: "text-sm font-semibold text-muted-foreground uppercase tracking-widest mb-2", children: "Available Credits" }),
|
|
381
|
-
/* @__PURE__ */ jsxs3("div", { className: "text-4xl font-extrabold text-primary tracking-tighter mb-2", children: [
|
|
382
|
-
"$",
|
|
383
|
-
amount.toFixed(2)
|
|
384
|
-
] }),
|
|
385
|
-
/* @__PURE__ */ jsx4("p", { className: "text-sm text-muted-foreground leading-relaxed", children: description })
|
|
386
|
-
] }),
|
|
387
|
-
onTopUp && /* @__PURE__ */ jsxs3("div", { className: "space-y-2.5 mt-5", children: [
|
|
388
|
-
/* @__PURE__ */ jsxs3("div", { className: "bg-card border border-border p-1 rounded-lg flex items-center", children: [
|
|
389
|
-
/* @__PURE__ */ jsx4(
|
|
390
|
-
"input",
|
|
391
|
-
{
|
|
392
|
-
type: "text",
|
|
393
|
-
value: `$${topUpValue}`,
|
|
394
|
-
onChange: (e) => {
|
|
395
|
-
const raw = e.target.value.replace(/[^0-9.]/g, "");
|
|
396
|
-
setTopUpValue(raw.match(/^(\d*\.?\d{0,2})/)?.[1] ?? "");
|
|
397
|
-
},
|
|
398
|
-
className: "bg-transparent border-none text-foreground font-mono text-lg w-full focus:ring-0 px-4 outline-none"
|
|
399
|
-
}
|
|
400
|
-
),
|
|
401
|
-
/* @__PURE__ */ jsx4(
|
|
402
|
-
"button",
|
|
403
|
-
{
|
|
404
|
-
type: "button",
|
|
405
|
-
onClick: () => {
|
|
406
|
-
const parsed = Number.parseFloat(topUpValue);
|
|
407
|
-
if (!Number.isFinite(parsed) || parsed <= 0) return;
|
|
408
|
-
onTopUp(parsed);
|
|
409
|
-
},
|
|
410
|
-
className: "bg-[var(--accent-surface-soft)] border border-border text-[var(--accent-text)] px-6 py-3 rounded-md font-bold text-xs uppercase tracking-widest active:scale-95 transition-transform hover:bg-[var(--accent-surface-strong)]",
|
|
411
|
-
children: "Top Up"
|
|
412
|
-
}
|
|
413
|
-
)
|
|
414
|
-
] }),
|
|
415
|
-
/* @__PURE__ */ jsx4("div", { className: "flex justify-between gap-2", children: quickAmounts.filter((qa) => Number.isFinite(qa) && qa > 0).map((qa) => /* @__PURE__ */ jsxs3(
|
|
416
|
-
"button",
|
|
417
|
-
{
|
|
418
|
-
type: "button",
|
|
419
|
-
onClick: () => {
|
|
420
|
-
const rounded = parseFloat(qa.toFixed(2));
|
|
421
|
-
setTopUpValue(qa.toFixed(2));
|
|
422
|
-
onTopUp(rounded);
|
|
423
|
-
},
|
|
424
|
-
className: "flex-1 py-2 text-[10px] font-mono text-muted-foreground border border-border rounded-md hover:bg-muted/50 hover:text-foreground transition-colors uppercase",
|
|
425
|
-
children: [
|
|
426
|
-
"+$",
|
|
427
|
-
qa
|
|
428
|
-
]
|
|
429
|
-
},
|
|
430
|
-
qa
|
|
431
|
-
)) })
|
|
432
|
-
] })
|
|
433
|
-
]
|
|
434
|
-
}
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// src/dashboard/invoice-table.tsx
|
|
439
|
-
import { Download, FileText } from "lucide-react";
|
|
440
|
-
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
441
|
-
var statusStyle = {
|
|
442
|
-
paid: "bg-[var(--accent-surface-soft)] text-primary border border-border",
|
|
443
|
-
pending: "bg-[var(--surface-warning-bg)] text-[var(--surface-warning-text)] border border-[var(--surface-warning-border)]",
|
|
444
|
-
failed: "bg-[var(--surface-danger-bg)] text-[var(--surface-danger-text)] border border-[var(--surface-danger-border)]"
|
|
445
|
-
};
|
|
446
|
-
function InvoiceTable({ invoices, onExportAll, onLoadMore, onViewInvoice, hasMore, className }) {
|
|
447
|
-
return /* @__PURE__ */ jsxs4("section", { className, children: [
|
|
448
|
-
/* @__PURE__ */ jsxs4("div", { className: "flex justify-between items-center mb-6 px-2", children: [
|
|
449
|
-
/* @__PURE__ */ jsx5("h2", { className: "text-2xl font-bold text-foreground tracking-tight", children: "Invoice History" }),
|
|
450
|
-
onExportAll && /* @__PURE__ */ jsxs4("button", { type: "button", onClick: onExportAll, className: "text-[10px] font-mono text-primary uppercase tracking-widest flex items-center gap-2 hover:underline", children: [
|
|
451
|
-
/* @__PURE__ */ jsx5(Download, { className: "h-3.5 w-3.5" }),
|
|
452
|
-
"Export All"
|
|
453
|
-
] })
|
|
454
|
-
] }),
|
|
455
|
-
/* @__PURE__ */ jsx5("div", { className: "bg-card rounded-xl overflow-hidden border border-border", children: /* @__PURE__ */ jsxs4("table", { className: "w-full text-left border-collapse", children: [
|
|
456
|
-
/* @__PURE__ */ jsx5("thead", { children: /* @__PURE__ */ jsxs4("tr", { className: "bg-background border-b border-border", children: [
|
|
457
|
-
/* @__PURE__ */ jsx5("th", { className: "px-6 py-4 font-mono text-[10px] text-muted-foreground uppercase tracking-widest", children: "Invoice ID" }),
|
|
458
|
-
/* @__PURE__ */ jsx5("th", { className: "px-6 py-4 font-mono text-[10px] text-muted-foreground uppercase tracking-widest", children: "Date" }),
|
|
459
|
-
/* @__PURE__ */ jsx5("th", { className: "px-6 py-4 font-mono text-[10px] text-muted-foreground uppercase tracking-widest", children: "Amount" }),
|
|
460
|
-
/* @__PURE__ */ jsx5("th", { className: "px-6 py-4 font-mono text-[10px] text-muted-foreground uppercase tracking-widest", children: "Status" }),
|
|
461
|
-
/* @__PURE__ */ jsx5("th", { className: "px-6 py-4 font-mono text-[10px] text-muted-foreground uppercase tracking-widest text-right", children: "Action" })
|
|
462
|
-
] }) }),
|
|
463
|
-
/* @__PURE__ */ jsx5("tbody", { className: "divide-y divide-border", children: invoices.map((inv) => /* @__PURE__ */ jsxs4("tr", { className: "hover:bg-muted/50 transition-colors", children: [
|
|
464
|
-
/* @__PURE__ */ jsx5("td", { className: "px-6 py-5 font-mono text-xs text-foreground", children: inv.id }),
|
|
465
|
-
/* @__PURE__ */ jsx5("td", { className: "px-6 py-5 text-sm text-foreground", children: inv.date }),
|
|
466
|
-
/* @__PURE__ */ jsxs4("td", { className: "px-6 py-5 text-sm font-bold text-foreground", children: [
|
|
467
|
-
"$",
|
|
468
|
-
inv.amount.toFixed(2)
|
|
469
|
-
] }),
|
|
470
|
-
/* @__PURE__ */ jsx5("td", { className: "px-6 py-5", children: /* @__PURE__ */ jsx5("span", { className: cn("px-2 py-1 text-[10px] font-mono rounded uppercase", statusStyle[inv.status] ?? statusStyle.paid), children: inv.status }) }),
|
|
471
|
-
/* @__PURE__ */ jsx5("td", { className: "px-6 py-5 text-right", children: /* @__PURE__ */ jsx5("button", { type: "button", onClick: () => onViewInvoice?.(inv.id), className: "text-muted-foreground hover:text-foreground transition-colors", children: /* @__PURE__ */ jsx5(FileText, { className: "h-4 w-4" }) }) })
|
|
472
|
-
] }, inv.id)) })
|
|
473
|
-
] }) }),
|
|
474
|
-
hasMore && onLoadMore && /* @__PURE__ */ jsx5("div", { className: "mt-6 flex justify-center", children: /* @__PURE__ */ jsx5("button", { type: "button", onClick: onLoadMore, className: "px-8 py-2 text-[10px] font-mono text-muted-foreground border border-border rounded-full hover:bg-muted/50 transition-colors uppercase tracking-widest", children: "Load More History" }) })
|
|
475
|
-
] });
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// src/dashboard/plan-cards.tsx
|
|
479
|
-
import { Check } from "lucide-react";
|
|
480
|
-
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
481
|
-
function PlanCards({ plans, className }) {
|
|
482
|
-
return /* @__PURE__ */ jsxs5("section", { className, children: [
|
|
483
|
-
/* @__PURE__ */ jsx6("h2", { className: "text-2xl font-bold text-foreground tracking-tight mb-5 px-2", children: "Subscription Plans" }),
|
|
484
|
-
/* @__PURE__ */ jsx6("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-6", children: plans.map((plan) => /* @__PURE__ */ jsxs5(
|
|
485
|
-
"div",
|
|
486
|
-
{
|
|
487
|
-
className: cn(
|
|
488
|
-
"p-5 rounded-xl transition-all relative overflow-hidden border",
|
|
489
|
-
plan.popular ? "bg-muted/50 border-border" : "bg-card border-border hover:bg-muted/50 hover:border-primary/20"
|
|
490
|
-
),
|
|
491
|
-
children: [
|
|
492
|
-
plan.popular && /* @__PURE__ */ jsx6("div", { className: "absolute top-0 right-0 bg-[var(--accent-surface-soft)] border-l border-b border-border px-4 py-1 text-[10px] font-bold text-[var(--accent-text)] uppercase tracking-widest rounded-bl-lg", children: "Popular" }),
|
|
493
|
-
/* @__PURE__ */ jsxs5("div", { className: "mb-4", children: [
|
|
494
|
-
/* @__PURE__ */ jsx6("div", { className: cn("text-xs font-mono uppercase tracking-widest mb-2", plan.popular ? "text-primary" : "text-muted-foreground"), children: plan.name }),
|
|
495
|
-
/* @__PURE__ */ jsxs5("div", { className: "text-3xl font-bold text-foreground", children: [
|
|
496
|
-
"$",
|
|
497
|
-
plan.price,
|
|
498
|
-
/* @__PURE__ */ jsxs5("span", { className: "text-sm font-normal text-muted-foreground tracking-normal", children: [
|
|
499
|
-
"/",
|
|
500
|
-
plan.period ?? "mo"
|
|
501
|
-
] })
|
|
502
|
-
] })
|
|
503
|
-
] }),
|
|
504
|
-
/* @__PURE__ */ jsx6("ul", { className: "space-y-2 mb-5 text-sm text-muted-foreground", children: plan.features.map((f, i) => /* @__PURE__ */ jsxs5("li", { className: "flex items-center gap-2", children: [
|
|
505
|
-
/* @__PURE__ */ jsx6(Check, { className: "h-3.5 w-3.5 text-primary shrink-0" }),
|
|
506
|
-
f.text
|
|
507
|
-
] }, i)) }),
|
|
508
|
-
/* @__PURE__ */ jsx6(
|
|
509
|
-
"button",
|
|
510
|
-
{
|
|
511
|
-
type: "button",
|
|
512
|
-
onClick: () => plan.onSelect?.(plan.id),
|
|
513
|
-
className: cn(
|
|
514
|
-
"w-full py-3 rounded-lg text-xs font-bold uppercase tracking-widest transition-all border",
|
|
515
|
-
plan.current ? "border-border text-muted-foreground hover:border-primary/20 hover:text-foreground" : plan.popular ? "bg-[var(--accent-surface-soft)] border-border text-[var(--accent-text)] hover:bg-[var(--accent-surface-strong)] active:scale-95 transition-transform" : "border-border text-foreground hover:border-primary/20 hover:text-primary"
|
|
516
|
-
),
|
|
517
|
-
children: plan.ctaLabel ?? (plan.current ? "Current Plan" : "Upgrade Now")
|
|
518
|
-
}
|
|
519
|
-
)
|
|
520
|
-
]
|
|
521
|
-
},
|
|
522
|
-
plan.id
|
|
523
|
-
)) })
|
|
524
|
-
] });
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
// src/dashboard/dashboard-layout.tsx
|
|
528
|
-
import * as React3 from "react";
|
|
529
|
-
import { Plus, Bell } from "lucide-react";
|
|
530
|
-
import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
531
|
-
function SettingsIconSmall({ className }) {
|
|
532
|
-
return /* @__PURE__ */ jsxs6("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: [
|
|
533
|
-
/* @__PURE__ */ jsx7("title", { children: "Settings" }),
|
|
534
|
-
/* @__PURE__ */ jsx7("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" }),
|
|
535
|
-
/* @__PURE__ */ jsx7("circle", { cx: "12", cy: "12", r: "3" })
|
|
536
|
-
] });
|
|
537
|
-
}
|
|
538
|
-
function MenuIcon({ className }) {
|
|
539
|
-
return /* @__PURE__ */ jsxs6("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: [
|
|
540
|
-
/* @__PURE__ */ jsx7("title", { children: "Menu icon" }),
|
|
541
|
-
/* @__PURE__ */ jsx7("line", { x1: "4", x2: "20", y1: "12", y2: "12" }),
|
|
542
|
-
/* @__PURE__ */ jsx7("line", { x1: "4", x2: "20", y1: "6", y2: "6" }),
|
|
543
|
-
/* @__PURE__ */ jsx7("line", { x1: "4", x2: "20", y1: "18", y2: "18" })
|
|
544
|
-
] });
|
|
545
|
-
}
|
|
546
|
-
function XIcon({ className }) {
|
|
547
|
-
return /* @__PURE__ */ jsxs6("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: [
|
|
548
|
-
/* @__PURE__ */ jsx7("title", { children: "Close icon" }),
|
|
549
|
-
/* @__PURE__ */ jsx7("path", { d: "M18 6 6 18" }),
|
|
550
|
-
/* @__PURE__ */ jsx7("path", { d: "m6 6 12 12" })
|
|
551
|
-
] });
|
|
552
|
-
}
|
|
553
|
-
function formatNotifDate(raw) {
|
|
554
|
-
const d = new Date(raw);
|
|
555
|
-
return Number.isNaN(d.getTime()) ? raw : d.toLocaleString(void 0, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
|
556
|
-
}
|
|
557
|
-
function DefaultLink2({
|
|
558
|
-
href,
|
|
559
|
-
to,
|
|
560
|
-
className,
|
|
561
|
-
children,
|
|
562
|
-
...rest
|
|
563
|
-
}) {
|
|
564
|
-
return /* @__PURE__ */ jsx7("a", { href: href ?? to, className, ...rest, children });
|
|
565
|
-
}
|
|
566
|
-
function DashboardLayoutInner({
|
|
567
|
-
children,
|
|
568
|
-
variant = "sandbox",
|
|
569
|
-
navItems,
|
|
570
|
-
modeItems = [],
|
|
571
|
-
panels = [],
|
|
572
|
-
activeNavId,
|
|
573
|
-
user,
|
|
574
|
-
isLoading = false,
|
|
575
|
-
onLogout,
|
|
576
|
-
onSettingsClick,
|
|
577
|
-
settingsHref = "/dashboard/settings",
|
|
578
|
-
onNewSandbox,
|
|
579
|
-
className,
|
|
580
|
-
sidebarClassName,
|
|
581
|
-
contentClassName,
|
|
582
|
-
topNavLinks,
|
|
583
|
-
activeTopNavHref,
|
|
584
|
-
LinkComponent = DefaultLink2,
|
|
585
|
-
footer,
|
|
586
|
-
railFooter,
|
|
587
|
-
profileMenuItems,
|
|
588
|
-
notifications: notifData
|
|
589
|
-
}) {
|
|
590
|
-
const Link = LinkComponent;
|
|
591
|
-
const [mobileMenuOpen, setMobileMenuOpen] = React3.useState(false);
|
|
592
|
-
const [notificationsOpen, setNotificationsOpen] = React3.useState(false);
|
|
593
|
-
const notifRef = React3.useRef(null);
|
|
594
|
-
React3.useEffect(() => {
|
|
595
|
-
if (!notificationsOpen) return;
|
|
596
|
-
const handler = (e) => {
|
|
597
|
-
if (notifRef.current && !notifRef.current.contains(e.target)) {
|
|
598
|
-
setNotificationsOpen(false);
|
|
599
|
-
}
|
|
600
|
-
};
|
|
601
|
-
const keyHandler = (e) => {
|
|
602
|
-
if (e.key === "Escape") setNotificationsOpen(false);
|
|
603
|
-
};
|
|
604
|
-
document.addEventListener("mousedown", handler);
|
|
605
|
-
document.addEventListener("keydown", keyHandler);
|
|
606
|
-
return () => {
|
|
607
|
-
document.removeEventListener("mousedown", handler);
|
|
608
|
-
document.removeEventListener("keydown", keyHandler);
|
|
609
|
-
};
|
|
610
|
-
}, [notificationsOpen]);
|
|
611
|
-
const { contentMargin, hidden, mode, hasPanels, panelOpen } = useSidebar();
|
|
612
|
-
const modeSet = React3.useMemo(() => new Set(modeItems), [modeItems]);
|
|
613
|
-
const sidebarUser = React3.useMemo(
|
|
614
|
-
() => user ? { email: user.email, name: user.name, tier: user.tier, avatarUrl: user.avatarUrl } : void 0,
|
|
615
|
-
[user?.email, user?.name, user?.tier, user?.avatarUrl]
|
|
616
|
-
);
|
|
617
|
-
const activePanel = panels.find((p) => p.mode === mode);
|
|
618
|
-
const buildSidebarContent = React3.useCallback(
|
|
619
|
-
(showLabels) => /* @__PURE__ */ jsxs6(Fragment4, { children: [
|
|
620
|
-
/* @__PURE__ */ jsxs6(SidebarRail, { wide: showLabels, children: [
|
|
621
|
-
/* @__PURE__ */ jsx7(SidebarRailHeader, { children: /* @__PURE__ */ jsx7(Link, { href: "/", to: "/", className: "p-1 rounded-md transition-colors hover:bg-muted/50", children: /* @__PURE__ */ jsx7(Logo, { variant, size: "sm", iconOnly: true }) }) }),
|
|
622
|
-
/* @__PURE__ */ jsx7(SidebarRailNav, { children: navItems.map((item, i) => {
|
|
623
|
-
const isMode = modeSet.has(item.id);
|
|
624
|
-
const prevIsMode = i > 0 && modeSet.has(navItems[i - 1].id);
|
|
625
|
-
const showSep = i > 0 && isMode && !prevIsMode;
|
|
626
|
-
return /* @__PURE__ */ jsxs6(React3.Fragment, { children: [
|
|
627
|
-
showSep && /* @__PURE__ */ jsx7(RailSeparator, {}),
|
|
628
|
-
isMode ? /* @__PURE__ */ jsx7(
|
|
629
|
-
RailModeButton,
|
|
630
|
-
{
|
|
631
|
-
mode: item.id,
|
|
632
|
-
icon: item.icon,
|
|
633
|
-
label: item.label,
|
|
634
|
-
badge: item.badge,
|
|
635
|
-
showLabel: showLabels
|
|
636
|
-
}
|
|
637
|
-
) : /* @__PURE__ */ jsx7(Link, { href: item.href, to: item.href, children: /* @__PURE__ */ jsx7(
|
|
638
|
-
RailButton,
|
|
639
|
-
{
|
|
640
|
-
icon: item.icon,
|
|
641
|
-
label: item.label,
|
|
642
|
-
isActive: activeNavId === item.id,
|
|
643
|
-
showLabel: showLabels
|
|
644
|
-
}
|
|
645
|
-
) })
|
|
646
|
-
] }, item.id);
|
|
647
|
-
}) }),
|
|
648
|
-
/* @__PURE__ */ jsxs6(SidebarRailFooter, { children: [
|
|
649
|
-
onSettingsClick ? /* @__PURE__ */ jsx7(RailButton, { icon: SettingsIconSmall, label: "Settings", onClick: onSettingsClick, showLabel: showLabels }) : /* @__PURE__ */ jsx7(Link, { href: settingsHref, to: settingsHref, children: /* @__PURE__ */ jsx7(RailButton, { icon: SettingsIconSmall, label: "Settings", showLabel: showLabels }) }),
|
|
650
|
-
railFooter,
|
|
651
|
-
/* @__PURE__ */ jsx7(RailSeparator, {}),
|
|
652
|
-
/* @__PURE__ */ jsx7(
|
|
653
|
-
ProfileAvatar,
|
|
654
|
-
{
|
|
655
|
-
user: sidebarUser,
|
|
656
|
-
isLoading,
|
|
657
|
-
onLogout,
|
|
658
|
-
onSettingsClick,
|
|
659
|
-
settingsHref,
|
|
660
|
-
LinkComponent,
|
|
661
|
-
children: profileMenuItems
|
|
662
|
-
}
|
|
663
|
-
)
|
|
664
|
-
] })
|
|
665
|
-
] }),
|
|
666
|
-
panels.length > 0 && /* @__PURE__ */ jsxs6(SidebarPanel, { children: [
|
|
667
|
-
/* @__PURE__ */ jsx7(SidebarPanelHeader, { title: activePanel?.title ?? mode }),
|
|
668
|
-
/* @__PURE__ */ jsx7(SidebarPanelContent, { children: activePanel?.content })
|
|
669
|
-
] })
|
|
670
|
-
] }),
|
|
671
|
-
// biome-ignore lint/correctness/useExhaustiveDependencies: intentional — only the inputs that actually affect the sidebar tree
|
|
672
|
-
[
|
|
673
|
-
Link,
|
|
674
|
-
variant,
|
|
675
|
-
navItems,
|
|
676
|
-
modeSet,
|
|
677
|
-
activeNavId,
|
|
678
|
-
onSettingsClick,
|
|
679
|
-
settingsHref,
|
|
680
|
-
railFooter,
|
|
681
|
-
sidebarUser,
|
|
682
|
-
isLoading,
|
|
683
|
-
onLogout,
|
|
684
|
-
LinkComponent,
|
|
685
|
-
profileMenuItems,
|
|
686
|
-
panels,
|
|
687
|
-
activePanel,
|
|
688
|
-
mode
|
|
689
|
-
]
|
|
690
|
-
);
|
|
691
|
-
const sidebarContent = React3.useMemo(() => buildSidebarContent(false), [buildSidebarContent]);
|
|
692
|
-
const mobileSidebarContent = React3.useMemo(() => buildSidebarContent(true), [buildSidebarContent]);
|
|
693
|
-
return /* @__PURE__ */ jsxs6("div", { className: cn("min-h-screen bg-background text-foreground", className), children: [
|
|
694
|
-
/* @__PURE__ */ jsxs6(
|
|
695
|
-
"nav",
|
|
696
|
-
{
|
|
697
|
-
className: "fixed top-0 z-50 bg-card border-b border-border flex justify-between items-center px-8 h-14 font-sans text-[13px] tracking-tight transition-[left,width] duration-200 ease-in-out",
|
|
698
|
-
style: {
|
|
699
|
-
left: hidden ? 0 : contentMargin,
|
|
700
|
-
width: hidden ? "100%" : `calc(100% - ${contentMargin}px)`
|
|
701
|
-
},
|
|
702
|
-
children: [
|
|
703
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-8", children: [
|
|
704
|
-
/* @__PURE__ */ jsx7(Link, { href: "/", to: "/", className: "lg:hidden flex items-center p-1 rounded-md hover:bg-muted/50 transition-colors", children: /* @__PURE__ */ jsx7(Logo, { variant, size: "sm", iconOnly: true }) }),
|
|
705
|
-
topNavLinks && topNavLinks.length > 0 && /* @__PURE__ */ jsx7("div", { className: "hidden md:flex gap-6", children: topNavLinks.map((link) => /* @__PURE__ */ jsx7(
|
|
706
|
-
Link,
|
|
707
|
-
{
|
|
708
|
-
href: link.href,
|
|
709
|
-
to: link.href,
|
|
710
|
-
className: cn(
|
|
711
|
-
"transition-all duration-300 px-2 py-1 rounded",
|
|
712
|
-
activeTopNavHref === link.href ? "text-foreground border-b-2 border-primary pb-1" : "text-muted-foreground hover:text-foreground hover:bg-muted/50"
|
|
713
|
-
),
|
|
714
|
-
children: link.label
|
|
715
|
-
},
|
|
716
|
-
link.href
|
|
717
|
-
)) })
|
|
718
|
-
] }),
|
|
719
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-4", children: [
|
|
720
|
-
onNewSandbox && /* @__PURE__ */ jsxs6(
|
|
721
|
-
"button",
|
|
722
|
-
{
|
|
723
|
-
type: "button",
|
|
724
|
-
onClick: onNewSandbox,
|
|
725
|
-
className: "hidden md:flex items-center gap-2 bg-[var(--btn-primary-bg)] border border-[var(--border-accent)] text-[var(--btn-primary-text)] px-4 py-2 rounded-lg font-bold hover:bg-[var(--btn-primary-hover)] transition-all active:scale-95 text-xs",
|
|
726
|
-
children: [
|
|
727
|
-
/* @__PURE__ */ jsx7(Plus, { className: "h-3.5 w-3.5" }),
|
|
728
|
-
"New Sandbox"
|
|
729
|
-
]
|
|
730
|
-
}
|
|
731
|
-
),
|
|
732
|
-
/* @__PURE__ */ jsxs6("div", { className: "relative", ref: notifRef, children: [
|
|
733
|
-
/* @__PURE__ */ jsxs6(
|
|
734
|
-
"button",
|
|
735
|
-
{
|
|
736
|
-
type: "button",
|
|
737
|
-
className: "relative text-muted-foreground hover:text-foreground transition-colors p-2 rounded-lg hover:bg-muted/50",
|
|
738
|
-
onClick: () => setNotificationsOpen(!notificationsOpen),
|
|
739
|
-
"aria-label": "Notifications",
|
|
740
|
-
"aria-expanded": notificationsOpen,
|
|
741
|
-
children: [
|
|
742
|
-
/* @__PURE__ */ jsx7(Bell, { className: "h-4 w-4" }),
|
|
743
|
-
(notifData?.unreadCount ?? 0) > 0 && /* @__PURE__ */ jsx7("span", { className: "absolute top-1 right-1 h-2 w-2 rounded-full bg-destructive" })
|
|
744
|
-
]
|
|
745
|
-
}
|
|
746
|
-
),
|
|
747
|
-
notificationsOpen && /* @__PURE__ */ jsxs6("div", { className: "absolute right-0 top-full mt-2 w-80 rounded-lg border border-border bg-card shadow-lg z-50", children: [
|
|
748
|
-
/* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between border-b border-border px-4 py-3", children: [
|
|
749
|
-
/* @__PURE__ */ jsx7("p", { className: "font-bold text-foreground text-sm", children: "Notifications" }),
|
|
750
|
-
(notifData?.unreadCount ?? 0) > 0 && notifData?.onMarkAllRead && /* @__PURE__ */ jsx7(
|
|
751
|
-
"button",
|
|
752
|
-
{
|
|
753
|
-
type: "button",
|
|
754
|
-
onClick: () => {
|
|
755
|
-
notifData.onMarkAllRead?.();
|
|
756
|
-
},
|
|
757
|
-
className: "text-primary text-xs font-medium hover:underline",
|
|
758
|
-
children: "Mark all read"
|
|
759
|
-
}
|
|
760
|
-
)
|
|
761
|
-
] }),
|
|
762
|
-
!notifData?.items || notifData.items.length === 0 ? /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center justify-center px-4 py-8 text-center", children: [
|
|
763
|
-
/* @__PURE__ */ jsx7(Bell, { className: "h-8 w-8 text-muted-foreground/40 mb-2" }),
|
|
764
|
-
/* @__PURE__ */ jsx7("p", { className: "text-muted-foreground text-sm", children: "No notifications yet" }),
|
|
765
|
-
/* @__PURE__ */ jsx7("p", { className: "text-muted-foreground/60 text-xs mt-1", children: "We'll notify you about important updates" })
|
|
766
|
-
] }) : /* @__PURE__ */ jsx7("div", { className: "max-h-80 overflow-y-auto", children: notifData.items.map((n) => /* @__PURE__ */ jsxs6(
|
|
767
|
-
"button",
|
|
768
|
-
{
|
|
769
|
-
type: "button",
|
|
770
|
-
className: cn(
|
|
771
|
-
"w-full text-left px-4 py-3 border-b border-border last:border-0 transition-colors",
|
|
772
|
-
n.read ? "cursor-default" : "bg-primary/5 hover:bg-muted/50"
|
|
773
|
-
),
|
|
774
|
-
onClick: () => {
|
|
775
|
-
if (!n.read) notifData.onMarkRead?.(n.id);
|
|
776
|
-
},
|
|
777
|
-
children: [
|
|
778
|
-
/* @__PURE__ */ jsx7("p", { className: cn("text-sm", !n.read ? "font-semibold text-foreground" : "text-muted-foreground"), children: n.title }),
|
|
779
|
-
/* @__PURE__ */ jsx7("p", { className: "text-xs text-muted-foreground mt-0.5 line-clamp-2", children: n.message }),
|
|
780
|
-
/* @__PURE__ */ jsx7("p", { className: "text-[10px] text-muted-foreground/50 mt-1", children: formatNotifDate(n.createdAt) })
|
|
781
|
-
]
|
|
782
|
-
},
|
|
783
|
-
n.id
|
|
784
|
-
)) })
|
|
785
|
-
] })
|
|
786
|
-
] })
|
|
787
|
-
] }),
|
|
788
|
-
/* @__PURE__ */ jsx7(
|
|
789
|
-
"button",
|
|
790
|
-
{
|
|
791
|
-
type: "button",
|
|
792
|
-
onClick: () => setMobileMenuOpen(!mobileMenuOpen),
|
|
793
|
-
className: "rounded-md p-2 hover:bg-muted/50 lg:hidden",
|
|
794
|
-
"aria-label": mobileMenuOpen ? "Close menu" : "Open menu",
|
|
795
|
-
"aria-expanded": mobileMenuOpen,
|
|
796
|
-
children: mobileMenuOpen ? /* @__PURE__ */ jsx7(XIcon, { className: "h-6 w-6" }) : /* @__PURE__ */ jsx7(MenuIcon, { className: "h-6 w-6" })
|
|
797
|
-
}
|
|
798
|
-
)
|
|
799
|
-
]
|
|
800
|
-
}
|
|
801
|
-
),
|
|
802
|
-
mobileMenuOpen && /* @__PURE__ */ jsx7("div", { className: "fixed inset-0 z-30 bg-black/50 lg:hidden", onClick: () => setMobileMenuOpen(false), "aria-hidden": "true" }),
|
|
803
|
-
/* @__PURE__ */ jsx7(
|
|
804
|
-
"aside",
|
|
805
|
-
{
|
|
806
|
-
className: cn(
|
|
807
|
-
"fixed top-14 bottom-0 left-0 z-30 flex bg-background transition-transform duration-200 lg:hidden",
|
|
808
|
-
mobileMenuOpen ? "translate-x-0" : "-translate-x-full"
|
|
809
|
-
),
|
|
810
|
-
style: {
|
|
811
|
-
width: panelOpen && hasPanels ? SIDEBAR_MOBILE_WIDTH + SIDEBAR_PANEL_WIDTH : SIDEBAR_MOBILE_WIDTH
|
|
812
|
-
},
|
|
813
|
-
children: mobileSidebarContent
|
|
814
|
-
}
|
|
815
|
-
),
|
|
816
|
-
/* @__PURE__ */ jsx7(Sidebar, { className: cn("hidden lg:flex", sidebarClassName), children: sidebarContent }),
|
|
817
|
-
/* @__PURE__ */ jsx7(SidebarContent, { className: cn("pt-16 px-6 pb-8 lg:px-8 bg-background", contentClassName), children }),
|
|
818
|
-
footer
|
|
819
|
-
] });
|
|
820
|
-
}
|
|
821
|
-
function DashboardLayout({ defaultPanelOpen, defaultMode, ...props }) {
|
|
822
|
-
return /* @__PURE__ */ jsx7(SidebarProvider, { defaultPanelOpen, defaultMode, hasPanels: (props.panels?.length ?? 0) > 0, children: /* @__PURE__ */ jsx7(DashboardLayoutInner, { defaultPanelOpen, defaultMode, ...props }) });
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
// src/dashboard/resource-meter.tsx
|
|
826
|
-
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
827
|
-
function getBarColor(percent) {
|
|
828
|
-
if (percent >= 90) return "bg-[var(--code-error)]";
|
|
829
|
-
if (percent >= 70) return "bg-[var(--surface-warning-text)]";
|
|
830
|
-
return "bg-primary";
|
|
831
|
-
}
|
|
832
|
-
function ResourceMeter({ label, value, max = 100, unit, icon, className }) {
|
|
833
|
-
const percent = max > 0 ? Math.min(value / max * 100, 100) : 0;
|
|
834
|
-
const barColor = getBarColor(percent);
|
|
835
|
-
return /* @__PURE__ */ jsxs7("div", { className: cn("flex items-center gap-3", className), children: [
|
|
836
|
-
/* @__PURE__ */ jsxs7("span", { className: "flex shrink-0 items-center gap-1 text-[10px] font-mono text-muted-foreground uppercase tracking-wide", children: [
|
|
837
|
-
icon,
|
|
838
|
-
label
|
|
839
|
-
] }),
|
|
840
|
-
/* @__PURE__ */ jsx8("div", { className: "h-1.5 min-w-0 flex-1 bg-card rounded-full overflow-hidden", children: /* @__PURE__ */ jsx8(
|
|
841
|
-
"div",
|
|
842
|
-
{
|
|
843
|
-
className: cn("h-full rounded-full transition-all duration-500", barColor),
|
|
844
|
-
style: { width: `${percent}%` }
|
|
845
|
-
}
|
|
846
|
-
) }),
|
|
847
|
-
/* @__PURE__ */ jsx8("span", { className: "shrink-0 text-[10px] font-mono tabular-nums text-muted-foreground", children: unit ? `${value}${unit}/${max}${unit}` : `${Math.round(percent)}%` })
|
|
848
|
-
] });
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
// src/dashboard/sandbox-card.tsx
|
|
852
|
-
import {
|
|
853
|
-
MoreVertical,
|
|
854
|
-
PowerOff,
|
|
855
|
-
Power,
|
|
856
|
-
Copy,
|
|
857
|
-
Clock,
|
|
858
|
-
Activity,
|
|
859
|
-
BarChart2,
|
|
860
|
-
Trash2,
|
|
861
|
-
Terminal,
|
|
862
|
-
Code2,
|
|
863
|
-
Network,
|
|
864
|
-
Play,
|
|
865
|
-
Plus as Plus2,
|
|
866
|
-
Users
|
|
867
|
-
} from "lucide-react";
|
|
868
|
-
import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
869
|
-
function canAdminSandbox(sandbox) {
|
|
870
|
-
if (!sandbox.team) return true;
|
|
871
|
-
return sandbox.team.role === "owner" || sandbox.team.role === "admin";
|
|
872
|
-
}
|
|
873
|
-
function SandboxCard({
|
|
874
|
-
sandbox,
|
|
875
|
-
onOpenIDE,
|
|
876
|
-
onOpenTerminal,
|
|
877
|
-
onWake,
|
|
878
|
-
onRestore,
|
|
879
|
-
onDelete,
|
|
880
|
-
onStop,
|
|
881
|
-
onResume,
|
|
882
|
-
onFork,
|
|
883
|
-
onKeepAlive,
|
|
884
|
-
onUsage,
|
|
885
|
-
onHealth,
|
|
886
|
-
className
|
|
887
|
-
}) {
|
|
888
|
-
const isRunning = sandbox.status === "running";
|
|
889
|
-
const isTransitioning = sandbox.status === "provisioning" || sandbox.status === "creating";
|
|
890
|
-
const isStopped = !isRunning && !isTransitioning;
|
|
891
|
-
return /* @__PURE__ */ jsxs8("div", { className: cn(
|
|
892
|
-
"group relative flex flex-col justify-between overflow-hidden rounded-lg border bg-card p-5 transition-colors",
|
|
893
|
-
isRunning ? "border-[var(--status-running)]/30" : "border-border",
|
|
894
|
-
"hover:border-foreground/15",
|
|
895
|
-
className
|
|
896
|
-
), children: [
|
|
897
|
-
/* @__PURE__ */ jsxs8("div", { className: "flex items-start justify-between", children: [
|
|
898
|
-
/* @__PURE__ */ jsxs8("div", { children: [
|
|
899
|
-
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2", children: [
|
|
900
|
-
/* @__PURE__ */ jsxs8("h3", { className: "flex items-center gap-2 text-sm font-bold text-foreground", children: [
|
|
901
|
-
sandbox.name,
|
|
902
|
-
isRunning && /* @__PURE__ */ jsxs8("span", { className: "relative flex h-2 w-2", children: [
|
|
903
|
-
/* @__PURE__ */ jsx9("span", { className: "absolute inline-flex h-full w-full animate-pulse rounded-full bg-[var(--status-running)] opacity-75" }),
|
|
904
|
-
/* @__PURE__ */ jsx9("span", { className: "relative inline-flex h-1.5 w-1.5 rounded-full bg-[var(--status-running)]" })
|
|
905
|
-
] })
|
|
906
|
-
] }),
|
|
907
|
-
sandbox.team && /* @__PURE__ */ jsxs8(
|
|
908
|
-
"span",
|
|
909
|
-
{
|
|
910
|
-
className: "inline-flex items-center gap-1 rounded-full bg-[var(--accent-surface-soft)] px-2 py-0.5 text-[10px] font-semibold text-[var(--accent-text)]",
|
|
911
|
-
title: `Shared with ${sandbox.team.name ?? "Team"} \xB7 ${sandbox.team.role}`,
|
|
912
|
-
children: [
|
|
913
|
-
/* @__PURE__ */ jsx9(Users, { className: "h-3 w-3", "aria-hidden": "true" }),
|
|
914
|
-
sandbox.team.name ?? "Team"
|
|
915
|
-
]
|
|
916
|
-
}
|
|
917
|
-
)
|
|
918
|
-
] }),
|
|
919
|
-
/* @__PURE__ */ jsxs8("p", { className: "mt-0.5 font-mono text-[10px] tracking-wider text-muted-foreground uppercase", children: [
|
|
920
|
-
sandbox.nodeId || "Unknown Node",
|
|
921
|
-
sandbox.team && /* @__PURE__ */ jsxs8("span", { className: "ml-2 normal-case tracking-normal", children: [
|
|
922
|
-
"\xB7 your role: ",
|
|
923
|
-
sandbox.team.role
|
|
924
|
-
] })
|
|
925
|
-
] })
|
|
926
|
-
] }),
|
|
927
|
-
/* @__PURE__ */ jsxs8(DropdownMenu, { children: [
|
|
928
|
-
/* @__PURE__ */ jsx9(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx9(
|
|
929
|
-
"button",
|
|
930
|
-
{
|
|
931
|
-
type: "button",
|
|
932
|
-
className: "rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground outline-none",
|
|
933
|
-
"aria-label": "Sandbox options",
|
|
934
|
-
children: /* @__PURE__ */ jsx9(MoreVertical, { className: "h-4 w-4" })
|
|
935
|
-
}
|
|
936
|
-
) }),
|
|
937
|
-
/* @__PURE__ */ jsxs8(DropdownMenuContent, { align: "end", className: "min-w-[180px]", children: [
|
|
938
|
-
isRunning && /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
939
|
-
onStop && /* @__PURE__ */ jsxs8(DropdownMenuItem, { onClick: () => onStop(sandbox.id), children: [
|
|
940
|
-
/* @__PURE__ */ jsx9(PowerOff, { className: "mr-2 h-4 w-4" }),
|
|
941
|
-
" Stop Sandbox"
|
|
942
|
-
] }),
|
|
943
|
-
onKeepAlive && /* @__PURE__ */ jsxs8(DropdownMenuItem, { onClick: () => onKeepAlive(sandbox.id), children: [
|
|
944
|
-
/* @__PURE__ */ jsx9(Clock, { className: "mr-2 h-4 w-4" }),
|
|
945
|
-
" Keep Alive"
|
|
946
|
-
] }),
|
|
947
|
-
(onStop || onKeepAlive) && /* @__PURE__ */ jsx9(DropdownMenuSeparator, {}),
|
|
948
|
-
onUsage && /* @__PURE__ */ jsxs8(DropdownMenuItem, { onClick: () => onUsage(sandbox.id), children: [
|
|
949
|
-
/* @__PURE__ */ jsx9(BarChart2, { className: "mr-2 h-4 w-4" }),
|
|
950
|
-
" View Usage"
|
|
951
|
-
] }),
|
|
952
|
-
onHealth && /* @__PURE__ */ jsxs8(DropdownMenuItem, { onClick: () => onHealth(sandbox.id), children: [
|
|
953
|
-
/* @__PURE__ */ jsx9(Activity, { className: "mr-2 h-4 w-4" }),
|
|
954
|
-
" Health Check"
|
|
955
|
-
] }),
|
|
956
|
-
(onUsage || onHealth) && /* @__PURE__ */ jsx9(DropdownMenuSeparator, {}),
|
|
957
|
-
onFork && /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
958
|
-
/* @__PURE__ */ jsxs8(DropdownMenuItem, { onClick: () => onFork(sandbox.id), children: [
|
|
959
|
-
/* @__PURE__ */ jsx9(Copy, { className: "mr-2 h-4 w-4" }),
|
|
960
|
-
" Fork Sandbox"
|
|
961
|
-
] }),
|
|
962
|
-
/* @__PURE__ */ jsx9(DropdownMenuSeparator, {})
|
|
963
|
-
] })
|
|
964
|
-
] }),
|
|
965
|
-
isStopped && /* @__PURE__ */ jsxs8(Fragment5, { children: [
|
|
966
|
-
onResume && /* @__PURE__ */ jsxs8(DropdownMenuItem, { onClick: () => onResume(sandbox.id), children: [
|
|
967
|
-
/* @__PURE__ */ jsx9(Power, { className: "mr-2 h-4 w-4" }),
|
|
968
|
-
" Resume Sandbox"
|
|
969
|
-
] }),
|
|
970
|
-
onFork && /* @__PURE__ */ jsxs8(DropdownMenuItem, { onClick: () => onFork(sandbox.id), children: [
|
|
971
|
-
/* @__PURE__ */ jsx9(Copy, { className: "mr-2 h-4 w-4" }),
|
|
972
|
-
" Fork Sandbox"
|
|
973
|
-
] }),
|
|
974
|
-
(onResume || onFork) && /* @__PURE__ */ jsx9(DropdownMenuSeparator, {})
|
|
975
|
-
] }),
|
|
976
|
-
onDelete && canAdminSandbox(sandbox) && /* @__PURE__ */ jsxs8(DropdownMenuItem, { className: "text-destructive focus:bg-destructive/10 focus:text-destructive", onClick: () => onDelete(sandbox.id), children: [
|
|
977
|
-
/* @__PURE__ */ jsx9(Trash2, { className: "mr-2 h-4 w-4" }),
|
|
978
|
-
" Delete Sandbox"
|
|
979
|
-
] })
|
|
980
|
-
] })
|
|
981
|
-
] })
|
|
982
|
-
] }),
|
|
983
|
-
/* @__PURE__ */ jsxs8("div", { className: "my-4", children: [
|
|
984
|
-
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-3 rounded-md border border-border bg-muted/30 p-3", children: [
|
|
985
|
-
/* @__PURE__ */ jsx9("div", { className: cn("flex h-10 w-10 items-center justify-center rounded-md", isRunning ? "bg-[var(--surface-success-bg)]" : "bg-muted"), children: sandbox.imageIcon ? sandbox.imageIcon : sandbox.image?.includes("node") ? /* @__PURE__ */ jsx9(Code2, { className: cn("h-5 w-5", isRunning ? "text-[var(--surface-success-text)]" : "text-muted-foreground") }) : /* @__PURE__ */ jsx9(Terminal, { className: cn("h-5 w-5", isRunning ? "text-[var(--surface-success-text)]" : "text-muted-foreground") }) }),
|
|
986
|
-
/* @__PURE__ */ jsxs8("div", { className: "flex flex-col", children: [
|
|
987
|
-
/* @__PURE__ */ jsx9("span", { className: "text-[10px] text-muted-foreground uppercase tracking-widest font-bold", children: "Environment" }),
|
|
988
|
-
/* @__PURE__ */ jsx9("span", { className: "text-xs font-medium text-foreground font-mono mt-0.5", children: sandbox.image || "Universal" })
|
|
989
|
-
] })
|
|
990
|
-
] }),
|
|
991
|
-
isTransitioning && /* @__PURE__ */ jsxs8("div", { className: "mt-3", children: [
|
|
992
|
-
/* @__PURE__ */ jsxs8("div", { className: "flex justify-between text-xs text-muted-foreground font-medium mb-1", children: [
|
|
993
|
-
/* @__PURE__ */ jsx9("span", { children: sandbox.provisioningMessage || "Starting..." }),
|
|
994
|
-
/* @__PURE__ */ jsxs8("span", { children: [
|
|
995
|
-
sandbox.provisioningPercent || 0,
|
|
996
|
-
"%"
|
|
997
|
-
] })
|
|
998
|
-
] }),
|
|
999
|
-
/* @__PURE__ */ jsx9("div", { className: "h-1 w-full overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx9(
|
|
1000
|
-
"div",
|
|
1001
|
-
{
|
|
1002
|
-
className: "h-full bg-primary transition-all duration-500 rounded-full",
|
|
1003
|
-
style: { width: `${sandbox.provisioningPercent || 5}%` }
|
|
1004
|
-
}
|
|
1005
|
-
) })
|
|
1006
|
-
] })
|
|
1007
|
-
] }),
|
|
1008
|
-
/* @__PURE__ */ jsx9("div", { className: "border-t border-border pt-3", children: isRunning ? /* @__PURE__ */ jsxs8(
|
|
1009
|
-
"button",
|
|
1010
|
-
{
|
|
1011
|
-
type: "button",
|
|
1012
|
-
onClick: () => onOpenIDE?.(sandbox.id),
|
|
1013
|
-
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]",
|
|
1014
|
-
children: [
|
|
1015
|
-
/* @__PURE__ */ jsx9(Network, { className: "h-4 w-4" }),
|
|
1016
|
-
"Connect Session"
|
|
1017
|
-
]
|
|
1018
|
-
}
|
|
1019
|
-
) : /* @__PURE__ */ jsxs8(
|
|
1020
|
-
"button",
|
|
1021
|
-
{
|
|
1022
|
-
type: "button",
|
|
1023
|
-
onClick: () => onWake?.(sandbox.id),
|
|
1024
|
-
disabled: isTransitioning,
|
|
1025
|
-
className: cn(
|
|
1026
|
-
"flex w-full items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-semibold transition-colors border",
|
|
1027
|
-
isTransitioning ? "bg-muted text-muted-foreground cursor-not-allowed border-border" : "bg-card text-foreground hover:bg-muted border-border active:scale-[0.97]"
|
|
1028
|
-
),
|
|
1029
|
-
children: [
|
|
1030
|
-
/* @__PURE__ */ jsx9(Play, { className: "h-4 w-4" }),
|
|
1031
|
-
isTransitioning ? "Starting..." : "Wake Sandbox"
|
|
1032
|
-
]
|
|
1033
|
-
}
|
|
1034
|
-
) })
|
|
1035
|
-
] });
|
|
1036
|
-
}
|
|
1037
|
-
function NewSandboxCard({ onClick, className }) {
|
|
1038
|
-
return /* @__PURE__ */ jsxs8(
|
|
1039
|
-
"button",
|
|
1040
|
-
{
|
|
1041
|
-
type: "button",
|
|
1042
|
-
onClick,
|
|
1043
|
-
className: cn(
|
|
1044
|
-
"border-2 border-dashed border-border rounded-lg p-5 flex flex-col items-center justify-center text-center cursor-pointer hover:border-foreground/20 hover:bg-muted/30 transition-colors w-full min-h-[160px]",
|
|
1045
|
-
className
|
|
1046
|
-
),
|
|
1047
|
-
children: [
|
|
1048
|
-
/* @__PURE__ */ jsx9("div", { className: "flex h-12 w-12 items-center justify-center rounded-lg bg-muted text-muted-foreground", children: /* @__PURE__ */ jsx9(Plus2, { className: "h-6 w-6" }) }),
|
|
1049
|
-
/* @__PURE__ */ jsx9("span", { className: "mt-4 text-sm font-semibold text-foreground", children: "New Sandbox" }),
|
|
1050
|
-
/* @__PURE__ */ jsx9("span", { className: "mt-1 text-xs text-muted-foreground", children: "Deploy a new isolated environment" })
|
|
1051
|
-
]
|
|
1052
|
-
}
|
|
1053
|
-
);
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
// src/dashboard/sandbox-table.tsx
|
|
1057
|
-
import { Terminal as Terminal2, Code2 as Code22, Key, Trash2 as Trash22, RefreshCw, ChevronLeft, ChevronRight, Users as Users2, User } from "lucide-react";
|
|
1058
|
-
import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1059
|
-
var statusColors = {
|
|
1060
|
-
running: { dot: "bg-[var(--code-success)] animate-pulse", text: "text-[var(--code-success)]", bar: "bg-[var(--code-success)]" },
|
|
1061
|
-
hibernating: { dot: "bg-muted-foreground", text: "text-muted-foreground", bar: "bg-muted-foreground" },
|
|
1062
|
-
provisioning: { dot: "bg-primary animate-pulse", text: "text-primary", bar: "bg-primary" },
|
|
1063
|
-
creating: { dot: "bg-primary animate-pulse", text: "text-primary", bar: "bg-primary" },
|
|
1064
|
-
stopped: { dot: "bg-muted-foreground", text: "text-foreground", bar: "bg-muted-foreground" },
|
|
1065
|
-
failed: { dot: "bg-[var(--code-error)]", text: "text-[var(--code-error)]", bar: "bg-[var(--code-error)]" },
|
|
1066
|
-
archived: { dot: "bg-border", text: "text-muted-foreground", bar: "bg-border" }
|
|
1067
|
-
};
|
|
1068
|
-
function MiniMeter({ label, percent, className }) {
|
|
1069
|
-
return /* @__PURE__ */ jsxs9("div", { className: cn("space-y-1", className), children: [
|
|
1070
|
-
/* @__PURE__ */ jsxs9("div", { className: "flex justify-between text-[10px] font-mono text-muted-foreground", children: [
|
|
1071
|
-
/* @__PURE__ */ jsx10("span", { className: "font-bold", children: label }),
|
|
1072
|
-
/* @__PURE__ */ jsxs9("span", { className: "text-primary", children: [
|
|
1073
|
-
percent,
|
|
1074
|
-
"%"
|
|
1075
|
-
] })
|
|
1076
|
-
] }),
|
|
1077
|
-
/* @__PURE__ */ jsx10("div", { className: "h-1.5 w-full bg-background rounded-full overflow-hidden", children: /* @__PURE__ */ jsx10("div", { className: "h-full bg-primary rounded-full", style: { width: `${percent}%` } }) })
|
|
1078
|
-
] });
|
|
1079
|
-
}
|
|
1080
|
-
function SandboxTable({
|
|
1081
|
-
sandboxes,
|
|
1082
|
-
page = 1,
|
|
1083
|
-
pageSize = 10,
|
|
1084
|
-
total,
|
|
1085
|
-
onPageChange,
|
|
1086
|
-
onOpenIDE,
|
|
1087
|
-
onOpenTerminal,
|
|
1088
|
-
onSSH,
|
|
1089
|
-
onWake,
|
|
1090
|
-
onMore,
|
|
1091
|
-
onDelete,
|
|
1092
|
-
className
|
|
1093
|
-
}) {
|
|
1094
|
-
const totalCount = total ?? sandboxes.length;
|
|
1095
|
-
const totalPages = Math.ceil(totalCount / pageSize);
|
|
1096
|
-
const hasTeamSandboxes = sandboxes.some((sb) => sb.team !== void 0);
|
|
1097
|
-
return /* @__PURE__ */ jsxs9("div", { className: cn("w-full", className), children: [
|
|
1098
|
-
/* @__PURE__ */ jsx10("div", { className: "w-full bg-card rounded-2xl overflow-hidden border border-border", children: /* @__PURE__ */ jsx10("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs9("table", { className: "w-full text-left border-collapse", children: [
|
|
1099
|
-
/* @__PURE__ */ jsx10("thead", { children: /* @__PURE__ */ jsxs9("tr", { className: "bg-background border-b border-border", children: [
|
|
1100
|
-
/* @__PURE__ */ jsx10("th", { className: "px-6 py-4 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Status" }),
|
|
1101
|
-
/* @__PURE__ */ jsx10("th", { className: "px-6 py-4 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Sandbox Name" }),
|
|
1102
|
-
hasTeamSandboxes && /* @__PURE__ */ jsx10("th", { className: "px-6 py-4 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Scope" }),
|
|
1103
|
-
/* @__PURE__ */ jsx10("th", { className: "px-6 py-4 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Environment" }),
|
|
1104
|
-
/* @__PURE__ */ jsx10("th", { className: "px-6 py-4 text-xs font-semibold text-muted-foreground uppercase tracking-wider", children: "Resources" }),
|
|
1105
|
-
/* @__PURE__ */ jsx10("th", { className: "px-6 py-4 text-xs font-semibold text-muted-foreground uppercase tracking-wider text-right", children: "Actions" })
|
|
1106
|
-
] }) }),
|
|
1107
|
-
/* @__PURE__ */ jsx10("tbody", { className: "divide-y divide-border", children: sandboxes.map((sb) => {
|
|
1108
|
-
const sc = statusColors[sb.status] ?? statusColors.stopped;
|
|
1109
|
-
const isActive = sb.status === "running";
|
|
1110
|
-
const isHibernating = sb.status === "hibernating";
|
|
1111
|
-
const isProvisioning = sb.status === "provisioning";
|
|
1112
|
-
return /* @__PURE__ */ jsxs9("tr", { className: "hover:bg-muted/50 transition-colors group relative", children: [
|
|
1113
|
-
/* @__PURE__ */ jsx10("td", { className: "px-6 py-5 whitespace-nowrap", children: /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
1114
|
-
/* @__PURE__ */ jsx10("span", { className: cn("flex h-2.5 w-2.5 rounded-full", sc.dot) }),
|
|
1115
|
-
/* @__PURE__ */ jsx10("span", { className: cn("text-xs font-bold uppercase tracking-wide", sc.text), children: sb.status.charAt(0).toUpperCase() + sb.status.slice(1) })
|
|
1116
|
-
] }) }),
|
|
1117
|
-
/* @__PURE__ */ jsx10("td", { className: "px-6 py-5", children: /* @__PURE__ */ jsxs9("div", { className: "flex flex-col", children: [
|
|
1118
|
-
/* @__PURE__ */ jsx10("span", { className: "text-sm font-bold text-foreground group-hover:text-primary transition-colors", children: sb.name }),
|
|
1119
|
-
sb.nodeId && /* @__PURE__ */ jsx10("span", { className: "text-[10px] font-mono text-muted-foreground", children: sb.nodeId })
|
|
1120
|
-
] }) }),
|
|
1121
|
-
hasTeamSandboxes && /* @__PURE__ */ jsx10("td", { className: "px-6 py-5", children: sb.team ? /* @__PURE__ */ jsxs9(
|
|
1122
|
-
"div",
|
|
1123
|
-
{
|
|
1124
|
-
className: "inline-flex 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)]",
|
|
1125
|
-
title: `Shared with ${sb.team.name ?? "Team"} \xB7 ${sb.team.role}`,
|
|
1126
|
-
children: [
|
|
1127
|
-
/* @__PURE__ */ jsx10(Users2, { className: "h-3 w-3", "aria-hidden": "true" }),
|
|
1128
|
-
/* @__PURE__ */ jsx10("span", { children: sb.team.name ?? "Team" }),
|
|
1129
|
-
/* @__PURE__ */ jsxs9("span", { className: "font-normal text-muted-foreground", children: [
|
|
1130
|
-
"\xB7 ",
|
|
1131
|
-
sb.team.role
|
|
1132
|
-
] })
|
|
1133
|
-
]
|
|
1134
|
-
}
|
|
1135
|
-
) : /* @__PURE__ */ jsxs9(
|
|
1136
|
-
"div",
|
|
1137
|
-
{
|
|
1138
|
-
className: "inline-flex items-center gap-1.5 rounded-full bg-muted px-2.5 py-1 text-[11px] font-medium text-muted-foreground",
|
|
1139
|
-
title: "Personal sandbox",
|
|
1140
|
-
children: [
|
|
1141
|
-
/* @__PURE__ */ jsx10(User, { className: "h-3 w-3", "aria-hidden": "true" }),
|
|
1142
|
-
"Personal"
|
|
1143
|
-
]
|
|
1144
|
-
}
|
|
1145
|
-
) }),
|
|
1146
|
-
/* @__PURE__ */ jsx10("td", { className: "px-6 py-5", children: /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-3", children: [
|
|
1147
|
-
sb.imageIcon && /* @__PURE__ */ jsx10("div", { className: "w-8 h-8 rounded-lg bg-muted/50 flex items-center justify-center", children: sb.imageIcon }),
|
|
1148
|
-
sb.image && /* @__PURE__ */ jsx10("span", { className: "text-xs font-bold text-foreground", children: sb.image })
|
|
1149
|
-
] }) }),
|
|
1150
|
-
/* @__PURE__ */ jsx10("td", { className: "px-6 py-5", children: isActive ? /* @__PURE__ */ jsxs9("div", { className: "space-y-3 w-48", children: [
|
|
1151
|
-
/* @__PURE__ */ jsx10(MiniMeter, { label: "CPU", percent: sb.cpuPercent ?? 0 }),
|
|
1152
|
-
/* @__PURE__ */ jsx10(MiniMeter, { label: "RAM", percent: sb.ramTotal ? Math.round((sb.ramUsed ?? 0) / sb.ramTotal * 100) : 0 })
|
|
1153
|
-
] }) : isProvisioning ? /* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2 text-primary italic text-[10px] font-bold", children: [
|
|
1154
|
-
/* @__PURE__ */ jsx10(RefreshCw, { className: "h-3.5 w-3.5 animate-spin" }),
|
|
1155
|
-
sb.provisioningMessage ?? "Allocating nodes..."
|
|
1156
|
-
] }) : isHibernating ? /* @__PURE__ */ jsxs9("div", { className: "space-y-3 w-48 opacity-30", children: [
|
|
1157
|
-
/* @__PURE__ */ jsx10(MiniMeter, { label: "CPU", percent: 0 }),
|
|
1158
|
-
/* @__PURE__ */ jsx10(MiniMeter, { label: "RAM", percent: 0 })
|
|
1159
|
-
] }) : null }),
|
|
1160
|
-
/* @__PURE__ */ jsx10("td", { className: "px-6 py-5 text-right", children: /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-end gap-1", children: [
|
|
1161
|
-
isActive && /* @__PURE__ */ jsxs9(Fragment6, { children: [
|
|
1162
|
-
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => onOpenIDE?.(sb.id), className: "p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-all active:scale-90", title: "Open IDE", children: /* @__PURE__ */ jsx10(Code22, { className: "h-4 w-4" }) }),
|
|
1163
|
-
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => onOpenTerminal?.(sb.id), className: "p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-all active:scale-90", title: "Terminal", children: /* @__PURE__ */ jsx10(Terminal2, { className: "h-4 w-4" }) }),
|
|
1164
|
-
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => onSSH?.(sb.id), className: "p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-all active:scale-90", title: "SSH", children: /* @__PURE__ */ jsx10(Key, { className: "h-4 w-4" }) })
|
|
1165
|
-
] }),
|
|
1166
|
-
isHibernating && /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => onWake?.(sb.id), className: "px-3 py-1.5 rounded-lg border border-border text-primary text-[10px] font-bold uppercase tracking-wider hover:bg-[var(--accent-surface-soft)] active:scale-95 transition-all", children: "Wake Up" }),
|
|
1167
|
-
onMore && /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => onMore(sb.id), className: "p-2 rounded-lg hover:bg-muted text-muted-foreground hover:text-foreground transition-all active:scale-90", children: /* @__PURE__ */ jsx10(Code22, { className: "h-4 w-4" }) }),
|
|
1168
|
-
onDelete && canAdminSandbox(sb) && /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => onDelete(sb.id), className: "p-2 rounded-lg hover:bg-[var(--surface-danger-bg)] text-muted-foreground hover:text-[var(--surface-danger-text)] transition-all active:scale-90", title: "Delete", children: /* @__PURE__ */ jsx10(Trash22, { className: "h-4 w-4" }) })
|
|
1169
|
-
] }) })
|
|
1170
|
-
] }, sb.id);
|
|
1171
|
-
}) })
|
|
1172
|
-
] }) }) }),
|
|
1173
|
-
totalPages > 1 && /* @__PURE__ */ jsxs9("div", { className: "mt-6 flex flex-col md:flex-row justify-between items-center text-muted-foreground text-xs font-medium gap-4", children: [
|
|
1174
|
-
/* @__PURE__ */ jsxs9("p", { children: [
|
|
1175
|
-
"Showing ",
|
|
1176
|
-
sandboxes.length,
|
|
1177
|
-
" of ",
|
|
1178
|
-
totalCount,
|
|
1179
|
-
" active sandboxes"
|
|
1180
|
-
] }),
|
|
1181
|
-
/* @__PURE__ */ jsxs9("div", { className: "flex items-center gap-2", children: [
|
|
1182
|
-
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => onPageChange?.(page - 1), disabled: page <= 1, className: "p-2 rounded-lg border border-border hover:bg-muted/50 transition-colors disabled:opacity-30", children: /* @__PURE__ */ jsx10(ChevronLeft, { className: "h-4 w-4" }) }),
|
|
1183
|
-
Array.from({ length: Math.min(totalPages, 5) }, (_, i) => i + 1).map((p) => /* @__PURE__ */ jsx10(
|
|
1184
|
-
"button",
|
|
1185
|
-
{
|
|
1186
|
-
type: "button",
|
|
1187
|
-
onClick: () => onPageChange?.(p),
|
|
1188
|
-
className: cn(
|
|
1189
|
-
"px-3 py-1 rounded-lg transition-colors",
|
|
1190
|
-
p === page ? "bg-[var(--accent-surface-soft)] text-primary border border-border" : "hover:bg-muted/50"
|
|
1191
|
-
),
|
|
1192
|
-
children: p
|
|
1193
|
-
},
|
|
1194
|
-
p
|
|
1195
|
-
)),
|
|
1196
|
-
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => onPageChange?.(page + 1), disabled: page >= totalPages, className: "p-2 rounded-lg border border-border hover:bg-muted/50 transition-colors disabled:opacity-30", children: /* @__PURE__ */ jsx10(ChevronRight, { className: "h-4 w-4" }) })
|
|
1197
|
-
] })
|
|
1198
|
-
] })
|
|
1199
|
-
] });
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
// src/dashboard/backend-selector.tsx
|
|
1203
|
-
import { ChevronDown } from "lucide-react";
|
|
1204
|
-
import * as Select from "@radix-ui/react-select";
|
|
1205
|
-
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1206
|
-
function BackendSelector({
|
|
1207
|
-
backends,
|
|
1208
|
-
selected,
|
|
1209
|
-
onChange,
|
|
1210
|
-
label = "Model",
|
|
1211
|
-
placeholder = "Select a model",
|
|
1212
|
-
className
|
|
1213
|
-
}) {
|
|
1214
|
-
const current = backends.find((b) => b.type === selected);
|
|
1215
|
-
return /* @__PURE__ */ jsxs10("div", { className: cn("space-y-1.5", className), children: [
|
|
1216
|
-
label && /* @__PURE__ */ jsx11("label", { className: "block text-xs font-medium text-muted-foreground uppercase tracking-[0.06em]", children: label }),
|
|
1217
|
-
/* @__PURE__ */ jsxs10(Select.Root, { value: selected, onValueChange: onChange, children: [
|
|
1218
|
-
/* @__PURE__ */ jsxs10(
|
|
1219
|
-
Select.Trigger,
|
|
1220
|
-
{
|
|
1221
|
-
className: cn(
|
|
1222
|
-
"flex w-full items-center justify-between gap-2 rounded-[var(--radius-md)]",
|
|
1223
|
-
"border border-border bg-card",
|
|
1224
|
-
"px-3 py-2.5 text-sm text-left",
|
|
1225
|
-
"transition-colors duration-[var(--transition-fast)]",
|
|
1226
|
-
"hover:border-primary/20 hover:bg-accent/30",
|
|
1227
|
-
"focus:outline-none focus:border-primary/30",
|
|
1228
|
-
"data-[state=open]:border-primary/30 data-[state=open]:bg-accent/30"
|
|
1229
|
-
),
|
|
1230
|
-
children: [
|
|
1231
|
-
/* @__PURE__ */ jsx11("div", { className: "min-w-0 flex-1", children: current ? /* @__PURE__ */ jsxs10("div", { children: [
|
|
1232
|
-
/* @__PURE__ */ jsx11("span", { className: "font-medium text-foreground", children: current.label }),
|
|
1233
|
-
current.description && /* @__PURE__ */ jsx11("span", { className: "ml-2 text-xs text-muted-foreground", children: current.description })
|
|
1234
|
-
] }) : /* @__PURE__ */ jsx11("span", { className: "text-muted-foreground", children: placeholder }) }),
|
|
1235
|
-
/* @__PURE__ */ jsx11(Select.Icon, { asChild: true, children: /* @__PURE__ */ jsx11(ChevronDown, { className: "h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-[var(--transition-fast)] data-[state=open]:rotate-180" }) })
|
|
1236
|
-
]
|
|
1237
|
-
}
|
|
1238
|
-
),
|
|
1239
|
-
/* @__PURE__ */ jsx11(Select.Portal, { children: /* @__PURE__ */ jsx11(
|
|
1240
|
-
Select.Content,
|
|
1241
|
-
{
|
|
1242
|
-
position: "popper",
|
|
1243
|
-
sideOffset: 4,
|
|
1244
|
-
className: cn(
|
|
1245
|
-
"z-50 w-[var(--radix-select-trigger-width)] overflow-hidden",
|
|
1246
|
-
"rounded-[var(--radius-md)] border border-border",
|
|
1247
|
-
"bg-card shadow-[var(--shadow-dropdown)]",
|
|
1248
|
-
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
1249
|
-
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
1250
|
-
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
1251
|
-
"data-[side=bottom]:slide-in-from-top-1"
|
|
1252
|
-
),
|
|
1253
|
-
children: /* @__PURE__ */ jsx11(Select.Viewport, { className: "p-1", children: backends.map((backend) => /* @__PURE__ */ jsxs10(
|
|
1254
|
-
Select.Item,
|
|
1255
|
-
{
|
|
1256
|
-
value: backend.type,
|
|
1257
|
-
className: cn(
|
|
1258
|
-
"relative flex cursor-pointer select-none flex-col rounded-[var(--radius-sm)]",
|
|
1259
|
-
"px-3 py-2.5 text-sm outline-none",
|
|
1260
|
-
"transition-colors duration-[var(--transition-fast)]",
|
|
1261
|
-
"hover:bg-accent/50 focus:bg-accent/50",
|
|
1262
|
-
"data-[state=checked]:bg-[var(--accent-surface-soft)] data-[state=checked]:text-[var(--brand-primary)]"
|
|
1263
|
-
),
|
|
1264
|
-
children: [
|
|
1265
|
-
/* @__PURE__ */ jsx11(Select.ItemText, { children: /* @__PURE__ */ jsx11("span", { className: "font-medium", children: backend.label }) }),
|
|
1266
|
-
backend.description && /* @__PURE__ */ jsx11("span", { className: "mt-0.5 text-xs text-muted-foreground data-[state=checked]:text-[var(--accent-text)]", children: backend.description })
|
|
1267
|
-
]
|
|
1268
|
-
},
|
|
1269
|
-
backend.type
|
|
1270
|
-
)) })
|
|
1271
|
-
}
|
|
1272
|
-
) })
|
|
1273
|
-
] })
|
|
1274
|
-
] });
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
// src/dashboard/harness-picker.tsx
|
|
1278
|
-
import { jsx as jsx12 } from "react/jsx-runtime";
|
|
1279
|
-
var HARNESS_OPTIONS = [
|
|
1280
|
-
{
|
|
1281
|
-
type: "opencode",
|
|
1282
|
-
label: "OpenCode",
|
|
1283
|
-
description: "Default agent \u2014 broad model support, deterministic streaming"
|
|
1284
|
-
},
|
|
1285
|
-
{
|
|
1286
|
-
type: "claude-code",
|
|
1287
|
-
label: "Claude Code",
|
|
1288
|
-
description: "Native Claude skills and tools (requires ANTHROPIC_API_KEY)"
|
|
1289
|
-
},
|
|
1290
|
-
{
|
|
1291
|
-
type: "codex",
|
|
1292
|
-
label: "Codex",
|
|
1293
|
-
description: "OpenAI Codex CLI (requires OPENAI_API_KEY)"
|
|
1294
|
-
},
|
|
1295
|
-
{
|
|
1296
|
-
type: "amp",
|
|
1297
|
-
label: "AMP",
|
|
1298
|
-
description: "Sourcegraph AMP agent"
|
|
1299
|
-
},
|
|
1300
|
-
{
|
|
1301
|
-
type: "factory-droids",
|
|
1302
|
-
label: "Factory Droids",
|
|
1303
|
-
description: "Factory Droid agent"
|
|
1304
|
-
},
|
|
1305
|
-
{
|
|
1306
|
-
type: "cli-base",
|
|
1307
|
-
label: "CLI base (no agent)",
|
|
1308
|
-
description: "Shell tools only \u2014 for non-AI scheduled tasks"
|
|
1309
|
-
}
|
|
1310
|
-
];
|
|
1311
|
-
function HarnessPicker({
|
|
1312
|
-
value,
|
|
1313
|
-
onChange,
|
|
1314
|
-
available,
|
|
1315
|
-
optionsOverride,
|
|
1316
|
-
label = "Agent harness",
|
|
1317
|
-
...rest
|
|
1318
|
-
}) {
|
|
1319
|
-
const allowed = new Set(available ?? HARNESS_OPTIONS.map((h) => h.type));
|
|
1320
|
-
const backends = HARNESS_OPTIONS.filter((h) => allowed.has(h.type)).map((h) => {
|
|
1321
|
-
const override = optionsOverride?.[h.type];
|
|
1322
|
-
return {
|
|
1323
|
-
type: h.type,
|
|
1324
|
-
label: override?.label ?? h.label,
|
|
1325
|
-
description: override?.description ?? h.description
|
|
1326
|
-
};
|
|
1327
|
-
});
|
|
1328
|
-
return /* @__PURE__ */ jsx12(
|
|
1329
|
-
BackendSelector,
|
|
1330
|
-
{
|
|
1331
|
-
backends,
|
|
1332
|
-
selected: value,
|
|
1333
|
-
onChange: (next) => onChange(next),
|
|
1334
|
-
label,
|
|
1335
|
-
...rest
|
|
1336
|
-
}
|
|
1337
|
-
);
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
// src/dashboard/model-picker.tsx
|
|
1341
|
-
import * as React4 from "react";
|
|
1342
|
-
import { ChevronDown as ChevronDown2, Search, Sparkles, Zap, Brain, Star, Loader2 } from "lucide-react";
|
|
1343
|
-
import * as Popover from "@radix-ui/react-dropdown-menu";
|
|
1344
|
-
import { Fragment as Fragment7, jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1345
|
-
function canonicalModelId(model) {
|
|
1346
|
-
const id = model.id;
|
|
1347
|
-
if (id.includes("/")) return id;
|
|
1348
|
-
const provider = model._provider ?? model.provider;
|
|
1349
|
-
return provider ? `${provider}/${id}` : id;
|
|
1350
|
-
}
|
|
1351
|
-
function formatPricing(pricing) {
|
|
1352
|
-
const prompt = Number(pricing?.prompt ?? 0);
|
|
1353
|
-
const completion = Number(pricing?.completion ?? 0);
|
|
1354
|
-
if (!prompt && !completion) return null;
|
|
1355
|
-
const fmt = (n) => {
|
|
1356
|
-
const perM = n * 1e6;
|
|
1357
|
-
if (perM === 0) return "0";
|
|
1358
|
-
if (perM >= 1) return `$${perM.toFixed(2)}`;
|
|
1359
|
-
return `$${perM.toFixed(2)}`;
|
|
1360
|
-
};
|
|
1361
|
-
return `${fmt(prompt)} / ${fmt(completion)} per 1M`;
|
|
1362
|
-
}
|
|
1363
|
-
function formatContext(ctx) {
|
|
1364
|
-
if (!ctx) return null;
|
|
1365
|
-
if (ctx >= 1e6) return `${(ctx / 1e6).toFixed(1)}M ctx`;
|
|
1366
|
-
if (ctx >= 1e3) return `${Math.round(ctx / 1e3)}k ctx`;
|
|
1367
|
-
return `${ctx} ctx`;
|
|
1368
|
-
}
|
|
1369
|
-
var DEFAULT_PRESETS = [
|
|
1370
|
-
{
|
|
1371
|
-
id: "fast",
|
|
1372
|
-
label: "Fast",
|
|
1373
|
-
hint: "Cheapest, lowest latency",
|
|
1374
|
-
icon: Zap,
|
|
1375
|
-
match: (models) => {
|
|
1376
|
-
const ids = models.map(canonicalModelId);
|
|
1377
|
-
return ids.find((m) => /gpt-5\.\d+-mini$/.test(m)) ?? ids.find((m) => /gpt-5-mini$/.test(m)) ?? ids.find((m) => m.endsWith("/claude-haiku-4.5")) ?? ids.find((m) => /haiku/.test(m));
|
|
1378
|
-
}
|
|
1379
|
-
},
|
|
1380
|
-
{
|
|
1381
|
-
id: "balanced",
|
|
1382
|
-
label: "Balanced",
|
|
1383
|
-
hint: "Best value for most chat",
|
|
1384
|
-
icon: Sparkles,
|
|
1385
|
-
match: (models) => {
|
|
1386
|
-
const ids = models.map(canonicalModelId);
|
|
1387
|
-
return ids.find((m) => /^openai\/gpt-5\.\d+$/.test(m)) ?? ids.find((m) => /^openai\/gpt-5$/.test(m)) ?? ids.find((m) => m.endsWith("/claude-sonnet-4-6")) ?? ids.find((m) => /sonnet/.test(m));
|
|
1388
|
-
}
|
|
1389
|
-
},
|
|
1390
|
-
{
|
|
1391
|
-
id: "best",
|
|
1392
|
-
label: "Best",
|
|
1393
|
-
hint: "Hardest reasoning, highest quality",
|
|
1394
|
-
icon: Brain,
|
|
1395
|
-
match: (models) => {
|
|
1396
|
-
const ids = models.map(canonicalModelId);
|
|
1397
|
-
return ids.find((m) => /^openai\/gpt-5\.\d+-pro$/.test(m)) ?? ids.find((m) => /^openai\/o3$/.test(m)) ?? ids.find((m) => m.endsWith("/claude-opus-4-7")) ?? ids.find((m) => /opus/.test(m));
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
];
|
|
1401
|
-
function ModelPicker({
|
|
1402
|
-
value,
|
|
1403
|
-
onChange,
|
|
1404
|
-
models,
|
|
1405
|
-
loading = false,
|
|
1406
|
-
recents,
|
|
1407
|
-
presets = DEFAULT_PRESETS,
|
|
1408
|
-
excludeProviders,
|
|
1409
|
-
modalities,
|
|
1410
|
-
variant = "field",
|
|
1411
|
-
label = "Model",
|
|
1412
|
-
placeholder = "Choose a model",
|
|
1413
|
-
className,
|
|
1414
|
-
disabled
|
|
1415
|
-
}) {
|
|
1416
|
-
const [query, setQuery] = React4.useState("");
|
|
1417
|
-
const [open, setOpen] = React4.useState(false);
|
|
1418
|
-
const filtered = React4.useMemo(() => {
|
|
1419
|
-
const excluded = new Set((excludeProviders ?? []).map((p) => p.toLowerCase()));
|
|
1420
|
-
const allowedModalities = modalities ? new Set(modalities) : null;
|
|
1421
|
-
const q = query.trim().toLowerCase();
|
|
1422
|
-
return models.filter((m) => {
|
|
1423
|
-
const provider = (m._provider ?? m.provider ?? "").toLowerCase();
|
|
1424
|
-
if (excluded.has(provider)) return false;
|
|
1425
|
-
if (allowedModalities && m.architecture?.modality && !allowedModalities.has(m.architecture.modality)) return false;
|
|
1426
|
-
if (!q) return true;
|
|
1427
|
-
const id = canonicalModelId(m).toLowerCase();
|
|
1428
|
-
const name = (m.name ?? "").toLowerCase();
|
|
1429
|
-
return id.includes(q) || name.includes(q) || provider.includes(q);
|
|
1430
|
-
});
|
|
1431
|
-
}, [models, query, modalities, excludeProviders]);
|
|
1432
|
-
const grouped = React4.useMemo(() => {
|
|
1433
|
-
const groups = /* @__PURE__ */ new Map();
|
|
1434
|
-
for (const m of filtered) {
|
|
1435
|
-
const provider = m._provider ?? m.provider ?? "other";
|
|
1436
|
-
const list = groups.get(provider);
|
|
1437
|
-
if (list) list.push(m);
|
|
1438
|
-
else groups.set(provider, [m]);
|
|
1439
|
-
}
|
|
1440
|
-
return Array.from(groups.entries()).sort(([a], [b]) => a.localeCompare(b));
|
|
1441
|
-
}, [filtered]);
|
|
1442
|
-
const current = React4.useMemo(
|
|
1443
|
-
() => models.find((m) => canonicalModelId(m) === value),
|
|
1444
|
-
[models, value]
|
|
1445
|
-
);
|
|
1446
|
-
const currentLabel = current?.name ?? current?.id ?? value;
|
|
1447
|
-
const recentIds = React4.useMemo(() => {
|
|
1448
|
-
if (!recents?.length) return [];
|
|
1449
|
-
const lookup = new Map(models.map((m) => [canonicalModelId(m), m]));
|
|
1450
|
-
return recents.map((id) => lookup.get(id)).filter((m) => Boolean(m)).slice(0, 4);
|
|
1451
|
-
}, [recents, models]);
|
|
1452
|
-
const handleSelect = (id) => {
|
|
1453
|
-
onChange(id);
|
|
1454
|
-
setOpen(false);
|
|
1455
|
-
setQuery("");
|
|
1456
|
-
};
|
|
1457
|
-
const trigger = variant === "pill" ? /* @__PURE__ */ jsxs11(
|
|
1458
|
-
"button",
|
|
1459
|
-
{
|
|
1460
|
-
type: "button",
|
|
1461
|
-
disabled,
|
|
1462
|
-
className: cn(
|
|
1463
|
-
"inline-flex items-center gap-1.5 rounded-full border border-border bg-card",
|
|
1464
|
-
"px-2.5 py-1 text-xs font-medium text-foreground",
|
|
1465
|
-
"transition-colors duration-[var(--transition-fast)]",
|
|
1466
|
-
"hover:border-primary/30 hover:bg-accent/30",
|
|
1467
|
-
"focus:outline-none focus:border-primary/40",
|
|
1468
|
-
"data-[state=open]:border-primary/40 data-[state=open]:bg-accent/30",
|
|
1469
|
-
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1470
|
-
className
|
|
1471
|
-
),
|
|
1472
|
-
children: [
|
|
1473
|
-
/* @__PURE__ */ jsx13(Sparkles, { className: "h-3 w-3 text-muted-foreground" }),
|
|
1474
|
-
/* @__PURE__ */ jsx13("span", { className: "truncate max-w-[160px]", children: currentLabel || placeholder }),
|
|
1475
|
-
/* @__PURE__ */ jsx13(ChevronDown2, { className: "h-3 w-3 text-muted-foreground transition-transform data-[state=open]:rotate-180" })
|
|
1476
|
-
]
|
|
1477
|
-
}
|
|
1478
|
-
) : /* @__PURE__ */ jsxs11(
|
|
1479
|
-
"button",
|
|
1480
|
-
{
|
|
1481
|
-
type: "button",
|
|
1482
|
-
disabled,
|
|
1483
|
-
className: cn(
|
|
1484
|
-
"flex w-full items-center justify-between gap-2 rounded-[var(--radius-md)]",
|
|
1485
|
-
"border border-border bg-card px-3 py-2.5 text-sm text-left",
|
|
1486
|
-
"transition-colors duration-[var(--transition-fast)]",
|
|
1487
|
-
"hover:border-primary/20 hover:bg-accent/30",
|
|
1488
|
-
"focus:outline-none focus:border-primary/30",
|
|
1489
|
-
"data-[state=open]:border-primary/30 data-[state=open]:bg-accent/30",
|
|
1490
|
-
"disabled:opacity-50 disabled:cursor-not-allowed",
|
|
1491
|
-
className
|
|
1492
|
-
),
|
|
1493
|
-
children: [
|
|
1494
|
-
/* @__PURE__ */ jsx13("span", { className: cn("truncate", current ? "text-foreground font-medium" : "text-muted-foreground"), children: currentLabel || placeholder }),
|
|
1495
|
-
/* @__PURE__ */ jsx13(ChevronDown2, { className: "h-4 w-4 shrink-0 text-muted-foreground transition-transform data-[state=open]:rotate-180" })
|
|
1496
|
-
]
|
|
1497
|
-
}
|
|
1498
|
-
);
|
|
1499
|
-
return /* @__PURE__ */ jsxs11("div", { className: cn(variant === "field" ? "space-y-1.5" : "inline-flex", variant === "field" ? className : void 0), children: [
|
|
1500
|
-
variant === "field" && label && /* @__PURE__ */ jsx13("label", { className: "block text-xs font-medium text-muted-foreground uppercase tracking-[0.06em]", children: label }),
|
|
1501
|
-
/* @__PURE__ */ jsxs11(Popover.Root, { open, onOpenChange: setOpen, children: [
|
|
1502
|
-
/* @__PURE__ */ jsx13(Popover.Trigger, { asChild: true, children: trigger }),
|
|
1503
|
-
/* @__PURE__ */ jsx13(Popover.Portal, { children: /* @__PURE__ */ jsxs11(
|
|
1504
|
-
Popover.Content,
|
|
1505
|
-
{
|
|
1506
|
-
sideOffset: 4,
|
|
1507
|
-
align: variant === "pill" ? "start" : "start",
|
|
1508
|
-
className: cn(
|
|
1509
|
-
"z-50 w-[var(--radix-dropdown-menu-trigger-width)] min-w-[320px] max-w-[460px]",
|
|
1510
|
-
"max-h-[440px] overflow-hidden flex flex-col",
|
|
1511
|
-
"rounded-[var(--radius-md)] border border-border bg-card shadow-[var(--shadow-dropdown)]",
|
|
1512
|
-
"data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
1513
|
-
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
1514
|
-
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95"
|
|
1515
|
-
),
|
|
1516
|
-
children: [
|
|
1517
|
-
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 border-b border-border px-3 py-2", children: [
|
|
1518
|
-
/* @__PURE__ */ jsx13(Search, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
|
|
1519
|
-
/* @__PURE__ */ jsx13(
|
|
1520
|
-
"input",
|
|
1521
|
-
{
|
|
1522
|
-
type: "text",
|
|
1523
|
-
value: query,
|
|
1524
|
-
onChange: (e) => setQuery(e.target.value),
|
|
1525
|
-
placeholder: "Search models...",
|
|
1526
|
-
autoFocus: true,
|
|
1527
|
-
className: "flex-1 bg-transparent text-sm outline-none placeholder:text-muted-foreground"
|
|
1528
|
-
}
|
|
1529
|
-
),
|
|
1530
|
-
loading && /* @__PURE__ */ jsx13(Loader2, { className: "h-3.5 w-3.5 animate-spin text-muted-foreground" })
|
|
1531
|
-
] }),
|
|
1532
|
-
/* @__PURE__ */ jsxs11("div", { className: "flex-1 overflow-y-auto", children: [
|
|
1533
|
-
!query && presets.length > 0 && /* @__PURE__ */ jsx13(Section, { label: "Presets", children: presets.map((preset) => {
|
|
1534
|
-
const Icon2 = preset.icon ?? Star;
|
|
1535
|
-
const matchedId = preset.match(models);
|
|
1536
|
-
if (!matchedId) return null;
|
|
1537
|
-
const matched = models.find((m) => canonicalModelId(m) === matchedId);
|
|
1538
|
-
const isCurrent = matchedId === value;
|
|
1539
|
-
return /* @__PURE__ */ jsxs11(
|
|
1540
|
-
PickerItem,
|
|
1541
|
-
{
|
|
1542
|
-
onSelect: () => handleSelect(matchedId),
|
|
1543
|
-
active: isCurrent,
|
|
1544
|
-
children: [
|
|
1545
|
-
/* @__PURE__ */ jsx13(Icon2, { className: "h-3.5 w-3.5 shrink-0 text-[var(--accent-text)]" }),
|
|
1546
|
-
/* @__PURE__ */ jsxs11("div", { className: "min-w-0 flex-1", children: [
|
|
1547
|
-
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-1.5", children: [
|
|
1548
|
-
/* @__PURE__ */ jsx13("span", { className: "text-sm font-medium", children: preset.label }),
|
|
1549
|
-
/* @__PURE__ */ jsxs11("span", { className: "text-[10px] text-muted-foreground truncate", children: [
|
|
1550
|
-
"\u2192 ",
|
|
1551
|
-
matched?.name ?? matchedId
|
|
1552
|
-
] })
|
|
1553
|
-
] }),
|
|
1554
|
-
/* @__PURE__ */ jsx13("span", { className: "text-xs text-muted-foreground", children: preset.hint })
|
|
1555
|
-
] })
|
|
1556
|
-
]
|
|
1557
|
-
},
|
|
1558
|
-
preset.id
|
|
1559
|
-
);
|
|
1560
|
-
}) }),
|
|
1561
|
-
!query && recentIds.length > 0 && /* @__PURE__ */ jsx13(Section, { label: "Recent", children: recentIds.map((m) => /* @__PURE__ */ jsx13(
|
|
1562
|
-
ModelRow,
|
|
1563
|
-
{
|
|
1564
|
-
model: m,
|
|
1565
|
-
active: canonicalModelId(m) === value,
|
|
1566
|
-
onSelect: handleSelect
|
|
1567
|
-
},
|
|
1568
|
-
`recent-${canonicalModelId(m)}`
|
|
1569
|
-
)) }),
|
|
1570
|
-
grouped.length === 0 ? /* @__PURE__ */ jsx13("div", { className: "px-3 py-8 text-center text-xs text-muted-foreground", children: loading ? "Loading models..." : query ? "No models match." : "No models available." }) : grouped.map(([provider, list]) => /* @__PURE__ */ jsx13(Section, { label: provider, children: list.map((m) => /* @__PURE__ */ jsx13(
|
|
1571
|
-
ModelRow,
|
|
1572
|
-
{
|
|
1573
|
-
model: m,
|
|
1574
|
-
active: canonicalModelId(m) === value,
|
|
1575
|
-
onSelect: handleSelect
|
|
1576
|
-
},
|
|
1577
|
-
canonicalModelId(m)
|
|
1578
|
-
)) }, provider))
|
|
1579
|
-
] }),
|
|
1580
|
-
/* @__PURE__ */ jsxs11("div", { className: "border-t border-border px-3 py-1.5 text-[10px] text-muted-foreground", children: [
|
|
1581
|
-
filtered.length,
|
|
1582
|
-
" of ",
|
|
1583
|
-
models.length,
|
|
1584
|
-
" model",
|
|
1585
|
-
models.length === 1 ? "" : "s"
|
|
1586
|
-
] })
|
|
1587
|
-
]
|
|
1588
|
-
}
|
|
1589
|
-
) })
|
|
1590
|
-
] })
|
|
1591
|
-
] });
|
|
1592
|
-
}
|
|
1593
|
-
function Section({ label, children }) {
|
|
1594
|
-
return /* @__PURE__ */ jsxs11("div", { className: "py-1", children: [
|
|
1595
|
-
/* @__PURE__ */ jsx13("div", { className: "px-3 pt-1.5 pb-0.5 text-[10px] font-mono uppercase tracking-widest text-muted-foreground", children: label }),
|
|
1596
|
-
/* @__PURE__ */ jsx13("div", { children })
|
|
1597
|
-
] });
|
|
1598
|
-
}
|
|
1599
|
-
function PickerItem({
|
|
1600
|
-
onSelect,
|
|
1601
|
-
active,
|
|
1602
|
-
children
|
|
1603
|
-
}) {
|
|
1604
|
-
return /* @__PURE__ */ jsx13(
|
|
1605
|
-
Popover.Item,
|
|
1606
|
-
{
|
|
1607
|
-
onSelect: (e) => {
|
|
1608
|
-
e.preventDefault();
|
|
1609
|
-
onSelect();
|
|
1610
|
-
},
|
|
1611
|
-
className: cn(
|
|
1612
|
-
"flex cursor-pointer items-start gap-2 px-3 py-2 outline-none",
|
|
1613
|
-
"transition-colors duration-[var(--transition-fast)]",
|
|
1614
|
-
"hover:bg-accent/40 focus:bg-accent/40",
|
|
1615
|
-
active && "bg-[var(--accent-surface-soft)] text-[var(--accent-text)]"
|
|
1616
|
-
),
|
|
1617
|
-
children
|
|
1618
|
-
}
|
|
1619
|
-
);
|
|
1620
|
-
}
|
|
1621
|
-
function ModelRow({
|
|
1622
|
-
model,
|
|
1623
|
-
active,
|
|
1624
|
-
onSelect
|
|
1625
|
-
}) {
|
|
1626
|
-
const id = canonicalModelId(model);
|
|
1627
|
-
const pricing = formatPricing(model.pricing);
|
|
1628
|
-
const ctx = formatContext(model.context_length);
|
|
1629
|
-
return /* @__PURE__ */ jsx13(PickerItem, { onSelect: () => onSelect(id), active, children: /* @__PURE__ */ jsxs11("div", { className: "min-w-0 flex-1", children: [
|
|
1630
|
-
/* @__PURE__ */ jsxs11("div", { className: "flex items-baseline justify-between gap-2", children: [
|
|
1631
|
-
/* @__PURE__ */ jsx13("span", { className: "text-sm font-medium truncate", children: model.name ?? model.id }),
|
|
1632
|
-
ctx && /* @__PURE__ */ jsx13("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: ctx })
|
|
1633
|
-
] }),
|
|
1634
|
-
/* @__PURE__ */ jsxs11("div", { className: "flex items-center gap-2 text-[11px] text-muted-foreground", children: [
|
|
1635
|
-
/* @__PURE__ */ jsx13("span", { className: "truncate", children: id }),
|
|
1636
|
-
pricing && /* @__PURE__ */ jsxs11(Fragment7, { children: [
|
|
1637
|
-
/* @__PURE__ */ jsx13("span", { className: "shrink-0", children: "\xB7" }),
|
|
1638
|
-
/* @__PURE__ */ jsx13("span", { className: "shrink-0 font-mono", children: pricing })
|
|
1639
|
-
] })
|
|
1640
|
-
] })
|
|
1641
|
-
] }) });
|
|
1642
|
-
}
|
|
1643
|
-
|
|
1644
|
-
// src/dashboard/profile-selector.tsx
|
|
1645
|
-
import { Check as Check2, ChevronDown as ChevronDown3, Plus as Plus3, Settings } from "lucide-react";
|
|
1646
|
-
import { Fragment as Fragment8, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1647
|
-
function ProfileSelector({
|
|
1648
|
-
profiles,
|
|
1649
|
-
selectedId,
|
|
1650
|
-
onSelect,
|
|
1651
|
-
onCreateClick,
|
|
1652
|
-
onManageClick,
|
|
1653
|
-
label = "Profile",
|
|
1654
|
-
placeholder = "Default (no custom profile)",
|
|
1655
|
-
showMetrics = true,
|
|
1656
|
-
className
|
|
1657
|
-
}) {
|
|
1658
|
-
const selected = profiles.find((p) => p.id === selectedId);
|
|
1659
|
-
const builtinProfiles = profiles.filter((p) => p.is_builtin);
|
|
1660
|
-
const customProfiles = profiles.filter((p) => !p.is_builtin);
|
|
1661
|
-
return /* @__PURE__ */ jsxs12("div", { className, children: [
|
|
1662
|
-
label && /* @__PURE__ */ jsx14("label", { className: "mb-2 block font-medium text-sm", children: label }),
|
|
1663
|
-
/* @__PURE__ */ jsxs12(DropdownMenu, { children: [
|
|
1664
|
-
/* @__PURE__ */ jsx14(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs12(Button, { variant: "outline", className: "w-full justify-between", children: [
|
|
1665
|
-
/* @__PURE__ */ jsx14("span", { className: "truncate", children: selected ? selected.name : placeholder }),
|
|
1666
|
-
/* @__PURE__ */ jsx14(ChevronDown3, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })
|
|
1667
|
-
] }) }),
|
|
1668
|
-
/* @__PURE__ */ jsxs12(DropdownMenuContent, { className: "w-[300px]", align: "start", children: [
|
|
1669
|
-
/* @__PURE__ */ jsxs12(
|
|
1670
|
-
DropdownMenuItem,
|
|
1671
|
-
{
|
|
1672
|
-
onClick: () => onSelect(null),
|
|
1673
|
-
className: "flex items-center justify-between",
|
|
1674
|
-
children: [
|
|
1675
|
-
/* @__PURE__ */ jsx14("span", { children: placeholder }),
|
|
1676
|
-
!selectedId && /* @__PURE__ */ jsx14(Check2, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
|
|
1677
|
-
]
|
|
1678
|
-
}
|
|
1679
|
-
),
|
|
1680
|
-
builtinProfiles.length > 0 && /* @__PURE__ */ jsxs12(Fragment8, { children: [
|
|
1681
|
-
/* @__PURE__ */ jsx14(DropdownMenuSeparator, {}),
|
|
1682
|
-
/* @__PURE__ */ jsx14(DropdownMenuLabel, { children: "Built-in Profiles" }),
|
|
1683
|
-
builtinProfiles.map((profile) => /* @__PURE__ */ jsxs12(
|
|
1684
|
-
DropdownMenuItem,
|
|
1685
|
-
{
|
|
1686
|
-
onClick: () => onSelect(profile),
|
|
1687
|
-
className: "flex flex-col items-start gap-1",
|
|
1688
|
-
children: [
|
|
1689
|
-
/* @__PURE__ */ jsxs12("div", { className: "flex w-full items-center justify-between", children: [
|
|
1690
|
-
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
|
|
1691
|
-
/* @__PURE__ */ jsx14("span", { className: "font-medium", children: profile.name }),
|
|
1692
|
-
profile.extends && /* @__PURE__ */ jsxs12(Badge, { variant: "secondary", className: "border-0 text-xs", children: [
|
|
1693
|
-
"extends ",
|
|
1694
|
-
profile.extends
|
|
1695
|
-
] })
|
|
1696
|
-
] }),
|
|
1697
|
-
selectedId === profile.id && /* @__PURE__ */ jsx14(Check2, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
|
|
1698
|
-
] }),
|
|
1699
|
-
profile.description && /* @__PURE__ */ jsx14("span", { className: "line-clamp-1 text-muted-foreground text-xs", children: profile.description })
|
|
1700
|
-
]
|
|
1701
|
-
},
|
|
1702
|
-
profile.id
|
|
1703
|
-
))
|
|
1704
|
-
] }),
|
|
1705
|
-
customProfiles.length > 0 && /* @__PURE__ */ jsxs12(Fragment8, { children: [
|
|
1706
|
-
/* @__PURE__ */ jsx14(DropdownMenuSeparator, {}),
|
|
1707
|
-
/* @__PURE__ */ jsx14(DropdownMenuLabel, { children: "Custom Profiles" }),
|
|
1708
|
-
customProfiles.map((profile) => /* @__PURE__ */ jsxs12(
|
|
1709
|
-
DropdownMenuItem,
|
|
1710
|
-
{
|
|
1711
|
-
onClick: () => onSelect(profile),
|
|
1712
|
-
className: "flex flex-col items-start gap-1",
|
|
1713
|
-
children: [
|
|
1714
|
-
/* @__PURE__ */ jsxs12("div", { className: "flex w-full items-center justify-between", children: [
|
|
1715
|
-
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
|
|
1716
|
-
/* @__PURE__ */ jsx14("span", { className: "font-medium", children: profile.name }),
|
|
1717
|
-
profile.model && /* @__PURE__ */ jsx14(Badge, { variant: "secondary", className: "border-0 text-xs", children: profile.model.split("/").pop() })
|
|
1718
|
-
] }),
|
|
1719
|
-
selectedId === profile.id && /* @__PURE__ */ jsx14(Check2, { className: "h-4 w-4 text-[var(--surface-success-text)]" })
|
|
1720
|
-
] }),
|
|
1721
|
-
profile.description && /* @__PURE__ */ jsx14("span", { className: "line-clamp-1 text-muted-foreground text-xs", children: profile.description }),
|
|
1722
|
-
showMetrics && profile.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */ jsxs12("div", { className: "flex gap-3 text-muted-foreground text-xs", children: [
|
|
1723
|
-
/* @__PURE__ */ jsxs12("span", { children: [
|
|
1724
|
-
profile.metrics.total_runs,
|
|
1725
|
-
" runs"
|
|
1726
|
-
] }),
|
|
1727
|
-
/* @__PURE__ */ jsxs12("span", { children: [
|
|
1728
|
-
profile.metrics.success_rate.toFixed(0),
|
|
1729
|
-
"% success"
|
|
1730
|
-
] }),
|
|
1731
|
-
/* @__PURE__ */ jsxs12("span", { children: [
|
|
1732
|
-
"~",
|
|
1733
|
-
(profile.metrics.avg_duration_ms / 1e3).toFixed(1),
|
|
1734
|
-
"s avg"
|
|
1735
|
-
] })
|
|
1736
|
-
] })
|
|
1737
|
-
]
|
|
1738
|
-
},
|
|
1739
|
-
profile.id
|
|
1740
|
-
))
|
|
1741
|
-
] }),
|
|
1742
|
-
(onCreateClick || onManageClick) && /* @__PURE__ */ jsxs12(Fragment8, { children: [
|
|
1743
|
-
/* @__PURE__ */ jsx14(DropdownMenuSeparator, {}),
|
|
1744
|
-
onCreateClick && /* @__PURE__ */ jsxs12(
|
|
1745
|
-
DropdownMenuItem,
|
|
1746
|
-
{
|
|
1747
|
-
onClick: onCreateClick,
|
|
1748
|
-
className: "text-[var(--surface-info-text)]",
|
|
1749
|
-
children: [
|
|
1750
|
-
/* @__PURE__ */ jsx14(Plus3, { className: "mr-2 h-4 w-4" }),
|
|
1751
|
-
"Create New Profile"
|
|
1752
|
-
]
|
|
1753
|
-
}
|
|
1754
|
-
),
|
|
1755
|
-
onManageClick && /* @__PURE__ */ jsxs12(
|
|
1756
|
-
DropdownMenuItem,
|
|
1757
|
-
{
|
|
1758
|
-
onClick: onManageClick,
|
|
1759
|
-
className: "text-muted-foreground",
|
|
1760
|
-
children: [
|
|
1761
|
-
/* @__PURE__ */ jsx14(Settings, { className: "mr-2 h-4 w-4" }),
|
|
1762
|
-
"Manage Profiles"
|
|
1763
|
-
]
|
|
1764
|
-
}
|
|
1765
|
-
)
|
|
1766
|
-
] })
|
|
1767
|
-
] })
|
|
1768
|
-
] })
|
|
1769
|
-
] });
|
|
1770
|
-
}
|
|
1771
|
-
function ProfileComparison({
|
|
1772
|
-
profiles,
|
|
1773
|
-
className
|
|
1774
|
-
}) {
|
|
1775
|
-
const profilesWithMetrics = profiles.filter(
|
|
1776
|
-
(p) => p.metrics && p.metrics.total_runs > 0
|
|
1777
|
-
);
|
|
1778
|
-
if (profilesWithMetrics.length === 0) {
|
|
1779
|
-
return null;
|
|
1780
|
-
}
|
|
1781
|
-
const bestSuccess = profilesWithMetrics.reduce(
|
|
1782
|
-
(best, p) => (p.metrics?.success_rate ?? 0) > (best.metrics?.success_rate ?? 0) ? p : best
|
|
1783
|
-
);
|
|
1784
|
-
const fastestProfile = profilesWithMetrics.reduce(
|
|
1785
|
-
(best, p) => (p.metrics?.avg_duration_ms ?? Number.POSITIVE_INFINITY) < (best.metrics?.avg_duration_ms ?? Number.POSITIVE_INFINITY) ? p : best
|
|
1786
|
-
);
|
|
1787
|
-
return /* @__PURE__ */ jsxs12("div", { className: `rounded-lg border border-border p-4 ${className ?? ""}`, children: [
|
|
1788
|
-
/* @__PURE__ */ jsx14("h4", { className: "mb-3 font-medium text-sm", children: "Profile Performance" }),
|
|
1789
|
-
/* @__PURE__ */ jsx14("div", { className: "space-y-3", children: profilesWithMetrics.map((profile) => {
|
|
1790
|
-
const isBestSuccess = profile.id === bestSuccess.id;
|
|
1791
|
-
const isFastest = profile.id === fastestProfile.id;
|
|
1792
|
-
return /* @__PURE__ */ jsxs12(
|
|
1793
|
-
"div",
|
|
1794
|
-
{
|
|
1795
|
-
className: "flex items-center justify-between gap-4",
|
|
1796
|
-
children: [
|
|
1797
|
-
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-2", children: [
|
|
1798
|
-
/* @__PURE__ */ jsx14("span", { className: "font-medium", children: profile.name }),
|
|
1799
|
-
isBestSuccess && /* @__PURE__ */ jsx14(Badge, { className: "border border-[var(--surface-success-border)] bg-[var(--surface-success-bg)] text-[var(--surface-success-text)] text-xs", children: "Best Success" }),
|
|
1800
|
-
isFastest && !isBestSuccess && /* @__PURE__ */ jsx14(Badge, { className: "border border-[var(--surface-info-border)] bg-[var(--surface-info-bg)] text-[var(--surface-info-text)] text-xs", children: "Fastest" })
|
|
1801
|
-
] }),
|
|
1802
|
-
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-4 text-sm", children: [
|
|
1803
|
-
/* @__PURE__ */ jsxs12("span", { children: [
|
|
1804
|
-
/* @__PURE__ */ jsx14("span", { className: "text-muted-foreground", children: "Success:" }),
|
|
1805
|
-
" ",
|
|
1806
|
-
/* @__PURE__ */ jsxs12(
|
|
1807
|
-
"span",
|
|
1808
|
-
{
|
|
1809
|
-
className: (profile.metrics?.success_rate ?? 0) >= 80 ? "text-[var(--surface-success-text)]" : (profile.metrics?.success_rate ?? 0) >= 50 ? "text-[var(--surface-warning-text)]" : "text-[var(--surface-danger-text)]",
|
|
1810
|
-
children: [
|
|
1811
|
-
profile.metrics?.success_rate.toFixed(0),
|
|
1812
|
-
"%"
|
|
1813
|
-
]
|
|
1814
|
-
}
|
|
1815
|
-
)
|
|
1816
|
-
] }),
|
|
1817
|
-
/* @__PURE__ */ jsxs12("span", { children: [
|
|
1818
|
-
/* @__PURE__ */ jsx14("span", { className: "text-muted-foreground", children: "Avg:" }),
|
|
1819
|
-
" ",
|
|
1820
|
-
((profile.metrics?.avg_duration_ms ?? 0) / 1e3).toFixed(1),
|
|
1821
|
-
"s"
|
|
1822
|
-
] }),
|
|
1823
|
-
/* @__PURE__ */ jsxs12("span", { className: "text-muted-foreground", children: [
|
|
1824
|
-
profile.metrics?.total_runs,
|
|
1825
|
-
" runs"
|
|
1826
|
-
] })
|
|
1827
|
-
] })
|
|
1828
|
-
]
|
|
1829
|
-
},
|
|
1830
|
-
profile.id
|
|
1831
|
-
);
|
|
1832
|
-
}) })
|
|
1833
|
-
] });
|
|
1834
|
-
}
|
|
1835
|
-
|
|
1836
|
-
// src/dashboard/variant-list.tsx
|
|
1837
|
-
import {
|
|
1838
|
-
Check as Check3,
|
|
1839
|
-
CheckCircle2,
|
|
1840
|
-
Clock as Clock2,
|
|
1841
|
-
ExternalLink,
|
|
1842
|
-
Loader2 as Loader22,
|
|
1843
|
-
Timer,
|
|
1844
|
-
X,
|
|
1845
|
-
XCircle
|
|
1846
|
-
} from "lucide-react";
|
|
1847
|
-
import { Fragment as Fragment9, jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1848
|
-
var statusConfig = {
|
|
1849
|
-
pending: {
|
|
1850
|
-
icon: Clock2,
|
|
1851
|
-
color: "text-[var(--surface-warning-text)]",
|
|
1852
|
-
bg: "bg-[var(--surface-warning-bg)]",
|
|
1853
|
-
border: "border-[var(--surface-warning-border)]",
|
|
1854
|
-
label: "Pending",
|
|
1855
|
-
animate: false
|
|
1856
|
-
},
|
|
1857
|
-
running: {
|
|
1858
|
-
icon: Loader22,
|
|
1859
|
-
color: "text-primary",
|
|
1860
|
-
bg: "bg-[var(--accent-surface-soft)]",
|
|
1861
|
-
border: "border-border",
|
|
1862
|
-
label: "Running",
|
|
1863
|
-
animate: true
|
|
1864
|
-
},
|
|
1865
|
-
completed: {
|
|
1866
|
-
icon: CheckCircle2,
|
|
1867
|
-
color: "text-[var(--surface-success-text)]",
|
|
1868
|
-
bg: "bg-[var(--surface-success-bg)]",
|
|
1869
|
-
border: "border-[var(--surface-success-border)]",
|
|
1870
|
-
label: "Completed",
|
|
1871
|
-
animate: false
|
|
1872
|
-
},
|
|
1873
|
-
failed: {
|
|
1874
|
-
icon: XCircle,
|
|
1875
|
-
color: "text-[var(--surface-danger-text)]",
|
|
1876
|
-
bg: "bg-[var(--surface-danger-bg)]",
|
|
1877
|
-
border: "border-[var(--surface-danger-border)]",
|
|
1878
|
-
label: "Failed",
|
|
1879
|
-
animate: false
|
|
1880
|
-
},
|
|
1881
|
-
cancelled: {
|
|
1882
|
-
icon: XCircle,
|
|
1883
|
-
color: "text-[var(--surface-neutral-text)]",
|
|
1884
|
-
bg: "bg-[var(--surface-neutral-bg)]",
|
|
1885
|
-
border: "border-[var(--surface-neutral-border)]",
|
|
1886
|
-
label: "Cancelled",
|
|
1887
|
-
animate: false
|
|
1888
|
-
}
|
|
1889
|
-
};
|
|
1890
|
-
var outcomeConfig = {
|
|
1891
|
-
pending_review: {
|
|
1892
|
-
color: "text-[var(--surface-warning-text)]",
|
|
1893
|
-
bg: "bg-[var(--surface-warning-bg)]",
|
|
1894
|
-
border: "border-[var(--surface-warning-border)]",
|
|
1895
|
-
label: "Pending Review"
|
|
1896
|
-
},
|
|
1897
|
-
accepted: {
|
|
1898
|
-
color: "text-[var(--surface-success-text)]",
|
|
1899
|
-
bg: "bg-[var(--surface-success-bg)]",
|
|
1900
|
-
border: "border-[var(--surface-success-border)]",
|
|
1901
|
-
label: "Accepted"
|
|
1902
|
-
},
|
|
1903
|
-
rejected: {
|
|
1904
|
-
color: "text-[var(--surface-danger-text)]",
|
|
1905
|
-
bg: "bg-[var(--surface-danger-bg)]",
|
|
1906
|
-
border: "border-[var(--surface-danger-border)]",
|
|
1907
|
-
label: "Rejected"
|
|
1908
|
-
},
|
|
1909
|
-
merged_with_conflicts: {
|
|
1910
|
-
color: "text-[var(--surface-orange-text)]",
|
|
1911
|
-
bg: "bg-[var(--surface-orange-bg)]",
|
|
1912
|
-
border: "border-[var(--surface-orange-border)]",
|
|
1913
|
-
label: "Merged (conflicts)"
|
|
1914
|
-
},
|
|
1915
|
-
expired: {
|
|
1916
|
-
color: "text-[var(--surface-neutral-text)]",
|
|
1917
|
-
bg: "bg-[var(--surface-neutral-bg)]",
|
|
1918
|
-
border: "border-[var(--surface-neutral-border)]",
|
|
1919
|
-
label: "Expired"
|
|
1920
|
-
}
|
|
1921
|
-
};
|
|
1922
|
-
function VariantList({
|
|
1923
|
-
variants,
|
|
1924
|
-
selectedId,
|
|
1925
|
-
onSelect,
|
|
1926
|
-
onAccept,
|
|
1927
|
-
onReject,
|
|
1928
|
-
isActioning,
|
|
1929
|
-
className
|
|
1930
|
-
}) {
|
|
1931
|
-
return /* @__PURE__ */ jsx15("div", { className: `space-y-2 ${className || ""}`, children: variants.map((variant) => {
|
|
1932
|
-
const status = statusConfig[variant.status];
|
|
1933
|
-
const StatusIcon = status.icon;
|
|
1934
|
-
const isSelected = variant.id === selectedId;
|
|
1935
|
-
return /* @__PURE__ */ jsxs13(
|
|
1936
|
-
"div",
|
|
1937
|
-
{
|
|
1938
|
-
className: `cursor-pointer rounded-lg border px-3 py-2.5 transition-colors ${isSelected ? "border-primary/30 bg-[var(--accent-surface-soft)]" : "border-border bg-card hover:border-primary/20 hover:bg-muted/50"}`,
|
|
1939
|
-
onClick: () => onSelect?.(variant.id),
|
|
1940
|
-
children: [
|
|
1941
|
-
/* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
|
|
1942
|
-
/* @__PURE__ */ jsxs13(Badge, { className: `shrink-0 ${status.bg} ${status.border} ${status.color}`, children: [
|
|
1943
|
-
/* @__PURE__ */ jsx15(
|
|
1944
|
-
StatusIcon,
|
|
1945
|
-
{
|
|
1946
|
-
className: `mr-1 h-3 w-3 ${status.animate ? "animate-spin" : ""}`
|
|
1947
|
-
}
|
|
1948
|
-
),
|
|
1949
|
-
status.label
|
|
1950
|
-
] }),
|
|
1951
|
-
/* @__PURE__ */ jsx15("span", { className: "truncate text-sm font-medium text-foreground", children: variant.label }),
|
|
1952
|
-
variant.sublabel && /* @__PURE__ */ jsxs13("span", { className: "shrink-0 text-xs text-muted-foreground", children: [
|
|
1953
|
-
"(",
|
|
1954
|
-
variant.sublabel,
|
|
1955
|
-
")"
|
|
1956
|
-
] }),
|
|
1957
|
-
variant.durationMs && /* @__PURE__ */ jsxs13("span", { className: "flex shrink-0 items-center gap-1 text-xs text-muted-foreground", children: [
|
|
1958
|
-
/* @__PURE__ */ jsx15(Timer, { className: "h-3 w-3" }),
|
|
1959
|
-
(variant.durationMs / 1e3).toFixed(1),
|
|
1960
|
-
"s"
|
|
1961
|
-
] }),
|
|
1962
|
-
/* @__PURE__ */ jsxs13("div", { className: "ml-auto flex shrink-0 items-center gap-1.5", children: [
|
|
1963
|
-
variant.outcome && /* @__PURE__ */ jsx15(
|
|
1964
|
-
Badge,
|
|
1965
|
-
{
|
|
1966
|
-
className: `${outcomeConfig[variant.outcome].bg} ${outcomeConfig[variant.outcome].border} ${outcomeConfig[variant.outcome].color}`,
|
|
1967
|
-
children: outcomeConfig[variant.outcome].label
|
|
1968
|
-
}
|
|
1969
|
-
),
|
|
1970
|
-
variant.status === "completed" && variant.outcome === "pending_review" && onAccept && onReject && /* @__PURE__ */ jsxs13(Fragment9, { children: [
|
|
1971
|
-
/* @__PURE__ */ jsxs13(
|
|
1972
|
-
Button,
|
|
1973
|
-
{
|
|
1974
|
-
variant: "outline",
|
|
1975
|
-
size: "sm",
|
|
1976
|
-
className: "h-7 border-[var(--surface-success-border)] bg-[var(--surface-success-bg)] px-2 text-xs text-[var(--surface-success-text)] hover:bg-[var(--surface-success-border)]",
|
|
1977
|
-
onClick: (e) => {
|
|
1978
|
-
e.stopPropagation();
|
|
1979
|
-
onAccept(variant.id);
|
|
1980
|
-
},
|
|
1981
|
-
disabled: isActioning === variant.id,
|
|
1982
|
-
children: [
|
|
1983
|
-
/* @__PURE__ */ jsx15(Check3, { className: "mr-1 h-3 w-3" }),
|
|
1984
|
-
"Accept"
|
|
1985
|
-
]
|
|
1986
|
-
}
|
|
1987
|
-
),
|
|
1988
|
-
/* @__PURE__ */ jsxs13(
|
|
1989
|
-
Button,
|
|
1990
|
-
{
|
|
1991
|
-
variant: "outline",
|
|
1992
|
-
size: "sm",
|
|
1993
|
-
className: "h-7 border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] px-2 text-xs text-[var(--surface-danger-text)] hover:bg-[var(--surface-danger-border)]",
|
|
1994
|
-
onClick: (e) => {
|
|
1995
|
-
e.stopPropagation();
|
|
1996
|
-
onReject(variant.id);
|
|
1997
|
-
},
|
|
1998
|
-
disabled: isActioning === variant.id,
|
|
1999
|
-
children: [
|
|
2000
|
-
/* @__PURE__ */ jsx15(X, { className: "mr-1 h-3 w-3" }),
|
|
2001
|
-
"Reject"
|
|
2002
|
-
]
|
|
2003
|
-
}
|
|
2004
|
-
)
|
|
2005
|
-
] }),
|
|
2006
|
-
variant.detailsUrl && /* @__PURE__ */ jsx15(
|
|
2007
|
-
Button,
|
|
2008
|
-
{
|
|
2009
|
-
variant: "ghost",
|
|
2010
|
-
size: "sm",
|
|
2011
|
-
className: "h-7 w-7 p-0 text-muted-foreground hover:text-foreground",
|
|
2012
|
-
onClick: (e) => {
|
|
2013
|
-
e.stopPropagation();
|
|
2014
|
-
window.open(variant.detailsUrl, "_blank");
|
|
2015
|
-
},
|
|
2016
|
-
children: /* @__PURE__ */ jsx15(ExternalLink, { className: "h-3.5 w-3.5" })
|
|
2017
|
-
}
|
|
2018
|
-
)
|
|
2019
|
-
] })
|
|
2020
|
-
] }),
|
|
2021
|
-
variant.error && /* @__PURE__ */ jsx15("p", { className: "mt-1.5 text-xs text-[var(--surface-danger-text)]", children: variant.error }),
|
|
2022
|
-
variant.summary && /* @__PURE__ */ jsx15("p", { className: "mt-1.5 line-clamp-2 text-xs text-muted-foreground", children: variant.summary })
|
|
2023
|
-
]
|
|
2024
|
-
},
|
|
2025
|
-
variant.id
|
|
2026
|
-
);
|
|
2027
|
-
}) });
|
|
2028
|
-
}
|
|
2029
|
-
|
|
2030
|
-
export {
|
|
2031
|
-
SIDEBAR_RAIL_WIDTH,
|
|
2032
|
-
SIDEBAR_PANEL_WIDTH,
|
|
2033
|
-
SIDEBAR_TOTAL_WIDTH,
|
|
2034
|
-
SIDEBAR_MOBILE_WIDTH,
|
|
2035
|
-
SidebarProvider,
|
|
2036
|
-
useSidebar,
|
|
2037
|
-
Sidebar,
|
|
2038
|
-
SidebarRail,
|
|
2039
|
-
SidebarRailHeader,
|
|
2040
|
-
SidebarRailNav,
|
|
2041
|
-
SidebarRailFooter,
|
|
2042
|
-
RailSeparator,
|
|
2043
|
-
RailButton,
|
|
2044
|
-
RailModeButton,
|
|
2045
|
-
SidebarPanel,
|
|
2046
|
-
SidebarPanelHeader,
|
|
2047
|
-
SidebarPanelContent,
|
|
2048
|
-
SidebarContent,
|
|
2049
|
-
ProfileAvatar,
|
|
2050
|
-
ClusterStatusBar,
|
|
2051
|
-
CreditBalance,
|
|
2052
|
-
InvoiceTable,
|
|
2053
|
-
PlanCards,
|
|
2054
|
-
DashboardLayout,
|
|
2055
|
-
ResourceMeter,
|
|
2056
|
-
canAdminSandbox,
|
|
2057
|
-
SandboxCard,
|
|
2058
|
-
NewSandboxCard,
|
|
2059
|
-
SandboxTable,
|
|
2060
|
-
BackendSelector,
|
|
2061
|
-
HARNESS_OPTIONS,
|
|
2062
|
-
HarnessPicker,
|
|
2063
|
-
canonicalModelId,
|
|
2064
|
-
formatPricing,
|
|
2065
|
-
formatContext,
|
|
2066
|
-
ModelPicker,
|
|
2067
|
-
ProfileSelector,
|
|
2068
|
-
ProfileComparison,
|
|
2069
|
-
VariantList
|
|
2070
|
-
};
|