@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.
Files changed (106) hide show
  1. package/dist/auth.d.ts +1 -74
  2. package/dist/auth.js +1 -4
  3. package/dist/chat.d.ts +1 -136
  4. package/dist/chat.js +2 -15
  5. package/dist/chunk-2BUPSB7O.js +0 -0
  6. package/dist/chunk-3J6FG3FJ.js +18 -0
  7. package/dist/chunk-76IQLPW2.js +206 -0
  8. package/dist/chunk-7ZA5SEK3.js +239 -0
  9. package/dist/chunk-AZ3AWMTM.js +8 -0
  10. package/dist/chunk-CMY7W45U.js +380 -0
  11. package/dist/chunk-EI44GEQ5.js +6 -0
  12. package/dist/chunk-ENMWGVDL.js +858 -0
  13. package/dist/{chunk-5OQ27N57.js → chunk-GPT7VKK6.js} +34 -38
  14. package/dist/chunk-HLZTKSGT.js +2652 -0
  15. package/dist/chunk-JBGKGLD7.js +16 -0
  16. package/dist/chunk-NJNME4J4.js +14 -0
  17. package/dist/chunk-QPAJR74X.js +20 -0
  18. package/dist/chunk-TK46XFLM.js +28 -0
  19. package/dist/chunk-WID73FPH.js +89 -0
  20. package/dist/chunk-YVXK4XRO.js +30 -0
  21. package/dist/dashboard.d.ts +450 -4
  22. package/dist/dashboard.js +20 -891
  23. package/dist/editor.d.ts +1 -120
  24. package/dist/editor.js +1 -5
  25. package/dist/files.d.ts +1 -129
  26. package/dist/files.js +2 -7
  27. package/dist/globals.css +2 -1265
  28. package/dist/hooks.d.ts +114 -11
  29. package/dist/hooks.js +17 -88
  30. package/dist/index.d.ts +24 -99
  31. package/dist/index.js +251 -256
  32. package/dist/markdown.d.ts +1 -29
  33. package/dist/markdown.js +2 -2
  34. package/dist/openui.d.ts +8 -115
  35. package/dist/openui.js +1 -6
  36. package/dist/pages.d.ts +13 -12
  37. package/dist/pages.js +91 -115
  38. package/dist/primitives.d.ts +14 -49
  39. package/dist/primitives.js +69 -77
  40. package/dist/run.d.ts +1 -14
  41. package/dist/run.js +2 -22
  42. package/dist/sdk-hooks.d.ts +3 -283
  43. package/dist/sdk-hooks.js +10 -14
  44. package/dist/stores.d.ts +2 -14
  45. package/dist/stores.js +11 -39
  46. package/dist/styles.css +2 -1265
  47. package/dist/template-card-DStb8boW.d.ts +183 -0
  48. package/dist/types.d.ts +11 -8
  49. package/dist/types.js +1 -0
  50. package/dist/utils.d.ts +1 -44
  51. package/dist/utils.js +6 -12
  52. package/dist/workspace.d.ts +5 -10
  53. package/dist/workspace.js +3 -19
  54. package/package.json +19 -54
  55. package/dist/active-sessions-store-CeOmXgv5.d.ts +0 -85
  56. package/dist/artifact-pane-Bh45Ssco.d.ts +0 -24
  57. package/dist/branding-DCi5VEik.d.ts +0 -13
  58. package/dist/button-CMQuQEW_.d.ts +0 -17
  59. package/dist/chat-container-f4yEs6KN.d.ts +0 -106
  60. package/dist/chunk-34A66VBG.js +0 -214
  61. package/dist/chunk-34I7UFSX.js +0 -92
  62. package/dist/chunk-36QY2W5G.js +0 -802
  63. package/dist/chunk-4CLN43XT.js +0 -45
  64. package/dist/chunk-54SQQMMM.js +0 -156
  65. package/dist/chunk-66EZOYZR.js +0 -102
  66. package/dist/chunk-BX6AQMUS.js +0 -183
  67. package/dist/chunk-DI3NZ5ZX.js +0 -192
  68. package/dist/chunk-DPGIXDAI.js +0 -220
  69. package/dist/chunk-DXMIEK4K.js +0 -1426
  70. package/dist/chunk-GSZA3TSY.js +0 -79
  71. package/dist/chunk-HB5Y37YU.js +0 -54
  72. package/dist/chunk-LQNEZDRM.js +0 -109
  73. package/dist/chunk-MA7YKRUP.js +0 -131
  74. package/dist/chunk-MKTSMWVD.js +0 -109
  75. package/dist/chunk-MQXABZTB.js +0 -1348
  76. package/dist/chunk-MT5FJ3ZT.js +0 -186
  77. package/dist/chunk-NKUPJC34.js +0 -2070
  78. package/dist/chunk-OEX7NZE3.js +0 -321
  79. package/dist/chunk-OKLQVY3Y.js +0 -139
  80. package/dist/chunk-Q56BYXQF.js +0 -61
  81. package/dist/chunk-QD4QE5P5.js +0 -40
  82. package/dist/chunk-QDH5GEGY.js +0 -630
  83. package/dist/chunk-QID2OOMG.js +0 -133
  84. package/dist/chunk-QMU2PWOU.js +0 -493
  85. package/dist/chunk-RQHJBTEU.js +0 -10
  86. package/dist/chunk-T7HMZEVO.js +0 -216
  87. package/dist/chunk-U6QTHMY6.js +0 -1290
  88. package/dist/chunk-US6JKJKH.js +0 -124
  89. package/dist/chunk-VX3XOUEB.js +0 -63
  90. package/dist/chunk-XLG757B6.js +0 -933
  91. package/dist/chunk-ZMNSRDMH.js +0 -127
  92. package/dist/chunk-ZNCEM5CD.js +0 -316
  93. package/dist/document-editor-pane-A70-EhdQ.d.ts +0 -124
  94. package/dist/document-editor-pane-TLPVRBBU.js +0 -11
  95. package/dist/expanded-tool-detail-Dh99mcbY.d.ts +0 -63
  96. package/dist/file-tabs-BLfxfmAH.d.ts +0 -51
  97. package/dist/parts-CyGkM6Fp.d.ts +0 -50
  98. package/dist/run-CtFZ6s-D.d.ts +0 -41
  99. package/dist/sidebar-drop-zone-tDBsuOH5.d.ts +0 -301
  100. package/dist/sidecar-CFU2W9j1.d.ts +0 -8
  101. package/dist/template-card-BAtvcAkU.d.ts +0 -18
  102. package/dist/tool-call-feed-Bs3MyQMT.d.ts +0 -68
  103. package/dist/tool-display-Ct9nFAzJ.d.ts +0 -32
  104. package/dist/usage-chart-CPTcNlGs.d.ts +0 -73
  105. package/dist/use-sandbox-metrics-DWc0k9Xm.d.ts +0 -153
  106. package/dist/variant-list-BrHYcBCk.d.ts +0 -540
@@ -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
- };