@tangle-network/sandbox-ui 0.3.3 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,829 +0,0 @@
1
- import {
2
- Logo
3
- } from "./chunk-OKCIKTXQ.js";
4
- import {
5
- DropdownMenu,
6
- DropdownMenuContent,
7
- DropdownMenuItem,
8
- DropdownMenuLabel,
9
- DropdownMenuSeparator,
10
- DropdownMenuTrigger
11
- } from "./chunk-MCGKDCOR.js";
12
- import {
13
- Skeleton
14
- } from "./chunk-FRGMMANX.js";
15
- import {
16
- Badge
17
- } from "./chunk-MXCSSOGH.js";
18
- import {
19
- Button
20
- } from "./chunk-HWLX5NME.js";
21
- import {
22
- cn
23
- } from "./chunk-RQHJBTEU.js";
24
-
25
- // src/primitives/theme-toggle.tsx
26
- import { useCallback, useEffect, useState } from "react";
27
- import { jsx, jsxs } from "react/jsx-runtime";
28
- function getSystemTheme() {
29
- return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
30
- }
31
- function applyTheme(theme) {
32
- const resolved = theme === "system" ? getSystemTheme() : theme;
33
- document.documentElement.classList.toggle("dark", resolved === "dark");
34
- }
35
- function useTheme() {
36
- const [theme, setThemeState] = useState(() => {
37
- if (typeof window === "undefined") return "system";
38
- return localStorage.getItem("theme") ?? "system";
39
- });
40
- const setTheme = useCallback((next) => {
41
- setThemeState(next);
42
- if (next === "system") {
43
- localStorage.removeItem("theme");
44
- } else {
45
- localStorage.setItem("theme", next);
46
- }
47
- applyTheme(next);
48
- }, []);
49
- useEffect(() => {
50
- applyTheme(theme);
51
- if (theme !== "system") return;
52
- const mq = window.matchMedia("(prefers-color-scheme: dark)");
53
- const handler = () => applyTheme("system");
54
- mq.addEventListener("change", handler);
55
- return () => mq.removeEventListener("change", handler);
56
- }, [theme]);
57
- return { theme, setTheme };
58
- }
59
- var iconClass = "h-4 w-4";
60
- function SunIcon() {
61
- return /* @__PURE__ */ jsxs(
62
- "svg",
63
- {
64
- xmlns: "http://www.w3.org/2000/svg",
65
- viewBox: "0 0 24 24",
66
- fill: "none",
67
- stroke: "currentColor",
68
- strokeWidth: 2,
69
- strokeLinecap: "round",
70
- strokeLinejoin: "round",
71
- className: iconClass,
72
- children: [
73
- /* @__PURE__ */ jsx("circle", { cx: 12, cy: 12, r: 5 }),
74
- /* @__PURE__ */ jsx("path", { d: "M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" })
75
- ]
76
- }
77
- );
78
- }
79
- function MoonIcon() {
80
- return /* @__PURE__ */ jsx(
81
- "svg",
82
- {
83
- xmlns: "http://www.w3.org/2000/svg",
84
- viewBox: "0 0 24 24",
85
- fill: "none",
86
- stroke: "currentColor",
87
- strokeWidth: 2,
88
- strokeLinecap: "round",
89
- strokeLinejoin: "round",
90
- className: iconClass,
91
- children: /* @__PURE__ */ jsx("path", { d: "M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" })
92
- }
93
- );
94
- }
95
- function ThemeToggle() {
96
- const { theme, setTheme } = useTheme();
97
- const resolved = theme === "system" ? getSystemTheme() : theme;
98
- return /* @__PURE__ */ jsx(
99
- "button",
100
- {
101
- type: "button",
102
- onClick: () => setTheme(resolved === "dark" ? "light" : "dark"),
103
- className: "inline-flex items-center justify-center rounded-md p-2 text-muted-foreground hover:bg-accent hover:text-accent-foreground transition-colors",
104
- "aria-label": `Switch to ${resolved === "dark" ? "light" : "dark"} mode`,
105
- children: resolved === "dark" ? /* @__PURE__ */ jsx(SunIcon, {}) : /* @__PURE__ */ jsx(MoonIcon, {})
106
- }
107
- );
108
- }
109
-
110
- // src/dashboard/dashboard-layout.tsx
111
- import * as React from "react";
112
- import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
113
- var variantStyles = {
114
- sandbox: {
115
- activeNav: "bg-[var(--accent-surface-soft)] text-[var(--accent-text)]",
116
- userGradient: "bg-[image:var(--accent-gradient-strong)]"
117
- }
118
- };
119
- function DefaultLink({
120
- href,
121
- to,
122
- className,
123
- children,
124
- ...rest
125
- }) {
126
- return /* @__PURE__ */ jsx2("a", { href: href ?? to, className, ...rest, children });
127
- }
128
- function UserIcon({ className }) {
129
- return /* @__PURE__ */ jsxs2(
130
- "svg",
131
- {
132
- xmlns: "http://www.w3.org/2000/svg",
133
- viewBox: "0 0 24 24",
134
- fill: "none",
135
- stroke: "currentColor",
136
- strokeWidth: "2",
137
- strokeLinecap: "round",
138
- strokeLinejoin: "round",
139
- className,
140
- children: [
141
- /* @__PURE__ */ jsx2("title", { children: "User icon" }),
142
- /* @__PURE__ */ jsx2("path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" }),
143
- /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "7", r: "4" })
144
- ]
145
- }
146
- );
147
- }
148
- function SettingsIcon({ className }) {
149
- return /* @__PURE__ */ jsxs2(
150
- "svg",
151
- {
152
- xmlns: "http://www.w3.org/2000/svg",
153
- viewBox: "0 0 24 24",
154
- fill: "none",
155
- stroke: "currentColor",
156
- strokeWidth: "2",
157
- strokeLinecap: "round",
158
- strokeLinejoin: "round",
159
- className,
160
- children: [
161
- /* @__PURE__ */ jsx2("title", { children: "Settings icon" }),
162
- /* @__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" }),
163
- /* @__PURE__ */ jsx2("circle", { cx: "12", cy: "12", r: "3" })
164
- ]
165
- }
166
- );
167
- }
168
- function LogOutIcon({ className }) {
169
- return /* @__PURE__ */ jsxs2(
170
- "svg",
171
- {
172
- xmlns: "http://www.w3.org/2000/svg",
173
- viewBox: "0 0 24 24",
174
- fill: "none",
175
- stroke: "currentColor",
176
- strokeWidth: "2",
177
- strokeLinecap: "round",
178
- strokeLinejoin: "round",
179
- className,
180
- children: [
181
- /* @__PURE__ */ jsx2("title", { children: "Log out icon" }),
182
- /* @__PURE__ */ jsx2("path", { d: "M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" }),
183
- /* @__PURE__ */ jsx2("polyline", { points: "16,17 21,12 16,7" }),
184
- /* @__PURE__ */ jsx2("line", { x1: "21", x2: "9", y1: "12", y2: "12" })
185
- ]
186
- }
187
- );
188
- }
189
- function ChevronRightIcon({ className }) {
190
- return /* @__PURE__ */ jsxs2(
191
- "svg",
192
- {
193
- xmlns: "http://www.w3.org/2000/svg",
194
- viewBox: "0 0 24 24",
195
- fill: "none",
196
- stroke: "currentColor",
197
- strokeWidth: "2",
198
- strokeLinecap: "round",
199
- strokeLinejoin: "round",
200
- className,
201
- children: [
202
- /* @__PURE__ */ jsx2("title", { children: "Chevron right icon" }),
203
- /* @__PURE__ */ jsx2("path", { d: "m9 18 6-6-6-6" })
204
- ]
205
- }
206
- );
207
- }
208
- function MenuIcon({ className }) {
209
- return /* @__PURE__ */ jsxs2(
210
- "svg",
211
- {
212
- xmlns: "http://www.w3.org/2000/svg",
213
- viewBox: "0 0 24 24",
214
- fill: "none",
215
- stroke: "currentColor",
216
- strokeWidth: "2",
217
- strokeLinecap: "round",
218
- strokeLinejoin: "round",
219
- className,
220
- children: [
221
- /* @__PURE__ */ jsx2("title", { children: "Menu icon" }),
222
- /* @__PURE__ */ jsx2("line", { x1: "4", x2: "20", y1: "12", y2: "12" }),
223
- /* @__PURE__ */ jsx2("line", { x1: "4", x2: "20", y1: "6", y2: "6" }),
224
- /* @__PURE__ */ jsx2("line", { x1: "4", x2: "20", y1: "18", y2: "18" })
225
- ]
226
- }
227
- );
228
- }
229
- function XIcon({ className }) {
230
- return /* @__PURE__ */ jsxs2(
231
- "svg",
232
- {
233
- xmlns: "http://www.w3.org/2000/svg",
234
- viewBox: "0 0 24 24",
235
- fill: "none",
236
- stroke: "currentColor",
237
- strokeWidth: "2",
238
- strokeLinecap: "round",
239
- strokeLinejoin: "round",
240
- className,
241
- children: [
242
- /* @__PURE__ */ jsx2("title", { children: "Close icon" }),
243
- /* @__PURE__ */ jsx2("path", { d: "M18 6 6 18" }),
244
- /* @__PURE__ */ jsx2("path", { d: "m6 6 12 12" })
245
- ]
246
- }
247
- );
248
- }
249
- function DashboardLayout({
250
- children,
251
- variant = "sandbox",
252
- navItems,
253
- activeNavId,
254
- user,
255
- isLoading = false,
256
- onLogout,
257
- onSettingsClick,
258
- settingsHref = "/dashboard/settings",
259
- className,
260
- sidebarClassName,
261
- contentClassName,
262
- LinkComponent = DefaultLink
263
- }) {
264
- const styles = variantStyles[variant];
265
- const Link = LinkComponent;
266
- const [mobileMenuOpen, setMobileMenuOpen] = React.useState(false);
267
- const handleNavClick = () => {
268
- setMobileMenuOpen(false);
269
- };
270
- const SidebarContent = () => /* @__PURE__ */ jsxs2(Fragment, { children: [
271
- /* @__PURE__ */ jsx2("div", { className: "border-border border-b p-6", children: /* @__PURE__ */ jsx2(Logo, { variant, size: "md" }) }),
272
- /* @__PURE__ */ jsx2("nav", { className: "flex-1 space-y-1 p-4", "aria-label": "Main navigation", children: navItems.map((item) => {
273
- const Icon = item.icon;
274
- const isActive = activeNavId === item.id;
275
- return /* @__PURE__ */ jsxs2(
276
- Link,
277
- {
278
- href: item.href,
279
- to: item.href,
280
- onClick: handleNavClick,
281
- "aria-current": isActive ? "page" : void 0,
282
- className: cn(
283
- "flex items-center gap-3 rounded-lg px-4 py-2.5 transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-background",
284
- isActive ? styles.activeNav : "text-muted-foreground hover:bg-accent hover:text-foreground"
285
- ),
286
- children: [
287
- /* @__PURE__ */ jsx2(Icon, { className: "h-5 w-5", "aria-hidden": "true" }),
288
- /* @__PURE__ */ jsx2("span", { className: "font-medium", children: item.label })
289
- ]
290
- },
291
- item.id
292
- );
293
- }) }),
294
- /* @__PURE__ */ jsxs2("div", { className: "border-border border-t p-4", children: [
295
- /* @__PURE__ */ jsx2("div", { className: "mb-2 flex justify-end", children: /* @__PURE__ */ jsx2(ThemeToggle, {}) }),
296
- /* @__PURE__ */ jsxs2(DropdownMenu, { children: [
297
- /* @__PURE__ */ jsx2(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs2(
298
- "button",
299
- {
300
- type: "button",
301
- className: "flex w-full items-center gap-3 rounded-lg p-3 transition-colors hover:bg-accent focus:outline-none focus:ring-2 focus:ring-offset-2",
302
- "aria-label": "User menu",
303
- children: [
304
- /* @__PURE__ */ jsx2(
305
- "div",
306
- {
307
- className: cn(
308
- "flex h-8 w-8 items-center justify-center rounded-full",
309
- styles.userGradient
310
- ),
311
- children: /* @__PURE__ */ jsx2(UserIcon, { className: "h-4 w-4 text-white", "aria-hidden": "true" })
312
- }
313
- ),
314
- /* @__PURE__ */ jsx2("div", { className: "flex-1 text-left", children: isLoading ? /* @__PURE__ */ jsxs2(Fragment, { children: [
315
- /* @__PURE__ */ jsx2(Skeleton, { className: "mb-1 h-4 w-24" }),
316
- /* @__PURE__ */ jsx2(Skeleton, { className: "h-3 w-16" })
317
- ] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
318
- /* @__PURE__ */ jsx2("p", { className: "truncate font-medium text-sm", children: user?.email ?? "Not logged in" }),
319
- /* @__PURE__ */ jsxs2("p", { className: "text-muted-foreground text-xs capitalize", children: [
320
- user?.tier ?? "Free",
321
- " Plan"
322
- ] })
323
- ] }) }),
324
- /* @__PURE__ */ jsx2(
325
- ChevronRightIcon,
326
- {
327
- className: "h-4 w-4 text-muted-foreground",
328
- "aria-hidden": "true"
329
- }
330
- )
331
- ]
332
- }
333
- ) }),
334
- /* @__PURE__ */ jsxs2(DropdownMenuContent, { align: "end", className: "w-56", children: [
335
- /* @__PURE__ */ jsx2(DropdownMenuLabel, { children: "My Account" }),
336
- /* @__PURE__ */ jsx2(DropdownMenuSeparator, {}),
337
- onSettingsClick ? /* @__PURE__ */ jsxs2(DropdownMenuItem, { onClick: onSettingsClick, children: [
338
- /* @__PURE__ */ jsx2(SettingsIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
339
- "Settings"
340
- ] }) : /* @__PURE__ */ jsx2(DropdownMenuItem, { asChild: true, children: /* @__PURE__ */ jsxs2(Link, { href: settingsHref, to: settingsHref, className: "flex items-center", children: [
341
- /* @__PURE__ */ jsx2(SettingsIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
342
- "Settings"
343
- ] }) }),
344
- onLogout && /* @__PURE__ */ jsxs2(DropdownMenuItem, { className: "text-red-400", onClick: onLogout, children: [
345
- /* @__PURE__ */ jsx2(LogOutIcon, { className: "mr-2 h-4 w-4", "aria-hidden": "true" }),
346
- "Sign Out"
347
- ] })
348
- ] })
349
- ] })
350
- ] })
351
- ] });
352
- return /* @__PURE__ */ jsxs2("div", { className: cn("flex min-h-screen bg-background", className), children: [
353
- /* @__PURE__ */ jsxs2("header", { className: "fixed top-0 right-0 left-0 z-40 flex h-16 items-center justify-between border-border border-b bg-card/95 px-4 backdrop-blur-xl md:hidden", children: [
354
- /* @__PURE__ */ jsx2(Logo, { variant, size: "sm" }),
355
- /* @__PURE__ */ jsx2(
356
- "button",
357
- {
358
- type: "button",
359
- onClick: () => setMobileMenuOpen(!mobileMenuOpen),
360
- className: "rounded-md p-2 hover:bg-accent focus:outline-none focus:ring-2 focus:ring-offset-2",
361
- "aria-label": mobileMenuOpen ? "Close menu" : "Open menu",
362
- "aria-expanded": mobileMenuOpen,
363
- children: mobileMenuOpen ? /* @__PURE__ */ jsx2(XIcon, { className: "h-6 w-6" }) : /* @__PURE__ */ jsx2(MenuIcon, { className: "h-6 w-6" })
364
- }
365
- )
366
- ] }),
367
- mobileMenuOpen && /* @__PURE__ */ jsx2(
368
- "div",
369
- {
370
- className: "fixed inset-0 z-30 bg-black/50 md:hidden",
371
- onClick: () => setMobileMenuOpen(false),
372
- "aria-hidden": "true"
373
- }
374
- ),
375
- /* @__PURE__ */ jsx2(
376
- "aside",
377
- {
378
- className: cn(
379
- "fixed top-16 bottom-0 left-0 z-30 flex w-64 flex-col border-border border-r bg-card/95 backdrop-blur-xl transition-transform duration-200 md:hidden",
380
- sidebarClassName,
381
- mobileMenuOpen ? "translate-x-0" : "-translate-x-full"
382
- ),
383
- children: /* @__PURE__ */ jsx2(SidebarContent, {})
384
- }
385
- ),
386
- /* @__PURE__ */ jsx2(
387
- "aside",
388
- {
389
- className: cn(
390
- "fixed top-0 bottom-0 left-0 hidden w-64 flex-col border-border border-r bg-card/50 backdrop-blur-xl md:flex",
391
- sidebarClassName
392
- ),
393
- children: /* @__PURE__ */ jsx2(SidebarContent, {})
394
- }
395
- ),
396
- /* @__PURE__ */ jsx2("main", { className: cn("flex-1 pt-16 md:ml-64 md:pt-0", contentClassName), children: /* @__PURE__ */ jsx2("div", { className: "p-4 md:p-8", children: /* @__PURE__ */ jsx2("div", { className: "mx-auto max-w-6xl", children }) }) })
397
- ] });
398
- }
399
-
400
- // src/dashboard/backend-selector.tsx
401
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
402
- function BackendSelector({
403
- backends,
404
- selected,
405
- onChange,
406
- label = "Models",
407
- hint,
408
- multiSelect = true,
409
- className
410
- }) {
411
- const toggle = (type) => {
412
- if (multiSelect) {
413
- onChange(
414
- selected.includes(type) ? selected.filter((b) => b !== type) : [...selected, type]
415
- );
416
- } else {
417
- onChange([type]);
418
- }
419
- };
420
- return /* @__PURE__ */ jsxs3("div", { className, children: [
421
- /* @__PURE__ */ jsxs3("label", { className: "mb-2 block font-medium text-sm", children: [
422
- label,
423
- multiSelect && /* @__PURE__ */ jsx3("span", { className: "ml-2 font-normal text-muted-foreground", children: "(select multiple to compare)" })
424
- ] }),
425
- /* @__PURE__ */ jsx3("div", { className: "flex flex-wrap gap-2", children: backends.map((backend) => {
426
- const isSelected = selected.includes(backend.type);
427
- return /* @__PURE__ */ jsx3(
428
- "button",
429
- {
430
- type: "button",
431
- onClick: () => toggle(backend.type),
432
- className: `rounded-lg border px-3 py-2 text-sm transition-colors ${isSelected ? "border-blue-500 bg-blue-500/10 text-blue-400" : "border-border bg-background text-muted-foreground hover:border-muted-foreground/50"}`,
433
- title: backend.description,
434
- children: backend.label
435
- },
436
- backend.type
437
- );
438
- }) }),
439
- multiSelect && selected.length > 1 && /* @__PURE__ */ jsx3("p", { className: "mt-2 text-muted-foreground text-xs", children: hint || `Will run on ${selected.length} variants in parallel for comparison` })
440
- ] });
441
- }
442
-
443
- // src/dashboard/profile-selector.tsx
444
- import { Check, ChevronDown, Plus, Settings } from "lucide-react";
445
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
446
- function ProfileSelector({
447
- profiles,
448
- selectedId,
449
- onSelect,
450
- onCreateClick,
451
- onManageClick,
452
- label = "Profile",
453
- placeholder = "Default (no custom profile)",
454
- showMetrics = true,
455
- className
456
- }) {
457
- const selected = profiles.find((p) => p.id === selectedId);
458
- const builtinProfiles = profiles.filter((p) => p.is_builtin);
459
- const customProfiles = profiles.filter((p) => !p.is_builtin);
460
- return /* @__PURE__ */ jsxs4("div", { className, children: [
461
- label && /* @__PURE__ */ jsx4("label", { className: "mb-2 block font-medium text-sm", children: label }),
462
- /* @__PURE__ */ jsxs4(DropdownMenu, { children: [
463
- /* @__PURE__ */ jsx4(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs4(Button, { variant: "outline", className: "w-full justify-between", children: [
464
- /* @__PURE__ */ jsx4("span", { className: "truncate", children: selected ? selected.name : placeholder }),
465
- /* @__PURE__ */ jsx4(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })
466
- ] }) }),
467
- /* @__PURE__ */ jsxs4(DropdownMenuContent, { className: "w-[300px]", align: "start", children: [
468
- /* @__PURE__ */ jsxs4(
469
- DropdownMenuItem,
470
- {
471
- onClick: () => onSelect(null),
472
- className: "flex items-center justify-between",
473
- children: [
474
- /* @__PURE__ */ jsx4("span", { children: placeholder }),
475
- !selectedId && /* @__PURE__ */ jsx4(Check, { className: "h-4 w-4 text-green-400" })
476
- ]
477
- }
478
- ),
479
- builtinProfiles.length > 0 && /* @__PURE__ */ jsxs4(Fragment2, { children: [
480
- /* @__PURE__ */ jsx4(DropdownMenuSeparator, {}),
481
- /* @__PURE__ */ jsx4(DropdownMenuLabel, { children: "Built-in Profiles" }),
482
- builtinProfiles.map((profile) => /* @__PURE__ */ jsxs4(
483
- DropdownMenuItem,
484
- {
485
- onClick: () => onSelect(profile),
486
- className: "flex flex-col items-start gap-1",
487
- children: [
488
- /* @__PURE__ */ jsxs4("div", { className: "flex w-full items-center justify-between", children: [
489
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
490
- /* @__PURE__ */ jsx4("span", { className: "font-medium", children: profile.name }),
491
- profile.extends && /* @__PURE__ */ jsxs4(Badge, { variant: "secondary", className: "border-0 text-xs", children: [
492
- "extends ",
493
- profile.extends
494
- ] })
495
- ] }),
496
- selectedId === profile.id && /* @__PURE__ */ jsx4(Check, { className: "h-4 w-4 text-green-400" })
497
- ] }),
498
- profile.description && /* @__PURE__ */ jsx4("span", { className: "line-clamp-1 text-muted-foreground text-xs", children: profile.description })
499
- ]
500
- },
501
- profile.id
502
- ))
503
- ] }),
504
- customProfiles.length > 0 && /* @__PURE__ */ jsxs4(Fragment2, { children: [
505
- /* @__PURE__ */ jsx4(DropdownMenuSeparator, {}),
506
- /* @__PURE__ */ jsx4(DropdownMenuLabel, { children: "Custom Profiles" }),
507
- customProfiles.map((profile) => /* @__PURE__ */ jsxs4(
508
- DropdownMenuItem,
509
- {
510
- onClick: () => onSelect(profile),
511
- className: "flex flex-col items-start gap-1",
512
- children: [
513
- /* @__PURE__ */ jsxs4("div", { className: "flex w-full items-center justify-between", children: [
514
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
515
- /* @__PURE__ */ jsx4("span", { className: "font-medium", children: profile.name }),
516
- profile.model && /* @__PURE__ */ jsx4(Badge, { variant: "secondary", className: "border-0 text-xs", children: profile.model.split("/").pop() })
517
- ] }),
518
- selectedId === profile.id && /* @__PURE__ */ jsx4(Check, { className: "h-4 w-4 text-green-400" })
519
- ] }),
520
- profile.description && /* @__PURE__ */ jsx4("span", { className: "line-clamp-1 text-muted-foreground text-xs", children: profile.description }),
521
- showMetrics && profile.metrics && profile.metrics.total_runs > 0 && /* @__PURE__ */ jsxs4("div", { className: "flex gap-3 text-muted-foreground text-xs", children: [
522
- /* @__PURE__ */ jsxs4("span", { children: [
523
- profile.metrics.total_runs,
524
- " runs"
525
- ] }),
526
- /* @__PURE__ */ jsxs4("span", { children: [
527
- profile.metrics.success_rate.toFixed(0),
528
- "% success"
529
- ] }),
530
- /* @__PURE__ */ jsxs4("span", { children: [
531
- "~",
532
- (profile.metrics.avg_duration_ms / 1e3).toFixed(1),
533
- "s avg"
534
- ] })
535
- ] })
536
- ]
537
- },
538
- profile.id
539
- ))
540
- ] }),
541
- (onCreateClick || onManageClick) && /* @__PURE__ */ jsxs4(Fragment2, { children: [
542
- /* @__PURE__ */ jsx4(DropdownMenuSeparator, {}),
543
- onCreateClick && /* @__PURE__ */ jsxs4(
544
- DropdownMenuItem,
545
- {
546
- onClick: onCreateClick,
547
- className: "text-blue-400",
548
- children: [
549
- /* @__PURE__ */ jsx4(Plus, { className: "mr-2 h-4 w-4" }),
550
- "Create New Profile"
551
- ]
552
- }
553
- ),
554
- onManageClick && /* @__PURE__ */ jsxs4(
555
- DropdownMenuItem,
556
- {
557
- onClick: onManageClick,
558
- className: "text-muted-foreground",
559
- children: [
560
- /* @__PURE__ */ jsx4(Settings, { className: "mr-2 h-4 w-4" }),
561
- "Manage Profiles"
562
- ]
563
- }
564
- )
565
- ] })
566
- ] })
567
- ] })
568
- ] });
569
- }
570
- function ProfileComparison({
571
- profiles,
572
- className
573
- }) {
574
- const profilesWithMetrics = profiles.filter(
575
- (p) => p.metrics && p.metrics.total_runs > 0
576
- );
577
- if (profilesWithMetrics.length === 0) {
578
- return null;
579
- }
580
- const bestSuccess = profilesWithMetrics.reduce(
581
- (best, p) => (p.metrics?.success_rate ?? 0) > (best.metrics?.success_rate ?? 0) ? p : best
582
- );
583
- const fastestProfile = profilesWithMetrics.reduce(
584
- (best, p) => (p.metrics?.avg_duration_ms ?? Number.POSITIVE_INFINITY) < (best.metrics?.avg_duration_ms ?? Number.POSITIVE_INFINITY) ? p : best
585
- );
586
- return /* @__PURE__ */ jsxs4("div", { className: `rounded-lg border border-border p-4 ${className ?? ""}`, children: [
587
- /* @__PURE__ */ jsx4("h4", { className: "mb-3 font-medium text-sm", children: "Profile Performance" }),
588
- /* @__PURE__ */ jsx4("div", { className: "space-y-3", children: profilesWithMetrics.map((profile) => {
589
- const isBestSuccess = profile.id === bestSuccess.id;
590
- const isFastest = profile.id === fastestProfile.id;
591
- return /* @__PURE__ */ jsxs4(
592
- "div",
593
- {
594
- className: "flex items-center justify-between gap-4",
595
- children: [
596
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2", children: [
597
- /* @__PURE__ */ jsx4("span", { className: "font-medium", children: profile.name }),
598
- isBestSuccess && /* @__PURE__ */ jsx4(Badge, { className: "border-0 bg-green-500/10 text-green-400 text-xs", children: "Best Success" }),
599
- isFastest && !isBestSuccess && /* @__PURE__ */ jsx4(Badge, { className: "border-0 bg-blue-500/10 text-blue-400 text-xs", children: "Fastest" })
600
- ] }),
601
- /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-4 text-sm", children: [
602
- /* @__PURE__ */ jsxs4("span", { children: [
603
- /* @__PURE__ */ jsx4("span", { className: "text-muted-foreground", children: "Success:" }),
604
- " ",
605
- /* @__PURE__ */ jsxs4(
606
- "span",
607
- {
608
- className: (profile.metrics?.success_rate ?? 0) >= 80 ? "text-green-400" : (profile.metrics?.success_rate ?? 0) >= 50 ? "text-yellow-400" : "text-red-400",
609
- children: [
610
- profile.metrics?.success_rate.toFixed(0),
611
- "%"
612
- ]
613
- }
614
- )
615
- ] }),
616
- /* @__PURE__ */ jsxs4("span", { children: [
617
- /* @__PURE__ */ jsx4("span", { className: "text-muted-foreground", children: "Avg:" }),
618
- " ",
619
- ((profile.metrics?.avg_duration_ms ?? 0) / 1e3).toFixed(1),
620
- "s"
621
- ] }),
622
- /* @__PURE__ */ jsxs4("span", { className: "text-muted-foreground", children: [
623
- profile.metrics?.total_runs,
624
- " runs"
625
- ] })
626
- ] })
627
- ]
628
- },
629
- profile.id
630
- );
631
- }) })
632
- ] });
633
- }
634
-
635
- // src/dashboard/variant-list.tsx
636
- import {
637
- Check as Check2,
638
- CheckCircle2,
639
- Clock,
640
- ExternalLink,
641
- Loader2,
642
- Timer,
643
- X,
644
- XCircle
645
- } from "lucide-react";
646
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
647
- var statusConfig = {
648
- pending: {
649
- icon: Clock,
650
- color: "text-yellow-400",
651
- bg: "bg-yellow-500/10",
652
- label: "Pending",
653
- animate: false
654
- },
655
- running: {
656
- icon: Loader2,
657
- color: "text-blue-400",
658
- bg: "bg-blue-500/10",
659
- label: "Running",
660
- animate: true
661
- },
662
- completed: {
663
- icon: CheckCircle2,
664
- color: "text-green-400",
665
- bg: "bg-green-500/10",
666
- label: "Completed",
667
- animate: false
668
- },
669
- failed: {
670
- icon: XCircle,
671
- color: "text-red-400",
672
- bg: "bg-red-500/10",
673
- label: "Failed",
674
- animate: false
675
- },
676
- cancelled: {
677
- icon: XCircle,
678
- color: "text-gray-400",
679
- bg: "bg-gray-500/10",
680
- label: "Cancelled",
681
- animate: false
682
- }
683
- };
684
- var outcomeConfig = {
685
- pending_review: {
686
- color: "text-amber-400",
687
- bg: "bg-amber-500/10",
688
- label: "Pending Review"
689
- },
690
- accepted: {
691
- color: "text-green-400",
692
- bg: "bg-green-500/10",
693
- label: "Accepted"
694
- },
695
- rejected: {
696
- color: "text-red-400",
697
- bg: "bg-red-500/10",
698
- label: "Rejected"
699
- },
700
- merged_with_conflicts: {
701
- color: "text-orange-400",
702
- bg: "bg-orange-500/10",
703
- label: "Merged (conflicts)"
704
- },
705
- expired: {
706
- color: "text-gray-400",
707
- bg: "bg-gray-500/10",
708
- label: "Expired"
709
- }
710
- };
711
- function VariantList({
712
- variants,
713
- selectedId,
714
- onSelect,
715
- onAccept,
716
- onReject,
717
- isActioning,
718
- className
719
- }) {
720
- return /* @__PURE__ */ jsx5("div", { className: `space-y-3 ${className || ""}`, children: variants.map((variant) => {
721
- const status = statusConfig[variant.status];
722
- const StatusIcon = status.icon;
723
- const isSelected = variant.id === selectedId;
724
- return /* @__PURE__ */ jsxs5(
725
- "div",
726
- {
727
- className: `cursor-pointer rounded-lg border p-4 transition-colors ${isSelected ? "border-blue-500 bg-blue-500/5" : "border-border hover:border-muted-foreground/50"}`,
728
- onClick: () => onSelect?.(variant.id),
729
- children: [
730
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center justify-between", children: [
731
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-3", children: [
732
- /* @__PURE__ */ jsxs5(Badge, { className: `${status.bg} ${status.color} border-0`, children: [
733
- /* @__PURE__ */ jsx5(
734
- StatusIcon,
735
- {
736
- className: `mr-1 h-3 w-3 ${status.animate ? "animate-spin" : ""}`
737
- }
738
- ),
739
- status.label
740
- ] }),
741
- /* @__PURE__ */ jsx5("span", { className: "font-medium", children: variant.label }),
742
- variant.sublabel && /* @__PURE__ */ jsxs5("span", { className: "text-muted-foreground text-sm", children: [
743
- "(",
744
- variant.sublabel,
745
- ")"
746
- ] }),
747
- variant.durationMs && /* @__PURE__ */ jsxs5("span", { className: "flex items-center gap-1 text-muted-foreground text-sm", children: [
748
- /* @__PURE__ */ jsx5(Timer, { className: "h-3 w-3" }),
749
- (variant.durationMs / 1e3).toFixed(2),
750
- "s"
751
- ] })
752
- ] }),
753
- /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
754
- variant.outcome && /* @__PURE__ */ jsx5(
755
- Badge,
756
- {
757
- className: `${outcomeConfig[variant.outcome].bg} ${outcomeConfig[variant.outcome].color} border-0`,
758
- children: outcomeConfig[variant.outcome].label
759
- }
760
- ),
761
- variant.status === "completed" && variant.outcome === "pending_review" && onAccept && onReject && /* @__PURE__ */ jsxs5("div", { className: "flex items-center gap-2", children: [
762
- /* @__PURE__ */ jsxs5(
763
- Button,
764
- {
765
- variant: "outline",
766
- size: "sm",
767
- className: "text-green-400 hover:bg-green-500/10",
768
- onClick: (e) => {
769
- e.stopPropagation();
770
- onAccept(variant.id);
771
- },
772
- disabled: isActioning === variant.id,
773
- children: [
774
- /* @__PURE__ */ jsx5(Check2, { className: "mr-1 h-4 w-4" }),
775
- "Accept"
776
- ]
777
- }
778
- ),
779
- /* @__PURE__ */ jsxs5(
780
- Button,
781
- {
782
- variant: "outline",
783
- size: "sm",
784
- className: "text-red-400 hover:bg-red-500/10",
785
- onClick: (e) => {
786
- e.stopPropagation();
787
- onReject(variant.id);
788
- },
789
- disabled: isActioning === variant.id,
790
- children: [
791
- /* @__PURE__ */ jsx5(X, { className: "mr-1 h-4 w-4" }),
792
- "Reject"
793
- ]
794
- }
795
- )
796
- ] }),
797
- variant.detailsUrl && /* @__PURE__ */ jsx5(
798
- Button,
799
- {
800
- variant: "ghost",
801
- size: "sm",
802
- className: "text-muted-foreground",
803
- onClick: (e) => {
804
- e.stopPropagation();
805
- window.open(variant.detailsUrl, "_blank");
806
- },
807
- children: /* @__PURE__ */ jsx5(ExternalLink, { className: "h-4 w-4" })
808
- }
809
- )
810
- ] })
811
- ] }),
812
- variant.error && /* @__PURE__ */ jsx5("p", { className: "mt-2 text-red-400 text-sm", children: variant.error }),
813
- variant.summary && /* @__PURE__ */ jsx5("p", { className: "mt-2 line-clamp-2 text-muted-foreground text-sm", children: variant.summary })
814
- ]
815
- },
816
- variant.id
817
- );
818
- }) });
819
- }
820
-
821
- export {
822
- useTheme,
823
- ThemeToggle,
824
- DashboardLayout,
825
- BackendSelector,
826
- ProfileSelector,
827
- ProfileComparison,
828
- VariantList
829
- };